dj7nt d266654696 Harden Modbus/Influx paths, add Grafana dashboard
Short or garbled gateway responses are rejected on register count
instead of half-decoding (previously: 'unpack requires a buffer',
OverflowError on garbage scale factors). Scale factors outside
+/-10 and non-finite floats are dropped before they reach line
protocol.

offgrid is written as integer offgrid_state: the existing DB
cannot be migrated (mixed inmem/tsi1 shards block all deletes)
and the old boolean field conflicts with integer writes, which
poisoned the spool - HTTP 400 now drops the batch and logs the
InfluxDB error body instead of re-spooling it forever.

grafana_dashboard.json: fully German dashboard (InfluxQL,
InfluxDB 1.x) with off-grid state, SoC (SoE*SoH/100) and
consumption-source panels; status tiles use integers plus value
mappings because Grafana drops string/boolean fields from
InfluxQL time series.
2026-10-10 16:58:44 +02:00
2020-06-04 21:41:08 +02:00
2020-06-04 21:28:38 +02:00
2026-10-10 16:13:58 +02:00

Usage

Installation

The easiest way this is to run the docker container and set it to restart always. This basically makes it a system service that will always run.

To make it safe and avoid passing credentials we're using a configuration file.

mkdir /etc/solaredge_modbus_mqtt
chmod 700 /etc/solaredge_modbus_mqtt
cp config.yaml-dist /etc/solaredge_modbus_mqtt/config.yaml
docker run --detach --name=solaredge_modbus_mqtt --restart=always --volume=/etc/solaredge_modbus_mqtt/config.yaml:/app/config.yaml marijnkoesen/solaredge_modbus_mqtt:latest

Configuration

modbus:
    host: 192.168.178.28     # inverter (SunSpec over Modbus TCP)
    port: 1502
    timeout: 1
    unit: 1

influx:
    url: http://influx.example.com:8086
    db: solaredge
    user: ~                   # optional basic-auth user with WRITE on the db
    pass: ~
    measurement: solaredge

poll_interval: 3

The daemon polls the inverter and writes one line-protocol point per cycle directly to InfluxDB. If InfluxDB is unreachable, points are spooled to spool.txt and replayed on the next successful write (capped at 20000 lines). Mount a volume for /app/spool.txt if backlog across container restarts matters.

model and serialnumber are written as tags; everything else as fields.

Off-grid / fail-over

  • offgrid — boolean, true while the inverter runs islanded (off-grid) — vendor event bit
  • error_code — inverter vendor error bitmask (0 = none), LCD-style codes
  • storage_control_mode_text — e.g. Backup Only, Maximize Self Consumption
  • battery1_* — SOE/SOH, power, voltage, temperatures, status of battery 1

Register addresses were validated by probing a SE10K-RWB48BFN4 (fw 0004.0025.0011) with one battery and one meter. Blocks that fail to read (flaky gateway) are skipped for that cycle; the fields are simply absent from the point.

Grafana dashboard

Import grafana_dashboard.json (Dashboards -> New -> Import). Select your InfluxDB datasource when prompted (e.g. InfluxDB-HJK); the $serial variable is filled from the serialnumber tag. InfluxQL only, InfluxDB 1.x.

The daemon also writes derived flow fields (house_load, grid_import, grid_export, battery_charge, battery_discharge, solar_to_house) so the dashboard's consumption-source panels are plain mean()/integral() queries.

Sign calibration: meter1_power positive = import and battery1_power positive = discharge are assumptions observed once; verify on the first sunny day (export while surplus / charge while battery fills). If inverted, flip METER_IMPORT_POSITIVE / BATTERY_DISCHARGE_POSITIVE in solaredge_modbus_mqtt/__init__.py and restart - all derived fields follow.

Uninstall

docker update --restart=no solaredge_modbus_mqtt
docker stop solaredge_modbus_mqtt

Update

docker update --restart=no solaredge_modbus_mqtt
docker stop solaredge_modbus_mqtt
docker rm solaredge_modbus_mqtt
docker run --detach --name=solaredge_modbus_mqtt --restart=always --volume=/etc/solaredge_modbus_mqtt/config.yaml:/app/config.yaml marijnkoesen/solaredge_modbus_mqtt:latest

For developers

Building and running the docker image

docker build -t solaredge_modbus_mqtt:latest .
or
docker buildx build --platform linux/amd64 solaredge_modbus_mqtt:latest .

cp config.yaml-dist config.yaml
docker run --volume=$PWD/config.yaml:/app/config.yaml solaredge_modbus_mqtt:latest

Running without docker

pip3 install -r requirements.txt
cp config.yaml-dist config.yaml
python3 solaredge_modbus_mqtt.py

Running tests

pip3 install -r requirements.txt
python3 -m unittest
S
Description
No description provided
Readme MIT
166 KiB
0 Stars 1 Watchers 0 Forks
Languages
Python 99.3%
Dockerfile 0.7%