vi-api-client 6.1.1__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.
- vi_api_client-6.1.1/LICENSE +21 -0
- vi_api_client-6.1.1/MANIFEST.in +17 -0
- vi_api_client-6.1.1/PKG-INFO +264 -0
- vi_api_client-6.1.1/README.md +228 -0
- vi_api_client-6.1.1/pyproject.toml +111 -0
- vi_api_client-6.1.1/setup.cfg +4 -0
- vi_api_client-6.1.1/src/vi_api_client/__init__.py +74 -0
- vi_api_client-6.1.1/src/vi_api_client/_adapter.py +321 -0
- vi_api_client-6.1.1/src/vi_api_client/_feature_diff.py +250 -0
- vi_api_client-6.1.1/src/vi_api_client/_types.py +12 -0
- vi_api_client-6.1.1/src/vi_api_client/auth.py +365 -0
- vi_api_client-6.1.1/src/vi_api_client/cli.py +1368 -0
- vi_api_client-6.1.1/src/vi_api_client/client.py +1004 -0
- vi_api_client-6.1.1/src/vi_api_client/const.py +20 -0
- vi_api_client-6.1.1/src/vi_api_client/credentials.py +136 -0
- vi_api_client-6.1.1/src/vi_api_client/exceptions.py +112 -0
- vi_api_client-6.1.1/src/vi_api_client/fixture_client.py +169 -0
- vi_api_client-6.1.1/src/vi_api_client/fixtures/Vitocal200S.json +3968 -0
- vi_api_client-6.1.1/src/vi_api_client/fixtures/Vitocal222S.json +6258 -0
- vi_api_client-6.1.1/src/vi_api_client/fixtures/Vitocal250A.json +6909 -0
- vi_api_client-6.1.1/src/vi_api_client/fixtures/Vitocal333G-with-Vitovent300F.json +4833 -0
- vi_api_client-6.1.1/src/vi_api_client/fixtures/Vitocharge03.json +896 -0
- vi_api_client-6.1.1/src/vi_api_client/fixtures/Vitodens200W.json +4640 -0
- vi_api_client-6.1.1/src/vi_api_client/fixtures/Vitopure350.json +1087 -0
- vi_api_client-6.1.1/src/vi_api_client/fixtures/discovery.json +62 -0
- vi_api_client-6.1.1/src/vi_api_client/fixtures/event_history.json +44 -0
- vi_api_client-6.1.1/src/vi_api_client/fixtures/event_history_final_page.json +6 -0
- vi_api_client-6.1.1/src/vi_api_client/models.py +536 -0
- vi_api_client-6.1.1/src/vi_api_client/parsing.py +592 -0
- vi_api_client-6.1.1/src/vi_api_client/privacy.py +172 -0
- vi_api_client-6.1.1/src/vi_api_client/py.typed +1 -0
- vi_api_client-6.1.1/src/vi_api_client/utils.py +138 -0
- vi_api_client-6.1.1/src/vi_api_client/validation.py +52 -0
- vi_api_client-6.1.1/src/vi_api_client.egg-info/PKG-INFO +264 -0
- vi_api_client-6.1.1/src/vi_api_client.egg-info/SOURCES.txt +37 -0
- vi_api_client-6.1.1/src/vi_api_client.egg-info/dependency_links.txt +1 -0
- vi_api_client-6.1.1/src/vi_api_client.egg-info/entry_points.txt +2 -0
- vi_api_client-6.1.1/src/vi_api_client.egg-info/requires.txt +11 -0
- vi_api_client-6.1.1/src/vi_api_client.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Michael
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
include LICENSE
|
|
2
|
+
include README.md
|
|
3
|
+
include pyproject.toml
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
recursive-include src/vi_api_client *.py
|
|
7
|
+
include src/vi_api_client/py.typed
|
|
8
|
+
recursive-include src/vi_api_client/fixtures *.json
|
|
9
|
+
|
|
10
|
+
# Exclude documentation and local config
|
|
11
|
+
exclude tokens.json
|
|
12
|
+
exclude HA_INTEGRATION_HANDOVER.md
|
|
13
|
+
prune tests
|
|
14
|
+
prune docs
|
|
15
|
+
global-exclude .DS_Store
|
|
16
|
+
global-exclude *.pyc
|
|
17
|
+
global-exclude __pycache__
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vi_api_client
|
|
3
|
+
Version: 6.1.1
|
|
4
|
+
Summary: Async Python client for Viessmann Climate Solutions API
|
|
5
|
+
Author: Michael
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/ignazhabibi/vi_api_client
|
|
8
|
+
Project-URL: Documentation, https://github.com/ignazhabibi/vi_api_client/tree/main/docs
|
|
9
|
+
Project-URL: Issues, https://github.com/ignazhabibi/vi_api_client/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/ignazhabibi/vi_api_client/releases
|
|
11
|
+
Keywords: api-client,asyncio,heat-pump,heating,home-assistant,viessmann
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Framework :: AsyncIO
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
20
|
+
Classifier: Topic :: Home Automation
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.14
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: aiohttp>=3.13.3
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: aiointercept>=0.1.12; extra == "dev"
|
|
28
|
+
Requires-Dist: build>=1.4; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest>=9; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-asyncio>=1.3; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-cov>=7.1; extra == "dev"
|
|
32
|
+
Requires-Dist: pyright==1.1.414; extra == "dev"
|
|
33
|
+
Requires-Dist: pre-commit==4.7.0; extra == "dev"
|
|
34
|
+
Requires-Dist: ruff==0.17.4; extra == "dev"
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
|
|
37
|
+
# Viessmann API Python Client
|
|
38
|
+
|
|
39
|
+
A Python library for accessing the [Viessmann Climate Solutions API](https://developer.viessmann-climatesolutions.com/start.html).
|
|
40
|
+
Designed for integration with Home Assistant and other async Python applications.
|
|
41
|
+
|
|
42
|
+
## Features
|
|
43
|
+
|
|
44
|
+
- **Asynchronous**: Built on `aiohttp` and `asyncio`.
|
|
45
|
+
- **OAuth2 Authentication**: Handles token retrieval and automatic renewal.
|
|
46
|
+
- **Auto-Discovery**: Automatically finds installations, gateways, and devices.
|
|
47
|
+
- **Recursive Feature Flattening**: Converts complex nested API responses into a simple, flat list of features (e.g., `heating.circuits.0.heating.curve.shift`).
|
|
48
|
+
- **Gateway-Scoped Refresh**: Refreshes multiple known devices with one normal-case request while preserving partial successes.
|
|
49
|
+
- **Command Execution**: Supports safe single-feature writes with automatic
|
|
50
|
+
parameter resolution and explicit multi-parameter commands.
|
|
51
|
+
- **Fixture-backed Client**: Runs the same client workflows against bundled real-device
|
|
52
|
+
responses without authentication, sessions, or network requests.
|
|
53
|
+
- **Strictly Typed**: Ships as a PEP 561 complete package with `py.typed`; the
|
|
54
|
+
shipped code passes strict Pyright and dynamic values follow a typed JSON
|
|
55
|
+
value contract.
|
|
56
|
+
|
|
57
|
+
## Public API
|
|
58
|
+
|
|
59
|
+
Import consumer-facing symbols from `vi_api_client`:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from vi_api_client import (
|
|
63
|
+
AbstractAuth,
|
|
64
|
+
CommandResponse,
|
|
65
|
+
DEFAULT_SCOPES,
|
|
66
|
+
Device,
|
|
67
|
+
ENDPOINT_AUTHORIZE,
|
|
68
|
+
ENDPOINT_TOKEN,
|
|
69
|
+
EventHistoryPage,
|
|
70
|
+
Feature,
|
|
71
|
+
FeatureControl,
|
|
72
|
+
FeatureValue,
|
|
73
|
+
Gateway,
|
|
74
|
+
GatewayDeviceRefreshResult,
|
|
75
|
+
Installation,
|
|
76
|
+
InstallationEvent,
|
|
77
|
+
JsonValue,
|
|
78
|
+
FixtureViClient,
|
|
79
|
+
OAuth,
|
|
80
|
+
ScheduleConstraints,
|
|
81
|
+
ValidationDetail,
|
|
82
|
+
ViAuthError,
|
|
83
|
+
ViClient,
|
|
84
|
+
ViConnectionError,
|
|
85
|
+
ViError,
|
|
86
|
+
ViNotFoundError,
|
|
87
|
+
ViRateLimitError,
|
|
88
|
+
ViResponseError,
|
|
89
|
+
ViServerInternalError,
|
|
90
|
+
ViValidationError,
|
|
91
|
+
format_feature,
|
|
92
|
+
redact_device,
|
|
93
|
+
redact_feature,
|
|
94
|
+
redact_sensitive,
|
|
95
|
+
validate_json_value,
|
|
96
|
+
)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`DEFAULT_SCOPES`, `ENDPOINT_AUTHORIZE`, and `ENDPOINT_TOKEN` support external
|
|
100
|
+
OAuth integrations. `JsonValue`, `FeatureValue`, `ValidationDetail`, and
|
|
101
|
+
`validate_json_value` form the public recursive JSON value contract that
|
|
102
|
+
dynamic feature values and API validation details follow. `redact_sensitive`,
|
|
103
|
+
`redact_feature`, and `redact_device` redact secrets, address data,
|
|
104
|
+
identifiers, and coordinates in log text, API documents, and model objects.
|
|
105
|
+
CLI helpers, transport details, persistence, and parsing remain available from
|
|
106
|
+
their dedicated modules.
|
|
107
|
+
|
|
108
|
+
## Installation
|
|
109
|
+
|
|
110
|
+
**Requires Python 3.14+.** Install the released package from PyPI:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
python3.14 -m venv .venv
|
|
114
|
+
source .venv/bin/activate
|
|
115
|
+
pip install vi_api_client
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
To work on the library itself, install it from a clone in editable mode:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
git clone https://github.com/ignazhabibi/vi_api_client.git
|
|
122
|
+
cd vi_api_client
|
|
123
|
+
pip install -e .
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Development and Tests
|
|
127
|
+
|
|
128
|
+
Install the development dependencies with the CI constraints to reproduce the
|
|
129
|
+
tested HTTP client and mock combination locally:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
python -m pip install -c constraints-ci.txt '.[dev]'
|
|
133
|
+
pre-commit install
|
|
134
|
+
ruff check .
|
|
135
|
+
ruff format --check .
|
|
136
|
+
pyright --pythonpath python
|
|
137
|
+
pyright --project pyrightconfig.strict.json
|
|
138
|
+
python -m pytest -q
|
|
139
|
+
python scripts/check_coverage.py
|
|
140
|
+
python -m build
|
|
141
|
+
python scripts/verify_distributions.py
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The shipped package is strictly typed and PEP 561 complete: the strict
|
|
145
|
+
Pyright pass covers `src/vi_api_client`, the built wheel and source
|
|
146
|
+
distribution ship `py.typed`, and the installed wheel passes
|
|
147
|
+
`pyright --verifytypes vi_api_client --ignoreexternal`. Tests remain under
|
|
148
|
+
standard type checking. The suite must keep at least 95% line
|
|
149
|
+
and branch coverage over `src/vi_api_client`; `scripts/check_coverage.py`
|
|
150
|
+
enforces both thresholds in the quality gate.
|
|
151
|
+
|
|
152
|
+
## Quick Start
|
|
153
|
+
|
|
154
|
+
### CLI
|
|
155
|
+
|
|
156
|
+
The `vi-client` tool is the easiest way to explore the API.
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# 1. Login
|
|
160
|
+
vi-client login --client-id <YOUR_CLIENT_ID>
|
|
161
|
+
|
|
162
|
+
# 2. List Devices
|
|
163
|
+
vi-client list-devices
|
|
164
|
+
|
|
165
|
+
# 3. List only enabled Features with values (auto-detects first device)
|
|
166
|
+
vi-client list-features --enabled --values
|
|
167
|
+
|
|
168
|
+
# 4. List Writable Features (Settings)
|
|
169
|
+
vi-client list-writable
|
|
170
|
+
|
|
171
|
+
# 5. List the complete installation event history (last 7 days)
|
|
172
|
+
vi-client list-events --days 7
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
See [CLI Reference](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/06_cli_reference.md) for more details.
|
|
176
|
+
|
|
177
|
+
### Python Code
|
|
178
|
+
|
|
179
|
+
The example reads tokens from `tokens.json`. Create that file once with
|
|
180
|
+
`vi-client login`, or log in from Python as shown in the
|
|
181
|
+
[Authentication reference](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/03_auth_reference.md#first-login).
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
import asyncio
|
|
185
|
+
import aiohttp
|
|
186
|
+
from vi_api_client import OAuth, ViClient
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
async def main():
|
|
190
|
+
async with aiohttp.ClientSession() as session:
|
|
191
|
+
# Initialize Auth (tokens saved to tokens.json)
|
|
192
|
+
auth = OAuth(
|
|
193
|
+
client_id="YOUR_CLIENT_ID",
|
|
194
|
+
redirect_uri="http://localhost:4200/",
|
|
195
|
+
token_file="tokens.json",
|
|
196
|
+
websession=session,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
client = ViClient(auth)
|
|
200
|
+
|
|
201
|
+
# 1. Get Installations & Gateways
|
|
202
|
+
installations = await client.get_installations()
|
|
203
|
+
if not installations:
|
|
204
|
+
return
|
|
205
|
+
installation = installations[0]
|
|
206
|
+
|
|
207
|
+
gateways = await client.get_gateways()
|
|
208
|
+
gateway = next(
|
|
209
|
+
(
|
|
210
|
+
gateway
|
|
211
|
+
for gateway in gateways
|
|
212
|
+
if gateway.installation_id == installation.id
|
|
213
|
+
),
|
|
214
|
+
None,
|
|
215
|
+
)
|
|
216
|
+
if gateway is None:
|
|
217
|
+
return
|
|
218
|
+
|
|
219
|
+
# 2. Discover and refresh devices behind one gateway
|
|
220
|
+
devices = await client.get_devices(installation.id, gateway.serial)
|
|
221
|
+
refresh = await client.refresh_gateway_devices(devices)
|
|
222
|
+
for device_id, error in refresh.errors_by_device_id.items():
|
|
223
|
+
print(f"Device {device_id} could not be refreshed: {error}")
|
|
224
|
+
if not refresh.updated_devices:
|
|
225
|
+
return
|
|
226
|
+
device = refresh.updated_devices[0]
|
|
227
|
+
print(f"Device: {device.model_id} ({device.status})")
|
|
228
|
+
|
|
229
|
+
# 3. Iterate Features (Flat List)
|
|
230
|
+
for feature in device.features:
|
|
231
|
+
print(f"{feature.name}: {feature.value}")
|
|
232
|
+
|
|
233
|
+
# 4. Write one Feature with automatic dependency resolution
|
|
234
|
+
# Find a writable feature (e.g. heating curve slope)
|
|
235
|
+
slope = next(
|
|
236
|
+
(f for f in device.features if "curve.slope" in f.name and f.is_writable),
|
|
237
|
+
None,
|
|
238
|
+
)
|
|
239
|
+
if slope:
|
|
240
|
+
print(f"Setting slope to 1.4...")
|
|
241
|
+
response, device = await client.set_feature(device, slope, 1.4)
|
|
242
|
+
if response.success:
|
|
243
|
+
print("✅ Success! Device updated.")
|
|
244
|
+
# Use updated device for subsequent calls
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
if __name__ == "__main__":
|
|
248
|
+
asyncio.run(main())
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Documentation
|
|
252
|
+
|
|
253
|
+
The detailed documentation is available in the `docs/` directory:
|
|
254
|
+
|
|
255
|
+
1. **[Getting Started](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/01_getting_started.md)**: Installation and First Steps.
|
|
256
|
+
2. **[API Structure & Concepts](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/02_api_structure.md)**: Understanding the Flat Architecture.
|
|
257
|
+
3. **[Authentication & Connection](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/03_auth_reference.md)**: Tokens, Sessions, and Thread-Safety.
|
|
258
|
+
4. **[Models Reference](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/04_models_reference.md)**: Devices, Features, and Controls.
|
|
259
|
+
5. **[Client Reference](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/05_client_reference.md)**: The `ViClient` class methods.
|
|
260
|
+
6. **[CLI Reference](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/06_cli_reference.md)**: Using the command line interface.
|
|
261
|
+
7. **[Exceptions Reference](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/07_exceptions_reference.md)**: Handling errors.
|
|
262
|
+
8. **[Architecture Guide](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/08_architecture.md)**: System structure,
|
|
263
|
+
responsibilities, data flows, and diagrams explained for developers and
|
|
264
|
+
non-specialists.
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Viessmann API Python Client
|
|
2
|
+
|
|
3
|
+
A Python library for accessing the [Viessmann Climate Solutions API](https://developer.viessmann-climatesolutions.com/start.html).
|
|
4
|
+
Designed for integration with Home Assistant and other async Python applications.
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
- **Asynchronous**: Built on `aiohttp` and `asyncio`.
|
|
9
|
+
- **OAuth2 Authentication**: Handles token retrieval and automatic renewal.
|
|
10
|
+
- **Auto-Discovery**: Automatically finds installations, gateways, and devices.
|
|
11
|
+
- **Recursive Feature Flattening**: Converts complex nested API responses into a simple, flat list of features (e.g., `heating.circuits.0.heating.curve.shift`).
|
|
12
|
+
- **Gateway-Scoped Refresh**: Refreshes multiple known devices with one normal-case request while preserving partial successes.
|
|
13
|
+
- **Command Execution**: Supports safe single-feature writes with automatic
|
|
14
|
+
parameter resolution and explicit multi-parameter commands.
|
|
15
|
+
- **Fixture-backed Client**: Runs the same client workflows against bundled real-device
|
|
16
|
+
responses without authentication, sessions, or network requests.
|
|
17
|
+
- **Strictly Typed**: Ships as a PEP 561 complete package with `py.typed`; the
|
|
18
|
+
shipped code passes strict Pyright and dynamic values follow a typed JSON
|
|
19
|
+
value contract.
|
|
20
|
+
|
|
21
|
+
## Public API
|
|
22
|
+
|
|
23
|
+
Import consumer-facing symbols from `vi_api_client`:
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from vi_api_client import (
|
|
27
|
+
AbstractAuth,
|
|
28
|
+
CommandResponse,
|
|
29
|
+
DEFAULT_SCOPES,
|
|
30
|
+
Device,
|
|
31
|
+
ENDPOINT_AUTHORIZE,
|
|
32
|
+
ENDPOINT_TOKEN,
|
|
33
|
+
EventHistoryPage,
|
|
34
|
+
Feature,
|
|
35
|
+
FeatureControl,
|
|
36
|
+
FeatureValue,
|
|
37
|
+
Gateway,
|
|
38
|
+
GatewayDeviceRefreshResult,
|
|
39
|
+
Installation,
|
|
40
|
+
InstallationEvent,
|
|
41
|
+
JsonValue,
|
|
42
|
+
FixtureViClient,
|
|
43
|
+
OAuth,
|
|
44
|
+
ScheduleConstraints,
|
|
45
|
+
ValidationDetail,
|
|
46
|
+
ViAuthError,
|
|
47
|
+
ViClient,
|
|
48
|
+
ViConnectionError,
|
|
49
|
+
ViError,
|
|
50
|
+
ViNotFoundError,
|
|
51
|
+
ViRateLimitError,
|
|
52
|
+
ViResponseError,
|
|
53
|
+
ViServerInternalError,
|
|
54
|
+
ViValidationError,
|
|
55
|
+
format_feature,
|
|
56
|
+
redact_device,
|
|
57
|
+
redact_feature,
|
|
58
|
+
redact_sensitive,
|
|
59
|
+
validate_json_value,
|
|
60
|
+
)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`DEFAULT_SCOPES`, `ENDPOINT_AUTHORIZE`, and `ENDPOINT_TOKEN` support external
|
|
64
|
+
OAuth integrations. `JsonValue`, `FeatureValue`, `ValidationDetail`, and
|
|
65
|
+
`validate_json_value` form the public recursive JSON value contract that
|
|
66
|
+
dynamic feature values and API validation details follow. `redact_sensitive`,
|
|
67
|
+
`redact_feature`, and `redact_device` redact secrets, address data,
|
|
68
|
+
identifiers, and coordinates in log text, API documents, and model objects.
|
|
69
|
+
CLI helpers, transport details, persistence, and parsing remain available from
|
|
70
|
+
their dedicated modules.
|
|
71
|
+
|
|
72
|
+
## Installation
|
|
73
|
+
|
|
74
|
+
**Requires Python 3.14+.** Install the released package from PyPI:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
python3.14 -m venv .venv
|
|
78
|
+
source .venv/bin/activate
|
|
79
|
+
pip install vi_api_client
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
To work on the library itself, install it from a clone in editable mode:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
git clone https://github.com/ignazhabibi/vi_api_client.git
|
|
86
|
+
cd vi_api_client
|
|
87
|
+
pip install -e .
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Development and Tests
|
|
91
|
+
|
|
92
|
+
Install the development dependencies with the CI constraints to reproduce the
|
|
93
|
+
tested HTTP client and mock combination locally:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
python -m pip install -c constraints-ci.txt '.[dev]'
|
|
97
|
+
pre-commit install
|
|
98
|
+
ruff check .
|
|
99
|
+
ruff format --check .
|
|
100
|
+
pyright --pythonpath python
|
|
101
|
+
pyright --project pyrightconfig.strict.json
|
|
102
|
+
python -m pytest -q
|
|
103
|
+
python scripts/check_coverage.py
|
|
104
|
+
python -m build
|
|
105
|
+
python scripts/verify_distributions.py
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The shipped package is strictly typed and PEP 561 complete: the strict
|
|
109
|
+
Pyright pass covers `src/vi_api_client`, the built wheel and source
|
|
110
|
+
distribution ship `py.typed`, and the installed wheel passes
|
|
111
|
+
`pyright --verifytypes vi_api_client --ignoreexternal`. Tests remain under
|
|
112
|
+
standard type checking. The suite must keep at least 95% line
|
|
113
|
+
and branch coverage over `src/vi_api_client`; `scripts/check_coverage.py`
|
|
114
|
+
enforces both thresholds in the quality gate.
|
|
115
|
+
|
|
116
|
+
## Quick Start
|
|
117
|
+
|
|
118
|
+
### CLI
|
|
119
|
+
|
|
120
|
+
The `vi-client` tool is the easiest way to explore the API.
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# 1. Login
|
|
124
|
+
vi-client login --client-id <YOUR_CLIENT_ID>
|
|
125
|
+
|
|
126
|
+
# 2. List Devices
|
|
127
|
+
vi-client list-devices
|
|
128
|
+
|
|
129
|
+
# 3. List only enabled Features with values (auto-detects first device)
|
|
130
|
+
vi-client list-features --enabled --values
|
|
131
|
+
|
|
132
|
+
# 4. List Writable Features (Settings)
|
|
133
|
+
vi-client list-writable
|
|
134
|
+
|
|
135
|
+
# 5. List the complete installation event history (last 7 days)
|
|
136
|
+
vi-client list-events --days 7
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
See [CLI Reference](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/06_cli_reference.md) for more details.
|
|
140
|
+
|
|
141
|
+
### Python Code
|
|
142
|
+
|
|
143
|
+
The example reads tokens from `tokens.json`. Create that file once with
|
|
144
|
+
`vi-client login`, or log in from Python as shown in the
|
|
145
|
+
[Authentication reference](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/03_auth_reference.md#first-login).
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
import asyncio
|
|
149
|
+
import aiohttp
|
|
150
|
+
from vi_api_client import OAuth, ViClient
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
async def main():
|
|
154
|
+
async with aiohttp.ClientSession() as session:
|
|
155
|
+
# Initialize Auth (tokens saved to tokens.json)
|
|
156
|
+
auth = OAuth(
|
|
157
|
+
client_id="YOUR_CLIENT_ID",
|
|
158
|
+
redirect_uri="http://localhost:4200/",
|
|
159
|
+
token_file="tokens.json",
|
|
160
|
+
websession=session,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
client = ViClient(auth)
|
|
164
|
+
|
|
165
|
+
# 1. Get Installations & Gateways
|
|
166
|
+
installations = await client.get_installations()
|
|
167
|
+
if not installations:
|
|
168
|
+
return
|
|
169
|
+
installation = installations[0]
|
|
170
|
+
|
|
171
|
+
gateways = await client.get_gateways()
|
|
172
|
+
gateway = next(
|
|
173
|
+
(
|
|
174
|
+
gateway
|
|
175
|
+
for gateway in gateways
|
|
176
|
+
if gateway.installation_id == installation.id
|
|
177
|
+
),
|
|
178
|
+
None,
|
|
179
|
+
)
|
|
180
|
+
if gateway is None:
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
# 2. Discover and refresh devices behind one gateway
|
|
184
|
+
devices = await client.get_devices(installation.id, gateway.serial)
|
|
185
|
+
refresh = await client.refresh_gateway_devices(devices)
|
|
186
|
+
for device_id, error in refresh.errors_by_device_id.items():
|
|
187
|
+
print(f"Device {device_id} could not be refreshed: {error}")
|
|
188
|
+
if not refresh.updated_devices:
|
|
189
|
+
return
|
|
190
|
+
device = refresh.updated_devices[0]
|
|
191
|
+
print(f"Device: {device.model_id} ({device.status})")
|
|
192
|
+
|
|
193
|
+
# 3. Iterate Features (Flat List)
|
|
194
|
+
for feature in device.features:
|
|
195
|
+
print(f"{feature.name}: {feature.value}")
|
|
196
|
+
|
|
197
|
+
# 4. Write one Feature with automatic dependency resolution
|
|
198
|
+
# Find a writable feature (e.g. heating curve slope)
|
|
199
|
+
slope = next(
|
|
200
|
+
(f for f in device.features if "curve.slope" in f.name and f.is_writable),
|
|
201
|
+
None,
|
|
202
|
+
)
|
|
203
|
+
if slope:
|
|
204
|
+
print(f"Setting slope to 1.4...")
|
|
205
|
+
response, device = await client.set_feature(device, slope, 1.4)
|
|
206
|
+
if response.success:
|
|
207
|
+
print("✅ Success! Device updated.")
|
|
208
|
+
# Use updated device for subsequent calls
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
if __name__ == "__main__":
|
|
212
|
+
asyncio.run(main())
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Documentation
|
|
216
|
+
|
|
217
|
+
The detailed documentation is available in the `docs/` directory:
|
|
218
|
+
|
|
219
|
+
1. **[Getting Started](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/01_getting_started.md)**: Installation and First Steps.
|
|
220
|
+
2. **[API Structure & Concepts](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/02_api_structure.md)**: Understanding the Flat Architecture.
|
|
221
|
+
3. **[Authentication & Connection](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/03_auth_reference.md)**: Tokens, Sessions, and Thread-Safety.
|
|
222
|
+
4. **[Models Reference](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/04_models_reference.md)**: Devices, Features, and Controls.
|
|
223
|
+
5. **[Client Reference](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/05_client_reference.md)**: The `ViClient` class methods.
|
|
224
|
+
6. **[CLI Reference](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/06_cli_reference.md)**: Using the command line interface.
|
|
225
|
+
7. **[Exceptions Reference](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/07_exceptions_reference.md)**: Handling errors.
|
|
226
|
+
8. **[Architecture Guide](https://github.com/ignazhabibi/vi_api_client/blob/main/docs/08_architecture.md)**: System structure,
|
|
227
|
+
responsibilities, data flows, and diagrams explained for developers and
|
|
228
|
+
non-specialists.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vi_api_client"
|
|
7
|
+
version = "6.1.1"
|
|
8
|
+
description = "Async Python client for Viessmann Climate Solutions API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [
|
|
11
|
+
{ name = "Michael" },
|
|
12
|
+
]
|
|
13
|
+
license = "MIT"
|
|
14
|
+
license-files = ["LICENSE"]
|
|
15
|
+
keywords = [
|
|
16
|
+
"api-client",
|
|
17
|
+
"asyncio",
|
|
18
|
+
"heat-pump",
|
|
19
|
+
"heating",
|
|
20
|
+
"home-assistant",
|
|
21
|
+
"viessmann",
|
|
22
|
+
]
|
|
23
|
+
classifiers = [
|
|
24
|
+
"Development Status :: 5 - Production/Stable",
|
|
25
|
+
"Framework :: AsyncIO",
|
|
26
|
+
"Intended Audience :: Developers",
|
|
27
|
+
"Operating System :: OS Independent",
|
|
28
|
+
"Programming Language :: Python :: 3",
|
|
29
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
30
|
+
"Programming Language :: Python :: 3.14",
|
|
31
|
+
"Programming Language :: Python :: 3.15",
|
|
32
|
+
"Topic :: Home Automation",
|
|
33
|
+
"Typing :: Typed",
|
|
34
|
+
]
|
|
35
|
+
requires-python = ">=3.14"
|
|
36
|
+
dependencies = [
|
|
37
|
+
"aiohttp>=3.13.3",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.urls]
|
|
41
|
+
Homepage = "https://github.com/ignazhabibi/vi_api_client"
|
|
42
|
+
Documentation = "https://github.com/ignazhabibi/vi_api_client/tree/main/docs"
|
|
43
|
+
Issues = "https://github.com/ignazhabibi/vi_api_client/issues"
|
|
44
|
+
Changelog = "https://github.com/ignazhabibi/vi_api_client/releases"
|
|
45
|
+
|
|
46
|
+
[project.optional-dependencies]
|
|
47
|
+
dev = [
|
|
48
|
+
"aiointercept>=0.1.12",
|
|
49
|
+
"build>=1.4",
|
|
50
|
+
"pytest>=9",
|
|
51
|
+
"pytest-asyncio>=1.3",
|
|
52
|
+
"pytest-cov>=7.1",
|
|
53
|
+
"pyright==1.1.414",
|
|
54
|
+
"pre-commit==4.7.0",
|
|
55
|
+
"ruff==0.17.4",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[project.scripts]
|
|
59
|
+
vi-client = "vi_api_client.cli:main"
|
|
60
|
+
|
|
61
|
+
[tool.setuptools.package-data]
|
|
62
|
+
vi_api_client = ["py.typed"]
|
|
63
|
+
|
|
64
|
+
[tool.ruff]
|
|
65
|
+
line-length = 88
|
|
66
|
+
target-version = "py314"
|
|
67
|
+
|
|
68
|
+
[tool.ruff.lint]
|
|
69
|
+
select = [
|
|
70
|
+
"D", # pydocstyle
|
|
71
|
+
"E", # pycodestyle error
|
|
72
|
+
"W", # pycodestyle warning
|
|
73
|
+
"F", # pyflakes
|
|
74
|
+
"I", # isort
|
|
75
|
+
"UP", # pyupgrade
|
|
76
|
+
"B", # flake8-bugbear
|
|
77
|
+
"SIM", # flake8-simplify
|
|
78
|
+
"PL", # pylint
|
|
79
|
+
"RUF", # ruff specific
|
|
80
|
+
"S" # flake8-bandit (security)
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
ignore = [
|
|
84
|
+
"D100", # Missing docstring in public module
|
|
85
|
+
"D104", # Missing docstring in public package
|
|
86
|
+
"D105", # Missing docstring in magic method
|
|
87
|
+
"D203", # 1 blank line required before class docstring
|
|
88
|
+
"D213", # Multi-line docstring summary should start at the second line
|
|
89
|
+
"PLR2004", # Magic value used
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
[tool.ruff.lint.per-file-ignores]
|
|
93
|
+
"tests/*" = [
|
|
94
|
+
"D", "PLR0913", "PLR0917", "PLR2004", "E501",
|
|
95
|
+
# Tests assert, use placeholder tokens, and run the CLI as a subprocess.
|
|
96
|
+
"S101", "S105", "S106", "S603",
|
|
97
|
+
]
|
|
98
|
+
# Repository scripts run fixed tool commands and parse the local coverage.xml.
|
|
99
|
+
"scripts/*" = ["S314", "S603"]
|
|
100
|
+
|
|
101
|
+
[tool.ruff.lint.pydocstyle]
|
|
102
|
+
convention = "google"
|
|
103
|
+
|
|
104
|
+
[tool.ruff.lint.isort]
|
|
105
|
+
combine-as-imports = true
|
|
106
|
+
|
|
107
|
+
[tool.pyright]
|
|
108
|
+
include = ["src", "tests"]
|
|
109
|
+
exclude = [".venv", "build", "dist"]
|
|
110
|
+
pythonVersion = "3.14"
|
|
111
|
+
typeCheckingMode = "standard"
|