Client API
The AlphaHWRClient is the main entry point for interacting with Grundfos ALPHA HWR pumps. It provides a service-oriented architecture where specialized services handle different aspects of pump communication.
Overview
The client acts as a facade and coordinator for specialized services:
- Telemetry - Real-time sensor data and monitoring
- Control - Pump control operations (start, stop, mode changes)
- Schedule - Weekly schedule management across 5 layers
- Device Info - Device identification and statistics
- Configuration - Backup and restore operations
- Time - Real-time clock management
- History - Historical trend data (100 cycles)
- Event Log - Pump event history (20 entries)
Basic Usage
import asyncio
from alpha_hwr import AlphaHWRClient
async def main():
# Connect using context manager (automatic disconnect)
async with AlphaHWRClient("AA:BB:CC:DD:EE:FF") as client:
# Read telemetry
data = await client.telemetry.read_once()
print(f"Flow: {data.flow_m3h} m³/h")
# Control pump
await client.control.set_constant_pressure(1.5)
# Manage schedules
entries = await client.schedule.read_entries()
asyncio.run(main())
API Reference
alpha_hwr.client.AlphaHWRClient
Main client for Grundfos ALPHA HWR pump interaction.
Provides a unified API for all pump operations through specialized services. Manages BLE connection, authentication, and service lifecycle.
Services
telemetry: Read sensor data (flow, pressure, power, temperature) control: Start/stop pump, set modes and setpoints schedule: Manage weekly pump schedules device_info: Read device identification and statistics config: Backup and restore pump configuration time: Read and synchronize pump real-time clock history: Read historical trend data (flow, head, temperature) event_log: Read pump event log entries and metadata writes: The serialized write path; every write settles through it single_events: One-off scheduled runs and vacations
Attributes:
| Name | Type | Description |
|---|---|---|
address |
str | None
|
BLE device address (UUID on macOS, MAC on Linux/Windows) |
adapter |
str | None
|
Optional BLE adapter identifier |
session |
Session | None
|
Session manager (tracks authentication state) |
transport |
Transport | None
|
BLE transport layer |
auth |
AuthenticationHandler | None
|
Authentication handler |
Example
async with AlphaHWRClient("DEVICE_ADDRESS") as client: # doctest: +SKIP ... # Telemetry ... data = await client.telemetry.read_once() ... print(f"Flow: {data.flow_m3h} m³/h") ... ... # Control ... await client.control.start() ... await client.control.set_constant_pressure(1.5) ... ... # Schedule ... await client.schedule.enable() ... ... # Backup ... await client.config.backup("pump.json")
Implementation Notes
The client is a thin orchestration layer. All business logic lives in the service modules. This makes the code: - Easier to understand (single responsibility per service) - Easier to test (mock services independently) - Easier to port (services are self-contained)
telemetry = None
instance-attribute
control = None
instance-attribute
device_info = None
instance-attribute
schedule = None
instance-attribute
history = None
instance-attribute
event_log = None
instance-attribute
time = None
instance-attribute
single_events = None
instance-attribute
writes = None
instance-attribute
config = None
instance-attribute
is_ready
property
Whether the client knows enough about the pump to write safely.
True once connected, authenticated, and the pump's stored configuration has been read. Writes that carry fields the caller did not set need that reading to preserve them, so this is the signal to wait for before driving the pump programmatically - rather than guessing at a settle delay.
__init__(address=None, adapter=None, auto_authenticate=True)
Initialize the ALPHA HWR client.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
address
|
str | None
|
BLE device address (UUID on macOS, MAC on Linux/Windows). If None, reads from ALPHA_HWR_DEVICE_ADDRESS env variable. |
None
|
adapter
|
str | None
|
Optional BLE adapter identifier (platform-specific) |
None
|
auto_authenticate
|
bool
|
Automatically authenticate after connection (default True) |
True
|
Example
Use address from environment
client = AlphaHWRClient()
Use specific address
client = AlphaHWRClient("A1B2C3D4-E5F6-7890-1234-567890ABCDEF")
Specify adapter (Linux)
client = AlphaHWRClient(address="00:11:22:33:44:55", adapter="hci1")
connect(timeout=60.0, fast_mode=False)
async
Connect to the pump via BLE.
Establishes BLE connection, initializes transport layer, and sets up all service modules. If auto_authenticate is enabled, also performs authentication handshake.
If no address is configured, automatically attempts to discover a nearby ALPHA HWR pump.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float
|
Connection timeout in seconds (default 60s) |
60.0
|
fast_mode
|
bool
|
If True, skips authentication delays (for testing) |
False
|
Raises:
| Type | Description |
|---|---|
ConnectionError
|
If connection fails or no device found during discovery |
ValueError
|
If discovery fails |
Example
Connect to specific address
client = AlphaHWRClient("DEVICE_ADDRESS") await client.connect() # doctest: +SKIP
Connect using automatic discovery
client = AlphaHWRClient() await client.connect() # doctest: +SKIP
Implementation Notes
Connection sequence: 1. Resolve address (discovery if needed) 2. Scan for advertisement data before connecting 3. Create BleakClient with device address ...
disconnect()
async
Disconnect from the pump.
Cleanly shuts down all services, stops BLE notifications, and disconnects from the device.
Example
await client.disconnect() # doctest: +SKIP print(f"Connected: {client.is_connected}") # False # doctest: +SKIP
Implementation Notes
Disconnect sequence: 1. Stop BLE notifications 2. Clear service references 3. Disconnect BLE client 4. Reset all state
Safe to call multiple times (idempotent).
authenticate(fast_mode=False)
async
Authenticate with the pump.
Performs the authentication handshake to enable control operations. Read-only operations (telemetry, device info) don't require authentication, but control operations (start, stop, mode changes) do.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fast_mode
|
bool
|
If True, skips delays for testing purposes. |
False
|
Returns:
| Type | Description |
|---|---|
bool
|
True if authentication successful, False otherwise |
Example
success = await client.authenticate() # doctest: +SKIP if success: # doctest: +SKIP ... print("Authenticated successfully") ... await client.control.start()
__aenter__()
async
Async context manager entry - connects to pump.
__aexit__(exc_type, exc_val, exc_tb)
async
Async context manager exit - disconnects from pump.
wait_until_ready(timeout=30.0)
async
Wait for :attr:is_ready, retrying the cache read if it failed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float
|
Seconds to keep trying. |
30.0
|
Returns:
| Type | Description |
|---|---|
bool
|
True if the client became ready in time. |
get_run_state()
async
What state the run flag and schedule flag put the pump in.
Worth asking rather than reading the two flags separately: one of their four combinations - stopped with the schedule armed - can never run, and looks healthy from every angle except the water.
set_run_state(target)
async
Move the pump to a state it can actually act on.
Writes only the flags that differ, in an order that never passes through the stalled combination - arming a schedule over a stopped pump, even for the moment between two writes, is a window that can be missed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
RunState
|
|
required |
Returns:
| Type | Description |
|---|---|
WriteResult
|
The most severe of the underlying writes, so a partial failure |
WriteResult
|
surfaces rather than being averaged away. |