Lambda から SORACOM 経由で Raspberry Pi の LED を操作する 3 つのパターン


これは、[SORACOM Advent Calendar 2021](https://qiita.com/advent-calendar/2021/soracom) の 8 日目の記事です。

## 作った物

こんなものを、3 つのパターンで作ってみた記事です。

https://twitter.com/n_mikuni/status/1462308120894443522?s=20

本当は LINE の連携部分から解説したかったのですが、かなり分量が多くなってしまって、AWS Lambda (以後、Lambda) から Raspberry Pi を操作するところに限定した記事にしてみました。LINE 部分はまた追ってブログにしたいと思います。

## 構成

以下のような 3 つの構成で、どのように Lambda から Raspberry Pi を操作するか紹介しようと思います。

![summary.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125247/9ff11204-16ee-61e3-7d5a-104156d9dd11.png)

### 参考: 双方向通信の 3 パターン

デバイスを遠隔操作するための構成について、実は SORACOM 公式では「双方向通信の 3 パターン」として以下のようにまとめられています。

1. IP アクセスパターン
2. アプリケーションパターン
3. デバイスリードパターン

公式の資料は [こちらのページ](https://soracom.jp/dl-device_to_cloud/) からダウンロードできますし、同じ内容を SORACOM のイベントで紹介したときの [資料](https://www.slideshare.net/SORACOM/b2-soracom-technology-camp-2020) や [動画](https://youtu.be/i6oxhgGdOko) も公開されています。

この記事では、上記の「双方向通信の 3 パターン」を、「Lambda から Raspberry Pi の LED を遠隔操作する」というシナリオに落とし込んで試してみようと思います。この記事では「双方向の 3 パターンとは何か」の細かい解説はしませんが、実際に手を動かして実装していくことでどのようなものか感じてもらったり使いたいものを選ぶ参考にしてもらえればと思います。

## 準備するもの

以下を使いました。セットアップ方法について細かく解説しないものもあります。

- AWS アカウント
- SORACOM アカウント
- Raspberry Pi (3B や 4)
- 電子工作グッズ
  - ブレッドボード
  - 330Ω 抵抗
  - LED
  - ジャンパーワイヤー オス - オス 1 本
  - ジャンパーワイヤー オス - メス 2 本

電子工作グッズについては単品で買えば 1000 円もしません。Amazon などでキットも探したのですが、[ドンピシャ](https://www.amazon.co.jp/dp/B00J8W368Y) なのが在庫切れでした。少し値段が張りますが、[ラズパイ４対応　Ｒａｓｐｂｅｒｒｙ　Ｐｉで学ぶ電子工作　パーツセット](https://akizukidenshi.com/catalog/g/gK-15351/) などが良いのではないかと思います。LED やモーターなどを動かすのは楽しいですし、ふと何か作りたくなった時に持っておくと便利です。

### 費用

今回は少しの利用だったため AWS や SORACOM はすべて無料枠で収まったはずです。そのためかかった費用は Raspberry Pi と電子工作グッズだけでした。ちなみに、今回は初期費用も掛からないことから SIM なしで SORACOM サービスを使える [SORACOM Arc](https://soracom.jp/services/arc/) を使いましたが、SIM と USB ドングルを使う場合はその分の費用も掛かります。

---

それでは、各パターンでの「共通手順」および各パターン別の構築手順を紹介していきます。

## (共通手順) Raspberry Pi から LED を操作する

この記事では Raspberry Pi のセットアップ方法は解説しません。以下のドキュメントなどを参考にすると良いかと思います。以下のドキュメントを参考にする場合は「Raspberry Pi へのログイン」までで大丈夫です。

https://users.soracom.io/ja-jp/guides/starter-kits/ultrasonic/setup-raspberry-pi/

### Raspberry Pi と LED の接続

はじめて、または久しぶりにフレットボードや LED を触る人は、まず以下の図のように配線して、プログラムを書くことなく LED が点灯することを確認してみると良いでしょう。LED の向きに注意してください。足の長い方が図中の右です。黒い線が GND、赤い線が 3.3V につながっているために、Raspberry Pi の電源が付いていれば、電気が流れて LED が点灯します。

![rasPi-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125247/a32b2654-7019-bc20-78fb-59d5c2adf4c9.png)

LED が点灯することを確認したら、次は以下のように接続します。この接続では、Raspberry Pi 側から指示があった時 (赤い線につながった GPIO 18 がオンとなったとき) に LED が点灯します。

![rasPi-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125247/e98d82da-7803-b71a-f665-1351db9b7f24.png)

### Raspberry Pi から LED の操作

Raspberry Pi 上で、以下のファイルを用意します。

```led.py
from gpiozero import LED
from time import sleep

led = LED(18)

led.on()
print(led.value)
sleep(5)
led.off()
print(led.value)
```

ファイルを置いたディレクトリ上で、以下のコマンドを実行すると、3 秒ごとに LED のオン・オフを確認でき、コンソール上で LED のオン・オフを表示できるはずです。

```screen
python3 led.py
```

このように、各パターンにおいて、LED は以下のような方法で操作します。

- LED 状態の取得: `led_state = led.value`
- 点灯: `led.on()`
- 消灯: `led.off()`

## (共通手順) Lambda が利用する SAM ユーザーの認証情報を発行する

今回は Lambda から SORACOM API を呼び出してメタデータの読み書きをしたり、リモートアクセスのための一時的な IP アドレス・ポート番号を作成したりします。Lambda から SORACOM API を呼び出すため、SAM ユーザーおよび認証情報の作成をします。

[Getting Started: SAM ユーザーを作成する | アクセス管理 (SORACOM Access Management: SAM) | SORACOM Users](https://users.soracom.io/ja-jp/docs/sam/create-sam-user/) にしたがって SAM ユーザーを作成します。「[認証キーの生成](https://users.soracom.io/ja-jp/docs/sam/create-sam-user/#%e8%aa%8d%e8%a8%bc%e3%82%ad%e3%83%bc%e3%81%ae%e7%94%9f%e6%88%90)」で生成した認証キーと認証シークレットは次の手順で使うので保持しておいてください。

[SAM ユーザーの権限設定](https://users.soracom.io/ja-jp/docs/sam/create-sam-user/#sam-%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%AE%E6%A8%A9%E9%99%90%E8%A8%AD%E5%AE%9A) では、以下の権限を設定します。`statements` の配列中の 1 つ目の要素が IP アクセスパターンで利用する権限、2 つ目の要素がデバイスリードパターンで利用する権限です。

```json
{
  "statements": [
    {
      "api": [
        "PortMapping:createPortMapping",
        "PortMapping:deletePortMapping"
      ],
      "effect": "allow"
    },
    {
      "api": [
        "Subscriber:putSubscriberTags",
        "Subscriber:getSubscriber"
      ],
      "effect": "allow"
    }
  ]
}
```

## (共通手順) Raspberry Pi を SORACOM に接続する

SORACOM のサービスを使うことで、遠隔操作がより簡単になります。SORACOM のサービスを使うために、Raspberry Pi を SORACOM へ接続しましょう。

今回は、SIM なしで SORACOM サービスを使える SORACOM Arc を用いました。以下の手順に則ってセットアップできます。

https://users.soracom.io/ja-jp/docs/arc/bootstrap-authkey/

SORACOM の IoT SIM を使う場合は SORACMO Onyx LTE USB ドングルなどを使って、以下のドキュメントの手順でセットアップできます。 

https://users.soracom.io/ja-jp/guides/devices/general/raspberry-pi-dongle/

以下のように SORACOM 上の PING 疎通確認用エンドポイントへ PING を送信して、SORACOM へ接続できていることを確認しましょう。 **各手順において、SORACOM へ接続できている必要があるので注意してください。**

```screen
ping pong.soracom.io
```

### (共通手順) Serverless の環境セットアップ

今回 Lambda は [Serverless Framework](https://www.serverless.com/) を使ってデプロイします。デプロイをするための PC に Serverless を実行できるようにしてください。Serverless Framework のインストール方法などは [公式からの日本語ブログ](https://serverless.co.jp/blog/25/) もありましたので、こちらを参考に「インストール」と「サービスの作成」までできていれば、次の手順で紹介するサンプルプログラムをデプロイできます。

### (共通手順) サンプルプログラムのダウンロード

サンプルプログラムは以下の GitHub リポジトリにあります。`raspberry_pi` 配下には Raspberry Pi にて実行するプログラム、`Lambda` 配下には Lambda にて実行するプログラムがあります。Serverless Framework をインストールした PC にてリポジトリのクローン、または zip ファイルのダウンロードと解凍をしてください。

https://github.com/nmikuni/lambda-soracom-raspi-led

---

それでは、それぞれのパターンを使って LED の遠隔操作をしてみましょう！

## IP アクセスパターンの構築手順

IP アクセスパターンでは、Raspberry Pi 上で [Flask](https://flask.palletsprojects.com/en/2.0.x/) を使って Web サーバーを建てます。HTTP GET リクエストが来たら LED の状態を返し、PUT リクエストが来たら Body に応じて LED をオンオフするというシンプルな構成です。Flask は Raspberry Pi 上で `pip3 install flask` を実行してインストールします。
Raspberry Pi 上の Web サーバーには、SORACOM Napter でアクセスします。SORACOM Napter は、SORACOM の SIM へインターネット越しにアクセスするため、一時的なグローバル IP アドレス・ポート番号をアクセス元を制限して払い出すオンデマンドでセキュアなリモートアクセスサービスです。一時的なアクセス情報は SORACOM API を呼び出して取得します。図にすると以下のとおりです。

![ip-access.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125247/8342850b-3a24-d4ae-a27e-cef83fefb696.png)

### Raspberry Pi の準備

Flask は Raspberry Pi 上で `pip3 install flask` を実行してインストールします。その後、以下のコマンドでサンプルプログラムを Raspberry Pi にダウンロードして、`python3 ip_access.py` で実行します。Flask が立ち上がり、IP アクセスを待ち受けます。

```shell-session
wget https://raw.githubusercontent.com/nmikuni/lambda-soracom-raspi-led/main/raspberry_pi/ip_access.py
```

### AWS の準備

1. ダウンロードしたサンプルコードの `lambda/ip_access_pattern` ディレクトリ配下に移動します。
2. `cp sample.env .env` で ENV ファイルをコピーします。
3. `.env` に、これまでの手順で控えておいた認証情報や IMSI を記載します。
4. `sls deploy` コマンドでデプロイします。

Raspberry Pi と AWS の準備ができたら、Lambda から LED を操作しましょう。以下のようなテストイベントを実行します (今後の全パターンで共通です)。

LED をつける

```led-on.json
{
  "message": "電気つけて"
}
```

LED を消す

```led-off.json
{
  "message": "電気消して"
}
```

LED の状態を確認する

```led-check.json
{
  "message": "電気ついてる？"
}
```


Raspberry Pi 側のコンソールログを見ても、アクセスが来ていることがわかるかと思います。

## アプリケーションパターンの構築手順

アプリケーションパターンでは Raspberry Pi 上で [paho-mqtt](https://pypi.org/project/paho-mqtt/) を使って MQTT クライアントとしてふるまいます。MQTT ブローカーには AWS IoT を用いて、LED オン・オフの指示を受けたり、自身の LED の状態を報告したりします。また、AWS IoT Shadow を利用することで、LED がとるべき状態 (`desired`)・現時点での LED の状態 (`reported`)・および desired と reported の差分 (`delta`) を管理します。SORACOM Beam を用いることで、AWS IoT の認証情報を Raspberry Pi に持たせることなく AWS IoT と接続できます。図にすると以下のとおりです。

![application.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125247/d544029a-babd-335c-0540-7d7a5052989b.png)

### AWS IoT と SORACOM Beam の準備

Raspberry Pi から SORACOM Beam 経由で AWS IoT Core へ接続します。以下のドキュメントを参照してください。

https://users.soracom.io/ja-jp/docs/beam/aws-iot-console/

なおこの時、モノの名前は `raspberry-pi`、Device Shadow には名前付きシャドウ `led` を作成してください (別の名前を使った場合は、サンプルコードの修正が必要になります)。

![image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125247/627cb850-495b-6d1d-872f-5f19be568a0b.png)
![image (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125247/930abdc2-29b3-5d9e-8ccf-982e1a5c8ce7.png)

また、SORACOM Beam の「ホスト名」に登録した AWS IoT Core の `xxxxx-ats.iot.ap-northeast-1.amazonaws.com` といったカスタムエンドポイントは後続の手順で使用するので控えておいてください。

Raspberry Pi から `mosquitto_pub -d -h beam.soracom.io -t beamdemo -m "Hello, World"` で AWS IoT へメッセージを送信できれば成功です。なお `mosquitto_pub` は  `sudo apt install mosquitto-clients` でインストールできます。

### AWS IoT Shadow の準備

AWS IoT Core のメニューよりサイドバーの「モノ」=> 「Device Shadow」タブ => 「led」(シャドウ名) を選択します。

![aws-iot-shadow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125247/4c89d6c1-a7d0-4acc-8dc8-65a93d2fcee2.png)

「編集」をクリックして、以下のように Shadow の初期状態を更新します。

```json
{
  "state": {
    "desired": {
      "led": "0"
    },
    "reported": {
      "led": "0"
    }
  }
}
```

### Raspberry Pi の準備

paho-mqtt は Raspberry Pi 上で `pip3 install paho-mqtt` を実行してインストールします。以下のコマンドでサンプルプログラムを Raspberry Pi にダウンロードして、`python3 application.py` で実行します。成功すれば一定間隔で LED の状態を SORACOM Beam 経由で AWS IoT へ Publish します。

```shell-session
wget https://raw.githubusercontent.com/nmikuni/lambda-soracom-raspi-led/main/raspberry_pi/application.py
```

### AWS の準備

1. ダウンロードしたサンプルコードの `lambda/application_pattern` ディレクトリ配下に移動します。
2. `cp sample.env .env` で ENV ファイルをコピーします。
3. `.env` に、これまでの手順で控えておいた認証情報や AWS IoT Core のカスタムエンドポイントを記載します。
4. `sls deploy` コマンドでデプロイします。

Raspberry Pi と AWS の準備ができたら、Lambda から LED を操作しましょう。Raspberry Pi 側のコンソールログを見ても、MQTT の メッセージが来ていることがわかるかと思います。

なお、今回は SORACOM Beam + MQTT を使いましたが、他にも [SORACOM Inventory](https://soracom.jp/services/inventory/) (LwM2M) や [SORACOM Krypton](https://soracom.jp/services/krypton/) (認証情報を SORACOM から取ってきて用いる) を使った実装も考えられます。

## デバイスリードパターンの構築手順

デバイスリードパターンでは Raspberry Pi の LED 状態を SIM のタグに保管します。Raspberry Pi は一定間隔でメタデータサービスを利用してタグの取得・更新をします。また Lambda から LED 情報の取得・更新をしたいときも SORACOM API を利用してSIM のタグへアクセスします。図にすると以下のとおりです。

![device-lead.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125247/0bb4ddcc-05c0-e0e7-2c9a-6149becd04b8.png)

### SORACOM の準備

以下のドキュメントを参照してメタデータサービスを有効にします。書き込みもするため、「読み取り専用」のチェックは外して下さい。

https://users.soracom.io/ja-jp/docs/air/use-metadata/

### Raspberry Pi の準備

以下のコマンドでサンプルプログラムを Raspberry Pi にダウンロードして、`python3 device_lead.py` で実行します。成功すれば一定間隔でタグに指定された LED の状態を取得して自身の LED へ反映し、自身の LED 状態をタグへ書き込みます。

```shell-session
wget https://raw.githubusercontent.com/nmikuni/lambda-soracom-raspi-led/main/raspberry_pi/device_lead.py
```

### AWS の準備

1. ダウンロードしたサンプルコードの `lambda/device_lead_pattern` ディレクトリ配下に移動します。
2. `cp sample.env .env` で ENV ファイルをコピーします。
3. `.env` に、これまでの手順で控えておいた認証情報や IMSI を記載します。
4. `sls deploy` コマンドでデプロイします。

Raspberry Pi と AWS の準備ができたら、Lambda から LED を操作しましょう。ほかのパターンと違って面白いのは、Raspberry Pi 側のコンソールログを見ると、Lambda から指示されたタイミングとは関係なく、自分のペースでタグの確認・LED の更新をしている点です。

なお、今回はタグを用いましたが、メタデータサービスのユーザーデータや、クラウド上の DB を使うことも考えられます。

## おわりに

ここまでお付き合いくださりありがとうございました。Lambda で IoT デバイスを操作するときのヒントになれば幸いです。かなり長文になったにもかかわらずまとめ切れていないところや説明が十分でないところもありますので、疑問点などあればコメントや [Twitter](https://twitter.com/n_mikuni) でご連絡ください。プログラムの解説や、LINE からの操作についてはまたどこかでブログに起こしたいです。