Skip to main content

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 /config branches
  • typed helpers for stable /info fields such as heat recovery filter time
  • 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_payload data 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. Calls without target retain the legacy finite and exact-decicelsius validation temporarily.

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.

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()
        nodes = await client.async_get_nodes_overview()

        print(api_info.public_api_version)
        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.md for the central public API inventory
  • docs/cli.md for the function probe CLI and shell examples
  • docs/config.md for system, node, and zone config reads and writes
  • docs/live-testing.md for local opt-in tests against a real Duco device
  • docs/replay-testing.md for local sample validation against ignored raw API captures
  • docs/actions.md for action discovery and execution
  • docs/nodes.md for node models and node information readers
  • docs/public-api-boundaries.md for the typed-model contract and raw escape hatch boundaries
  • docs/zones.md for zone and group info and config readers
  • docs/ventilation-states.md for ventilation enum values and compatibility members
  • docs/payload-preservation.md for 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 /api
  • GET /info with generic module, submodule, and parameter queries
  • GET /config with generic module, submodule, and parameter queries
  • PATCH /config with a no-op TimeZone write against the current value
  • GET /info?module=General&submodule=Board
  • GET /info?module=General&submodule=Lan
  • GET /info?module=Ventilation
  • GET /info?module=HeatRecovery
  • GET /info/nodes
  • GET /info?module=General&submodule=PublicApi
  • GET /config?module=HeatRecovery&submodule=Bypass&parameter=TempSupTgtZone1
  • PATCH /config?module=HeatRecovery&submodule=Bypass&parameter=TempSupTgtZone1 with a no-op write against the current value
  • POST /action/nodes/{node} with a no-op SetVentilationState

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.14.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for python-duco-connectivity 0.14.0
File Size Uploaded
python_duco_connectivity-0.14.0.tar.gz 73.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for python-duco-connectivity 0.14.0
File Interpreter ABI Platform
python_duco_connectivity-0.14.0-py3-none-any.whl Python 3 none any Details

Total release size: 107.5 kB

Release files / python_duco_connectivity-0.14.0.tar.gz

Download URL python_duco_connectivity-0.14.0.tar.gz
Size 73.1 kB
Tags Source
SHA-256 checksum
How to use checksums
19e671dc6a66777d57dbab7cbe56f81ca7378906162e58e4f7c4dc5ec7b83616
BLAKE2b-256 checksum
How to use checksums
df527b50e5d010ce024c3edaa98386238c5faa9ce37f56656d71d96754e62fe4
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 Aug 31, 2026.

Transparency log

Release files / python_duco_connectivity-0.14.0-py3-none-any.whl

Download URL python_duco_connectivity-0.14.0-py3-none-any.whl
Size 34.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
040da840888605d5b877f958e830d643edf21eea79fc1dde33a9d91560479d04
BLAKE2b-256 checksum
How to use checksums
dca8013530b5ba0b630c773e72c81f58a9371e2191a89ca9586a4f69942e584b
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 Aug 31, 2026.

Transparency log

Release history Release notifications | RSS feed

0.18.0

2 release files

0.17.0

2 release files

0.16.0

2 release files

This release

0.14.0 This release

2 release files

0.13.1

2 release files

0.13.0

2 release files

0.12.0

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page