SORACOM Enterprise Buttonを押した地点の住所をLINEに通知する

この記事は SORACOM Advent Calendar 2019 12/9分の記事となります

皆様こん**は。
昨年に引き続きSORACOM Advent Calendarに投稿させていただきます。

2019年の振り返り

まず、今年も年末なので振り返りをします。

昨年のAdvent Calendar寄稿記事では、2018年は私にとってはIoT開発に開眼した年となったと書きましたが、2019年はより一層コミュニティ活動に参加し露出が増えた1年となりました。
(ブログに時間をなかなか割けず、発信が少なくなってすみません)

1年の活動を振り返ります。

1月①社内ハッカソンでSORACOMサービスの解説を行い広める
②このブログを運営しているサーバをオンプレミス⇒GCPに移行(記事化できず。。。)
2月①所属する企業にSORACOM-UG勉強会を誘致し、社内参加者にSORACOMサービスを広める
②社内ハッカソンでAmazon Connectに触れる。(当時新人)の樋口さんに指導し彼は後で大化けすることに・・・
3月JAWS-UG/SORACOM-UG/TwilioJP-UG信州のハンズオンイベント@上田に招待いただき、ハンズオン講師を務める。
SORAZINE記事 ハンズオンマニュアル
(あのボタンを押すとTwilioから電話が掛かってくる"会議脱出ボタン")
4月-
5月SORACOM UG Tokyo#13にて飛び入りLT登壇(こちらの内容
6月DevRel/Community #3イベントにて、SORACOM UG参加者代表として登壇
7月所属する企業の社内でSORACOM LTE-M Button Powered by AWSを用いたハンズオントレーニングを開催(ブログ記事
8月SORACOM UG/Twilio JP-UG イベント@茅野にて再びハンズオン講師を務める。
SORAZINE記事 ハンズオンマニュアル
(しろボタンを押すとTwilioから電話が掛かってくる"会議脱出ボタン")
9月-
10月有志で所属する企業にIoTLT勉強会を誘致、無事成功させる。2月に指導した樋口さん大化けする。
11月SORACOM UG Explorer 2019の運営スタッフとして参画。
12月SORACOM Advent Calendarにて1年の振り返り(本記事)

通年で仕事が多忙だったのと、後半はSORACOM UG Explorerの準備に費やしたので、なかなか学習し発信する時間に割けなかったな、という感想です。来年はもう少しメリハリを持って時間配分したいですね。


また、コミュニティイベントの自社への誘致や、社内のハッカソン仲間をコミュニティイベントへ登壇斡旋するなどして、社内のエンジニアが外で活躍するきっかけ作りができればと思い活動しています。

成果も出つつありまして、今年の SORACOM Advent Calendar は弊社(グループ)から私を含み4名エントリーしています。今年巻き込んだ(笑) 樋口さんは IoTLT や SORACOM UG Explorer で大ブレークし、単純に嬉しいです。

SORACOM UG Explorer 2019 – ボタンハンズオン

さて、SORACOM UG Explorer 2019では主に以下のタスクを担当させて頂きました。

参加者の皆様、登壇者の皆様、スポンサーの皆様などのお陰で、大変良いイベントになったと思っています。
ここで御礼させていただきます。ありがとうございました。

経緯

ボタンハンズオンの内容決めの経緯についてお話ししたいと思います。

2018年11月にSORACOM LTE-M Buttonが登場した際、色々な方々からアイディアの発案がありましたが、その中でも実用的だったのが、いわゆる “かえるボタン” (山添さんの記事) でした。

  • LTE-M網なので、国内であれば外出先どこからでも使える
  • “押す”という誰でもわかるシンプルなアクション
  • 子供に持たせて雑に扱っても(最悪紛失しても)影響が少ない

という合理性を持ったアイディアでしたが、やはり子供の安全安心には位置情報が必須と思います。親心としては、どこに居るか知りたいですよね。

その要望を受けてか、今年8月からSORACOM LTE-M Button for Enterpriseにて簡易位置即位機能が提供されました。早速、本機能を利用して位置情報を親のLINE通知しようというアイディアとさせて頂きました。

簡易位置測位機能が利用できるのは
・しろボタン(SORACOM LTE-M Button for Enterprise)
・ひげボタン(SORACOM LTE-M Button for Enterprise Plus)
以上のみです。
あのボタン(SORACOM LTE-M Button Powered by AWS)では利用できませんのでご注意下さい。

アーキテクチャ

一部の参加予定者の方より、LINEアカウントを保有していないというお話がありました。
またLINEアカウントは取得の方法によりIDやパスワードが不明確になる懸念がありましたので、ハンズオンマニュアルは LINE通知版、メール通知版の2種類用意することとしました。

いずれも 緯度経度 と Google MapへのリンクURL が通知されるため、スマートフォンで開くと現在接続している基地局の位置情報が地図上で表示されます。

あくまで基地局ベースの位置情報のため、現在位置との誤差はあります。ご注意ください。

ハンズオンマニュアル

当日のハンズオンマニュアルはこちらです。
即使える実用的な内容としたつもりです。ご活用頂ければ幸いです。

住所を通知する方法

さて、LINEもしくはメールで緯度・経度を通知しても場所がピンとくる方は少ないかと思います。
やはり位置情報としては住所を知りたい。そこでGoogle Map APIの逆ジオコーディング機能を利用し、緯度・経度から住所情報を取得し通知することとします。

手順

手順は基本的に上記のハンズオンマニュアルと同様です。
(以下はLINE通知版で記載します)

  1. ハンズオンマニュアル通りに環境を整える
  2. Google Maps APIのキーを取得する
  3. ソースコードと環境変数を差し替える

Google Maps APIの利用開始

Google Map APIは昨年より有償化されましたので、利用開始の手続きが必要です。
(但し$200/月まで、今回の利用方法では50,000回/月まで無償なので、実質無償と言っていいでしょう)
なお、GCPのアカウントが必要となります。

まず、Google Maps Platformのサイトにアクセスし「使ってみる」をクリックします。

今回の利用方法であれば「プレイス」のみで問題ありません。続行をクリックします。

Google Maps APIを有効にするGCPプロジェクトを指定します。
このプロジェクトに課金が紐付きます。今回は新しいプロジェクトを選択し名前を入力します。

請求先アカウントの設定の確認画面が出ますが、そのまま「アカウントを設定」をクリックします。

APIの有効化ができました。「次へ」をクリックします。

APIキーが表示されますので、コピーして控えておきます。

Lambda関数

LINE通知版のソースコードは以下の通りとなりました。
zipパッケージでダウンロードする方はこちらからどうぞ。

import os
import requests
import json

def lambda_handler(event, context):
    # contextから緯度経度の情報を取得
    try:
        location_lat = context.client_context.custom["location"]["lat"]
        location_lon = context.client_context.custom["location"]["lon"]
    except:
        return {'statusCode': 400, 'body': json.dumps('Location incorrect')}

    # 緯度経度から住所情報を取得
    address_json = rev_geocode(location_lat,location_lon)
    address = extra_address(address_json,'administrative_area_level_1') + \
              extra_address(address_json,'locality') 

    try:
        address = address + extra_address(address_json,'sublocality_level_2') 
    except:
        pass
    try:
        address = address + extra_address(address_json,'sublocality_level_3') 
    except:
        pass
    try:
        address = address + extra_address(address_json,'sublocality_level_4') 
    except:
        pass


    # メッセージ生成
    message = "ボタンが押されました。\nおおよその住所 : " + address + "\n https://www.google.com/maps/search/?api=1&query=" + str(location_lat) + "," + str(location_lon)

    # LINE Notify呼び出し
    data = push_line(message)
    response = json.loads(data)
    return {'statusCode': 200, 'body': json.dumps(response)}

def push_line(message):
    """LINEにメッセージを通知する"""

    # 環境変数取得/定義
    line_notify_token = os.environ['line_token']
    line_notify_url   = 'https://notify-api.line.me/api/notify'
    payload = {'message': message }
    headers = {'Authorization': 'Bearer ' + line_notify_token}

    # line notify呼び出し
    line_notify = requests.post(line_notify_url, data=payload, headers=headers).text
    return line_notify

def rev_geocode(lat,lng):
    """Google Map APIにて位置情報から住所を取得する"""
    gmap_apikey = os.environ['gmap_apikey']
    gmap_apiurl = 'https://maps.googleapis.com/maps/api/geocode/json?language=ja&latlng=' + str(lat) + ',' + str(lng) + '&key=' + gmap_apikey
    
    res_text = requests.get(gmap_apiurl).text
    res_json = json.loads(res_text)

    return res_json['results'][0]['address_components']
    
def extra_address(addjson,addtype):
    """Google Map API出力結果から住所要素の文字列を抽出する"""
    comp = [e['long_name'] for e in addjson if addtype in e['types']]
    return comp[0]

環境変数(gmap_apikey)として、上記でコピーしたGoogle Maps APIのキーを入力します。

以上で完成です!

補足

Google Maps APIから入手できる住所情報(JSON、抜粋)は以下のようなフォーマットになっています。
郵便番号まで含むformatted_addressでは冗長であったため、address_componentsに含まれる各要素のlong_nameを組み立てるようにしています。
また、地域によりsublocality_level_3およびsublocality_level_4は付与されないことがあることがあるため、付与されていない場合は含めないようにしています。

{
   "plus_code" : {
      "compound_code" : "MM5X+66 日本、東京都東京",
      "global_code" : "8Q7XMM5X+66"
   },
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "12",
               "short_name" : "12",
               "types" : [ "political", "sublocality", "sublocality_level_4" ]
            },
            {
               "long_name" : "1丁目",
               "short_name" : "1丁目",
               "types" : [ "political", "sublocality", "sublocality_level_3" ]
            },
            {
               "long_name" : "道玄坂",
               "short_name" : "道玄坂",
               "types" : [ "political", "sublocality", "sublocality_level_2" ]
            },
            {
               "long_name" : "渋谷区",
               "short_name" : "渋谷区",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "東京都",
               "short_name" : "東京都",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "日本",
               "short_name" : "JP",
               "types" : [ "country", "political" ]
            },
            {
               "long_name" : "150-0043",
               "short_name" : "150-0043",
               "types" : [ "postal_code" ]
            }
         ],
         "formatted_address" : "日本、〒150-0043 東京都渋谷区道玄坂1丁目12",
         "geometry" : {
            "location" : {
               "lat" : 35.6580483,
               "lng" : 139.6980886
            },
            "location_type" : "ROOFTOP",
            "viewport" : {
               "northeast" : {
                  "lat" : 35.6593972802915,
                  "lng" : 139.6994375802915
               },
               "southwest" : {
                  "lat" : 35.6566993197085,
                  "lng" : 139.6967396197085
               }
            }

結果/まとめ

SORACOM LTE-M Button for Enterpriseを押すことで、ボタンを押したおおよその住所とGoogle Mapへのリンクが表示されるようになりました。

さてSORACOM Advent Calendar 2019、今日(12/9)から明後日(12/11)まで社内ハッカソン仲間の3連続です。

大口さんが華麗なスルーパスを出して樋口さんがゴールを決めてくれるでしょう。お楽しみに。

コメント