Metadata-Version: 2.4
Name: pyairobotmodbus
Version: 0.2.0
Summary: Python library for communicating with Airobot ventilation units via Modbus TCP
Project-URL: Homepage, https://github.com/dmednis/pyairobotmodbus
Project-URL: Repository, https://github.com/dmednis/pyairobotmodbus
Project-URL: Issues, https://github.com/dmednis/pyairobotmodbus/issues
Author-email: Dāvis Mednis <davis@medn.is>
License-Expression: MIT
License-File: LICENSE
Keywords: airobot,home-assistant,hvac,modbus,ventilation
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Home Automation
Classifier: Topic :: System :: Hardware :: Hardware Drivers
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: pymodbus<4,>=3.10
Provides-Extra: dev
Requires-Dist: mypy>=1.15; extra == 'dev'
Requires-Dist: pre-commit>=4; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest-cov>=6; extra == 'dev'
Requires-Dist: pytest-timeout>=2; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.11; extra == 'dev'
Description-Content-Type: text/markdown

# pyairobotmodbus

Python library for communicating with Airobot ventilation units via Modbus TCP.

## Installation

```bash
pip install pyairobotmodbus
```

## Usage

### Context manager (recommended)

```python
import asyncio
from pyairobotmodbus import AirobotModbusClient, OperatingMode

async def main():
    async with AirobotModbusClient("192.168.1.100") as client:
        data = await client.async_get_data()
        print(f"Supply air: {data.supply_air_temp}°C")
        print(f"CO2: {data.co2_level} ppm")

        await client.async_set_mode(OperatingMode.MANUAL)
        await client.async_set_fan_speed(7)

asyncio.run(main())
```

### Factory method

```python
client = await AirobotModbusClient.create("192.168.1.100")
```

### Error handling

All exceptions inherit from `AirobotError`:

```python
from pyairobotmodbus import AirobotError, AirobotConnectionError, AirobotTimeoutError

try:
    async with AirobotModbusClient("192.168.1.100") as client:
        data = await client.async_get_data()
except AirobotTimeoutError:
    print("Device did not respond in time")
except AirobotConnectionError:
    print("Could not connect to device")
except AirobotError as e:
    print(f"Communication error: {e}")
```

### Sensor data

`async_get_data()` returns an `AirobotData` snapshot with:

- **Temperatures** — supply, extract, outside, exhaust, extra (°C)
- **Humidity** — supply, extract, outside, exhaust, extra (RH%)
- **Air quality** — CO2 (ppm), VOC (index), PM2.5 (μg/m³)
- **Fans** — supply/extract level, RPM, and airflow (m³/h)
- **Status** — error flags, heat recovery efficiency, working time

### Device control

```python
# Operating mode
await client.async_set_mode(OperatingMode.AUTOMATIC)

# Fan speed (1-10)
await client.async_set_fan_speed(7)

# Toggles
await client.async_set_boost(True)
await client.async_set_overpressure(True)
await client.async_set_bypass(True)
await client.async_set_power(True)

# Setpoints
await client.async_set_co2_setpoint(800)         # ppm
await client.async_set_humidity_setpoint(50.0)    # RH%
await client.async_set_voc_setpoint(200)          # index
await client.async_set_pm25_setpoint(25)          # μg/m³

# Timeouts
await client.async_set_boost_timeout(1200)        # seconds
await client.async_set_overpressure_timeout(600)  # seconds

# Filter reminder
await client.async_set_filter_reminder_interval(4380)  # hours

# Sensor control toggles
await client.async_set_humidity_control(True)
await client.async_set_voc_control(True)
await client.async_set_pm_control(True)
```

## CLI

```bash
# Read all data from the device
pyairobotmodbus read 192.168.1.100

# Set a parameter
pyairobotmodbus set 192.168.1.100 fan_speed 7

# Monitor continuously
pyairobotmodbus monitor 192.168.1.100
```
