smartbox 2.7.0__tar.gz → 3.0.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.
- {smartbox-2.7.0 → smartbox-3.0.0}/CHANGELOG.md +26 -0
- smartbox-3.0.0/PKG-INFO +131 -0
- smartbox-3.0.0/README.md +111 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/pyproject.toml +42 -23
- smartbox-3.0.0/src/smartbox/__init__.py +17 -0
- smartbox-3.0.0/src/smartbox/cli.py +615 -0
- smartbox-3.0.0/src/smartbox/core/__init__.py +37 -0
- smartbox-3.0.0/src/smartbox/core/deadlines.py +272 -0
- smartbox-3.0.0/src/smartbox/core/engine.py +1772 -0
- smartbox-3.0.0/src/smartbox/core/feed.py +198 -0
- smartbox-3.0.0/src/smartbox/core/merging.py +369 -0
- smartbox-3.0.0/src/smartbox/core/state.py +190 -0
- smartbox-3.0.0/src/smartbox/protocol/__init__.py +67 -0
- smartbox-3.0.0/src/smartbox/protocol/auth.py +415 -0
- smartbox-3.0.0/src/smartbox/protocol/client.py +421 -0
- smartbox-3.0.0/src/smartbox/protocol/errors.py +35 -0
- smartbox-3.0.0/src/smartbox/protocol/events.py +65 -0
- smartbox-3.0.0/src/smartbox/protocol/jwt.py +75 -0
- smartbox-3.0.0/src/smartbox/protocol/paths.py +31 -0
- {smartbox-2.7.0/src/smartbox → smartbox-3.0.0/src/smartbox/protocol}/reseller.py +54 -26
- smartbox-3.0.0/src/smartbox/protocol/retry.py +38 -0
- smartbox-3.0.0/src/smartbox/protocol/timing.py +24 -0
- smartbox-3.0.0/src/smartbox/protocol/transport.py +78 -0
- smartbox-3.0.0/src/smartbox/protocol/values.py +314 -0
- smartbox-3.0.0/src/smartbox/protocol/writes.py +740 -0
- smartbox-3.0.0/src/smartbox/protocol/ws_user.py +735 -0
- smartbox-3.0.0/tests/fake_api.py +393 -0
- smartbox-3.0.0/tests/fake_transport.py +77 -0
- smartbox-3.0.0/tests/fakes.py +253 -0
- smartbox-3.0.0/tests/fixtures/live/README.md +11 -0
- smartbox-3.0.0/tests/test_auth.py +597 -0
- smartbox-3.0.0/tests/test_cli.py +21 -0
- smartbox-3.0.0/tests/test_client.py +625 -0
- smartbox-3.0.0/tests/test_core_availability.py +1269 -0
- smartbox-3.0.0/tests/test_core_engine.py +1368 -0
- smartbox-3.0.0/tests/test_core_state.py +74 -0
- smartbox-3.0.0/tests/test_core_writes.py +1360 -0
- smartbox-3.0.0/tests/test_layering.py +30 -0
- smartbox-3.0.0/tests/test_reseller.py +40 -0
- smartbox-3.0.0/tests/test_retry.py +24 -0
- smartbox-3.0.0/tests/test_values.py +255 -0
- smartbox-3.0.0/tests/test_writes.py +790 -0
- smartbox-3.0.0/tests/test_ws_user_transport.py +1231 -0
- smartbox-3.0.0/tests/utils.py +54 -0
- smartbox-2.7.0/.env.example +0 -16
- smartbox-2.7.0/.github/FUNDING.yml +0 -3
- smartbox-2.7.0/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
- smartbox-2.7.0/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
- smartbox-2.7.0/.github/ISSUE_TEMPLATE/new-reseller.md +0 -19
- smartbox-2.7.0/.github/dependabot.yml +0 -19
- smartbox-2.7.0/.github/workflows/publish-to-pypi.yml +0 -31
- smartbox-2.7.0/.github/workflows/python-package.yml +0 -88
- smartbox-2.7.0/.pre-commit-config.yaml +0 -29
- smartbox-2.7.0/.vscode/settings.json +0 -12
- smartbox-2.7.0/CODEOWNERS +0 -5
- smartbox-2.7.0/PKG-INFO +0 -254
- smartbox-2.7.0/README.md +0 -234
- smartbox-2.7.0/ajtudela-pr-64-audit.md +0 -497
- smartbox-2.7.0/api-notes.md +0 -861
- smartbox-2.7.0/codecov.yml +0 -8
- smartbox-2.7.0/src/smartbox/__init__.py +0 -93
- smartbox-2.7.0/src/smartbox/cmd.py +0 -663
- smartbox-2.7.0/src/smartbox/error.py +0 -54
- smartbox-2.7.0/src/smartbox/models.py +0 -325
- smartbox-2.7.0/src/smartbox/retry.py +0 -78
- smartbox-2.7.0/src/smartbox/session.py +0 -1872
- smartbox-2.7.0/src/smartbox/socket.py +0 -509
- smartbox-2.7.0/src/smartbox/update_manager.py +0 -774
- smartbox-2.7.0/src/smartbox/ws_user.py +0 -758
- smartbox-2.7.0/tests/common.py +0 -28
- smartbox-2.7.0/tests/conftest.py +0 -142
- smartbox-2.7.0/tests/test_cmd.py +0 -706
- smartbox-2.7.0/tests/test_live_payloads.py +0 -133
- smartbox-2.7.0/tests/test_models.py +0 -334
- smartbox-2.7.0/tests/test_reseller.py +0 -65
- smartbox-2.7.0/tests/test_session.py +0 -2776
- smartbox-2.7.0/tests/test_session_reliability.py +0 -552
- smartbox-2.7.0/tests/test_socket.py +0 -673
- smartbox-2.7.0/tests/test_update_manager.py +0 -974
- smartbox-2.7.0/tests/test_ws_user.py +0 -887
- smartbox-2.7.0/tools/api_functional_tests.py +0 -233
- smartbox-2.7.0/tools/away_probe.py +0 -109
- smartbox-2.7.0/tools/capture_prog.py +0 -84
- smartbox-2.7.0/tools/live_check.py +0 -137
- smartbox-2.7.0/tools/probe_extra_options.py +0 -145
- smartbox-2.7.0/tools/probe_modified_auto.py +0 -214
- smartbox-2.7.0/tools/probe_settle_window.py +0 -146
- smartbox-2.7.0/tools/probe_ws_user.py +0 -491
- smartbox-2.7.0/tools/prog_functional_tests.py +0 -143
- smartbox-2.7.0/tools/watch_status.py +0 -123
- smartbox-2.7.0/uv.lock +0 -1424
- smartbox-2.7.0/webapi-spec.md +0 -186
- {smartbox-2.7.0 → smartbox-3.0.0}/.gitignore +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/LICENSE +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/src/smartbox/py.typed +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/__init__.py +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/acm/1/samples.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/acm/1/setup.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/acm/1/status.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/acm/1/version.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/connected.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/htr/0/samples.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/htr/0/setup.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/htr/0/status.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/htr/0/version.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/htr_system/power_limit.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/mgr/away_status.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/mgr/nodes.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/pmo/3/samples.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/pmo/3/setup.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/pmo/3/status.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/pmo/3/version.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/connected.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/0/samples.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/0/setup.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/0/status.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/0/version.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/1/samples.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/1/setup.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/1/status.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/1/version.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/2/samples.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/2/setup.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/2/status.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/2/version.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/3/samples.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/3/setup.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/3/status.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/3/version.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/4/samples.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/4/setup.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/4/status.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/4/version.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/5/samples.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/5/setup.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/5/status.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/5/version.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_system/power_limit.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/mgr/away_status.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/mgr/nodes.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/grouped_devs.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/groups/test_home/guest_users.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_prog_addr2.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_prog_addr3.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_prog_addr4.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_prog_addr5.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_prog_addr6.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_setup_addr2.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_setup_addr3.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_setup_addr4.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_setup_addr5.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_setup_addr6.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_setup_no_boost.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_status_boost_off.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/socket_update_status_frame.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/socket_update_sync_lost_frame.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/socket_update_version_frame.json +0 -0
- {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/test_path.json +0 -0
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.0.0
|
|
4
|
+
|
|
5
|
+
First stable release of the standalone protocol/core library used by the 3.x
|
|
6
|
+
Home Assistant integration.
|
|
7
|
+
|
|
8
|
+
### Breaking
|
|
9
|
+
|
|
10
|
+
* The 2.7 session/update-manager API is replaced by `smartbox.protocol`
|
|
11
|
+
(`SmartboxClient`, auth, `ws_user` transport, named writes) and
|
|
12
|
+
`smartbox.core` (`SmartboxEngine`, state, deadlines, feed).
|
|
13
|
+
* The library is Home Assistant-free by construction; the integration depends
|
|
14
|
+
on it instead of vendoring the layers.
|
|
15
|
+
* The CLI now uses the new client and `ws_user` transport. The old per-device
|
|
16
|
+
`socket` command is replaced by `listen`; `set-setup` exposes the granular
|
|
17
|
+
setup writes; boost and node power-limit commands are added.
|
|
18
|
+
|
|
19
|
+
### New
|
|
20
|
+
|
|
21
|
+
* The CLI remains available as the optional `cli` extra:
|
|
22
|
+
`pip install "smartbox[cli] ..."`.
|
|
23
|
+
* `SmartboxClient.get_home_guests()` and the CLI `guests` command.
|
|
24
|
+
* `WriteApi.set_setup_value()` as the CLI/debug escape hatch for setup keys
|
|
25
|
+
without a named setter.
|
|
26
|
+
|
|
27
|
+
See GitHub release notes: https://github.com/jandado/smartbox/releases
|
|
28
|
+
|
|
3
29
|
## 2.7.0
|
|
4
30
|
|
|
5
31
|
### New
|
smartbox-3.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: smartbox
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: Python API to control heating 'smart boxes'
|
|
5
|
+
Project-URL: Homepage, https://github.com/jandado/smartbox
|
|
6
|
+
Project-URL: Issues, https://github.com/jandado/smartbox/issues
|
|
7
|
+
Project-URL: Upstream, https://github.com/ajtudela/smartbox
|
|
8
|
+
Author-email: Alberto Tudela <ajtudela@gmail.com>, Delmael <delmael@outlook.com>, graham33 <graham@grahambennett.org>
|
|
9
|
+
Maintainer: Jan Dado
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Requires-Python: >=3.14.2
|
|
16
|
+
Requires-Dist: aiohttp<4,>=3
|
|
17
|
+
Provides-Extra: cli
|
|
18
|
+
Requires-Dist: asyncclick; extra == 'cli'
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# smartbox 3.0
|
|
22
|
+
|
|
23
|
+
Python library for Smartbox heating systems (Helki and its resellers: Elnur,
|
|
24
|
+
Haverland, Climastar, Technotherm, HJM, …).
|
|
25
|
+
|
|
26
|
+
This is the 3.0 rewrite. It exposes the protocol and domain layers that the
|
|
27
|
+
Home Assistant integration uses, without importing Home Assistant. The 2.7
|
|
28
|
+
API remains available on the `main` branch and the `v2.7.0` tag.
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
From the tagged source:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
pip install "smartbox @ https://github.com/jandado/smartbox/archive/refs/tags/v3.0.0.tar.gz"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
With the optional command line tool:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
pip install "smartbox[cli] @ https://github.com/jandado/smartbox/archive/refs/tags/v3.0.0.tar.gz"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
For development:
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
uv sync --all-extras --dev
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Library
|
|
51
|
+
|
|
52
|
+
`SmartboxClient` owns the REST API and the token lifecycle. `smartbox.core`
|
|
53
|
+
contains the Home Assistant-free state engine, write confirmation and feed
|
|
54
|
+
supervision.
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
import asyncio
|
|
58
|
+
|
|
59
|
+
from smartbox.core import SmartboxEngine
|
|
60
|
+
from smartbox.protocol import API_HOST, AuthConfig, ManagedTokenSource, SmartboxClient
|
|
61
|
+
|
|
62
|
+
CONFIG = AuthConfig(
|
|
63
|
+
api_host=API_HOST,
|
|
64
|
+
basic_auth_creds="<reseller Basic auth>",
|
|
65
|
+
serial_id="1",
|
|
66
|
+
username="you@example.com",
|
|
67
|
+
password="secret",
|
|
68
|
+
referer="https://app.helki.com/",
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
async def main() -> None:
|
|
72
|
+
client = SmartboxClient(CONFIG)
|
|
73
|
+
try:
|
|
74
|
+
print(await client.get_devices())
|
|
75
|
+
finally:
|
|
76
|
+
await client.close()
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The lower layers are Home Assistant-free and are tested without the HA test
|
|
80
|
+
harness.
|
|
81
|
+
|
|
82
|
+
## CLI
|
|
83
|
+
|
|
84
|
+
The CLI is an optional extra; the base package only depends on `aiohttp`.
|
|
85
|
+
|
|
86
|
+
Authentication options are `-a/--api-name`, `-b/--basic-auth-creds`,
|
|
87
|
+
`-u/--username`, `-p/--password`, `-r/--x-referer`, `-i/--x-serial-id`.
|
|
88
|
+
They also resolve from `SMARTBOX_*` environment variables, and the script
|
|
89
|
+
loads the nearest `.env` file. Command line values win over the environment,
|
|
90
|
+
which wins over `.env`.
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
smartbox -a api -u you@example.com -p secret devices
|
|
94
|
+
smartbox -a api -u you@example.com -p secret nodes
|
|
95
|
+
smartbox -a api -u you@example.com -p secret status
|
|
96
|
+
smartbox -a api -u you@example.com -p secret set-status -d DEV -n 0 --mode auto
|
|
97
|
+
smartbox -a api -u you@example.com -p secret set-boost-mode -d DEV -n 0 \
|
|
98
|
+
--active --mode runback --temperature 21 --time-minutes 60
|
|
99
|
+
smartbox -a api -u you@example.com -p secret listen
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`smartbox --help` lists every command. Reads print the raw wire payloads;
|
|
103
|
+
writes print the posted path and body. `listen` follows the shared `ws_user`
|
|
104
|
+
feed and can filter updates with `--device-id`.
|
|
105
|
+
|
|
106
|
+
## Layout
|
|
107
|
+
|
|
108
|
+
- `smartbox.protocol` — auth, REST client, `ws_user` transport, wire values
|
|
109
|
+
and named writes.
|
|
110
|
+
- `smartbox.core` — versioned state store, merges, write confirmation,
|
|
111
|
+
deadlines and feed supervision.
|
|
112
|
+
- `smartbox.cli` — the optional debugging CLI.
|
|
113
|
+
|
|
114
|
+
The canonical wire record lives in the sibling `hass-smartbox` repository
|
|
115
|
+
under `docs/` (`api-contract.md`, `api-ws-user.md`, `webapi-spec.md`);
|
|
116
|
+
`webapi-spec.md` in this repo is a pointer.
|
|
117
|
+
|
|
118
|
+
## Development
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
uv run pytest
|
|
122
|
+
uv run ruff check src tests
|
|
123
|
+
uv run mypy src
|
|
124
|
+
uv run tox
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Credits
|
|
128
|
+
|
|
129
|
+
The original library and the 2.7.x line are by Alberto Tudela, Delmael,
|
|
130
|
+
graham33 and the upstream contributors. This fork carries the 3.0 rewrite;
|
|
131
|
+
upstream collaboration is welcome.
|
smartbox-3.0.0/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# smartbox 3.0
|
|
2
|
+
|
|
3
|
+
Python library for Smartbox heating systems (Helki and its resellers: Elnur,
|
|
4
|
+
Haverland, Climastar, Technotherm, HJM, …).
|
|
5
|
+
|
|
6
|
+
This is the 3.0 rewrite. It exposes the protocol and domain layers that the
|
|
7
|
+
Home Assistant integration uses, without importing Home Assistant. The 2.7
|
|
8
|
+
API remains available on the `main` branch and the `v2.7.0` tag.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
From the tagged source:
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
pip install "smartbox @ https://github.com/jandado/smartbox/archive/refs/tags/v3.0.0.tar.gz"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
With the optional command line tool:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
pip install "smartbox[cli] @ https://github.com/jandado/smartbox/archive/refs/tags/v3.0.0.tar.gz"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
For development:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
uv sync --all-extras --dev
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Library
|
|
31
|
+
|
|
32
|
+
`SmartboxClient` owns the REST API and the token lifecycle. `smartbox.core`
|
|
33
|
+
contains the Home Assistant-free state engine, write confirmation and feed
|
|
34
|
+
supervision.
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
import asyncio
|
|
38
|
+
|
|
39
|
+
from smartbox.core import SmartboxEngine
|
|
40
|
+
from smartbox.protocol import API_HOST, AuthConfig, ManagedTokenSource, SmartboxClient
|
|
41
|
+
|
|
42
|
+
CONFIG = AuthConfig(
|
|
43
|
+
api_host=API_HOST,
|
|
44
|
+
basic_auth_creds="<reseller Basic auth>",
|
|
45
|
+
serial_id="1",
|
|
46
|
+
username="you@example.com",
|
|
47
|
+
password="secret",
|
|
48
|
+
referer="https://app.helki.com/",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
async def main() -> None:
|
|
52
|
+
client = SmartboxClient(CONFIG)
|
|
53
|
+
try:
|
|
54
|
+
print(await client.get_devices())
|
|
55
|
+
finally:
|
|
56
|
+
await client.close()
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The lower layers are Home Assistant-free and are tested without the HA test
|
|
60
|
+
harness.
|
|
61
|
+
|
|
62
|
+
## CLI
|
|
63
|
+
|
|
64
|
+
The CLI is an optional extra; the base package only depends on `aiohttp`.
|
|
65
|
+
|
|
66
|
+
Authentication options are `-a/--api-name`, `-b/--basic-auth-creds`,
|
|
67
|
+
`-u/--username`, `-p/--password`, `-r/--x-referer`, `-i/--x-serial-id`.
|
|
68
|
+
They also resolve from `SMARTBOX_*` environment variables, and the script
|
|
69
|
+
loads the nearest `.env` file. Command line values win over the environment,
|
|
70
|
+
which wins over `.env`.
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
smartbox -a api -u you@example.com -p secret devices
|
|
74
|
+
smartbox -a api -u you@example.com -p secret nodes
|
|
75
|
+
smartbox -a api -u you@example.com -p secret status
|
|
76
|
+
smartbox -a api -u you@example.com -p secret set-status -d DEV -n 0 --mode auto
|
|
77
|
+
smartbox -a api -u you@example.com -p secret set-boost-mode -d DEV -n 0 \
|
|
78
|
+
--active --mode runback --temperature 21 --time-minutes 60
|
|
79
|
+
smartbox -a api -u you@example.com -p secret listen
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`smartbox --help` lists every command. Reads print the raw wire payloads;
|
|
83
|
+
writes print the posted path and body. `listen` follows the shared `ws_user`
|
|
84
|
+
feed and can filter updates with `--device-id`.
|
|
85
|
+
|
|
86
|
+
## Layout
|
|
87
|
+
|
|
88
|
+
- `smartbox.protocol` — auth, REST client, `ws_user` transport, wire values
|
|
89
|
+
and named writes.
|
|
90
|
+
- `smartbox.core` — versioned state store, merges, write confirmation,
|
|
91
|
+
deadlines and feed supervision.
|
|
92
|
+
- `smartbox.cli` — the optional debugging CLI.
|
|
93
|
+
|
|
94
|
+
The canonical wire record lives in the sibling `hass-smartbox` repository
|
|
95
|
+
under `docs/` (`api-contract.md`, `api-ws-user.md`, `webapi-spec.md`);
|
|
96
|
+
`webapi-spec.md` in this repo is a pointer.
|
|
97
|
+
|
|
98
|
+
## Development
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
uv run pytest
|
|
102
|
+
uv run ruff check src tests
|
|
103
|
+
uv run mypy src
|
|
104
|
+
uv run tox
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Credits
|
|
108
|
+
|
|
109
|
+
The original library and the 2.7.x line are by Alberto Tudela, Delmael,
|
|
110
|
+
graham33 and the upstream contributors. This fork carries the 3.0 rewrite;
|
|
111
|
+
upstream collaboration is welcome.
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "smartbox"
|
|
3
|
-
version = "
|
|
3
|
+
version = "3.0.0"
|
|
4
4
|
requires-python = ">=3.14.2"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name="Alberto Tudela", email="ajtudela@gmail.com" },
|
|
7
7
|
{ name="Delmael", email="delmael@outlook.com" },
|
|
8
8
|
{ name="graham33", email="graham@grahambennett.org" },
|
|
9
9
|
]
|
|
10
|
+
maintainers = [
|
|
11
|
+
{ name="Jan Dado" },
|
|
12
|
+
]
|
|
10
13
|
description = "Python API to control heating 'smart boxes'"
|
|
11
14
|
readme = "README.md"
|
|
12
15
|
|
|
@@ -19,38 +22,44 @@ license = "MIT"
|
|
|
19
22
|
license-files = ["LICEN[CS]E*"]
|
|
20
23
|
dependencies = [
|
|
21
24
|
"aiohttp>=3,<4",
|
|
22
|
-
"asyncclick",
|
|
23
|
-
"jq",
|
|
24
|
-
"pydantic>=2,<3",
|
|
25
|
-
"python-socketio>=5,<6",
|
|
26
25
|
]
|
|
27
26
|
|
|
28
|
-
[project.
|
|
29
|
-
|
|
30
|
-
Issues = "https://github.com/ajtudela/smartbox/issues"
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
cli = ["asyncclick"]
|
|
31
29
|
|
|
32
30
|
[project.scripts]
|
|
33
|
-
smartbox = "smartbox.
|
|
31
|
+
smartbox = "smartbox.cli:cli"
|
|
32
|
+
|
|
33
|
+
[project.urls]
|
|
34
|
+
Homepage = "https://github.com/jandado/smartbox"
|
|
35
|
+
Issues = "https://github.com/jandado/smartbox/issues"
|
|
36
|
+
Upstream = "https://github.com/ajtudela/smartbox"
|
|
34
37
|
|
|
35
38
|
[build-system]
|
|
36
39
|
requires = ["hatchling"]
|
|
37
40
|
build-backend = "hatchling.build"
|
|
38
41
|
|
|
42
|
+
[tool.hatch.build.targets.sdist]
|
|
43
|
+
include = [
|
|
44
|
+
"/src/smartbox",
|
|
45
|
+
"/tests",
|
|
46
|
+
"/README.md",
|
|
47
|
+
"/LICENSE",
|
|
48
|
+
"/CHANGELOG.md",
|
|
49
|
+
]
|
|
50
|
+
|
|
39
51
|
|
|
40
52
|
[dependency-groups]
|
|
41
53
|
dev = [
|
|
42
|
-
"
|
|
43
|
-
"
|
|
54
|
+
"asyncclick",
|
|
55
|
+
"multidict",
|
|
44
56
|
"pytest",
|
|
45
57
|
"pytest-asyncio",
|
|
46
58
|
"pytest-cov",
|
|
47
|
-
"pytest-mock",
|
|
48
|
-
"pytest-randomly",
|
|
49
|
-
"requests-mock",
|
|
50
|
-
"tox",
|
|
51
59
|
"ruff",
|
|
52
60
|
"mypy",
|
|
53
|
-
"
|
|
61
|
+
"tox",
|
|
62
|
+
"yarl",
|
|
54
63
|
]
|
|
55
64
|
|
|
56
65
|
[tool.pytest.ini_options]
|
|
@@ -61,6 +70,11 @@ markers = [
|
|
|
61
70
|
"network: tests that make real HTTP calls to reseller servers (deselected by default; run with -m network)",
|
|
62
71
|
]
|
|
63
72
|
|
|
73
|
+
[tool.coverage.run]
|
|
74
|
+
# The CLI is an optional extra; it is exercised manually against the live API
|
|
75
|
+
# and by the `--help`/reseller smoke tests, not by the core coverage gate.
|
|
76
|
+
omit = ["src/smartbox/cli.py"]
|
|
77
|
+
|
|
64
78
|
[tool.coverage.report]
|
|
65
79
|
fail_under = 95
|
|
66
80
|
exclude_also = ["if __name__ == .__main__.:"]
|
|
@@ -69,18 +83,14 @@ exclude_also = ["if __name__ == .__main__.:"]
|
|
|
69
83
|
warn_unused_configs = true
|
|
70
84
|
|
|
71
85
|
[[tool.mypy.overrides]]
|
|
72
|
-
module = [
|
|
73
|
-
"jq",
|
|
74
|
-
"socketio",
|
|
75
|
-
"asyncio",
|
|
76
|
-
]
|
|
86
|
+
module = ["asyncio"]
|
|
77
87
|
ignore_missing_imports = true
|
|
78
88
|
disable_error_code = ["arg-type"]
|
|
79
89
|
|
|
80
90
|
[tool.ruff]
|
|
81
91
|
target-version = "py314"
|
|
82
92
|
fix = true
|
|
83
|
-
line-length =
|
|
93
|
+
line-length = 88
|
|
84
94
|
extend-exclude = ["tools"]
|
|
85
95
|
|
|
86
96
|
[tool.ruff.lint]
|
|
@@ -140,8 +150,17 @@ max-complexity = 25
|
|
|
140
150
|
"S106",
|
|
141
151
|
"PLR2004",
|
|
142
152
|
"B018",
|
|
153
|
+
"PT011",
|
|
154
|
+
]
|
|
155
|
+
"src/smartbox/cli.py" = [
|
|
156
|
+
"ANN401",
|
|
157
|
+
"D10",
|
|
158
|
+
"EM101",
|
|
159
|
+
"EM102",
|
|
160
|
+
"PLR2004",
|
|
161
|
+
"TRY003",
|
|
143
162
|
]
|
|
144
|
-
"src/smartbox/
|
|
163
|
+
"src/smartbox/core/**" = ["TID252"]
|
|
145
164
|
"tools/*" = ["T201", "ANN401", "INP001", "PLR0911", "PLR0915", "S108", "ASYNC240"]
|
|
146
165
|
|
|
147
166
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Smartbox protocol and domain layers.
|
|
2
|
+
|
|
3
|
+
The package is Home Assistant-agnostic: ``smartbox.protocol`` owns the
|
|
4
|
+
wire and the ``smartbox.core`` package owns the domain state. Both are
|
|
5
|
+
usable without the HA test harness.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
9
|
+
|
|
10
|
+
from . import core, protocol
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
__version__ = version("smartbox")
|
|
14
|
+
except PackageNotFoundError: # pragma: no cover - vendored/undist import
|
|
15
|
+
__version__ = "0.0.0"
|
|
16
|
+
|
|
17
|
+
__all__ = ["__version__", "core", "protocol"]
|