## 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. ```shell 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 ```yaml 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`, `pv_power`, `grid_import`, `grid_export`, `battery_charge`, `battery_discharge`, `solar_to_house`) so the dashboard's consumption-source panels are plain `mean()`/`integral()` queries. **Sign conventions (verified against the SolarEdge app):** `meter1_power` positive = export, `battery1_power` negative = discharge, and `power_ac` is the inverter's *total* AC output (PV + battery, DC-coupled Energy Hub) - which is why `pv_power = power_ac - battery` and `house_load = power_ac + grid`. If a different system disagrees, flip `METER_IMPORT_POSITIVE` / `BATTERY_DISCHARGE_POSITIVE` in `solaredge_modbus_mqtt/__init__.py` and restart - the derived fields follow. ### Uninstall ```shell docker update --restart=no solaredge_modbus_mqtt docker stop solaredge_modbus_mqtt ``` ### Update ```shell 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 ```shell 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 ```shell pip3 install -r requirements.txt cp config.yaml-dist config.yaml python3 solaredge_modbus_mqtt.py ``` ### Running tests ```shell pip3 install -r requirements.txt python3 -m unittest ```