LTE-M Buttonが押されたらLINE BotへPushメッセージを送る【SORACOM】

#はじめに
この記事は全4章からなる記事の第2章です。

1. [IoTを駆使してお年寄りの家を見守る「だけじゃない」システムを作った【SORACOM Summer Challenge 2020】](https://qiita.com/tik26/items/fab2d34eb3a533fa19a5) 
2. [LTE-M Buttonが押されたらLINE BotへPushメッセージを送る【SORACOM】](https://qiita.com/tik26/items/a3c2e587b7df51313135) :arrow_backward: 今ココ
3. [【Raspberry Pi】人感センサーが感知したらtimestampをFirebase Realtime Databaseに格納する](https://qiita.com/tik26/items/92738ded6bb180cd56d4) 
4. [SORACOMと家電とLINE Botを連携させる【Python / Flask / Raspberry Pi】](https://qiita.com/tik26/items/c0395ee548793159a402) **全ソース公開** 
#きっかけ
離れて暮らす年老いた親に何かがあったときにLTE-M Buttonが押されるという想定です。SORACOM LagoonからLINE Notifyに通知をする機能はありますが、テキストメッセージで通知が来るだけでその後のアクションを選択できないのでLINE Botを作ることにしました。
このようにボタンが1つだけというシンプルな機構だと機械が苦手なお年寄りでも見た目でわかるのでいいですね。
![LTE-M Button](https://soracom.jp/wp-content/uploads/2019/08/products_soracom-lte-button-plus.png)

# 動作環境
Raspberry Pi 3 Model B
Python 3.7.3
Flask==1.1.2
line-bot-sdk==1.16.0

# LTE-M ButtonとLINE Botを連携するまで
###① SORACOM Lagoonからアラートを発する
具体的な使い方に関しては公式の[SORACOM Lagoon を利用してダッシュボードを作成する](https://dev.soracom.io/jp/start/lagoon-dashboards/)と[SORACOM Lagoon を利用してアラートを設定する](https://dev.soracom.io/jp/start/lagoon-alert/)に詳しく書かれているので割愛させていただきます。

LTE-M Buttonは1クリックが1、ダブルクリックが2、長押しが3というInt型のデータが送信されます。今回は緊急時ですからどんなボタン操作が行われるかわかりません。そこで、値が0.5以上（すべてのボタン操作）でアラートを送るという形にしました（画像参照）。
<img src="https://docs.google.com/drawings/d/e/2PACX-1vRtu-aEr9-4_IVPRP6hWkCww4RcLI-2jKRUzlIg3AurFsC4aJqeJgYiFmAk5PvcpTY5RBMO2eZbMLGi/pub?w=927&amp;h=459">

また、通知チャンネルでは`Webhook`を選択します。URLは後で設定するので今は``https://test.example``とでもしておいてください。
<img src="https://docs.google.com/drawings/d/e/2PACX-1vSTI5E7ROtptgCaZnQ7C2korYP4qkRWw8hQEuSJ7h4UvID86tK4oHLUHhVlNy-mqDVzk9HyvJ863tAs/pub?w=929&amp;h=454">

### ② LINE Botを登録する
[LINE Developers](https://developers.line.biz/console/)から新しいChannelを作成します。「Choose a channel type to continue」ではMessaging APIとしてください。
`Basic settings`にある`Channel secret`と`Messaging API`の`Channel access token`は後で使うので控えておいてください。
<img src="https://docs.google.com/drawings/d/e/2PACX-1vSGMD4cy0B4cgBOsbRaojPGK_GU0MnkDoBBNSd6LSeLAn-EQZSOZ5Vv0bsLgI_UrVQ8WVUN1lIdRAG5/pub?w=1390&amp;h=150">
<img src="https://docs.google.com/drawings/d/e/2PACX-1vTeQ8hk0YC7TBcWi1xJPVB8gZ5plyyOuBdQkMkCOaTrZaM8VOp-iHENu981YEp0E-B1mF0Gav9cecvW/pub?w=1393&amp;h=592">

### ③ ラズパイをサーバとして使う
Raspberry Pi上でFlaskを動かしてWebhookを受け取ったり、メッセージを返したりします。各種設定は[Python・ラズパイでLINE BOTを作ってみる！](Python・ラズパイでLINE BOTを作ってみる！)に従ってください。
##### 注意点
上記サイト、pyenv-virtualenvの設定は無視してもいいですが、それ以外の.bash_profile等の書き換えは必ず行ってください。そうでないと動きません。
また、上記サイト内にも書かれているようにChannel secretやChannel access tokenは環境変数に設定するようにしてください。

### ④ Pushメッセージを送る
Pushメッセージを送るには`userId`を知る必要があります。この`userId`は個人で任意に設定した、友だち追加するときに使うIDとは別物ですので別の方法で知る必要があります。
次のコードを使えばテキストメッセージを送ると`userId`を返してくれます。

```line_bot.py
from flask import Flask, request, abort
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage
import os

app = Flask(__name__)

LINE_BOT_ACCESS_TOKEN = os.environ["LINE_BOT_ACCESS_TOKEN"]
LINE_BOT_CHANNEL_SECRET = os.environ["LINE_BOT_CHANNEL_SECRET"]

line_bot_api = LineBotApi(LINE_BOT_ACCESS_TOKEN)
handler = WebhookHandler(LINE_BOT_CHANNEL_SECRET)

@app.route("/callback", methods=['POST'])
def callback():
    signature = request.headers['X-Line-Signature']

    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)
    
    return 'OK'

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    profile = line_bot_api.get_profile(event.source.user_id)
    messages = str(profile.user_id)
    line_bot_api.reply_message(event.reply_token, TextSendMessage(text=messages))

if __name__ == "__main__":
    port = int(os.getenv("PORT", 6000))
    app.run(host="0.0.0.0", port=port)
```

きちんと設定できていればこのようにUから始まるIDが返ってくるはずです。
<img src="https://docs.google.com/drawings/d/e/2PACX-1vQ9SDBZ98XL13ylrPgW9XD_smmFAuhRAMnCFmNMP_OX1hXAA1BSgkjO61_y_z7dlRo9SPKqwJovWqML/pub?w=881&amp;h=300">

ここまでできたら、ようやくSORACOM Lagoonとの連携です。
先ほどのコードに少し追記します。`/webhook`に`POST`があったときにユーザにPushメッセージを送れるようにします。`import`も追加しているので注意してください。

```line_bot.py
from flask import Flask, request, abort
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage
import os
import json  #追加

app = Flask(__name__)

LINE_BOT_ACCESS_TOKEN = os.environ["LINE_BOT_ACCESS_TOKEN"]
LINE_BOT_CHANNEL_SECRET = os.environ["LINE_BOT_CHANNEL_SECRET"]

line_bot_api = LineBotApi(LINE_BOT_ACCESS_TOKEN)
handler = WebhookHandler(LINE_BOT_CHANNEL_SECRET)

# 以下追記
@app.route("/webhook", methods=['POST'])
def webhook():
    print(json.dumps(request.get_json(), indent=2))
    object = request.get_json()
    if object['title'] == "[Alerting] Emergency alert":
        user_id = "U03xxxxxx(先ほど取得したuserId)"
        messages = TextSendMessage(text="アラートがきました")
        line_bot_api.push_message(user_id, messages=messages)

    return request.get_data()
# ここまで

@app.route("/callback", methods=['POST'])
def callback():
    signature = request.headers['X-Line-Signature']

    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)
    
    return 'OK'

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    profile = line_bot_api.get_profile(event.source.user_id)
    messages = str(profile.user_id)
    line_bot_api.reply_message(event.reply_token, TextSendMessage(text=messages))

if __name__ == "__main__":
    port = int(os.getenv("PORT", 6000))
    app.run(host="0.0.0.0", port=port)
```

最後にSORACOM Lagoonの通知チャネルを設定します。
Raspberry Pi上で動かしてるngrokのURLを入力し、末尾に`/webhook`を追加します。こうすることでLagoonからのWebhookを受け取ることができます。
<img src="https://docs.google.com/drawings/d/e/2PACX-1vR-__PEbP4lFEVZ0EcPyio6IYAB8c0I0Evm1dEuEaIhAj4Aine2p1Mr4GCh2mi8oXofx6RN63Y8k8zV/pub?w=539&amp;h=688">

##### デモ動画
[[YouTube] SORACOM LTE-M Buttonを押すとLINEへ通知する](https://youtu.be/28Z1u3gg-uE)
予想以上に反応が早い！これなら緊急時に1秒でも早く行動することができますね。