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.
Files changed (159) hide show
  1. {smartbox-2.7.0 → smartbox-3.0.0}/CHANGELOG.md +26 -0
  2. smartbox-3.0.0/PKG-INFO +131 -0
  3. smartbox-3.0.0/README.md +111 -0
  4. {smartbox-2.7.0 → smartbox-3.0.0}/pyproject.toml +42 -23
  5. smartbox-3.0.0/src/smartbox/__init__.py +17 -0
  6. smartbox-3.0.0/src/smartbox/cli.py +615 -0
  7. smartbox-3.0.0/src/smartbox/core/__init__.py +37 -0
  8. smartbox-3.0.0/src/smartbox/core/deadlines.py +272 -0
  9. smartbox-3.0.0/src/smartbox/core/engine.py +1772 -0
  10. smartbox-3.0.0/src/smartbox/core/feed.py +198 -0
  11. smartbox-3.0.0/src/smartbox/core/merging.py +369 -0
  12. smartbox-3.0.0/src/smartbox/core/state.py +190 -0
  13. smartbox-3.0.0/src/smartbox/protocol/__init__.py +67 -0
  14. smartbox-3.0.0/src/smartbox/protocol/auth.py +415 -0
  15. smartbox-3.0.0/src/smartbox/protocol/client.py +421 -0
  16. smartbox-3.0.0/src/smartbox/protocol/errors.py +35 -0
  17. smartbox-3.0.0/src/smartbox/protocol/events.py +65 -0
  18. smartbox-3.0.0/src/smartbox/protocol/jwt.py +75 -0
  19. smartbox-3.0.0/src/smartbox/protocol/paths.py +31 -0
  20. {smartbox-2.7.0/src/smartbox → smartbox-3.0.0/src/smartbox/protocol}/reseller.py +54 -26
  21. smartbox-3.0.0/src/smartbox/protocol/retry.py +38 -0
  22. smartbox-3.0.0/src/smartbox/protocol/timing.py +24 -0
  23. smartbox-3.0.0/src/smartbox/protocol/transport.py +78 -0
  24. smartbox-3.0.0/src/smartbox/protocol/values.py +314 -0
  25. smartbox-3.0.0/src/smartbox/protocol/writes.py +740 -0
  26. smartbox-3.0.0/src/smartbox/protocol/ws_user.py +735 -0
  27. smartbox-3.0.0/tests/fake_api.py +393 -0
  28. smartbox-3.0.0/tests/fake_transport.py +77 -0
  29. smartbox-3.0.0/tests/fakes.py +253 -0
  30. smartbox-3.0.0/tests/fixtures/live/README.md +11 -0
  31. smartbox-3.0.0/tests/test_auth.py +597 -0
  32. smartbox-3.0.0/tests/test_cli.py +21 -0
  33. smartbox-3.0.0/tests/test_client.py +625 -0
  34. smartbox-3.0.0/tests/test_core_availability.py +1269 -0
  35. smartbox-3.0.0/tests/test_core_engine.py +1368 -0
  36. smartbox-3.0.0/tests/test_core_state.py +74 -0
  37. smartbox-3.0.0/tests/test_core_writes.py +1360 -0
  38. smartbox-3.0.0/tests/test_layering.py +30 -0
  39. smartbox-3.0.0/tests/test_reseller.py +40 -0
  40. smartbox-3.0.0/tests/test_retry.py +24 -0
  41. smartbox-3.0.0/tests/test_values.py +255 -0
  42. smartbox-3.0.0/tests/test_writes.py +790 -0
  43. smartbox-3.0.0/tests/test_ws_user_transport.py +1231 -0
  44. smartbox-3.0.0/tests/utils.py +54 -0
  45. smartbox-2.7.0/.env.example +0 -16
  46. smartbox-2.7.0/.github/FUNDING.yml +0 -3
  47. smartbox-2.7.0/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
  48. smartbox-2.7.0/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  49. smartbox-2.7.0/.github/ISSUE_TEMPLATE/new-reseller.md +0 -19
  50. smartbox-2.7.0/.github/dependabot.yml +0 -19
  51. smartbox-2.7.0/.github/workflows/publish-to-pypi.yml +0 -31
  52. smartbox-2.7.0/.github/workflows/python-package.yml +0 -88
  53. smartbox-2.7.0/.pre-commit-config.yaml +0 -29
  54. smartbox-2.7.0/.vscode/settings.json +0 -12
  55. smartbox-2.7.0/CODEOWNERS +0 -5
  56. smartbox-2.7.0/PKG-INFO +0 -254
  57. smartbox-2.7.0/README.md +0 -234
  58. smartbox-2.7.0/ajtudela-pr-64-audit.md +0 -497
  59. smartbox-2.7.0/api-notes.md +0 -861
  60. smartbox-2.7.0/codecov.yml +0 -8
  61. smartbox-2.7.0/src/smartbox/__init__.py +0 -93
  62. smartbox-2.7.0/src/smartbox/cmd.py +0 -663
  63. smartbox-2.7.0/src/smartbox/error.py +0 -54
  64. smartbox-2.7.0/src/smartbox/models.py +0 -325
  65. smartbox-2.7.0/src/smartbox/retry.py +0 -78
  66. smartbox-2.7.0/src/smartbox/session.py +0 -1872
  67. smartbox-2.7.0/src/smartbox/socket.py +0 -509
  68. smartbox-2.7.0/src/smartbox/update_manager.py +0 -774
  69. smartbox-2.7.0/src/smartbox/ws_user.py +0 -758
  70. smartbox-2.7.0/tests/common.py +0 -28
  71. smartbox-2.7.0/tests/conftest.py +0 -142
  72. smartbox-2.7.0/tests/test_cmd.py +0 -706
  73. smartbox-2.7.0/tests/test_live_payloads.py +0 -133
  74. smartbox-2.7.0/tests/test_models.py +0 -334
  75. smartbox-2.7.0/tests/test_reseller.py +0 -65
  76. smartbox-2.7.0/tests/test_session.py +0 -2776
  77. smartbox-2.7.0/tests/test_session_reliability.py +0 -552
  78. smartbox-2.7.0/tests/test_socket.py +0 -673
  79. smartbox-2.7.0/tests/test_update_manager.py +0 -974
  80. smartbox-2.7.0/tests/test_ws_user.py +0 -887
  81. smartbox-2.7.0/tools/api_functional_tests.py +0 -233
  82. smartbox-2.7.0/tools/away_probe.py +0 -109
  83. smartbox-2.7.0/tools/capture_prog.py +0 -84
  84. smartbox-2.7.0/tools/live_check.py +0 -137
  85. smartbox-2.7.0/tools/probe_extra_options.py +0 -145
  86. smartbox-2.7.0/tools/probe_modified_auto.py +0 -214
  87. smartbox-2.7.0/tools/probe_settle_window.py +0 -146
  88. smartbox-2.7.0/tools/probe_ws_user.py +0 -491
  89. smartbox-2.7.0/tools/prog_functional_tests.py +0 -143
  90. smartbox-2.7.0/tools/watch_status.py +0 -123
  91. smartbox-2.7.0/uv.lock +0 -1424
  92. smartbox-2.7.0/webapi-spec.md +0 -186
  93. {smartbox-2.7.0 → smartbox-3.0.0}/.gitignore +0 -0
  94. {smartbox-2.7.0 → smartbox-3.0.0}/LICENSE +0 -0
  95. {smartbox-2.7.0 → smartbox-3.0.0}/src/smartbox/py.typed +0 -0
  96. {smartbox-2.7.0 → smartbox-3.0.0}/tests/__init__.py +0 -0
  97. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/acm/1/samples.json +0 -0
  98. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/acm/1/setup.json +0 -0
  99. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/acm/1/status.json +0 -0
  100. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/acm/1/version.json +0 -0
  101. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/connected.json +0 -0
  102. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/htr/0/samples.json +0 -0
  103. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/htr/0/setup.json +0 -0
  104. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/htr/0/status.json +0 -0
  105. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/htr/0/version.json +0 -0
  106. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/htr_system/power_limit.json +0 -0
  107. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/mgr/away_status.json +0 -0
  108. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/mgr/nodes.json +0 -0
  109. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/pmo/3/samples.json +0 -0
  110. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/pmo/3/setup.json +0 -0
  111. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/pmo/3/status.json +0 -0
  112. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device1/pmo/3/version.json +0 -0
  113. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/connected.json +0 -0
  114. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/0/samples.json +0 -0
  115. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/0/setup.json +0 -0
  116. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/0/status.json +0 -0
  117. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/0/version.json +0 -0
  118. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/1/samples.json +0 -0
  119. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/1/setup.json +0 -0
  120. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/1/status.json +0 -0
  121. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/1/version.json +0 -0
  122. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/2/samples.json +0 -0
  123. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/2/setup.json +0 -0
  124. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/2/status.json +0 -0
  125. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/2/version.json +0 -0
  126. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/3/samples.json +0 -0
  127. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/3/setup.json +0 -0
  128. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/3/status.json +0 -0
  129. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/3/version.json +0 -0
  130. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/4/samples.json +0 -0
  131. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/4/setup.json +0 -0
  132. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/4/status.json +0 -0
  133. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/4/version.json +0 -0
  134. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/5/samples.json +0 -0
  135. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/5/setup.json +0 -0
  136. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/5/status.json +0 -0
  137. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_mod/5/version.json +0 -0
  138. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/htr_system/power_limit.json +0 -0
  139. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/mgr/away_status.json +0 -0
  140. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs/device2/mgr/nodes.json +0 -0
  141. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/devs.json +0 -0
  142. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/grouped_devs.json +0 -0
  143. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/groups/test_home/guest_users.json +0 -0
  144. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_prog_addr2.json +0 -0
  145. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_prog_addr3.json +0 -0
  146. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_prog_addr4.json +0 -0
  147. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_prog_addr5.json +0 -0
  148. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_prog_addr6.json +0 -0
  149. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_setup_addr2.json +0 -0
  150. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_setup_addr3.json +0 -0
  151. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_setup_addr4.json +0 -0
  152. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_setup_addr5.json +0 -0
  153. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_setup_addr6.json +0 -0
  154. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_setup_no_boost.json +0 -0
  155. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/htr_status_boost_off.json +0 -0
  156. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/socket_update_status_frame.json +0 -0
  157. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/socket_update_sync_lost_frame.json +0 -0
  158. {smartbox-2.7.0 → smartbox-3.0.0}/tests/fixtures/live/socket_update_version_frame.json +0 -0
  159. {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
@@ -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.
@@ -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 = "2.7.0"
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.urls]
29
- Homepage = "https://github.com/ajtudela/smartbox"
30
- Issues = "https://github.com/ajtudela/smartbox/issues"
27
+ [project.optional-dependencies]
28
+ cli = ["asyncclick"]
31
29
 
32
30
  [project.scripts]
33
- smartbox = "smartbox.cmd:cli"
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
- "pre-commit",
43
- "freezegun",
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
- "time-machine",
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 = 80
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/cmd.py" = ["T201", "ANN001"]
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"]