Raspberry PiにAWS IoT Greengrass V2をインストールしてLEDの点滅をリモートモニタリングする

![Screen Shot 2021-12-13 at 20.55.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198011/31ed8854-a942-9a82-79c0-e956a1d02762.png)

# はじめに
仕事でIoTプロジェクトにジョインしたため、事前キャッチアップとして簡単なIoTシステムを構築してみた。構成はシンプルで、クラウド側にAWS IoT Core、エッジ側のデバイスにRaspberry Pi 4を使ってデバイスのリモートモニタリングを試すというもの。

Raspberry PiにはスイッチのON/OFFでLEDが点滅する電子回路を構築する。また、3秒周期でGreengrassコンポーネントからLEDの点滅のON/OFFを監視しつつ、クラウド側のIoT CoreにMQTTメッセージを送信する。
最終的には、クラウドのAWS IoT Coreコンソールから、Raspberry Piの点滅ステータスを確認できることを目指す。

### 目指すゴール
![002_GGV2_and_Rpi.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198011/7638b49a-c18c-215e-72e8-28680e1e2bbc.png "アーキテクチャ")

構築手順
1. Raspberry PiにLEDの点滅スイッチ回路を組む。
2. Raspberry PiにAWS IoT Greengrass V2をインストールする。
3. Raspberry PiでGreengrassコンポーネントを実装し、デプロイする。

スイッチとLEDの状態、MQTTで送信するステータスの関係は以下となる。

|スイッチの状態|LEDの状態|クラウドに送信するステータス|
|---|---|---|
|ON（押されている）|点灯|1|
|OFF（押されていない）|消灯|0|

IoTプロジェクトとしては最もシンプルな構成である。しかし、クラウド側の多岐にわたるIoT系サービスをいろいろ試す際にエッジ側は複雑でないほうが良いと思い、この構成を採択した。

### ソフトウェアVer情報
- Raspberry Pi 4
- Raspbian Ver.11
- Python 3.9.2
- pip 20.3.4
- Java 11.0.13
- aws cli 1.22.23

# Raspberry Piのセットアップ
Raspberry Piを使うには、キーボード、マウス、ディスプレイ、電源アダプタ、MicroSDカード（OSとストレージ）、SDカードリーダーといった周辺機器が必要となる。

PCで[こちら](https://www.raspberrypi.com/software/)からダウンロードしたRaspbian OSをMicroSDカードに書き込み、Raspberry PiにMicroSDカードを差し込む。電源を入れるとRaspberry Piが起動して、ディスプレイにRaspbian OSの初期画面が表示されるはずだ。詳しいやり方は[こちら](https://www.indoorcorgielec.com/resources/raspberry-pi/raspberry-pi-os%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB/#about-raspberry-pi-os)を参考にさせて頂いた。

初期設定を終えたら、OSをアップデートしておく。

```shell
$ sudo apt update
$ sudo apt full-upgrade -y
$ sudo apt autoremove -y
$ sudo apt clean
$ sudo reboot  # 再起動
```

# Raspberry PiにLEDの点滅スイッチ回路を組む
![003_Rpi.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198011/2a49e6cb-ce80-cc7a-d6b7-3ac403103740.png "LED点滅スイッチ回路")
Raspberry Piと以下材料を使い、LEDの点滅スイッチ回路を組んでいく。

- ブレッドボード × 1
- 抵抗 1kΩ × 1、330Ω × 1
- 赤LED × 1
- ジャンプワイヤ オス・メス × 4
- ジャンプワイヤ オス・オス × 数本
- スイッチ × 1

Raspberry Piと電子回路の基礎は、こちらがおすすめ。上記のLED点滅回路がより詳細にわかりやすく解説されています。
<a target="_blank" href="https://www.amazon.co.jp/gp/product/4065193397/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=4065193397&linkCode=as2&tag=polawork-22&linkId=5fc67c1236bb3add822bb05aa4d88cea">ラズパイ4対応 カラー図解 最新 Raspberry Piで学ぶ電子工作 作る、動かす、しくみがわかる! (ブルーバックス)</a>

[こちら](https://www.amazon.co.jp/gp/product/B01M6ZFNSS/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=B01M6ZFNSS&linkCode=as2&tag=polawork-22&linkId=b140a77f87b7980e345a49b928e09607)はおすすめの電子工作セット。

この回路を動かすためのPythonスクリプトは以下となる。

blink_led.py

```python
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(25, GPIO.OUT)
GPIO.setup(24, GPIO.IN)

while True:
    if GPIO.input(24) == GPIO.HIGH:
        GPIO.output(25, GPIO.HIGH)
    else:
        GPIO.output(25, GPIO.LOW)

    time.sleep(3)
```

Raspberry Piでターミナルを開き、blink_led.py スクリプトを設置する。
スクリプトを実行すると、回路が動き始める。

```shell
$ python blink_led.py
```

この回路を簡単に説明する。

- スイッチを押すと、GPIO 24ピンが電気信号の入力を検知し、`GPIO.input(24) == GPIO.HIGH` がTrueとなる。
すると、GPIO 25ピンに電流が流れ、LEDが点灯する。
- スイッチを離すと、GPIO 24ピンが電気信号のOFFを検知し、`GPIO.input(24) == GPIO.HIGH` がFalseとなる。
すると、GPIO 25ピンへの電流が止まり、LEDが消灯する。
- 以上を、3秒おきに繰り返す。

# Raspberry Piとクラウドを連携させる
### AWS IoT Greengrass V2をインストール
![004_GGV2_and_Rpi.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198011/7fac77d9-2c0c-f22e-3aac-1ae1d42ee776.png)

Raspberry PiでAWS IoT Greengrassを動かすための準備をしていく。
公式の入門チュートリアルに沿って、Greengrass V2をセットアップする。

https://docs.aws.amazon.com/ja_jp/greengrass/v2/developerguide/getting-started.html

#### Raspberry Pi に Java ランタイムをインストール

```shell
$ sudo apt install default-jdk
$ java -version  # バージョン確認
```

#### Raspberry Pi に AWS CLI をインストール

```shell
$ sudo pip3 install awscli --upgrade
$ aws configure    # 登録済みのAWSアカウントでCLIの初期設定を行う
```

#### Raspberry Pi に Greengrassをセットアップ
Raspberry Pi に Greengrassをインストールするには、AWSコンソールで必要事項を入力し、表示されたインストーラのダウンロードコマンドとインストールコマンドを Raspberry Pi で実行するだけである。

まずはコアデバイスの新規セットアップ画面で、任意のコアデバイス名、モノのグループ名、インストール先のOSを選択。そうすると、画面下部にインストーラのダウンロードコマンドと、インストーラの実行コマンドが表示される。

![Screen Shot 2021-12-14 at 16.47.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198011/e71a17b7-ae13-ff15-e582-32a11af2ee90.png)

![Screen Shot 2021-12-14 at 16.50.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198011/bb79c6ba-27d7-7556-4aff-6b7b9a627378.png)

![Screen Shot 2021-12-14 at 16.52.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198011/ab2f2f40-01ea-38f4-f791-f360ba96bb0d.png)

インストーラの実行にはAWS認証が必要となるため、予めAWSアカウント情報を環境変数にセットしておく。

```shell
$ export AWS_ACCESS_KEY_ID=<AWS_ACCESS_KEY_ID>
$ export AWS_SECRET_ACCESS_KEY=<AWS_SECRET_ACCESS_KEY>
```

次に、Greengrassインストーラをダウンロードする。Raspberry Piのターミナルで、AWSコンソールで表示されたインストーラのダウンロードコマンドを実行。

```shell
$ curl -s https://d2s8p88vqu9w66.cloudfront.net/releases/greengrass-nucleus-latest.zip > greengrass-nucleus-latest.zip && unzip greengrass-nucleus-latest.zip -d GreengrassCore
```

続けてAWSコンソールで表示されたインストーラの実行コマンドも実行。

```shell
$ sudo -E java -Droot="/greengrass/v2" -Dlog.store=FILE -jar ./GreengrassCore/lib/Greengrass.jar --aws-region ap-northeast-1 --thing-name test-device-1 --thing-group-name test-group-1 --component-default-user ggc_user:ggc_group --provision true --setup-system-service true --deploy-dev-tools true
```

実行すると、Greengrassのコアデバイスと、AWSと通信するための証明書が Raspberry Pi にインストールされる。また、AWSコンソールのGreengrass コアデバイス一覧では、Raspberry PiにインストールしたGreengrassコアデバイスが登録されていることが確認できる。

#### Raspberry Pi に AWS IoT SDK for Python v2 をインストール
Raspberry Pi にこれから実装するGreengrassコンポーネントで使用する AWS IoT SDK for Python v2 をインストールする。

```shell
$ sudo -H pip3 install awsiotsdk
```

#### Greengrassコンポーネント実行ユーザー（ggc_user）をシリアルポートアクセス権限を持つグループに追加
Greengrass のコンポーネントはggc_userで実行される。しかし、デフォルトではRaspberry PiのシリアルポートとGPIOピンにアクセスができない。そのため、ggc_userを以下のグループに追加する。

```shell
$ sudo gpasswd -a ggc_user dialout
$ sudo gpasswd -a ggc_user gpio
```

### Greengrassコンポーネントを実装し、デプロイする
![005_GGV2_and_Rpi.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198011/22fb0206-02a3-2e94-c157-da64645eee04.png)

Greengrass V2では、コンポーネントという単位のモジュールを開発する。今回は、エッジデバイス内で実装したコンポーネントを、Greengrass CLI でデプロイしてみる。

コンポーネントはアーティファクトとレシピで構成されている。

#### アーティファクト
実行スクリプト、バイナリ、その他リソースなど。
エッジデバイスに設置するアーティファクトのパスは以下に決められている。
`artifacts/{componentName}/{componentVersion}/script`

以下にアーティファクトのスクリプトを設置する。

```shell
$ mkdir -p /home/pi/components/artifacts/com.example.BlinkLed/1.0.0/
$ touch /home/pi/components/artifacts/com.example.BlinkLed/1.0.0/blink_led.py
```

blink_led.py

```python
import RPi.GPIO as GPIO
import time
import datetime
import json
import awsiot.greengrasscoreipc
from awsiot.greengrasscoreipc.model import (
    QOS,
    PublishToIoTCoreRequest
)

GPIO.setmode(GPIO.BCM)
GPIO.setup(25, GPIO.OUT)
GPIO.setup(24, GPIO.IN)

TIMEOUT = 10
topic = "ggv2/rpi/led1"
qos = QOS.AT_LEAST_ONCE

ipc_client = awsiot.greengrasscoreipc.connect()

status = 0
while True:
    if GPIO.input(24) == GPIO.HIGH:
        GPIO.output(25, GPIO.HIGH)
        status = 1
    else:
        GPIO.output(25, GPIO.LOW)
        status = 0

    message = {
        "timestamp": str(datetime.datetime.now()),
        "led_status": status
    }
    message_json = json.dumps(message).encode('utf-8')

    request = PublishToIoTCoreRequest()
    request.topic_name = topic
    request.payload = message_json
    request.qos = qos
    operation = ipc_client.new_publish_to_iot_core()
    operation.activate(request)
    future = operation.get_response()
    future.result(10)

    with open('/tmp/Greengrass_BlinkLed.log', 'a') as f:
        print(f"{str(datetime.datetime.now())} / status: {status}.", file=f)

    time.sleep(3)
```

このコードは、上記の `blink_led.py` を拡張した内容となっていることに気づいただろうか。
Raspberry Piでは、PythonなどのスクリプトによってRaspberry Piで組まれた電子回路の様々な機能を制御可能である。クラウド（AWS IoT Core）にエッジデバイス情報をMQTTメッセージ送信する処理に加え、LEDの点滅スイッチの制御処理を加えることで、Greengrassコンポーネントという単位でリモートモニタリングのためのスクリプトを管理できる。

#### レシピ
設定パラメータ、依存関係、ライフサイクル、互換性を指定するメタ情報。

以下にアーティファクトのスクリプトを設置する。

```shell
$ touch /home/pi/components/recipes/com.example.BlinkLed-1.0.0.yaml
```

com.example.BlinkLed-1.0.0.yaml

```yaml
---
RecipeFormatVersion: 2020-01-25
ComponentName: com.example.BlinkLed
ComponentVersion: '1.0.0'
ComponentConfiguration:
  DefaultConfiguration:
    accessControl:
      aws.greengrass.ipc.mqttproxy:
        com.example.BlinkLed:publish:1:
          operations:
            - "aws.greengrass#PublishToIoTCore"
          resources:
            - "ggv2/rpi/led1"
Manifests:
  - Platform:
      os: linux
  - Lifecycle:
      Run: |
        python3 -u {artifacts:path}/blink_led.py
```

レシピでは、`accessControl` にてIoT CoreへのPublishを許可する設定が必要となる。
`resources` では、MQTTメッセージ送信先となる AWS IoT Core のトピック名を記載する。

アーティファクトとレシピが以下のように設置されていることを確認する。

```shell
/home/pi/components
    ├── artifacts
    │   └── com.example.BlinkLed
    │       └── 1.0.0
    │           └── blink_led.py
    └── recipes
        └── com.example.BlinkLed-1.0.0.yaml
```

ここまで来て、ようやくデプロイを実行できるようになる。
デプロイは、[Greengrass CLI](https://docs.aws.amazon.com/ja_jp/greengrass/v2/developerguide/gg-cli-reference.html)を使用する。このコマンドを使うことにより、コンポーネントのデプロイやリスタート、停止や削除などが実行できる。

では、デプロイを実行してみよう。

```shell
$ sudo /greengrass/v2/bin/greengrass-cli deployment create \
   --recipeDir /home/pi/components/recipes \
   --artifactDir /home/pi/components/artifacts \
   --merge "com.example.BlinkLed=1.0.0"
```

スクリプトで出力しているログを確認。

```shell
$ $ tail -f /tmp/Greengrass_BlinkLed.log
```


### エッジデバイスのLED点滅切り替えをクラウドでリモートモニタリングする
![006_GGV2_and_Rpi.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198011/9ee482cd-4c01-4936-aa1d-4d7c22d14f9d.png)

エッジ側でのデプロイが完了したら、クラウド側でエッジ側のLED点滅ステータスがリモートモニタリングできる状態になっている。

![Screen Shot 2021-12-13 at 20.55.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198011/31ed8854-a942-9a82-79c0-e956a1d02762.png)

回路のスイッチをON/OFFにしてLEDが点滅することを確認してみる。

![Screen Shot 2021-12-12 at 19.25.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198011/2974150d-08c6-ccb4-ddd6-40b11384461f.png)

AWS IoT Coreのテストクライアントにて、スクリプトで指定したトピック名 `ggv2/rpi/led1` でサブスクライブしてみると、エッジ側のLEDの点滅ステータスがリアルタイムでモニタリングできていることが確認できる。

# 最後に
Greengrassコンポーネントのコードについては以下で共有していますので、Star押してもらえたら嬉しいです！

https://github.com/dsonoda/Aws-IoT-Edge-Architecture-Samples

[次回](https://qiita.com/dsonoda/items/b2e6557f9bfa29ecee14)はRaspberry PiとAWS IoT Events を連携させ、デバイスのステートマシンを構築してみます。

https://qiita.com/dsonoda/items/b2e6557f9bfa29ecee14