SORACOM AWS LTE-M ButtonでRaspberry Piを操作してみた

先日、[JAWS-UG名古屋 SORACOM-UG東海 共催 LTE-M Button ハンズオン](https://jawsug-nagoya.doorkeeper.jp/events/84819)に参加させてもらい、安かったのでLTE-M Buttonを買いました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="und" dir="ltr"><a href="https://twitter.com/hashtag/jawsug?src=hash&amp;ref_src=twsrc%5Etfw">#jawsug</a> <a href="https://twitter.com/hashtag/soracomug?src=hash&amp;ref_src=twsrc%5Etfw">#soracomug</a> <a href="https://twitter.com/hashtag/%E3%81%82%E3%81%AE%E3%83%9C%E3%82%BF%E3%83%B3?src=hash&amp;ref_src=twsrc%5Etfw">#あのボタン</a> <a href="https://t.co/t8M5K2FQ0a">pic.twitter.com/t8M5K2FQ0a</a></p>&mdash; K.Miura (@k_miura_io) <a href="https://twitter.com/k_miura_io/status/1086479240772513794?ref_src=twsrc%5Etfw">2019年1月19日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ハンズオンを試していくうちに、なんとなく実用的だと思ったので、自分でもなにか作ろうと思い、試しにRaspberry Piや手持ちのパーツを組み合わせてLTE-Mボタンで操作できるデバイスを作ってみました。

#使うもの
Raspberry Pi3 Model B+
アノードコモンフルカラーLED
抵抗（あるもので用意しました。200Ωぐらいあればいいです）
ジャンパーケーブル
ブレッドボード

#AWS側の構築手順
##Raspberry Pi用のポリシーの作成
[こちら](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-sdk-setup.html) を参考にしてRaspberry Piを接続するための設定を行い、証明書などをダウンロードしていきます。証明書は再発行出来ないのでなくさないようにします。

##Lambda
ランタイムをpython3.6で設定し、実行ロールではAWS Iotが使えるようにしておきます。
そして、lambda_function.pyを以下の内容に変更します。

```python:lambda_function.py
import json
import os
import urllib.request
import logging
import boto3

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

iot = boto3.client('iot-data', region_name="us-west-2")

def lambda_handler(event, context):

    logger.info('request event: \n' + json.dumps(event))
    
    click_type = event['deviceEvent']['buttonClicked'].get('clickType')
    logger.info("click_type: " + click_type)
    
    topic = "raspberry_pi/cmd"
    payload = event['placementInfo']['attributes'][click_type]
    logger.info(payload)
    
    try:
        iot.publish(
            topic=topic,
            qos=0,
            payload=json.dumps(payload, ensure_ascii=False)
        )

        return "Succeed"
        
    except Exception as e:
        logger.info(e)
        return "Falid"

```

実際にボタンを動かす前にテストをするときはテストイベントの設定で以下のJSONを書き込みます。

```json
{
  "deviceInfo": {
    "deviceId": "G030PMXXXXXXXXXX",
    "type": "button",
    "remainingLife": 94.2,
    "attributes": {
      "projectRegion": "us-west-2",
      "projectName": "One-click-Raspi",
      "placementName": "button1",
      "deviceTemplateName": "RequestCmd"
    }
  },
  "deviceEvent": {
    "buttonClicked": {
      "clickType": "SINGLE",
      "reportedTime": "2019-01-24T18:49:36.813Z"
    }
  },
  "placementInfo": {
    "projectName": "One-click-Raspi",
    "placementName": "button1",
    "attributes": {
      "SINGLE": "{\"cmd\":\"green\"}",
      "DOUBLE": "{\"cmd\":\"blue\"}",
      "LONG": "{\"cmd\":\"red\"}"
    },
    "devices": {
      "RequestCmd": "G030PMXXXXXXXXXX"
    }
  }
}
```
この時点ではまだRaspberry Piの設定を行っていませんが、エラーを出すことなくIotプラットフォームに送信することができたら、成功です。（関数ではSucceedと出力されます。）もし、Faildと出た場合は、ロールにIoT Full AccessのPolicyがついていない可能性があります。もう一度lambdaで設定したポリシーを確認してみてください。

##ボタンのデバイス登録
1.AWS Iot 1-clickを開き、オンボードから、デバイスの登録を行います。
![スクリーンショット 2019-01-27 18.49.10.png](https://qiita-image-store.s3.amazonaws.com/0/170520/ca59bb66-15ae-246c-9924-2cbaa44ed53e.png)

2.新たにプロジェクトを作成します。プロジェクト名はOne-click-Raspiとしておきます。
3.「プロジェクトのプレイスメントのテンプレートの定義」ではデバイステンプレートの設定では、先程登録したデバイスを選択し、ボタンを押したときのアクションはlambda関数を選択し、実行するlambda関数を選択します。デバイステンプレート名は何でも良いです。

![スクリーンショット 2019-01-27 19.01.57.png](https://qiita-image-store.s3.amazonaws.com/0/170520/4d1a466c-465a-88eb-dadb-79ab8831b1ba.png)

4.プレイスメントの属性を以下のように登録させます

| 名前       |      デフォルト値 | 
|:-----------------|:------------------|
| SINGLE          |  {"cmd":"green"} | 
| DOUBLE           | {"cmd":"blue"} |    
| LONG           |  {"cmd":"red"} |  

名前の欄にはボタンが行った操作の種類が書かれており、lambdaで受け取るrequestの中に記載されるものです。(先程のテスト用に用意したJSONがlambda関数に送信され実行されるイメージです。)




#Raspberry Pi側の構築手順
##配線図
配線は下図のように簡単に配線しました。黄色のジャンパーケーブル以外は接続先のピンの色に対応させています。
![Raspi_led.png](https://qiita-image-store.s3.amazonaws.com/0/170520/d78a5fa8-b0cc-63cc-46f4-b39704b76f9b.png)

##証明書のダウンロード
AWS Iotへの接続設定を行ったときにダウンロードした証明書は ```cert```ディレクトリを作成しその中にファイルを保存していきます。分かりやすくするためにcertディレクトリはLEDを点灯させるプログラムと同じディレクトリに配置します。

##プログラム
AWSIoTのPythonSDKをインストールします。

```
sudo pip install AWSIoTPythonSDK
```
以下のプログラムを用意します。

```python:3led.py
import pigpio
from time import sleep
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient
import json

green_pin = 9
red_pin  = 10
blue_pin = 11

CLIENT_ID = "raspi_control"
ENDPOINT = "YOUR_ENDPOINT"
PORT = 8883

ROOT_CA = "./cert/rootCA.pem"
PRIVATE_KEY = "./cert/YOUR_KEY.pem.key"
CERTIFICATE = "./cert/YOUR_CATE.pem.crt"

TOPIC = "raspberry_pi/cmd"

pi = pigpio.pi()
pi.set_mode(green_pin, pigpio.OUTPUT)
pi.set_mode(red_pin, pigpio.OUTPUT)
pi.set_mode(blue_pin, pigpio.OUTPUT)

pi.write(green_pin, 1)
pi.write(red_pin, 1)
pi.write(blue_pin, 1)

def main():
    # https://s3.amazonaws.com/aws-iot-device-sdk-python-docs/sphinx/html/index.html
    client = AWSIoTMQTTClient(CLIENT_ID)
    client.configureEndpoint(ENDPOINT, PORT)
    client.configureCredentials(ROOT_CA, PRIVATE_KEY, CERTIFICATE)

    client.configureAutoReconnectBackoffTime(1, 32, 20)
    client.configureOfflinePublishQueueing(-1)
    client.configureDrainingFrequency(2)
    client.configureConnectDisconnectTimeout(10)
    client.configureMQTTOperationTimeout(5)

    client.connect()
    client.subscribe(TOPIC, 1, subscribe_callback)

    while True:
        sleep(5)

def subscribe_callback(client, userdata, message):
    d = json.loads(message.payload.decode())
    d = json.loads(d)
    print("Received a new message: ")
    print(d)
    print("from topic: ")
    print(message.topic)
    print("--------------\n\n")
    color = d.get("cmd")
    led_chika(color)

def led_chika(color):
    if color == "blue":
        pi.write(blue_pin, 0)
        sleep(2)
        pi.write(blue_pin, 1)
    elif color == "green":
        pi.write(green_pin, 0)
        sleep(2)
        pi.write(green_pin, 1)
    elif color == "red":
        pi.write(red_pin, 0)
        sleep(2)
        pi.write(red_pin, 1)
    else:
        print("No Color")

if __name__ == "__main__":
    main()

```
#動作チェック
実際にボタンを押して、ボタンの押し方で光るLEDの色が変わったら、成功です。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/%E3%81%82%E3%81%AE%E3%83%9C%E3%82%BF%E3%83%B3?src=hash&amp;ref_src=twsrc%5Etfw">#あのボタン</a> を使ってRaspberry Piを操作できるようになった<a href="https://twitter.com/hashtag/soracom?src=hash&amp;ref_src=twsrc%5Etfw">#soracom</a> <a href="https://twitter.com/hashtag/AWSIot?src=hash&amp;ref_src=twsrc%5Etfw">#AWSIot</a> <a href="https://twitter.com/hashtag/ltembutton?src=hash&amp;ref_src=twsrc%5Etfw">#ltembutton</a> <a href="https://t.co/5S0hp2YbIw">pic.twitter.com/5S0hp2YbIw</a></p>&mdash; K.Miura (@k_miura_io) <a href="https://twitter.com/k_miura_io/status/1089582017786785793?ref_src=twsrc%5Etfw">2019年1月27日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 参考
[【AWS Lambdaの基本コードその4】 AWS IoTにメッセージをPublish](https://recipe.kc-cloud.jp/archives/10348)
[Raspi(デバイス)とAWSIoT(クラウド)間でMQTTを使ってメッセージを送受信する](https://qiita.com/is_ryo/items/ecf822b12513be1bc156)
[Soracom LTE-M ButtonでAlexaに通知させてみた](https://dev.classmethod.jp/voice-assistant/soracom-lte-m-button-integrated-with-alexa/)
[Raspberry PiでAWS IoT Coreと接続し、GPIO制御をしてみた](https://qiita.com/gnk263/items/a7937259746c81a6b052)
[AWS IoT への Raspberry Pi の接続](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-sdk-setup.html)