👤

AWS IoT Device Shadowを理解する

に公開

AWS IoT Device Shadowとは何か

AWS IoT Device Shadowは、デバイスの「現在の状態」や「希望する状態」をクラウド上の「シャドウ」と呼ばれるデータとして保存しておくサービスです。具体的に以下のようなことができます。

  • デバイスがオフラインの状態でも、オフラインになる前に報告された最新の状態を参照し、オンラインになった際にデバイスが希望する状態に遷移してくれるように更新を行うことができる
  • シャドウの作成・更新・削除はAWS IoTのコンソール上を初めとして、AWS CLI、MQTT、REST APIが対応
  • デバイス1つに対して複数の名前付きシャドウが作成可能
  • シャドウはJson shadow documentsとしてデータの取得・保存を行う。JSONに記述されている内容は
    • desired:クラウド側がデバイスに望む状態
    • reported:デバイスが報告する実際の状態
    • delta:上記二つの差分
  • 上記JSONはそれぞれversionが発行されており、メッセージが到着する順番が前後した場合でも小さい番号のversionを無視することができる

上記ができることで、以下のような嬉しさがあります。

  • どこからでもデバイスの状態を確認・更新可能。
  • デバイスの電源が不安定/ネットワークが不安定でもとりあえず「こう変更してほしい」という命令を出しておける
  • 複数の名前付きシャドウを用いることで、カメラ制御、物体検知…といった機能ごとにシャドウを分けることができ、アクセス制御も機能ごとに分離できる。並列更新も可能

AWS IoT Device Shadowを用いた構成

下図のようなシンプルな構成を考えます。

シャドウを用いるためには、ShadowManagerコンポーネントをデバイスにデプロイする必要があります。

ShadowManagerコンポーネントのデプロイ

このコンポーネントにより、デバイス上でローカルシャドウ(クラウドのシャドウをローカルに持ってきたもの)とのやり取りが行えるようになります。具体的には、

  • ローカルシャドウはクラウド上のデバイスシャドウと同期。デバイスがオフライン時でもローカルに状態を保持・更新し、オンラインになった際に自動的に差分をクラウドに共有
  • デバイス上のアプリケーションがIPC経由でローカルシャドウを読み書きできる

などが行えるようになります。
デプロイ時に、コンポーネントとしてaws.greengrass.ShadowManagerを追加するだけでOKです。

また、もし「親デバイスと子デバイスがあり、子デバイスの情報もクラウドでやり取りしたい」場合などはaws.greengrass.clientdevices.mqtt.Bridgeコンポーネントのデプロイが必要になりますが、本記事ではこちらには触れません。

AWS IoT Device Shadowの使用例

例として、「温度・湿度を監視し、両方が設定された閾値を超えた場合にアラートを出すデバイス」を考えてみましょう。シャドウは下記のように双方向に読み書きが行われるとします。

  1. アプリケーションから設定を変更する場合(アプリケーションから設定を送り、クラウドを経由してデバイスの設定を変更する)
  2. デバイスから設定を変更する場合(デバイスで設定を変更し、クラウドの情報を書き換える)

このとき、MQTTを用いてシャドウがどのような順序でやり取りされるのかを説明します。

アプリケーションから設定を変更する場合

デバイスの初期状態を以下とします。

{
  "state": {
    "reported": {
      "alert_threshold": {
        "temperature": 38,
        "humidity": 80
      }
    }
  }
}

このシャドウでは、デバイスの現在の状態 (reported) として「温度38度、湿度80%をアラートの閾値としてますよ」ということが表されています。アプリケーション側が希望する状態 (desird) はまだありません。

  1. アプリケーションから「希望する状態」を送信
    アプリケーションからMQTTトピック$aws/things/{thingName}/shadow/updateに以下をPublish
{
  "state": {
    "desired": {
      "alert_threshold": {
        "temperature": 35,
        "humidity": 80
      }
    }
  }
}
  1. AWS IoTが自動で「差分」を発行
    クラウドが自動でMQTTトピック$aws/things/{thingName}/shadow/update/deltaに以下をPublish
{
  "version": 1,
  "timestamp": 1753671871,
  "state": {
    "alert_threshold": {
      "temperature": 35
    }
  },
  "metadata": {
    "alert_threshold": {
      "temperature": {
        "timestamp": 1753671871
      }
    }
  }
}
  1. デバイスが「変更すべき設定」を受信
    デバイスがMQTTトピック$aws/things/{thingName}/shadow/update/deltaをSubscribeしている場合、上記差分を受信し「温度を35度に設定」すればいいことが分かります

  2. デバイスが設定を変更し、現状をレポート
    デバイスが変更後の状態をMQTTトピック$aws/things/{thingName}/shadow/updateにPublish

{
  "state": {
    "reported": {
      "alert_threshold": {
        "temperature": 35,
        "humidity": 80
      }
    }
  }
}

これによって、クラウド上にあるreporteddesiredの差分がなくなるため、deltaは発行されず設定変更が完了したことになります。

デバイスから設定を変更する場合

クラウドが保存しているシャドウを以下とします。

{
  "state": {
    "desired": {
      "alert_threshold": {
        "temperature": 35,
        "humidity": 70
      }
    },
    "reported": {
      "alert_threshold": {
        "temperature": 35,
        "humidity": 70
      }
    }
  }
}

このシャドウでは、デバイスの現在の状態と希望の状態が一致しており、「温度35度、湿度70%をアラートの閾値としてますよ」ということが表されています。

  1. デバイスが「希望する状態」も「現在の状態」も送信
    現在の状態のみをクラウドに送ってしまうと、クラウドが持っているdesiredとデバイスからついさっきやってきたreportedに差分が発生してしまい、deltaに自動的にPublishされてしまいます。そのため、デバイスの現在の状態が希望の状態であることを同時にクラウドへ伝えます。
    デバイスからMQTTトピック$aws/things/{thingName}/shadow/updateに以下をPublishします。
{
  "state": {
    "reported": {
      "alert_threshold": {
        "temperature": 35,
        "humidity": 80
      }
    },
    "desired": {
      "alert_threshold": {
        "temperature": 35,
        "humidity": 80
      }
    }
  }
}

これだけです。当然、クラウド上にあるreporteddesiredの差分は発生しないため、deltaは発行されず設定変更が完了したことになります。

まとめ

AWS IoT Device Shadowの主な使い方と処理の流れを簡単に解説しました。現時点で公式の資料で日本語訳されているものが非常に少ないので、最初の理解の一助となれば幸いです。

株式会社TechSword

Discussion