Metadata-Version: 2.4
Name: sma-net2
Version: 0.1.0
Summary: Async SMA-Net2 Bluetooth Classic inverter protocol client
Author: sma-net2-bluetooth contributors
License-Expression: GPL-3.0-or-later
Project-URL: Homepage, https://github.com/CReimer/sma-net2-bluetooth
Project-URL: Source, https://github.com/CReimer/sma-net2-bluetooth/tree/main/packages/sma-net2
Project-URL: Issues, https://github.com/CReimer/sma-net2-bluetooth/issues
Keywords: sma,solar,inverter,bluetooth,net2,asyncio
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: AsyncIO
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Home Automation
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: dbus-fast>=5.0.22
Provides-Extra: test
Requires-Dist: coverage==7.15.3; extra == "test"
Dynamic: license-file

# sma-net2

An asynchronous Python client for the legacy SMA-Net2 Bluetooth Classic
protocol. It discovers and authenticates SMA inverters and reads measurements
and the inverter's five-minute archive. It has no Home Assistant dependency.

This is the communication library extracted from
[SMA-Net2 Bluetooth for Home Assistant](https://github.com/CReimer/sma-net2-bluetooth).

## Requirements

- Python 3.11 or newer, on Linux with Bluetooth Classic RFCOMM support.
- A local Bluetooth adapter and SMA-Net2-capable inverter within radio range.
- The SMA **user** password, not an installer password or Bluetooth pairing PIN.
- For optional discovery: access to BlueZ on the system D-Bus.

ESPHome BLE proxies do not support this protocol. The known tested hardware is
SMA Sunny Boy SB 3000HF-30; other legacy Bluetooth models may provide different
measurement sets. This project is not affiliated with or endorsed by SMA.

## Installation

Install a published release from PyPI:

```sh
python -m pip install sma-net2==0.1.0
```

## Development installation

For development, install from the package source directory:

```sh
python -m pip install -e '.[test]'
```

## Read measurements

```python
import asyncio
import os

from sma_net2 import SMAClassicClient


async def main():
    async with SMAClassicClient(
        os.environ["SMA_BT_ADDRESS"],
        os.environ["SMA_USER_PASSWORD"],
        connection_mode="auto",
    ) as client:
        inverters = await client.async_query()
        for serial, inverter in inverters.items():
            print(serial, inverter.model, inverter.values)


asyncio.run(main())
```

`auto` uses direct mode for NetID 1 and network mode for NetID 2–F. `single`
reads only the selected inverter. `network` requires NetID 2–F. The result maps
serial-number strings to `SMAInverter` objects. Missing measurements remain
unknown; energy counters and source timestamps are not altered to hide resets
or backwards readings.

Use one client per session and serialize clients sharing a Bluetooth adapter.
The library does not apply Home Assistant's daylight scheduling, retry policy,
adapter recovery, entity ownership or Recorder import policy; the caller owns
those decisions. Inverters are normally unreachable at night.

`async_query()`, `async_read_archive(periods)` and `async_sync_clock(...)` each
start and stop an authenticated session inside the open RFCOMM context. For
multiple operations in one session, call `async_start_session()`, use the
corresponding `*_active()` methods, and call `async_stop_session()` in `finally`.
Clock synchronization writes to the plant clock and is explicitly invoked,
with bounds and a minimum interval checked by the client.

`async_read_archive()` accepts Unix start/end timestamp pairs (end exclusive),
and returns a mapping from each serial to a list of `SMAArchivePoint` objects. No Home Assistant statistics
are written. Original source ordering is preserved. Discovery is available as
`from sma_net2.discovery import async_discover_sma_devices` and returns a mapping
of Bluetooth addresses to display names.

Catch `SMAAuthenticationError` for incorrect credentials,
`SMAConfigurationError`/`SMANetworkModeError` for incompatible topology, and
`SMATransportError` for connection failures. These derive from `SMAProtocolError`.
The async context manager closes the socket on exit.

## Offline tests and distribution build

```sh
python -m coverage run -m unittest discover -s tests -v
python -m coverage report
python -m build
python -m twine check dist/*
```

The tests use mock sockets and D-Bus objects; they never contact an inverter or
change its clock. The CI workflow tests Python 3.11 and 3.14, builds a wheel and
source distribution, checks metadata, and installs both artifacts in isolated
environments without Home Assistant. Release tags use `sma-net2-v<VERSION>` and
must match the version in `pyproject.toml`.

## License and attribution

GPL-3.0-or-later. The protocol adapts the GPLv3-or-later work of Wim Hofman and
Stephen Collier (2010–2011) in
[sma-bluetooth/sma-bluetooth](https://github.com/sma-bluetooth/sma-bluetooth).
All original notices and the complete GPL license are retained. This extraction
does not relicense the protocol. The optional BlueZ discovery uses the
OSI-licensed `dbus-fast` package.
