Files
home-automation/docs/references/SDM120-Modbus-Protocol.md
T
tliu93 0cb94d85ec docs(design): plan M4 login-hardening (first) + M5 IoT/energy
- Add docs/references/SDM120-Modbus-Protocol.md extracted from the SDM120 PDF
- M4 login hardening: brute-force exponential backoff, CLI escape hatch
  (reset-password/unlock/disable-totp), optional TOTP 2FA
- M5 IoT/energy: Modbus-TCP SDM120 polling + energy tables, MQTT/HA
  Discovery expose framework, frontend sidebar + energy view
- Add manual acceptance walkthroughs (M4 lock/unlock; M5 energy_cli read)
- Index both milestones in docs/design/README.md
2026-06-21 20:46:12 +02:00

7.8 KiB
Raw Permalink Blame History

SDM120 Modbus 协议(从官方 PDF 提取)

来源:docs/references/SDM120-MODBUS_Protocol.pdf Eastron SDM120 Modbus Smart Meter Modbus Protocol Implementation V2.4) 本文件是 PDF 的可读化提取,供本项目的 Modbus 采集驱动设计参考。以官方 PDF 为准,本文件如有出入以 PDF 为准。

0. 本项目的接入方式(重要)

SDM120 物理层是 Modbus RTURS-485 串口)。本项目通过一个 Modbus-TCP 网关接入:

  • 后端用 Modbus TCPIP:port)连到网关,网关在串口侧转成 RTU 与电表通信。
  • TCP 帧用 MBAP header、无 CRCCRC/Error Check 由网关在 RTU 侧处理)。本文档里 RTU 帧的 Error Check (Lo/Hi) 字段在 TCP 模式下不需要我们关心。
  • Slave Address / Unit ID = 电表的 Meter ID(默认 1,范围 1–247),在 TCP 请求里作为 unit id 传入。
  • 若以后直连串口(RTU),才需要管波特率 / 校验位 / CRC(见 §5 holding 寄存器)。

1. 协议帧格式

MODBUS 定义 master 查询 / slave 响应的格式。Eastron 电表用 16-bit 寄存器在主从间传值,但实际数据是 32-bit IEEE-754 浮点,因此每个测量参数占两个相邻的 16-bit 寄存器

Querymaster → slaveRTU 帧)

字段 说明
Slave Address 8-bit,目标从机地址 1247(0=广播,Eastron 不支持广播)
Function Code 8-bit,功能码(Eastron 支持 03 / 04 / 08 / 16(=0x10)
Start Address (Hi/Lo) 16-bit 起始寄存器地址;寄存器成对使用、从 0 开始,所以起始地址必须是偶数
Number of Points (Hi/Lo) 16-bit 请求的寄存器数量;也必须是偶数(成对读浮点)
Error Check (Lo/Hi) 16-bit CRCRTU 模式;TCP 网关模式无此字段)

Responseslave → master

字段 说明
Slave Address 响应从机地址
Function Code 与查询相同的功能码(表示识别并已响应)
Byte Count 8-bit,本次返回的数据字节数
Data (寄存器对) 每个寄存器 Hi byte / Lo byte,按"高寄存器在前"排列
Error Check (Lo/Hi) 16-bit CRCRTU 模式)

Exception Response(异常响应)

  • 异常响应的 Function Code = 查询功能码 OR 0x80(最高位置 1)。
  • 数据是单字节 Error Code(异常码)。
  • PDF 正文写了"见后文 Table Of Exception Codes",但提取的 8 页里没有附上该表。标准 Modbus 异常码(供参考,非本 PDF 内容):01 非法功能、02 非法数据地址、03 非法数据值、04 从机设备故障。

2. 功能码

功能码 作用 寄存器区
04 Read Input Registers(读输入寄存器,3X)—— 所有测量值都在这里 30001+
03 Read Holding Registers(读保持寄存器,4X)—— 配置项 40001+
16 / 0x10 Write Holding Registers(写保持寄存器,4X)—— 改配置 40001+
08 Diagnostics(诊断)

⚠️ 测量值用 FC 04(输入寄存器),不是 FC 03。 这是最常见的踩坑点。

3. 浮点数据编码

  • 每个参数 = 32-bit IEEE-754 float,占两个相邻 16-bit 寄存器。
  • 字序(word order)= 大端:高寄存器在前。
  • 字节序(byte order)= 大端:寄存器内高字节在前。
  • 即整体就是标准大端 float>f),4 字节顺序 = [Reg1 Hi][Reg1 Lo][Reg2 Hi][Reg2 Lo]

实例(来自 PDF

含义 原始 4 字节 (hex) 解码值
Volts 1 43 66 33 34 230.2 V
Demand Time 3F 80 00 00 1.0
Network Node 42 70 00 00 60.0

Python 解码:struct.unpack('>f', bytes([0x43,0x66,0x33,0x34]))[0]230.2。 pymodbus 用 BinaryPayloadDecoder.fromRegisters(regs, byteorder=Endian.BIG, wordorder=Endian.BIG)

4. 输入寄存器表(FC 04 读测量值)

全部为 Float,长度 4 字节,每项占 2 个寄存器。"Hex 起始"是 Modbus 协议起始地址(即 Start Address Hi/Lo)。

寄存器 参数 单位 Hex 起始
30001 Voltage(电压) Volts 0000
30007 Current(电流) Amps 0006
30013 Active power(有功功率) Watts 000C
30019 Apparent power(视在功率) VA 0012
30025 Reactive power(无功功率) VAr 0018
30031 Power factor(功率因数) 001E
30071 Frequency(频率) Hz 0046
30073 Import active energy(导入有功电能) kWh 0048
30075 Export active energy(导出有功电能) kWh 004A
30077 Import reactive energy(导入无功电能) kvarh 004C
30079 Export reactive energy(导出无功电能) kvarh 004E
30085 Total system power demand W 0054
30087 Maximum total system power demand W 0056
30089 Import system power demand W 0058
30091 Maximum import system power demand W 005A
30093 Export system power demand W 005C
30095 Maximum export system power demand W 005E
30259 Current demand Amps 0102
30265 Maximum current demand Amps 0108
30343 Total active energy(总有功电能) kWh 0156
30345 Total reactive energy(总无功电能) kvarh 0158

读取分块建议0x00000x005E(30001–30095)地址连续,可一次块读;0x0102/0x01080x0156/0x0158 各为独立小块。整表用 2–3 次块读即可覆盖,减少 Modbus 事务数。

常用核心子集(日常监控够用)

电压 0000、电流 0006、有功功率 000C、功率因数 001E、频率 0046、导入有功电能 0048、导出有功电能 004A、总有功电能 0156

5. 保持寄存器表(FC 03 读 / FC 16 写配置)

寄存器 参数 Hex 起始 格式 说明
40013 Relay Pulse Width 000C Float 继电器脉宽 60/100/200 ms,默认 100ms
40019 Network Parity Stop 0012 Float 0=1停止位无校验(默认),1=1停止位偶校验,2=1停止位奇校验,3=2停止位无校验;改后需重启生效
40021 Meter ID 0014 Float 从机地址 1247,默认 1
40029 Baud rate 001C Float 0=2400(默认)1=48002=96005=1200
40087 Pulse 1 output mode 0056 Float 0001 导入有功,0002 导入+导出有功,0004 导出有功(默认),0005 导入无功,0006 导入+导出无功,0008 导出无功
463745 Time of scroll display F900 HEX 2字节 滚动显示时间 0–30s,默认 0(不滚动)
463761 Pulse 1 output F910 HEX 2字节 0000:0.001kWh/imp(默认)0001:0.010002:0.10003:1 kWh/imp
463777 Measurement mode F920 HEX 2字节 1:total=import2:total=import+export(默认)3:total=import-export
464513 Serial number FC00 uint32 4字节 序列号,只读
464515 Meter code FC02 Hex 2字节 设备码=0020只读
464516 Software version FC03 Hex 2字节 软件版本,只读

⚠️ 写保持寄存器(改 Meter ID / 波特率 / 校验位等)会改变电表通信参数,配错可能导致通信中断。本项目默认只读采集,不建议在自动化链路里写电表配置。

6. 给本项目采集驱动的要点小结

  1. Modbus TCP 网关ModbusTcpClient(host, port)slave=<Meter ID>
  2. 测量值用 FC 04 / 输入寄存器,按 §4 地址读。
  3. 解码 大端 float32word & byte 都大端,高寄存器在前)。
  4. 起始地址与数量都用偶数(成对读)。
  5. 默认只读,不写电表配置寄存器。
  6. 不同型号电表 → 不同"寄存器 profile"。本表是 sdm120 这一个 profile 的定义。