2. ThingWorx基础架构与核心概念
ThingWorx 的建模体系本质上是一套“面向工业对象的软件抽象”。如果只记住术语名称,很容易在真正建模时把 Thing、ThingTemplate、ThingShape 混用,导致后续属性继承混乱、服务无法复用、事件订阅失效。理解这些概念的关键,不是背定义,而是弄清它们之间的“实例化关系”和“能力装配关系”。
一、从工业设备到软件对象:Thing 是实例
Thing 是 ThingWorx 中最基本的可运行实体,代表一个具体的“物”。在工业场景中,一台编号为 CNC-01 的数控机床、一个 T-101 温度传感器、一条 LINE-A 装配线,都可以建模为一个 Thing。Thing 拥有自己的属性值、可调用的服务、可触发的事件,并且有唯一的名称标识。
需要强调的是:Thing 是实例,不是模板。它承载的是“这一个对象当前的状态”。例如 CNC-01 这个 Thing 上,SpindleSpeed 属性当前值为 8200,RunState 为 Running,这些值随现场数据变化而变化。如果把 Thing 当成模板去复制,就会出现“改一个影响一片”的问题。
二、ThingTemplate:定义一类设备的公共能力
ThingTemplate 是“一类 Thing 的模板”。它规定了这类设备应该具备哪些属性、服务和事件。例如可以建立 CNCMachineTemplate,在其中定义 SpindleSpeed、FeedRate、RunState 三个属性,定义 Start()、Stop()、GetOEE() 三个服务,并声明 AlarmTriggered 事件。
当基于该模板创建 CNC-01、CNC-02 时,它们会自动继承这些属性、服务和事件。模板的价值在于“一次定义、多处复用”,同时保证同类设备的数据结构一致,便于后续批量做指标计算和统一告警。
三、ThingShape:可拼装的能力模块
ThingShape 是比 ThingTemplate 更细粒度的能力集合,它同样包含属性、服务、事件的定义,但设计目的是“被组合”。一个 ThingTemplate 可以继承多个 ThingShape,一个 Thing 也可以直接实现多个 ThingShape。
在工业场景中,这种机制非常实用。例如把“温度采集能力”做成 TemperatureSensorShape,把“振动监测能力”做成 VibrationMonitorShape,把“远程启停能力”做成 RemoteControlShape。一台设备如果同时具备这三种能力,就让它的模板同时继承这三个 Shape,而不必把所有定义都塞进一个庞大的模板里。这样能力可以跨设备类型复用,模型结构也更清晰。
四、属性、服务、事件、订阅:Thing 的四个行为面
属性(Property)描述 Thing 的状态,是数据的载体。属性有数据类型(如 NUMBER、STRING、BOOLEAN、DATETIME),还可以设置是否持久化、是否记录历史。工业场景中,Temperature、Pressure、RunState 都是典型属性。
服务(Service)是 Thing 上可被调用的逻辑单元,用 JavaScript 编写。服务可以读取属性、写入属性、调用其他服务、访问数据库或外部系统。例如 CalculateOEE() 服务读取 RunTime、DownTime、GoodCount、TotalCount 四个属性,计算并返回 OEE 值。
事件(Event)是 Thing 主动发出的通知,表示“某件事发生了”。事件可以携带事件数据,例如 AlarmTriggered 事件携带 alarmCode 和 alarmLevel。
订阅(Subscription)是事件与处理逻辑之间的绑定关系。当事件触发时,订阅所指定的服务会被执行。例如订阅 CNC-01 的 AlarmTriggered 事件,触发 SendMaintenanceTicket() 服务,实现“报警即派单”。
五、概念之间的实例化与装配关系
下面这张图把 ThingShape、ThingTemplate、Thing 三者的装配关系,以及属性、服务、事件、订阅在 Thing 上的挂载位置集中呈现出来,便于对照理解。
六、工业场景中的映射与建模建议
把上述概念落到真实产线时,可以按以下思路组织:先识别设备类型,为每类设备建立 ThingTemplate;再把跨设备类型的通用能力抽成 ThingShape,例如“采集能力”“告警能力”“控制能力”;然后为每台具体设备创建 Thing 实例,并绑定实际数据源。
属性设计要区分“实时值”和“统计值”。Temperature 是实时值,适合高频更新;DailyAvgTemperature 是统计值,适合由服务定时计算后写入。服务设计要遵循单一职责,CalculateOEE() 只负责计算,SendMaintenanceTicket() 只负责派单,避免一个服务既算指标又发通知又改属性。事件命名要体现业务含义,AlarmTriggered 比 Event1 更利于订阅方理解。订阅关系要避免循环触发,例如 A 事件触发 B 服务,B 服务又触发 A 事件,会造成无限循环。