Metadata-Version: 2.4
Name: trovis-modbus
Version: 1.0.0
Summary: Read a Samson Trovis 557x heating controller over Modbus.
Project-URL: Homepage, https://github.com/balloob/trovis-modbus
Author: Trovis Modbus contributors
License: Apache-2.0
License-File: LICENSE
Keywords: heating,home-assistant,modbus,samson,trovis
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Home Automation
Requires-Python: >=3.12
Requires-Dist: modbus-connection<4,>=3.0
Provides-Extra: cli
Requires-Dist: modbus-connection[pymodbus]<4,>=3.0; extra == 'cli'
Description-Content-Type: text/markdown

# trovis-modbus

A standalone Python library that reads a **Samson Trovis 557x** heating
controller over Modbus, exposed as a normal, object-oriented Python API.

Addresses, scales and data types are taken from the canonical Trovis 557x point
list (the [Tom-Bom-badil](https://github.com/Tom-Bom-badil/samson_trovis_557x)
SmartHomeNG plugin) and **verified in tests** against a vendored copy of that
table (`tests/reference/canonical_points.json`).

## Design

- It **consumes the connection abstraction**, not a backend: the API takes a
  [`modbus_connection.ModbusUnit`](../modbus-connection) and reads/writes through
  it. You choose the backend (pymodbus, tmodbus, …).
- A `Trovis557x` is a tree of independently-updatable **sub-systems**, each a
  `Component` that knows its own registers:

  | Attribute | What |
  | --- | --- |
  | `info` | model, firmware/hardware version, serial → `DeviceInfo` |
  | `controller` | faults, rotary switches, summer mode, frost limit, locks |
  | `clock` | date/time as native `datetime` objects |
  | `sensors` | every temperature input (outside, flow, return, room, storage, remote) |
  | `heating_circuit_1` / `_2` / `_3` | space-heating circuits (RK1-3) |
  | `hot_water` | domestic hot water (HK4): setpoints, charging, disinfection |

- Each sub-system can refresh on its own and has its **own update listeners**, so
  a single Home Assistant entity can subscribe to just the part it shows
  (e.g. one climate entity per heating circuit).
- Units of measurement live in each property's docstring, not in the value.

## Use

```python
import asyncio
from modbus_connection.pymodbus import connect_tcp
from trovis_modbus import Trovis557x, OperatingMode


async def main() -> None:
    conn = await connect_tcp("192.168.1.50", port=502)
    try:
        trovis = Trovis557x(conn.for_unit(1))     # unit 1 = the controller's Modbus address
        await trovis.async_update()

        print("Outside:", trovis.sensors.outside_1, "°C")
        print("HK1 mode:", trovis.heating_circuit_1.mode)
        print("HK1 target:", trovis.heating_circuit_1.room_setpoint_active, "°C")
        print("HK1 pump:", trovis.heating_circuit_1.pump_running)
        print("HK1 curve:", trovis.heating_circuit_1.heating_curve())
        print("Hot water:", trovis.hot_water.setpoint_active, "charging:", trovis.hot_water.charge_pump_running)
        print("Clock:", trovis.clock.datetime)

        # Writes (reverse the scaling/encoding automatically)
        await trovis.heating_circuit_1.set_room_setpoint_day(21.5)
        await trovis.heating_circuit_1.set_mode(OperatingMode.DAY)
        await trovis.hot_water.start_forced_charge()
    finally:
        await conn.close()


asyncio.run(main())
```

### Updating just one sub-system

```python
await trovis.hot_water.async_update()              # only reads the HK4 registers
unsub = trovis.hot_water.add_update_listener(refresh_my_entity)
```

## Command-line tool

`script/query.py` connects to a controller, reads it once, and prints every
value — handy for checking a real device without Home Assistant. It needs a
concrete backend, so install the `cli` extra (`pip install trovis-modbus[cli]`,
or run via `uv run --extra cli`):

```bash
# Network gateway (RTU-over-TCP by default — how Trovis gateways work):
uv run --extra cli python script/query.py tcp 192.168.1.50 --unit 246

# Serial / USB (defaults to the Trovis 19200 8N1 line):
uv run --extra cli python script/query.py serial /dev/ttyUSB0 --unit 246
```

Use `--port`, `--framer {rtu,socket}` (TCP) or `--baudrate`/`--parity`/… (serial)
to override defaults; `--help` lists them all. Output is grouped by sub-system:

```text
Device
------
  model             Trovis 5579
  firmware_version  3.05
  ...

Heating circuit 1
-----------------
  mode                  automatic
  room_temperature      20.0 °C
  room_setpoint_active  21.0 °C
  flow_temperature      55.0 °C
  pump_running          True
  ...
```

## Develop / test

```bash
uv sync
uv run pytest
```

The suite cross-checks every field against the canonical point list and
exercises decoding, the heating curve, writes and listeners against the
in-memory mock backend that ships with `modbus-connection` (its `mock_modbus_unit`
pytest fixture) — no real Modbus server or backend is needed.

Formatting/linting is [ruff](https://docs.astral.sh/ruff/); install the commit
hook with [prek](https://github.com/j178/prek):

```bash
uvx prek install
uvx prek run --all-files
```
