ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

03-BACnet对象模型详解

03-BACnet对象模型详解 目录BACnet 对象模型详解设备、对象与属性一、BACnet 对象模型概述对象模型的核心价值自描述的聚合数据点二、标准对象类型对象的标识类型 实例号对象实例号的几个要点三、标准属性点对象AI/AO/AV/BI/BO/BV 等共有的属性Analog Input 对象的典型属性四、设备对象Device Object设备实例号的几个要点五、对象模型的 C 语言表示六、属性访问的 C 语言实现七、对象模型的扩展性八、小结BACnet 对象模型详解设备、对象与属性一、BACnet 对象模型概述BACnet 的核心抽象是对象模型。在 BACnet 看来网络上的所有数据和行为都被建模为对象每个对象拥有一组属性。这种设计将楼宇设备中千差万别的物理量温度、湿度、开关状态、设定值等统一为标准化的数据结构使不同厂商设备可以无歧义地交换信息。BACnet 对象模型包含三个层次设备Device └── 对象Object └── 属性Property这是一个包含关系设备里有对象对象里有属性不是分类关系。三者各自的角色层次角色能否独立寻址类比设备物理硬件是所有对象的容器通过设备实例号寻址文件柜对象设备内的一个数据点或功能单元通过对象标识符类型实例寻址柜子里的文件夹属性对象内的一个数据字段不能必须依附于对象文件夹里的文件需要注意属性不是对象。对象有自己的标识符Object Identifier会出现在设备的 Object List 中可以被独立创建和删除属性只有一个编号如 Present Value 85必须依附于某个对象不能脱离对象单独访问。读数据时需要先指定对象再指定属性两级定位。以一台空调控制器为例它的内部结构大致如下设备空调控制器Device Instance 100 │ ├── 对象1Analog Input 0回风温度传感器 │ ├── 属性Present Value 24.5 ← 当前温度 │ ├── 属性Units ℃ ← 工程单位 │ └── 属性High Limit 30 ← 报警上限 │ ├── 对象2Analog Input 1送风温度传感器 │ └── 属性Present Value 18.2 │ ├── 对象3Binary Output 0风机启停控制 │ └── 属性Present Value Active ← 风机正在运行 │ └── 对象4Device 100设备自身信息 ├── 属性Vendor Name 某某厂商 └── 属性Object List [AI-0, AI-1, BO-0, Device-100]要读取回风温度路径是找到设备 100 → 找到 Analog Input 0 → 读取 Present Value → 得到 24.5。这就是 BACnet 读写操作的基本路径设备 → 对象 → 属性三层逐级定位。每个 BACnet 设备至少包含一个设备对象以及若干个其他类型的对象用于表示设备所监控或控制的物理量。对象模型的核心价值自描述的聚合数据点理解了对象模型的结构自然会产生一个问题为什么要这么设计与传统协议如 Modbus相比对象模型的优势在哪里传统协议的方式数据是分散的在 Modbus 里一个温度点的信息散落在不同寄存器中而且很多信息协议本身根本不携带信息在哪里说明温度值寄存器 40001只有一个原始数值单位℃不在协议里靠集成商在 SCADA 里手动配置报警上限寄存器 40010或没有可能是另一个寄存器也可能根本没有描述回风温度不在协议里靠集成商在 SCADA 里手动命名传感器是否故障不在协议里靠集成商自己判断也就是说Modbus 只传一个裸数字至于这个数字是什么单位、叫什么名字、什么时候该报警——协议不管全靠集成商在工程现场手动配置。换一个项目、换一个人就得重新配一遍。BACnet 的方式相关信息聚合成一个对象同样的温度点在 BACnet 里是一个 Analog Input 对象所有相关信息都聚合在一起Analog Input 0回风温度 ├── Present Value 24.5 ← 数值 ├── Units ℃ ← 单位协议自带不用外部配 ├── High Limit 30 ← 报警上限协议自带 ├── Low Limit 10 ← 报警下限协议自带 ├── Deadband 0.5 ← 报警死区 ├── Description 回风温度 ← 描述协议自带 ├── Event State Normal ← 当前是否报警 ├── Status Flags (正常) ← 是否故障/被覆盖/越限 └── Out Of Service false ← 是否处于维护状态关键区别自描述 vs 需要外部配置传统协议ModbusBACnet数值有有Present Value单位没有靠外部配有Units 属性报警限可能没有或散在别的寄存器有High/Low Limit 属性描述没有靠外部命名有Description 属性故障状态没有靠外部判断有Status Flags / Event State设备自我描述不能能Device 对象带厂商、型号、固件版本等BACnet 对象是自描述的——用 ReadProperty 读一个对象不仅能拿到数值还能拿到单位、报警限、描述、状态不需要任何外部配置文件。这种聚合带来三个直接好处减少外部配置不用在 SCADA 里手动填单位、报警限、描述设备自己就告诉你了。避免配置不一致传统协议里现场改了报警限但 SCADA 没同步就会出错BACnet 里报警限就在对象里读出来就是当前值。跨厂商即插即用换一台不同厂商的设备只要对象类型一样上位机不用改任何配置就能读到完整的温度信息。一句话总结传统协议传的是散落的裸数据BACnet 传的是聚合的、自描述的数据点——把一个物理量相关的所有信息值、单位、限值、描述、状态打包在一起让数据点自己会说话。这正是对象模型的精髓。二、标准对象类型BACnet 标准至今已定义 60 余种标准对象类型BACnet-2020编号 0–62涵盖照明、电梯、门禁、审计等对象族每种对象对应一类楼宇自动化场景。下表列出最常用的几种对象类型类型编号用途Analog Input模拟量输入0读取模拟量传感器如温度、压力、流量Analog Output模拟量输出1控制模拟量执行器如调节阀开度Analog Value模拟量值2软件计算的模拟量如设定值Binary Input二进制输入3读取开关量传感器如水流开关、运行状态Binary Output二进制输出4控制开关量执行器如风机启停、灯具开关Binary Value二进制值5软件计算的开关量Multi-state Input多态输入13多状态反馈如风机档位Multi-state Output多态输出14多状态控制如三档风机控制Schedule日程17时间表控制Program程序16内置控制程序Device设备8设备本身的信息Trend Log趋势记录20历史数据记录对象的标识类型 实例号每个对象都由一个 32 位的对象标识符Object Identifier唯一标识其中高 10 位为对象类型低 22 位为对象实例号对象类型Object Type10 位标识对象种类如 Analog Input 0、Device 8。标准对象类型编号固定如上表厂商可定义私有对象类型编号 ≥ 128以满足特殊需求。对象实例号Object Instance22 位范围 0 ~ 4194303用于在同一设备内区分同类型的多个对象。对象实例号的几个要点1. 唯一性范围设备内 同类型对象实例号只在同一设备内、同一对象类型间唯一。不同类型的对象可以复用同一个实例号。例如一台设备里可以同时存在Analog Input实例 0回风温度Analog Input实例 1送风温度Binary Output实例 0风机启停Binary Output实例 1水阀开关这里Analog Input 0和Binary Output 0实例号都是 0但因为类型不同并不冲突。组合(类型, 实例)即可在一个设备内唯一定位一个对象。2. 分配方式对象实例号通常由设备厂商在出厂时设定默认值或由集成商在工程调试时通过配置工具修改写入非易失存储后开机自动加载。正常运行期间一般不改动——改了会导致所有引用该对象的联动、趋势记录、COV 订阅失效。和设备实例号一样属于配一次、用很久的参数。3. 跨网络定位对象三段式地址(对象类型, 对象实例号)只能在一个设备内定位对象。要在整个 BACnet 网络中定位一个对象还需要加上设备实例号形成三段式地址设备实例号 对象类型 对象实例号例如设备 100 的 Analog Input 1就唯一确定了全网中的某个温度采集点。BACnet 的 ReadProperty 等服务在请求报文中携带的就是这三个参数。三、标准属性每个对象都拥有一组属性属性是 BACnet 数据交互的最小单位。所有对象都共享一些通用属性同时每种对象类型还有自己的专属属性。点对象AI/AO/AV/BI/BO/BV 等共有的属性注真正所有对象类型都必选的只有Object Identifier、Object Name、Object Type三个。下表中的Present Value、Status Flags、Event State等主要适用于点对象模拟量/二进制/多态的输入、输出、值Device、File、Notification Class 等对象并不一定具备这些属性。属性数据类型必选/可选说明Object IdentifierBACnetObjectIdentifier必选对象唯一标识Object NameCharacterString必选对象名称Object TypeBACnetObjectType必选对象类型DescriptionCharacterString可选对象描述Present Value视对象类型而定必选对象当前值Status FlagsBACnetStatusFlags必选状态标志故障、覆盖、越限、报警Event StateBACnetEventState必选事件状态正常、报警、故障等ReliabilityBACnetReliability可选可靠性状态Out Of ServiceBoolean必选是否处于维护状态Update IntervalUnsigned可选数据更新间隔Analog Input 对象的典型属性属性说明Present Value当前测量值浮点数Units工程单位如 ℃、Pa、kWhCov IncrementCOV 通知的最小变化量High Limit / Low Limit报警上下限Deadband报警死区Resolution测量精度Device Type传感器型号四、设备对象Device Object每个 BACnet 设备必须且只能包含一个 Device 对象它描述了设备本身的信息是设备发现和管理的入口。Device 对象的关键属性包括属性说明Object Identifier设备对象标识格式为(8, 设备实例号)类型固定为 8Vendor Identifier厂商编号由 ASHRAE 分配Vendor Name厂商名称Product Name产品名称Model Name产品型号Firmware Revision固件版本Application Software Version应用软件版本Protocol Version支持的 BACnet 协议版本Protocol Services Supported支持的服务列表位图Protocol Object Types Supported支持的对象类型列表位图Object List设备中所有对象的列表Max APDU Length Accepted设备能接收的最大 APDU 长度Segmentation Supported是否支持报文分段APDU Segment Timeout分段超时设备实例号的几个要点设备实例号Device Instance是 BACnet 网络中设备的唯一标识范围 0 ~ 419430322 位。它不是 Device 对象的一个独立属性而是 Device 对象的 Object Identifier 的实例号部分——因为 Device 对象的类型固定为 8所以(8, 设备实例号)中真正起区分作用的只有实例号。1. 唯一性范围整个 BACnet 互联网络与对象实例号设备内同类型唯一不同设备实例号必须在整个 BACnet 互联网络范围内唯一——跨越所有网络号、所有链路层。如果两台设备实例号相同Who-Is 会收到两条相同实例号的 I-Am地址绑定表会混乱系统无法正确寻址。2. 分配方式出厂时厂商通常给一个默认值常见为 0 或最大值不是最终使用的值。系统集成商在工程调试时通过 WriteProperty 修改 Device 对象的Object_Identifier属性来设定写入非易失存储后开机自动加载。正常运行期间一般不改动——改了会导致所有引用该设备的绑定、联动、COV 订阅失效相当于改名代价很大。3. 在寻址中的作用设备实例号是三段式地址设备实例号 对象类型 对象实例号的第一段。要在整个 BACnet 网络中定位一个对象必须先通过设备实例号找到设备再由对象类型和对象实例号定位设备内的具体对象。五、对象模型的 C 语言表示以下代码展示如何用 C 结构体表示 BACnet 对象模型#include stdint.h #include stdbool.h ​ /* 对象类型枚举 */ typedef enum { OBJ_ANALOG_INPUT 0, OBJ_ANALOG_OUTPUT 1, OBJ_ANALOG_VALUE 2, OBJ_BINARY_INPUT 3, OBJ_BINARY_OUTPUT 4, OBJ_BINARY_VALUE 5, OBJ_DEVICE 8, OBJ_MULTI_STATE_INPUT 13, OBJ_MULTI_STATE_OUTPUT 14, /* ... 其他类型 ... */ } bacnet_object_type_t; ​ /* 对象标识符类型 实例号共 32 位 */ typedef struct { uint32_t type : 10; /* 对象类型10 位 */ uint32_t instance: 22; /* 对象实例号22 位 */ } bacnet_object_identifier_t; ​ /* 工程单位部分 */ typedef enum { UNITS_DEGREES_CELSIUS 62, UNITS_PASCAL 113, UNITS_KILOWATT_HOURS 19, UNITS_PERCENT 98, } bacnet_units_t; ​ /* 状态标志 */ typedef struct { bool in_alarm; /* 报警中 */ bool fault; /* 故障 */ bool overridden; /* 被覆盖 */ bool out_of_service; /* 维护中 */ } bacnet_status_flags_t; ​ /* 模拟量输入对象 */ typedef struct { bacnet_object_identifier_t object_id; const char *object_name; const char *description; float present_value; /* 当前值 */ bacnet_units_t units; /* 工程单位 */ bacnet_status_flags_t status_flags; /* 状态标志 */ uint8_t event_state; /* 事件状态 */ bool out_of_service; /* 维护状态 */ float cov_increment; /* COV 变化量 */ float high_limit; /* 报警上限 */ float low_limit; /* 报警下限 */ float deadband; /* 死区 */ } bacnet_analog_input_t; ​ /* 设备对象 */ typedef struct { bacnet_object_identifier_t object_id; /* (8, device_instance) */ uint16_t vendor_id; const char *vendor_name; const char *product_name; const char *model_name; const char *firmware_revision; uint32_t protocol_version; uint16_t max_apdu_length_accepted; bool segmentation_supported; /* Object List 由运行时维护此处省略 */ } bacnet_device_object_t;六、属性访问的 C 语言实现下面是一个通用的读属性函数示例展示如何按属性编号访问对象/* 属性编号部分 */ typedef enum { PROP_OBJECT_IDENTIFIER 75, PROP_OBJECT_NAME 77, PROP_OBJECT_TYPE 79, PROP_PRESENT_VALUE 85, PROP_STATUS_FLAGS 111, PROP_EVENT_STATE 36, PROP_OUT_OF_SERVICE 81, PROP_UNITS 117, PROP_DESCRIPTION 28, PROP_HIGH_LIMIT 45, PROP_LOW_LIMIT 59, PROP_DEADBAND 25, PROP_COV_INCREMENT 22, } bacnet_property_id_t; ​ /* 读取 Analog Input 对象的属性 */ int analog_input_read_property(const bacnet_analog_input_t *obj, bacnet_property_id_t prop, uint8_t *out_buf, uint16_t *out_len) { switch (prop) { case PROP_OBJECT_IDENTIFIER: memcpy(out_buf, obj-object_id, sizeof(obj-object_id)); *out_len sizeof(obj-object_id); return 0; case PROP_OBJECT_NAME: strncpy((char *)out_buf, obj-object_name, *out_len); *out_len (uint16_t)strlen(obj-object_name); return 0; case PROP_PRESENT_VALUE: memcpy(out_buf, obj-present_value, sizeof(float)); *out_len sizeof(float); return 0; case PROP_UNITS: memcpy(out_buf, obj-units, sizeof(obj-units)); *out_len sizeof(obj-units); return 0; case PROP_STATUS_FLAGS: memcpy(out_buf, obj-status_flags, sizeof(obj-status_flags)); *out_len sizeof(obj-status_flags); return 0; default: return -1; /* 不支持的属性 */ } }七、对象模型的扩展性BACnet 对象模型具有良好的扩展性体现在两个方面新增对象类型厂商可定义私有对象类型编号 ≥ 128用于表示特殊设备的功能。私有对象在标准对象无法覆盖的场景下使用。新增属性厂商也可为标准对象添加私有属性编号 ≥ 512注意与私有对象类型的 ≥ 128 区分用于厂商专有功能扩展。这种扩展机制使 BACnet 既能保证标准设备间的互操作又能为厂商差异化功能留出空间。但需要注意私有扩展应作为附加而非替代否则会破坏互操作性。八、小结BACnet 对象模型是整个协议的基石。设备—对象—属性的三层抽象将楼宇设备中纷繁复杂的数据统一为标准化的数据结构使不同厂商设备能够无歧义地交换信息。理解对象类型、对象实例号、属性编号这三个核心概念是阅读 BACnet 报文、开发 BACnet 应用的前提。后续文章将在此基础上展开服务机制——即如何通过 BACnet 服务对对象属性进行读写、订阅与控制。
返回列表