本文将介绍设备连接物联网开发平台后,如何通过物模型 Topic 上报设备属性和事件,以及接收云端属性控制和行为调用。
物模型用于将设备能力以统一的数据结构进行描述。产品定义物模型后,平台可以按照属性、事件和行为理解设备数据,并对设备上报的数据格式进行校验。
功能介绍
物模型(Thing Model)是设备在云端的数字化描述,通过属性、事件和行为三个维度定义产品能力。
类型 | 含义 | 典型场景 |
属性 Property | 设备当前状态或可配置参数。 | 开关、温度、亮度。 |
事件 Event | 设备主动上报的业务事件。 | 告警、故障、信息。 |
行为 Action | 云端调用设备执行具体动作。 | 开锁、调整音量、执行任务。 |
其中,属性可由设备主动上报;对于可写属性,云端也可以向设备下发设置请求。事件由设备主动上报,事件类型包括
alert、fault 和 info。行为由云端发起调用,设备执行后返回结果。物模型通信使用平台规定的 Topic 和 JSON 协议。设备上报的数据需要与产品中定义的属性、事件和行为保持一致,平台会对物模型数据进行校验,不符合物模型定义的数据不会被正常存储和展示。
物模型 Topic
物模型主要使用以下 Topic:
能力 | 上行 Topic | 下行 Topic |
属性 | $thing/up/property/{ProductID}/{DeviceName} | $thing/down/property/{ProductID}/{DeviceName} |
事件 | $thing/up/event/{ProductID}/{DeviceName} | $thing/down/event/{ProductID}/{DeviceName} |
行为 | $thing/up/action/{ProductID}/{DeviceName} | $thing/down/action/{ProductID}/{DeviceName} |
不同 Topic 对应不同物模型语义:
属性 Topic 用于属性上报、属性控制及相关响应。
事件 Topic 用于事件上报及事件响应。
行为 Topic 用于行为调用及行为执行结果返回。
通信流程
物模型通信主要包含两类链路:

前提条件
使用物模型通信前,请确认:
已在产品中完成物模型定义。
设备已完成 MQTT 身份认证并成功连接物联网开发平台。
设备端使用的属性标识符、事件标识符、行为标识符及对应参数,与产品物模型定义保持一致。
物模型协议使用这些标识符描述具体设备能力,因此设备端不能自行修改字段名称或数据类型。
使用限制
单设备 MQTT 上行消息存在速率限制:
QoS | 单设备最大上行速率 |
QoS 0 | 30 条/秒 |
QoS 1 | 10 条/秒 |
超过限制时,可在设备行为日志中看到:
Fail, reach max limit
使用注意事项
物模型 Topic 由平台定义,不需要像自定义 Topic 一样创建 Topic 类。
设备上报和接收的数据必须遵循物模型协议规定的 JSON 结构。
属性、事件、行为标识符以及参数必须与产品物模型定义保持一致。
属性下行 Topic 中可能同时包含
report_reply、control、get_status_reply 等消息,应结合 method 判断具体消息类型。属性控制完成后,应返回
control_reply;行为执行完成后,应返回 action_reply。clientToken 用于关联请求和响应,设备回复时应保持一致。事件的
type 应使用 alert、fault 或 info。timestamp 统一使用毫秒级 Unix 时间戳;如果无特殊时间需求,可以不填写,由平台使用当前系统时间。timestamp 与服务端当前时间相差超过24小时时,平台会返回 405。行为调用后,设备应在5秒内返回
action_reply,否则平台会判定调用超时。物模型数据不符合定义时,平台不会正常存储对应数据。
单设备消息上报应遵守 QoS 对应的速率限制。
操作步骤
步骤 1:订阅物模型下行 Topic
设备连接平台后,需要根据实际业务订阅对应的物模型下行 Topic,用于接收平台响应、属性控制及行为调用。
以下代码以 Python Paho MQTT 为例,假设 MQTT Client 已经完成身份认证并成功连接平台。
property_down_topic = (f"$thing/down/property/{product_id}/{device_name}")event_down_topic = (f"$thing/down/event/{product_id}/{device_name}")action_down_topic = (f"$thing/down/action/{product_id}/{device_name}")client.subscribe(property_down_topic, qos=1)client.subscribe(event_down_topic, qos=1)client.subscribe(action_down_topic, qos=1)
设备需要保持 MQTT 消息循环运行:
client.loop_forever()
实际项目只需要订阅业务使用到的 Topic,不要求同时使用属性、事件和行为。
步骤 2:上报设备属性
设备属性用于描述设备当前状态,例如开关状态、温度和亮度。
属性上报 Topic:
$thing/up/property/{ProductID}/{DeviceName}
设备按照物模型属性协议构造消息,例如:
{"method": "report","clientToken": "123","params": {"power_switch": 1,"color": 1,"brightness": 32}}
主要字段:
字段 | 说明 |
method | 属性上报固定为 report。 |
clientToken | 消息 ID,用于关联请求和响应。 |
timestamp | Unix 时间戳,单位为毫秒,可选;不填写时由平台使用当前系统时间。 |
params | 本次上报的属性键值。 |
如果无特殊时间需求,可以不填写
timestamp。如需填写,应使用当前毫秒级 Unix 时间戳;上报时间与服务端当前时间相差超过24小时时,平台会返回 405。Python 示例:
import jsonimport timetopic = (f"$thing/up/property/"f"{product_id}/{device_name}")payload = {"method": "report","clientToken": "property-001","timestamp": int(time.time() * 1000),"params": {"power_switch": 1,"brightness": 32}}client.publish(topic,json.dumps(payload),qos=1,)
params 中的字段必须已在产品物模型中定义,并符合对应数据类型和取值范围。平台处理完成后,会通过属性下行 Topic 返回
report_reply:{"method": "report_reply","clientToken": "123","code": 0,"status": ""}
其中,
clientToken 与属性上报请求保持一致,code = 0 表示平台成功处理本次属性上报。步骤 3:接收并处理属性控制
对于可写属性,平台可以通过以下 Topic 向设备下发控制消息:
$thing/down/property/{ProductID}/{DeviceName}
典型控制消息:
{"method": "control","clientToken": "123","params": {"brightness": 66}}
设备收到后,需要先判断
method == "control",再根据 params 执行业务逻辑。def on_message(client, userdata, msg):data = json.loads(msg.payload.decode("utf-8"))if (msg.topic == property_down_topicand data.get("method") == "control"):handle_property_control(data)
这里必须判断
method,因为属性下行 Topic 中还可能收到 report_reply、get_status_reply 等消息,不能把所有属性下行消息都当成控制指令。设备完成控制后,需要向属性上行 Topic 返回
control_reply:{"method": "control_reply","clientToken": "123","code": 0,"status": ""}
回复中的
clientToken 应与控制请求保持一致,用于平台关联本次请求和响应。步骤 4:上报设备事件
事件适用于设备主动上报告警、故障和信息类业务状态。
事件上报 Topic:
$thing/up/event/{ProductID}/{DeviceName}
事件响应 Topic:
$thing/down/event/{ProductID}/{DeviceName}
事件请求示例:
{"method": "event_post","clientToken": "123","version": "1.0","eventId": "PowerAlarm","type": "fault","params": {"Voltage": 2.8,"Percent": 20}}
主要字段:
字段 | 说明 |
method | 固定为 event_post。 |
clientToken | 消息 ID,用于关联请求和响应。 |
version | 协议版本,当前默认 1.0。 |
eventId | 产品物模型中定义的事件标识。 |
type | 事件类型: alert、fault 或 info。 |
timestamp | 事件发生时间,Unix 时间戳,单位为毫秒,可选。 |
params | 产品物模型中定义的事件参数。 |
其中,
eventId 和 type 是事件上报的关键字段,设备需要根据产品物模型定义填写对应事件标识和事件类型。如果需要携带事件发生时间,应填写当前毫秒级 Unix 时间戳;无特殊时间需求时可以省略
timestamp。平台处理后通过事件下行 Topic 返回:
{"method": "event_reply","clientToken": "123","version": "1.0","code": 0,"status": "","data": {}}
code = 0 表示事件上报成功。步骤 5:接收并处理行为调用
行为适用于云端调用设备执行具体动作,并实时获取执行结果的场景。
行为调用下行 Topic:
$thing/down/action/{ProductID}/{DeviceName}
设备执行完成后,通过以下 Topic 返回结果:
$thing/up/action/{ProductID}/{DeviceName}
例如云端调用设备调整音量:
{"method": "action","clientToken": "20a4ccfd-d308-****-86c6-5254008a4f10","actionId": "control_volume","params": {"action": "set","volume": 50}}
主要字段:
字段 | 说明 |
method | 行为调用固定为 action。 |
clientToken | 本次行为调用 ID。 |
actionId | 产品物模型中定义的行为标识。 |
timestamp | 行为调用时间,Unix 时间戳,单位为毫秒,可选。 |
params | 行为输入参数。 |
如果需要填写
timestamp,应使用当前毫秒级 Unix 时间戳;否则可以省略。设备根据
actionId 和 params 执行业务逻辑后,需要返回 action_reply:{"method": "action_reply","clientToken": "20a4ccfd-d308-****-86c6-5254008a4f10","code": 0,"status": "","response": {"volume": 50}}
其中:
字段 | 说明 |
method | 行为回复固定为 action_reply。 |
clientToken | 与行为调用请求保持一致。 |
code | 行为执行结果, 0 表示成功。 |
status | 执行结果或错误信息。 |
response | 物模型中定义的行为输出参数。 |
行为回复中的返回参数必须放在
response 中,而不是 params。设备需要在5秒内返回行为执行结果,否则平台会判定本次行为调用超时。
步骤 6:统一处理下行消息
如果同时使用属性、事件和行为,可以先根据 Topic 将下行消息分发到对应处理逻辑,再根据
method 判断具体消息类型。def on_message(client, userdata, msg):data = json.loads(msg.payload.decode("utf-8"))method = data.get("method")if msg.topic == property_down_topic:if method == "control":handle_property_control(data)elif method == "report_reply":handle_property_report_reply(data)elif method == "get_status_reply":handle_status_reply(data)elif msg.topic == event_down_topic:if method == "event_reply":handle_event_reply(data)elif msg.topic == action_down_topic:if method == "action":handle_action(data)
如果处理
get_status_reply,属性数据位于 data.reported 下,例如:{"method": "get_status_reply","code": 0,"clientToken": "123","type": "report","data": {"reported": {"power_switch": 1,"brightness": 66}}}
因此读取属性值时,应从
data.reported 获取,而不是直接从 data 根节点读取。建议业务实现同时结合
clientToken、eventId、actionId 等字段关联请求和响应。验证物模型通信
设备成功上报合法物模型数据后,可以在设备详情的物模型数据或相关日志页面查看平台处理结果。
验证时建议依次检查:
是否发布到了正确的物模型 Topic。
Payload 是否为合法 JSON。
method 是否正确。属性、事件和行为标识符是否与产品物模型定义一致。
参数类型和取值范围是否符合物模型定义。
如填写
timestamp,是否为毫秒级 Unix 时间戳,且与服务端当前时间相差不超过24小时。常见问题
返回码 / 现象 | 排查建议 |
400 | Payload 不是合法 JSON,检查 JSON 格式。 |
403 | 检查 method 是否正确,或属性、事件、行为标识符是否与产品物模型定义一致。 |
405 | 时间戳错误。确认 timestamp 为毫秒级 Unix 时间戳,并检查与服务端当前时间是否相差超过 24 小时。 |
406 | 参数不符合物模型定义,检查数据类型、枚举值、数值范围等。例如整型枚举不要使用字符串 "0"、"1"。 |
503 | 平台服务端处理异常,可结合日志进行重试或进一步排查。 |
MQTT 已连接,但属性上报后没有数据。 | 检查属性 Topic、JSON 格式、 method、属性标识符及数据类型。 |
云端修改属性后设备没有收到。 | 检查是否订阅 $thing/down/property/...,并确认回调中正确处理 method = control。 |
属性控制已执行,但平台仍认为失败。 | 检查是否返回 control_reply,以及 clientToken 是否与控制请求一致。 |
事件上报后没有记录。 | 检查事件 Topic、 eventId、type 和 params 是否与产品物模型定义一致。 |
行为调用后平台提示超时。 | 检查设备是否订阅行为下行 Topic,并确认是否在5秒内返回 action_reply。 |
行为回复后平台无法解析结果。 | 检查输出参数是否放在 response 中,而不是 params。 |
get_status_reply 中读取不到属性值。 | 属性数据位于 data.reported 下,不在 data 根节点。 |
行为日志出现 Fail, reach max limit。 | 检查设备是否超过单设备 MQTT 上行速率限制。 |
Payload 为二进制或私有协议。 | 建议使用自定义透传。 |
仅需传输自定义业务消息。 | 企业实例可使用自定义 Topic,具体以当前实例能力为准。 |