3.7 物模型与设备抽象
3.7.1 物模型(Thing Model)概念与 Profile 实现
智能温室的温湿度传感器、仓储中的RFID读写器、车间里的振动监测仪——这些设备来自不同厂商,接口协议各异,上报的数据格式也完全不同。A公司的温度传感器以JSON格式上报 {"temp": 25.3, "unit": "C"},B公司的同类设备却用二进制报文,解析依赖一份300页的协议文档。搭建一套物联网平台,大量精力花在“翻译”这些设备数据上。只要接入一个新品牌、新型号的设备,就得重新写一遍适配代码。这种局面让异构设备之间的互操作变得极其昂贵,也拖慢了项目部署节奏。
解决这个问题的核心思路,是给每一类设备一张“能力卡片”——把它的数据类型、控制接口、能上报什么事件,统一用一种可被机器理解的描述语言写清楚。行业通常把这类能力描述称为物模型(Thing Model);IoT DC3 则以 Profile(模板)承载同类设备的能力定义。物模型描述设备类型的能力契约,与记录单个设备运行状态的“设备影子”(Device Shadow)并不是同一概念——影子是运行时的状态快照,物模型是永恒的能力蓝图。
物模型把同型号设备共有的属性、服务、事件聚合在一起,描述“这类设备能采什么、能控什么、会报什么”。 一个设备恰好归属一个物模型,多个设备可以复用同一个物模型。例如同一批100个温湿度传感器,共享同一个物模型定义——它们的基本能力一致,只是ID和当前数值不同。物模型不关心单台设备的瞬时状态,它只描述这类设备的可能行为。
属性(Property)、服务(Service,在 DC3 中也称“指令”或“动作”)和事件(Event)是物模型的三个基本要素。属性是设备的状态值,可读可写或只读——例如一个温度传感器的当前温度、一个智能插座的开关状态、一个电池的电量百分比。服务是设备对外暴露的可执行操作,比如远程重启网关、校准传感器零点、设定报警阈值。事件是设备主动发出的信号,通常表示某种状态变化或异常,比如温度越界报警、设备离线通知、周期性的心跳。这三个要素的定义,本质上是把物理设备的行为抽象成一种可编程接口。应用层工程师只需知道“有一个属性叫temperature,我可以读取它的值”,而不需要知道这个温度值是从Modbus寄存器读出来的,还是通过I²C总线从芯片直接获取的。
主流的物模型标准各有侧重,但核心理念一致。W3C(万维网联盟)提出的 Web of Things (WoT) Thing Description (TD) 是较为成熟的开放规范,它把设备描述为一组属性(Property)、动作(Action)和事件(Event),支持通过JSON Schema定义输入输出数据模式、定义安全方案(OAuth2、PSK等)以及协议绑定(HTTP、CoAP、MQTT)。另一位重要的标准贡献者是 oneM2M,它面向蜂窝物联网场景,对资源模型、订阅与通知等操作做了更精细的定义,强调层级和语义的一致性。无论选用哪种标准,核心设计原则是一致的:把“设备能力”与“设备实现”剥离——物模型定义的是“能干什么”,而不是“怎么干”。这种抽象让应用层开发者只需关心属性值、服务调用和事件接收,无需理解底层是Modbus RTU还是CoAP协议。
在 IoT DC3 这类开源平台中,物模型概念被实际落地,称为 Profile。平台提供一组 RESTful API 来管理物模型:新增、更新、查询、删除。设备实例绑定其所属型号的 Profile,应用层访问设备时不再直面原始协议,而是通过 Profile 接口读取标准化后的属性值或触发服务。这正好呼应了本章开篇提出的感知层演进方向——从“采集数据”到“抽象能力”。物模型把物理世界的千差万别浓缩成一套可编程的接口,让应用层工程师可以像调用函数一样与物理设备交互,而不必理解每种传感器背后的通信细节。
一份 DC3 风格的 Profile 可以精简到十余行 JSON。以本章反复使用的温度传感器为例,其最小骨架如下:
{
"name": "无线温度传感器 T-100",
"description": "冷链仓储电池供电温度传感器,精度 ±0.1℃",
"properties": [
{ "name": "currentTemperature", "type": "double", "unit": "℃", "accessMode": "r" },
{ "name": "maxAlarmThreshold", "type": "double", "unit": "℃", "accessMode": "rw" }
],
"services": [
{ "name": "calibrateSensor", "invocation": "async", "input": { "referenceTemperature": "double" } }
],
"events": [
{ "name": "overTemperatureAlarm", "data": { "currentTemperature": "double", "timestamp": "string" } }
]
}与 W3C WoT TD 对照着看更清楚:两者表达的是同一份能力契约——Profile 的属性对应 TD 的 properties,服务对应 actions,事件对应 events。差别在详略:WoT TD 用 @context、forms、security 等字段承载语义标注、协议绑定与安全方案,面向跨平台互操作;DC3 Profile 面向平台内部管理,只保留最小必需字段——属性即位号,服务即平台可下发的指令,事件对接告警通道。invocation: "async" 标注服务的异步调用模式,这一点在 3.7.2 节还会展开。
物模型并非锦上添花的工作。没有它,平台接入每一个新设备品类都像在解一道新的谜题;有了它,设备接入变成填表——厂商只需把自己的设备能力映射到已有的物模型模板上,或者为新型号新增一个模板。这正是规模化部署物联网系统的工程基石:将互操作成本从“逐设备定制”降低到“一次建模、无限复用”。上面只给出了 Profile 的最小骨架,一份完整的物模型文档在工程上还有哪些设计考量?第3.7.2节将用一个具体的温度传感器示例,演示如何定义一份Profile JSON文档。至于物模型如何作为AI Agent与物理世界交互的接口,我们将在第7章AIoT与智能体应用中深入探讨。
3.7.2 物模型设计示例:温度传感器
直接上手,为一种常见的物联网设备——温度传感器——定义物模型。这能让你直观地看到上一节的概念如何落地。
假设你负责为一款冷链仓储用的无线温度传感器 Model-T-100 设计物模型。它每30秒上报一次温度,精度0.1℃,支持远程校准,当温度超出预设范围时主动上报报警。这个场景很适合演示物模型的核心结构。
属性、服务、事件:一张设备能力卡片
物模型本质上是一张“设备能力卡片”。参考业界主流的 W3C Web of Things Thing Description (WoT TD) 规范,以及 IoT DC3 中对物模型的定义方式,这张卡片需要描述三种类型的能力:
- 属性(Properties):设备可以被读取或设置的状态变量。比如
当前温度(只读)、温度上下限阈值(可写)。 - 服务(Services):设备能执行的远程操作。比如
校准传感器、恢复出厂设置。它们往往是一个过程,可能耗时较长,并返回执行结果。 - 事件(Events):设备主动发出的消息,用于通知某个条件被触发。比如
温度越界报警,一旦传感器数值越界,就立刻向平台推送一条消息。
物模型的价值在于:它将设备千差万别的能力,用这三类标准接口统一定义成机器可解析的模板。平台开发者只需读懂这个模板,就能和任意符合该模板的设备进行交互,而无需关心它的硬件差异。
下面用 JSON(JavaScript Object Notation)格式(基于 W3C WoT TD 的核心结构并做简化)为 Model-T-100 编写物模型:
{
"@context": "https://www.w3.org/2019/wot/td/v1",
"id": "urn:dev:profile:temperature-sensor:t-100:v1",
"title": "Wireless Temperature Sensor T-100",
"description": "A battery-powered temperature sensor for cold chain monitoring, accuracy ±0.1°C.",
"@type": "TemperatureSensor",
"properties": {
"currentTemperature": {
"title": "Current Temperature",
"type": "number",
"unit": "celsius",
"readOnly": true,
"minimum": -40,
"maximum": 85
},
"minAlarmThreshold": {
"title": "Minimum Alarm Threshold",
"type": "number",
"unit": "celsius",
"readOnly": false,
"minimum": -40,
"maximum": 85
},
"maxAlarmThreshold": {
"title": "Maximum Alarm Threshold",
"type": "number",
"unit": "celsius",
"readOnly": false,
"minimum": -40,
"maximum": 85
},
"batteryLevel": {
"title": "Battery Level",
"type": "integer",
"unit": "percent",
"readOnly": true,
"minimum": 0,
"maximum": 100
}
},
"actions": {
"calibrateSensor": {
"title": "Calibrate Sensor",
"description": "One-point calibration using a reference temperature. The device compares its reading with the provided value and adjusts the offset.",
"input": {
"type": "object",
"properties": { "referenceTemperature": { "type": "number" } },
"required": ["referenceTemperature"]
},
"output": {
"type": "object",
"properties": {
"status": { "type": "string", "enum": ["success", "failure"] },
"adjustedOffset": { "type": "number" }
}
}
},
"resetToFactory": {
"title": "Reset to Factory Defaults",
"input": { "type": "null" },
"output": {
"type": "object",
"properties": { "status": { "type": "string", "enum": ["success", "failure"] } }
}
}
},
"events": {
"overTemperatureAlarm": {
"title": "Over-Temperature Alarm",
"data": {
"type": "object",
"properties": {
"currentTemperature": { "type": "number" },
"thresholdValue": { "type": "number" },
"timestamp": { "type": "string", "format": "date-time" }
}
}
},
"underTemperatureAlarm": {
"title": "Under-Temperature Alarm",
"data": {
"type": "object",
"properties": {
"currentTemperature": { "type": "number" },
"thresholdValue": { "type": "number" },
"timestamp": { "type": "string", "format": "date-time" }
}
}
}
},
"links": {
"properties": "mqtt://broker.iot.example.com/devices/t-100-001/properties",
"actions": "mqtt://broker.iot.example.com/devices/t-100-001/actions",
"events": "mqtt://broker.iot.example.com/devices/t-100-001/events"
}
}这个 JSON 文件清晰定义了:
- 这台传感器有 4 个属性,其中
currentTemperature和batteryLevel是只读的,两个报警阈值是可写的。平台可以通过修改这些属性来改变设备的行为。 - 它支持 2 个服务:
calibrateSensor需要输入一个参考温度,并返回校准结果;resetToFactory不需要输入,执行后返回状态。 - 它能主动上报 2 个事件:温度过高或过低报警。每个事件携带当时的温度值、阈值和时间戳。
下面这张图展示了物模型作为模板与设备实例之间的关系,以及三类能力在平台侧的交互模式。
工程权衡:设计时的三个决策点
上面示例看起来直接,但实际项目中,以下几个权衡需要仔细考虑。
1. 属性粒度的取舍
是把每个阈值单独作为一个属性,还是把所有配置项合并成一个 JSON 对象属性?示例中 minAlarmThreshold 和 maxAlarmThreshold 分开定义,好处是平台可以单独修改其中一个,不用读写整个配置对象。如果配置项非常多(比如十几个),单独定义会导致属性列表过长,这时可以考虑用复合属性(如 alarmConfig,类型为 object)来管理。关键在于:频率高的读写操作应使用细粒度属性,低频的批量配置则适合复合属性。
2. 服务的同步与异步
示例中的 calibrateSensor 既有输入也有输出,看起来是同步的。但在许多 IoT 场景下,执行一个服务可能需要几秒甚至更久,设备无法实时返回结果。IoT DC3 中的指令模型采用异步设计:平台下发指令后,设备在另一个独立的信道上回复执行结果。设计服务时,必须明确标注它的调用模式。可以在 actions 定义里增加一个扩展字段,如 "invocation": "async",并说明超时时间和回调机制。
3. 事件的数据载荷
越界报警事件携带了 currentTemperature、thresholdValue、timestamp 三个字段。如果事件携带太多数据,会增加网络开销和平台负载。需要判断哪些是下游告警系统必须立即知晓的,哪些可以放到后续的接口中补充查询。例如,报警事件可以只携带 deviceId、eventType 和时间戳,详细的温度趋势数据设备可以缓存在本地,待平台后续通过属性拉取。这是一个典型的带宽 vs 实时性的权衡。
从物模型到平台交互
物模型定义一旦完成,平台就可以根据它自动生成数据存储模型、API 接口和 UI 控件。IoT DC3 提供了对应的 /profile API 来管理物模型(新增、查询、删除等)。设备接入时,只需要声明自己所属的物模型 ID(如 urn:dev:profile:temperature-sensor:t-100:v1),平台内部就自动知道该设备有哪些属性、支持哪些服务、能上报哪些事件,无需额外适配代码。设计物模型不是在描述“某一个设备此刻的状态”,而是在定义“这类设备能做的一切”。一个设计良好的物模型,能让上层应用开发变得更简单,也能让平台在接入新型号设备时,只需要解析一张新的“能力卡片”,而不是重写一套适配代码。这个思路,在下一节跨平台数据集成中会体现得更加明显。
至于物模型如何被上层 AI Agent 调用,我们将在第7章深入讨论。
3.7.3 物模型在数据互通中的实践
上一节为温度传感器定义了属性、服务、事件的能力卡片,一个型号的设备有了统一描述。但在真实项目中,很少有只接一种设备的情况:A 厂的温湿度变送器走 Modbus RTU,温度数据在第 3–4 字节以十六进制表达;B 厂的空调控制器用 KNX 总线,温度设定值对应一个通讯对象号;C 厂的智能电表遵循 DL/T645 协议,数据标识符层层嵌套。每个新品牌接入,应用团队都要学习私有协议、编写解析代码、反复调试位号映射。物模型真正要解决的核心问题,就是这套“异构数据归一”——让来源各异的物理量汇入同一个语义空间。
物模型在数据互通中扮演三层工程角色。
语义适配层消弭协议鸿沟。 物模型将设备能力抽象为属性(Property,即位号值,point value)、服务(Service)和事件(Event)三类,这与 W3C Web of Things Thing Description 对设备能力分类的逻辑相似。A 厂传感器输出十六进制帧“00 64”,适配层将两字节按大端拼接为 0x0064,即十进制 100,再乘以 0.1 的系数字段,得到 10.0℃;B 厂空调的 KNX 数据点“9.001”表达的也是标准浮点温度值。通过物模型,这两者的“温度”属性归入同一个位号。上层应用读取温度值时,完全不需要知道原始数据来自 Modbus 寄存器、KNX 通讯对象还是 DL/T645 数据标识符。这个适配过程通常在边缘网关或设备驱动层一次性实现,后续同型号设备接入复用同一套映射,无需重复编码。
设备影子(Device Shadow)拆解同步耦合。 物联网设备往往存在离线时刻——低功耗节点大部分时间休眠,或现场网络抖动导致连接断开。如果每次下发指令都要等待设备在线,业务流程会被拖死。设备影子就是缓冲区:平台持有设备的最新物模型状态,应用层对影子的某个属性(如“设定温度”)进行写操作,影子记录期望值;设备下次上线时主动拉取影子中的期望值,与当前状态对比,发现差异就执行同步。写操作不再被设备在线状况阻塞,同步问题转化为异步状态管理。这是物模型在平台解耦中最直接的工程收益——应用不感知设备在线状态,设备不感知应用调用时序。
降低应用对协议的耦合。 假设一套楼宇能源优化策略需要读取各层送风温度。若不同设备映射到兼容的物模型,核心计算可以复用;但单位、精度、采样周期、质量标记和可写范围仍可能不同,部署前必须做契约与现场验证。物模型减少协议适配代码,并不会让业务逻辑与基础设施“彻底解耦”。
用一个流程可以更直观地理解这种数据互通:温度传感器上报原始报文 → 边缘网关上的物模型适配器解析出“温度=25.3℃,湿度=60.2%RH”并更新设备影子 → 云平台应用通过同一物模型读取影子中的属性值。整个过程应用不接触任何私有通信细节,数据从感知层一路带着清晰的语义标签向上传递。实时监控面板、告警规则、能源报表都能在这个统一的语义空间里直接对话,不需要为每个厂商的私有格式单独处理。在 IoT DC3 这类平台中,物模型通过 /profile 系列的 REST API 管理,遵循“一个设备归属一个物模型,多个同型号设备复用一个物模型”的设计原则,将适配层逻辑集成到设备接入模块,让物模型成为整个数据流动的语义锚点。当后续 AI 层需要调用设备能力时,它同样通过物模型读写属性、调用服务,而不必重复处理协议碎片——这是从感知层到智能层实现统一数据模型的关键工程基础。