PyPlumIO 0.5.31__tar.gz → 0.5.33__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 (142) hide show
  1. {pyplumio-0.5.31 → pyplumio-0.5.33}/PKG-INFO +1 -1
  2. {pyplumio-0.5.31 → pyplumio-0.5.33}/PyPlumIO.egg-info/PKG-INFO +1 -1
  3. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/_version.py +2 -2
  4. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/devices/__init__.py +5 -8
  5. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/helpers/parameter.py +4 -3
  6. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/helpers/test_parameter.py +30 -6
  7. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/test_devices.py +0 -4
  8. {pyplumio-0.5.31 → pyplumio-0.5.33}/.gitattributes +0 -0
  9. {pyplumio-0.5.31 → pyplumio-0.5.33}/.github/CODE_OF_CONDUCT.md +0 -0
  10. {pyplumio-0.5.31 → pyplumio-0.5.33}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  11. {pyplumio-0.5.31 → pyplumio-0.5.33}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  12. {pyplumio-0.5.31 → pyplumio-0.5.33}/.github/dependabot.yml +0 -0
  13. {pyplumio-0.5.31 → pyplumio-0.5.33}/.github/workflows/ci.yml +0 -0
  14. {pyplumio-0.5.31 → pyplumio-0.5.33}/.github/workflows/codeql-analysis.yml +0 -0
  15. {pyplumio-0.5.31 → pyplumio-0.5.33}/.github/workflows/deploy.yml +0 -0
  16. {pyplumio-0.5.31 → pyplumio-0.5.33}/.github/workflows/documentation.yml +0 -0
  17. {pyplumio-0.5.31 → pyplumio-0.5.33}/.gitignore +0 -0
  18. {pyplumio-0.5.31 → pyplumio-0.5.33}/.pre-commit-config.yaml +0 -0
  19. {pyplumio-0.5.31 → pyplumio-0.5.33}/.vscode/settings.json +0 -0
  20. {pyplumio-0.5.31 → pyplumio-0.5.33}/LICENSE +0 -0
  21. {pyplumio-0.5.31 → pyplumio-0.5.33}/MANIFEST.in +0 -0
  22. {pyplumio-0.5.31 → pyplumio-0.5.33}/PyPlumIO.egg-info/SOURCES.txt +0 -0
  23. {pyplumio-0.5.31 → pyplumio-0.5.33}/PyPlumIO.egg-info/dependency_links.txt +0 -0
  24. {pyplumio-0.5.31 → pyplumio-0.5.33}/PyPlumIO.egg-info/requires.txt +0 -0
  25. {pyplumio-0.5.31 → pyplumio-0.5.33}/PyPlumIO.egg-info/top_level.txt +0 -0
  26. {pyplumio-0.5.31 → pyplumio-0.5.33}/README.md +0 -0
  27. {pyplumio-0.5.31 → pyplumio-0.5.33}/docs/Makefile +0 -0
  28. {pyplumio-0.5.31 → pyplumio-0.5.33}/docs/make.bat +0 -0
  29. {pyplumio-0.5.31 → pyplumio-0.5.33}/docs/source/callbacks.rst +0 -0
  30. {pyplumio-0.5.31 → pyplumio-0.5.33}/docs/source/conf.py +0 -0
  31. {pyplumio-0.5.31 → pyplumio-0.5.33}/docs/source/connecting.rst +0 -0
  32. {pyplumio-0.5.31 → pyplumio-0.5.33}/docs/source/frames.rst +0 -0
  33. {pyplumio-0.5.31 → pyplumio-0.5.33}/docs/source/index.rst +0 -0
  34. {pyplumio-0.5.31 → pyplumio-0.5.33}/docs/source/mixers_thermostats.rst +0 -0
  35. {pyplumio-0.5.31 → pyplumio-0.5.33}/docs/source/protocol.rst +0 -0
  36. {pyplumio-0.5.31 → pyplumio-0.5.33}/docs/source/reading.rst +0 -0
  37. {pyplumio-0.5.31 → pyplumio-0.5.33}/docs/source/schedules.rst +0 -0
  38. {pyplumio-0.5.31 → pyplumio-0.5.33}/docs/source/writing.rst +0 -0
  39. {pyplumio-0.5.31 → pyplumio-0.5.33}/images/ecomax.png +0 -0
  40. {pyplumio-0.5.31 → pyplumio-0.5.33}/images/rs485.png +0 -0
  41. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/__init__.py +0 -0
  42. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/__main__.py +0 -0
  43. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/connection.py +0 -0
  44. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/const.py +0 -0
  45. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/devices/ecomax.py +0 -0
  46. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/devices/ecoster.py +0 -0
  47. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/devices/mixer.py +0 -0
  48. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/devices/thermostat.py +0 -0
  49. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/exceptions.py +0 -0
  50. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/filters.py +0 -0
  51. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/frames/__init__.py +0 -0
  52. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/frames/messages.py +0 -0
  53. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/frames/requests.py +0 -0
  54. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/frames/responses.py +0 -0
  55. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/helpers/__init__.py +0 -0
  56. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/helpers/data_types.py +0 -0
  57. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/helpers/event_manager.py +0 -0
  58. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/helpers/factory.py +0 -0
  59. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/helpers/schedule.py +0 -0
  60. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/helpers/task_manager.py +0 -0
  61. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/helpers/timeout.py +0 -0
  62. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/helpers/uid.py +0 -0
  63. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/protocol.py +0 -0
  64. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/py.typed +0 -0
  65. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/stream.py +0 -0
  66. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/__init__.py +0 -0
  67. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/alerts.py +0 -0
  68. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/boiler_load.py +0 -0
  69. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/boiler_power.py +0 -0
  70. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/ecomax_parameters.py +0 -0
  71. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/fan_power.py +0 -0
  72. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/frame_versions.py +0 -0
  73. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/fuel_consumption.py +0 -0
  74. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/fuel_level.py +0 -0
  75. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/lambda_sensor.py +0 -0
  76. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/mixer_parameters.py +0 -0
  77. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/mixer_sensors.py +0 -0
  78. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/modules.py +0 -0
  79. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/network_info.py +0 -0
  80. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/output_flags.py +0 -0
  81. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/outputs.py +0 -0
  82. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/pending_alerts.py +0 -0
  83. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/product_info.py +0 -0
  84. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/program_version.py +0 -0
  85. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/regulator_data.py +0 -0
  86. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/regulator_data_schema.py +0 -0
  87. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/schedules.py +0 -0
  88. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/statuses.py +0 -0
  89. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/temperatures.py +0 -0
  90. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/thermostat_parameters.py +0 -0
  91. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/structures/thermostat_sensors.py +0 -0
  92. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyplumio/utils.py +0 -0
  93. {pyplumio-0.5.31 → pyplumio-0.5.33}/pyproject.toml +0 -0
  94. {pyplumio-0.5.31 → pyplumio-0.5.33}/requirements.txt +0 -0
  95. {pyplumio-0.5.31 → pyplumio-0.5.33}/requirements_docs.txt +0 -0
  96. {pyplumio-0.5.31 → pyplumio-0.5.33}/requirements_test.txt +0 -0
  97. {pyplumio-0.5.31 → pyplumio-0.5.33}/setup.cfg +0 -0
  98. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/__init__.py +0 -0
  99. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/conftest.py +0 -0
  100. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/frames/test_init.py +0 -0
  101. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/frames/test_messages.py +0 -0
  102. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/frames/test_requests.py +0 -0
  103. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/frames/test_responses.py +0 -0
  104. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/helpers/__init__.py +0 -0
  105. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/helpers/test_data_types.py +0 -0
  106. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/helpers/test_event_manager.py +0 -0
  107. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/helpers/test_factory.py +0 -0
  108. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/helpers/test_schedule.py +0 -0
  109. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/helpers/test_task_manager.py +0 -0
  110. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/helpers/test_timeout.py +0 -0
  111. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/helpers/test_uid.py +0 -0
  112. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/ruff.toml +0 -0
  113. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/test_connection.py +0 -0
  114. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/test_filters.py +0 -0
  115. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/test_init.py +0 -0
  116. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/test_main.py +0 -0
  117. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/test_protocol.py +0 -0
  118. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/test_stream.py +0 -0
  119. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/test_utils.py +0 -0
  120. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/messages/regulator_data.json +0 -0
  121. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/messages/sensor_data.json +0 -0
  122. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/requests/alerts.json +0 -0
  123. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/requests/ecomax_control.json +0 -0
  124. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/requests/ecomax_parameters.json +0 -0
  125. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/requests/mixer_parameters.json +0 -0
  126. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/requests/set_ecomax_parameter.json +0 -0
  127. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/requests/set_mixer_parameter.json +0 -0
  128. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/requests/set_schedule.json +0 -0
  129. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/requests/set_thermostat_parameter.json +0 -0
  130. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/requests/thermostat_parameters.json +0 -0
  131. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/responses/alerts.json +0 -0
  132. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/responses/device_available.json +0 -0
  133. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/responses/ecomax_parameters.json +0 -0
  134. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/responses/mixer_parameters.json +0 -0
  135. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/responses/password.json +0 -0
  136. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/responses/program_version.json +0 -0
  137. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/responses/regulator_data_schema.json +0 -0
  138. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/responses/schedules.json +0 -0
  139. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/responses/thermostat_parameters.json +0 -0
  140. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/responses/uid.json +0 -0
  141. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/unknown/unknown_ecomax_parameter.json +0 -0
  142. {pyplumio-0.5.31 → pyplumio-0.5.33}/tests/testdata/unknown/unknown_mixer_parameter.json +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: PyPlumIO
3
- Version: 0.5.31
3
+ Version: 0.5.33
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: PyPlumIO
3
- Version: 0.5.31
3
+ Version: 0.5.33
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
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.5.31'
16
- __version_tuple__ = version_tuple = (0, 5, 31)
15
+ __version__ = version = '0.5.33'
16
+ __version_tuple__ = version_tuple = (0, 5, 33)
@@ -151,15 +151,12 @@ class PhysicalDevice(Device, ABC):
151
151
 
152
152
  self.subscribe(ATTR_FRAME_VERSIONS, update_frame_versions)
153
153
 
154
- def has_frame_version(self, frame_type: int, version: int | None = None) -> bool:
154
+ def has_frame_version(self, frame_type: FrameType | int, version: int) -> bool:
155
155
  """Return True if frame data is up to date, False otherwise."""
156
- if frame_type not in self._frame_versions:
157
- return False
158
-
159
- if version is None or self._frame_versions[frame_type] == version:
160
- return True
161
-
162
- return False
156
+ return (
157
+ frame_type in self._frame_versions
158
+ and self._frame_versions[frame_type] == version
159
+ )
163
160
 
164
161
  def supports_frame_type(self, frame_type: int) -> bool:
165
162
  """Check if frame type is supported by the device."""
@@ -187,9 +187,6 @@ class Parameter(ABC):
187
187
  def validate(self, value: ParameterValue) -> int:
188
188
  """Validate a parameter value."""
189
189
  value = _normalize_parameter_value(value)
190
- if value == self.values.value:
191
- raise ValueError("Parameter value is unchanged.")
192
-
193
190
  if value < self.values.min_value or value > self.values.max_value:
194
191
  raise ValueError(
195
192
  f"Value must be between '{self.min_value}' and '{self.max_value}'"
@@ -209,6 +206,10 @@ class Parameter(ABC):
209
206
  self, value: Any, retries: int = 5, timeout: float = 5.0
210
207
  ) -> bool:
211
208
  """Try to set a parameter value."""
209
+ if value == self.values.value:
210
+ # Value is unchanged
211
+ return True
212
+
212
213
  self._previous_value = self._values.value
213
214
  self._values.value = value
214
215
  self._pending_update = True
@@ -113,9 +113,6 @@ async def test_number_validate(number: Number) -> None:
113
113
  """Test the number validation."""
114
114
  assert number.validate(2)
115
115
 
116
- with pytest.raises(ValueError):
117
- number.validate(1)
118
-
119
116
  with pytest.raises(ValueError):
120
117
  number.validate(6)
121
118
 
@@ -135,9 +132,6 @@ async def test_switch_validate(switch: Switch) -> None:
135
132
  """Test the switch validation."""
136
133
  assert switch.validate(STATE_ON)
137
134
 
138
- with pytest.raises(ValueError):
139
- assert switch.validate(STATE_OFF)
140
-
141
135
  with pytest.raises(ValueError):
142
136
  switch.validate(2)
143
137
 
@@ -264,6 +258,36 @@ def test_switch_repr(switch: Switch) -> None:
264
258
  )
265
259
 
266
260
 
261
+ @patch("asyncio.Queue.put")
262
+ async def test_number_request_with_unchanged_value(
263
+ mock_put, number: Number, bypass_asyncio_sleep, caplog
264
+ ) -> None:
265
+ """Test that a frame doesn't get dispatched if it's value is unchanged."""
266
+ assert not number.pending_update
267
+ assert not await number.set(5, retries=3)
268
+ assert number.pending_update
269
+ assert mock_put.await_count == 3 # type: ignore [unreachable]
270
+ mock_put.reset_mock()
271
+ assert "Timed out while trying to set 'test_number' parameter" in caplog.text
272
+ await number.set(5)
273
+ mock_put.assert_not_awaited()
274
+
275
+
276
+ @patch("asyncio.Queue.put")
277
+ async def test_switch_request_with_unchanged_value(
278
+ mock_put, switch: Switch, bypass_asyncio_sleep, caplog
279
+ ) -> None:
280
+ """Test that a frame doesn't get dispatched if it's value is unchanged."""
281
+ assert not switch.pending_update
282
+ assert not await switch.set(True, retries=3)
283
+ assert switch.pending_update
284
+ assert mock_put.await_count == 3 # type: ignore [unreachable]
285
+ mock_put.reset_mock()
286
+ assert "Timed out while trying to set 'test_switch' parameter" in caplog.text
287
+ await switch.set(True)
288
+ mock_put.assert_not_awaited()
289
+
290
+
267
291
  @patch("pyplumio.helpers.parameter.Switch.set")
268
292
  async def test_switch_turn_on(mock_set, switch: Switch) -> None:
269
293
  """Test that switch can be turned on."""
@@ -165,15 +165,11 @@ async def test_async_setup_error() -> None:
165
165
 
166
166
  async def test_frame_versions_update(ecomax: EcoMAX) -> None:
167
167
  """Test requesting updated frames."""
168
- assert not ecomax.has_frame_version(RegulatorDataSchemaRequest.frame_type)
169
168
  test_data = load_json_test_data("messages/sensor_data.json")[0]
170
169
  with patch("asyncio.Queue.put_nowait") as mock_put_nowait:
171
170
  ecomax.handle_frame(SensorDataMessage(message=test_data["message"]))
172
171
  await ecomax.wait_until_done()
173
172
 
174
- assert not ecomax.has_frame_version(RegulatorDataSchemaRequest.frame_type, 0)
175
- assert ecomax.has_frame_version(RegulatorDataSchemaRequest.frame_type, 45559)
176
-
177
173
  mock_put_nowait.assert_has_calls(
178
174
  [
179
175
  call(RegulatorDataSchemaRequest(recipient=DeviceType.ECOMAX)),
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