smartbox 2.5.0__tar.gz → 2.5.2__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 (85) hide show
  1. {smartbox-2.5.0 → smartbox-2.5.2}/.github/workflows/publish-to-pypi.yml +1 -1
  2. {smartbox-2.5.0 → smartbox-2.5.2}/.github/workflows/python-package.yml +1 -1
  3. {smartbox-2.5.0 → smartbox-2.5.2}/.gitignore +2 -2
  4. {smartbox-2.5.0 → smartbox-2.5.2}/PKG-INFO +2 -2
  5. {smartbox-2.5.0 → smartbox-2.5.2}/pyproject.toml +2 -2
  6. {smartbox-2.5.0 → smartbox-2.5.2}/src/smartbox/session.py +20 -0
  7. smartbox-2.5.2/tests/fixtures/devs/device1/acm/1/version.json +6 -0
  8. smartbox-2.5.2/tests/fixtures/devs/device1/htr/0/version.json +6 -0
  9. smartbox-2.5.2/tests/fixtures/devs/device1/pmo/3/version.json +6 -0
  10. smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/0/version.json +6 -0
  11. smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/1/version.json +6 -0
  12. smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/2/version.json +6 -0
  13. smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/3/version.json +6 -0
  14. smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/4/version.json +6 -0
  15. smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/5/version.json +6 -0
  16. {smartbox-2.5.0 → smartbox-2.5.2}/tests/test_session.py +46 -2
  17. smartbox-2.5.2/uv.lock +1155 -0
  18. smartbox-2.5.0/uv.lock +0 -1065
  19. {smartbox-2.5.0 → smartbox-2.5.2}/.github/FUNDING.yml +0 -0
  20. {smartbox-2.5.0 → smartbox-2.5.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  21. {smartbox-2.5.0 → smartbox-2.5.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  22. {smartbox-2.5.0 → smartbox-2.5.2}/.github/ISSUE_TEMPLATE/new-reseller.md +0 -0
  23. {smartbox-2.5.0 → smartbox-2.5.2}/.github/dependabot.yml +0 -0
  24. {smartbox-2.5.0 → smartbox-2.5.2}/.pre-commit-config.yaml +0 -0
  25. {smartbox-2.5.0 → smartbox-2.5.2}/.vscode/settings.json +0 -0
  26. {smartbox-2.5.0 → smartbox-2.5.2}/CHANGELOG.md +0 -0
  27. {smartbox-2.5.0 → smartbox-2.5.2}/CODEOWNERS +0 -0
  28. {smartbox-2.5.0 → smartbox-2.5.2}/LICENSE +0 -0
  29. {smartbox-2.5.0 → smartbox-2.5.2}/README.md +0 -0
  30. {smartbox-2.5.0 → smartbox-2.5.2}/api-notes.md +0 -0
  31. {smartbox-2.5.0 → smartbox-2.5.2}/codecov.yml +0 -0
  32. {smartbox-2.5.0 → smartbox-2.5.2}/src/smartbox/__init__.py +0 -0
  33. {smartbox-2.5.0 → smartbox-2.5.2}/src/smartbox/cmd.py +0 -0
  34. {smartbox-2.5.0 → smartbox-2.5.2}/src/smartbox/error.py +0 -0
  35. {smartbox-2.5.0 → smartbox-2.5.2}/src/smartbox/models.py +0 -0
  36. {smartbox-2.5.0 → smartbox-2.5.2}/src/smartbox/py.typed +0 -0
  37. {smartbox-2.5.0 → smartbox-2.5.2}/src/smartbox/reseller.py +0 -0
  38. {smartbox-2.5.0 → smartbox-2.5.2}/src/smartbox/socket.py +0 -0
  39. {smartbox-2.5.0 → smartbox-2.5.2}/src/smartbox/update_manager.py +0 -0
  40. {smartbox-2.5.0 → smartbox-2.5.2}/tests/__init__.py +0 -0
  41. {smartbox-2.5.0 → smartbox-2.5.2}/tests/common.py +0 -0
  42. {smartbox-2.5.0 → smartbox-2.5.2}/tests/conftest.py +0 -0
  43. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device1/acm/1/samples.json +0 -0
  44. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device1/acm/1/setup.json +0 -0
  45. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device1/acm/1/status.json +0 -0
  46. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device1/connected.json +0 -0
  47. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device1/htr/0/samples.json +0 -0
  48. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device1/htr/0/setup.json +0 -0
  49. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device1/htr/0/status.json +0 -0
  50. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device1/htr_system/power_limit.json +0 -0
  51. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device1/mgr/away_status.json +0 -0
  52. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device1/mgr/nodes.json +0 -0
  53. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device1/pmo/3/samples.json +0 -0
  54. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device1/pmo/3/setup.json +0 -0
  55. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device1/pmo/3/status.json +0 -0
  56. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/connected.json +0 -0
  57. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/0/samples.json +0 -0
  58. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/0/setup.json +0 -0
  59. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/0/status.json +0 -0
  60. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/1/samples.json +0 -0
  61. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/1/setup.json +0 -0
  62. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/1/status.json +0 -0
  63. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/2/samples.json +0 -0
  64. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/2/setup.json +0 -0
  65. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/2/status.json +0 -0
  66. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/3/samples.json +0 -0
  67. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/3/setup.json +0 -0
  68. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/3/status.json +0 -0
  69. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/4/samples.json +0 -0
  70. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/4/setup.json +0 -0
  71. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/4/status.json +0 -0
  72. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/5/samples.json +0 -0
  73. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/5/setup.json +0 -0
  74. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_mod/5/status.json +0 -0
  75. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/htr_system/power_limit.json +0 -0
  76. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/mgr/away_status.json +0 -0
  77. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs/device2/mgr/nodes.json +0 -0
  78. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/devs.json +0 -0
  79. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/grouped_devs.json +0 -0
  80. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/groups/test_home/guest_users.json +0 -0
  81. {smartbox-2.5.0 → smartbox-2.5.2}/tests/fixtures/test_path.json +0 -0
  82. {smartbox-2.5.0 → smartbox-2.5.2}/tests/test_cmd.py +0 -0
  83. {smartbox-2.5.0 → smartbox-2.5.2}/tests/test_models.py +0 -0
  84. {smartbox-2.5.0 → smartbox-2.5.2}/tests/test_reseller.py +0 -0
  85. {smartbox-2.5.0 → smartbox-2.5.2}/tests/test_update_manager.py +0 -0
@@ -28,4 +28,4 @@ jobs:
28
28
  - name: Build a binary wheel and a source tarball
29
29
  run: uv build
30
30
  - name: Publish 📦 to PyPI
31
- uses: pypa/gh-action-pypi-publish@release/v1.13
31
+ uses: pypa/gh-action-pypi-publish@release/v1.14
@@ -77,7 +77,7 @@ jobs:
77
77
  uv sync --all-extras --dev
78
78
  uv run tox -e py
79
79
  - name: "Upload coverage to Codecov"
80
- uses: codecov/codecov-action@v5.5.2
80
+ uses: codecov/codecov-action@v6.0.0
81
81
  with:
82
82
  token: ${{ secrets.CODECOV_TOKEN }}
83
83
  fail_ci_if_error: true
@@ -48,7 +48,7 @@ htmlcov/
48
48
  .nox/
49
49
  .coverage
50
50
  .coverage.*
51
- .cache
51
+ .*cache*
52
52
  nosetests.xml
53
53
  coverage.xml
54
54
  *.cover
@@ -72,4 +72,4 @@ venv.bak/
72
72
  junit.xml
73
73
  .DS_Store
74
74
 
75
- *.code-workspace
75
+ *.code-workspace
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: smartbox
3
- Version: 2.5.0
3
+ Version: 2.5.2
4
4
  Summary: Python API to control heating 'smart boxes'
5
5
  Project-URL: Homepage, https://github.com/ajtudela/smartbox
6
6
  Project-URL: Issues, https://github.com/ajtudela/smartbox/issues
@@ -14,7 +14,7 @@ Requires-Python: >=3.14.2
14
14
  Requires-Dist: aiohttp
15
15
  Requires-Dist: asyncclick
16
16
  Requires-Dist: jq
17
- Requires-Dist: pydantic==2.12.2
17
+ Requires-Dist: pydantic
18
18
  Requires-Dist: python-socketio
19
19
  Requires-Dist: requests
20
20
  Requires-Dist: websocket-client
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "smartbox"
3
- version = "2.5.0"
3
+ version = "2.5.2"
4
4
  requires-python = ">=3.14.2"
5
5
  authors = [
6
6
  { name="Alberto Tudela", email="ajtudela@gmail.com" },
@@ -21,7 +21,7 @@ dependencies = [
21
21
  "aiohttp",
22
22
  "asyncclick",
23
23
  "jq",
24
- "pydantic==2.12.2",
24
+ "pydantic",
25
25
  "python-socketio",
26
26
  "requests",
27
27
  "websocket-client",
@@ -27,6 +27,7 @@ from smartbox.models import (
27
27
  Nodes,
28
28
  NodeSetup,
29
29
  NodeStatus,
30
+ NodeVersion,
30
31
  Samples,
31
32
  SmartboxNodeType,
32
33
  Token,
@@ -539,6 +540,25 @@ class AsyncSmartboxSession(AsyncSession):
539
540
  path=f"devs/{device_id}/{_node.type}/{_node.addr}/setup",
540
541
  )
541
542
 
543
+ async def get_node_version(
544
+ self,
545
+ device_id: str,
546
+ node: dict[str, Any],
547
+ ) -> dict[str, Any] | NodeVersion:
548
+ """Get a node setup."""
549
+ _node: Node = Node.model_validate(node)
550
+ response = await self._api_request(
551
+ f"devs/{device_id}/{_node.type}/{_node.addr}/version",
552
+ )
553
+ _LOGGER.debug("(%s) Version config data %s", _node.type, response)
554
+ if self.raw_response is True:
555
+ return response
556
+ try:
557
+ return NodeVersion.model_validate(response)
558
+ except ValidationError:
559
+ _LOGGER.exception("Version config validation error %s", response)
560
+ raise
561
+
542
562
 
543
563
  class Session:
544
564
  """For retro compatibility, this class is a sync which called the async."""
@@ -0,0 +1,6 @@
1
+ {
2
+ "hw_version": "1.1",
3
+ "fw_version": "2.3.1",
4
+ "uid": "AABBCCDDEEFF0022",
5
+ "pid": "ACM-001"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "hw_version": "1.0",
3
+ "fw_version": "2.3.1",
4
+ "uid": "AABBCCDDEEFF0011",
5
+ "pid": "HTR-001"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "hw_version": "1.0",
3
+ "fw_version": "2.1.0",
4
+ "uid": "003E003F0D47373436363733",
5
+ "pid": "PMO-001"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "hw_version": "2.0",
3
+ "fw_version": "3.1.0",
4
+ "uid": "CCDDEE001122AABB",
5
+ "pid": "HTR_MOD-001"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "hw_version": "2.0",
3
+ "fw_version": "3.1.0",
4
+ "uid": "CCDDEE001122AABC",
5
+ "pid": "HTR_MOD-001"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "hw_version": "2.0",
3
+ "fw_version": "3.1.0",
4
+ "uid": "CCDDEE001122AABD",
5
+ "pid": "HTR_MOD-001"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "hw_version": "2.0",
3
+ "fw_version": "3.1.0",
4
+ "uid": "CCDDEE001122AABE",
5
+ "pid": "HTR_MOD-001"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "hw_version": "2.0",
3
+ "fw_version": "3.1.0",
4
+ "uid": "CCDDEE001122AABF",
5
+ "pid": "HTR_MOD-001"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "hw_version": "2.0",
3
+ "fw_version": "3.1.0",
4
+ "uid": "CCDDEE001122AAC0",
5
+ "pid": "HTR_MOD-001"
6
+ }
@@ -192,8 +192,8 @@ async def test_get_node_samples_default_times(async_smartbox_session):
192
192
  called_start = int(match.group(1))
193
193
  called_end = int(match.group(2))
194
194
 
195
- assert abs(called_start - (now - 3600)) <= 5
196
- assert abs(called_end - (now + 3600)) <= 5
195
+ assert abs(called_start - (now - 3600)) <= 20
196
+ assert abs(called_end - (now + 3600)) <= 20
197
197
 
198
198
 
199
199
  @pytest.mark.asyncio
@@ -1383,6 +1383,50 @@ async def test_get_node_setup(async_smartbox_session, caplog):
1383
1383
  async_smartbox_session.raw_response = True
1384
1384
 
1385
1385
 
1386
+ @pytest.mark.asyncio
1387
+ async def test_get_node_version(async_smartbox_session, caplog):
1388
+ for mock_device in await async_smartbox_session.get_devices():
1389
+ mock_device_id = mock_device["dev_id"]
1390
+ for mock_node in await async_smartbox_session.get_nodes(mock_device_id):
1391
+ with patch.object(
1392
+ async_smartbox_session,
1393
+ "_api_request",
1394
+ new_callable=AsyncMock,
1395
+ ) as mock_api_request:
1396
+ url = f"devs/{mock_device_id}/{mock_node['type']}/{mock_node['addr']}/version"
1397
+ mock_api_request.return_value = await fake_get_request(
1398
+ mock_api_request,
1399
+ url,
1400
+ )
1401
+
1402
+ async_smartbox_session.raw_response = True
1403
+ version = await async_smartbox_session.get_node_version(
1404
+ device_id=mock_device_id,
1405
+ node=mock_node,
1406
+ )
1407
+ assert version == mock_api_request.return_value
1408
+ mock_api_request.assert_called_with(url)
1409
+
1410
+ async_smartbox_session.raw_response = False
1411
+ version_model = await async_smartbox_session.get_node_version(
1412
+ device_id=mock_device_id,
1413
+ node=mock_node,
1414
+ )
1415
+ assert version_model.fw_version == version["fw_version"]
1416
+ assert version_model.hw_version == version["hw_version"]
1417
+ assert version_model.uid == version["uid"]
1418
+ assert version_model.pid == version["pid"]
1419
+
1420
+ with pytest.raises(ValidationError):
1421
+ mock_api_request.return_value = {"fw_version": "1.0.0"}
1422
+ await async_smartbox_session.get_node_version(
1423
+ device_id=mock_device_id,
1424
+ node=mock_node,
1425
+ )
1426
+ assert "Version config validation error" in caplog.text
1427
+ async_smartbox_session.raw_response = True
1428
+
1429
+
1386
1430
  @pytest.mark.asyncio
1387
1431
  async def test_get_homes(async_smartbox_session):
1388
1432
  with patch.object(