尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

智能电表调试必读:DLMS/COSEM报文抓包与解析实战

智能电表调试必读:DLMS/COSEM报文抓包与解析实战 干“抄表”这行大部分时间其实并不是在抄表而是在跟各种读不到数、读数异常、报文超时的现场问题打交道。智能电表也好集中器、主站系统也好只要牵扯到 DLMS/COSEM 协议基本都跑不掉 IEC 62056 报文。我第一次被报文“救回来”是某国外表计在集抄任务里总返回异常状态码厂商文档写得不痛不痒最后把抓包文件里的 HDLC 帧手工拆了一遍才定位到是 OBIS 对象编号和 attribute 选错。从那以后我就养成了一个习惯接到抄表相关的问题第一反应永远是先抓包再看协议解析最后才去翻厂商文档。这篇文章把我平时怎么抓包、拆帧、解析 APDU、把 OBIS 码对应到业务数据的整个流程完整写出来。适合正在做集中器调试、主站接入、掌机/APP 抄表模块或者刚进入能源计量领域的嵌入式开发者。读完之后你至少能自己打开一个 hex 文件从一帧7E开头的 DLMS 报文里把明确的表计对象和数值找出来。1. 从“读不到数”到“看报文”一个抄表调试官的必经之路1.1 为什么 IED 62056 报文的坑如此常见DLMS/COSEM 并不是单一的协议而是一整套面向计量设备通信的规范族IEC 62056 是它的国际标准版本。拆开来看DLMSDevice Language Message Specification管的是“报文该怎么组织语言”COSEMCompanion Specification for Energy Metering管的是“电表里的数据长什么样、用什么方式访问”。所以你会看到一根串口线上跑着 HDLC 数据链路HDLC 里面封装 APDU 应用层协议APDU 里的 OBIS 码才真正对应到电压、电流、有功电量这些业务数据。这种分层方式本身很漂亮但对现场调试者很不友好。协议栈从物理层到应用层隔了至少三四个层级任何一个环节出错表现到业务系统上都是统一的“读不到数据”或“返回异常”。不看报文你很难判断到底是集中器没有建立链路还是主站下发的 OBIS 错了又或者是表计返回的数据格式和你解析代码里写的不一致。1.2 “抄表程序员”与普通上位机开发者的区别做抄表相关开发最尴尬的地方在于你很难复现现场问题。实验室里的表计是厂商配好的协议参数、波特率、密钥全是已知的可到了现场一块运行了三五年的表可能被人改过端口地址可能连接的是某型号集中器透传甚至可能 RS-485 线序反了但偶尔又能通。纯靠日志和文档排查效率极低。所以我一直跟团队里的人说异常日志是别人的翻译抓包报文才是原始现场。你不需要每时每刻都去抓包但当业务逻辑推不动的时候一定要有能力把 Wireshark 打开把串口工具切到 HEX 模式把报文从链路层到应用层一层层剥开看。这就是我要写这篇长文的原因——我不打算重新科普一遍协议标准而是把我这些年认为最实用的报文解析方法按调试流程一步步摆出来。调试阶段看什么常用工具物理链路串口波形、电平、波特率示波器、逻辑分析仪数据链路HDLC 帧、7E 边界、FCS 校验Wireshark、串口助手应用层AARQ/AARE、Get/Set 请求响应Wireshark dissector、Gurux业务数据OBIS、COSEM 类、单位换算自写解析脚本、对象目录2. 抓包之前先把链路、端口和工具这盘棋走对2.1 先搞清楚报文到底从哪条路走很多人一上来就开 Wireshark结果抓了半天抓不到帧。原因很简单DLMS/COSEM 可以跑在多种介质上每种介质的抓包方式完全不同。最常见的三种链路是这样光学头/串口通过 IEC 62056-21 光电头和电表通信物理层就是 UART波特率常见 9600、19200、38400。抓包时用串口助手的 HEX 显示模式即可或者把串口接到逻辑分析仪上。RS-485 总线集中器和表计之间常用。这种链路需要总线监听设备或者直接在调试接口上并一根线出来避免影响正在运行的 485 通信。TCP/IP 网络很多集中器用 DLMS/COSEM over TCP或 UDP 包装。IANA 给 DLMS/COSEM 分配的默认端口是 4059但也有厂家自定义端口抓包前先确认端口号。我见过最多的情况是调试者拿了个串口助手一直盯着 ASCII 文本输出结果看到一堆“乱码”。这不是表计坏了而是 DLMS 报文本身就是二进制 HDLC 帧你必须切到 HEX 显示才能看到7E这种帧头。串口助手设置至少先保证这三项HEX 显示、HEX 发送、显示时间戳。显示时间戳极其重要因为你后面判断超时重发、AARQ 重连都依赖它。2.2 工具选型不是越贵越好而是用对场景我常态化使用的抓包工具组合很简单Wireshark、tcpdump、串口助手、逻辑分析仪。针对不同链路我会这样搭配链路场景抓包手段备注集中器和主站网络通信Wireshark 抓网卡过滤tcp port 4059也可用 tcpdump 在服务器上抓包本地串口调表串口助手 HEX 保存可以把字节完整落盘需要被动监听 485 总线逻辑分析仪或专用 485 监听器避免干扰现有通信集中器已接 4G / NB-IoT集中器侧抓网络报文或加镜像口需要厂商开发口支持Wireshark 对 DLMS 的解码支持在新版本里越来越完善。抓到 TCP 数据后可以选定一条 TCP 流右键 Decode As把端口或载荷强制解析成 DLMS如果版本较老没有这个选项就用“导出分组字节流”直接看原始 HEX手动拆 HDLC 帧。2.3 抓包前最容易踩的几个坑抓包本身不复杂但抓包之前的环境准备错误却很多。我总结成几条经验串口参数不一致最常见。DLMS HDLC 的帧头是7E如果你看到一堆乱码且没有 7E先看看波特率、数据位、校验位、停止位配置是否和表计一致。光学头接触不良光锥没对准、角度偏了会导致帧时断时续。Wireshark 抓错网卡笔记本访问集中器走的是无线网卡结果抓到的是本机虚拟机的虚拟网卡自然没有数据。没按表计的通信窗口抓包某些表计只在特定时间段响应命令过了窗口就静默抓包文件里只有客户端单方向的数据。抓包不止是“按个开始”你要在抓包前就明确三个问题报文的路径是什么物理链路是什么传输端口是什么。这三个问题只要有一个不明确后面的解析环节全都无从谈起。3. 拆开 HDLC 帧7E、帧格式字、地址和 FCS 之间到底藏了什么3.1 一帧 DLMS HDLC 报文的总体轮廓DLMS 在数据链路层用的是 HDLC 帧帧一般长这样7E | 帧格式字(2字节) | 目标地址 | 源地址 | HCS(2字节) | LLC(3字节) | APDU | FCS(2字节) | 7E首尾的两个7E是帧边界。你在串口助手里看到报文的第一个字节和最后一个字节都是7E基本可以确认这帧是 HDLC。中间的帧格式字两个字节里面包含了帧类型和帧长信息。举例来说A0 1F这一组工具解析出来通常表示这是一帧 31 字节的帧具体帧长需要看帧格式字里的低 12 位换算。帧类型这里要稍作区分I 帧传数据S 帧做链路流控U 帧做链路建立和拆除。U 帧常见的有 SNRM、UA、DISC在 DLMS 里面也有对应的十六进制特征看到类似93、73、53这种简单帧基本可以判断是在建链或者拆链。3.2 地址字段为什么不能当固定字节数来处理目标地址和源地址是关着电表通信身份的关键字段。DLMS 地址字段不是固定长度它可以是 1 到 4 字节甚至更长具体取值取决于地址编码规则。现场排错时你会发现不同厂家表计的地址长度差异很大有的表地址是对端地址1有的表地址是某个大的物理设备编号。最稳妥的做法是不要自己想当然Wireshark 会按 DLMS 的规则解析出 dest address 和 src address。如果你手动拆帧要把地址字段的“最终标志位”一起看了当地址字节包含继续扩展位时后面还会跟着后续字节。地址之后是 HCS帧头校验一般 2 字节接着是 LLC 逻辑链路控制字段。DLMS 的 LLC 通常固定为E6 E6 00这个特征非常好用。我在一串字节里只要能看到E6 E6 00就知道跟着它后面的一定是 APDU 应用层数据。3.3 分段机制拆了半个帧就开始解析会让你怀疑人生DLMS 一帧能装下的应用层数据有限超过链路层最大信息长度时就要分成多个段。分段在帧格式字里用标志位标记表示后面还有后续段。调试集中器时如果只抓到了第一段就急着用软件去解 APDU大概率会得到“报文长度不对”或“解析异常”的结果。正确的做法是先把分段重组再进入应用层解析。Wireshark 对这种多帧报文已经做了重组处理不过前提是你抓包的时候保证数据包完整别中途断流也别用一些会自动截断长度的抓包工具。3.4 手工拆一帧的实操演示我们拿一段示意性数据来做手工拆帧说明思路。7E A0 1F 03 00 11 E6 E6 00 60 1F A1 09 06 07 60 85 74 05 08 01 01 ... FCS 7E我来按顺序剥7E起始符A0 1F帧格式字解析出长度约为 31 字节帧类型为 I 帧03目标地址00 11源地址具体地址编码与厂家实现有关E6 E6 00LLC60 1F A1 09 06 07 60 85 74 05 08 01 01 ...这里就是 APDU60开头的通常是 AARQ 应用层关联请求最后两个字节是 FCS帧校验序列收尾7E第一次手拆帧不需要把每个字节都看懂。先学会“找 7E、数长度、找 LLC、分应用层”把层级边界找到后面的字段解析就是按部就班的事。我做了这么多年调试拆帧速度最关键的进阶点不是背长度表而是建立一种字段边界意识心里时刻清楚当前这个字节属于哪一层。4. APDU 应用层AARQ 握手和 Get/Set/Action 三兄弟4.1 AARQ/AARE通信双方先谈好条件再干活APDU 应用层的第一个常客是 AARQ应用联结请求。它的 tag 是0x60当客户端想和表计建立 DLMS/COSEM 会话时就会发一个 AARQ。服务端如果同意会回一个 AAREtag 是0x61。AARQ 里带着协议版本号、应用上下文名称、以及身份验证需要的参数。现场调试时你不需要把 AARQ 的每个嵌套字段都背下来但你要能认出60开头的报文是建链请求61开头的报文是建链确认。如果 AARE 返回的结果不是“接受”多半是密钥错误、客户端 SAP 不被支持、或协议版本不匹配。我在现场见过很多次这种场景主站软件里填了密码但电表里的安全模块已经换过密钥于是抓包里全是 AARQ 和 AARE拒绝循环。这种问题不看报文根本查不出来因为主站日志里只会显示“连接失败”。4.2 Get/Set/Action读数据、改参数、控制操作的三个动作DLMS/COSEM 的应用层操作抽象成三种基本动作Get读数据。请求 tag 是0xC0响应 tag 是0xC1Set写数据。请求 tag 是0xC2响应 tag 是0xC3Action执行方法。请求 tag 是0xC5响应 tag 是0xC6命令的 payload 里会带上 invoke-id用于把响应和请求匹配起来。多线程并发读表时invoke-id 如果没管理好就会出现响应错位。Wireshark 会显示invoke-id字段解析成脚本时千万要保留这个字段否则你没法判断响应对应的是哪一次请求。4.3 一条读正有功电量的典型请求假设我需要用 Get 请求读取总正向有功电量典型的 GetRequest 报文结构看起来是这样C0 01 01 02 01 00 01 08 00 FF 02这里只做层次说明不展开每个偏移量的绝对含义C0GetRequest01invoke-id 之类01表示 Normal 模式的读取02是类 ID表示 Register这个区域需要对照 COSEM 类定义01 00 01 08 00 FF就是 OBIS 码对应我们常写的1-0:1.8.0*25502attribute 编号对应 Register 的 value 属性响应报文也不会太复杂用C1开头后面跟着结果结果的数据字段里第一个字节是 DLMS 数据类型标签比如06是八位位组串、09是无符号长整数这一类的数据类型。然后才是真正的数值。很多初学者把数据类型标签当成业务数值去解析结果是把一个 32 位电量值拆成了好几个字节乱序展示这种错误在报文中非常明显只要你看过一次就不会忘。5. OBIS 与 COSEM 对象报文里的字节如何对应“正向有功电量”5.1 OBIS 码的六级结构其实不复杂OBIS 码是 DLMS/COSEM 里定位数据的“门牌号”它由 6 个字节组成写成人类可读的形式是 A-B:C.D.E*F。每一级都有自己的含义。我挑几个最常用的字段列出来OBIS 字段含义常见取值A计量范围/介质1 表示电2 表示气3 表示水B信道号0 表示默认通道三相表可能用 1、2、3C物理量1 正向有功2 反向有功3 正向无功4 反向无功D积算/变量类型8 表示电量积算值0 表示总量E缓冲区/时段0 当前值1/2/3 分别对应不同时段F费率/存储编号255 表示当前费率0-63 表示具体费率号所以1-0:1.8.0*255翻译成人类语言就是电介质、默认通道、正向有功、积算电量、总量、当前存储区。报文里对应的十六进制字节段就是01 00 01 08 00 FF。你要做的就是把这一串字节和工作票上的“正向有功总电量”映射起来。5.2 电能表常见的 OBIS 速查表不同厂商的表计 OBIS 会有细节差异但以下这几个在绝大多数 DLMS/COSEM 智能电表里都通用OBIS业务含义单位1-0:1.8.0*255组合正向有功电量kWh1-0:2.8.0*255组合反向有功电量kWh1-0:3.8.0*255组合正向无功电量kvarh1-0:4.8.0*255组合反向无功电量kvarh1-0:1.6.0*255正向有功最大需量kW0-0:1.0.0*255表计当前时间日期时间0-0:96.1.0*255表计资产/ID字符串这张表只能作为起步参考。我处理过的表计里真有厂商把电压 OBIS 放在1-0:32.7.0*255也有厂商把电压放在1-0:33.7.0*255差别还不小。所以拿到一张新表时第一件事是先把它的“对象目录”导出来确认每个 OBIS 的具体含义再写进你的解析配置。5.3 读秒表记录和曲线数据Profile Generic 才是大头日常抄表最常用的是 Register 类对象也就是 1-0:1.8.0 这种。但如果你想读冻结数据、日冻结、月冻结或者负荷曲线接触到的其实是 Profile Generic 类。Profile Generic 是一个通用配置类里面有一个“数据捕获对象列表”和一个“缓冲区”。缓冲区里顺序存放着每次冻结的多个对象值。解析这类数据时不能像读单个 OBIS 那样直接看一个值你要先读取它的捕获对象定义然后把缓冲区里的数据按定义顺序一个个拆开。我见过太多人卡在这一步试了很多次都读不出完整曲线原因是把缓冲区的数据当作单个寄存器去读拿到一堆错位的十六进制。正确流程是两步走先拿捕获对象定义再解缓冲区字段。抓包里呈现出来的就是一个 Get 响应里带着十几个字段每个字段又有自己的数据类型非常考验解析代码的健壮性。5.4 OBIS 解析最容易翻车的几个隐藏原因即便你把 OBIS 的结构背熟了现场还是会遇到奇怪问题。我这个人在调试时吃过不少亏把主要经验写出来多费率表计总量是 1.8.0但费率 1、2、3、4 分别可能是 1.8.1、1.8.2、1.8.3、1.8.4。有些表在 D 字段上的定义并不完全符合标准需要现场确认。class_id 与 attribute_id 组合错误同一个 OBIS 可以出现在 Register 类里也可以出现在 Profile Generic 类的捕获对象里。你用对 OBIS 但用错了类照样读不到。数据类型不匹配表计返回的数据类型可能和你写死的类型不一致比如部分表返回06八位位组串你按09无符号整数解析就会多出好几个字节。时区与冻结时刻差读历史曲线时时间字段解释错了数据本身没问题但图上就是不对。6. 现场排错从抓包结果反向定位故障的三层套路6.1 链路层的故障抓不到帧或者帧校验失败排错时我永远先把问题分成三层链路层、会话层、应用层。链路层最常见的表现是抓包文件里没有7E开头的完整帧或是一堆断断续续的字节。如果完全抓不到帧先查物理链路。串口通信的话看波特率RS-485 看 A/B 线是否接反集中器网络看 IP 和端口是否可达。如果能看到帧但 FCS 校验不过问题多半在电气干扰或者抓包工具丢包。HCS 和 FCS 的作用在这里就体现出来了——它不是摆设而是帮你快速区分“链路是否干净”的重要指标。6.2 会话层的故障握手建链反复失败会话层问题反映在报文中就是 SNRM/U A 或者 AARQ/AARE 来回反复。AARQ 发出去了AARE 一直不回来或者回的是失败结果常见原因有这么几类现象大概率原因验证方法AARQ 发出无响应表计非活动窗口或客户端地址不对查表计通信窗口确认地址长度AARE 返回拒绝认证参数错误或密钥不匹配替换正确密钥后重新抓包建链成功后马上断心跳超时或表计资源限制缩短间隔延长会话保持时间反复无响应重连并发连接占用表计会话数一下通道占用数释放无用会话现场最磨人的一点是很多表计同时只允许一个逻辑设备连接。你在 PC 上调试的时候如果集中器还占着这个会话你这边发 AARQ 就会被拒绝或者直接忽略。抓包前先确认没有其他客户端挂在表上这是经验之谈。6.3 应用层的故障读到了值但总感觉哪里不对链路层通了会话也建起来了最后发现读回来一个“离谱”的数据这就是应用层问题。处理方法也很直接就盯紧 APDU 里的数据类型、单位、系数三个点数据类型标签对不对。06还是09还是05决定了后续几个字节怎么拆。单位字段有没有被忽略。同样一个字节值单位可能是 V可能是 A也可能是 kWh。scaler 倍率有没有包含在数据里。很多 DLMS 类的属性里带一个 “scaler” 属性数值要先按 10 的幂次缩放。我曾经调试一块光伏表读出来电能量总是偏大 1000 倍。后来抓包一对照电表对象定义里明确写着 entity 的 scaler 是-3我解析脚本没处理这个字段直接把原始值显示出来了。协议栈从不骗人骗人的是我们总不看完整对象定义。6.4 一套可复制的排查顺序现在无论遇到什么问题我都按下面这个顺序查用抓包工具确认帧边界7E是否存在。检查 FCS/HCS 是否通过。判断帧类型是 I 帧还是 U 帧是不是分段报文。找到 LLC 后面的 APDU tag60、61、C0、C1等。把 OBIS 对应成业务字段同时记录 class_id 和 attribute_id。对照表计对象目录和单位、scaler最后再落库。这套流程看起来朴素但效率极高。因为它每一层都在用报文里的客观证据说话而不是靠猜。如果哪一步对不上就往哪一层去深挖基本不会跑偏。7. 把每次报文都变成自己的调试资产报文解析这件事做得多了你会有种手感看到7E就知道链路层没问题看到60就知道对方在请求建链看到C0就知道下一步响应应该是什么。这种手感不是背出来的是无数次抓包、拆帧、对照对象定义练出来的。我现在每处理一个现场异常都会把抓包文件、对象目录和解析脚本放到同一个目录下命名规范里面包含表计厂家、故障现象和日期。刚开始觉得多余半年之后再回看才发现那是宝贵的历史资产。再次遇到类似故障时翻一翻旧报文五分钟就能定位问题比什么文档都有说服力。DLMS/COSEM 报文并不可怕它只是把你的现场问题用十六进制的方式写了出来。只要你肯花一次完整的流程去抓包、去拆帧、去解析 OBIS之后再看 IEC 62056 里的那些“拦路虎”就会觉得难得多了。
返回列表