Raspberry Piを使ってAWS IoTへ入門してみた

## はじめに
こんにちは！ KAGでエンジニアやっている**h_id32**です！

埃かぶってるRaspberryPiが家にあったので、勉強がてらAWS IoTに接続してみます。
今回は基本的なチュートリアルにとどめていますが、第二弾、第三弾と続けていきGreengrass/Device Shadowにも触れられたらなと思っています。

## IoT Coreのクイック接続でRaspberryPiと接続できるか試してみよう

まずは疎通確認も兼ねてAWS IoT Coreのクイック接続を利用して自宅環境のRaspberryPiと通信ができるか試してみます。

### 使用機材
- 埃かぶった RaspberryPi 3 Model B +
![スクリーンショット 2023-12-20 21.50.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516184/dee2b90e-ba3f-3be6-e44f-8a1880fca3f9.png)



:::note warn
今回自宅に余っていたRaspberryPiをそのまま使うがコンセプトなため、初期設定などには触れません。
:::


## AWS IoT
AWSのマネジメントコンソールからIoT Coreを選択

![スクリーンショット 2023-12-17 13.51.37_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516184/e7a5f0e3-09ce-f92d-0455-08f66336d655.png)

IoT Coreからデバイスを接続を選択
![スクリーンショット 2023-12-17 13.51.49_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516184/34f897d0-111e-048c-c110-4920a212826b.png)

1. デバイスを準備する

    記載されているping コマンドをRaspberryPiから実行しAWSのサーバに接続できるか確認

    ![スクリーンショット 2023-12-17 13.51.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516184/8fb4696d-fd14-79ca-051c-93333dd7c3dc.png)

    ``` bash
    ping hoge.iot.ap-northeast-1.amazonaws.com
    ```
    
    ```bash
    PING hoge.ap-northeast-1.amazonaws.com(2400:.... (2400:...)) 56 data bytes
    64 bytes from 2400:... (2400:...): icmp_seq=1 ttl=250 time=5.30 ms
    64 bytes from 2400:... (2400:...): icmp_seq=1 ttl=250 time=5.13 ms
    ```

    よかった！成功ですね。
    ここで失敗する場合はネットワーク周りの環境を見直しましょう。
    
1. デバイスを登録して保護する

    IoTデバイスの名前としてモノの名前を設定します。「raspberry_pi_3」で作ります。

    ![スクリーンショット 2023-12-17 14.06.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516184/2fadb9ea-0c29-7a1b-4ad4-91484661a4e1.png)

1. プラットフォームとSDKを選択

    RaspberryPiなため、Linuxを選択しSDKはPythonを選択

    ![スクリーンショット 2023-12-17 14.07.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516184/5b3d98cc-3eaf-c425-25e5-74f00e2fc37e.png)

1. 接続キットをダウンロード

    ダウンロードした接続キットをscpなどを使ってRaspberryPiに送りそれを解凍する
    ![スクリーンショット 2023-12-17 14.07.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516184/d6392efa-698b-7193-cbc3-8d4880893a6d.png)
    
    ```bash
    -rw-r--r-- 1 pi pi 6423 Dec 17 14:10 connect_device_package.zip
    pi@raspberrypi:~/awsiot $
    pi@raspberrypi:~/awsiot $ unzip connect_device_package.zip
    Archive:  connect_device_package.zip
     extracting: raspberry_pi_3.cert.pem
     extracting: raspberry_pi_3.public.key
     extracting: raspberry_pi_3.private.key
     extracting: raspberry_pi_3-Policy
     extracting: start.sh
    pi@raspberrypi:~/awsiot $
    ```

1. 解凍してできた start.shに権限を付与

    ![スクリーンショット 2023-12-17 14.11.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516184/894ef899-3159-3ce5-8e0c-020410548375.png)

    ```bash
    pi@raspberrypi:~/awsiot $ chmod +x start.sh
    pi@raspberrypi:~/awsiot $ ls -l
    total 28
    -rw-r--r-- 1 pi pi 6423 Dec 17 14:10 connect_device_package.zip
    -rw-r--r-- 1 pi pi 1224 Dec 17 05:07 raspberry_pi_3.cert.pem
    -rw-r--r-- 1 pi pi 1098 Dec 17 05:07 raspberry_pi_3-Policy
    -rw-r--r-- 1 pi pi 1675 Dec 17 05:07 raspberry_pi_3.private.key
    -rw-r--r-- 1 pi pi  451 Dec 17 05:07 raspberry_pi_3.public.key
    -rwxr-xr-x 1 pi pi 1367 Dec 17 05:07 start.sh
    ```

1. start.shを実行

    SDKをダウンロードししサンプルアプリケーションを走らせます
    ```bash
    pi@raspberrypi:~/awsiot $ ./start.sh
    
    Downloading AWS IoT Root CA certificate from AWS...
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100  1188  100  1188    0     0   4790      0 --:--:-- --:--:-- --:--:--  4790
    
    Cloning the AWS SDK...
    Cloning into 'aws-iot-device-sdk-python-v2'...
    remote: Enumerating objects: 2472, done.
    remote: Counting objects: 100% (953/953), done.
    remote: Compressing objects: 100% (250/250), done.
    remote: Total 2472 (delta 783), reused 774 (delta 689), pack-reused 1519
    Receiving objects: 100% (2472/2472), 2.11 MiB | 4.94 MiB/s, done.
    Resolving deltas: 100% (1614/1614), done.
    
    Installing AWS SDK...
    Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
    Processing ./aws-iot-device-sdk-python-v2
    Collecting awscrt==0.20.0
      Downloading awscrt-0.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (7.7 MB)
         |████████████████████████████████| 7.7 MB 48 kB/s
    Building wheels for collected packages: awsiotsdk
      Building wheel for awsiotsdk (setup.py) ... done
      Created wheel for awsiotsdk: filename=awsiotsdk-1.0.0.dev0-py3-none-any.whl size=73575 sha256=cba38b9290b0313161ed583523f4e42963cdd0807a8616ed9231f6e9c19454ac
      Stored in directory: /home/pi/.cache/pip/wheels/af/fc/a4/e58680f127da99f9fd9c68f33e690c8e9e7a8d796345826e61
    Successfully built awsiotsdk
    Installing collected packages: awscrt, awsiotsdk
    Successfully installed awscrt-0.20.0 awsiotsdk-1.0.0.dev0
    ```

    SDKのインストールが完了したのちしばらくするとサンプルアプリケーションが動作しはじめます。
    ```bash
    Running pub/sub sample application...
    Connecting to hoge.iot.ap-northeast-1.amazonaws.com with client ID 'basicPubSub'...
    Connection Successful with return code: 0 session present: False
    Connected!
    Subscribing to topic 'sdk/test/python'...
    Subscribed with QoS.AT_LEAST_ONCE
    Sending messages until program killed
    Publishing message to topic 'sdk/test/python': Hello World!  [1]
    Received message from topic 'sdk/test/python': b'"Hello World!  [1]"'
    Publishing message to topic 'sdk/test/python': Hello World!  [2]
    Received message from topic 'sdk/test/python': b'"Hello World!  [2]"'
    Publishing message to topic 'sdk/test/python': Hello World!  [3]
    Received message from topic 'sdk/test/python': b'"Hello World!  [3]"'
    Publishing message to topic 'sdk/test/python': Hello World!  [4]
    Received message from topic 'sdk/test/python': b'"Hello World!  [4]"'
    Publishing message to topic 'sdk/test/python': Hello World!  [5]
    Received message from topic 'sdk/test/python': b'"Hello World!  [5]"'
    Publishing message to topic 'sdk/test/python': Hello World!  [6]
    Received message from topic 'sdk/test/python': b'"Hello World!  [6]"'
    Publishing message to topic 'sdk/test/python': Hello World!  [7]
    Received message from topic 'sdk/test/python': b'"Hello World!  [7]"'
    Publishing message to topic 'sdk/test/python': Hello World!  [8]
    Received message from topic 'sdk/test/python': b'"Hello World!  [8]"'
    Publishing message to topic 'sdk/test/python': Hello World!  [9]
    Received message from topic 'sdk/test/python': b'"Hello World!  [9]"'
    Publishing message to topic 'sdk/test/python': Hello World!  [10]
    Received message from topic 'sdk/test/python': b'"Hello World!  [10]"'
    Publishing message to topic 'sdk/test/python': Hello World!  [11]
    Received message from topic 'sdk/test/python': b'"Hello World!  [11]"'
    Publishing message to topic 'sdk/test/python': Hello World!  [12]
    Received message from topic 'sdk/test/python': b'"Hello World!  [12]"'
    Publishing message to topic 'sdk/test/python': Hello World!  [13]
    Received message from topic 'sdk/test/python': b'"Hello World!  [13]"'
    ```
    AWSのコンソールを確認するとサンプルアプリケーションで送信されたメッセージがサブスクリプションされていることを確認できます。
    ![スクリーンショット 2023-12-17 14.14.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516184/9ded3254-a555-fbc7-dc26-bb3391f82378.png)


これにてクイック接続を用いたAWS IoTとの連携は完了となります。
思ったより簡単に疎通ができてびっくりですね！
次はAWSが用意しているAWS IoT Device Clientを用いた[チュートリアル](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-tutorials-dc-intro.html)をやってみます。

---

## AWS IoT Device Client でデモを構築する

チュートリアルは以下の4つの順となっています。デバイスの準備はほぼほぼ完了しているため一部の手順をスキップします。
1. [チュートリアル: AWS IoT Device Client 用のデバイスの準備](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-dc-prepare-device.html)
2. [チュートリアル: AWS IoT Device Client のインストールと設定](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-dc-install-dc.html)
3. [チュートリアル: AWS IoT Device Client との MQTT メッセージ通信をデモンストレーションする](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-dc-testconn.html)
4. [チュートリアル: AWS IoT Device Client でのリモートアクション (ジョブ) をデモンストレーションする](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-dc-runjobs.html)


### チュートリアル: AWS IoT Device Client 用のデバイスの準備

#### AWS Command Line Interface をインストールする

手順に則りAWS CLIをインストール
```bash
export PATH=$PATH:~/.local/bin # configures the path to include the directory with the AWS CLI
git clone https://github.com/aws/aws-cli.git # download the AWS CLI code from GitHub
cd aws-cli && git checkout v2 # go to the directory with the repo and checkout version 2
pip3 install -r requirements.txt # install the prerequisite software
```

```bash
pip3 install . # install the AWS CLI 
```
バージョンを確認し、2.2以降であることを確認

```bash
pi@raspberrypi:~ $ aws --version
aws-cli/2.15.2 Python/3.9.2 Linux/6.1.21-v8+ source/aarch64.debian.11 prompt/off
pi@raspberrypi:~ $
```

#### AWS アカウント 認証情報を設定する

AWSのIAMユーザを作成し、raspberrypi用のAWSアカウントを作成します。
※最低限の権限だけ付与することをお勧めします。




#### AWS アカウント 認証情報を設定する

作成したIAMユーザの認証情報を設定する
```
aws configure
```

```
AWS Access Key ID [None]: hoge
AWS Secret Access Key [None]: fuga
Default region name [None]: ap-northeast-1
Default output format [None]: json
```

以下のコマンドを実行し、AWSの認証情報が正しく設定されていることを確認

```bash
pi@raspberrypi:~/aws-cli $ aws iot describe-endpoint --endpoint-type iot:Data-ATS
{
    "endpointAddress": "hogehoge.iot.ap-northeast-1.amazonaws.com"
}
pi@raspberrypi:~/aws-cli $
```



### チュートリアル: AWS IoT Device Client のインストールと設定

#### AWS IoT Device Client をダウンロードして保存する

Raspberry Pi に AWS IoT Device Client をダウンロードしてビルドします。
```bash
cd ~
git clone https://github.com/awslabs/aws-iot-device-client aws-iot-device-client
mkdir ~/aws-iot-device-client/build && cd ~/aws-iot-device-client/build
cmake ..
```

AWS IoT Device Client をビルドします。
このコマンドは完了までに、最大で 15 分かかるらしいです。
```bash
cmake --build . --target aws-iot-device-client
```

次のコマンドを実行してテストします。

```bash
pi@raspberrypi:~/aws-iot-device-client/build $ ./aws-iot-device-client --help


	AWS IoT Device Client BINARY

For more documentation, see https://github.com/awslabs/aws-iot-device-client

Available sub-commands:

--help:									Get more help on commands
--version:								Output current version
--export-default-settings <JSON-File-Location>:				Export default settings for the AWS IoT Device Client binary to the specified file and exit program
--config-file <JSON-File-Location>:					Take settings defined in the specified JSON file and start the binary
--log-level <[DEBUG, INFO, WARN, ERROR]>:				Specify the log level for the AWS IoT Device Client
--log-type <[STDOUT, FILE]>:						Specify the logger implementation to use.
--log-file <File-Location>:						Write logs to specified log file when using the file logger.
--enable-sdk-logging 							Enable SDK Logging.
....
...
..
.
pi@raspberrypi:~/aws-iot-device-client/build $
```
コマンド成功してホッとしました。

#### チュートリアルで使用するディレクトリを作成する

次のコマンドを実行して、必要なディレクトリを作成します。
```bash
mkdir ~/dc-configs
mkdir ~/policies
mkdir ~/messages
mkdir ~/certs/testconn
mkdir ~/certs/pubsub
mkdir ~/certs/jobs
```

```bash
chmod 745 ~
chmod 700 ~/certs/testconn
chmod 700 ~/certs/pubsub
chmod 700 ~/certs/jobs
```



### AWS IoT で Raspberry Pi をプロビジョニングする

デバイスのデバイス証明書ファイルを作成
```bash
mkdir ~/certs/testconn
aws iot create-keys-and-certificate \
--set-as-active \
--certificate-pem-outfile "~/certs/testconn/device.pem.crt" \
--public-key-outfile "~/certs/testconn/public.pem.key" \
--private-key-outfile "~/certs/testconn/private.pem.key"
```
AWS IoT リソースの作成
権限絞っていたためAWS CloudShellを使ってリソース作成しました！めっちゃ便利ですね！


AWS アカウント のデバイスデータエンドポイントのアドレスを取得します。
```bash
aws iot describe-endpoint --endpoint-type IoT:Data-ATS
```

Raspberry Pi 用の AWS IoT のモノのリソースを作成します。
```bash
aws iot create-thing --thing-name "DevCliTestThing"
```


ポリシードキュメントを作成します。
（こういった作業もCloudShellでできるんですね、すごい。。。！）

```json:dev_cli_test_thing_policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iot:Publish",
                "iot:Subscribe",
                "iot:Receive",
                "iot:Connect"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
```
ポリシードキュメントを使用して AWS IoT ポリシーを作成します。

```bash
aws iot create-policy \
--policy-name "DevCliTestThingPolicy" \
--policy-document "file://~/dev_cli_test_thing_policy.json"
```
ポリシーをデバイス証明書にアタッチします。
```bash
aws iot attach-policy \
--policy-name "DevCliTestThingPolicy" \
--target "certificateArn"
```

デバイス証明書を AWS IoT のモノのリソースにアタッチします。

```bash
aws iot attach-thing-principal \
--thing-name "DevCliTestThing" \
--principal "certificateArn"
```


### AWS IoT Device Client を設定して接続をテストする
`~/dc-configs/dc-testconn-config.json`に以下のjsonを配置します。

```json:dc-testconn-config.json
{
  "endpoint": "hogehoge-ats.iot.us-west-2.amazonaws.com",
  "cert": "~/certs/testconn/device.pem.crt",
  "key": "~/certs/testconn/private.pem.key",
  "root-ca": "~/certs/AmazonRootCA1.pem",
  "thing-name": "DevCliTestThing",
  "logging": {
    "enable-sdk-logging": true,
    "level": "DEBUG",
    "type": "STDOUT",
    "file": ""
  },
  "jobs": {
    "enabled": false,
    "handler-directory": ""
  },
  "tunneling": {
    "enabled": false
  },
  "device-defender": {
    "enabled": false,
    "interval": 300
  },
  "fleet-provisioning": {
    "enabled": false,
    "template-name": "",
    "template-parameters": "",
    "csr-file": "",
    "device-key": ""
  },
  "samples": {
    "pub-sub": {
      "enabled": true,
      "publish-topic": "test/dc/pubtopic",
      "publish-file": "",
      "subscribe-topic": "test/dc/subtopic",
      "subscribe-file": ""
    }
  },
  "config-shadow": {
    "enabled": false
  },
  "sample-shadow": {
    "enabled": false,
    "shadow-name": "",
    "shadow-input-file": "",
    "shadow-output-file": ""
  }
}
```

権限を644に設定します。
```bash
pi@raspberrypi:~ $ chmod 644 ~/dc-configs/dc-testconn-config.json
```

作成したjsonファイルを指定して AWS IoT Device Client を実行します。

:::note warn
手順にはないのですが、実行ユーザの権限によってはディレクトリが作成できないというエラーが出てしまうため
以下のコマンドで作成しましょう。
```
sudo mkdir /var/log/aws-iot-device-client
sudo chmod 745 /var/log/aws-iot-device-client
sudo chown pi:pi /var/log/aws-iot-device-client
```
:::


```bash
pi@raspberrypi:~/aws-iot-device-client/build $ ./aws-iot-device-client --config-file ~/dc-configs/dc-testconn-config.json
2023-12-19T14:19:33.612Z [WARN]  {Config.cpp}: Key {publish-file} was provided in the JSON configuration file with an empty value
2023-12-19T14:19:33.612Z [WARN]  {Config.cpp}: Key {subscribe-file} was provided in the JSON configuration file with an empty value
2023-12-19T14:19:33.612Z [INFO]  {Config.cpp}: Successfully fetched JSON config file: {
....
...
..
.
2023-12-19T14:20:01.556Z [INFO]  {Main.cpp}: Pub Sub Sample has stopped
2023-12-19T14:20:01.556Z [INFO]  {Main.cpp}: All features have stopped
2023-12-19T14:20:01.556Z [DEBUG] {SharedCrtResourceManager.cpp}: Attempting to disconnect MQTT connection
2023-12-19T14:20:01.559Z [INFO]  {SharedCrtResourceManager.cpp}: MQTT Connection is now disconnected
pi@raspberrypi:~/aws-iot-device-client/build $
```

AWSコンソールのMQTTテストクライアントでメッセージがサブスクライブできていることを確認します。

![スクリーンショット 2023-12-19 23.19.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516184/42945520-fe9a-06cb-23e6-35ba6c715ad7.png)

Hello World!出ました！やったー！！！！


----

### さいごに
今回はAWSが用意しているチュートリアルのうち、2つ目まで完了させました。
クイック接続と同じくMQTTメッセージを確認するといった結果は変わらないのに、手順はこうも違うのですね。
今回権限の関係でいくつかのコマンドをCloudShellから叩いたのですが、これが追加費用なしで利用可能なのに驚きました。

続きのチュートリアルは次の記事で予定しています！！！！　ではでは！！

[チュートリアル: AWS IoT Device Client との MQTT メッセージ通信をデモンストレーションする](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-dc-testconn.html)
[チュートリアル: AWS IoT Device Client でのリモートアクション (ジョブ) をデモンストレーションする](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-dc-runjobs.html)