python-duco-connectivity
Async Python client for the local Duco HTTP API.
python-duco-connectivity is a small async client for the unauthenticated
local Duco HTTP endpoints that were validated during initial development. The
library keeps its public models close to the API payload shape and is intended
to stay reusable outside Home Assistant.
Installation
Until the first PyPI release is published, install directly from GitHub:
pip install git+https://github.com/ronaldvdmeer/python-duco-connectivity.git
After the package is published on PyPI, install it with:
pip install python-duco-connectivity
The package also installs a duco-probe CLI and supports module execution for
quick function probes against a local Duco box. When you are not running inside
an activated virtual environment, use the explicit .venv/bin/... paths shown
in the development examples below.
Current scope
- HTTP only
- asynchronous communication via
aiohttp - typed stable config families for the documented
/configbranches - typed helpers for stable
/infofields such as heat recovery filter time - a typed overview for selected values from one unfiltered
/inforequest - natural empty results for optional capability discovery and explicit errors for strict capability access
- typed models that stay close to the API response shape
- preserved
raw_payloaddata on typed response models for forward compatibility
Error handling
Discovery-style helpers use their natural empty result when a Duco box reports
an optional capability as unsupported: filter time returns None, ventilation
temperatures return an empty VentilationTemperatureInfo, and bulk bypass
targets return {}. Malformed responses and operational failures remain
exceptions. The strict parameter-specific bypass helper raises
DucoUnsupportedCapabilityError for an unsupported target; this
DucoResponseError subclass preserves the HTTP status, path, and response body.
The bypass-target helpers only return models with complete and coherent value,
minimum, increment, and maximum metadata. Bulk reads omit an invalid individual
zone without suppressing valid zones. Parameter-specific reads and write
responses raise DucoError when the requested target is missing, incomplete,
or inconsistent. BypassSupplyTemperatureTarget.validate_value() checks a
Celsius value against the target-specific range and step, while
normalize_value() rounds converted values to the nearest supported step. Pass
the target to async_set_bypass_supply_temperature_target(..., target=target)
to validate a write without an additional read.
Diagnostic subsystem reads expose known status values as normalized DiagStatus
members (ok, disabled, or error). Each DiagComponent also keeps the exact
API value in raw_status; an unrecognized future value produces status=None
without discarding the raw value. Subsystem names remain unfiltered so future
components are available to downstream consumers. Direct construction using a
pre-0.13 raw status string remains compatible and derives raw_status
automatically; callers using a normalized DiagStatus must provide
raw_status explicitly.
async_get_info_overview() combines RSSI, diagnostic subsystems, heat recovery
filter time, and ventilation temperatures from one GET /info request. Missing
product-specific modules produce their natural empty values. Unlike most typed
models, InfoOverview does not retain the broad response or the LAN raw
payload, because that response can contain network credentials such as the
Wi-Fi access point key.
async_set_node_identify(node_id, identify) exposes the node SetIdentify
action with an explicit Boolean state. The helper raises DucoActionError when
the box returns an unsuccessful action result.
Getting started
import asyncio
import aiohttp
from duco_connectivity import DucoClient
async def main() -> None:
async with aiohttp.ClientSession() as session:
client = DucoClient(session, "192.168.1.10")
api_info = await client.async_get_api_info()
info = await client.async_get_info_overview()
nodes = await client.async_get_nodes_overview()
print(api_info.public_api_version)
print(info.rssi_wifi)
print([node.node_id for node in nodes])
if __name__ == "__main__":
asyncio.run(main())
Documentation map
Start with docs/api-reference.md when you want a compact inventory of the
public client methods, exports, compatibility aliases, and construction rules.
docs/api-reference.mdfor the central public API inventorydocs/cli.mdfor the function probe CLI and shell examplesdocs/config.mdfor system, node, and zone config reads and writesdocs/endpoint-inventory.mdfor the Public API 2.5 read routes and observed response shapes across tested Duco productsdocs/live-testing.mdfor local opt-in tests against a real Duco devicedocs/replay-testing.mdfor local sample validation against ignored raw API capturesdocs/actions.mdfor action discovery and executiondocs/nodes.mdfor node models and node information readersdocs/public-api-boundaries.mdfor the typed-model contract and raw escape hatch boundariesdocs/zones.mdfor zone and group info and config readersdocs/ventilation-states.mdfor ventilation enum values and compatibility membersdocs/payload-preservation.mdfor raw payload preservation and raw endpoint access
The public surface keeps a deliberate split between stable typed readers and
broader raw escape hatches. Use the typed methods when the model already
matches the data you need, and use the raw helpers when you need endpoint
coverage, selector flexibility, or payload fields that have not been typed yet.
See docs/public-api-boundaries.md for the full contract.
Testing strategy
The repository uses three automated test layers:
- Synthetic unit tests cover focused parser and client behavior with mocked HTTP responses.
- Local sample-validation tests can replay a small set of typed client methods against your own ignored raw API captures.
- Live tests validate read paths, safe writes, and latency probes against your own Duco device.
That split matters for Duco support. Synthetic tests keep day-to-day iteration fast. Local sample validation lets you check real captures without committing them or maintaining a sanitization workflow. Live tests confirm that the client still behaves correctly against actual hardware.
Public API maintenance
The compact API reference is generated from the published exports and public async client methods. Regenerate it after public surface changes with:
python tools/api_reference.py write
Development
From the repository root, use any activated virtual environment you prefer. The
commands below use a local .venv so they stay copy-pasteable from a clean
checkout. Create it first if needed, then install the development dependencies
and run the same checks as CI:
python -m venv .venv
.venv/bin/python -m pip install -e ".[dev]"
.venv/bin/pytest
.venv/bin/ruff check src tests
.venv/bin/ruff format --check src tests
.venv/bin/mypy src
.venv/bin/bandit -r src -ll
.venv/bin/pip-audit --desc on
For local function probes without activating the environment first:
.venv/bin/python -m duco_connectivity --host 192.168.1.10 call async_get_board_info
.venv/bin/duco-probe --host 192.168.1.10 call async_get_board_info
.venv/bin/duco-probe --host 192.168.1.10 call async_get_ventilation_temperature_info
.venv/bin/duco-probe --host 192.168.1.10 call async_get_bypass_supply_temperature_targets
.venv/bin/duco-probe --host 192.168.1.10 call async_get_bypass_supply_temperature_target --kwargs '{"zone_id": 1}'
For local real-device validation against your own Duco box, use the opt-in
workflow documented in docs/live-testing.md.
For local sample validation against ignored raw captures,
use docs/replay-testing.md.
If you want to validate raw API captures locally, follow the layout guidance in
docs/replay-testing.md and the fixture-specific notes in
tests/fixtures/replay/README.md.
Validation
The current API surface was validated against a real Duco box during the first development pass, covering:
GET /apiGET /infowith generic module, submodule, and parameter queriesGET /configwith generic module, submodule, and parameter queriesPATCH /configwith a no-opTimeZonewrite against the current valueGET /info?module=General&submodule=BoardGET /info?module=General&submodule=LanGET /info?module=VentilationGET /info?module=HeatRecoveryGET /info/nodesGET /info?module=General&submodule=PublicApiGET /config?module=HeatRecovery&submodule=Bypass¶meter=TempSupTgtZone1PATCH /config?module=HeatRecovery&submodule=Bypass¶meter=TempSupTgtZone1with a no-op write against the current valuePOST /action/nodes/{node}with a no-opSetVentilationState
The repository now also includes opt-in local live tests so the same read and safe-write checks can be repeated against your own device without changing the default mock-only test workflow.
Metadata
Release files for python-duco-connectivity 0.17.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| python_duco_connectivity-0.17.0.tar.gz | 75.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| python_duco_connectivity-0.17.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 110.5 kB
Release files / python_duco_connectivity-0.17.0.tar.gz
| Download URL | python_duco_connectivity-0.17.0.tar.gz |
|---|---|
| Size | 75.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6912cf667adb2f7f36a128872bfb1b14bf14f1427c268556f9f61d4528b5971a
|
|
BLAKE2b-256 checksum How to use checksums |
9c412e5b8e9907cf16186bf706feaa824d02218c99e1457d4a9e49ff380e664c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency logRelease files / python_duco_connectivity-0.17.0-py3-none-any.whl
| Download URL | python_duco_connectivity-0.17.0-py3-none-any.whl |
|---|---|
| Size | 35.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7422e620079d55f4a388f0507d8813a0c796c29ad4522ad87920fd54112f50de
|
|
BLAKE2b-256 checksum How to use checksums |
ce3e46170780d56dc4972cbf43ac158f67d890c9991dd2b3a4fb60d69f14c54e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency log