A multi-target Prometheus exporter for Sigenergy plants and inverters over Modbus TCP. Prometheus supplies the target address at scrape time and the exporter synchronously reads the selected protocol module.
The bundled sigenstor_plant_v2_5 module covers plant and ESS running information
from Sigenergy Modbus Protocol V2.5 (2025-02-19), using plant unit ID 247.
The bundled sigenstor_inverter_v2_5 module covers hybrid-inverter, battery,
grid, and up to 16 PV-string measurements using inverter unit ID 1. Neither
module calls a Modbus write function.
Python 3.12 or newer is required.
python -m venv .venv
.venv/bin/pip install --constraint constraints.txt .
.venv/bin/sigenergy-exporter --config.file=sigenergy.ymlRun the published non-root container:
docker run --rm -p 10047:10047 ghcr.io/fdomf/sigenergy-exporter:0.2.0Or build it locally:
docker build --target runtime -t sigenergy-exporter .
docker run --rm -p 10047:10047 sigenergy-exporterDocker Compose can use the published image without cloning or building this repository:
services:
sigenergy-exporter:
image: ghcr.io/fdomf/sigenergy-exporter:0.2.0
restart: unless-stopped
ports:
- "10047:10047"Other services in the same Compose project can reach the exporter at
http://sigenergy-exporter:10047.
To maintain a customized module configuration outside the image, add:
volumes:
- ./sigenergy.yml:/etc/sigenergy-exporter/sigenergy.yml:roValidate configuration without starting the server:
sigenergy-exporter --config.file=sigenergy.yml --dry-runThe module parameter is optional and defaults to sigenstor_plant_v2_5.
scrape_configs:
- job_name: sigenergy
scrape_interval: 15s
scrape_timeout: 14s
metrics_path: /sigenergy
static_configs:
- targets:
- 192.0.2.10
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: sigenergy-exporter:10047
- job_name: sigenergy-inverter
scrape_interval: 15s
scrape_timeout: 14s
metrics_path: /sigenergy
params:
module: [sigenstor_inverter_v2_5]
static_configs:
- targets:
- 192.0.2.10
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: sigenergy-exporter:10047
- job_name: sigenergy-exporter
static_configs:
- targets: [sigenergy-exporter:10047]Targets may be a DNS name, IPv4 address, host:port, or bracketed IPv6
address. Port 502 is used by default.
| Endpoint | Purpose |
|---|---|
/sigenergy?target=HOST[:PORT]&module=MODULE |
Collect a plant |
/metrics |
Exporter and process metrics |
/-/healthy |
Process health |
/-/reload |
Atomically reload configuration with POST |
/ |
Landing page and manual collection form |
A required Modbus read failure returns HTTP 200 with sigenergy_up 0.
Metrics from failed blocks are omitted, while successfully collected blocks
remain available. Exporter HTTP and process metrics are intentionally exposed
only on /metrics. The exporter honors Prometheus'
X-Prometheus-Scrape-Timeout-Seconds header and reserves 500 ms to encode and
return the response; a block that cannot fit before that deadline is omitted.
Target metrics use Prometheus base-unit conventions:
- state of charge and health are ratios from
0to1; - energy and capacity use joules;
- active power uses watts and reactive power uses vars;
- electrical measurements use volts, amperes, hertz, and ohms;
- phase measurements use the bounded
phase="a|b|c"label; - operating modes and plant state are one-hot gauge families with a bounded
modeorstatelabel, including anunknownvalue for undocumented codes.
Exporter instrumentation on /metrics includes Modbus connection attempts and
failures, register-block requests and failures, collection concurrency, and
scrape deadline exhaustion. Deadline stages use the bounded values queue,
connect, and pacing; target addresses are never used as metric labels.
sigenergy.yml contains reusable protocol modules, not targets. Each module
defines its Modbus unit, read-only function code, timeout, minimum request
period, read blocks, and metric decoding. Function codes 3 and 4 are
supported; no write function code is accepted. The exporter strictly validates
names, types, block bounds, scales, state mappings, static label schemas, and
duplicate samples before accepting a file.
A failed reload leaves the last valid configuration active.
Supported register types are u16, s16, u32, s32, u64, and s64.
Multi-register values are decoded high-word first. The bundled plant module
reads:
- required block
30003-30072; - optional ESS detail block
30083-30087.
The bundled inverter module reads required blocks 30540-30623 and
31000-31065. It defaults to inverter unit ID 1; installations that assign a
different inverter address from 1 through 246 should mount a copy of
sigenergy.yml with the module's unit_id changed.
Opaque alarm bitfields, reserved registers, and identity strings are
deliberately not exported. Metrics whose registers match a configured
invalid_values sentinel are omitted. AC/DC charger modules remain outside the
current scope.
Reload after editing the mounted file:
curl -fsS -X POST http://127.0.0.1:10047/-/reload
docker kill --signal HUP sigenergy-exporterSigenergy V2.5 specifies a minimum 1000 ms request period. The exporter serializes collections per target and preserves each target's last request time across scrapes, while still allowing different plants to be collected concurrently.
The collection endpoint can connect to a host supplied in the query string.
Run it only on a trusted network and avoid publishing port 10047 to the
public internet.
The bundled profile implements Sigenergy Modbus Protocol V2.5 dated 2025-02-19:
| Profile | Modbus function | Unit ID | Register ranges | Automated validation |
|---|---|---|---|---|
sigenstor_plant_v2_5 |
FC04 input registers | 247 | 30003-30072, 30083-30087 |
Decoding, scaling, pacing, failures, exposition |
sigenstor_inverter_v2_5 |
FC03 read-only registers | 1 (configurable) | 30540-30623, 31000-31065 |
Function code, unit ID, decoding, scaling, invalid sentinels, states, pacing, exposition |
The plant and inverter profiles have been validated against a Sigenergy hybrid inverter with SigenStack battery system.
Published container tags are multi-platform images for linux/amd64 and
linux/arm64.
python -m pip install --constraint constraints.txt ".[dev]"
ruff check src tests
ruff format --check src tests
python -m unittest discover -v tests
docker build --target test -t sigenergy-exporter:test .
docker run --rm sigenergy-exporter:testThe register facts are derived from Sigenergy Modbus Protocol V2.5. The protocol PDF is copyrighted by Sigenergy and is not redistributed here.
Maintained by Francesc Domene.
Licensed under the Apache License 2.0.