PyPlumIO 0.5.36__py3-none-any.whl → 0.5.37__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: PyPlumIO
3
- Version: 0.5.36
3
+ Version: 0.5.37
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
@@ -27,15 +27,15 @@ Requires-Dist: dataslots==1.2.0
27
27
  Requires-Dist: pyserial-asyncio==0.6
28
28
  Requires-Dist: typing-extensions==4.12.2
29
29
  Provides-Extra: test
30
- Requires-Dist: codespell==2.4.0; extra == "test"
30
+ Requires-Dist: codespell==2.4.1; extra == "test"
31
31
  Requires-Dist: coverage==7.6.10; extra == "test"
32
32
  Requires-Dist: mypy==1.14.1; extra == "test"
33
33
  Requires-Dist: pyserial-asyncio-fast==0.14; extra == "test"
34
34
  Requires-Dist: pytest==8.3.4; extra == "test"
35
- Requires-Dist: pytest-asyncio==0.25.2; extra == "test"
36
- Requires-Dist: ruff==0.9.3; extra == "test"
35
+ Requires-Dist: pytest-asyncio==0.25.3; extra == "test"
36
+ Requires-Dist: ruff==0.9.4; extra == "test"
37
37
  Requires-Dist: tox==4.24.1; extra == "test"
38
- Requires-Dist: types-pyserial==3.5.0.20250124; extra == "test"
38
+ Requires-Dist: types-pyserial==3.5.0.20250130; extra == "test"
39
39
  Provides-Extra: docs
40
40
  Requires-Dist: sphinx==8.1.3; extra == "docs"
41
41
  Requires-Dist: sphinx_rtd_theme==3.0.2; extra == "docs"
@@ -49,8 +49,8 @@ Requires-Dist: tomli==2.2.1; extra == "dev"
49
49
  [![PyPI version](https://badge.fury.io/py/PyPlumIO.svg)](https://badge.fury.io/py/PyPlumIO)
50
50
  [![PyPI Supported Python Versions](https://img.shields.io/pypi/pyversions/pyplumio.svg)](https://pypi.python.org/pypi/pyplumio/)
51
51
  [![PyPlumIO CI](https://github.com/denpamusic/PyPlumIO/actions/workflows/ci.yml/badge.svg)](https://github.com/denpamusic/PyPlumIO/actions/workflows/ci.yml)
52
- [![Maintainability](https://api.codeclimate.com/v1/badges/9f275fbc50fe9082a909/maintainability)](https://codeclimate.com/github/denpamusic/PyPlumIO/maintainability)
53
- [![Test Coverage](https://api.codeclimate.com/v1/badges/9f275fbc50fe9082a909/test_coverage)](https://codeclimate.com/github/denpamusic/PyPlumIO/test_coverage)
52
+ [![Maintainability](https://api.codeclimate.com/v1/badges/e802127770476b7ba6fd/maintainability)](https://codeclimate.com/github/denpamusic/PyPlumIO/maintainability)
53
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/e802127770476b7ba6fd/test_coverage)](https://codeclimate.com/github/denpamusic/PyPlumIO/test_coverage)
54
54
  [![stability-release-candidate](https://img.shields.io/badge/stability-pre--release-48c9b0.svg)](https://guidelines.denpa.pro/stability#release-candidate)
55
55
  [![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)
56
56
 
@@ -1,6 +1,6 @@
1
1
  pyplumio/__init__.py,sha256=3ibJ43RIdfFrWp1PAsQixybAA--NPRw43B5OdLOwsU8,3319
2
2
  pyplumio/__main__.py,sha256=3IwHHSq-iay5FaeMc95klobe-xv82yydSKcBE7BFZ6M,500
3
- pyplumio/_version.py,sha256=gzGL-qBNqAXMnFJc3Sr0_AdQLS33_rosqhjOurMUizQ,413
3
+ pyplumio/_version.py,sha256=orZLgglRSt7G3Yf4YysqzFGUuXQI2XkO9JT2vDRdeJc,413
4
4
  pyplumio/connection.py,sha256=-dbrIK6ewoYNeBQod9ZmXT8JkxMKbcS6nosINFsg9RI,5972
5
5
  pyplumio/const.py,sha256=LyXa5aVy2KxnZq7H7F8s5SYsAgEC2UzZYMMRauliB2E,5502
6
6
  pyplumio/exceptions.py,sha256=_B_0EgxDxd2XyYv3WpZM733q0cML5m6J-f55QOvYRpI,996
@@ -22,7 +22,7 @@ pyplumio/helpers/__init__.py,sha256=H2xxdkF-9uADLwEbfBUoxNTdwru3L5Z2cfJjgsuRsn0,
22
22
  pyplumio/helpers/data_types.py,sha256=nB3afOLmppgSCWkZoX1-1yWPNMMNSem77x7XQ1Mi8H8,9103
23
23
  pyplumio/helpers/event_manager.py,sha256=xQOfiP_nP1Pz5zhB6HU5gXyyJXjhisYshL8_HRxDgt8,6412
24
24
  pyplumio/helpers/factory.py,sha256=v07s9DyihfkNUzt7ndyJbNd_DLS8UpRkut_xkGrbi6c,1123
25
- pyplumio/helpers/parameter.py,sha256=ubqgleTPT-m3yxhJkQWoLjkbjCdwOeaNhdA7O66l47Q,12425
25
+ pyplumio/helpers/parameter.py,sha256=LoTYAtSLv2bGjEMABn7S1Ycqd_DzcMt_6UPG8frFZ-8,12740
26
26
  pyplumio/helpers/schedule.py,sha256=0lkghnnpQRdRtgqoNv7PnHMYYJpJNMHl9PR4_SaHB8w,5374
27
27
  pyplumio/helpers/task_manager.py,sha256=HAd69yGTRL0zQsu-ywnbLu1UXiJzgHWuhYWA--vs4lQ,1181
28
28
  pyplumio/helpers/timeout.py,sha256=JAhWNtIpcXyVILIwHWVy5mYofqbbRDGKLdTUKkQuajs,772
@@ -31,7 +31,7 @@ pyplumio/structures/__init__.py,sha256=EjK-5qJZ0F7lpP2b6epvTMg9cIBl4Kn91nqNkEcLw
31
31
  pyplumio/structures/alerts.py,sha256=8ievMl5_tUBlnTLCiZoIloucIngCcoAYy6uI9sSXrt0,3664
32
32
  pyplumio/structures/boiler_load.py,sha256=p3mOzZUU-g7A2tG_yp8podEqpI81hlsOZmHELyPNRY8,838
33
33
  pyplumio/structures/boiler_power.py,sha256=72qsvccg49FdRdXv2f2K5sGpjT7wAOLFjlIGWpO-DVg,901
34
- pyplumio/structures/ecomax_parameters.py,sha256=wLwhTdKee-UtCU5NuRfOHRPvnjDOtDNUDeUgeO0VH8w,27974
34
+ pyplumio/structures/ecomax_parameters.py,sha256=4hsLM8pgcLrfYL0loLqTH4kMSdVzOThu5SL_QTodSYs,27997
35
35
  pyplumio/structures/fan_power.py,sha256=Q5fv-7_2NVuLeQPIVIylvgN7M8-a9D8rRUE0QGjyS3w,871
36
36
  pyplumio/structures/frame_versions.py,sha256=hbcVuhuPNy5qd39Vk7w4WdPCW-TNx1cAYWzA2mXocyk,1548
37
37
  pyplumio/structures/fuel_consumption.py,sha256=_p2dI4H67Eopn7IF0Gj77A8c_8lNKhhDDAtmugxLd4s,976
@@ -53,8 +53,8 @@ pyplumio/structures/statuses.py,sha256=wkoynyMRr1VREwfBC6vU48kPA8ZQ83pcXuciy2xHJ
53
53
  pyplumio/structures/temperatures.py,sha256=1CDzehNmbALz1Jyt_9gZNIk52q6Wv-xQXjijVDCVYec,2337
54
54
  pyplumio/structures/thermostat_parameters.py,sha256=QA-ZyulBG3P10sqgdI7rmpQYlKm9SJIXxBxAXs8Bwow,8295
55
55
  pyplumio/structures/thermostat_sensors.py,sha256=8e1TxYIJTQKT0kIGO9gG4hGdLOBUpIhiPToQyOMyeNE,3237
56
- PyPlumIO-0.5.36.dist-info/LICENSE,sha256=m-UuZFjXJ22uPTGm9kSHS8bqjsf5T8k2wL9bJn1Y04o,1088
57
- PyPlumIO-0.5.36.dist-info/METADATA,sha256=F7biRxVKU0EPVYWi2uJXZYfVmvwM5j3C_o-O2aoJjQI,5510
58
- PyPlumIO-0.5.36.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
59
- PyPlumIO-0.5.36.dist-info/top_level.txt,sha256=kNBz9UPPkPD9teDn3U_sEy5LjzwLm9KfADCXtBlbw8A,9
60
- PyPlumIO-0.5.36.dist-info/RECORD,,
56
+ PyPlumIO-0.5.37.dist-info/LICENSE,sha256=m-UuZFjXJ22uPTGm9kSHS8bqjsf5T8k2wL9bJn1Y04o,1088
57
+ PyPlumIO-0.5.37.dist-info/METADATA,sha256=CNXGeqKEbJVnM1LlpzV33S7TDJXCJYlrY8pU8n_4w1w,5510
58
+ PyPlumIO-0.5.37.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
59
+ PyPlumIO-0.5.37.dist-info/top_level.txt,sha256=kNBz9UPPkPD9teDn3U_sEy5LjzwLm9KfADCXtBlbw8A,9
60
+ PyPlumIO-0.5.37.dist-info/RECORD,,
pyplumio/_version.py CHANGED
@@ -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.36'
16
- __version_tuple__ = version_tuple = (0, 5, 36)
15
+ __version__ = version = '0.5.37'
16
+ __version_tuple__ = version_tuple = (0, 5, 37)
@@ -28,7 +28,7 @@ def unpack_parameter(
28
28
  data: bytearray, offset: int = 0, size: int = 1
29
29
  ) -> ParameterValues | None:
30
30
  """Unpack a device parameter."""
31
- if not validate_parameter(data[offset : offset + size * 3]):
31
+ if not is_valid_parameter(data[offset : offset + size * 3]):
32
32
  return None
33
33
 
34
34
  value = data[offset : offset + size]
@@ -42,7 +42,7 @@ def unpack_parameter(
42
42
  )
43
43
 
44
44
 
45
- def validate_parameter(data: bytearray) -> bool:
45
+ def is_valid_parameter(data: bytearray) -> bool:
46
46
  """Check if parameter contains any bytes besides 0xFF."""
47
47
  return any(x for x in data if x != BYTE_UNDEFINED)
48
48
 
@@ -75,6 +75,7 @@ class ParameterDescription:
75
75
  """Represents a parameter description."""
76
76
 
77
77
  name: str
78
+ optimistic: bool = False
78
79
 
79
80
 
80
81
  class Parameter(ABC):
@@ -204,13 +205,21 @@ class Parameter(ABC):
204
205
  self, value: int, retries: int = 5, timeout: float = 5.0
205
206
  ) -> bool:
206
207
  """Attempt to update a parameter value on the remote device."""
208
+ _LOGGER.debug(
209
+ "Attempting to update '%s' parameter to %d", self.description.name, value
210
+ )
207
211
  if value == self.values.value:
208
212
  # Value is unchanged
209
213
  return True
210
214
 
211
- self._pending_update = True
212
215
  self._values.value = value
213
- initial_retries = retries
216
+ request = await self.create_request()
217
+ if self.description.optimistic or not (initial_retries := retries):
218
+ # No retries
219
+ await self.device.queue.put(request)
220
+ return True
221
+
222
+ self._pending_update = True
214
223
  while self.pending_update:
215
224
  if retries <= 0:
216
225
  _LOGGER.warning(
@@ -220,7 +229,7 @@ class Parameter(ABC):
220
229
  )
221
230
  return False
222
231
 
223
- await self.device.queue.put(await self.create_request())
232
+ await self.device.queue.put(request)
224
233
  await asyncio.sleep(timeout)
225
234
  retries -= 1
226
235
 
@@ -825,7 +825,9 @@ ECOMAX_PARAMETERS: dict[ProductType, tuple[EcomaxParameterDescription, ...]] = {
825
825
  ),
826
826
  }
827
827
 
828
- ECOMAX_CONTROL_PARAMETER = EcomaxSwitchDescription(name=ATTR_ECOMAX_CONTROL)
828
+ ECOMAX_CONTROL_PARAMETER = EcomaxSwitchDescription(
829
+ name=ATTR_ECOMAX_CONTROL, optimistic=True
830
+ )
829
831
  THERMOSTAT_PROFILE_PARAMETER = EcomaxNumberDescription(name=ATTR_THERMOSTAT_PROFILE)
830
832
 
831
833