PyPlumIO 0.6.7__tar.gz → 0.6.8__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 (151) hide show
  1. {pyplumio-0.6.7 → pyplumio-0.6.8}/.pre-commit-config.yaml +2 -2
  2. {pyplumio-0.6.7 → pyplumio-0.6.8}/PKG-INFO +7 -7
  3. {pyplumio-0.6.7 → pyplumio-0.6.8}/PyPlumIO.egg-info/PKG-INFO +7 -7
  4. {pyplumio-0.6.7 → pyplumio-0.6.8}/PyPlumIO.egg-info/requires.txt +6 -6
  5. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/_version.py +3 -3
  6. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/connection.py +19 -13
  7. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyproject.toml +6 -6
  8. pyplumio-0.6.8/requirements.txt +1 -0
  9. {pyplumio-0.6.7 → pyplumio-0.6.8}/requirements_test.txt +5 -5
  10. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/test_connection.py +29 -36
  11. pyplumio-0.6.7/requirements.txt +0 -1
  12. {pyplumio-0.6.7 → pyplumio-0.6.8}/.gitattributes +0 -0
  13. {pyplumio-0.6.7 → pyplumio-0.6.8}/.github/CODE_OF_CONDUCT.md +0 -0
  14. {pyplumio-0.6.7 → pyplumio-0.6.8}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  15. {pyplumio-0.6.7 → pyplumio-0.6.8}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  16. {pyplumio-0.6.7 → pyplumio-0.6.8}/.github/dependabot.yml +0 -0
  17. {pyplumio-0.6.7 → pyplumio-0.6.8}/.github/workflows/ci.yml +0 -0
  18. {pyplumio-0.6.7 → pyplumio-0.6.8}/.github/workflows/codeql.yml +0 -0
  19. {pyplumio-0.6.7 → pyplumio-0.6.8}/.github/workflows/deploy.yml +0 -0
  20. {pyplumio-0.6.7 → pyplumio-0.6.8}/.github/workflows/documentation.yml +0 -0
  21. {pyplumio-0.6.7 → pyplumio-0.6.8}/.gitignore +0 -0
  22. {pyplumio-0.6.7 → pyplumio-0.6.8}/.qlty/qlty.toml +0 -0
  23. {pyplumio-0.6.7 → pyplumio-0.6.8}/.vscode/settings.json +0 -0
  24. {pyplumio-0.6.7 → pyplumio-0.6.8}/LICENSE +0 -0
  25. {pyplumio-0.6.7 → pyplumio-0.6.8}/MANIFEST.in +0 -0
  26. {pyplumio-0.6.7 → pyplumio-0.6.8}/PyPlumIO.egg-info/SOURCES.txt +0 -0
  27. {pyplumio-0.6.7 → pyplumio-0.6.8}/PyPlumIO.egg-info/dependency_links.txt +0 -0
  28. {pyplumio-0.6.7 → pyplumio-0.6.8}/PyPlumIO.egg-info/top_level.txt +0 -0
  29. {pyplumio-0.6.7 → pyplumio-0.6.8}/README.md +0 -0
  30. {pyplumio-0.6.7 → pyplumio-0.6.8}/docs/Makefile +0 -0
  31. {pyplumio-0.6.7 → pyplumio-0.6.8}/docs/make.bat +0 -0
  32. {pyplumio-0.6.7 → pyplumio-0.6.8}/docs/source/callbacks.rst +0 -0
  33. {pyplumio-0.6.7 → pyplumio-0.6.8}/docs/source/conf.py +0 -0
  34. {pyplumio-0.6.7 → pyplumio-0.6.8}/docs/source/connecting.rst +0 -0
  35. {pyplumio-0.6.7 → pyplumio-0.6.8}/docs/source/frames.rst +0 -0
  36. {pyplumio-0.6.7 → pyplumio-0.6.8}/docs/source/index.rst +0 -0
  37. {pyplumio-0.6.7 → pyplumio-0.6.8}/docs/source/mixers_thermostats.rst +0 -0
  38. {pyplumio-0.6.7 → pyplumio-0.6.8}/docs/source/protocol.rst +0 -0
  39. {pyplumio-0.6.7 → pyplumio-0.6.8}/docs/source/reading.rst +0 -0
  40. {pyplumio-0.6.7 → pyplumio-0.6.8}/docs/source/schedules.rst +0 -0
  41. {pyplumio-0.6.7 → pyplumio-0.6.8}/docs/source/writing.rst +0 -0
  42. {pyplumio-0.6.7 → pyplumio-0.6.8}/images/ecomax.png +0 -0
  43. {pyplumio-0.6.7 → pyplumio-0.6.8}/images/rs485.png +0 -0
  44. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/__init__.py +0 -0
  45. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/__main__.py +0 -0
  46. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/const.py +0 -0
  47. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/data_types.py +0 -0
  48. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/devices/__init__.py +0 -0
  49. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/devices/ecomax.py +0 -0
  50. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/devices/ecoster.py +0 -0
  51. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/devices/mixer.py +0 -0
  52. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/devices/thermostat.py +0 -0
  53. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/exceptions.py +0 -0
  54. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/filters.py +0 -0
  55. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/frames/__init__.py +0 -0
  56. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/frames/messages.py +0 -0
  57. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/frames/requests.py +0 -0
  58. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/frames/responses.py +0 -0
  59. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/helpers/__init__.py +0 -0
  60. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/helpers/async_cache.py +0 -0
  61. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/helpers/event_manager.py +0 -0
  62. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/helpers/task_manager.py +0 -0
  63. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/parameters/__init__.py +0 -0
  64. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/parameters/custom/__init__.py +0 -0
  65. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/parameters/custom/ecomax_860d3_hb.py +0 -0
  66. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/parameters/ecomax.py +0 -0
  67. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/parameters/mixer.py +0 -0
  68. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/parameters/thermostat.py +0 -0
  69. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/protocol.py +0 -0
  70. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/py.typed +0 -0
  71. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/stream.py +0 -0
  72. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/structures/__init__.py +0 -0
  73. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/structures/alerts.py +0 -0
  74. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/structures/ecomax_parameters.py +0 -0
  75. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/structures/frame_versions.py +0 -0
  76. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/structures/mixer_parameters.py +0 -0
  77. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/structures/network_info.py +0 -0
  78. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/structures/product_info.py +0 -0
  79. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/structures/program_version.py +0 -0
  80. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/structures/regulator_data.py +0 -0
  81. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/structures/regulator_data_schema.py +0 -0
  82. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/structures/schedules.py +0 -0
  83. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/structures/sensor_data.py +0 -0
  84. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/structures/thermostat_parameters.py +0 -0
  85. {pyplumio-0.6.7 → pyplumio-0.6.8}/pyplumio/utils.py +0 -0
  86. {pyplumio-0.6.7 → pyplumio-0.6.8}/requirements_docs.txt +0 -0
  87. {pyplumio-0.6.7 → pyplumio-0.6.8}/setup.cfg +0 -0
  88. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/__init__.py +0 -0
  89. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/conftest.py +0 -0
  90. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/devices/__init__.py +0 -0
  91. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/devices/test_ecomax.py +0 -0
  92. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/devices/test_ecoster.py +0 -0
  93. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/devices/test_init.py +0 -0
  94. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/devices/test_mixer.py +0 -0
  95. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/devices/test_thermostat.py +0 -0
  96. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/frames/test_init.py +0 -0
  97. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/frames/test_messages.py +0 -0
  98. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/frames/test_requests.py +0 -0
  99. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/frames/test_responses.py +0 -0
  100. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/helpers/__init__.py +0 -0
  101. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/helpers/test_async_cache.py +0 -0
  102. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/helpers/test_event_manager.py +0 -0
  103. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/helpers/test_task_manager.py +0 -0
  104. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/helpers/test_uid.py +0 -0
  105. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/parameters/__init__.py +0 -0
  106. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/parameters/custom/__init__.py +0 -0
  107. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/parameters/custom/test_ecomax_860d3_hb.py +0 -0
  108. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/parameters/custom/test_init.py +0 -0
  109. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/parameters/test_ecomax.py +0 -0
  110. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/parameters/test_init.py +0 -0
  111. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/parameters/test_mixers.py +0 -0
  112. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/parameters/test_thermostats.py +0 -0
  113. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/ruff.toml +0 -0
  114. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/structures/__init__.py +0 -0
  115. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/structures/test_alerts.py +0 -0
  116. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/structures/test_ecomax_parameters.py +0 -0
  117. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/structures/test_frame_versions.py +0 -0
  118. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/structures/test_mixer_parameters.py +0 -0
  119. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/structures/test_product_info.py +0 -0
  120. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/structures/test_schedules.py +0 -0
  121. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/test_data_types.py +0 -0
  122. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/test_filters.py +0 -0
  123. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/test_init.py +0 -0
  124. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/test_main.py +0 -0
  125. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/test_protocol.py +0 -0
  126. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/test_stream.py +0 -0
  127. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/test_utils.py +0 -0
  128. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/messages/regulator_data.json +0 -0
  129. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/messages/sensor_data.json +0 -0
  130. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/parameters/ecomax_860d3_hb.json +0 -0
  131. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/requests/alerts.json +0 -0
  132. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/requests/ecomax_control.json +0 -0
  133. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/requests/ecomax_parameters.json +0 -0
  134. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/requests/mixer_parameters.json +0 -0
  135. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/requests/set_ecomax_parameter.json +0 -0
  136. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/requests/set_mixer_parameter.json +0 -0
  137. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/requests/set_schedule.json +0 -0
  138. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/requests/set_thermostat_parameter.json +0 -0
  139. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/requests/thermostat_parameters.json +0 -0
  140. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/responses/alerts.json +0 -0
  141. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/responses/device_available.json +0 -0
  142. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/responses/ecomax_parameters.json +0 -0
  143. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/responses/mixer_parameters.json +0 -0
  144. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/responses/password.json +0 -0
  145. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/responses/program_version.json +0 -0
  146. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/responses/regulator_data_schema.json +0 -0
  147. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/responses/schedules.json +0 -0
  148. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/responses/thermostat_parameters.json +0 -0
  149. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/responses/uid.json +0 -0
  150. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/unknown/unknown_ecomax_parameter.json +0 -0
  151. {pyplumio-0.6.7 → pyplumio-0.6.8}/tests/testdata/unknown/unknown_mixer_parameter.json +0 -0
@@ -3,7 +3,7 @@
3
3
  # See https://pre-commit.com/hooks.html for more hooks
4
4
  repos:
5
5
  - repo: https://github.com/astral-sh/ruff-pre-commit
6
- rev: v0.14.4
6
+ rev: v0.14.10
7
7
  hooks:
8
8
  - id: ruff
9
9
  args:
@@ -13,6 +13,6 @@ repos:
13
13
  hooks:
14
14
  - id: codespell
15
15
  - repo: https://github.com/pre-commit/mirrors-mypy
16
- rev: v1.18.2
16
+ rev: v1.19.1
17
17
  hooks:
18
18
  - id: mypy
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPlumIO
3
- Version: 0.6.7
3
+ Version: 0.6.8
4
4
  Summary: PyPlumIO is a native ecoNET library for Plum ecoMAX controllers.
5
5
  Author-email: Denis Paavilainen <denpa@denpa.pro>
6
6
  License: MIT License
@@ -23,17 +23,17 @@ Classifier: Topic :: Home Automation
23
23
  Requires-Python: >=3.10
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE
26
- Requires-Dist: pyserial-asyncio==0.6
26
+ Requires-Dist: pyserial-asyncio-fast==0.16
27
27
  Provides-Extra: test
28
28
  Requires-Dist: codespell==2.4.1; extra == "test"
29
- Requires-Dist: coverage==7.12.0; extra == "test"
29
+ Requires-Dist: coverage==7.13.0; extra == "test"
30
30
  Requires-Dist: freezegun==1.5.5; extra == "test"
31
- Requires-Dist: mypy==1.19.0; extra == "test"
31
+ Requires-Dist: mypy==1.19.1; extra == "test"
32
32
  Requires-Dist: numpy<3.0.0,>=2.0.0; extra == "test"
33
33
  Requires-Dist: pyserial-asyncio-fast==0.16; extra == "test"
34
- Requires-Dist: pytest==9.0.1; extra == "test"
34
+ Requires-Dist: pytest==9.0.2; extra == "test"
35
35
  Requires-Dist: pytest-asyncio==1.3.0; extra == "test"
36
- Requires-Dist: ruff==0.14.7; extra == "test"
36
+ Requires-Dist: ruff==0.14.10; extra == "test"
37
37
  Requires-Dist: tox==4.32.0; extra == "test"
38
38
  Requires-Dist: types-pyserial==3.5.0.20251001; extra == "test"
39
39
  Provides-Extra: docs
@@ -42,7 +42,7 @@ Requires-Dist: sphinx_rtd_theme==3.0.2; extra == "docs"
42
42
  Requires-Dist: readthedocs-sphinx-search==0.3.2; extra == "docs"
43
43
  Provides-Extra: dev
44
44
  Requires-Dist: pyplumio[docs,test]; extra == "dev"
45
- Requires-Dist: pre-commit==4.5.0; extra == "dev"
45
+ Requires-Dist: pre-commit==4.5.1; extra == "dev"
46
46
  Requires-Dist: tomli==2.3.0; extra == "dev"
47
47
  Dynamic: license-file
48
48
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPlumIO
3
- Version: 0.6.7
3
+ Version: 0.6.8
4
4
  Summary: PyPlumIO is a native ecoNET library for Plum ecoMAX controllers.
5
5
  Author-email: Denis Paavilainen <denpa@denpa.pro>
6
6
  License: MIT License
@@ -23,17 +23,17 @@ Classifier: Topic :: Home Automation
23
23
  Requires-Python: >=3.10
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE
26
- Requires-Dist: pyserial-asyncio==0.6
26
+ Requires-Dist: pyserial-asyncio-fast==0.16
27
27
  Provides-Extra: test
28
28
  Requires-Dist: codespell==2.4.1; extra == "test"
29
- Requires-Dist: coverage==7.12.0; extra == "test"
29
+ Requires-Dist: coverage==7.13.0; extra == "test"
30
30
  Requires-Dist: freezegun==1.5.5; extra == "test"
31
- Requires-Dist: mypy==1.19.0; extra == "test"
31
+ Requires-Dist: mypy==1.19.1; extra == "test"
32
32
  Requires-Dist: numpy<3.0.0,>=2.0.0; extra == "test"
33
33
  Requires-Dist: pyserial-asyncio-fast==0.16; extra == "test"
34
- Requires-Dist: pytest==9.0.1; extra == "test"
34
+ Requires-Dist: pytest==9.0.2; extra == "test"
35
35
  Requires-Dist: pytest-asyncio==1.3.0; extra == "test"
36
- Requires-Dist: ruff==0.14.7; extra == "test"
36
+ Requires-Dist: ruff==0.14.10; extra == "test"
37
37
  Requires-Dist: tox==4.32.0; extra == "test"
38
38
  Requires-Dist: types-pyserial==3.5.0.20251001; extra == "test"
39
39
  Provides-Extra: docs
@@ -42,7 +42,7 @@ Requires-Dist: sphinx_rtd_theme==3.0.2; extra == "docs"
42
42
  Requires-Dist: readthedocs-sphinx-search==0.3.2; extra == "docs"
43
43
  Provides-Extra: dev
44
44
  Requires-Dist: pyplumio[docs,test]; extra == "dev"
45
- Requires-Dist: pre-commit==4.5.0; extra == "dev"
45
+ Requires-Dist: pre-commit==4.5.1; extra == "dev"
46
46
  Requires-Dist: tomli==2.3.0; extra == "dev"
47
47
  Dynamic: license-file
48
48
 
@@ -1,8 +1,8 @@
1
- pyserial-asyncio==0.6
1
+ pyserial-asyncio-fast==0.16
2
2
 
3
3
  [dev]
4
4
  pyplumio[docs,test]
5
- pre-commit==4.5.0
5
+ pre-commit==4.5.1
6
6
  tomli==2.3.0
7
7
 
8
8
  [docs]
@@ -12,13 +12,13 @@ readthedocs-sphinx-search==0.3.2
12
12
 
13
13
  [test]
14
14
  codespell==2.4.1
15
- coverage==7.12.0
15
+ coverage==7.13.0
16
16
  freezegun==1.5.5
17
- mypy==1.19.0
17
+ mypy==1.19.1
18
18
  numpy<3.0.0,>=2.0.0
19
19
  pyserial-asyncio-fast==0.16
20
- pytest==9.0.1
20
+ pytest==9.0.2
21
21
  pytest-asyncio==1.3.0
22
- ruff==0.14.7
22
+ ruff==0.14.10
23
23
  tox==4.32.0
24
24
  types-pyserial==3.5.0.20251001
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.6.7'
32
- __version_tuple__ = version_tuple = (0, 6, 7)
31
+ __version__ = version = '0.6.8'
32
+ __version_tuple__ = version_tuple = (0, 6, 8)
33
33
 
34
- __commit_id__ = commit_id = 'g6d0ba3b08'
34
+ __commit_id__ = commit_id = 'gbde57b4a1'
@@ -11,6 +11,7 @@ from types import MappingProxyType
11
11
  from typing import Any, Final
12
12
 
13
13
  from serial import EIGHTBITS, PARITY_NONE, STOPBITS_ONE
14
+ import serial_asyncio_fast
14
15
 
15
16
  from pyplumio.devices import PhysicalDevice
16
17
  from pyplumio.exceptions import ConnectionFailedError
@@ -23,13 +24,6 @@ _LOGGER = logging.getLogger(__name__)
23
24
  TRY_CONNECT_FOR_SECONDS: Final = 5
24
25
  RECONNECT_AFTER_SECONDS: Final = 20
25
26
 
26
- try:
27
- import serial_asyncio_fast as pyserial_asyncio
28
-
29
- _LOGGER.info("Using pyserial-asyncio-fast in place of pyserial-asyncio")
30
- except ImportError:
31
- import serial_asyncio as pyserial_asyncio # type: ignore[no-redef]
32
-
33
27
 
34
28
  class Connection(ABC, TaskManager):
35
29
  """Represents a connection.
@@ -37,11 +31,12 @@ class Connection(ABC, TaskManager):
37
31
  All specific connection classes MUST be inherited from this class.
38
32
  """
39
33
 
40
- __slots__ = ("_protocol", "_reconnect_on_failure", "_options")
34
+ __slots__ = ("_protocol", "_reconnect_on_failure", "_options", "_retries")
41
35
 
42
36
  _protocol: Protocol
43
37
  _reconnect_on_failure: bool
44
38
  _options: dict[str, Any]
39
+ _retries: int
45
40
 
46
41
  def __init__(
47
42
  self,
@@ -60,6 +55,7 @@ class Connection(ABC, TaskManager):
60
55
  self._reconnect_on_failure = reconnect_on_failure
61
56
  self._protocol = protocol
62
57
  self._options = options
58
+ self._retries = 0
63
59
 
64
60
  async def __aenter__(self) -> Connection:
65
61
  """Provide an entry point for the context manager."""
@@ -86,11 +82,21 @@ class Connection(ABC, TaskManager):
86
82
  """Try to connect and reconnect on failure."""
87
83
  try:
88
84
  await self._connect()
85
+ if self._retries > 0:
86
+ _LOGGER.info(
87
+ "Connection to device restored after %i retries", self._retries
88
+ )
89
+ self._retries = 0
89
90
  except ConnectionFailedError:
90
- _LOGGER.error(
91
- "Can't connect to the device, retrying in %.1f seconds",
92
- RECONNECT_AFTER_SECONDS,
93
- )
91
+ if self._retries == 0:
92
+ _LOGGER.error(
93
+ (
94
+ "Unable to connect to the device. Connection we be retried "
95
+ "automatically every %i seconds in background."
96
+ ),
97
+ RECONNECT_AFTER_SECONDS,
98
+ )
99
+ self._retries += 1
94
100
  await asyncio.sleep(RECONNECT_AFTER_SECONDS)
95
101
  self.create_task(self._reconnect(), name="reconnect_task")
96
102
 
@@ -209,7 +215,7 @@ class SerialConnection(Connection):
209
215
  self,
210
216
  ) -> tuple[asyncio.StreamReader, asyncio.StreamWriter]:
211
217
  """Open the connection and return reader and writer objects."""
212
- return await pyserial_asyncio.open_serial_connection(
218
+ return await serial_asyncio_fast.open_serial_connection(
213
219
  url=self.url,
214
220
  baudrate=self.baudrate,
215
221
  bytesize=EIGHTBITS,
@@ -24,7 +24,7 @@ classifiers = [
24
24
  "Topic :: Home Automation",
25
25
  ]
26
26
  dependencies = [
27
- "pyserial-asyncio==0.6"
27
+ "pyserial-asyncio-fast==0.16"
28
28
  ]
29
29
  dynamic = ["version"]
30
30
 
@@ -36,14 +36,14 @@ dynamic = ["version"]
36
36
  [project.optional-dependencies]
37
37
  test = [
38
38
  "codespell==2.4.1",
39
- "coverage==7.12.0",
39
+ "coverage==7.13.0",
40
40
  "freezegun==1.5.5",
41
- "mypy==1.19.0",
41
+ "mypy==1.19.1",
42
42
  "numpy<3.0.0,>=2.0.0",
43
43
  "pyserial-asyncio-fast==0.16",
44
- "pytest==9.0.1",
44
+ "pytest==9.0.2",
45
45
  "pytest-asyncio==1.3.0",
46
- "ruff==0.14.7",
46
+ "ruff==0.14.10",
47
47
  "tox==4.32.0",
48
48
  "types-pyserial==3.5.0.20251001"
49
49
  ]
@@ -54,7 +54,7 @@ docs = [
54
54
  ]
55
55
  dev = [
56
56
  "pyplumio[test,docs]",
57
- "pre-commit==4.5.0",
57
+ "pre-commit==4.5.1",
58
58
  "tomli==2.3.0"
59
59
  ]
60
60
 
@@ -0,0 +1 @@
1
+ pyserial-asyncio-fast==0.16
@@ -1,13 +1,13 @@
1
1
  codespell==2.4.1
2
- coverage==7.12.0
2
+ coverage==7.13.0
3
3
  freezegun==1.5.5
4
- mypy==1.19.0
4
+ mypy==1.19.1
5
5
  numpy<3.0.0,>=2.0.0
6
- pre-commit==4.5.0
6
+ pre-commit==4.5.1
7
7
  pyserial-asyncio-fast==0.16
8
+ pytest==9.0.2
8
9
  pytest-asyncio==1.3.0
9
- pytest==9.0.1
10
- ruff==0.14.7
10
+ ruff==0.14.10
11
11
  tomli==2.3.0
12
12
  tox==4.32.0
13
13
  types-pyserial==3.5.0.20251001
@@ -3,40 +3,24 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from asyncio import StreamReader, StreamWriter
6
- from importlib import reload
7
6
  import logging
8
- import sys
9
- from typing import Any, Final
7
+ from typing import Final
10
8
  from unittest.mock import AsyncMock, Mock, patch
11
9
 
12
10
  import pytest
13
11
  from serial import EIGHTBITS, PARITY_NONE, STOPBITS_ONE
14
12
 
15
- import pyplumio.connection
16
- from pyplumio.connection import Connection, SerialConnection, TcpConnection
13
+ from pyplumio.connection import (
14
+ RECONNECT_AFTER_SECONDS,
15
+ Connection,
16
+ SerialConnection,
17
+ TcpConnection,
18
+ )
17
19
  from pyplumio.devices.ecomax import EcoMAX
18
20
  from pyplumio.exceptions import ConnectionFailedError
19
21
  from pyplumio.protocol import AsyncProtocol, DummyProtocol, Protocol
20
22
 
21
23
 
22
- @pytest.fixture(name="use_fast", params=(True, False))
23
- def fixture_use_fast(request, monkeypatch, caplog) -> Any:
24
- """Try with and without serial-asyncio-fast package."""
25
- if not request.param:
26
- monkeypatch.setitem(sys.modules, "serial_asyncio_fast", None)
27
-
28
- with caplog.at_level(logging.INFO):
29
- reload(pyplumio.connection)
30
-
31
- message = "Using pyserial-asyncio-fast in place of pyserial-asyncio"
32
- if request.param:
33
- assert message in caplog.text
34
- else:
35
- assert message not in caplog.text
36
-
37
- return request.param
38
-
39
-
40
24
  @pytest.fixture(name="stream_writer")
41
25
  def fixture_stream_writer():
42
26
  """Return a mock of asyncio stream writer."""
@@ -64,12 +48,11 @@ def fixture_asyncio_open_connection(
64
48
 
65
49
  @pytest.fixture(name="serial_asyncio_open_serial_connection")
66
50
  def fixture_serial_asyncio_open_serial_connection(
67
- use_fast, stream_reader: StreamReader, stream_writer: StreamWriter
51
+ stream_reader: StreamReader, stream_writer: StreamWriter
68
52
  ):
69
53
  """Bypass opening serial_asyncio connection."""
70
- module = "serial_asyncio_fast" if use_fast else "serial_asyncio"
71
54
  with patch(
72
- f"{module}.open_serial_connection",
55
+ "serial_asyncio_fast.open_serial_connection",
73
56
  return_value=(stream_reader, stream_writer),
74
57
  ) as mock_connection:
75
58
  yield mock_connection
@@ -115,33 +98,43 @@ class TestConnection:
115
98
  await connection.close()
116
99
  mock_protocol.shutdown.assert_called_once()
117
100
 
118
- @pytest.mark.parametrize(
119
- ("reconnect_on_failure", "expected_log"),
120
- [
121
- (True, "Can't connect to the device"),
122
- (False, None),
123
- ],
101
+ @pytest.mark.parametrize("reconnect_on_failure", [True, False])
102
+ @patch.object(
103
+ DummyConnection,
104
+ "_open_connection",
105
+ side_effect=(OSError, (AsyncMock(), AsyncMock), None),
124
106
  )
125
- @patch.object(DummyConnection, "_open_connection", side_effect=(OSError, None))
107
+ @patch("pyplumio.protocol.AsyncProtocol.connection_established")
126
108
  async def test_reconnect(
127
109
  self,
110
+ mock_connection_established,
128
111
  mock_open_connection,
129
112
  caplog,
130
113
  reconnect_on_failure: bool,
131
- expected_log: str | None,
132
114
  ) -> None:
133
115
  """Test reconnect logic."""
134
116
  connection = DummyConnection(reconnect_on_failure=reconnect_on_failure)
135
117
  if reconnect_on_failure:
136
118
  with caplog.at_level(logging.ERROR):
137
119
  await connection.connect()
120
+ assert "Unable to connect to the device." in caplog.text
121
+ assert (
122
+ f"automatically every {RECONNECT_AFTER_SECONDS} seconds"
123
+ in caplog.text
124
+ )
125
+
126
+ with caplog.at_level(logging.INFO):
127
+ await connection.connect()
128
+ assert "Connection to device restored after 1 retries" in caplog.text
129
+ mock_connection_established.assert_called_once()
130
+
131
+ assert mock_open_connection.await_count == 2
138
132
 
139
- assert expected_log in caplog.text
140
133
  else:
141
134
  with pytest.raises(ConnectionFailedError):
142
135
  await connection.connect()
143
136
 
144
- mock_open_connection.assert_awaited_once()
137
+ mock_open_connection.assert_awaited_once()
145
138
 
146
139
  @patch.object(DummyConnection, "close")
147
140
  @patch.object(DummyConnection, "connect")
@@ -1 +0,0 @@
1
- pyserial-asyncio==0.6
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes