Repository navigation
Real device profiles
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.
- 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_modbuspackage reads all input and holding registers of the simulated SDM630; the SunSpec Alliance'spysunspec2scans the inverter, finds models 1 and 103 and decodes every point with its scale factor.
- 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]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.
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*_SFregisters 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]Open an issue with a link to the public register documentation. Or write a profile yourself — the format is in the README.
modbus-sim · MIT licensed · Eastron, Omron and SunSpec are trademarks of their owners; modbus-sim is not affiliated with them.