DL/T645 驱动
dc3-driver-dlt645 通过 RS485 读取符合国标 DL/T645-2007 的电能表,按数据标识(DI0-DI3)解析数值。
协议背景
DL/T645-2007 是多功能电能表国标,帧以 68H 定界、携带 6 字节 BCD 表地址、以累加和结尾。
驱动 code:Dlt645Driver,类型:DRIVER_CLIENT,底层库:jSerialComm
属性配置
驱动属性
| 属性 | code | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
| Serial Port | port | STRING | /dev/ttyUSB0 | 串口设备路径 |
| Baud Rate | baudRate | INT | 2400 | 波特率 |
| Parity | parity | INT | 2 | 校验位(2=偶校验) |
| Timeout | timeout | INT | 1000 | 读超时(毫秒) |
| Meter Address | meterAddress | STRING | 000000000000 | 12 位 BCD 表地址 |
| Data Bits | dataBits | INT | 8 | 数据位 |
| Stop Bits | stopBits | INT | 1 | 停止位 |
| Write Password | password | STRING | 00000000 | 写表密码 |
| Operator Code | operatorCode | STRING | 00000000 | 操作员码(写表用) |
位号属性
| 属性 | code | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
| Data Identifier | di | STRING | 00010000 | 4 字节数据标识(DI0-DI3,默认组合有功总电能) |
| Data Format | dataFormat | STRING | HEX | HEX, BCD, INT, FLOAT, ASCII |
命令属性
| 属性 | code | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
| Data Identifier | di | STRING | 00010000 | 写数据标识(DI0-DI3,8 位十六进制) |
| Data Format | dataFormat | STRING | HEX | 写入值的编码:HEX, BCD, INT, FLOAT, ASCII |
写链路当前不读这张表
write() 从位号属性取 di 与 dataFormat,从设备属性取 meterAddress / password / operatorCode;这张表里的两条命令属性只在驱动的 application.yml 中注册,write() 并不消费。要改写行为,改位号属性。
采集与健康
- 采集周期:
read调度默认 cron0/30 * * * * ?(每 30 秒对所有位号跑一轮轮询)。 - 健康/在线:设备健康检查默认 cron
0/15 * * * * ?,租约超时45 秒。
能力矩阵
| 能力 | 支持 |
|---|---|
| 读 | ✓ |
| 写 | ✓ |
| 订阅 | — |
实现状态:完整
帧编解码(Dlt645Frame)与串口连接(Dlt645SerialPortConnection)已完整实现。
故障排查
串口设备的问题多半出在物理层与参数上,先对症状再下手。
Failed to open serial port 只说明串口没打开
路径不存在、驱动进程没有权限、串口被别的程序(串口调试工具、另一个驱动实例)占用,都会让 openPort() 失败并抛 ConnectorException。容器部署时还要确认串口设备真的挂载进了容器。
- 症状:
Invalid DL/T 645 meter address或Invalid hexadecimal value→ 原因:meterAddress必须是 12 位十进制数字,di、password、operatorCode必须是 8 位十六进制字符,长度或字符集不对会在组帧前就被拒掉。排查:对照表铭牌补齐前导零,meterAddress里不要出现 A-F。 - 症状:
Empty DL/T 645 response反复出现、连接反复重建 → 原因:表没有应答——表地址填错、波特率或校验位与表内设置不符、485 的 A/B 线接反。空应答会抛ReadPointException并作废连接,下一轮重开串口依旧如此。排查:用串口工具按同一组参数手发一帧读请求验证链路,再核对meterAddress、baudRate、parity。 - 症状:读抛
Unexpected DL/T 645 response control code,或写返回失败 → 原因:表回了非正常应答。读侧只认读应答控制码0x91/0xB1(含后续帧),别的控制码一律抛异常;写侧只有应答控制码为0x94才算成功,密码或操作员码不对、该数据标识不可写时表回错误帧,写返回 false 且不抛异常。排查:读侧确认di在表的数据标识表内;写侧核对password/operatorCode与表内通信参数一致。 - 症状:
checksum mismatch/response too short/invalid frame delimiters→ 原因:应答帧残缺或受干扰,典型是串口参数不匹配、总线干扰、timeout太短只收到半帧。排查:核对串口参数,必要时调大设备属性timeout。 - 症状:值读到了但量纲明显不对 → 原因:
dataFormat与该数据标识的实际编码不符。驱动完全按位号上的dataFormat解码,电表示值类数据标识多为 BCD,配成 FLOAT 会解出错值。排查:查该 DI 的编码格式(形如 XXX.X 的示值是 BCD),改对位号属性。 - 症状:设备在线但一直没有值 → 原因:健康检查只看串口句柄是否还开着,不代表表在应答;采集失败只落在驱动日志里。排查:翻驱动日志找
ReadPointException,按上面对号。
在 IoT DC3 中如何落地
一块 DL/T645 电表在平台里就是一个设备:串口参数(port / baudRate / dataBits / stopBits / parity / timeout)与表地址(meterAddress)全部填在设备属性上,驱动按 deviceId 为每台设备维护一条独立的串口连接,首次读、写或健康检查时才惰性打开。协议本身是 485 总线上一主多从的轮询模型,主机按 6 字节 BCD 表地址逐表寻址;一台设备只带一个表地址,总线上挂多块表就建多个设备,各填各的 meterAddress。
读链路:调度器默认每 30 秒逐位号调一次 read()。驱动用位号属性 di 组一帧控制码 0x11 的读数据请求发往串口,收到应答后校验累加和、把数据域逐字节减 0x33 还原,再按位号属性 dataFormat(BCD / INT / FLOAT / ASCII / HEX)格式化成字符串,封装成位号值送回平台。写链路复用同一组位号属性:write() 取位号的 di 定位数据标识、按 dataFormat 编码待写值,再从设备属性取 meterAddress / password / operatorCode 组控制码 0x14 的写数据帧,应答控制码为 0x94 即成功(命令属性不被 write() 消费,见上文警告);execute() 在本驱动没有实现,自定义命令走接口默认的空返回。
连接是自愈式的:读链路一旦抛异常,驱动就关闭并移除该设备的串口连接,下一轮访问重新打开;设备被删除或更新时,元数据事件同样会关掉旧连接。在线状态走健康检查加租约:健康检查默认每 15 秒一次,只确认串口句柄还开着,租约超时 45 秒,机制见设备。告警与联动由平台侧基于位号值触发,驱动不注册事件属性,与能力矩阵的「订阅 —」一致。
最小接入示例
- 选 DL/T645 驱动创建设备,填 port、baudRate=2400、parity=2、meterAddress。
- 加位号(READ_ONLY),填 di=02010100、dataFormat=FLOAT。
- 启动驱动,30 秒内即可看到采集值。