python-duco-connectivity 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. python_duco_connectivity-0.3.0/PKG-INFO +193 -0
  2. python_duco_connectivity-0.3.0/README.md +161 -0
  3. {python_duco_connectivity-0.2.0 → python_duco_connectivity-0.3.0}/pyproject.toml +10 -1
  4. python_duco_connectivity-0.3.0/src/duco_connectivity/__init__.py +121 -0
  5. python_duco_connectivity-0.3.0/src/duco_connectivity/__main__.py +6 -0
  6. python_duco_connectivity-0.3.0/src/duco_connectivity/cli.py +288 -0
  7. python_duco_connectivity-0.3.0/src/duco_connectivity/client.py +1883 -0
  8. python_duco_connectivity-0.3.0/src/duco_connectivity/models.py +588 -0
  9. python_duco_connectivity-0.3.0/src/python_duco_connectivity.egg-info/PKG-INFO +193 -0
  10. {python_duco_connectivity-0.2.0 → python_duco_connectivity-0.3.0}/src/python_duco_connectivity.egg-info/SOURCES.txt +9 -1
  11. python_duco_connectivity-0.3.0/src/python_duco_connectivity.egg-info/entry_points.txt +2 -0
  12. python_duco_connectivity-0.3.0/tests/test_api_reference.py +95 -0
  13. python_duco_connectivity-0.3.0/tests/test_cli.py +398 -0
  14. python_duco_connectivity-0.3.0/tests/test_client.py +3847 -0
  15. python_duco_connectivity-0.3.0/tests/test_local_sample_validation.py +219 -0
  16. python_duco_connectivity-0.3.0/tests/test_models.py +423 -0
  17. python_duco_connectivity-0.3.0/tests/test_pytest_live_support.py +105 -0
  18. python_duco_connectivity-0.3.0/tests/test_replay_helpers.py +262 -0
  19. python_duco_connectivity-0.2.0/PKG-INFO +0 -102
  20. python_duco_connectivity-0.2.0/README.md +0 -70
  21. python_duco_connectivity-0.2.0/src/duco_connectivity/__init__.py +0 -57
  22. python_duco_connectivity-0.2.0/src/duco_connectivity/client.py +0 -424
  23. python_duco_connectivity-0.2.0/src/duco_connectivity/models.py +0 -244
  24. python_duco_connectivity-0.2.0/src/python_duco_connectivity.egg-info/PKG-INFO +0 -102
  25. python_duco_connectivity-0.2.0/tests/test_client.py +0 -727
  26. python_duco_connectivity-0.2.0/tests/test_models.py +0 -193
  27. {python_duco_connectivity-0.2.0 → python_duco_connectivity-0.3.0}/LICENSE +0 -0
  28. {python_duco_connectivity-0.2.0 → python_duco_connectivity-0.3.0}/setup.cfg +0 -0
  29. {python_duco_connectivity-0.2.0 → python_duco_connectivity-0.3.0}/src/duco_connectivity/exceptions.py +0 -0
  30. {python_duco_connectivity-0.2.0 → python_duco_connectivity-0.3.0}/src/duco_connectivity/py.typed +0 -0
  31. {python_duco_connectivity-0.2.0 → python_duco_connectivity-0.3.0}/src/python_duco_connectivity.egg-info/dependency_links.txt +0 -0
  32. {python_duco_connectivity-0.2.0 → python_duco_connectivity-0.3.0}/src/python_duco_connectivity.egg-info/requires.txt +0 -0
  33. {python_duco_connectivity-0.2.0 → python_duco_connectivity-0.3.0}/src/python_duco_connectivity.egg-info/top_level.txt +0 -0
  34. {python_duco_connectivity-0.2.0 → python_duco_connectivity-0.3.0}/tests/test_exceptions.py +0 -0
@@ -0,0 +1,193 @@
1
+ Metadata-Version: 2.4
2
+ Name: python-duco-connectivity
3
+ Version: 0.3.0
4
+ Summary: Async HTTP client for the local Duco Connectivity API
5
+ Author: Ronald van der Meer
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/ronaldvdmeer/python-duco-connectivity
8
+ Project-URL: Repository, https://github.com/ronaldvdmeer/python-duco-connectivity
9
+ Project-URL: Issues, https://github.com/ronaldvdmeer/python-duco-connectivity/issues
10
+ Classifier: Development Status :: 2 - Pre-Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Topic :: Home Automation
16
+ Classifier: Framework :: AsyncIO
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: >=3.12
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: aiohttp>=3.9.0
22
+ Provides-Extra: dev
23
+ Requires-Dist: aioresponses>=0.7; extra == "dev"
24
+ Requires-Dist: bandit>=1.7; extra == "dev"
25
+ Requires-Dist: mypy>=1.8; extra == "dev"
26
+ Requires-Dist: pip-audit>=2.7; extra == "dev"
27
+ Requires-Dist: pytest>=8.0; extra == "dev"
28
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
29
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
30
+ Requires-Dist: ruff>=0.11; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # python-duco-connectivity
34
+
35
+ Async Python client for the local Duco HTTP API.
36
+
37
+ `python-duco-connectivity` is a small async client for the unauthenticated
38
+ local Duco HTTP endpoints that were validated during initial development. The
39
+ library keeps its public models close to the API payload shape and is intended
40
+ to stay reusable outside Home Assistant.
41
+
42
+ ## Installation
43
+
44
+ Until the first PyPI release is published, install directly from GitHub:
45
+
46
+ ```bash
47
+ pip install git+https://github.com/ronaldvdmeer/python-duco-connectivity.git
48
+ ```
49
+
50
+ After the package is published on PyPI, install it with:
51
+
52
+ ```bash
53
+ pip install python-duco-connectivity
54
+ ```
55
+
56
+ The package also installs a `duco-probe` CLI and supports module execution for
57
+ quick function probes against a local Duco box. When you are not running inside
58
+ an activated virtual environment, use the explicit `.venv/bin/...` paths shown
59
+ in the development examples below.
60
+
61
+ ## Current scope
62
+
63
+ - HTTP only
64
+ - asynchronous communication via `aiohttp`
65
+ - typed models that stay close to the API response shape
66
+ - preserved `raw_payload` data on typed response models for forward compatibility
67
+
68
+ ## Getting started
69
+
70
+ ```python
71
+ import asyncio
72
+
73
+ import aiohttp
74
+
75
+ from duco_connectivity import DucoClient
76
+
77
+
78
+ async def main() -> None:
79
+ async with aiohttp.ClientSession() as session:
80
+ client = DucoClient(session, "192.168.1.10")
81
+ api_info = await client.async_get_api_info()
82
+ nodes = await client.async_get_nodes_overview()
83
+
84
+ print(api_info.public_api_version)
85
+ print([node.node_id for node in nodes])
86
+
87
+
88
+ if __name__ == "__main__":
89
+ asyncio.run(main())
90
+ ```
91
+
92
+ ## Documentation map
93
+
94
+ Start with `docs/api-reference.md` when you want a compact inventory of the
95
+ public client methods, exports, compatibility aliases, and construction rules.
96
+
97
+ - `docs/api-reference.md` for the central public API inventory
98
+ - `docs/cli.md` for the function probe CLI and shell examples
99
+ - `docs/config.md` for system, node, and zone config reads and writes
100
+ - `docs/live-testing.md` for local opt-in tests against a real Duco device
101
+ - `docs/replay-testing.md` for local sample validation against ignored raw API
102
+ captures
103
+ - `docs/actions.md` for action discovery and execution
104
+ - `docs/nodes.md` for node models and node information readers
105
+ - `docs/zones.md` for zone and group info and config readers
106
+ - `docs/ventilation-states.md` for ventilation enum values and compatibility
107
+ members
108
+ - `docs/payload-preservation.md` for raw payload preservation and raw endpoint
109
+ access
110
+
111
+ The public surface keeps a split between stable typed readers and broader raw
112
+ escape hatches. Use the typed methods when the model already matches the data
113
+ you need, and use the raw helpers when you need endpoint coverage that has not
114
+ been typed yet.
115
+
116
+ ## Testing strategy
117
+
118
+ The repository uses three automated test layers:
119
+
120
+ - Synthetic unit tests cover focused parser and client behavior with mocked HTTP
121
+ responses.
122
+ - Local sample-validation tests can replay a small set of typed client methods
123
+ against your own ignored raw API captures.
124
+ - Live tests validate read paths, safe writes, and latency probes against your
125
+ own Duco device.
126
+
127
+ That split matters for Duco support. Synthetic tests keep day-to-day iteration
128
+ fast. Local sample validation lets you check real captures without committing
129
+ them or maintaining a sanitization workflow. Live tests confirm that the client
130
+ still behaves correctly against actual hardware.
131
+
132
+ ## Public API maintenance
133
+
134
+ The compact API reference is generated from the published exports and public
135
+ async client methods. Regenerate it after public surface changes with:
136
+
137
+ ```bash
138
+ python tools/api_reference.py write
139
+ ```
140
+
141
+ ## Development
142
+
143
+ From the repository root, use any activated virtual environment you prefer. The
144
+ commands below use a local `.venv` so they stay copy-pasteable from a clean
145
+ checkout. Create it first if needed, then install the development dependencies
146
+ and run the same checks as CI:
147
+
148
+ ```bash
149
+ python -m venv .venv
150
+ .venv/bin/python -m pip install -e ".[dev]"
151
+ .venv/bin/pytest
152
+ .venv/bin/ruff check src tests
153
+ .venv/bin/ruff format --check src tests
154
+ .venv/bin/mypy src
155
+ .venv/bin/bandit -r src -ll
156
+ .venv/bin/pip-audit --desc on
157
+ ```
158
+
159
+ For local function probes without activating the environment first:
160
+
161
+ ```bash
162
+ .venv/bin/python -m duco_connectivity --host 192.168.1.10 call async_get_board_info
163
+ .venv/bin/duco-probe --host 192.168.1.10 call async_get_board_info
164
+ ```
165
+
166
+ For local real-device validation against your own Duco box, use the opt-in
167
+ workflow documented in `docs/live-testing.md`.
168
+
169
+ For local sample validation against ignored raw captures,
170
+ use `docs/replay-testing.md`.
171
+
172
+ If you want to validate raw API captures locally, follow the layout guidance in
173
+ `docs/replay-testing.md` and the fixture-specific notes in
174
+ `tests/fixtures/replay/README.md`.
175
+
176
+ ## Validation
177
+
178
+ The current API surface was validated against a real Duco box during the first
179
+ development pass, covering:
180
+
181
+ - `GET /api`
182
+ - `GET /info` with generic module, submodule, and parameter queries
183
+ - `GET /config` with generic module, submodule, and parameter queries
184
+ - `PATCH /config` with a no-op `TimeZone` write against the current value
185
+ - `GET /info?module=General&submodule=Board`
186
+ - `GET /info?module=General&submodule=Lan`
187
+ - `GET /info/nodes`
188
+ - `GET /info?module=General&submodule=PublicApi`
189
+ - `POST /action/nodes/{node}` with a no-op `SetVentilationState`
190
+
191
+ The repository now also includes opt-in local live tests so the same read and
192
+ safe-write checks can be repeated against your own device without changing the
193
+ default mock-only test workflow.
@@ -0,0 +1,161 @@
1
+ # python-duco-connectivity
2
+
3
+ Async Python client for the local Duco HTTP API.
4
+
5
+ `python-duco-connectivity` is a small async client for the unauthenticated
6
+ local Duco HTTP endpoints that were validated during initial development. The
7
+ library keeps its public models close to the API payload shape and is intended
8
+ to stay reusable outside Home Assistant.
9
+
10
+ ## Installation
11
+
12
+ Until the first PyPI release is published, install directly from GitHub:
13
+
14
+ ```bash
15
+ pip install git+https://github.com/ronaldvdmeer/python-duco-connectivity.git
16
+ ```
17
+
18
+ After the package is published on PyPI, install it with:
19
+
20
+ ```bash
21
+ pip install python-duco-connectivity
22
+ ```
23
+
24
+ The package also installs a `duco-probe` CLI and supports module execution for
25
+ quick function probes against a local Duco box. When you are not running inside
26
+ an activated virtual environment, use the explicit `.venv/bin/...` paths shown
27
+ in the development examples below.
28
+
29
+ ## Current scope
30
+
31
+ - HTTP only
32
+ - asynchronous communication via `aiohttp`
33
+ - typed models that stay close to the API response shape
34
+ - preserved `raw_payload` data on typed response models for forward compatibility
35
+
36
+ ## Getting started
37
+
38
+ ```python
39
+ import asyncio
40
+
41
+ import aiohttp
42
+
43
+ from duco_connectivity import DucoClient
44
+
45
+
46
+ async def main() -> None:
47
+ async with aiohttp.ClientSession() as session:
48
+ client = DucoClient(session, "192.168.1.10")
49
+ api_info = await client.async_get_api_info()
50
+ nodes = await client.async_get_nodes_overview()
51
+
52
+ print(api_info.public_api_version)
53
+ print([node.node_id for node in nodes])
54
+
55
+
56
+ if __name__ == "__main__":
57
+ asyncio.run(main())
58
+ ```
59
+
60
+ ## Documentation map
61
+
62
+ Start with `docs/api-reference.md` when you want a compact inventory of the
63
+ public client methods, exports, compatibility aliases, and construction rules.
64
+
65
+ - `docs/api-reference.md` for the central public API inventory
66
+ - `docs/cli.md` for the function probe CLI and shell examples
67
+ - `docs/config.md` for system, node, and zone config reads and writes
68
+ - `docs/live-testing.md` for local opt-in tests against a real Duco device
69
+ - `docs/replay-testing.md` for local sample validation against ignored raw API
70
+ captures
71
+ - `docs/actions.md` for action discovery and execution
72
+ - `docs/nodes.md` for node models and node information readers
73
+ - `docs/zones.md` for zone and group info and config readers
74
+ - `docs/ventilation-states.md` for ventilation enum values and compatibility
75
+ members
76
+ - `docs/payload-preservation.md` for raw payload preservation and raw endpoint
77
+ access
78
+
79
+ The public surface keeps a split between stable typed readers and broader raw
80
+ escape hatches. Use the typed methods when the model already matches the data
81
+ you need, and use the raw helpers when you need endpoint coverage that has not
82
+ been typed yet.
83
+
84
+ ## Testing strategy
85
+
86
+ The repository uses three automated test layers:
87
+
88
+ - Synthetic unit tests cover focused parser and client behavior with mocked HTTP
89
+ responses.
90
+ - Local sample-validation tests can replay a small set of typed client methods
91
+ against your own ignored raw API captures.
92
+ - Live tests validate read paths, safe writes, and latency probes against your
93
+ own Duco device.
94
+
95
+ That split matters for Duco support. Synthetic tests keep day-to-day iteration
96
+ fast. Local sample validation lets you check real captures without committing
97
+ them or maintaining a sanitization workflow. Live tests confirm that the client
98
+ still behaves correctly against actual hardware.
99
+
100
+ ## Public API maintenance
101
+
102
+ The compact API reference is generated from the published exports and public
103
+ async client methods. Regenerate it after public surface changes with:
104
+
105
+ ```bash
106
+ python tools/api_reference.py write
107
+ ```
108
+
109
+ ## Development
110
+
111
+ From the repository root, use any activated virtual environment you prefer. The
112
+ commands below use a local `.venv` so they stay copy-pasteable from a clean
113
+ checkout. Create it first if needed, then install the development dependencies
114
+ and run the same checks as CI:
115
+
116
+ ```bash
117
+ python -m venv .venv
118
+ .venv/bin/python -m pip install -e ".[dev]"
119
+ .venv/bin/pytest
120
+ .venv/bin/ruff check src tests
121
+ .venv/bin/ruff format --check src tests
122
+ .venv/bin/mypy src
123
+ .venv/bin/bandit -r src -ll
124
+ .venv/bin/pip-audit --desc on
125
+ ```
126
+
127
+ For local function probes without activating the environment first:
128
+
129
+ ```bash
130
+ .venv/bin/python -m duco_connectivity --host 192.168.1.10 call async_get_board_info
131
+ .venv/bin/duco-probe --host 192.168.1.10 call async_get_board_info
132
+ ```
133
+
134
+ For local real-device validation against your own Duco box, use the opt-in
135
+ workflow documented in `docs/live-testing.md`.
136
+
137
+ For local sample validation against ignored raw captures,
138
+ use `docs/replay-testing.md`.
139
+
140
+ If you want to validate raw API captures locally, follow the layout guidance in
141
+ `docs/replay-testing.md` and the fixture-specific notes in
142
+ `tests/fixtures/replay/README.md`.
143
+
144
+ ## Validation
145
+
146
+ The current API surface was validated against a real Duco box during the first
147
+ development pass, covering:
148
+
149
+ - `GET /api`
150
+ - `GET /info` with generic module, submodule, and parameter queries
151
+ - `GET /config` with generic module, submodule, and parameter queries
152
+ - `PATCH /config` with a no-op `TimeZone` write against the current value
153
+ - `GET /info?module=General&submodule=Board`
154
+ - `GET /info?module=General&submodule=Lan`
155
+ - `GET /info/nodes`
156
+ - `GET /info?module=General&submodule=PublicApi`
157
+ - `POST /action/nodes/{node}` with a no-op `SetVentilationState`
158
+
159
+ The repository now also includes opt-in local live tests so the same read and
160
+ safe-write checks can be repeated against your own device without changing the
161
+ default mock-only test workflow.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-duco-connectivity"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "Async HTTP client for the local Duco Connectivity API"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -26,6 +26,9 @@ dependencies = [
26
26
  "aiohttp>=3.9.0",
27
27
  ]
28
28
 
29
+ [project.scripts]
30
+ duco-probe = "duco_connectivity.cli:main"
31
+
29
32
  [project.optional-dependencies]
30
33
  dev = [
31
34
  "aioresponses>=0.7",
@@ -51,7 +54,13 @@ duco_connectivity = ["py.typed"]
51
54
 
52
55
  [tool.pytest.ini_options]
53
56
  testpaths = ["tests"]
57
+ pythonpath = ["."]
54
58
  asyncio_mode = "auto"
59
+ markers = [
60
+ "live: requires --live and a configured local Duco device",
61
+ "writes: requires --live-writes and may send no-op or reversible writes to a live Duco device",
62
+ "performance: requires --live-performance and runs local Duco latency probes",
63
+ ]
55
64
  addopts = [
56
65
  "--cov=duco_connectivity",
57
66
  "--cov-report=term-missing",
@@ -0,0 +1,121 @@
1
+ """Public package exports for python-duco-connectivity."""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version
4
+
5
+ from .client import DucoClient
6
+ from .exceptions import (
7
+ DucoConnectionError,
8
+ DucoError,
9
+ DucoRateLimitError,
10
+ DucoWriteLimitError,
11
+ )
12
+ from .models import (
13
+ Action,
14
+ ActionItem,
15
+ ActionItemList,
16
+ ActionNode,
17
+ ActionResult,
18
+ ActionResultStatus,
19
+ ActionValueType,
20
+ ApiEndpoint,
21
+ ApiEndpointInfo,
22
+ ApiInfo,
23
+ BoardInfo,
24
+ Config,
25
+ ConfigGroup,
26
+ ConfigGroupStruct,
27
+ ConfigNode,
28
+ ConfigNodeOverview,
29
+ ConfigNodeStruct,
30
+ ConfigSection,
31
+ ConfigValue,
32
+ ConfigValueOptions,
33
+ ConfigValueString,
34
+ ConfigZone,
35
+ ConfigZonesOverview,
36
+ ConfigZoneStruct,
37
+ DiagComponent,
38
+ DiagStatus,
39
+ InfoGroup,
40
+ InfoGroupStruct,
41
+ InfoZone,
42
+ InfoZoneGroup,
43
+ InfoZonesOverview,
44
+ InfoZoneStruct,
45
+ LanInfo,
46
+ NetworkType,
47
+ Node,
48
+ NodeActionItemList,
49
+ NodeGeneralInfo,
50
+ NodeListActionItemList,
51
+ NodeMotorStateInfo,
52
+ NodeOverview,
53
+ NodeSensorInfo,
54
+ NodeType,
55
+ NodeVentilationInfo,
56
+ PatchConfigNodeValue,
57
+ PatchConfigValue,
58
+ VentilationMode,
59
+ VentilationState,
60
+ )
61
+
62
+ try:
63
+ __version__ = version("python-duco-connectivity")
64
+ except PackageNotFoundError:
65
+ __version__ = "0.0.0"
66
+
67
+ __all__ = [
68
+ "Action",
69
+ "ActionItem",
70
+ "ActionItemList",
71
+ "ActionNode",
72
+ "ActionResult",
73
+ "ActionResultStatus",
74
+ "ActionValueType",
75
+ "ApiEndpoint",
76
+ "ApiEndpointInfo",
77
+ "ApiInfo",
78
+ "BoardInfo",
79
+ "Config",
80
+ "ConfigGroup",
81
+ "ConfigGroupStruct",
82
+ "ConfigNode",
83
+ "ConfigNodeOverview",
84
+ "ConfigNodeStruct",
85
+ "ConfigSection",
86
+ "ConfigZone",
87
+ "ConfigZonesOverview",
88
+ "ConfigZoneStruct",
89
+ "ConfigValue",
90
+ "ConfigValueOptions",
91
+ "ConfigValueString",
92
+ "DucoClient",
93
+ "DucoConnectionError",
94
+ "DucoError",
95
+ "DucoRateLimitError",
96
+ "DucoWriteLimitError",
97
+ "DiagComponent",
98
+ "DiagStatus",
99
+ "InfoGroup",
100
+ "InfoGroupStruct",
101
+ "InfoZone",
102
+ "InfoZoneGroup",
103
+ "InfoZonesOverview",
104
+ "InfoZoneStruct",
105
+ "LanInfo",
106
+ "NetworkType",
107
+ "Node",
108
+ "NodeActionItemList",
109
+ "NodeGeneralInfo",
110
+ "NodeListActionItemList",
111
+ "NodeMotorStateInfo",
112
+ "NodeOverview",
113
+ "NodeSensorInfo",
114
+ "NodeType",
115
+ "NodeVentilationInfo",
116
+ "PatchConfigNodeValue",
117
+ "PatchConfigValue",
118
+ "VentilationMode",
119
+ "VentilationState",
120
+ "__version__",
121
+ ]
@@ -0,0 +1,6 @@
1
+ """Module entrypoint for python -m duco_connectivity."""
2
+
3
+ from .cli import main
4
+
5
+ if __name__ == "__main__":
6
+ raise SystemExit(main())