ruoyi-vue-pro 开发指南 ruoyi-vue-pro 开发指南
  • 萌新必读
  • 后端手册
  • 中间件手册
  • 工作流手册
  • 大屏手册
  • 支付手册
  • 会员手册
  • 商城手册
  • ERP 手册
  • CRM 手册
  • MES 手册
  • WMS 手册
  • HRM 手册
  • FMS 手册
  • PMS 手册
  • OA 手册
  • IM 即时通讯手册
  • AI 大模型手册
  • IoT 物联网手册
  • 公众号手册
  • 系统手册
  • 运维手册
  • 前端手册 Vue 3.x
  • 前端手册 Vben 5.x
  • 前端手册 Vue 2.x
  • 前端手册 Admin Uniapp
  • 工作流手册
  • 大屏手册
  • 支付手册
  • 会员手册
  • 商城手册
  • ERP 手册
  • CRM 手册
  • MES 手册
  • WMS 手册
  • HRM 手册
  • FMS 手册
  • PMS 手册
  • OA 手册
  • IM 即时通讯手册
  • AI 大模型手册
  • IoT 物联网手册
  • 公众号手册
  • 系统手册
视频教程
  • Vue3 + element-plus (opens new window)
  • Vue3 + vben5(ant-design-vue、element-plus) (opens new window)
  • Vue2 + element-ui (opens new window)
微服务版 (opens new window)
作者博客 (opens new window)
GitHub (opens new window)
  • 萌新必读
  • 后端手册
  • 中间件手册
  • 工作流手册
  • 大屏手册
  • 支付手册
  • 会员手册
  • 商城手册
  • ERP 手册
  • CRM 手册
  • MES 手册
  • WMS 手册
  • HRM 手册
  • FMS 手册
  • PMS 手册
  • OA 手册
  • IM 即时通讯手册
  • AI 大模型手册
  • IoT 物联网手册
  • 公众号手册
  • 系统手册
  • 运维手册
  • 前端手册 Vue 3.x
  • 前端手册 Vben 5.x
  • 前端手册 Vue 2.x
  • 前端手册 Admin Uniapp
  • 工作流手册
  • 大屏手册
  • 支付手册
  • 会员手册
  • 商城手册
  • ERP 手册
  • CRM 手册
  • MES 手册
  • WMS 手册
  • HRM 手册
  • FMS 手册
  • PMS 手册
  • OA 手册
  • IM 即时通讯手册
  • AI 大模型手册
  • IoT 物联网手册
  • 公众号手册
  • 系统手册
视频教程
  • Vue3 + element-plus (opens new window)
  • Vue3 + vben5(ant-design-vue、element-plus) (opens new window)
  • Vue2 + element-ui (opens new window)
微服务版 (opens new window)
作者博客 (opens new window)
GitHub (opens new window)
  • 萌新必读

    • 简介
    • 交流群
    • 视频教程
    • 功能列表
    • 快速启动(后端项目)
    • 快速启动(前端项目)
    • 接口文档
    • 技术选型
    • 项目结构
    • 代码热加载
    • 一键改包
    • 迁移模块(适合新项目)
    • 删除功能(以租户为例)
    • 表结构变更(版本升级)
    • 国产信创数据库(DM 达梦、大金、OpenGauss、瀚高、OceanBase、TiDB、GaussDB、PolarDB、神通、Vastbase、MogDB、TongRDS、CacheDB)
    • 如何去除 Redis 缓存
    • 面试题、简历模版、简历优化
    • 项目外包
  • 后端手册

    • 新建模块
    • 代码生成【单表】(新增功能)
    • 代码生成【主子表】
    • 代码生成(树表)
    • 代码生成(移动端)
    • 功能权限
    • 数据权限
    • 用户体系
    • 三方登录
    • OAuth 2.0(SSO 单点登录)
    • SaaS 多租户【字段隔离】
    • SaaS 多租户【数据库隔离】
    • WebSocket 实时通信
    • 异常处理(错误码)
    • 参数校验、时间传参
    • 分页实现
    • VO 对象转换、数据翻译
    • 文件存储(上传下载)
    • Excel 导入导出
    • 操作日志、访问日志、异常日志
    • MyBatis 数据库
    • MyBatis 联表&分页查询
    • 多数据源(读写分离)、事务
    • Redis 缓存
    • 本地缓存
    • 异步任务
    • 分布式锁
    • 幂等性(防重复提交)
    • 请求限流(RateLimiter)
    • HTTP 接口签名(防篡改)
    • HTTP 接口加解密
    • 单元测试
    • 验证码
    • 工具类 Util
    • 配置管理
    • 数据库文档
  • 中间件手册

    • 定时任务
    • 消息队列(内存)
    • 消息队列(Redis)
    • 消息队列(RocketMQ)
    • 消息队列(RabbitMQ)
    • 消息队列(Kafka)
    • 限流熔断
    • 分库分表
    • 分布式事务
  • 工作流手册

    • 工作流演示
    • 功能开启
    • 工作流(达梦适配)
    • 审批接入(流程表单)
    • 审批接入(业务表单)
    • 流程设计器(BPMN)
    • 流程设计器(钉钉、飞书)
    • 选择审批人、发起人自选
    • 会签、或签、依次审批
    • 流程发起、取消、重新发起
    • 审批通过、不通过、驳回
    • 审批加签、减签
    • 审批转办、委派、抄送
    • 执行监听器、任务监听器
    • 流程表达式
    • 流程审批通知
    • 移动端审批
  • 大屏手册

    • 报表设计器
    • 大屏设计器
  • 支付手册

    • 功能开启
    • 支付宝支付接入
    • 微信公众号支付接入
    • 微信小程序支付接入
    • 支付宝、微信退款接入
    • 支付宝转账接入
    • 微信转账接入
    • 钱包充值、支付、退款
    • 模拟支付、退款
    • 移动端支付管理
  • 会员手册

    • 功能开启
    • 微信公众号登录
    • 微信小程序登录
    • 微信小程序订阅消息
    • 微信小程序码
    • 会员用户、标签、分组
    • 会员等级、积分、签到
    • 移动端会员管理
  • 商城手册

    • 商城演示
    • 功能开启
    • 商城装修
    • 在线客服
    • 【商品】商品分类
    • 【商品】商品属性
    • 【商品】商品 SPU 与 SKU
    • 【商品】商品评价
    • 【交易】购物车
    • 【交易】交易订单
    • 【交易】售后退款
    • 【交易】快递发货
    • 【交易】门店自提
    • 【交易】分销返佣
    • 【营销】优惠劵
    • 【营销】积分商城
    • 【营销】拼团活动
    • 【营销】秒杀活动
    • 【营销】砍价活动
    • 【营销】满减送活动
    • 【营销】限时折扣
    • 【营销】内容管理
    • 【统计】会员、商品、交易统计
    • 移动端商城管理
  • ERP手册

    • ERP 演示
    • 功能开启
    • 【产品】产品信息、分类、单位
    • 【库存】产品库存、库存明细
    • 【库存】其它入库、其它出库
    • 【库存】库存调拨、库存盘点
    • 【采购】采购订单、入库、退货
    • 【销售】销售订单、出库、退货
    • 【财务】采购付款、销售收款
    • 移动端 ERP
  • CRM手册

    • CRM 演示
    • 功能开启
    • 【线索】线索管理
    • 【客户】客户管理、公海客户
    • 【商机】商机管理、商机状态
    • 【合同】合同管理、合同提醒
    • 【回款】回款管理、回款计划
    • 【产品】产品管理、产品分类
    • 【通用】数据权限
    • 【通用】跟进记录、待办事项
    • 移动端 CRM
  • AI大模型手册

    • AI 大模型演示
    • 功能开启
    • AI 聊天对话
    • AI 绘画创作
    • AI 知识库(RAG)
    • AI 音乐创作
    • AI 写作助手
    • AI 思维导图
    • AI 工具(function calling)
    • AI 工作流
    • Dify 工作流
    • FastGPT 工作流
    • Coze 智能体
    • 推理模式(thinking)
    • 联网搜索
    • MCP Client 客户端
    • MCP Server 服务端
    • 【模型接入】Claude
    • 【模型接入】OpenAI
    • 【模型接入】通义千问
    • 【模型接入】DeepSeek
    • 【模型接入】字节豆包
    • 【模型接入】腾讯混元
    • 【模型接入】硅基流动
    • 【模型接入】MiniMax
    • 【模型接入】月之暗面
    • 【模型接入】百川智能
    • 【模型接入】文心一言
    • 【模型接入】LLAMA
    • 【模型接入】智谱 GLM
    • 【模型接入】讯飞星火
    • 【模型接入】微软 OpenAI
    • 【模型接入】谷歌 Gemini
    • 【模型接入】Stable Diffusion
    • 【模型接入】Midjourney
    • 【模型接入】Suno
    • 【模型接入】Grok
    • 【模型接入】阶跃星辰
    • 移动端 AI 大模型
  • IoT物联网手册

    • 功能开启
    • 产品管理
    • 设备管理
    • 物模型配置
    • 设备网关与子设备
    • 设备动态注册
    • 设备影子
      • 1. 影子概述
        • 1.1 影子文档
        • 1.2 工作流程
        • 1.3 规则与限制
      • 2. 表结构
      • 3. 管理后台
        • 3.1 页面操作
        • 3.2 接口
      • 4. 设备协议
        • 4.1 消息格式
        • 4.2 获取影子(get)
        • 4.3 上报状态(update)
        • 4.4 清空影子(version = -1)
        • 4.5 期望状态推送
        • 4.6 错误码
      • 5. 快速验证
    • 消息透传与数据解析
    • 设备接入(概述)
    • 设备接入(HTTP 协议)
    • 设备接入(MQTT 协议)
    • 设备接入(EMQX 协议)
    • 设备接入(TCP 协议)
    • 设备接入(UDP 协议)
    • 设备接入(WebSocket 协议)
    • 设备接入(CoAP 协议)
    • 设备接入(Modbus Client 模式)
    • 设备接入(Modbus Server 模式)
    • 设备接入(自定义协议)
    • 场景联动
    • 数据流转
    • 告警配置
    • OTA 固件升级
    • 移动端 IoT 物联网
  • MES手册

    • MES 演示
    • 功能开启
    • 【基础】物料产品、分类、计量单位
    • 【基础】客户管理、供应商管理
    • 【基础】车间设置、工作站设置
    • 【基础】编码规则
    • 【生产】工序设置、工艺流程
    • 【生产】生产工单
    • 【生产】生产排产、工序流转卡
    • 【生产】生产报工
    • 【生产】安灯配置、安灯呼叫
    • 【生产】工作记录
    • 【仓库】仓库与库区库位、条码赋码、SN码
    • 【仓库】批次管理、库存现有量、库存事务
    • 【仓库】到货通知、采购入库、采购退货
    • 【仓库】生产领料、生产退料、物料消耗
    • 【仓库】产品产出、产品入库
    • 【仓库】发货通知、销售出库、销售退货
    • 【仓库】外协发料、外协入库
    • 【仓库】其他入库、其他出库
    • 【仓库】调拨单、装箱管理
    • 【仓库】库存盘点
    • 【质量】检测项设置、常见缺陷
    • 【质量】质检方案
    • 【质量】来料检验(IQC)
    • 【质量】过程检验(IPQC)
    • 【质量】出货检验(OQC)
    • 【质量】退货检验(RQC)
    • 【质量】待检任务、检验结果、缺陷记录
    • 【设备】设备类型、设备台账
    • 【设备】点检保养项目、点检保养方案
    • 【设备】点检记录、保养记录、维修单
    • 【工具】工具类型、工装夹具台账
    • 【排班】班组设置、节假日设置
    • 【排班】排班计划、排班日历
    • 移动端 MES
  • WMS手册

    • WMS 演示
    • 功能开启
    • 【基础】仓库
    • 【基础】商品、SKU、分类、品牌
    • 【基础】往来企业(供应商、客户)
    • 【库存】库存记录、流水、统计
    • 【单据】入库
    • 【单据】出库
    • 【单据】移库
    • 【单据】盘库
    • 【其它】WMS、MES、ERP 对比
    • 移动端 WMS
  • HRM人力资源

    • HRM 演示
    • 功能开启
    • 【组织】工作台、组织架构
    • 【员工】员工管理
    • 【招聘】招聘管理
    • 【考勤】考勤管理
    • 【社保】社保管理
    • 【薪资】计薪设置、薪资档案
    • 【薪资】月度工资、工资条
    • 【绩效】绩效模板、绩效计划
    • 【绩效】绩效考核、绩效档案
    • 移动端 HRM
  • FMS财务管理

    • FMS 演示
    • 功能开启
    • 【设置】账套管理、财务参数、财务指标
    • 【设置】币别、科目、辅助核算、初始余额
    • 【设置】凭证字、常用摘要、凭证模板
    • 【凭证】凭证管理
    • 【账簿】账簿管理
    • 【报表】财务报表
    • 【结账】期末结账
    • 移动端 FMS
  • PMS项目管理

    • PMS 演示
    • 功能开启
    • 【项目中心】工作台与项目管理
    • 【项目中心】项目详情与迭代
    • 【项目中心】工作项与协作
    • 【知识中心】知识库管理
    • 【知识中心】文档与协作
    • 移动端 PMS
  • OA协同办公

    • OA 演示
    • 功能开启
    • 【协作】日程、任务、计划与汇报
    • 【协作】公告、讨论、通讯录与笔记
    • 【办公】企业邮箱
    • 【办公】企业云盘
    • 【行政】办公用品、用印管理
    • 【行政】会议室、车辆管理
    • 【流程】公文管理
    • 【流程】出差、费用报销
    • 【流程】考勤、请假、加班、转正与离职
    • 移动端 OA
  • IM即时通讯手册

    • IM 演示
    • 功能开启
    • 【好友】好友关系、好友申请
    • 【群聊】群组、群成员、入群申请
    • 【消息】私聊、群聊、频道消息
    • 【频道】频道、频道素材
    • 【内容】表情、敏感词
    • 【通话】语音通话、视频通话、共享屏幕
    • 【WebSocket】实时推送与离线消息
    • 移动端 IM 即时通讯
  • 公众号手册

    • 功能开启
    • 公众号接入
    • 公众号粉丝
    • 公众号标签
    • 公众号消息
    • 模版消息
    • 自动回复
    • 公众号菜单
    • 公众号素材
    • 公众号图文
    • 公众号统计
    • 移动端公众号管理
  • 系统手册

    • 短信配置
    • 邮件配置
    • 站内信配置
    • Webhook(钉钉、飞书、企微)
    • 数据脱敏、字段权限
    • 敏感词
    • 地区 & IP 库
  • 运维手册

    • 开发环境
    • Linux 部署
    • Docker 部署
    • Jenkins 部署
    • 宝塔部署
    • 1Panel 部署
    • Docker Compose 部署
    • Kubernetes 部署
    • HTTPS 证书
    • 服务监控
    • Tomcat WAR 部署
    • 东方通服务器部署(TongWeb、TongHttpServer)
    • 宝兰德服务器部署(BES AppServer)
    • 内网穿透
  • 前端手册 Vue 3.x

    • 开发规范
    • 菜单路由
    • Icon 图标
    • 字典数据
    • 系统组件
    • 通用方法
    • 配置读取
    • CRUD 组件
    • 国际化
    • IDE 调试
    • 代码格式化
  • 前端手册 Vben 5.x

    • 开发规范
    • 菜单路由
    • 图标、主题、国际化
    • 字典数据
    • 系统组件
    • 通用方法
    • 配置读取
    • IDE 调试
    • 代码格式化
  • 前端手册 Vue 2.x

    • 开发规范
    • 菜单路由
    • Icon 图标
    • 字典数据
    • 系统组件
    • 通用方法
    • 配置读取
  • 前端手册 Admin Uniapp

    • 开发规范
    • 菜单路由
    • 图标、主题、国际化
    • 字典数据
    • 系统组件
    • 通用方法
    • IDE 调试
    • 代码格式化
    • 运行发布
  • 更新日志

    • 【v2026-10】
    • 【v2026-09】
    • 【v2026-08】
    • 【v2026-07】
    • 【v2026-06】
    • 【v2026-05】
    • 【v2026-04】
    • 【v2026-03】
    • 【v2026-01】
    • 【v2025-12】
    • 【v2025-11】
    • 【v2025-10】
    • 【v2025-09】
    • 【v2025-08】
  • 开发指南
  • IoT物联网手册
芋道源码
2026-10-26
目录

设备影子

推荐阅读:

  • 《设备接入(概述)》 — 了解 IotDeviceMessage 消息格式
  • 《设备接入(MQTT 协议)》 — 了解 MQTT 主题与连接认证
  • 《阿里云物联网平台 —— 设备影子》 (opens new window)

设备影子(Device Shadow),由 yudao-module-iot-biz 后端模块实现:IotDeviceShadowController 提供管理接口,IotDeviceShadowService 负责影子读写、设备上行处理。

平台为每个设备保存一份状态文档:管理后台写入期望状态(desired),设备上报实际状态(reported)。设备离线时,期望状态先保存在影子中,设备上线后再主动拉取并执行,从而解耦「下发指令」与「设备在线」。例如:

  • 设备离线时,修改开关、运行模式等属性,设备上线后主动拉取并执行
  • 对比期望值与上报值,确认设备是否已执行到位

如果想先跑通一遍,可以直接看「5. 快速验证」小节。

# 1. 影子概述

# 1.1 影子文档

每个设备有且只有一份影子,在首次访问时(管理后台查看、下发期望、切换开关,或设备首次发送影子消息)自动创建,默认开启。

字段 说明
desired 期望状态,Key 为物模型属性标识符(identifier),由管理后台写入
reported 上报状态,Key 同上,由设备上报写入
metadata 元数据,记录每个属性的最后更新时间:{ desired: { key: { timestamp } }, reported: { ... } }
version 版本号,desired、reported 共用:每次成功更新 + 1,清空影子后归 0
shadowTime 影子最后更新时间
status 影子开关,参见 CommonStatusEnum 枚举(0 开启、1 关闭)

注意时间单位

metadata 中的 timestamp、shadowTime(设备协议中为 timestamp)均为 epoch 秒;而物模型 date 类型的属性值,是毫秒时间戳。

# 1.2 工作流程

  1. 下发期望:管理后台填写期望值,合并写入 desired,version + 1
  2. 推送影子:平台记录了设备所在网关时,尝试向设备推送完整影子;否则仅保存
  3. 拉取期望:设备上线后,主动 get 获取最新 desired 并执行;收到完整推送时,也可直接执行
  4. 上报状态:设备执行后,通过 update 上报 reported
  5. 对比差异:管理后台对比 desired 与 reported,高亮不一致的属性

重要

① 平台没有离线消息队列,不会在设备上线时自动重放期望值。设备每次连接成功后,都应主动 get 一次影子。

② 平台不会自动清除 desired。设备上报的 reported 与 desired 一致后,差异高亮自然消失;需要清空时,使用「重置影子」。

# 1.3 规则与限制

① 属性数:desired、reported 合并后各自最多 128 个属性,超过时拒绝本次更新。

② 并发更新:按 version 乐观锁写入数据库,冲突时基于最新影子重新合并,最多尝试 3 次(含首次),仍冲突则返回「版本冲突」。

③ 影子开关:关闭后,params 解析通过的设备影子消息被忽略(不继续处理、不回复),管理后台也不能下发期望值(提示「设备影子未启用」);仍可查看、重置影子。未传 params 时仍回复 400,params 解析失败时仍可能回复 500。

④ 删除设备:删除设备时,一并删除其影子。

⑤ 缓存:仅管理后台的影子查询使用 Redis 缓存(60 秒过期,写入后删除),设备消息处理和所有写入都以数据库为准。

⑥ 与属性上报相互独立:设备的属性上报(thing.property.post,包括 数据解析脚本 解析出的)只更新「物模型数据」,不会写入影子的 reported;设备影子的 update 也不会保存属性数据。同样,下发期望只写影子并推送影子文档,不会发送 thing.property.set 属性设置指令。需要影子对比的设备,要单独发送影子消息。

⑦ 合并与数据类型:

  • desired、reported 按顶层属性合并:本次提交的属性整体覆盖同名旧值(结构体、数组也是整体替换,不做深度合并),未提交的属性保留。
  • 不支持删除单个属性。需要清空时,使用「重置影子」或设备发送 version = -1,两者都会同时清空 desired 和 reported。
  • 后端只校验属性数,不按物模型校验属性标识符和数据类型,值按 JSON 原样保存。管理后台的属性对比表只展示物模型中定义的属性,其它属性只能在「原始影子文档」中看到。

# 2. 表结构

对应 iot_device_shadow 表,每个设备一行,desired、reported、metadata 以 JSON 文本保存影子状态。

已包含 creator/create_time/updater/update_time/deleted/tenant_id 等通用字段

CREATE TABLE IF NOT EXISTS `iot_device_shadow`  (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  `device_id` bigint NOT NULL COMMENT '设备编号',

  `product_id` bigint NOT NULL COMMENT '产品编号',
  `product_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '产品标识',
  `device_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '设备名称',

  `reported` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '上报状态',
  `desired` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '期望状态',
  `metadata` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '元数据',

  `version` bigint NOT NULL DEFAULT 0 COMMENT '版本号',
  `shadow_time` bigint NOT NULL DEFAULT 0 COMMENT '文档最后更新时间(epoch 秒)',

  `status` tinyint NOT NULL DEFAULT 0 COMMENT '状态',

  `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',

  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `uk_device_id`(`device_id` ASC) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'IoT 设备影子表';

① device_id 为设备编号,关联 iot_device 表的 id 字段。唯一索引 uk_device_id 保证每个设备只有一份影子。

② product_id、product_key、device_name 冗余存储设备信息,方便查询和展示。

③ reported、desired、metadata 以 JSON 文本存储在 text 字段中,对应 IotDeviceShadowDO 的 Map 字段。结构见「1.1 影子文档」。

④ version 为影子版本号,用于乐观锁;shadow_time 为影子最后更新时间(epoch 秒)。

⑤ status 为影子开关,参见 CommonStatusEnum 枚举,默认 0 开启。

# 3. 管理后台

对应 [IoT 物联网 -> 设备接入 -> 设备管理] 菜单,进入设备详情页的「设备影子」Tab。对应前端项目的文件:

  • Vue3:src/views/iot/device/device/detail/DeviceDetailsShadow.vue
  • Vben Antd / Ele:apps/web-antd、apps/web-ele 下的 src/views/iot/device/device/detail/modules/shadow.vue
  • Admin Uniapp:src/pages-iot/device/device/shadow/index.vue(独立页面)

管理后台 - 设备影子(示例数据)

# 3.1 页面操作

① 顶部信息栏:展示版本号、最后更新时间,以及「影子开关」。

② 属性对比表:按产品物模型的属性,逐行展示期望值、上报值,以及各自的更新时间(来自 metadata)。有期望值、且与上报值不一致的行会高亮:比较时区分 JSON 类型(例如期望 1,上报 true 或 "1" 仍算不一致),结构体、数组按内容比较。没有期望值的行不高亮。

③ 下发期望状态:仅列出访问模式为「读写」「只写」的属性,按物模型数据类型提供输入方式:

数据类型 输入方式 期望值
bool、enum 下拉选择 物模型定义的取值,例如 0 / 1
int、float、double 数字输入 数字,int 取整
date 日期时间选择 毫秒时间戳(数字)
struct、array JSON 输入 JSON 对象、JSON 数组
text 等其它 文本输入 字符串

只需填写要修改的属性,未填写的属性保持不变;页面不能把已有的期望值改为空。下发成功后,会尝试推送给设备,详见「4.5 期望状态推送」小节。

④ 重置影子:清空 desired、reported、metadata,version 归 0。

⑤ 原始影子文档:展开后可查看完整的影子 JSON。

# 3.2 接口

由 IotDeviceShadowController 提供:

接口 说明 权限
GET /iot/device/shadow/get 获取设备影子 iot:device:shadow-query
PUT /iot/device/shadow/update-desired 更新期望状态 iot:device:shadow-update
PUT /iot/device/shadow/update-status 更新影子开关状态 iot:device:shadow-update
DELETE /iot/device/shadow/reset 重置设备影子 iot:device:shadow-update

# 4. 设备协议

# 4.1 消息格式

设备影子使用统一的 IotDeviceMessage 消息格式(见 《设备接入(概述)》 的「2.1 消息格式」):

  • 外层 method 固定为 thing.shadow.update
  • params.method 为内层方法:get 获取影子、update 上报状态

以 MQTT 协议为例,对应主题如下(设备需提前订阅回复主题,或直接订阅 /sys/{productKey}/{deviceName}/#):

方向 MQTT 主题 说明
上行 /sys/{productKey}/{deviceName}/thing/shadow/update 设备发送 get、update 请求
下行 /sys/{productKey}/{deviceName}/thing/shadow/update_reply 平台回复、期望状态推送

① 下文示例使用 JSON 序列化,并省略了 id、reportTime、deviceId 等后端自动填充的字段。

② 建议设备在请求中携带 requestId,回复会原样带回,便于与请求配对。

③ 影子的回复、推送都依赖下行通道。HTTP、CoAP 等短连接协议不支持下行推送,因此无法收到影子回复。

④ 影子消息只走各协议的标准消息格式:使用 《消息透传与数据解析》 的产品,数据解析脚本不能输出 thing.shadow.update,影子的回复、推送也不经过脚本编码。

⑤ 影子的请求与回复会记录在设备详情的「设备消息」Tab 中,便于排查。

# 4.2 获取影子(get)

请求消息:

{
  "requestId": "1001",
  "method": "thing.shadow.update",
  "params": {
    "method": "get"
  }
}

回复消息:

{
  "requestId": "1001",
  "method": "thing.shadow.update",
  "code": 0,
  "msg": "成功",
  "data": {
    "state": {
      "desired": {
        "PowerSwitch": 1
      },
      "reported": {
        "PowerSwitch": 0
      }
    },
    "version": 3,
    "timestamp": 1792980000
  }
}

data.state 包含 desired、reported,version 为影子当前版本,timestamp 为影子最后更新时间(epoch 秒)。回复中不包含 metadata。

# 4.3 上报状态(update)

请求消息:

{
  "requestId": "1002",
  "method": "thing.shadow.update",
  "params": {
    "method": "update",
    "state": {
      "reported": {
        "PowerSwitch": 1
      }
    },
    "version": 3
  }
}

① state.reported 为本次上报的属性,合并到影子的 reported 中:只覆盖本次上报的属性,其它属性保留。合并规则见「1.3 规则与限制」的 ⑦。建议按物模型的数据类型上报(例如 bool 属性上报数字 0 / 1),否则管理后台的差异高亮不会消失。

② version 为设备已知的影子版本,可选:

  • 携带时:必须等于影子当前版本,否则回复 409,data.version 为当前版本。设备应先 get 同步,再重新上报。
  • 不携带时:平台基于最新影子强制合并。写入时仍按 version 乐观锁保护,冲突时自动重试,仍冲突则回复 409。

注意:携带的 version 须等于当前版本;管理后台下发期望值也会使 version + 1。

回复消息:

{
  "requestId": "1002",
  "method": "thing.shadow.update",
  "code": 0,
  "msg": "成功",
  "data": {
    "version": 4,
    "timestamp": 1792980060
  }
}

# 4.4 清空影子(version = -1)

params.version 为 -1 时,清空影子的 desired、reported、metadata,version 归 0,此时不需要传 state:

{
  "requestId": "1003",
  "method": "thing.shadow.update",
  "params": {
    "method": "update",
    "version": -1
  }
}

成功时,回复 code 为 0、data.version 为 0。效果与管理后台的「重置影子」相同。

# 4.5 期望状态推送

管理后台下发期望状态成功后,如果平台记录了设备所在的网关(设备最近一次上行消息所在的网关,设备离线后不清除),会尝试通过 update_reply 主题推送完整影子,data 结构与「4.2 获取影子」的回复相同,requestId 由平台生成。

推送不保证送达(发送失败仅记录日志),设备不在线时也不会重发,但期望状态已保存在影子中。设备下次上线后,通过 get 获取即可。

推荐的设备端处理流程:

  1. 连接成功后,订阅 update_reply 主题,并发送一次 get
  2. 收到 get 回复或推送后,执行 desired 中的期望值
  3. 执行完成后,携带最新 version 发送 update 上报 reported
  4. 收到 409 时,重新 get 后再上报

# 4.6 错误码

影子回复的 code、msg,参见 IotDeviceShadowErrorCodeEnum 枚举。失败时 data 仍包含 version、timestamp,便于设备重新同步:

code msg 说明
0 成功
400 JSON 格式错误 未传 params
401 缺少 method 未传 params.method
402 缺少 state update 未传 state(version = -1 除外)
404 缺少 reported 未传 state.reported
405 reported 为空 state.reported 为空对象
406 无效内层 method params.method 不是 get、update
408 影子属性数超过限制 合并后 reported 超过 128 个属性
409 影子版本冲突 版本不一致或重试后仍冲突,data.version 为当前版本
500 服务端异常 平台处理异常

另外,影子关闭时,params 解析通过的影子消息被直接忽略,不会回复;params 为空或解析失败时,仍可能按上表回复 400、500。

# 5. 快速验证

下面以 MQTT 直连设备为例,使用 MQTTX (opens new window) 模拟设备,走一遍「下发期望 → 设备拉取 → 设备上报 → 差异消失」。

请将主题中的 {productKey}、{deviceName} 替换为实际值,PowerSwitch 替换为你的属性标识符。

① 准备物模型属性:在设备所属产品的「物模型(功能定义)」中,确认有一个访问模式为「读写」的属性。下文以 bool 类型的 PowerSwitch 为例。

② 连接设备:按 《设备接入(MQTT 协议)》 的「4.1 连接认证」连接设备,并订阅 /sys/{productKey}/{deviceName}/thing/shadow/update_reply 主题(或直接订阅 /sys/{productKey}/{deviceName}/#)。

③ 打开设备影子:进入设备详情的「设备影子」Tab,确认「影子开关」为开启。为便于对照下文的版本号,可以先点击「重置影子」,此时版本号为 0。

④ 下发期望:在「下发期望状态」中,将 PowerSwitch 选择为 1,点击「下发期望状态」。如下图所示:

管理后台 - 下发期望状态(示例)

  • 版本号变为 1,PowerSwitch 行的期望值为 1、上报值为 -,该行高亮
  • 设备在线时,MQTTX 在 update_reply 主题收到一条完整影子推送,data.state.desired.PowerSwitch 为 1

⑤ 设备拉取期望:发布到 /sys/{productKey}/{deviceName}/thing/shadow/update 主题:

{
  "requestId": "2001",
  "method": "thing.shadow.update",
  "params": {
    "method": "get"
  }
}

回复的 data.state.desired 中可以看到 PowerSwitch: 1,data.version 为 1。即使错过了 ④ 的推送(例如设备当时离线),也能通过 get 拿到期望值。

⑥ 设备上报执行结果:携带 ⑤ 回复中的 data.version,发布到同一主题:

{
  "requestId": "2002",
  "method": "thing.shadow.update",
  "params": {
    "method": "update",
    "state": {
      "reported": {
        "PowerSwitch": 1
      }
    },
    "version": 1
  }
}

回复 code 为 0、data.version 为 2。如果回复 409,说明期间影子又被更新过,重新 get 后再上报。

⑦ 查看差异消失:回到「设备影子」Tab,点击「刷新」。PowerSwitch 的上报值变为 1,高亮消失。在「设备消息」Tab 中,可以看到上述 thing.shadow.update 的请求与回复。

友情提示:

  • 如果 ⑦ 仍然高亮,检查上报值与期望值的 JSON 类型是否一致,例如不要用 true 或 "1" 上报期望值 1。
  • 只发 thing.property.post 属性上报,不会改变影子的上报值;影子的 update 也不会改变「物模型数据」Tab 的属性值。
  • 验证完成后,可以点击「重置影子」清空测试数据。
设备动态注册
消息透传与数据解析

← 设备动态注册 消息透传与数据解析→

Theme by Vdoing | Copyright © 2019-2026 芋道源码 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×