Verified against simultaneous SolarEdge app readings (PV 40 W, battery discharge 520 W, house 560 W): battery1_power negative means discharge, and power_ac on this DC-coupled Energy Hub is the inverter's TOTAL AC output - it already contains the battery contribution. The old formula double-counted the battery, so house_load collapsed (44 W shown vs 560 W real) and the PV tile showed battery-inflated totals, which looked like PV and house consumption were swapped. New derived fields: house_load = power_ac + grid, and pv_power = power_ac - battery (true PV production). Dashboard PV tiles and both yield panels now use pv_power / integral(pv_power) - the energy_total lifetime counter also counts battery throughput and is not a PV yield.
121 lines
3.7 KiB
Markdown
121 lines
3.7 KiB
Markdown
## 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
|
|
```
|