v0.1.0: First light ☀️
☀️ First light
This is the first release of solaredged, an asynchronous Python client for SolarEdge inverters over Modbus. It reads and controls inverters, meters, and batteries, decoding the SunSpec information model and SolarEdge's proprietary register blocks into typed values.
It does one job and leans on others for the rest. This library declares the register layout and detects the device; the transport and the field decoding live in modbus-connection underneath. The consumer owns the connection and hands over a single unit, so a whole site of inverters shares one connection instead of every integration opening its own. That is the shared-connection approach from the Modernizing Modbus developer blog.
What you get
- The whole device. Inverter, per-string DC (multiple-MPPT / SunSpec 160), up to three meters, batteries, and the storage, export, and power control blocks, all decoded to typed values with the right units.
- Detection built in.
async_probevalidates the SunSpec header and works out which meters, batteries, and control blocks are actually present. - Writable control. Typed
set_*methods for storage mode, export and site limit, active power limit, power factor, backup reserve, charge policy, and remote charge and discharge. Only on hardware you own. - Honest values. A point the device does not implement decodes to
None. The library never turns a real reading intoNone, nor lets a read failure masquerade as one. - Transport-agnostic. Modbus TCP, RS485/RTU, or an RTU-to-TCP gateway. Anything that hands it a
ModbusUnitwill do. - EV charger detection. Recognises a SolarEdge EV charger answering on its own unit id (identity only; it exposes no telemetry over Modbus).
- One error contract. Reads and writes surface as
SolarEdgeConnectionError(transport) orSolarEdgeError(a bad value or undecodable data). No raw exceptions leak. - Optional CLI and TUI. Read your inverter from the terminal, dump the register map, or watch a live dashboard.
A taste
import asyncio
from modbus_connection.tmodbus import connect_tcp
from solaredged import SolarEdge
async def main() -> None:
connection = await connect_tcp("solaredge.local", port=1502)
try:
unit = connection.for_unit(1)
solaredge = await SolarEdge.async_probe(unit) # detects the layout
await solaredge.async_update() # one pooled read
print(solaredge.inverter.ac_power, "W")
for battery in solaredge.batteries:
print(battery.state_of_energy, "%")
finally:
await connection.close()
asyncio.run(main())pip install solaredgedThe CLI ships under an extra and drives the tmodbus backend:
pip install "solaredged[cli,tmodbus]"Tested where it counts
100% test coverage on the package. The register map is checked against the vendored SunSpec model definitions, and against real device dumps contributed by the community. The decode path is exercised with property-based fuzzing, so a garbled register cannot crash a read: it decodes to None or surfaces as our own error.
A note on the version
This is 0.1.0, and python-solaredged is pre-1.0. The register map is validated as spec-accurate and against real hardware, and the error contract is firm. Parts of the API may still shift before 1.0 as the library gathers production feedback.
Not affiliated with, endorsed by, or supported by SolarEdge Technologies. Writing control registers changes how your inverter and battery behave, so only do it on hardware you own and understand.
Thanks for taking it for a spin. Issues, ideas, and pull requests are welcome ☀️
../Frenck
Blogging my personal ramblings at frenck.dev