Metadata-Version: 2.4
Name: pyvenstar
Version: 0.1.1
Summary: Stateless Python client for the Venstar ColorTouch T8900 Local (LAN) REST API
Author-email: Stefan Slivinski <sslivins@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/sslivins/pyvenstar
Project-URL: Bug Tracker, https://github.com/sslivins/pyvenstar/issues
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Home Automation
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.31.0
Provides-Extra: tests
Requires-Dist: pytest>=8.3.4; extra == "tests"
Requires-Dist: requests-mock>=1.12.1; extra == "tests"
Requires-Dist: pytest-cov>=5.0.0; extra == "tests"
Requires-Dist: ruff>=0.6.0; extra == "tests"
Requires-Dist: mypy>=1.10.0; extra == "tests"
Dynamic: license-file

# pyvenstar

A small, stateless Python client for the Venstar ColorTouch **T8900**
Local (LAN) REST API. Built for managing a fleet of thermostats across
multiple sites (e.g. from a central scheduler reaching devices over a
site-to-site VPN), not as a general Venstar SDK.

Reference: [developer.venstar.com](https://developer.venstar.com/) (Local
API v5+).

## Why stateless?

Each `VenstarClient` call round-trips to the device rather than caching
setpoints/mode on the instance. That costs a little extra HTTP overhead
(negligible on a LAN/VPN, these devices are polled/commanded on the order
of minutes, not milliseconds) but means a process managing dozens of
thermostats can freely construct/discard clients per operation without
worrying about stale cached state from a previous call.

## Usage

```python
from pyvenstar import VenstarClient, ThermostatMode, FanMode

with VenstarClient("10.0.1.42", timeout=5.0) as client:
    info = client.get_info()
    print(info.name, info.mode, info.space_temp)

    client.set_setpoints(heat_temp=70, cool_temp=76)
    client.set_mode(ThermostatMode.AUTO)
    client.set_fan(FanMode.AUTO)

    for sensor in client.get_sensors():
        print(sensor.name, sensor.temp, sensor.humidity)
```

Setpoint writes are validated locally (against the device's reported
min/max range and, in `AUTO` mode, its `setpointdelta`) before any
network call is made — bad values from a scheduler never reach the
hardware. Validation failures raise `VenstarValidationError`; device/API
problems raise `VenstarAPIError`; unreachable devices raise
`VenstarConnectionError`. All three derive from `VenstarError`.

## Security — read this before deploying

**The T8900 Local API is unauthenticated, plaintext HTTP by default.**
This library optionally supports a PIN (`pin=`) or HTTP Digest auth
(`user=`/`password=`) if configured on the device, but neither is
encrypted in transit. Treat network isolation as the primary control,
not this library:

- Put thermostats on an isolated VLAN/SSID per site with no general
  LAN/WiFi access.
- Firewall rules so only the control host's VPN-routed IP can reach
  port 80 on these devices — nothing else in or out.
- Use DHCP reservations so device IPs stay fixed (this library takes a
  host/IP directly; it does not implement Venstar's SSDP discovery).
- Enable the device PIN or Digest auth as defense-in-depth, not a
  substitute for network isolation.

## Development

```powershell
python -m venv .venv
.\.venv\Scripts\python -m pip install -e ".[tests]"
.\.venv\Scripts\python -m pytest -q
.\.venv\Scripts\python -m ruff check src tests
.\.venv\Scripts\python -m mypy src
```
