Skip to content

Real device profiles

Ralf Steinert edited this page Nov 1, 2026 · 1 revision

Three bundled profiles follow the published register maps of real products, so code written against them should work against the real device's map. They were built from public documentation, not from captured traffic, and are not verified on real hardware. Each profile file starts with a comment that lists its source and what it leaves out (modbus-sim map <profile> prints the map).

profile device source
eastron-sdm630 Eastron SDM630 three-phase DIN-rail meter Eastron "SDM630 Modbus Protocol" V1.5
omron-e5cc Omron E5CC temperature controller Omron "E5@C Digital Temperature Controllers Communications Manual" (H175), sections 3-2, 4 and 5
sunspec-inverter three-phase PV inverter with the SunSpec map SunSpec model definitions (github.com/sunspec/models), models 1 and 103

steitec is not affiliated with Eastron, Omron or the SunSpec Alliance; the names identify the documented register maps only. Firmware versions differ, so check your device's documentation.

How they were checked

  • Unit tests read each documented address and compare the value and encoding with the manual (tests/test_device_profiles.py).
  • Third-party clients against a running simulator: the sdm_modbus package reads all input and holding registers of the simulated SDM630; the SunSpec Alliance's pysunspec2 scans the inverter, finds models 1 and 103 and decodes every point with its scale factor.

eastron-sdm630

  • Input registers 30001–30381 (function 04): every parameter of the protocol — phase voltages, currents, active/apparent/reactive power, power factor, phase angle, averages and sums, frequency, import/export kWh and kvarh (total and per phase), kVAh, Ah, demand values with maxima, line-to-line voltages, neutral current, THD.
  • Holding registers 40001 ff. (functions 03/16): demand period, system type, pulse width, Modbus address, parity, baud rate, pulse divisor, password.
  • Everything is a float32 in two registers, most significant register first (ABCD). Address = register − 30001 (or − 40001).
  • Power factor sign: negative for inductive loads, as the protocol states.
  • Unlisted addresses read 0 (gaps: zero), so block reads across the map work.

Simplified: the real meter rejects odd register counts and requests over 80 registers — the simulator accepts them. THD is constant with a little noise; demand values are an exponential average, not fixed demand periods. Set-up registers are stored only (no password, no restart, no register-order switching). A reset_energy coil is added for tests; the meter has none.

$ modbus-sim serve eastron-sdm630
$ modbus-sim read input 0x46 -t float32           # 30071 frequency
input 70: 50  [4248 0000]
$ modbus-sim read holding 20 -t float32           # 40021 Modbus address
holding 20: 1  [3f80 0000]

omron-e5cc

Two-byte mode: every value is one signed 16-bit register, read with function 03; values carry the decimal point of the input type (here Pt100 with one decimal, so 215 = 21.5 °C).

Address Point
0x0000 operation command write only, function 06: high byte command, low byte information
0x2000 PV process value; 3276.7 (0x7FFF) on input error
0x2001 status lower 16 status bits (manual section 3-2)
0x2002 internal set point
0x2004 MV monitor (heating) % × 0.1
0x2103 set point −199.9 … 500.0
0x2402 / 0x2403 PV, internal set point copies
0x2404 multi-SP number 0
0x2406 / 0x2407 status lower / upper word
0x2410 decimal point 1
0x2600 manual MV used in manual mode

Communications writing. The E5CC refuses every setting write and every operation command (except command 00) with exception 04 (operation error) until communications writing is on. The profile starts with it off, so your code has to handle it:

Write to 0x0000 Meaning
0x0001 / 0x0000 communications writing on / off
0x0100 / 0x0101 run / stop
0x0900 / 0x0901 automatic / manual
0x0400 / 0x0401 write mode backup / RAM

A wrong command code or related information answers exception 03. The other commands of the manual (AT, multi-SP, alarm latch cancel …) are accepted without effect. model_params: {comms_write: true} starts with writing on.

Status bits set by the simulator: 6 input error, 8 control output (heating) in the lower word; 20 RAM write mode, 24 stop, 25 communications writing, 26 manual in the upper word (bit numbers as in the manual, the upper word is 0x2407 bits 0–15 = status bits 16–31). Alarm, heater current and event input bits stay 0.

Simplified: only two-byte mode (the four-byte addresses are not simulated, so 0x0000 is only the command register); no heater current, alarm values or status 2; the plant is a generic PI-controlled oven.

sunspec-inverter

40000  "SunS"                      (register 40001 in 1-based documentation)
40002  model 1 (common), length 66 manufacturer, model, options, version, serial, device address
40070  model 103, length 50        AC and DC values, energy, temperatures, state, events
40122  end model 0xFFFF, length 0
  • Integer values with scale-factor registers (A_SF = −2, V_SF = −1, W_SF = 0, Hz_SF = −2, PF_SF = −2, Tmp_SF = −1 …). The scale factors are fixed, as on many real inverters, so clients that read the *_SF registers and clients that hard-code them both work.
  • Operating state (40108): 2 sleeping (night), 4 MPPT (producing), 5 throttled, 7 fault. Events (Evt1, 40110–40111): bit 0 ground fault, bit 4 grid disconnect, bit 7 over temperature.
  • Optional points that are not simulated return SunSpec's "not implemented" values: int16 0x8000, uint16/enum16 0xFFFF, bitfield32 0xFFFFFFFF.
  • A day curve: between sunrise (6:00) and sunset (20:00) the power follows a half sine up to 10 kW; the energy counter (WH, acc32) integrates it. The simulated time starts at noon; model_params: {time_scale: 3600} runs a day in 24 seconds.
  • Faults: grid_loss (state 7, event bit 4, AC values 0), ground_fault (state 7, bit 0), over_temp (state 5 at half power, bit 7).

The device is generic — manufacturer "steitec", model "SIM-PV10" — not any vendor's inverter. Control models (120–127) are not included.

$ modbus-sim serve sunspec-inverter
$ modbus-sim read holding 40070 -c 2
holding 40070: 103  [0067]
holding 40071: 50  [0032]

Want another device?

Open an issue with a link to the public register documentation. Or write a profile yourself — the format is in the README.

Clone this wiki locally