GitHub - graphras-com/HaClient: A high-level typed Python SDK for building applications on top of the Home Assistant REST and WebSocket APIs.
A high-level typed Python SDK for building applications on top of the Home Assistant REST and WebSocket APIs.
Unlike low-level Home Assistant clients that expose raw service calls and entity state payloads, this library provides domain-oriented accessors and intent-driven APIs designed for application development.
Features
- Async context manager with automatic WebSocket connection and state priming
- Typed domain accessors: air quality, binary sensor, climate, cover, event, fan, humidifier, light, lock, media player, scene, sensor, switch, timer, vacuum, valve
- Intent-specific methods over raw service calls (e.g.
light.set_brightness(200)instead oflight.turn_on(brightness=200)) - Real-time state change listeners with granular attribute and state-transition filtering
- Synchronous blocking wrapper for scripts, REPL, and Jupyter
- Automatic WebSocket reconnection with exponential backoff
- Configurable service routing policy (
ws,rest, orauto) - Plugin system for third-party domain extensions via entry points
- Fully typed (PEP 561) with strict mypy enforcement
- Single runtime dependency (
aiohttp)
Requirements
- Python 3.11+
- A running Home Assistant instance
- A long-lived access token from Home Assistant
Installation
Or install from source:
git clone https://github.com/graphras-com/HaClient.git cd HaClient pip install .
Usage
Async
from haclient import HAClient async with HAClient.from_url("http://localhost:8123", token="YOUR_TOKEN") as ha: light = ha.light("kitchen") await light.set_brightness(200) await light.set_kelvin(3000) switch = ha.switch("garage_door") await switch.off() # Listen for state changes sensor = ha.sensor("outdoor_temperature") sensor.on_value_change(lambda old, new: print(f"Temp: {old} -> {new}"))
Synchronous
from haclient import SyncHAClient with SyncHAClient.from_url("http://localhost:8123", token="YOUR_TOKEN") as ha: light = ha.light("kitchen") light.set_brightness(200) player = ha.media_player("living_room") player.set_volume(0.5)
Configuration
Create a client with HAClient.from_url() or by passing a ConnectionConfig directly:
base_url-- Base URL of your Home Assistant instance (e.g.http://localhost:8123)token-- Long-lived access token generated from the Home Assistant UIreconnect-- Enable automatic WebSocket reconnection (default:True)ping_interval-- WebSocket keepalive interval in seconds (default:30)request_timeout-- Timeout for REST and WS commands in seconds (default:30)verify_ssl-- Verify SSL certificates (default:True)service_policy-- Service call routing:"ws","rest", or"auto"(default:"auto")
Store tokens securely using environment variables or a secrets manager. Do not commit tokens to version control.
Development
Install development dependencies:
Run tests:
Run tests with coverage:
pytest --cov=haclient --cov-report=term-missing
Lint and format:
ruff check src tests ruff format --check src tests
Type checking:
Security
- Never commit Home Assistant tokens or secrets to the repository
- Gitleaks runs on every CI pipeline execution to detect accidentally committed secrets
- The
.gitignoreexcludes.envfiles by default
CI/CD
GitHub Actions workflows handle:
- Lint -- Ruff check and format verification
- Type Check -- Strict mypy analysis
- Tests -- Pytest matrix across Python 3.11/3.12/3.13 with 95% coverage threshold
- Secrets Scan -- Gitleaks full-history scan
- Release -- Automated GitHub release on
v*tags - Dependabot -- Weekly dependency updates for pip and GitHub Actions
Contributing
Contributions are welcome. Please open an issue or pull request. Follow existing code style and ensure all CI checks pass before submitting.
License
Apache-2.0 -- see LICENSE.