一、功能介绍
物模型(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_topic and 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,具体以当前实例能力为准。 |