AWS IoT
开发人员指南
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 Amazon AWS 入门

使用影子

AWS IoT 针对设备的影子提供了三项操作:

UPDATE

如果设备的影子不存在,则创建一个该影子;如果存在,则使用请求中提供的数据更新设备的影子的内容。存储数据时使用时间戳信息,以指明最新更新时间。向所有订阅者发送消息,告知 desired 状态与 reported 状态之间的差异 (增量)。接收到消息的事物或应用程序可以根据 desired 状态和 reported 状态之间的差异执行操作。例如,设备可将其状态更新为预期状态,或者应用程序可以更新其 UI,以反映设备状态的更改。

GET

检索设备的影子中存储的最新状态 (例如,在设备启动期间,检索配置和最新操作状态)。此操作将返回整个 JSON 文档,其中包括元数据。

DELETE

删除设备的影子,包括其所有内容。这将从数据存储中删除 JSON 文档。您无法还原已删除的设备的影子,但可以创建具有相同名称的新影子。

协议支持

MQTT 和通过 HTTPS 的 RESTful API 都支持这些操作。由于 MQTT 是一种发布/订阅的通信模式,AWS IoT 将采用一组预留主题。为了实施请求 – 响应操作,事物或应用程序应先订阅这些主题,然后向请求主题发布消息。有关更多信息,请参阅 影子 MQTT 主题Device Shadow RESTful API

更新影子

您可以通过使用 UpdateThingShadow RESTful API 或向 /更新 主题发布消息来更新设备的影子。更新仅影响请求中指定的字段。

初始状态:

{ "state": { "reported" : { "color" : { "r" :255, "g": 255, "b": 0 } } } }

发送一条更新信息:

{ "state": { "desired" : { "color" : { "r" : 10 }, "engine" : "ON" } } }

设备收到由之前的 desired 消息触发的 /update/delta 状态 (位于 /update 主题下),然后执行预期更改。结束后,设备应通过影子 JSON 文档中的 reported 部分确认其更新后的状态。

最终状态:

{ "state": { "reported" : { "color" : { "r" : 10, "g" : 255, "b": 0 }, "engine" : "ON" } } }

检索影子文档

您可以通过使用 GetThingShadow RESTful API 或通过订阅和发布消息到 /get 主题来检索设备的影子。这将检索整个文档以及 desired 状态与 reported 状态之间的增量。

示例文档:

{ "state": { "desired": { "lights": { "color": "RED" }, "engine": "ON" }, "reported": { "lights": { "color": "GREEN" }, "engine": "ON" } }, "metadata": { "desired": { "lights": { "color": { "timestamp": 123456 }, "engine": { "timestamp": 123456 } } }, "reported": { "lights": { "color": { "timestamp": 789012 } }, "engine": { "timestamp": 789012 } }, "version": 10, "timestamp": 123456789 } }

响应:

{ "state": { "desired": { "lights": { "color": "RED" }, "engine": "ON" }, "reported": { "lights": { "color": "GREEN" }, "engine": "ON" }, "delta": { "lights": { "color": "RED" } } }, "metadata": { "desired": { "lights": { "color": { "timestamp": 123456 }, } "engine": { "timestamp": 123456 } }, "reported": { "lights": { "color": { "timestamp": 789012 } }, "engine": { "timestamp": 789012 } }, "delta": { "lights": { "color": { "timestamp": 123456 } } } }, "version": 10, "timestamp": 123456789 }

乐观锁

您可以使用状态文档版本来确保正在更新的设备的影子文档为最新版本。当您为更新请求提供版本时,如果状态文档的当前版本与提供的版本不符,该服务将显示 HTTP 409 冲突响应代码并拒绝请求。

例如:

初始文档:

{ "state" : { "desired" : { "colors" : ["RED", "GREEN", "BLUE" ] } }, "version" : 10 }

更新:(版本不匹配;请求将被拒绝)

{ "state": { "desired": { "colors": [ "BLUE" ] } }, "version": 9 }

结果:

409 Conflict

更新:(版本匹配;请求将被接受)

{ "state": { "desired": { "colors": [ "BLUE" ] } }, "version": 10 }

最终状态:

{ "state": { "desired": { "colors": [ "BLUE" ] } }, "version": 11 }

删除数据

您可以通过将消息发布到 /更新 主题并将要删除的字段设置为空,从设备的影子中删除数据。值为 null 的所有字段均将从文档中删除。

初始状态:

{ "state": { "desired" : { "lights": { "color": "RED" }, "engine" : "ON" }, "reported" : { "lights" : { "color": "GREEN" }, "engine" : "OFF" } } }

发送一条更新信息:

{ "state": { "desired": null, "reported": { "engine": null } } }

最终状态:

{ "state": { "reported" : { "lights" : { "color" : "GREEN" } } } }

您可以将设备的影子的状态设置为 null 来从中删除所有数据。例如,发送以下消息时将删除所有状态数据,但仍将保留设备的影子。

{ "state": null }

即使状态为 null,设备的影子仍然存在。在下次更新时,该影子的版本将递增。

删除影子

您可以通过使用 DeleteThingShadow RESTful API 或向 /delete 主题发布消息来删除设备的影子文档。

注意

删除设备的影子不会删除事物。删除事物不会删除相应设备的影子。

初始状态:

{ "state": { "desired" : { "lights": { "color": "RED" }, "engine" : "ON" }, "reported" : { "lights" : { "color": "GREEN" }, "engine" : "OFF" } } }

在 /delete 主题下发布了空消息。

最终状态:

HTTP 404 - resource not found

增量状态

增量状态是一种虚拟类型的状态,包含 desired 状态和 reported 状态之间的差异。对于 desired 部分中的字段,如果 reported 部分没有这些字段,则它们将包含在增量中。对于 reported 部分中的字段,如果 desired 部分没有这些字段,则它们不会包含在增量中。增量包含元数据,且其值与 desired 字段的元数据相同。例如:

{ "state": { "desired": { "color": "RED", "state": "STOP" }, "reported": { "color": "GREEN", "engine": "ON" }, "delta": { "color": "RED", "state": "STOP" } }, "metadata": { "desired": { "color": { "timestamp": 12345 }, "state": { "timestamp": 12345 }, "reported": { "color": { "timestamp": 12345 }, "engine": { "timestamp": 12345 } }, "delta": { "color": { "timestamp": 12345 }, "state": { "timestamp": 12345 } } }, "version": 17, "timestamp": 123456789 } }

当嵌套对象不同时,增量将包含根路径。

{ "state": { "desired": { "lights": { "color": { "r": 255, "g": 255, "b": 255 } } }, "reported": { "lights": { "color": { "r": 255, "g": 0, "b": 255 } } }, "delta": { "lights": { "color": { "g": 255 } } } }, "version": 18, "timestamp": 123456789 }

Device Shadow 服务通过循环访问 desired 状态中的每个字段并将其与 reported 状态进行比较来计算增量。

数组的处理方式与值类似。如果 desired 部分中的数组与 reported 部分中的数组不匹配,则整个预期数组将被复制到增量中。

观察状态更改

设备的影子更新后,将在两个 MQTT 主题下发布消息:

  • $aws/things/thing-name/shadow/update/accepted

  • $aws/things/thing-name/shadow/update/delta

发送到 update/delta 主题的消息将用于状态正在更新的事物。此消息仅包含设备的影子文档中 desired 部分与 reported 部分之间的差异。在收到此消息后,设备应立即决定是否要执行请求的更改。如果设备的状态发生变化,它应向 $aws/things/thing-name/shadow/update 主题发布其当前最新状态。

设备和应用程序可以订阅任一主题,以便在文档状态更改后收到通知。

以下是该流程的示例:

  1. 一台设备报告了自身的状态。

  2. 系统在其持久性数据存储中更新状态文档。

  3. 系统发布仅包含增量并面向订阅设备的增量消息。要接收更新,设备应订阅此主题。

  4. 设备的影子发布接受的消息,包括内含元数据的整个已接收文档。要接收更新,应用程序应订阅此主题。

消息顺序

不保证 AWS IoT 服务发送的消息按任何特定顺序到达设备。

初始状态文档:

{ "state" : { "reported" : { "color" : "blue" } }, "version" : 10, "timestamp": 123456777 }

更新 1:

{ "state": { "desired" : { "color" : "RED" } }, "version": 10, "timestamp": 123456777 }

更新 2:

{ "state": { "desired" : { "color" : "GREEN" } }, "version": 11 , "timestamp": 123456778 }

最终状态文档:

{ "state": { "reported": { "color" : "GREEN" } }, "version": 12, "timestamp": 123456779 }

这将产生两个增量消息:

{ "state": { "color": "RED" }, "version": 11, "timestamp": 123456778 }
{ "state": { "color" : "GREEN" }, "version": 12, "timestamp": 123456779 }

设备可能不会按次序收到这些消息。由于这些消息中的状态是累计的,设备可以安全地弃用版本号比正在追踪的版本号更早的所有消息。如果设备在接收版本 11 的增量之前收到版本 12 的增量,则可以安全地弃用版本 11 的消息。

修剪影子消息

要降低发送到您的设备的影子消息的大小,请定义一项规则,以仅选择设备所需的字段然后将消息重新发布到设备正在侦听的 MQTT 主题。

规则应在 JSON 中指定,且应与以下内容类似:

{ "sql": "SELECT state, version FROM '$aws/things/+/shadow/update/delta'", "ruleDisabled": false, "actions": [{ "republish": { "topic": "${topic(2)}/delta", "roleArn": "arn:aws:iam::123456789012:role/my-iot-role" } }] }

SELECT 语句用于确定将消息中的哪些字段重新发布到指定的主题。“+”通配符用于匹配所有影子名称。该规则指定,应将所有匹配的消息重新发布到指定的主题。在此情况下,可以使用 "topic()" 函数指定将消息重新发布到哪个主题。topic(2) 用于评估原始主题中的事物名称。有关创建规则的更多信息,请参阅规则