用电信息采集系统通信协议集合解析与测试工具实战 简介面向电力行业开发、运维及测试人员的电力用户用电信息采集系统通信协议集合与配套测试工具重点覆盖376.1/376.2/376.3、645、698等常用规约可用于协议解析、设备联调、故障排查和采集系统功能验证。压缩包共89个文件约105.57MB包含37个txt协议说明与解析记录、7个exe测试工具、8个dll动态库、6个pdf文档以及doc/ini/config等配置与说明文件可支撑从协议学习到工具使用的完整闭环。具体内容包括QGDW1376.2解析、DLT698-45(1.0)国网电表测试软件、1376.1-2013、376.2Q-GDW集中器下行本地接口协议调试软件、645协议测试与DLT645标准测试程序等帮助开发者在真实场景中验证帧格式、命令交互和异常处理流程。已有3546人学习下载适合正在做电力采集主站、集中器或电能表通信模块开发需要对照标准规约进行联调与测试的技术人员。 干这行的人应该都有同感搞电力用户用电信息采集系统最磨人的往往不是业务逻辑而是协议。主站一套规约集中器一套规约到了表计又是另一套规约现场联调的时候A厂家和B厂家的帧对不上光靠肉眼看十六进制报文看得头大。我前前后后折腾了小半年把用采系统里主流的通信协议集合整理成了一套内部规范又配套做了一套测试工具才把联调和回归测试的效率拉起来。这篇文章就把这套协议集合的拆解思路和测试工具的实现细节都抖出来给做用电信息采集、智能表计、物联网网关的同行一个参考。这套东西适合谁看如果你正在写采集终端、集中器、表计的嵌入式代码或者在做主站与终端之间的协议适配又或者只是接了国网南网的项目需要过协议一致性检测那下面的内容基本都能直接用。我会从协议在整个系统里的位置说起再逐个拆传输协议、应用协议最后把测试工具的造帧、解析、自动化脚本思路完整过一遍。1. 用电信息采集系统里通信协议到底在管什么1.1 先理清三层架构才知道协议怎么分层用电信息采集系统在物理上一般分三层最上面是主站中间是采集终端最下面是电能表。主站负责数据汇聚、费控下发、线损分析采集终端集中器、采集器、专变终端负责把主站的命令翻译给下面的表计也把表计的数据汇总上报电能表就是最末梢的计量设备。通信协议就分布在两层链路上。主站与采集终端之间叫上行通道通常走无线公网、光纤或以太网常见协议是 DL/T 634.5101101、DL/T 634.5104104以及电力行业广泛使用的 Q/GDW 1376.1 主站与采集终端通信协议采集终端与电能表之间叫下行通道物理层走 RS-485、载波、微功率无线应用协议最典型的是 DL/T 645-2007 多功能电能表通信协议。两层链路协议不同所以采集终端本质上是个协议转换网关这也是为什么做这一点的人必须同时对上下行协议都有概念。1.2 为什么一个采集系统需要协议集合纯粹从抄表角度看一个集中器下面可能挂几十上百只表这些表不一定是同一个厂家的。有些工程是分批改造的一期装了A家的表二期装了B家的表但集中器不能换所以它必须能同时识别多套协议的变体。国网系统里现在在推 DL/T 698.45 面向对象协议南网和不少存量项目还在大量使用 DL/T 645主站与终端之间又各自有 1376.1、101、104 的混杂。协议集合这个概念本质上就是把上下行所有可能碰到的协议收拢到一个统一的字典和解析框架里谁的帧来了都能认谁的命令都能发。我见过最典型的坑是一个集中器固件里只写了645的读表逻辑现场换了一批698.45的新表直接抄不上数据。所以协议集合不是简单堆代码而是要有统一的数据模型去承载不同协议的差异。2. 核心协议逐个拆解链路层到应用层2.1 DL/T 645现场覆盖率最高的电表协议DL/T 645 是单费率、多费率电能表最常用的通信协议物理层以 RS-485 为主。它最核心的是帧结构起始符 68H6 字节地址域再一个 68H 起始符接着控制码、数据域长度、数据域、校验码 CS、结束符 16H。地址域特别容易踩坑。645 的地址域是低字节在前也就是表地址要反着放。如果你真拿十六进制串去做字符串匹配肯定对不上。控制码的高位区分方向主站请求和从站应答低四位是功能码常用的读数据命令是 11H写数据是 14H响应时方向位置1所以读数据应答是 91H。数据域里最关键的是四字节数据标识 DI它决定了你读的是正向有功电能、实时电压还是事件记录。校验 CS 是帧起始符到数据域最后一个字节的8位累加和注意不包含结束符这是手写解析器时最常错的点。2.2 DL/T 698.45面向对象的新一代协议698.45 和 645 完全不是一个思路。它不是简单的地址命令数据而是引入了基于对象的建模通过接口类、对象标识 OID、属性描述来访问数据。数据和操作都被抽象成对象抄表和费控变成对属性和方法的调用加上它支持 TLS 加密、长帧传输、多级应用层安全性比 645 高一个量级。但 698.45 的解析复杂度也明显高。一个 APDU 里面要处理 TLV 编码、对象列表、不同接口类的差异还要区分 CONNECT、GET、SET、ACTION 等多种操作。第一次写解析器的时候光一个时间对象的数据类型就能折腾半天。建议做 698.45 功能时先把它官方的接口类文档完整过一遍别直接上手写代码。2.3 上行协议主站和集中器如何对话上行协议在整个采集链路里容易被低估。Q/GDW 1376.1 是主站与采集终端之间最常用的协议之一它定义了登录、心跳、参数下发、数据上报、远程升级等一整套应用流程链路层有自己的帧格式、地址字段、帧序号和防止串帧/丢帧的校验机制。调试时顶层主站抓一个包过来如果不停做链路层之外的企业码、登录状态判断光链路层都会出很多问题。有些地区或项目会用 101/104 远动协议和主站通信规约结构跟 1376.1 有明显差异尤其是 104 这种走 TCP 的规约会有专门的 apci 控制域、序号区、类型标识调试工具里往往要单独适配。2.4 协议对比与选型建议协议应用位置典型物理层帧/报文复杂度是否加密适用场景DL/T 645-2007终端与电能表RS-485、载波低无存量表计、长期稳定DL/T 698.45终端与电能表RS-485、载波高可选 TLS新项目、国网采购Q/GDW 1376.1主站与终端4G/光纤中有认证机制用电信息采集主站DL/T 634.5104主站与终端TCP/IP中高可选SCADA/远动接入如果你在做新设备选型下行优先看能不能支持双向协议切换也就是 645 和 698.45 都保留避免现场换表之后固件又要重新开发。3. 测试工具为什么要自己造轮子3.1 现成工具不够用的地方很多人一开始会拿通用串口助手、Modbus 调试工具去抓 645 报文只能说能看个大概。645 的帧是二进制帧没有 ASCII 可读性一串 68 AA AA AA AA AA AA 68 11 04 33 33 34 33 直接贴在终端里别说校验对不对就连字段边界都要数半天。Wireshark 虽然能解析不少电力协议但 645/698.45 这类 RS-485 上的协议本来就不走 IP 链路抓包也要靠串口透传整体流程非常别扭。所以我的思路是自己做一个协议集合测试工具把帧构造、帧解析、链路收发、场景脚本、回归断言全部统一进来。工具不一定要图形界面命令行反而更适合自动化扔到 CI 里也能跑。3.2 测试工具的核心模块工具分成四个模块帧构造器、帧解析器、通信层、用例引擎。帧构造器负责按协议规则把所有字段拼成二进制帧自动算校验码你需要关心的只有业务参数。帧解析器反过来把收到的原始字节按照协议帧格式拆解输出控制码、地址、数据域、校验结果。通信层统一封装串口和 TCP串口用 pyserialTCP 用标准库 socket上层不用关心底层是 RS-485 还是网络。用例引擎负责把造帧、发帧、等响应、断言结果串成一条用例跑完自动出报告。3.3 工具实现从帧构造到校验核心代码直接抄我先给出 645 的部分。addr_to_bytes 把表地址转成6字节低字节在前build_read_frame 构造读数据帧parse_frame 把响应帧解析成可读字段。import serial import struct def addr_to_bytes(addr: str) - bytes: # addr 形如 12345678按645要求低字节在前 tmp bytes.fromhex(addr)[::-1] return tmp b\x00 * (6 - len(tmp)) def cs(data: bytes) - int: # 从起始符68到数据域最后一字节的累加和取低8位 return sum(data) 0xFF def build_read_frame(addr: str, di: bytes) - bytes: a addr_to_bytes(addr) body b\x68 a b\x68\x11 bytes([len(di)]) di body bytes([cs(body)]) body b\x16 return body def parse_frame(raw: bytes): if len(raw) 10 or raw[0] ! 0x68 or raw[-1] ! 0x16: return {error: not a valid dl645 frame} addr raw[1:7][::-1].hex() ctrl raw[7] length raw[8] data raw[9:9 length] cs_val raw[9 length] expect_cs cs(raw[:9 length]) return { address: addr, ctrl: hex(ctrl), length: length, data: data.hex(), cs_ok: cs_val expect_cs, }用的时候这样frame build_read_frame(12345678, bytes.fromhex(01000000)) print(frame.hex()) resp b\x68... # 现场收到的响应帧 parsed parse_frame(resp) if parsed.get(cs_ok): print(校验通过数据域:, parsed[data]) else: print(校验失败)这里数据标识 DI 在帧里是按协议规定的顺序拼接的具体读哪种数据你按规约表格填读电压、电流、电能用的 di 字节组都不一样。这段代码的关键思想是协议细节都被封装在 build 和 parse 两个函数里后续测试用例只需要关心参数。4. 实操用测试工具做一轮一致性验证4.1 环境准备与连接决策跑之前先想清楚你要模拟哪一侧。模拟主站时工具通过串口或网络连到集中器主动发命令、收响应模拟终端时工具要能接收主站连接并回应报文。做下行采集测试时工具连着的是一只真实的表计或一个能响应协议的虚拟表模拟器。我用的是 USB 转 RS-485 的适配器接表计 A/B 端时要确认共地不然信号飘得没法看。电平不对时表现为有帧出来但表无响应。波特率一般设置 2400、4800、9600 三档先拿默认 2400 测逐个往上试。4.2 造帧、发帧、解析响应的一次完整演示假设现在要通过集中器读一台 645 表计的正向有功总电能最朴素的流程是这样用 build_read_frame 构造读数据帧。如果连的是电表的 RS-485直接把帧通过串口发给表计如果连的是集中器则需要包一层上行协议的命令使得集中器知道你要下行抄表。等待响应收到帧后用 parse_frame 解析并断言控制码是应答帧、校验正确、数据域长度符合预期。把数据域按数据类型解析成十进制。下面是通信层封装的样例连真实表计前用虚拟表做了验证def read_meter(port: str, addr: str, di: bytes, baudrate2400): ser serial.Serial(port, baudrate, timeout1) frame build_read_frame(addr, di) ser.write(frame) raw ser.read(64) if not raw: return {error: timeout} return parse_frame(raw)实测下来2400 波特率下整个往返在几百毫秒到一秒之间。如果响应超时第一件事不是调协议而是检查 A/B 是不是接反、是否共地、终端地址是否匹配。地址错了表也会回帧但回的是地址不匹配之类的错误帧这种帧解析函数会报地址字段不等于请求地址。4.3 把单条命令变成自动化用例单条命令验证只是起点。协议一致性测试最怕的是重复劳动我通常会把常用业务操作整理成一张用例表用例编号操作预期结果TC-01读正向有功总电能返回91H应答帧数据域6字节电能值TC-02读电压返回数据域包含A/B/C三相电压TC-03广播校时表计无应答或按规约返回时间同步成功TC-04读事件记录若无事件返回空记录标识TC-05错误帧响应发送错误地址返回错误应答帧每个用例写成 Python 函数断言解析结果def test_read_energy(port, addr): result read_meter(port, addr, bytes.fromhex(01000000)) assert result.get(cs_ok) is True assert result[ctrl].endswith(91) print([PASS] read energy, data, result[data])把这些用例跑一轮能覆盖绝大多数厂商的协议实现雷区尤其是该回帧但不回帧地址域顺序混乱校验码算错这类问题在自动化下曝光率非常高。5. 现场问题排查速查全是踩过坑的经验5.1 排查思路链路、帧、业务三层分离遇到具体问题我习惯按三层排查先看物理链路通不通再看帧格式和校验对不对最后看业务数据和状态是否符合预期。千万别一上来就疯狂抓包不然很容易被各种无关的广播帧带偏。链路层重点查 A/B 接反、波特率、共地、终端上下拉电阻帧格式层重点查地址域顺序、控制码方向位、长度字节、CS 累加和业务层重点查数据标识 DI 是否匹配、费率/时标参数、表计是否处于载波休眠或自动轮显状态。5.2 常见问题速查表问题现象可能原因排查方法发送帧后无任何响应485 A/B 接反、波特率不匹配、未共地示波器或串口工具确收返回错误帧或地址错误地址域反序没处理、长度字段和实际数据不一致用 parse_frame 核对地址和长度数据域全 0 或明显不对DI 数据标识配错、费率对象选择错误对照规约表核对 DI偶发超时重发后正常半双工总线冲突、载波信道抢占增大帧间隔、减少并发命令CS 校验总是失败手工构造时把结束符 16H 算进累加和严格按帧格式排除结束符698.45 连接失败TLS 证书不匹配、CONNECT 流程未完成先抓 APDU 看是否在建立安全连接阶段失败主站和集中器交互超时心跳和登录态异常、链路序号不连续检查登录响应和心跳周期5.3 几条只有踩过坑才懂的经验第一个经验工具比人可靠。凡是需要重复操作的验证一定要脚本化。手动在终端里拼帧拼到第五十次的时候一定会打错校验码而脚本一次都不会错。第二个经验虚假的表计模拟器会害死人。我之前用一套自写模拟器测逻辑表计模拟器永远秒回正确帧一到现场发现真实表响应慢、偶发补帧程序直接超时。测试工具必须支持注入延时、注入错误帧、模拟异常长度才能把边界情况提前暴露出来。第三个经验协议版本归档要做进工具。现场最怕的是不知道当前电表固件、集中器固件支持哪个协议版本。我的工具在解析结果里会附带协议类型和版本字段这样现场排查时可以优先判断是不是版本差异。6. 最后再分享一点扩展思路协议集合测试工具做到后面已经不局限于 645 和 698.45 了。把上行协议也纳进来之后整套工具可以模拟主站直接驱动集中器做批量下行抄表也能模拟终端接主站验证主站的登录、参数下发、事件上报逻辑。进一步可以加进模糊测试的思路随机改帧里某个字节验证终端和主站会不会异常复位或漏处理这一层往往能提前发现安全性和健壮性问题。如果团队有条件还可以把协议解析和用例引擎拆成服务接到内部 CI 里每次固件提交都自动跑一遍全协议回归。个人觉得这套方案的长期价值不在于省了多少手工测试时间而在于把协议实现是否正确这件事变成了可量化、可追溯的自动化结果。踩过那么多坑之后我的体会是通信协议调试没有捷径但好的工具能把看不懂协议变成慢慢看懂了协议这个过程本身就是最大的收获。本文还有配套的精品资源点击获取