デバイスは、デバイスシャドウの desired を null にしよう。なぜなら処理がシンプルになるからだ。
デバイスがIoT Coreに接続してデバイスシャドウを使っているとき、クラウドからの指示がdesired
に格納されます。
そして、デバイス側の状態がreported
に格納されます。
- desired
- デバイスに対して要求する状態を格納する
- reported
- デバイスが現在の状態を格納する
- delta
- desiredとreportedが異なる場合に存在する(AWS自動付与)
- 正確な仕様はドキュメントを参照
クラウドがデバイスに対して依頼を行ったとき、デバイスはdesired
をnull
にしようという話をしていきます。
デバイスシャドウの内容をシミュレーションしてみる
任意に光るLEDを持つデバイス(led-device)があるとします。このデバイスは下記のトピックをSubscribeしており、クラウドからの依頼を反映します。
- トピック: $aws/things/led-device/shadow/update/delta
なお、このデバイスはユーザも任意にLEDの色を変更可能とします。
1. 現在のLEDの状態は赤色とする
現在のLEDの状態は赤色です。
{ "reported": { "led": "red" } }
2. クラウドが「LEDを緑にしてね」と依頼する
このデバイスに対して、クラウドから「LEDを緑色にしてね」と依頼します。
- トピック: $aws/things/led-device/shadow/update
{ "state": { "desired": { "led": "green" } } }
依頼後のデバイスシャドウは下記です。
{ "desired": { "led": "green" }, "reported": { "led": "red" } }
そして、$aws/things/led-device/shadow/update/delta
に来たデータは下記です。デバイスはこのデータを元にLEDを緑に変更します。
{ "version": 3, "timestamp": 1596512574, "state": { "led": "green" }, "metadata": { "led": { "timestamp": 1596512574 } } }
3. LEDを緑にしたので、デバイスシャドウを更新する
LEDを緑に変更したので、デバイスはデバイスシャドウを更新します。
- トピック: $aws/things/led-device/shadow/update
{ "state": { "reported": { "led": "green" } } }
更新後のデバイスシャドウは下記です。
{ "desired": { "led": "green" }, "reported": { "led": "green" } }
差分がないため、$aws/things/led-device/shadow/update/delta
に対してデータは来ません。
4. ユーザがLEDの色を青に変更したので、デバイスシャドウを更新する
ユーザがLEDを青に変更したので、デバイスはデバイスシャドウを更新します。
- トピック: $aws/things/led-device/shadow/update
{ "state": { "reported": { "led": "blue" } } }
更新後のデバイスシャドウは下記です。
{ "desired": { "led": "green" }, "reported": { "led": "blue" } }
$aws/things/led-device/shadow/update/delta
にデータが来ました。……来ちゃいました。
{ "version": 5, "timestamp": 1596513537, "state": { "led": "green" }, "metadata": { "led": { "timestamp": 1596512574 } } }
5. デバイスは、deltaの内容に従ってLEDを更新……していいの?
このとき、LEDを最後に変更したのはユーザであり、その際の色は青でした。
そのため/update/delta
の内容に従ってLEDを緑に変更する動作は求めていません。
デバイスはどのように動作すれば良いでしょうか?
このあたりを対応する方法のひとつとして、下記のトピックに空データをPublishして最新のデバイスシャドウを取得します。
- トピック: $aws/things/led-device/shadow/get
取得したデバイスシャドウは下記です。このデバイスシャドウを元にして「desired
のタイムスタンプより、reported
のタイムスタンプが新しければ、クラウドの要求に従って動作したものとみなす」という判断をすることは可能です。(ただし、クラウドの要求を反映したのかユーザの要求を反映したのかは分からない)
{ "state": { "desired": { "led": "green" }, "reported": { "led": "blue" }, "delta": { "led": "green" } }, "metadata": { "desired": { "led": { "timestamp": 1596512574 } }, "reported": { "led": { "timestamp": 1596513537 } } }, "version": 5, "timestamp": 1596514164 }
とはいえ、こんなことをするのはめんどくさいです。そこで出てくるのがdesiredをnullにしようという話です。
デバイスシャドウの内容をシミュレーションしてみる(desiredをnullにする版)
2番目まで同じ動作を行います。
1. 現在のLEDの状態は赤色とする
下記のデバイスシャドウがあり、現在のLEDの状態は赤色です。
{ "reported": { "led": "red" } }
2. クラウドが「LEDを緑にしてね」と依頼する
このデバイスに対して、クラウドから「LEDを緑色にしてね」と依頼します。
- トピック: $aws/things/led-device/shadow/update
{ "state": { "desired": { "led": "green" } } }
依頼後のデバイスシャドウは下記です。
{ "desired": { "led": "green" }, "reported": { "led": "red" } }
そして、/update/delta
に来たデータは下記です。デバイスはこのデータを元にLEDを緑に変更します。
{ "version": 7, "timestamp": 1596515708, "state": { "led": "green" }, "metadata": { "led": { "timestamp": 1596515708 } } }
3. LEDを緑にしたので、デバイスシャドウを更新する(一緒にdesiredを削除する)
LEDを緑に変更したので、デバイスはデバイスシャドウを更新します。このとき、desired
の値をnull
にして削除します。
- トピック: $aws/things/led-device/shadow/update
{ "state": { "desired": { "led": null }, "reported": { "led": "green" } } }
更新後のデバイスシャドウは下記です。desired
が消えています。
{ "reported": { "led": "green" } }
差分がないため、$aws/things/led-device/shadow/update/delta
に対してデータは来ません。
4. ユーザがLEDの色を青に変更したので、デバイスシャドウを更新する
ユーザがLEDを青に変更したので、デバイスはデバイスシャドウを更新します。
- トピック: $aws/things/led-device/shadow/update
{ "state": { "reported": { "led": "blue" } } }
更新後のデバイスシャドウは下記です。スッキリしていますね。
{ "reported": { "led": "blue" } }
差分がないため、$aws/things/led-device/shadow/update/delta
に対してデータは来ません。
先ほどと異なり、デバイスは迷うこと無くシンプルに処理ができました。
さいごに
デバイスシャドウにdesired
が常に残り続けているとき、「クラウドが依頼したけどまだ未反映」なのか「デバイスは対応したけど、単に残っているだけ」なのかがパット見でも分かりません。何かあったときに人間が見ても分かりにくいですし、デバイスでロジックを組むにしても煩雑化して不具合の原因にもなりかねません。
デバイス側でdesired
をnull
にすると処理がシンプルになります。