How to read a Modbus energy meter: register maps, float32 and word order

By Synacl · 9 min read · Published

Almost every DIN-rail energy meter sold today has a Modbus port, and reading one should take ten minutes. It usually takes an afternoon, because the datasheet's register map leaves three things for you to work out: which address the first register really is, how two 16-bit registers combine into one reading, and which way round the meter puts them. Get any of the three wrong and the meter answers perfectly while you chart nonsense, like a mains voltage of 17,254 V, or 0, or 80,871 A through a kettle. This guide explains how to read the register map, then decodes real values from an Eastron SDM630 and a PZEM-004T so you can recognise each mistake by its symptom.

Reading the register map

A meter's Modbus document is a table with one row per measurement. For the Eastron SDM630 it starts like this:

Parameter Datasheet address Wire address (hex) Format Unit
Phase 1 voltage 30001 0 (0x0000) Float V
Phase 1 current 30007 6 (0x0006) Float A
Phase 1 active power 30013 12 (0x000C) Float W
Total active power 30053 52 (0x0034) Float W
Frequency 30071 70 (0x0046) Float Hz
Import active energy 30073 72 (0x0048) Float kWh
Total active energy 30343 342 (0x0156) Float kWh

The datasheet address carries two facts in one number. The leading digit is the register table: 3xxxx is an input register, read with function code 04, and 4xxxx is a holding register, read with function code 03. The rest is a 1-based position within that table. The wire address is what actually goes into the Modbus request, and it is 0-based. So 30001 is input register 0, and 30073 is input register 72.

That off-by-one causes more wrong readings than anything else. If a datasheet gives only hex addresses (0x0048), those are already wire addresses. If it gives 30073, subtract 30001. Some documents use six digits (300073), which works the same way. The table matters as much as the address: reading holding register 72 on a meter that keeps its measurements in input registers returns zeros or an "illegal address" exception, not the value. Many meters keep their measurements in input registers and their settings (baud rate, parity, unit ID) in holding registers.

Why one reading takes two registers

A Modbus register is 16 bits. That holds 0 to 65,535, which isn't enough for a meter that reports 230.5 V to one decimal place or an energy counter in the tens of thousands of kWh. Meters solve this in one of three ways:

Format Registers How the value is stored Typical meters
16-bit integer + scale 1 2305 means 230.5 V ("×0.1") PZEM-004T voltage, many sensors
32-bit integer + scale 2 1234 means 1.234 A ("×0.001") PZEM-004T current, power, energy
32-bit IEEE-754 float 2 The value itself, 230.5 Eastron SDM series, most European DIN-rail meters

Integers can also be signed. A meter that measures export can report power as negative, and a signed 16-bit register holding −1 arrives as 65,535 if you read it as unsigned.

Here's what 230.5 V looks like on the wire from an SDM630. As a float its bit pattern is 0x43668000, so register 0 holds 0x4366 and register 1 holds 0x8000:

How you read registers 0–1 Result
Register 0 alone, as a 16-bit integer 17,254
Both, as a float, high word first 230.5 ✓
Both, as a float, low word first −2.4 × 10⁻⁴¹ (shows as 0)

The first row is the classic "my voltage reads 17,254" forum post. The fix isn't a scale factor. The value is a float, so you have to read both registers as one.

Word order: ABCD or CDAB

The Modbus standard defines the byte order inside a register (high byte first) but says nothing about the order of two registers that form one value. Vendors split into two camps:

Two rarer orders, BADC and DCBA, also swap the bytes inside each register. They mostly come from converters and PLCs, and you'll rarely see them on a meter.

The datasheet usually says which order it uses, if you know where to look ("high word first", "LSW first", "word order: little"). When it doesn't, the symptom tells you. Take a PZEM-004T drawing 1.234 A. It stores 1234 in two registers with the low word first: 0x04D2, 0x0000.

Read as Raw After ×0.001
32-bit, CDAB (correct) 1,234 1.234 A ✓
32-bit, ABCD (wrong) 80,871,424 80,871 A

A mismatched word order almost always produces values that are absurdly large, tiny, negative or NaN, not values that are slightly off. That's useful: if a reading is plausible but 10% out, the word order is right and the problem is elsewhere, usually the scale, or the CT ratio on a meter with external current transformers.

When you don't know the order, capture the raw bytes and try all four. The free Modbus frame decoder shows every register pair as a float and as 32-bit integers in all four orders and highlights the most plausible one, and the Modbus RTU tester reads the registers straight from the meter through a USB-RS485 adapter in Chrome.

Scaling and units

Floats need no scaling: 230.5 is 230.5 V. Integers almost always do, and the datasheet expresses it three different ways, all meaning the same thing:

Two unit traps are specific to energy meters:

  1. Wh versus kWh. The PZEM-004T counts energy in Wh, so a scale of ×0.001 turns it into kWh. Eastron floats are already in kWh. Mix the two on one dashboard and a building appears to use a thousand times more than its neighbour.
  2. CT meters. A meter with external current transformers either takes the CT ratio in its setup menu and reports primary current, or reports secondary current and expects you to multiply. The datasheet says which. The symptom of getting it wrong is a reading off by a constant factor such as 20 or 40.

kWh counters that add up

The energy registers are counters: they only ever go up, and they survive power cuts because the meter stores them in non-volatile memory. That changes how you compute consumption:

Serial settings and the bus

A meter that doesn't answer is almost always one of these, in rough order of likelihood:

Check Why it bites
Baud rate The SDM120 ships at 2400 baud, while the SDM230, SDM630 and PZEM-004T ship at 9600. One wrong default meter on a 9600 bus is invisible.
Parity 8N1 and 8E1 are both common defaults. A parity mismatch looks like total silence, not garbage.
Unit ID Most meters leave the factory as ID 1. On a bus with several meters, give each a unique ID from its front panel before you wire them together.
A/B swapped Vendors disagree on which terminal is A. If nothing answers, swap the two wires once.
Termination and ground 120 Ω across A/B at each end of a long run, and a common reference between devices. Intermittent timeouts are usually this.

Bus time matters once there are several meters. Each value is one request and one response. At 9600 baud a two-register read takes a few tens of milliseconds including the meter's reply time, so fifteen values from each of ten meters take several seconds per pass. At 2400 baud it's four times that. If you plan to read many values from many meters, raise every meter to 9600 or 19200 from its setup menu, and poll only the values you'll actually use.

The PZEM-004T v3 is a special case: its header is 5 V TTL serial, not RS485. It speaks Modbus RTU, but it needs a TTL-to-RS485 converter to share a bus with other meters. It also answers the broadcast-style address 0xF8 when it is the only device on the line, which is a handy way to find a board whose ID you don't know.

Reading a meter with Synacl

Synacl's ESP32 gateway reads Modbus RTU meters on its RS485 port, and every value in this guide maps onto a tag's fields:

32-bit formats are decoded on the gateway and need gateway firmware 1.5.4 or later, which is the current stable release. The app won't save a 32-bit tag on a gateway whose firmware can't decode it, and tells you to update over the air instead. That's better than silently charting 17,254 V.

You don't have to type the register map. The device catalog has pages for the Eastron SDM120, SDM230, SDM630 and PZEM-004T v3, each with its register map, serial defaults and wiring. In the app, Add device → Start from a catalog device fills in the connection settings and every tag with its format, word order and scale. You only pick the gateway and adjust the unit ID. The catalog entries are built from the vendors' own Modbus documents, and each page says so. If a reading doesn't match the meter's display, the page has a link to report it.

The gateway can poll the bus as often as every ten seconds, separately from how often it publishes, so gateway-side macros react quickly while the cloud stores readings at the publish interval you choose. Rules use the scaled value, so "alert if phase 1 current > 32" means 32 A. The energy counters chart as a climbing line, and consumption over any period is the difference between two points on it.

If you have no meter to hand, the free Modbus slave simulator turns a laptop and a USB-RS485 adapter into one, including float and word-swapped values, so you can check a whole configuration before you're on site. For the first wiring job from scratch, ESP32 Modbus RTU to a cloud dashboard goes from bare board to live chart, and Modbus RTU vs Modbus TCP helps when a meter offers both.

Try it on your own hardware

Synacl is free for five devices — no card, no sales call. Flash a gateway from the browser, add your first device, and see live data in a few minutes.