Metadata-Version: 2.5
Name: sma-modbus
Version: 2.1.3
Summary: Library for SMA Modbus TCP interface, built on modbus-connection
Project-URL: Homepage, https://github.com/burmistrzak/sma-modbus
Project-URL: Repository, https://github.com/burmistrzak/sma-modbus
Project-URL: Changelog, https://github.com/burmistrzak/sma-modbus/releases
Author-email: burmistrzak <61958704+burmistrzak@users.noreply.github.com>
License-Expression: GPL-3.0-or-later
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: System :: Hardware
Requires-Python: >=3.12
Requires-Dist: modbus-connection<5,>=4.6.1
Description-Content-Type: text/markdown

# sma-modbus

Async Python library for the Modbus TCP interface of SMA devices, built on
[modbus-connection](https://github.com/home-assistant-libs/modbus-connection).

> [!WARNING]
>
> **Developer Preview**
>
> Working, but **do not** use in production. Please report any issues you come across.

> [!NOTE]
>
> Based on a partial agentic port of [fronius-modbus](https://github.com/farmio/fronius-modbus). 🫶

Supports the following SMA devices (so far):

- **Sunny Home Manager 2.0**
- **Sunny Boy Smart Energy 3.6-6.0**
- **Sunny Boy 3.0-6.0**
- **Sunny Tripower 3.0-6.0** <sup>untested</sup>

Not all Modbus parameters have been added, _yet_. Support for read/write registers _maybe_ later.

The SMA register map is mostly fixed, but it has been slightly modified with firmware updates in the past.


## Reading

The library consumes a `ModbusConnection` and manages its own unit handles
internally. Use `discover()` to auto-detect the device type and serial number
from the Type Label (probes unit ID 1, then unit ID 3):

```python
import asyncio

from modbus_connection.tmodbus import connect_tcp

from sma_modbus import DEVICE_CLASSES, discover


async def main() -> None:
    connection = await connect_tcp("192.168.1.50", port=502)
    info = await discover(connection)
    inverter = DEVICE_CLASSES[info.device_type](connection, info.unit_id)

    # one pooled read refreshes the whole device, block by block
    await inverter.async_update()

    print("PV power:", inverter.pv_power, "W")
    print("PV energy:", inverter.pv_energy_total, "Wh")
    print("Battery SoC:", inverter.battery_state_of_charge, "%")
    print("DC string 1:", inverter.dc_voltage_1, "V", inverter.dc_power_1, "W")

    await connection.close()


asyncio.run(main())
```

Pass `unit_id=` to `discover()` to read the Type Label from a specific unit ID
and use it for measurements. This covers inverters that have been reconfigured
to a non-default unit ID. Without `unit_id`, discovery probes unit IDs 1 and 3
and uses the device type's standard default (3 for inverters, 2 for the
Sunny Home Manager):

```python
info = await discover(connection, unit_id=5)
```

A field reads as `None` when the device reports its not-a-value sentinel, so a
powered-down or unsupported measurement is distinct from a real zero.

## Testing on real hardware

`scripts/read_device.py` is a one-shot dump of everything the library reads:

```
uv run scripts/read_device.py <host> [--port 502] [--unit <id>]
```

The device type is auto-detected. Use `--unit` to override the measurement
unit ID if the device has been reconfigured.

Modbus must be enabled on the device.

## Testing support

`sma_modbus.testing` provides `set_input_registers()` to load a
`modbus_connection.mock.MockModbusConnection` with raw register words for a
component:

```python
from modbus_connection.mock import MockModbusConnection
from sma_modbus import SunnyHomeManager
from sma_modbus.testing import set_input_registers

connection = MockModbusConnection()
device = SunnyHomeManager(connection)
set_input_registers(
    connection,
    device,
    {"grid_import_energy": 123456, "grid_export_power": 750},
)
await device.async_update()
assert device.grid_import_energy == 123456
```

The `mock_modbus_connection` fixture (shipped by `modbus_connection`'s pytest
plugin) hands a ready-to-configure connection to each test.

## Disclaimer

This is an unofficial library and in no way affiliated with SMA Solar Technology AG.
