PyPlumIO 0.5.56__tar.gz → 0.6.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 (173) hide show
  1. {pyplumio-0.5.56 → pyplumio-0.6.0}/.github/workflows/ci.yml +1 -1
  2. {pyplumio-0.5.56 → pyplumio-0.6.0}/.pre-commit-config.yaml +2 -2
  3. {pyplumio-0.5.56 → pyplumio-0.6.0}/PKG-INFO +11 -12
  4. {pyplumio-0.5.56 → pyplumio-0.6.0}/PyPlumIO.egg-info/PKG-INFO +11 -12
  5. {pyplumio-0.5.56 → pyplumio-0.6.0}/PyPlumIO.egg-info/requires.txt +5 -7
  6. {pyplumio-0.5.56 → pyplumio-0.6.0}/README.md +4 -2
  7. {pyplumio-0.5.56 → pyplumio-0.6.0}/docs/source/callbacks.rst +18 -26
  8. {pyplumio-0.5.56 → pyplumio-0.6.0}/docs/source/connecting.rst +10 -8
  9. {pyplumio-0.5.56 → pyplumio-0.6.0}/docs/source/mixers_thermostats.rst +21 -25
  10. {pyplumio-0.5.56 → pyplumio-0.6.0}/docs/source/reading.rst +23 -22
  11. {pyplumio-0.5.56 → pyplumio-0.6.0}/docs/source/schedules.rst +21 -21
  12. {pyplumio-0.5.56 → pyplumio-0.6.0}/docs/source/statistics.rst +10 -3
  13. {pyplumio-0.5.56 → pyplumio-0.6.0}/docs/source/writing.rst +17 -19
  14. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/__init__.py +10 -10
  15. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/_version.py +3 -3
  16. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/connection.py +76 -16
  17. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/const.py +1 -3
  18. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/filters.py +4 -5
  19. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/frames/__init__.py +3 -16
  20. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/helpers/async_cache.py +2 -4
  21. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/helpers/event_manager.py +1 -3
  22. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/parameters/__init__.py +8 -17
  23. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/parameters/custom/__init__.py +2 -6
  24. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/parameters/ecomax.py +2 -7
  25. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/parameters/mixer.py +2 -7
  26. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/parameters/thermostat.py +2 -6
  27. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/protocol.py +35 -44
  28. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/__init__.py +1 -3
  29. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/alerts.py +1 -3
  30. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/modules.py +1 -4
  31. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/network_info.py +3 -3
  32. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/product_info.py +1 -3
  33. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/program_version.py +1 -4
  34. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/schedules.py +3 -21
  35. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/utils.py +1 -3
  36. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyproject.toml +10 -14
  37. pyplumio-0.6.0/requirements.txt +1 -0
  38. {pyplumio-0.5.56 → pyplumio-0.6.0}/requirements_test.txt +5 -5
  39. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/parameters/test_init.py +2 -2
  40. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/structures/test_fuel_level.py +0 -1
  41. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/test_connection.py +41 -7
  42. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/test_data_types.py +1 -1
  43. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/test_filters.py +6 -2
  44. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/test_init.py +3 -3
  45. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/test_protocol.py +6 -0
  46. pyplumio-0.5.56/requirements.txt +0 -3
  47. {pyplumio-0.5.56 → pyplumio-0.6.0}/.gitattributes +0 -0
  48. {pyplumio-0.5.56 → pyplumio-0.6.0}/.github/CODE_OF_CONDUCT.md +0 -0
  49. {pyplumio-0.5.56 → pyplumio-0.6.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  50. {pyplumio-0.5.56 → pyplumio-0.6.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  51. {pyplumio-0.5.56 → pyplumio-0.6.0}/.github/dependabot.yml +0 -0
  52. {pyplumio-0.5.56 → pyplumio-0.6.0}/.github/workflows/codeql.yml +0 -0
  53. {pyplumio-0.5.56 → pyplumio-0.6.0}/.github/workflows/deploy.yml +0 -0
  54. {pyplumio-0.5.56 → pyplumio-0.6.0}/.github/workflows/documentation.yml +0 -0
  55. {pyplumio-0.5.56 → pyplumio-0.6.0}/.gitignore +0 -0
  56. {pyplumio-0.5.56 → pyplumio-0.6.0}/.qlty/qlty.toml +0 -0
  57. {pyplumio-0.5.56 → pyplumio-0.6.0}/.vscode/settings.json +0 -0
  58. {pyplumio-0.5.56 → pyplumio-0.6.0}/LICENSE +0 -0
  59. {pyplumio-0.5.56 → pyplumio-0.6.0}/MANIFEST.in +0 -0
  60. {pyplumio-0.5.56 → pyplumio-0.6.0}/PyPlumIO.egg-info/SOURCES.txt +0 -0
  61. {pyplumio-0.5.56 → pyplumio-0.6.0}/PyPlumIO.egg-info/dependency_links.txt +0 -0
  62. {pyplumio-0.5.56 → pyplumio-0.6.0}/PyPlumIO.egg-info/top_level.txt +0 -0
  63. {pyplumio-0.5.56 → pyplumio-0.6.0}/docs/Makefile +0 -0
  64. {pyplumio-0.5.56 → pyplumio-0.6.0}/docs/make.bat +0 -0
  65. {pyplumio-0.5.56 → pyplumio-0.6.0}/docs/source/conf.py +0 -0
  66. {pyplumio-0.5.56 → pyplumio-0.6.0}/docs/source/frames.rst +0 -0
  67. {pyplumio-0.5.56 → pyplumio-0.6.0}/docs/source/index.rst +0 -0
  68. {pyplumio-0.5.56 → pyplumio-0.6.0}/docs/source/protocol.rst +0 -0
  69. {pyplumio-0.5.56 → pyplumio-0.6.0}/images/ecomax.png +0 -0
  70. {pyplumio-0.5.56 → pyplumio-0.6.0}/images/rs485.png +0 -0
  71. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/__main__.py +0 -0
  72. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/data_types.py +0 -0
  73. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/devices/__init__.py +0 -0
  74. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/devices/ecomax.py +0 -0
  75. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/devices/ecoster.py +0 -0
  76. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/devices/mixer.py +0 -0
  77. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/devices/thermostat.py +0 -0
  78. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/exceptions.py +0 -0
  79. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/frames/messages.py +0 -0
  80. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/frames/requests.py +0 -0
  81. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/frames/responses.py +0 -0
  82. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/helpers/__init__.py +0 -0
  83. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/helpers/factory.py +0 -0
  84. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/helpers/task_manager.py +0 -0
  85. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/parameters/custom/ecomax_860d3_hb.py +0 -0
  86. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/py.typed +0 -0
  87. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/stream.py +0 -0
  88. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/boiler_load.py +0 -0
  89. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/boiler_power.py +0 -0
  90. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/ecomax_parameters.py +0 -0
  91. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/fan_power.py +0 -0
  92. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/frame_versions.py +0 -0
  93. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/fuel_consumption.py +0 -0
  94. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/fuel_level.py +0 -0
  95. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/lambda_sensor.py +0 -0
  96. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/mixer_parameters.py +0 -0
  97. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/mixer_sensors.py +0 -0
  98. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/output_flags.py +0 -0
  99. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/outputs.py +0 -0
  100. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/pending_alerts.py +0 -0
  101. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/regulator_data.py +0 -0
  102. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/regulator_data_schema.py +0 -0
  103. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/statuses.py +0 -0
  104. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/temperatures.py +0 -0
  105. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/thermostat_parameters.py +0 -0
  106. {pyplumio-0.5.56 → pyplumio-0.6.0}/pyplumio/structures/thermostat_sensors.py +0 -0
  107. {pyplumio-0.5.56 → pyplumio-0.6.0}/requirements_docs.txt +0 -0
  108. {pyplumio-0.5.56 → pyplumio-0.6.0}/setup.cfg +0 -0
  109. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/__init__.py +0 -0
  110. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/conftest.py +0 -0
  111. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/devices/__init__.py +0 -0
  112. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/devices/test_ecomax.py +0 -0
  113. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/devices/test_ecoster.py +0 -0
  114. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/devices/test_init.py +0 -0
  115. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/devices/test_mixer.py +0 -0
  116. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/devices/test_thermostat.py +0 -0
  117. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/frames/test_init.py +0 -0
  118. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/frames/test_messages.py +0 -0
  119. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/frames/test_requests.py +0 -0
  120. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/frames/test_responses.py +0 -0
  121. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/helpers/__init__.py +0 -0
  122. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/helpers/test_async_cache.py +0 -0
  123. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/helpers/test_event_manager.py +0 -0
  124. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/helpers/test_factory.py +0 -0
  125. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/helpers/test_task_manager.py +0 -0
  126. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/helpers/test_uid.py +0 -0
  127. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/parameters/__init__.py +0 -0
  128. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/parameters/custom/__init__.py +0 -0
  129. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/parameters/custom/test_ecomax_860d3_hb.py +0 -0
  130. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/parameters/custom/test_init.py +0 -0
  131. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/parameters/test_ecomax.py +0 -0
  132. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/parameters/test_mixers.py +0 -0
  133. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/parameters/test_thermostats.py +0 -0
  134. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/ruff.toml +0 -0
  135. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/structures/__init__.py +0 -0
  136. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/structures/test_alerts.py +0 -0
  137. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/structures/test_boiler_load.py +0 -0
  138. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/structures/test_boiler_power.py +0 -0
  139. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/structures/test_ecomax_parameters.py +0 -0
  140. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/structures/test_fan_power.py +0 -0
  141. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/structures/test_frame_versions.py +0 -0
  142. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/structures/test_fuel_consumption.py +0 -0
  143. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/structures/test_lambda_sensor.py +0 -0
  144. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/structures/test_mixer_parameters.py +0 -0
  145. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/structures/test_product_info.py +0 -0
  146. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/structures/test_schedules.py +0 -0
  147. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/test_main.py +0 -0
  148. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/test_stream.py +0 -0
  149. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/test_utils.py +0 -0
  150. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/messages/regulator_data.json +0 -0
  151. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/messages/sensor_data.json +0 -0
  152. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/parameters/ecomax_860d3_hb.json +0 -0
  153. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/requests/alerts.json +0 -0
  154. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/requests/ecomax_control.json +0 -0
  155. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/requests/ecomax_parameters.json +0 -0
  156. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/requests/mixer_parameters.json +0 -0
  157. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/requests/set_ecomax_parameter.json +0 -0
  158. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/requests/set_mixer_parameter.json +0 -0
  159. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/requests/set_schedule.json +0 -0
  160. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/requests/set_thermostat_parameter.json +0 -0
  161. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/requests/thermostat_parameters.json +0 -0
  162. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/responses/alerts.json +0 -0
  163. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/responses/device_available.json +0 -0
  164. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/responses/ecomax_parameters.json +0 -0
  165. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/responses/mixer_parameters.json +0 -0
  166. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/responses/password.json +0 -0
  167. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/responses/program_version.json +0 -0
  168. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/responses/regulator_data_schema.json +0 -0
  169. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/responses/schedules.json +0 -0
  170. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/responses/thermostat_parameters.json +0 -0
  171. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/responses/uid.json +0 -0
  172. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/unknown/unknown_ecomax_parameter.json +0 -0
  173. {pyplumio-0.5.56 → pyplumio-0.6.0}/tests/testdata/unknown/unknown_mixer_parameter.json +0 -0
@@ -14,7 +14,7 @@ jobs:
14
14
  runs-on: ubuntu-latest
15
15
  strategy:
16
16
  matrix:
17
- python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
17
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
18
18
 
19
19
  steps:
20
20
  - uses: actions/checkout@v4
@@ -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.12.11
6
+ rev: v0.13.0
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.17.1
16
+ rev: v1.18.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.5.56
3
+ Version: 0.6.0
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
@@ -13,30 +13,27 @@ Classifier: Development Status :: 4 - Beta
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: License :: OSI Approved :: MIT License
15
15
  Classifier: Operating System :: OS Independent
16
- Classifier: Programming Language :: Python :: 3.9
17
16
  Classifier: Programming Language :: Python :: 3.10
18
17
  Classifier: Programming Language :: Python :: 3.11
19
18
  Classifier: Programming Language :: Python :: 3.12
20
19
  Classifier: Programming Language :: Python :: 3.13
21
20
  Classifier: Topic :: Software Development :: Libraries
22
21
  Classifier: Topic :: Home Automation
23
- Requires-Python: >=3.9
22
+ Requires-Python: >=3.10
24
23
  Description-Content-Type: text/markdown
25
24
  License-File: LICENSE
26
- Requires-Dist: dataslots==1.2.0
27
25
  Requires-Dist: pyserial-asyncio==0.6
28
- Requires-Dist: typing-extensions<5.0,>=4.14.0
29
26
  Provides-Extra: test
30
27
  Requires-Dist: codespell==2.4.1; extra == "test"
31
- Requires-Dist: coverage==7.10.5; extra == "test"
28
+ Requires-Dist: coverage==7.10.6; extra == "test"
32
29
  Requires-Dist: freezegun==1.5.5; extra == "test"
33
- Requires-Dist: mypy==1.17.1; extra == "test"
30
+ Requires-Dist: mypy==1.18.1; extra == "test"
34
31
  Requires-Dist: numpy<3.0.0,>=2.0.0; extra == "test"
35
32
  Requires-Dist: pyserial-asyncio-fast==0.16; extra == "test"
36
- Requires-Dist: pytest==8.4.1; extra == "test"
33
+ Requires-Dist: pytest==8.4.2; extra == "test"
37
34
  Requires-Dist: pytest-asyncio==1.1.0; extra == "test"
38
- Requires-Dist: ruff==0.12.10; extra == "test"
39
- Requires-Dist: tox==4.28.4; extra == "test"
35
+ Requires-Dist: ruff==0.13.0; extra == "test"
36
+ Requires-Dist: tox==4.30.2; extra == "test"
40
37
  Requires-Dist: types-pyserial==3.5.0.20250822; extra == "test"
41
38
  Provides-Extra: docs
42
39
  Requires-Dist: sphinx==8.1.3; extra == "docs"
@@ -53,8 +50,8 @@ Dynamic: license-file
53
50
  [![PyPI version](https://badge.fury.io/py/PyPlumIO.svg)](https://badge.fury.io/py/PyPlumIO)
54
51
  [![PyPI Supported Python Versions](https://img.shields.io/pypi/pyversions/pyplumio.svg)](https://pypi.python.org/pypi/pyplumio/)
55
52
  [![PyPlumIO CI](https://github.com/denpamusic/PyPlumIO/actions/workflows/ci.yml/badge.svg)](https://github.com/denpamusic/PyPlumIO/actions/workflows/ci.yml)
56
- [![Maintainability](https://qlty.sh/badges/2455933c-6c18-45bc-a205-da5cc0b49d0b/maintainability.svg)](https://qlty.sh/gh/denpamusic/projects/PyPlumIO)
57
- [![Code Coverage](https://qlty.sh/badges/2455933c-6c18-45bc-a205-da5cc0b49d0b/test_coverage.svg)](https://qlty.sh/gh/denpamusic/projects/PyPlumIO)
53
+ [![Maintainability](https://qlty.sh/gh/denpamusic/projects/PyPlumIO/maintainability.svg)](https://qlty.sh/gh/denpamusic/projects/PyPlumIO)
54
+ [![Code Coverage](https://qlty.sh/gh/denpamusic/projects/PyPlumIO/coverage.svg)](https://qlty.sh/gh/denpamusic/projects/PyPlumIO)
58
55
  [![stability-release-candidate](https://img.shields.io/badge/stability-pre--release-48c9b0.svg)](https://guidelines.denpa.pro/stability#release-candidate)
59
56
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
60
57
 
@@ -82,11 +79,13 @@ through network by using RS-485 to Ethernet/WiFi converter.
82
79
  - [Callbacks](https://pyplumio.denpa.pro/callbacks.html)
83
80
  - [Mixers/Thermostats](https://pyplumio.denpa.pro/mixers_thermostats.html)
84
81
  - [Schedules](https://pyplumio.denpa.pro/schedules.html)
82
+ - [Statistics](https://pyplumio.denpa.pro/statistics.html)
85
83
  - [Protocol](https://pyplumio.denpa.pro/protocol.html)
86
84
  - [Frame Structure](https://pyplumio.denpa.pro/protocol.html#frame-structure)
87
85
  - [Requests and Responses](https://pyplumio.denpa.pro/protocol.html#requests-and-responses)
88
86
  - [Communication](https://pyplumio.denpa.pro/protocol.html#communication)
89
87
  - [Versioning](https://pyplumio.denpa.pro/protocol.html#versioning)
88
+ - [Supported frames](https://pyplumio.denpa.pro/frames.html)
90
89
 
91
90
  ## Quickstart
92
91
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPlumIO
3
- Version: 0.5.56
3
+ Version: 0.6.0
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
@@ -13,30 +13,27 @@ Classifier: Development Status :: 4 - Beta
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: License :: OSI Approved :: MIT License
15
15
  Classifier: Operating System :: OS Independent
16
- Classifier: Programming Language :: Python :: 3.9
17
16
  Classifier: Programming Language :: Python :: 3.10
18
17
  Classifier: Programming Language :: Python :: 3.11
19
18
  Classifier: Programming Language :: Python :: 3.12
20
19
  Classifier: Programming Language :: Python :: 3.13
21
20
  Classifier: Topic :: Software Development :: Libraries
22
21
  Classifier: Topic :: Home Automation
23
- Requires-Python: >=3.9
22
+ Requires-Python: >=3.10
24
23
  Description-Content-Type: text/markdown
25
24
  License-File: LICENSE
26
- Requires-Dist: dataslots==1.2.0
27
25
  Requires-Dist: pyserial-asyncio==0.6
28
- Requires-Dist: typing-extensions<5.0,>=4.14.0
29
26
  Provides-Extra: test
30
27
  Requires-Dist: codespell==2.4.1; extra == "test"
31
- Requires-Dist: coverage==7.10.5; extra == "test"
28
+ Requires-Dist: coverage==7.10.6; extra == "test"
32
29
  Requires-Dist: freezegun==1.5.5; extra == "test"
33
- Requires-Dist: mypy==1.17.1; extra == "test"
30
+ Requires-Dist: mypy==1.18.1; extra == "test"
34
31
  Requires-Dist: numpy<3.0.0,>=2.0.0; extra == "test"
35
32
  Requires-Dist: pyserial-asyncio-fast==0.16; extra == "test"
36
- Requires-Dist: pytest==8.4.1; extra == "test"
33
+ Requires-Dist: pytest==8.4.2; extra == "test"
37
34
  Requires-Dist: pytest-asyncio==1.1.0; extra == "test"
38
- Requires-Dist: ruff==0.12.10; extra == "test"
39
- Requires-Dist: tox==4.28.4; extra == "test"
35
+ Requires-Dist: ruff==0.13.0; extra == "test"
36
+ Requires-Dist: tox==4.30.2; extra == "test"
40
37
  Requires-Dist: types-pyserial==3.5.0.20250822; extra == "test"
41
38
  Provides-Extra: docs
42
39
  Requires-Dist: sphinx==8.1.3; extra == "docs"
@@ -53,8 +50,8 @@ Dynamic: license-file
53
50
  [![PyPI version](https://badge.fury.io/py/PyPlumIO.svg)](https://badge.fury.io/py/PyPlumIO)
54
51
  [![PyPI Supported Python Versions](https://img.shields.io/pypi/pyversions/pyplumio.svg)](https://pypi.python.org/pypi/pyplumio/)
55
52
  [![PyPlumIO CI](https://github.com/denpamusic/PyPlumIO/actions/workflows/ci.yml/badge.svg)](https://github.com/denpamusic/PyPlumIO/actions/workflows/ci.yml)
56
- [![Maintainability](https://qlty.sh/badges/2455933c-6c18-45bc-a205-da5cc0b49d0b/maintainability.svg)](https://qlty.sh/gh/denpamusic/projects/PyPlumIO)
57
- [![Code Coverage](https://qlty.sh/badges/2455933c-6c18-45bc-a205-da5cc0b49d0b/test_coverage.svg)](https://qlty.sh/gh/denpamusic/projects/PyPlumIO)
53
+ [![Maintainability](https://qlty.sh/gh/denpamusic/projects/PyPlumIO/maintainability.svg)](https://qlty.sh/gh/denpamusic/projects/PyPlumIO)
54
+ [![Code Coverage](https://qlty.sh/gh/denpamusic/projects/PyPlumIO/coverage.svg)](https://qlty.sh/gh/denpamusic/projects/PyPlumIO)
58
55
  [![stability-release-candidate](https://img.shields.io/badge/stability-pre--release-48c9b0.svg)](https://guidelines.denpa.pro/stability#release-candidate)
59
56
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
60
57
 
@@ -82,11 +79,13 @@ through network by using RS-485 to Ethernet/WiFi converter.
82
79
  - [Callbacks](https://pyplumio.denpa.pro/callbacks.html)
83
80
  - [Mixers/Thermostats](https://pyplumio.denpa.pro/mixers_thermostats.html)
84
81
  - [Schedules](https://pyplumio.denpa.pro/schedules.html)
82
+ - [Statistics](https://pyplumio.denpa.pro/statistics.html)
85
83
  - [Protocol](https://pyplumio.denpa.pro/protocol.html)
86
84
  - [Frame Structure](https://pyplumio.denpa.pro/protocol.html#frame-structure)
87
85
  - [Requests and Responses](https://pyplumio.denpa.pro/protocol.html#requests-and-responses)
88
86
  - [Communication](https://pyplumio.denpa.pro/protocol.html#communication)
89
87
  - [Versioning](https://pyplumio.denpa.pro/protocol.html#versioning)
88
+ - [Supported frames](https://pyplumio.denpa.pro/frames.html)
90
89
 
91
90
  ## Quickstart
92
91
 
@@ -1,6 +1,4 @@
1
- dataslots==1.2.0
2
1
  pyserial-asyncio==0.6
3
- typing-extensions<5.0,>=4.14.0
4
2
 
5
3
  [dev]
6
4
  pyplumio[docs,test]
@@ -14,13 +12,13 @@ readthedocs-sphinx-search==0.3.2
14
12
 
15
13
  [test]
16
14
  codespell==2.4.1
17
- coverage==7.10.5
15
+ coverage==7.10.6
18
16
  freezegun==1.5.5
19
- mypy==1.17.1
17
+ mypy==1.18.1
20
18
  numpy<3.0.0,>=2.0.0
21
19
  pyserial-asyncio-fast==0.16
22
- pytest==8.4.1
20
+ pytest==8.4.2
23
21
  pytest-asyncio==1.1.0
24
- ruff==0.12.10
25
- tox==4.28.4
22
+ ruff==0.13.0
23
+ tox==4.30.2
26
24
  types-pyserial==3.5.0.20250822
@@ -3,8 +3,8 @@
3
3
  [![PyPI version](https://badge.fury.io/py/PyPlumIO.svg)](https://badge.fury.io/py/PyPlumIO)
4
4
  [![PyPI Supported Python Versions](https://img.shields.io/pypi/pyversions/pyplumio.svg)](https://pypi.python.org/pypi/pyplumio/)
5
5
  [![PyPlumIO CI](https://github.com/denpamusic/PyPlumIO/actions/workflows/ci.yml/badge.svg)](https://github.com/denpamusic/PyPlumIO/actions/workflows/ci.yml)
6
- [![Maintainability](https://qlty.sh/badges/2455933c-6c18-45bc-a205-da5cc0b49d0b/maintainability.svg)](https://qlty.sh/gh/denpamusic/projects/PyPlumIO)
7
- [![Code Coverage](https://qlty.sh/badges/2455933c-6c18-45bc-a205-da5cc0b49d0b/test_coverage.svg)](https://qlty.sh/gh/denpamusic/projects/PyPlumIO)
6
+ [![Maintainability](https://qlty.sh/gh/denpamusic/projects/PyPlumIO/maintainability.svg)](https://qlty.sh/gh/denpamusic/projects/PyPlumIO)
7
+ [![Code Coverage](https://qlty.sh/gh/denpamusic/projects/PyPlumIO/coverage.svg)](https://qlty.sh/gh/denpamusic/projects/PyPlumIO)
8
8
  [![stability-release-candidate](https://img.shields.io/badge/stability-pre--release-48c9b0.svg)](https://guidelines.denpa.pro/stability#release-candidate)
9
9
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
10
10
 
@@ -32,11 +32,13 @@ through network by using RS-485 to Ethernet/WiFi converter.
32
32
  - [Callbacks](https://pyplumio.denpa.pro/callbacks.html)
33
33
  - [Mixers/Thermostats](https://pyplumio.denpa.pro/mixers_thermostats.html)
34
34
  - [Schedules](https://pyplumio.denpa.pro/schedules.html)
35
+ - [Statistics](https://pyplumio.denpa.pro/statistics.html)
35
36
  - [Protocol](https://pyplumio.denpa.pro/protocol.html)
36
37
  - [Frame Structure](https://pyplumio.denpa.pro/protocol.html#frame-structure)
37
38
  - [Requests and Responses](https://pyplumio.denpa.pro/protocol.html#requests-and-responses)
38
39
  - [Communication](https://pyplumio.denpa.pro/protocol.html#communication)
39
40
  - [Versioning](https://pyplumio.denpa.pro/protocol.html#versioning)
41
+ - [Supported frames](https://pyplumio.denpa.pro/frames.html)
40
42
 
41
43
  ## Quickstart
42
44
 
@@ -166,16 +166,13 @@ processing.
166
166
  async def main():
167
167
  """Subscribes callback to the current heating temperature."""
168
168
  async with pyplumio.open_tcp_connection("localhost", 8899) as conn:
169
+ async with conn.device("ecomax") as ecomax:
170
+ # Await the callback on value change but no faster than
171
+ # once per 5 seconds.
172
+ ecomax.subscribe("heating_temp", throttle(on_change(my_callback), seconds=5))
169
173
 
170
- # Get the ecoMAX device.
171
- ecomax = await conn.get("ecomax")
172
-
173
- # Await the callback on value change but no faster than
174
- # once per 5 seconds.
175
- ecomax.subscribe("heating_temp", throttle(on_change(my_callback), seconds=5))
176
-
177
- # Wait until disconnected (forever)
178
- await conn.wait_until_done()
174
+ # Wait until disconnected (forever)
175
+ await conn.wait_until_done()
179
176
 
180
177
 
181
178
  asyncio.run(main())
@@ -199,15 +196,12 @@ current heating temperature on every SensorDataMessage.
199
196
  async def main():
200
197
  """Subscribes callback to the current heating temperature."""
201
198
  async with pyplumio.open_tcp_connection("localhost", 8899) as conn:
199
+ async with conn.device("ecomax") as ecomax:
200
+ # Subscribe my_callback to heating_temp event.
201
+ ecomax.subscribe("heating_temp", my_callback)
202
202
 
203
- # Get the ecoMAX device.
204
- ecomax = await conn.get("ecomax")
205
-
206
- # Subscribe my_callback to heating_temp event.
207
- ecomax.subscribe("heating_temp", my_callback)
208
-
209
- # Wait until disconnected (forever)
210
- await conn.wait_until_done()
203
+ # Wait until disconnected (forever)
204
+ await conn.wait_until_done()
211
205
 
212
206
 
213
207
  asyncio.run(main())
@@ -235,17 +229,15 @@ when heating temperature will change more the 0.1 degrees Celsius.
235
229
  async def main():
236
230
  """Subscribes callback to the current heating temperature."""
237
231
  async with pyplumio.open_tcp_connection("localhost", 8899) as conn:
238
- # Get the ecoMAX device.
239
- ecomax = await conn.get("ecomax")
240
-
241
- # Subscribe my_callback to heating_target_temp event.
242
- ecomax.subscribe_once("heating_target_temp", my_callback)
232
+ async with conn.device("ecomax") as ecomax:
233
+ # Subscribe my_callback to heating_target_temp event.
234
+ ecomax.subscribe_once("heating_target_temp", my_callback)
243
235
 
244
- # Subscribe my_callback2 to heating_temp changes.
245
- ecomax.subscribe("heating_temp", on_change(my_callback2))
236
+ # Subscribe my_callback2 to heating_temp changes.
237
+ ecomax.subscribe("heating_temp", on_change(my_callback2))
246
238
 
247
- # Wait until disconnected (forever)
248
- await conn.wait_until_done()
239
+ # Wait until disconnected (forever)
240
+ await conn.wait_until_done()
249
241
 
250
242
 
251
243
  asyncio.run(main())
@@ -70,15 +70,15 @@ working with device classes and queues.
70
70
  """Open a connection and request alerts."""
71
71
  async with pyplumio.open_tcp_connection(
72
72
  host="localhost", port=8899, protocol=pyplumio.DummyProtocol()
73
- ) as connection:
74
- await connection.writer.write(
73
+ ) as conn:
74
+ await conn.writer.write(
75
75
  requests.AlertsRequest(recipient=DeviceType.ECOMAX, start=0, count=5)
76
76
  )
77
77
 
78
- while connection.connected:
78
+ while conn.connected:
79
79
  try:
80
80
  if isinstance(
81
- (frame := await connection.reader.read()), responses.AlertsResponse
81
+ (frame := await conn.reader.read()), responses.AlertsResponse
82
82
  ):
83
83
  print(frame.data)
84
84
  break
@@ -139,7 +139,7 @@ In the example below, we'll set both ethernet and wireless parameters.
139
139
  signal_quality=100,
140
140
  ),
141
141
  ),
142
- ) as connection:
142
+ ) as conn:
143
143
  ...
144
144
 
145
145
 
@@ -165,7 +165,8 @@ context manager.
165
165
  async with pyplumio.open_tcp_connection("localhost", port=8899) as conn:
166
166
  try:
167
167
  # Get the ecoMAX device within 10 seconds or timeout.
168
- ecomax = await conn.get("ecomax", timeout=10)
168
+ async with conn.device("ecomax", timeout=10) as ecomax:
169
+ ...
169
170
  except asyncio.TimeoutError:
170
171
  # If device times out, log the error.
171
172
  _LOGGER.error("Failed to get the device within 10 seconds")
@@ -197,11 +198,12 @@ using Python's context manager.
197
198
 
198
199
  try:
199
200
  # Get the ecoMAX device within 10 seconds or timeout.
200
- ecomax = await connection.get("ecomax", timeout=10)
201
+ async with conn.device("ecomax", timeout=10) as ecomax:
202
+ ...
201
203
  except asyncio.TimeoutError:
202
204
  # If device times out, log the error.
203
205
  _LOGGER.error("Failed to get the device within 10 seconds")
204
-
206
+
205
207
  # Close the connection.
206
208
  await connection.close()
207
209
 
@@ -10,9 +10,9 @@ respective properties.
10
10
 
11
11
  .. code-block:: python
12
12
 
13
- ecomax = await conn.get("ecomax")
14
- thermostats = await ecomax.get("thermostats")
15
- mixers = await ecomax.get("mixers")
13
+ async with conn.device("ecomax") as ecomax:
14
+ thermostats = await ecomax.get("thermostats")
15
+ mixers = await ecomax.get("mixers")
16
16
 
17
17
  Result of this call will be a dictionary of ``Mixer`` or ``Thermostat``
18
18
  object keyed by the device indexes.
@@ -34,20 +34,18 @@ get it's current_temp property and set it's target temperature to
34
34
 
35
35
  from pyplumio.devices import Mixer
36
36
 
37
- # Get the ecoMAX device.
38
- ecomax = await conn.get("ecomax")
37
+ async with conn.device("ecomax") as ecomax:
38
+ # Get connected mixers.
39
+ mixers = await ecomax.get("mixers")
39
40
 
40
- # Get connected mixers.
41
- mixers = await ecomax.get("mixers")
41
+ # Get a single mixer.
42
+ mixer: Mixer = mixers[1]
42
43
 
43
- # Get single mixer.
44
- mixer: Mixer = mixers[1]
44
+ # Get current mixer temperature.
45
+ mixer_current_temp = await mixer.get("current_temp")
45
46
 
46
- # Get current mixer temperature.
47
- mixer_current_temp = await mixer.get("current_temp")
48
-
49
- # Set mixer target temperature to 50 degrees Celsius.
50
- await mixer.set("mixer_target_temp", 50)
47
+ # Set mixer target temperature to 50 degrees Celsius.
48
+ await mixer.set("mixer_target_temp", 50)
51
49
 
52
50
  Thermostat Examples
53
51
  -------------------
@@ -60,17 +58,15 @@ degrees Celsius.
60
58
 
61
59
  from pyplumio.device import Thermostat
62
60
 
63
- # Get the ecoMAX device.
64
- ecomax = await conn.get("ecomax")
65
-
66
- # Get connected thermostats.
67
- thermostats = await ecomax.get("thermostats")
61
+ async with conn.device("ecomax") as ecomax:
62
+ # Get connected thermostats.
63
+ thermostats = await ecomax.get("thermostats")
68
64
 
69
- # Get single thermostat.
70
- thermostat: Thermostat = thermostats[1]
65
+ # Get single thermostat.
66
+ thermostat: Thermostat = thermostats[1]
71
67
 
72
- # Get current room temperature.
73
- thermostat_current_temp = await thermostat.get("current_temp")
68
+ # Get current room temperature.
69
+ thermostat_current_temp = await thermostat.get("current_temp")
74
70
 
75
- # Set day target temperature to 20 degrees Celsius.
76
- await thermostat.set("day_target_temp", 20)
71
+ # Set day target temperature to 20 degrees Celsius.
72
+ await thermostat.set("day_target_temp", 20)
@@ -10,8 +10,8 @@ You can use this property get a full device dataset.
10
10
 
11
11
  .. code-block:: python
12
12
 
13
- ecomax = await conn.get("ecomax")
14
- print(ecomax.data)
13
+ async with conn.device("ecomax") as ecomax:
14
+ print(ecomax.data)
15
15
 
16
16
  In a pinch, you can also use this attribute to directly access the data,
17
17
  but this is not recommended, please use getters instead.
@@ -36,12 +36,11 @@ and close the connection.
36
36
  """Read the current heating temperature."""
37
37
  async with pyplumio.open_tcp_connection("localhost", 8899) as conn:
38
38
  # Get the ecoMAX device.
39
- ecomax = await conn.get("ecomax")
40
-
41
- # Get the heating temperature.
42
- heating_temp = await ecomax.get("heating_temp")
43
- print(heating_temp)
44
- ...
39
+ async with conn.device("ecomax") as ecomax:
40
+ # Get the heating temperature.
41
+ heating_temp = await ecomax.get("heating_temp")
42
+ print(heating_temp)
43
+ ...
45
44
 
46
45
 
47
46
  asyncio.run(main())
@@ -92,11 +91,14 @@ keys, and can be accessed via the **regdata** property.
92
91
 
93
92
  .. code-block:: python
94
93
 
95
- ecomax = await conn.get("ecomax")
96
- regdata = await ecomax.get("regdata")
94
+ from typing import Any
95
+
96
+ async with conn.device("ecomax") as ecomax:
97
+ # Get regulator data.
98
+ regdata: dict[int, Any] = await ecomax.get("regdata")
97
99
 
98
- # Get regulator data with the 1280 key.
99
- heating_target = regdata[1280]
100
+ # Get regulator data with the 1280 key.
101
+ heating_target = regdata[1280]
100
102
 
101
103
 
102
104
  Reading Examples
@@ -119,18 +121,17 @@ to the terminal.
119
121
  """
120
122
  async with pyplumio.open_tcp_connection("localhost", 8899) as conn:
121
123
  # Get the ecoMAX device.
122
- ecomax = await conn.get("ecomax")
123
-
124
- # Get heating temperature, if it's available otherwise
125
- # return the default value (65).
126
- heating_temp = ecomax.get_nowait("heating_temp", default=65)
124
+ async with conn.device("ecomax") as ecomax:
125
+ # Get heating temperature, if it's available otherwise
126
+ # return the default value (65).
127
+ heating_temp = ecomax.get_nowait("heating_temp", default=65)
127
128
 
128
- # Wait for heating temperature and get it's value.
129
- heating_target_temp = await ecomax.get("heating_target_temp")
129
+ # Wait for heating temperature and get it's value.
130
+ heating_target_temp = await ecomax.get("heating_target_temp")
130
131
 
131
- # Wait until regulator data is available then grab key 1792.
132
- await ecomax.wait_for("regdata")
133
- status = ecomax.regdata[1792]
132
+ # Wait until regulator data is available then grab key 1792.
133
+ await ecomax.wait_for("regdata")
134
+ status = ecomax.regdata[1792]
134
135
 
135
136
  print(
136
137
  f"Current temp: {heating_temp}, "
@@ -115,27 +115,27 @@ Schedule Examples
115
115
 
116
116
  async def main():
117
117
  """Set a device schedule."""
118
- async with pyplumio.open_tcp_connection("localhost", 8899) as connection:
119
- ecomax = await connection.get("ecomax")
120
- schedules = await ecomax.get("schedules")
121
- heating_schedule = schedules["heating"]
122
-
123
- # Turn the heating schedule on.
124
- await ecomax.set("schedule_heating_switch", "on")
125
-
126
- # Drop the heating temperature by 10 degrees in the nighttime mode.
127
- await ecomax.set("schedule_heating_parameter", 10)
128
-
129
- for weekday in heating_schedule:
130
- weekday.set_state(STATE_ON, "00:00", "00:30")
131
- weekday.set_state(STATE_OFF, "00:30", "09:00")
132
- weekday.set_state(STATE_ON, "09:00", "00:00")
133
- weekday["19:00"] = STATE_OFF
134
-
135
- # There will be no nighttime mode on sunday.
136
- heating_schedule.sunday.set_state(STATE_ON)
137
-
138
- await heating_schedule.commit()
118
+ async with pyplumio.open_tcp_connection("localhost", 8899) as conn:
119
+ async with conn.device("ecomax") as ecomax:
120
+ schedules = await ecomax.get("schedules")
121
+ heating_schedule = schedules["heating"]
122
+
123
+ # Turn the heating schedule on.
124
+ await ecomax.set("schedule_heating_switch", "on")
125
+
126
+ # Drop the heating temperature by 10 degrees in the nighttime mode.
127
+ await ecomax.set("schedule_heating_parameter", 10)
128
+
129
+ for weekday in heating_schedule:
130
+ weekday.set_state(STATE_ON, "00:00", "00:30")
131
+ weekday.set_state(STATE_OFF, "00:30", "09:00")
132
+ weekday.set_state(STATE_ON, "09:00", "00:00")
133
+ weekday["19:00"] = STATE_OFF
134
+
135
+ # There will be no nighttime mode on sunday.
136
+ heating_schedule.sunday.set_state(STATE_ON)
137
+
138
+ await heating_schedule.commit()
139
139
 
140
140
 
141
141
  asyncio.run(main())
@@ -13,11 +13,17 @@ as well as datetime of when connection was established, when connection was lost
13
13
  number of connection loss event.
14
14
 
15
15
  .. autoclass:: pyplumio.protocol.Statistics
16
+ :members:
17
+ :exclude-members: update_transfer_statistics, track_connection_loss, reset_transfer_statistics
16
18
 
17
19
  The `devices` property of statistics class of also contains a list of
18
- device statistics objects.
20
+ device statistics objects. Those statistics include time the device was initially
21
+ connected as well as time, when device was last seen (sent an :ref:`RegulatorData`
22
+ message).
19
23
 
20
24
  .. autoclass:: pyplumio.protocol.DeviceStatistics
25
+ :members:
26
+ :exclude-members: update_last_seen
21
27
 
22
28
  Statistics Examples
23
29
  -------------------
@@ -34,7 +40,8 @@ as in example below.
34
40
  async def main():
35
41
  """Read the current heating temperature."""
36
42
  async with pyplumio.open_tcp_connection("localhost", 8899) as conn:
37
- print(conn.statistic)
43
+ print(conn.statistics)
38
44
 
39
45
 
40
- asyncio.run(main())
46
+ asyncio.run(main())
47
+
@@ -47,9 +47,9 @@ Numbers are parameters that have numerical value associated with them.
47
47
 
48
48
  from pyplumio.parameters import Number
49
49
 
50
- ecomax = await conn.get("ecomax")
51
- heating_target: Number = ecomax.get("heating_target_temp")
52
- result = heating_target.set(65)
50
+ async with conn.device("ecomax") as ecomax:
51
+ heating_target: Number = ecomax.get("heating_target_temp")
52
+ result = heating_target.set(65)
53
53
 
54
54
  Each number has an unique range of allowed values.
55
55
  PyPlumIO will raise ``ValueError`` if value isn't within acceptable
@@ -63,10 +63,10 @@ Please note, that both values are **inclusive**.
63
63
 
64
64
  from pyplumio.parameters import Number
65
65
 
66
- ecomax = await connection.get("ecomax")
67
- target_temp: Number = await ecomax.get("heating_target_temp")
68
- print(target_temp.min_value) # Minimum allowed target temperature.
69
- print(target_temp.max_value) # Maximum allowed target temperature.
66
+ async with conn.device("ecomax") as ecomax:
67
+ target_temp: Number = await ecomax.get("heating_target_temp")
68
+ print(target_temp.min_value) # Minimum allowed target temperature.
69
+ print(target_temp.max_value) # Maximum allowed target temperature.
70
70
 
71
71
  Switches
72
72
  ^^^^^^^^
@@ -129,18 +129,16 @@ outputting the result to the terminal.
129
129
  """Turn on the controller and set target temperature."""
130
130
  async with pyplumio.open_tcp_connection("localhost", 8899) as conn:
131
131
  # Get the ecoMAX device.
132
- ecomax = await conn.get("ecomax")
133
-
134
- # Turn on controller without waiting for the result.
135
- ecomax.turn_on_nowait()
136
-
137
- # Set heating temperature to 65 degrees.
138
- result = await ecomax.set("heating_target_temp", 65)
139
- if result:
140
- print("Heating temperature is set to 65.")
141
- else:
142
- print("Couldn't set heating temperature.")
132
+ async with conn.device("ecomax") as ecomax:
133
+ # Turn on controller without waiting for the result.
134
+ ecomax.turn_on_nowait()
135
+
136
+ # Set heating temperature to 65 degrees.
137
+ result = await ecomax.set("heating_target_temp", 65)
138
+ if result:
139
+ print("Heating temperature is set to 65.")
140
+ else:
141
+ print("Couldn't set heating temperature.")
143
142
 
144
-
145
143
 
146
144
  asyncio.run(main())