- Go 99.3%
- Makefile 0.7%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
New commands: - save: reads PARAMS block and writes to YAML with raw values for lossless round-trip - load: reads settings YAML, shows dry-run preview, writes with --yes confirmation - set: writes a single register by address or name, accepts numeric and enum labels Adds write support to transport layer (FC06 via simonvetter/modbus WriteRegister), value encoding (reverse of interpretation with range/enum validation), and device write orchestration with safety guards for dangerous registers (RESET, RESTART ISG). |
||
| cmd/stiebel-modbus | ||
| internal | ||
| .gitignore | ||
| CLAUDE.md | ||
| config.yaml | ||
| config.yaml.example | ||
| go.mod | ||
| go.sum | ||
| Makefile | ||
| README.md | ||
stiebel-modbus
CLI tool for reading Modbus TCP registers from a Stiebel Eltron ISG (Internet Service Gateway) heat pump controller.
Connects to the ISG, reads all system values, and displays them with human-readable descriptions, valid ranges, and cross-references to related settings.
Install
Requires Go 1.21+.
go install github.com/h15/stiebel-modbus-tool/cmd/stiebel-modbus@latest
Or build from source:
git clone https://github.com/h15/stiebel-modbus-tool.git
cd stiebel-modbus-tool
make build
# binary at ./bin/stiebel-modbus
Quick start
# Read all populated registers (hides UNAVAILABLE by default)
stiebel-modbus list --host 192.168.16.104
# Show a specific block
stiebel-modbus list --host 192.168.16.104 --block params
# Show everything including unpopulated registers
stiebel-modbus list --host 192.168.16.104 --all
Commands
list
Read and display ISG registers grouped by block.
stiebel-modbus list --host <ip> [flags]
| Flag | Default | Description |
|---|---|---|
--block |
all | Filter by block ID: SYSTEM, STATUS, ENERGY, PARAMS |
-a, --all |
false | Show all registers including UNAVAILABLE ones |
-v, --verbose |
false | Show detailed descriptions, valid ranges, and related registers |
--format |
table |
Output format: table or json |
Blocks:
| Block | Registers | Contents |
|---|---|---|
| SYSTEM | 501–582 | Temperatures, pressures, flow rates (read-only) |
| STATUS | 2501–2546 | Operating status bitmasks, pump states, fault codes (read-only) |
| ENERGY | 3501–3618 | Heat production, power consumption, per-HP energy (read-only) |
| PARAMS | 1501–1521 | Operating mode, temperature setpoints, heating curves (read/write) |
Compact mode (default) — one line per register:
=== Operating Parameters (Read/Write) ===
Configurable system parameters (read/write capable, currently read-only)
ADDR | NAME | ACCESS | VALUE | UNIT | DESCRIPTION
------------------------------------------------------------------------------------------------------------------------
1501 | OPERATING MODE | R/W | PROGRAMMED | | System operating mode selection
1502 | COMFORT TEMPERATURE HC1 | R/W | 23.0 °C | °C | HC1 comfort (day) room temperature setpoint
1504 | HEATING CURVE RISE HC1 | R/W | 1.66 | | HC1 heating curve gradient (steepness)
Verbose mode (-v) — detailed view with ranges and cross-references:
[1504] HEATING CURVE RISE HC1
Value: 1.66
Access: Read/Write
Range: 0 to 3
Info: Slope of the HC1 weather-compensated heating curve. Higher values
produce higher flow temperatures at the same outside temperature.
Typical values: 0.3-0.8 for underfloor heating, 1.0-1.5 for radiators.
Related: 1502 (COMFORT TEMPERATURE HC1), 1503 (ECO TEMPERATURE HC1),
507 (OUTSIDE TEMPERATURE), 512 (ACTUAL FLOW TEMPERATURE WP)
JSON output (--format json):
stiebel-modbus list --host 192.168.16.104 --format json --block energy | jq '.blocks[0].registers[:2]'
[
{
"address": 3501,
"name": "HEATING PRODUCED DAY",
"description": "Today's heating energy produced by all heat pumps",
"unit": "kWh",
"access": "read",
"raw": 7,
"value": 7,
"display": "7 kWh"
},
{
"address": 3502,
"name": "HEATING PRODUCED TOTAL kWh",
"description": "Total heating energy produced (kWh portion)",
"unit": "kWh",
"access": "read",
"raw": 278,
"value": 278,
"display": "278 kWh"
}
]
scan
Scan the device and generate a YAML profile listing only the registers that are populated on your specific installation.
stiebel-modbus scan --host 192.168.16.104 -o my-device.yaml
Scanning 192.168.16.104:502 (unit ID 1, timeout 5s)...
Connected. Reading all registers...
Scan complete:
Total registers: 261
Populated: 92
Unavailable: 169
Profile written to: my-device.yaml
The generated YAML profile contains metadata and a list of every populated register:
generated_at: "2026-04-25T09:49:51Z"
host: 192.168.16.104
port: 502
unit_id: 1
blocks:
- id: SYSTEM
name: System Values
registers:
- address: 507
name: OUTSIDE TEMPERATURE
unit: °C
access: read
scanned_value: 14.5 °C
# ...
summary:
total_registers: 261
populated_registers: 92
unavailable_registers: 169
Global flags
| Flag | Default | Description |
|---|---|---|
--host |
(required) | ISG hostname or IP address |
--port |
502 |
Modbus TCP port |
--timeout |
5s |
Connection and read timeout |
--unit-id |
1 |
Modbus unit/slave ID |
--format |
table |
Output format (table or json) |
Register data types
| ISG Type | Interpretation | Scale | Example |
|---|---|---|---|
| Signed ×0.1 | int16(raw) × 0.1 |
0.1 | raw 217 → 21.7 °C |
| Unsigned | uint16(raw) |
1 | raw 42 → 42 kWh |
| Signed ×0.01 | int16(raw) × 0.01 |
0.01 | raw 253 → 2.53 bar |
| Enum | uint16(raw) |
1 | raw 2 → PROGRAMMED |
Registers returning 0x8000 (32768) are marked UNAVAILABLE — the sensor or feature is not installed on your device.
Project structure
cmd/stiebel-modbus/ CLI entrypoint
internal/
cli/ Cobra command definitions (list, scan)
register/ Register types and complete ISG catalog (~260 registers)
transport/ Modbus TCP client (Reader interface)
value/ Raw → scaled value interpretation
device/ Orchestrator: batch-read all blocks
output/ Table and JSON formatters
Development
make build # Build binary to ./bin/stiebel-modbus
make test # Run tests with -race
make lint # gofmt + go vet
make clean # Remove build artifacts
License
See LICENSE for details.