Python library for Weishaupt WAB11 heat pump control via Modbus TCP
Project description
WAB11 Python Library
A Python library for controlling Weishaupt WAB11 heat pump controllers via Modbus TCP.
Features
- Digital Twin Pattern: Maintains a synchronized local representation of the heat pump state
- Type-Safe Models: Pydantic-based models for all WAB11 components
- Secure by Default: Validated writes, rate limiting, and confirmation for critical operations
- Async & Sync Support: Both asyncio-based and synchronous interfaces
- Event System: Subscribe to state changes with callbacks
- Comprehensive Audit Log: Full trail of all operations
Installation
pip install wab11
Or install from source:
git clone https://github.com/your-repo/wab11.git
cd wab11
pip install -e .
Requirements
- Python 3.10+
- pymodbus >= 3.5
- pydantic >= 2.0
Quick Start
Async Usage
import asyncio
from wab11 import WAB11Client, SystemMode
async def main():
async with WAB11Client("192.168.1.100") as wab:
# Sync state from device
await wab.sync()
# Read values
print(f"Outdoor temperature: {wab.system.outdoor_temp}°C")
print(f"System mode: {wab.system.system_mode.name}")
print(f"Operating state: {wab.system.operating_state.name}")
# Check for errors
if wab.system.has_error:
print(f"⚠️ Error code: {wab.system.error_code}")
# Heating circuit info
for i, hk in enumerate(wab.heating_circuits, 1):
if hk.is_configured:
print(f"HK{i}: {hk.room_temp.celsius}°C → {hk.room_setpoint_effective.celsius}°C")
# Hot water
print(f"Hot water: {wab.hot_water.temperature.celsius}°C")
asyncio.run(main())
Sync Usage
from wab11 import WAB11SyncClient, SystemMode
with WAB11SyncClient("192.168.1.100") as wab:
wab.sync()
print(f"Outdoor: {wab.system.outdoor_temp}°C")
print(f"Mode: {wab.system.system_mode.name}")
Setting Values
async with WAB11Client("192.168.1.100") as wab:
# Change system mode (requires confirmation for safety)
await wab.set_system_mode(SystemMode.HEATING, confirmed=True)
# Set heating circuit setpoint
await wab.set_heating_circuit_setpoint(
circuit=1,
level="comfort", # "comfort", "normal", or "setback"
temperature=22.0
)
# Activate party mode for 3 hours
await wab.set_heating_party_pause(circuit=1, mode="party", hours=3.0)
# Hot water boost
await wab.trigger_hot_water_push(minutes=30)
Continuous Monitoring
async with WAB11Client("192.168.1.100") as wab:
# Subscribe to changes
def on_change(event):
print(f"{event.register}: {event.old_value} → {event.new_value}")
wab.on_change(on_change)
# Start background polling
await wab.start_polling(interval=5.0)
# Keep running
await asyncio.sleep(3600)
Security
The library implements several security measures:
Write Validation
All writes are validated against documented limits:
# This will raise ValidationError
await wab.set_heating_circuit_setpoint(1, "comfort", 50.0) # Too high!
Critical Operation Confirmation
Safety-critical operations require explicit confirmation:
# This raises SafetyError
await wab.set_system_mode(SystemMode.STANDBY)
# This works
await wab.set_system_mode(SystemMode.STANDBY, confirmed=True)
Rate Limiting
Write operations are rate-limited to protect the controller:
- Max 10 writes per minute globally
- Max 2 writes per register per minute
- 1 second cooldown between same-register writes
Audit Logging
All operations are logged:
# Get recent write operations
for entry in wab.audit_log.get_writes():
print(f"{entry.timestamp}: {entry.register} = {entry.new_value}")
Network Security Warning
⚠️ Important: The Modbus TCP interface is unencrypted. As per Weishaupt documentation, the controller should only be accessible on an isolated network segment, not your general home LAN.
API Reference
WAB11Client
The main async client class.
Properties:
system- Global system stateheating_circuits- List of 5 heating circuits (HK1-HK5)hot_water- Hot water stateheat_pump- Heat pump statesecondary_heat- Secondary heat source stateinputs- Digital inputs and SG-Ready stateenergy- Energy statisticsis_connected- Connection statuslast_sync- Timestamp of last sync
Methods:
connect()/disconnect()- Connection managementsync()- Synchronize state with devicestart_polling(interval)/stop_polling()- Background pollingon_change(callback)- Subscribe to state changesset_system_mode(mode, confirmed)- Set system modeset_heating_circuit_mode(circuit, mode)- Set HK modeset_heating_circuit_setpoint(circuit, level, temp)- Set temperatureset_heating_party_pause(circuit, mode, hours)- Party/pause modeset_hot_water_setpoint(level, temp)- Set hot water temptrigger_hot_water_push(minutes)- Hot water boostread_register(name)/write_register(name, value)- Raw access
Enums
from wab11 import (
SystemMode, # AUTOMATIC, HEATING, COOLING, SUMMER, STANDBY, SECOND_HEAT
OperatingState, # Current state (HEATING, COOLING, HOT_WATER, DEFROST, etc.)
HeatingCircuitMode, # AUTOMATIC, COMFORT, NORMAL, SETBACK, STANDBY
SGReadyState, # NORMAL, EVU_LOCK, RECOMMENDED, MAXIMUM
)
Exceptions
from wab11 import (
WAB11Error, # Base exception
ConnectionError, # Connection failures
ValidationError, # Invalid values
SafetyError, # Unconfirmed critical operation
RateLimitError, # Rate limit exceeded
)
Supported Registers
The library supports all documented WAB11 Modbus registers:
| Range | Description |
|---|---|
| 30xxx | System status (outdoor temp, errors, state) |
| 31xxx | Heating circuit status (HK1-HK5) |
| 32xxx | Hot water status |
| 33xxx | Heat pump status |
| 34xxx | Secondary heat source status |
| 35xxx | Digital inputs, SG-Ready |
| 36xxx | Energy statistics |
| 40xxx | System parameters |
| 41xxx | Heating circuit parameters |
| 42xxx | Hot water parameters |
| 43xxx | Heat pump parameters |
| 44xxx | Secondary heat source parameters |
| 45xxx | Input configuration |
Development
# Install with dev dependencies
pip install -e ".[dev]"
# Run the default test suite
pytest
# Type checking
mypy src/wab11
# Linting
ruff check src/wab11
Testing
The default test suite uses a fake Modbus system defined in
tests/fixtures/fake_system.json. That fixture is used for normal
regression tests and is safe to run on any machine because it does not
talk to a real controller.
The repository also includes a warm live-device test in
tests/test_warm_live_device.py. This test is skipped by default and
must be enabled explicitly. It is designed to be read-only:
- It only connects, syncs state, syncs energy values, and reads registers
- It does not call any library write API
- It replaces the connection write method with a failing guard, so the test aborts immediately if any write is attempted
Run the warm test only when you intentionally want to exercise a real WAB11 device:
pytest tests/test_warm_live_device.py \
--run-warm \
--warm-host <ip-or-host> \
--warm-heating-circuits <1-5>
You can also provide the live-device settings through environment variables:
WAB11_TEST_HOSTWAB11_TEST_PORTWAB11_TEST_UNIT_IDWAB11_TEST_TIMEOUTWAB11_TEST_HEATING_CIRCUITS
License
MIT License - see LICENSE file.
Disclaimer
This is an unofficial library. Use at your own risk. Always verify operations with the official Weishaupt documentation and ensure you understand the effects of any changes you make to your heating system.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wab11-0.1.0.tar.gz.
File metadata
- Download URL: wab11-0.1.0.tar.gz
- Upload date:
- Size: 132.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b30a5246d2b4890ad773d3a0bfce926ca0bab58264d668f0a568a5a1da4d6e0c
|
|
| MD5 |
c39d6793fe3eeb8e52e1c3b042769107
|
|
| BLAKE2b-256 |
cd22b72e23aa6de8288a23edc24cff3d57db1f8e2c2c84e6025878557c80c3dd
|
Provenance
The following attestation bundles were made for wab11-0.1.0.tar.gz:
Publisher:
version_publish_main.yml on JulianKimmig/wab11
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wab11-0.1.0.tar.gz -
Subject digest:
b30a5246d2b4890ad773d3a0bfce926ca0bab58264d668f0a568a5a1da4d6e0c - Sigstore transparency entry: 1281728892
- Sigstore integration time:
-
Permalink:
JulianKimmig/wab11@d74ef6dbc876cb229a2d07879ced682d9aefa2c8 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/JulianKimmig
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
version_publish_main.yml@d74ef6dbc876cb229a2d07879ced682d9aefa2c8 -
Trigger Event:
push
-
Statement type:
File details
Details for the file wab11-0.1.0-py3-none-any.whl.
File metadata
- Download URL: wab11-0.1.0-py3-none-any.whl
- Upload date:
- Size: 47.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
360a99b0a7052c13cf6edfad3e5901997ed02a83a1b8aaf042d5de45965ddba4
|
|
| MD5 |
6a2dbf5cfe081523283169b764b28d2c
|
|
| BLAKE2b-256 |
80796a3aefd78961a4ea373282774fb18a6a6d0178ad09fa06a6a49bab142159
|
Provenance
The following attestation bundles were made for wab11-0.1.0-py3-none-any.whl:
Publisher:
version_publish_main.yml on JulianKimmig/wab11
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wab11-0.1.0-py3-none-any.whl -
Subject digest:
360a99b0a7052c13cf6edfad3e5901997ed02a83a1b8aaf042d5de45965ddba4 - Sigstore transparency entry: 1281729005
- Sigstore integration time:
-
Permalink:
JulianKimmig/wab11@d74ef6dbc876cb229a2d07879ced682d9aefa2c8 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/JulianKimmig
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
version_publish_main.yml@d74ef6dbc876cb229a2d07879ced682d9aefa2c8 -
Trigger Event:
push
-
Statement type: