AWS IoTのThing Shadowを気軽に試してみる with mosquitto

AWS IoTを色々と試してはいたのですが、よく目にするThing Shadowに関しては説明文だけではいまいちピンときませんでした。とりあえずshadowを触ってみたら、仕組みや出来ることのイメージがつきました。
簡単に要点を5つ書きます。

- Thing Shadowは、デバイスの状態を管理することのできる機能。
- Thing Shadowで使えるtopic名は、あらかじめ決まっている。（記事投稿時点で、11個⇒一応全部試した結果を下に書きました）
- Thing Shadowへデバイスの状態を送るには、JSON形式で"state"セクションを記述したものをpublishする。
- 上記"state"セクションには、デバイスの現在の状態を通知するための"reported"セクションと、デバイスへの指示を通知するための"desired"セクションが存在する。
- Thing Shadowへのsubscribeによって受け取ったJSONファイルには、デバイスの状態"state"の他、タイムスタンプなどの"metadata"が含まれる。

ここでは気軽にmosquittoを使って試した結果を載せます。

前提条件は、
・mosquitto-clientsを利用して、AWS IoTとのPub/Subができていること
https://qiita.com/TKYK38/items/2ca19b27503f6e0dfc84
です。

#### AWSコンソールでシャドウドキュメントを開いておく
これを開きながら作業すると、状態が更新されていくところがよく理解できます。
（IoTコンソール > 管理 > モノ > シャドウ　で開けます）
![shadow_mod.png](https://qiita-image-store.s3.amazonaws.com/0/207718/e6798cfa-4504-1942-3c62-ac43d70118c5.png)

#### publish用のサンプルスクリプト

```bash:pub.shadow.sh
#!/bin/bash

endpoint=`aws iot describe-endpoint`

keydir=/home/ubuntu/iot_sdk

### update
topic=\$aws/things/EC2_ubuntu/shadow/update

### get
#topic=\$aws/things/EC2_ubuntu/shadow/get

### delete
#topic=\$aws/things/EC2_ubuntu/shadow/delete

#ifile=shadow.desired.json
ifile=shadow.reported.json

mosquitto_pub --cafile ${keydir}/root-CA.crt --cert ${keydir}/EC2_ubuntu.cert.pem --key ${keydir}/EC2_ubuntu.private.key -h "${endpoint}" -p 8883 -q 1 -t ${topic} -i mosquitto_pub -f ${ifile}
```

#### subscribe用のサンプルスクリプト
```bash:sub.shadow.sh
endpoint=`aws iot describe-endpoint`

keydir=/home/ubuntu/iot_sdk

topic=\$aws/things/EC2_ubuntu/shadow/update
#topic=\$aws/things/EC2_ubuntu/shadow/update/accepted
#topic=\$aws/things/EC2_ubuntu/shadow/update/documents
#topic=\$aws/things/EC2_ubuntu/shadow/update/rejected
#topic=\$aws/things/EC2_ubuntu/shadow/update/delta
#topic=\$aws/things/EC2_ubuntu/shadow/get
#topic=\$aws/things/EC2_ubuntu/shadow/get/accepted
#topic=\$aws/things/EC2_ubuntu/shadow/get/rejected
#topic=\$aws/things/EC2_ubuntu/shadow/delete
#topic=\$aws/things/EC2_ubuntu/shadow/delete/accepted
#topic=\$aws/things/EC2_ubuntu/shadow/delete/rejected

mosquitto_sub --cafile ${cadir}/root-CA.crt --cert ${keydir}/tmp.cert.txt --key ${keydir}/tmp.private.txt -h "${endpoint}" -p 8883 -q 1 -t ${topic}
```

#### デバイス状態を通知するためのJSONサンプル

```json:shadow.reported.json
{
    "state" : {
        "reported" : {
            "color" : "yellow",
            "power" : "on"
         }
     }
}
```

#### デバイスへ指示（状態更新）するためのJSONサンプル

```json:shadow.desired.json
{
    "state" : {
        "desired" : {
            "color" : "red",
            "power" : "on"
         }
     }
}
```

## デバイス状態の更新 /update

#### /update/accepted をsubした状態で、/updateへshadow.reported.jsonをpubする
以下のようなJSONをsubscribeできる。

```json
{"state":{"reported":{"color":"yellow","power":"on"}},"metadata":{"reported":{"color":{"timestamp":1512807898},"power":{"timestamp":1512807898}}},"version":13,"timestamp":1512807898}
```

#### /update/documents をsubした状態で、/updateへshadow.reported.jsonをpubする
以下のようなJSONをsubscribeできる。

```json
{"previous":{"state":{"desired":{"color":"red","power":"on"},"reported":{"color":"blue","power":"on"}},"metadata":{"desired":{"color":{"timestamp":1512805884},"power":{"timestamp":1512805884}},"reported":{"color":{"timestamp":1512808170},"power":{"timestamp":1512808170}}},"version":17},"current":{"state":{"desired":{"color":"red","power":"on"},"reported":{"color":"blue","power":"on"}},"metadata":{"desired":{"color":{"timestamp":1512805884},"power":{"timestamp":1512805884}},"reported":{"color":{"timestamp":1512808184},"power":{"timestamp":1512808184}}},"version":18},"timestamp":1512808184}
```

#### /update/rejected をsubした状態で、/updateへshadow.reported.jsonをpubする
例えば、"reported"を"report"と変更し、pubしてみると、以下のようなエラー（JSON）をsubscribeできる。

```json
{"code":400,"message":"State contains an invalid node: 'report'"}
```

#### /update/delta をsubした状態で、/updateへshadow.reported.jsonをpubする
reportedとdesiredの差分がある場合にsubscribeできる。

```json
{"version":21,"timestamp":1512808331,"state":{"color":"red"},"metadata":{"color":{"timestamp":1512805884}}}
```

## デバイス状態の取得 /get


#### /get/accepted をsubした状態で、/getへメッセージをpubする
/getへpubすると、desiredとreported両方の情報をsubscribeできる。
(/getへpubするメッセージは何でもよい。)

```json
{"state":{"desired":{"color":"red","power":"on"},"reported":{"color":"yellow","power":"on"}},"metadata":{"desired":{"color":{"timestamp":1512805884},"power":{"timestamp":1512805884}},"reported":{"color":{"timestamp":1512808392},"power":{"timestamp":1512808392}}},"version":23,"timestamp":1512808573}
```

#### /get/rejected をsubした状態で、/getへメッセージをpubする
shadowが存在しない状態で、/getへpubすると、以下のようなエラー（JSON）をsubscribeできる。

```json
{"code":404,"message":"No shadow exists with name: 'EC2_ubuntu'"}
```

## デバイス状態の削除 /delete

#### /delete/accepted をsubした状態で、/deleteへメッセージをpubする
shadowが削除されると、以下のようなJSONをsubscribeできる。

```json
{"version":23,"timestamp":1512809286}
```

#### /delete/rejected をsubした状態で、/deleteへメッセージをpubする
shadowが存在しない状態で、shadowを削除しようとすると、以下のようなエラー（JSON）をsubscribeできる。

```json
{"code":404,"message":"No shadow exists with name: 'EC2_ubuntu'"}
```











## 参考情報
AWS IoTの開発者ガイドです。
[Thing Shadow の MQTT トピック](http://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/thing-shadow-mqtt.html)