BACnet/IP 驱动
概述
BACnet/IP — 楼宇自动化(HVAC / 照明 / 消防 / 门禁)标准协议。基于 UDP/47808,按 BVLC + NPDU + APDU 分层工作。2026-07 原生重写 — 已移除旧的 Apache PLC4j bacnet-ip 委派方式(PLC4j 0.13.1 BACnet 为 canRead()=false(仅 passive/EDE),connect 时会抛出 "doesn't support reading" 异常,导致根本无法采集)。现改用 plantpulse-plc-protocol 中自研的 BACnet/IP confirmed ReadProperty 轮询实现(BacnetIpPLC) — 与 AB-ETH 相同的原生模式。
| 项目 | 值 |
|---|---|
opc_type | BACNET |
| 实现类 | plantpulse.driver.protocol.bacnet.BACnetDriver |
| 库 | 自研原生 (plantpulse-plc-protocol 的 bacnet — ReadProperty) |
| 继承 | BaseProtocolDriver (非 PLC4j) |
| 默认端口 | 47808 (0xBAC0, UDP) |
| 状态 | 稳定 (ReadProperty 轮询) |
| read | OK (ReadProperty,单个 property) |
| write | ❌ (只读 — 未实现 WriteProperty) |
| 安全 | 无 (不支持 BACnet/SC) |
无需 EDE 文件
旧的 PLC4j 实现通过 EDE(Engineering Data Exchange) CSV 文件静态映射对象列表。原生驱动不使用 EDE 文件 — 直接按标签地址发送 confirmed ReadProperty。旧表单中的 ede-file-path / ede-directory-path 选项将被忽略(已移除)。
类结构
BaseProtocolDriver
└── BACnetDriver — connect() 에서 BacnetIpPLC(host, port) 생성 (UDP connectionless)
UDP 是无连接的,因此没有握手 — 套接字就绪即视为连接完成,通信活性在 read 失败时由 setConnected(false) 管理(AB-ETH 模式)。read 失败时会将套接字置为无效,促使 Edge 重新连接。
wire 格式概要 (自研实现)
- BVLC(Block Virtual Link Control) → NPDU(Network) → APDU(Application)。
- ReadProperty-Request:
objectIdentifier+propertyIdentifier。 - ReadProperty-ACK: 将 BACnet 原始类型(Real / Unsigned / Boolean / Enumerated / CharacterString)解码为字符串。
- 不使用 BBMD(Foreign Device Registration) — 仅在同一子网的广播域内工作。
OPC 注册选项
| 字段 | 含义 | 默认 |
|---|---|---|
opc_agent_ip | BACnet device IP | 192.168.1.50 |
opc_agent_port | UDP 端口 | 47808 (通常固定) |
options.read-timeout | 响应超时 (ms) | 3000 |
标签 plc_address 格式
<object-type>:<instance>[:<property>]
省略 property 时,按 present-value 处理。object-type / property 既可用名称也可用数字代码。旧的 PLC4j 写法(property 前加点:analog-input:1.present-value)也兼容接受。
| 写法 | 含义 |
|---|---|
analog-input:0 | AI 0 的 present-value (REAL) — 省略 property |
analog-input:0:present-value | 同上 (显式指定) |
binary-input:1 | BI 1 present-value (Boolean) |
analog-value:10 | AV 10 (计算值) |
multi-state-input:2 | MSI 2 (Unsigned) |
device:1:object-name | Device 1 的名称 (CharacterString) |
0:5:85 | object-type 0(AI) / instance 5 / property 85(present-value) — 数字代码 |
支持 / 不支持
- read: ReadProperty (单个 property) — OK。
- write: 不支持 —
isWriteSupported() = false、write()始终返回false。(WriteProperty 后续实现。) - COV (Change Of Value) subscription: 不支持 — 基于轮询。
- BBMD / Foreign Device: 不支持 — 仅限同一子网。
- BACnet/SC (Secure Connect WebSocket) 及 BACnet MS/TP 串行: 不支持。
curl 注册示例
curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_BACNET_AHU1",
"opc_type": "BACNET",
"opc_name": "AHU-1 Controller",
"opc_agent_ip": "192.168.1.50",
"opc_agent_port": "47808",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 2000,
"options": { "read-timeout": "3000" },
"tag_list": [
{"tag_id":"OPC_BACNET_AHU1_T01","tag_name":"SupplyTemp","plc_address":"analog-input:0","data_type":"Float"},
{"tag_id":"OPC_BACNET_AHU1_T02","tag_name":"FanRun","plc_address":"binary-input:1","data_type":"Boolean"}
]
}'
参考
- BACnet ASHRAE 135 标准。
- 代码:
plantpulse-edge-driver/src/plantpulse/driver/protocol/bacnet/BACnetDriver.java+plantpulse-plc-protocol的bacnet包。 - 运维: 需要处于同一 L2 广播域。跨路由器的 device 需要 BBMD 或单独的网关(不支持)。