4、设备影子API概览:获取影子、更新影子、删除影子、订阅影子变更

好,咱们进入正题。设备影子这东西,说白了就是一个 JSON 文件,躺在服务端,随时反映你设备的「最新状态」。你想想看,设备可能离线,可能网络不好,但影子一直在。这就是它的价值。

我刚开始接触 ThingsBoard 时,总觉得影子 API 很神秘。后来用多了才发现,核心就四个操作:查、改、删、听。嗯,咱们一个一个来。

4.1 获取影子:看看设备现在啥样

获取影子,就是问服务端:「嘿,这个设备的最新状态是什么?」

我个人习惯用 REST API 来查,简单直接。你只需要知道设备的实体 ID(就是那个 UUID),然后发一个 GET 请求。

GET /api/plugins/telemetry/DEVICE/{entityId}/attributes/CLIENT_SCOPE

这里有个坑,我一开始没注意——影子数据存在 CLIENT_SCOPE 下。不是 SHARED_SCOPE,也不是 SERVER_SCOPE。你如果查错了 scope,返回的就是空数组。

返回的数据长这样:

{
  "temperature": 25.6,
  "humidity": 68,
  "lastUpdate": 1695000000000
}

我在项目中遇到过一个问题:设备上报频率很高,每次查影子都拿到一堆旧数据。后来我加了个时间戳字段,每次更新时带上,查的时候比对一下,就知道数据是不是最新的了。

小技巧: 如果你用 MQTT 方式获取影子,可以订阅这个主题:v1/devices/me/attributes。设备上线后,服务端会自动推送一次全量影子数据。

4.2 更新影子:把新状态写进去

更新影子,就是告诉服务端:「设备现在的状态变了,你记一下。」

更新用 POST 请求,数据格式也是 JSON。注意,更新是覆盖式的——你传什么,服务端就存什么。不会自动合并。

POST /api/plugins/telemetry/DEVICE/{entityId}/attributes/CLIENT_SCOPE

{
  "temperature": 26.1,
  "humidity": 65,
  "fanSpeed": 3
}

我曾经踩过一个坑:设备上报时只传了 temperature,没传 humidity。结果 humidity 在服务端被清空了。为什么?因为更新是整体替换,不是局部更新。

避坑指南: 更新影子时,一定要把所有需要保留的字段都传进去。如果你只想更新某个字段,建议先 GET 一次,拿到完整数据,修改后再 POST 回去。或者,你可以在业务逻辑里做合并。

我个人习惯在设备端维护一个「全量状态缓存」,每次上报前,把当前所有状态打包成一个 JSON,再发出去。这样就不会丢字段了。

4.3 删除影子:清理不需要的数据

删除影子,说实话,我用得不多。但有些场景确实需要:比如设备报废了、设备被重置了、或者你想清理测试数据。

删除操作也是 REST API,用 DELETE 方法:

DELETE /api/plugins/telemetry/DEVICE/{entityId}/attributes/CLIENT_SCOPE

注意,这个操作会清空整个 CLIENT_SCOPE 下的所有属性。不是只删一个字段,是全部删掉。

我记得有一次,测试环境里有个设备影子数据乱了,我直接删了重新创建。嗯,简单粗暴,但有效。

警告: 删除影子是不可逆的。如果你只是想让某个字段失效,建议把它的值设为 null 或空字符串,而不是直接删整个影子。删了之后,所有依赖这个影子的服务都会拿到空数据。

4.4 订阅影子变更:实时感知变化

订阅影子变更,这才是 IoT 场景里的核心能力。你想想看,如果每次都要轮询查影子,那效率多低?而且实时性也差。

ThingsBoard 支持通过 WebSocket 或 MQTT 订阅影子变更。我个人更推荐 MQTT,因为它在弱网环境下表现更好。

订阅的主题是:

v1/devices/me/attributes

设备端订阅这个主题后,只要影子数据有变化,服务端就会主动推送。推送的数据格式和 GET 返回的一样。

我在项目中遇到过一个问题:设备订阅了影子变更,但有时候收不到推送。排查了半天,发现是 MQTT 的 QoS 设置成了 0(最多一次)。改成 QoS 1(至少一次)后,问题就解决了。

建议: 订阅影子变更时,把 QoS 设为 1。这样即使网络波动,消息也不会丢。代价是可能会有重复消息,你需要在业务逻辑里做去重。

另外,订阅变更时,你可以指定只关注某些字段。比如我只关心 temperature 的变化,可以这样:

v1/devices/me/attributes/temperature

这样推送的数据里就只有 temperature 字段,省流量,也省解析时间。

4.5 四个操作的对比

操作 HTTP 方法 MQTT 主题 说明
获取影子 GET 订阅 v1/devices/me/attributes 获取设备最新状态
更新影子 POST 发布到 v1/devices/me/attributes 覆盖式更新,注意保留所有字段
删除影子 DELETE 清空整个 CLIENT_SCOPE,谨慎使用
订阅变更 WebSocket 订阅 v1/devices/me/attributes 实时推送,推荐 QoS 1

核心要点:

  • 影子数据存在 CLIENT_SCOPE 下,别搞错 scope
  • 更新是覆盖式的,记得传全量数据
  • 删除操作不可逆,慎用
  • 订阅变更用 MQTT + QoS 1,稳得很

好了,这四个 API 就是设备影子的核心操作。说白了,就是增删改查加一个订阅。你只要掌握了这些,设备影子这块就基本拿下了。下一节咱们会动手写代码,把这些 API 串起来,做一个完整的远程控制 demo。