Amazon IoT Device Shadow 演示应用程序 - FreeRTOS
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

Amazon IoT Device Shadow 演示应用程序

重要

该演示托管在已弃用的 Amazon-FreeRTOS 存储库中。当您创建新项目时,我们建议从此处开始。如果您已经有一个基于现已弃用的 Amazon-FreeRTOS 存储库的 FreeRTOS 项目,请参阅 Amazon-FreeRTOS Github 存储库迁移指南

简介

此演示展示了如何使用 Amazon IoT Device Shadow 库连接到 Amazon Device Shadow 服务。它使用 coreMQTT 库 通过 TLS(双向身份验证)与 Amazon IoT MQTT 代理建立 MQTT 连接,并使用 coreJson 库解析器来解析从 Amazon Shadow 服务收到的影子文档。该演示展示了基本的影子操作,例如如何更新影子文档和如何删除影子文档。该演示还展示了如何在 coreMQTT 库中注册回调函数来处理影子消息,例如,影子 /update 和从 Amazon IoT Device Shadow 服务发送的 /update/delta 消息等。

此演示仅用于学习练习,因为更新影子文档(状态)的请求和更新响应是由同一个应用程序完成的。在现实生产场景中,即使设备当前未连接,外部应用程序也会请求远程更新设备的状态。设备连接后将确认更新请求。

注意

要设置和运行 FreeRTOS 演示,请按照开始使用 FreeRTOS中的步骤操作。

功能

该演示创建了一个应用程序任务,该任务会循环执行一组示例,这些示例演示了影子 /update/update/delta 回调,从而模拟切换远程设备的状态。它会发送带有新的 desired 状态的影子更新,并等待设备根据新的 reported 状态更改其 desired 状态。此外,它还使用影子 /update 回调来输出不断变化的影子状态。该演示还使用了与 Amazon IoT MQTT 代理的安全的 MQTT 连接,并假设设备影子中存在 powerOn 状态。

该演示执行以下操作:

  1. 使用 shadow_demo_helpers.c 中的帮助程序函数建立 MQTT 连接。

  2. 使用 Amazon IoT Device Shadow 库定义的宏汇编用于设备影子操作的 MQTT 主题字符串。

  3. 发布到用于删除设备影子的 MQTT 主题以删除任何现有设备影子。

  4. 使用 shadow_demo_helpers.c 中的帮助程序函数为 /update/delta/update/accepted/update/rejected 订阅 MQTT 主题。

  5. 使用 shadow_demo_helpers.c 中的帮助程序函数发布 powerOn 的所需状态。这将导致向设备发送 /update/delta 消息。

  6. 使用 Amazon IoT Device Shadow 库 (Shadow_MatchTopic) 定义的函数处理在 prvEventCallback 中传入的 MQTT 消息,并确定该消息是否与设备影子相关。如果该消息是设备影子 /update/delta 消息,则主演示函数将发布第二条消息,将报告的状态更新为 powerOn。如果收到一条 /update/accepted 消息,请确认该消息与之前在更新消息中发布的消息具有相同的 clientToken。这标志演示的结束。


                影子演示终端输出

该演示可在文件 freertos/demos/device_shadow_for_aws/shadow_demo_main.c 中或 GitHub 上找到。

以下屏幕截图显示了演示成功时的预期输出。


                显示成功的影子演示终端输出

连接到 Amazon IoT MQTT 代理。

要连接到 Amazon IoT MQTT 代理,我们使用与coreMQTT 双向身份验证演示中的 MQTT_Connect() 相同的方法。

删除影子文档

要删除影子文档,请使用 Amazon IoT Device Shadow 库定义的宏,通过一条空消息来调用 xPublishToTopic。这会使用 MQTT_Publish 来发布到 /delete 主题。以下代码部分显示了如何在函数 prvShadowDemoTask 中执行此操作。

/* First of all, try to delete any Shadow document in the cloud. */ returnStatus = PublishToTopic( SHADOW_TOPIC_STRING_DELETE( THING_NAME ), SHADOW_TOPIC_LENGTH_DELETE( THING_NAME_LENGTH ), pcUpdateDocument, 0U );

订阅影子主题

订阅 Device Shadow 主题,接收 Amazon IoT 代理发送的有关影子变更的通知。Device Shadow 主题由 Device Shadow 库中定义的宏汇编而成。以下代码部分显示了如何在函数 prvShadowDemoTask 中执行此操作。

/* Then try to subscribe shadow topics. */ if( returnStatus == EXIT_SUCCESS ) { returnStatus = SubscribeToTopic( SHADOW_TOPIC_STRING_UPDATE_DELTA( THING_NAME ), SHADOW_TOPIC_LENGTH_UPDATE_DELTA( THING_NAME_LENGTH ) ); } if( returnStatus == EXIT_SUCCESS ) { returnStatus = SubscribeToTopic( SHADOW_TOPIC_STRING_UPDATE_ACCEPTED( THING_NAME ), SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED( THING_NAME_LENGTH ) ); } if( returnStatus == EXIT_SUCCESS ) { returnStatus = SubscribeToTopic( SHADOW_TOPIC_STRING_UPDATE_REJECTED( THING_NAME ), SHADOW_TOPIC_LENGTH_UPDATE_REJECTED( THING_NAME_LENGTH ) ); }

发送影子更新

要发送影子更新,该演示使用由 Device Shadow 库定义的宏,通过一条 JSON 格式的消息调用 xPublishToTopic。这会使用 MQTT_Publish 来发布到 /delete 主题。以下代码部分显示了如何在函数 prvShadowDemoTask 中执行此操作。

#define SHADOW_REPORTED_JSON \ "{" \ "\"state\":{" \ "\"reported\":{" \ "\"powerOn\":%01d" \ "}" \ "}," \ "\"clientToken\":\"%06lu\"" \ "}" snprintf( pcUpdateDocument, SHADOW_REPORTED_JSON_LENGTH + 1, SHADOW_REPORTED_JSON, ( int ) ulCurrentPowerOnState, ( long unsigned ) ulClientToken ); xPublishToTopic( SHADOW_TOPIC_STRING_UPDATE( THING_NAME ), SHADOW_TOPIC_LENGTH_UPDATE( THING_NAME_LENGTH ), pcUpdateDocument, ( SHADOW_DESIRED_JSON_LENGTH + 1 ) );

处理阴影增量消息和影子更新消息

使用 MQTT_Init 函数注册到 coreMQTT 客户端库的用户回调函数将通知我们传入数据包的事件。请参阅参见 GitHub 上的回调函数 prvEventCallback

回调函数确认传入的数据包的类型为 MQTT_PACKET_TYPE_PUBLISH,并使用 Device Shadow 库 API Shadow_MatchTopic 确认传入的消息是否为影子消息。

如果传入的消息是类型为 ShadowMessageTypeUpdateDelta 的影子消息,则我们会调用 prvUpdateDeltaHandler 来处理该消息。处理程序 prvUpdateDeltaHandler 使用 coreJson 库解析消息,以便获取 powerOn 状态的增量值,并将其与本地维护的当前设备状态进行比较。如果不同,则会更新本地设备状态以反映影子文档中 powerOn 状态的新值。

如果传入的消息是类型为 ShadowMessageTypeUpdateAccepted 的影子消息,则我们会调用 prvUpdateAcceptedHandler 来处理该消息。处理程序 prvUpdateAcceptedHandler 使用 coreJson 库解析消息,以便从消息获取 clientToken。此处理函数会检查 JSON 消息中的客户端令牌是否与应用程序使用的客户端令牌匹配。如果不匹配,则此函数会记录警告消息。