PyPlumIO 0.5.55__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.55 → pyplumio-0.6.0}/.github/workflows/ci.yml +1 -1
  2. {pyplumio-0.5.55 → pyplumio-0.6.0}/.pre-commit-config.yaml +2 -2
  3. {pyplumio-0.5.55 → pyplumio-0.6.0}/PKG-INFO +11 -12
  4. {pyplumio-0.5.55 → pyplumio-0.6.0}/PyPlumIO.egg-info/PKG-INFO +11 -12
  5. {pyplumio-0.5.55 → pyplumio-0.6.0}/PyPlumIO.egg-info/SOURCES.txt +1 -0
  6. {pyplumio-0.5.55 → pyplumio-0.6.0}/PyPlumIO.egg-info/requires.txt +5 -7
  7. {pyplumio-0.5.55 → pyplumio-0.6.0}/README.md +4 -2
  8. {pyplumio-0.5.55 → pyplumio-0.6.0}/docs/source/callbacks.rst +18 -26
  9. {pyplumio-0.5.55 → pyplumio-0.6.0}/docs/source/connecting.rst +10 -8
  10. {pyplumio-0.5.55 → pyplumio-0.6.0}/docs/source/index.rst +1 -0
  11. {pyplumio-0.5.55 → pyplumio-0.6.0}/docs/source/mixers_thermostats.rst +21 -25
  12. {pyplumio-0.5.55 → pyplumio-0.6.0}/docs/source/reading.rst +23 -22
  13. {pyplumio-0.5.55 → pyplumio-0.6.0}/docs/source/schedules.rst +21 -21
  14. pyplumio-0.6.0/docs/source/statistics.rst +47 -0
  15. {pyplumio-0.5.55 → pyplumio-0.6.0}/docs/source/writing.rst +17 -19
  16. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/__init__.py +10 -10
  17. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/_version.py +3 -3
  18. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/connection.py +76 -16
  19. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/const.py +1 -3
  20. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/filters.py +4 -5
  21. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/frames/__init__.py +3 -16
  22. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/helpers/async_cache.py +2 -4
  23. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/helpers/event_manager.py +1 -3
  24. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/parameters/__init__.py +8 -17
  25. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/parameters/custom/__init__.py +2 -6
  26. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/parameters/ecomax.py +2 -7
  27. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/parameters/mixer.py +2 -7
  28. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/parameters/thermostat.py +2 -6
  29. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/protocol.py +109 -8
  30. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/__init__.py +1 -3
  31. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/alerts.py +1 -3
  32. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/modules.py +1 -4
  33. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/network_info.py +3 -3
  34. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/product_info.py +1 -3
  35. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/program_version.py +1 -4
  36. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/schedules.py +3 -21
  37. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/utils.py +1 -3
  38. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyproject.toml +10 -14
  39. pyplumio-0.6.0/requirements.txt +1 -0
  40. {pyplumio-0.5.55 → pyplumio-0.6.0}/requirements_test.txt +5 -5
  41. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/parameters/test_init.py +2 -2
  42. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/structures/test_fuel_level.py +0 -1
  43. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/test_connection.py +41 -7
  44. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/test_data_types.py +1 -1
  45. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/test_filters.py +6 -2
  46. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/test_init.py +3 -3
  47. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/test_protocol.py +75 -7
  48. pyplumio-0.5.55/requirements.txt +0 -3
  49. {pyplumio-0.5.55 → pyplumio-0.6.0}/.gitattributes +0 -0
  50. {pyplumio-0.5.55 → pyplumio-0.6.0}/.github/CODE_OF_CONDUCT.md +0 -0
  51. {pyplumio-0.5.55 → pyplumio-0.6.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  52. {pyplumio-0.5.55 → pyplumio-0.6.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  53. {pyplumio-0.5.55 → pyplumio-0.6.0}/.github/dependabot.yml +0 -0
  54. {pyplumio-0.5.55 → pyplumio-0.6.0}/.github/workflows/codeql.yml +0 -0
  55. {pyplumio-0.5.55 → pyplumio-0.6.0}/.github/workflows/deploy.yml +0 -0
  56. {pyplumio-0.5.55 → pyplumio-0.6.0}/.github/workflows/documentation.yml +0 -0
  57. {pyplumio-0.5.55 → pyplumio-0.6.0}/.gitignore +0 -0
  58. {pyplumio-0.5.55 → pyplumio-0.6.0}/.qlty/qlty.toml +0 -0
  59. {pyplumio-0.5.55 → pyplumio-0.6.0}/.vscode/settings.json +0 -0
  60. {pyplumio-0.5.55 → pyplumio-0.6.0}/LICENSE +0 -0
  61. {pyplumio-0.5.55 → pyplumio-0.6.0}/MANIFEST.in +0 -0
  62. {pyplumio-0.5.55 → pyplumio-0.6.0}/PyPlumIO.egg-info/dependency_links.txt +0 -0
  63. {pyplumio-0.5.55 → pyplumio-0.6.0}/PyPlumIO.egg-info/top_level.txt +0 -0
  64. {pyplumio-0.5.55 → pyplumio-0.6.0}/docs/Makefile +0 -0
  65. {pyplumio-0.5.55 → pyplumio-0.6.0}/docs/make.bat +0 -0
  66. {pyplumio-0.5.55 → pyplumio-0.6.0}/docs/source/conf.py +0 -0
  67. {pyplumio-0.5.55 → pyplumio-0.6.0}/docs/source/frames.rst +0 -0
  68. {pyplumio-0.5.55 → pyplumio-0.6.0}/docs/source/protocol.rst +0 -0
  69. {pyplumio-0.5.55 → pyplumio-0.6.0}/images/ecomax.png +0 -0
  70. {pyplumio-0.5.55 → pyplumio-0.6.0}/images/rs485.png +0 -0
  71. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/__main__.py +0 -0
  72. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/data_types.py +0 -0
  73. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/devices/__init__.py +0 -0
  74. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/devices/ecomax.py +0 -0
  75. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/devices/ecoster.py +0 -0
  76. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/devices/mixer.py +0 -0
  77. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/devices/thermostat.py +0 -0
  78. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/exceptions.py +0 -0
  79. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/frames/messages.py +0 -0
  80. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/frames/requests.py +0 -0
  81. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/frames/responses.py +0 -0
  82. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/helpers/__init__.py +0 -0
  83. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/helpers/factory.py +0 -0
  84. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/helpers/task_manager.py +0 -0
  85. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/parameters/custom/ecomax_860d3_hb.py +0 -0
  86. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/py.typed +0 -0
  87. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/stream.py +0 -0
  88. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/boiler_load.py +0 -0
  89. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/boiler_power.py +0 -0
  90. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/ecomax_parameters.py +0 -0
  91. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/fan_power.py +0 -0
  92. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/frame_versions.py +0 -0
  93. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/fuel_consumption.py +0 -0
  94. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/fuel_level.py +0 -0
  95. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/lambda_sensor.py +0 -0
  96. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/mixer_parameters.py +0 -0
  97. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/mixer_sensors.py +0 -0
  98. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/output_flags.py +0 -0
  99. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/outputs.py +0 -0
  100. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/pending_alerts.py +0 -0
  101. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/regulator_data.py +0 -0
  102. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/regulator_data_schema.py +0 -0
  103. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/statuses.py +0 -0
  104. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/temperatures.py +0 -0
  105. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/thermostat_parameters.py +0 -0
  106. {pyplumio-0.5.55 → pyplumio-0.6.0}/pyplumio/structures/thermostat_sensors.py +0 -0
  107. {pyplumio-0.5.55 → pyplumio-0.6.0}/requirements_docs.txt +0 -0
  108. {pyplumio-0.5.55 → pyplumio-0.6.0}/setup.cfg +0 -0
  109. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/__init__.py +0 -0
  110. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/conftest.py +0 -0
  111. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/devices/__init__.py +0 -0
  112. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/devices/test_ecomax.py +0 -0
  113. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/devices/test_ecoster.py +0 -0
  114. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/devices/test_init.py +0 -0
  115. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/devices/test_mixer.py +0 -0
  116. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/devices/test_thermostat.py +0 -0
  117. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/frames/test_init.py +0 -0
  118. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/frames/test_messages.py +0 -0
  119. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/frames/test_requests.py +0 -0
  120. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/frames/test_responses.py +0 -0
  121. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/helpers/__init__.py +0 -0
  122. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/helpers/test_async_cache.py +0 -0
  123. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/helpers/test_event_manager.py +0 -0
  124. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/helpers/test_factory.py +0 -0
  125. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/helpers/test_task_manager.py +0 -0
  126. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/helpers/test_uid.py +0 -0
  127. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/parameters/__init__.py +0 -0
  128. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/parameters/custom/__init__.py +0 -0
  129. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/parameters/custom/test_ecomax_860d3_hb.py +0 -0
  130. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/parameters/custom/test_init.py +0 -0
  131. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/parameters/test_ecomax.py +0 -0
  132. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/parameters/test_mixers.py +0 -0
  133. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/parameters/test_thermostats.py +0 -0
  134. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/ruff.toml +0 -0
  135. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/structures/__init__.py +0 -0
  136. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/structures/test_alerts.py +0 -0
  137. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/structures/test_boiler_load.py +0 -0
  138. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/structures/test_boiler_power.py +0 -0
  139. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/structures/test_ecomax_parameters.py +0 -0
  140. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/structures/test_fan_power.py +0 -0
  141. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/structures/test_frame_versions.py +0 -0
  142. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/structures/test_fuel_consumption.py +0 -0
  143. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/structures/test_lambda_sensor.py +0 -0
  144. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/structures/test_mixer_parameters.py +0 -0
  145. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/structures/test_product_info.py +0 -0
  146. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/structures/test_schedules.py +0 -0
  147. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/test_main.py +0 -0
  148. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/test_stream.py +0 -0
  149. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/test_utils.py +0 -0
  150. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/messages/regulator_data.json +0 -0
  151. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/messages/sensor_data.json +0 -0
  152. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/parameters/ecomax_860d3_hb.json +0 -0
  153. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/requests/alerts.json +0 -0
  154. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/requests/ecomax_control.json +0 -0
  155. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/requests/ecomax_parameters.json +0 -0
  156. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/requests/mixer_parameters.json +0 -0
  157. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/requests/set_ecomax_parameter.json +0 -0
  158. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/requests/set_mixer_parameter.json +0 -0
  159. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/requests/set_schedule.json +0 -0
  160. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/requests/set_thermostat_parameter.json +0 -0
  161. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/requests/thermostat_parameters.json +0 -0
  162. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/responses/alerts.json +0 -0
  163. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/responses/device_available.json +0 -0
  164. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/responses/ecomax_parameters.json +0 -0
  165. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/responses/mixer_parameters.json +0 -0
  166. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/responses/password.json +0 -0
  167. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/responses/program_version.json +0 -0
  168. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/responses/regulator_data_schema.json +0 -0
  169. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/responses/schedules.json +0 -0
  170. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/responses/thermostat_parameters.json +0 -0
  171. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/responses/uid.json +0 -0
  172. {pyplumio-0.5.55 → pyplumio-0.6.0}/tests/testdata/unknown/unknown_ecomax_parameter.json +0 -0
  173. {pyplumio-0.5.55 → 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.55
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.55
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
 
@@ -34,6 +34,7 @@ docs/source/mixers_thermostats.rst
34
34
  docs/source/protocol.rst
35
35
  docs/source/reading.rst
36
36
  docs/source/schedules.rst
37
+ docs/source/statistics.rst
37
38
  docs/source/writing.rst
38
39
  images/ecomax.png
39
40
  images/rs485.png
@@ -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
 
@@ -51,6 +51,7 @@ Documentation
51
51
  callbacks
52
52
  mixers_thermostats
53
53
  schedules
54
+ statistics
54
55
  protocol
55
56
  frames
56
57
 
@@ -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())
@@ -0,0 +1,47 @@
1
+ Statistics
2
+ ==========
3
+
4
+ About Statistics
5
+ ----------------
6
+
7
+ Since PyPlumIO v0.5.56, you can access statistics via following property.
8
+
9
+ .. autoattribute:: pyplumio.protocol.AsyncProtocol.statistics
10
+
11
+ Statistics contain transfer data consisting of number of received/sent frames and bytes
12
+ as well as datetime of when connection was established, when connection was lost and
13
+ number of connection loss event.
14
+
15
+ .. autoclass:: pyplumio.protocol.Statistics
16
+ :members:
17
+ :exclude-members: update_transfer_statistics, track_connection_loss, reset_transfer_statistics
18
+
19
+ The `devices` property of statistics class of also contains a list of
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).
23
+
24
+ .. autoclass:: pyplumio.protocol.DeviceStatistics
25
+ :members:
26
+ :exclude-members: update_last_seen
27
+
28
+ Statistics Examples
29
+ -------------------
30
+
31
+ You can easily access statistic object via proxy call through Connection object
32
+ as in example below.
33
+
34
+ .. code-block:: python
35
+
36
+ import asyncio
37
+
38
+ import pyplumio
39
+
40
+ async def main():
41
+ """Read the current heating temperature."""
42
+ async with pyplumio.open_tcp_connection("localhost", 8899) as conn:
43
+ print(conn.statistics)
44
+
45
+
46
+ asyncio.run(main())
47
+