PyPlumIO 0.5.30__py3-none-any.whl → 0.5.32__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
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: PyPlumIO
3
- Version: 0.5.30
3
+ Version: 0.5.32
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
@@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3.9
17
17
  Classifier: Programming Language :: Python :: 3.10
18
18
  Classifier: Programming Language :: Python :: 3.11
19
19
  Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
20
21
  Classifier: Topic :: Software Development :: Libraries
21
22
  Classifier: Topic :: Home Automation
22
23
  Requires-Python: >=3.9
@@ -27,14 +28,14 @@ Requires-Dist: pyserial-asyncio==0.6
27
28
  Requires-Dist: typing-extensions==4.12.2
28
29
  Provides-Extra: test
29
30
  Requires-Dist: codespell==2.3.0; extra == "test"
30
- Requires-Dist: coverage==7.6.8; extra == "test"
31
- Requires-Dist: mypy==1.13.0; extra == "test"
31
+ Requires-Dist: coverage==7.6.10; extra == "test"
32
+ Requires-Dist: mypy==1.14.1; extra == "test"
32
33
  Requires-Dist: pyserial-asyncio-fast==0.14; extra == "test"
33
34
  Requires-Dist: pytest==8.3.4; extra == "test"
34
- Requires-Dist: pytest-asyncio==0.24.0; extra == "test"
35
- Requires-Dist: ruff==0.8.1; extra == "test"
35
+ Requires-Dist: pytest-asyncio==0.25.2; extra == "test"
36
+ Requires-Dist: ruff==0.9.2; extra == "test"
36
37
  Requires-Dist: tox==4.23.2; extra == "test"
37
- Requires-Dist: types-pyserial==3.5.0.20240826; extra == "test"
38
+ Requires-Dist: types-pyserial==3.5.0.20241221; extra == "test"
38
39
  Provides-Extra: docs
39
40
  Requires-Dist: sphinx==8.1.3; extra == "docs"
40
41
  Requires-Dist: sphinx_rtd_theme==3.0.2; extra == "docs"
@@ -1,15 +1,15 @@
1
1
  pyplumio/__init__.py,sha256=ditJTIOFGJDg60atHzOpiggdUrZHpSynno7MtpZUGVk,3299
2
2
  pyplumio/__main__.py,sha256=3IwHHSq-iay5FaeMc95klobe-xv82yydSKcBE7BFZ6M,500
3
- pyplumio/_version.py,sha256=PRcySwknPDLJzIxasFyVZNYI8LFj_28fjnJMHK2q0Ko,413
3
+ pyplumio/_version.py,sha256=G1xfKG6efA0TsiygMdo8hJeE0DmA_V8-y12DGNZw7do,413
4
4
  pyplumio/connection.py,sha256=6mUbcjGxxEhMVIbzZgCqH-Ez-fcYoRj7ZbVSzpikpNA,5949
5
5
  pyplumio/const.py,sha256=LyXa5aVy2KxnZq7H7F8s5SYsAgEC2UzZYMMRauliB2E,5502
6
6
  pyplumio/exceptions.py,sha256=Wn-y5AJ5xfaBlHhTUVKB27_0Us8_OVHqh-sicnr9sYA,700
7
- pyplumio/filters.py,sha256=KK_AV_EHy5gj9s9BNZbn9i0RnT3uZsdEg6gdve1WYrY,11152
7
+ pyplumio/filters.py,sha256=AMW1zHQ1YjJfHX7e87Dhv7AGixJ3y9Vn-_JAQn7vIsg,12526
8
8
  pyplumio/protocol.py,sha256=VRxrj8vZ1FMawqblKkyxg_V61TBSvVynd9u0JXYnMUU,8090
9
9
  pyplumio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  pyplumio/stream.py,sha256=mtMpnUR3TfEmL5JUGXr6GnpPGBwzCokqIKDWp4vYiVg,4654
11
11
  pyplumio/utils.py,sha256=TnBzRopinyp92wruguijxcIYmaeyNVTFX0dygI5FCMU,823
12
- pyplumio/devices/__init__.py,sha256=YN09bGsyJ5WVmF8_-veUckqUl57eBwmfNr8M5qhyqy0,8149
12
+ pyplumio/devices/__init__.py,sha256=BEUpL2XxEk4YDfp4w0VX_LI4JQwK27eGWoJ6al_e1nE,8038
13
13
  pyplumio/devices/ecomax.py,sha256=ybFLJN7O3unBcyzuVmYTssBv86bPiiTGvFpFJezwUE4,15478
14
14
  pyplumio/devices/ecoster.py,sha256=jNWli7ye9T6yfkcFJZhhUHH7KOv-L6AgYFp_dKyv3OM,263
15
15
  pyplumio/devices/mixer.py,sha256=CnHWrJELtFgs2YTHGpQwKr2UTRdetX76OvLBA2PH-fs,3207
@@ -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=6ArzJDq3MiiMaRpMEP0kC6wJWsoqOqe32V1RCxg1478,1005
25
- pyplumio/helpers/parameter.py,sha256=yO3KSX8FtU-dMe5FzNW-RXs5yW-lYu2F5Po-4ghcSnM,12533
25
+ pyplumio/helpers/parameter.py,sha256=I0LJ4d29kLRt83ukfumWP6NJXfEuPS7vRlS_1HeZHT4,12306
26
26
  pyplumio/helpers/schedule.py,sha256=PnVEkgthg6tHpHvZK9fXJz9VKNDyQ_7BFT4TTVEwNhI,5310
27
27
  pyplumio/helpers/task_manager.py,sha256=HAd69yGTRL0zQsu-ywnbLu1UXiJzgHWuhYWA--vs4lQ,1181
28
28
  pyplumio/helpers/timeout.py,sha256=JAhWNtIpcXyVILIwHWVy5mYofqbbRDGKLdTUKkQuajs,772
@@ -31,13 +31,13 @@ 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=ki9YSzVRhCD_rYHFogJoyk0NwyNlWdZrHcp-rrCuKCU,28440
34
+ pyplumio/structures/ecomax_parameters.py,sha256=wLwhTdKee-UtCU5NuRfOHRPvnjDOtDNUDeUgeO0VH8w,27974
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
38
38
  pyplumio/structures/fuel_level.py,sha256=mJpp1dnRD1wXi_6EyNX7TNXosjcr905rSHOnuZ5VD74,1069
39
39
  pyplumio/structures/lambda_sensor.py,sha256=JNSCiBJoM8Uk3OGbmFIigaLOntQST5U_UrmCpaQBlM0,1595
40
- pyplumio/structures/mixer_parameters.py,sha256=S_YOigzM9TsdEjk5EluME5fJ8owO84-xOFT9tTdBgEo,9553
40
+ pyplumio/structures/mixer_parameters.py,sha256=idF3tYukfAz1EM1CE-hZBjjmGrNZN6X1MlcZr3FHrzA,9089
41
41
  pyplumio/structures/mixer_sensors.py,sha256=-cN7U-Fr2fmAQ5McQL7bZUC8CFlb1y8TN0f_dqy3UK0,2312
42
42
  pyplumio/structures/modules.py,sha256=oXUIqrOAV1dZzBV5zUH3HDUSFvNOjpUSx0TF9nZVnbs,2569
43
43
  pyplumio/structures/network_info.py,sha256=kPxmIaDGm5SyLRKVFzcrODlUtB0u5JjiZqekoKSyDpA,4159
@@ -48,13 +48,13 @@ pyplumio/structures/product_info.py,sha256=uiEN6DFQlzmBvQByTirFzXQShoex0YGdFS9WI
48
48
  pyplumio/structures/program_version.py,sha256=R-medELYHDlk_ALsw5HOVbZRb7JD3yBUsGwqwVCjrkU,2550
49
49
  pyplumio/structures/regulator_data.py,sha256=z2mSE-cxImn8YRr_yZCcDlIbXnKdETkN7GigV5vEJqA,2265
50
50
  pyplumio/structures/regulator_data_schema.py,sha256=XM6M9ep3NyogbLPqp88mMTg8Sa9e5SFzV5I5pSYw5GY,1487
51
- pyplumio/structures/schedules.py,sha256=rKPWC5qcKAh6xxs91oY23NqQcWby8e3gXrD6qJAVDGo,7153
51
+ pyplumio/structures/schedules.py,sha256=_D8HmxMVvAAPb0cc_xSxXFRNwR9u-RWuyTy0Z5KscUk,6717
52
52
  pyplumio/structures/statuses.py,sha256=wkoynyMRr1VREwfBC6vU48kPA8ZQ83pcXuciy2xHJrk,1166
53
53
  pyplumio/structures/temperatures.py,sha256=1CDzehNmbALz1Jyt_9gZNIk52q6Wv-xQXjijVDCVYec,2337
54
- pyplumio/structures/thermostat_parameters.py,sha256=6r8_EU9T1IJ0vzZMduiLzsAaaWr6cKW_zHHAGsfGZI4,8804
54
+ pyplumio/structures/thermostat_parameters.py,sha256=QA-ZyulBG3P10sqgdI7rmpQYlKm9SJIXxBxAXs8Bwow,8295
55
55
  pyplumio/structures/thermostat_sensors.py,sha256=8e1TxYIJTQKT0kIGO9gG4hGdLOBUpIhiPToQyOMyeNE,3237
56
- PyPlumIO-0.5.30.dist-info/LICENSE,sha256=m-UuZFjXJ22uPTGm9kSHS8bqjsf5T8k2wL9bJn1Y04o,1088
57
- PyPlumIO-0.5.30.dist-info/METADATA,sha256=KMMtx2B4gTlnFBoLVzVHGs75Od9qf6BN1tH3pqeYgqM,5458
58
- PyPlumIO-0.5.30.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
59
- PyPlumIO-0.5.30.dist-info/top_level.txt,sha256=kNBz9UPPkPD9teDn3U_sEy5LjzwLm9KfADCXtBlbw8A,9
60
- PyPlumIO-0.5.30.dist-info/RECORD,,
56
+ PyPlumIO-0.5.32.dist-info/LICENSE,sha256=m-UuZFjXJ22uPTGm9kSHS8bqjsf5T8k2wL9bJn1Y04o,1088
57
+ PyPlumIO-0.5.32.dist-info/METADATA,sha256=9VeND8m5qvmZeIwWG3ne9GcBET6IAr5aDdzNtMNbHT8,5510
58
+ PyPlumIO-0.5.32.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
59
+ PyPlumIO-0.5.32.dist-info/top_level.txt,sha256=kNBz9UPPkPD9teDn3U_sEy5LjzwLm9KfADCXtBlbw8A,9
60
+ PyPlumIO-0.5.32.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
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.30'
16
- __version_tuple__ = version_tuple = (0, 5, 30)
15
+ __version__ = version = '0.5.32'
16
+ __version_tuple__ = version_tuple = (0, 5, 32)
@@ -107,9 +107,6 @@ class Device(ABC, EventManager):
107
107
  this value is used to determine failure when
108
108
  retrying and doesn't block, defaults to `None`
109
109
  :type timeout: float, optional
110
- :return: `True` if parameter was successfully set, `False`
111
- otherwise.
112
- :rtype: bool
113
110
  """
114
111
  self.create_task(self.set(name, value, retries, timeout))
115
112
 
pyplumio/filters.py CHANGED
@@ -125,6 +125,52 @@ class Filter(ABC):
125
125
  """Set a new value for the callback."""
126
126
 
127
127
 
128
+ class _Clamp(Filter):
129
+ """Represents a clamp filter.
130
+
131
+ Calls callback with a value clamped between specified boundaries.
132
+ """
133
+
134
+ __slots__ = ("_min_value", "_max_value")
135
+
136
+ _min_value: float
137
+ _max_value: float
138
+
139
+ def __init__(self, callback: Callback, min_value: float, max_value: float) -> None:
140
+ """Initialize a new clamp filter."""
141
+ super().__init__(callback)
142
+ self._min_value = min_value
143
+ self._max_value = max_value
144
+
145
+ async def __call__(self, new_value: Any) -> Any:
146
+ """Set a new value for the callback."""
147
+ if new_value < self._min_value:
148
+ return await self._callback(self._min_value)
149
+
150
+ if new_value > self._max_value:
151
+ return await self._callback(self._max_value)
152
+
153
+ return await self._callback(new_value)
154
+
155
+
156
+ def clamp(callback: Callback, min_value: float, max_value: float) -> _Clamp:
157
+ """Return a clamp filter.
158
+
159
+ A callback function will be called with value clamped between
160
+ specified boundaries.
161
+
162
+ :param callback: A callback function to be awaited on new value
163
+ :type callback: Callback
164
+ :param min_value: A lower boundary
165
+ :type min_value: float
166
+ :param max_value: An upper boundary
167
+ :type max_value: float
168
+ :return: An instance of callable filter
169
+ :rtype: _Clamp
170
+ """
171
+ return _Clamp(callback, min_value, max_value)
172
+
173
+
128
174
  class _OnChange(Filter):
129
175
  """Represents a value changed filter.
130
176
 
@@ -151,7 +197,7 @@ def on_change(callback: Callback) -> _OnChange:
151
197
 
152
198
  :param callback: A callback function to be awaited on value change
153
199
  :type callback: Callback
154
- :return: A instance of callable filter
200
+ :return: An instance of callable filter
155
201
  :rtype: _OnChange
156
202
  """
157
203
  return _OnChange(callback)
@@ -201,7 +247,7 @@ def debounce(callback: Callback, min_calls: int) -> _Debounce:
201
247
  :param min_calls: Value shouldn't change for this amount of
202
248
  filter calls
203
249
  :type min_calls: int
204
- :return: A instance of callable filter
250
+ :return: An instance of callable filter
205
251
  :rtype: _Debounce
206
252
  """
207
253
  return _Debounce(callback, min_calls)
@@ -248,7 +294,7 @@ def throttle(callback: Callback, seconds: float) -> _Throttle:
248
294
  :param seconds: A callback will be awaited at most once per
249
295
  this amount of seconds
250
296
  :type seconds: float
251
- :return: A instance of callable filter
297
+ :return: An instance of callable filter
252
298
  :rtype: _Throttle
253
299
  """
254
300
  return _Throttle(callback, seconds)
@@ -285,7 +331,7 @@ def delta(callback: Callback) -> _Delta:
285
331
  :param callback: A callback function that will be awaited with
286
332
  difference between values in two subsequent calls
287
333
  :type callback: Callback
288
- :return: A instance of callable filter
334
+ :return: An instance of callable filter
289
335
  :rtype: _Delta
290
336
  """
291
337
  return _Delta(callback)
@@ -340,7 +386,7 @@ def aggregate(callback: Callback, seconds: float) -> _Aggregate:
340
386
  :param seconds: A callback will be awaited with a sum of values
341
387
  aggregated over this amount of seconds.
342
388
  :type seconds: float
343
- :return: A instance of callable filter
389
+ :return: An instance of callable filter
344
390
  :rtype: _Aggregate
345
391
  """
346
392
  return _Aggregate(callback, seconds)
@@ -382,7 +428,7 @@ def custom(callback: Callback, filter_fn: Callable[[Any], bool]) -> _Custom:
382
428
  :param filter_fn: Filter function, that will be called with a
383
429
  value and should return `True` to await filter's callback
384
430
  :type filter_fn: Callable[[Any], bool]
385
- :return: A instance of callable filter
431
+ :return: An instance of callable filter
386
432
  :rtype: _Custom
387
433
  """
388
434
  return _Custom(callback, filter_fn)
@@ -184,16 +184,32 @@ class Parameter(ABC):
184
184
  )
185
185
  return type(self)(self.device, self.description, values)
186
186
 
187
- async def set(self, value: Any, retries: int = 5, timeout: float = 5.0) -> bool:
188
- """Set a parameter value."""
189
- if (value := _normalize_parameter_value(value)) == self.values.value:
190
- return True
191
-
187
+ def validate(self, value: ParameterValue) -> int:
188
+ """Validate a parameter value."""
189
+ value = _normalize_parameter_value(value)
192
190
  if value < self.values.min_value or value > self.values.max_value:
193
191
  raise ValueError(
194
192
  f"Value must be between '{self.min_value}' and '{self.max_value}'"
195
193
  )
196
194
 
195
+ return value
196
+
197
+ async def set(self, value: Any, retries: int = 5, timeout: float = 5.0) -> bool:
198
+ """Set a parameter value."""
199
+ return await self._try_set(self.validate(value), retries, timeout)
200
+
201
+ def set_nowait(self, value: Any, retries: int = 5, timeout: float = 5.0) -> None:
202
+ """Set a parameter value without waiting."""
203
+ self.device.create_task(self._try_set(self.validate(value), retries, timeout))
204
+
205
+ async def _try_set(
206
+ self, value: Any, retries: int = 5, timeout: float = 5.0
207
+ ) -> bool:
208
+ """Try to set a parameter value."""
209
+ if value == self.values.value:
210
+ # Value is unchanged
211
+ return True
212
+
197
213
  self._previous_value = self._values.value
198
214
  self._values.value = value
199
215
  self._pending_update = True
@@ -206,9 +222,6 @@ class Parameter(ABC):
206
222
  return False
207
223
 
208
224
  await self.device.queue.put(await self.create_request())
209
- if not self.is_tracking_changes:
210
- await self.force_refresh()
211
-
212
225
  await asyncio.sleep(timeout)
213
226
  retries -= 1
214
227
 
@@ -221,15 +234,6 @@ class Parameter(ABC):
221
234
 
222
235
  self._values = values
223
236
 
224
- async def force_refresh(self) -> None:
225
- """Refresh the parameter from remote."""
226
- await self.device.queue.put(await self.create_refresh_request())
227
-
228
- @property
229
- def is_tracking_changes(self) -> bool:
230
- """Return True if remote's tracking changes, False otherwise."""
231
- return False
232
-
233
237
  @property
234
238
  def pending_update(self) -> bool:
235
239
  """Check if parameter is pending update on the device."""
@@ -278,10 +282,6 @@ class Parameter(ABC):
278
282
  async def create_request(self) -> Request:
279
283
  """Create a request to change the parameter."""
280
284
 
281
- @abstractmethod
282
- async def create_refresh_request(self) -> Request:
283
- """Create a request to refresh the parameter."""
284
-
285
285
 
286
286
  @dataslots
287
287
  @dataclass
@@ -308,16 +308,12 @@ class Number(Parameter):
308
308
  self, value: int | float, retries: int = 5, timeout: float = 5.0
309
309
  ) -> None:
310
310
  """Set a parameter value without waiting."""
311
- self.device.create_task(self.set(value, retries, timeout))
311
+ super().set_nowait(value, retries, timeout)
312
312
 
313
313
  async def create_request(self) -> Request:
314
314
  """Create a request to change the number."""
315
315
  return Request()
316
316
 
317
- async def create_refresh_request(self) -> Request:
318
- """Create a request to refresh the number."""
319
- return Request()
320
-
321
317
  @property
322
318
  def value(self) -> int | float:
323
319
  """Return the value."""
@@ -362,7 +358,7 @@ class Switch(Parameter):
362
358
  self, value: bool | Literal["off", "on"], retries: int = 5, timeout: float = 5.0
363
359
  ) -> None:
364
360
  """Set a switch value without waiting."""
365
- self.device.create_task(self.set(value, retries, timeout))
361
+ super().set_nowait(value, retries, timeout)
366
362
 
367
363
  async def turn_on(self) -> bool:
368
364
  """Set a switch value to 'on'.
@@ -394,10 +390,6 @@ class Switch(Parameter):
394
390
  """Create a request to change the switch."""
395
391
  return Request()
396
392
 
397
- async def create_refresh_request(self) -> Request:
398
- """Create a request to refresh the switch."""
399
- return Request()
400
-
401
393
  @property
402
394
  def value(self) -> Literal["off", "on"]:
403
395
  """Return the value."""
@@ -83,17 +83,6 @@ class EcomaxParameter(Parameter):
83
83
  data={ATTR_INDEX: self._index, ATTR_VALUE: self.values.value},
84
84
  )
85
85
 
86
- async def create_refresh_request(self) -> Request:
87
- """Create a request to refresh the parameter."""
88
- return await Request.create(
89
- FrameType.REQUEST_ECOMAX_PARAMETERS, recipient=self.device.address
90
- )
91
-
92
- @property
93
- def is_tracking_changes(self) -> bool:
94
- """Return True if remote's tracking changes, False otherwise."""
95
- return self.device.has_frame_version(FrameType.REQUEST_ECOMAX_PARAMETERS)
96
-
97
86
 
98
87
  @dataslots
99
88
  @dataclass
@@ -479,8 +468,8 @@ ECOMAX_PARAMETERS: dict[ProductType, tuple[EcomaxParameterDescription, ...]] = {
479
468
  ),
480
469
  EcomaxNumberDescription(
481
470
  name="max_fuel_flow",
482
- multiplier=0.1,
483
- unit_of_measurement=UnitOfMeasurement.KILOGRAMS_PER_HOUR,
471
+ multiplier=20,
472
+ unit_of_measurement=UnitOfMeasurement.GRAMS,
484
473
  ),
485
474
  EcomaxNumberDescription(
486
475
  name="feeder_calibration",
@@ -65,17 +65,6 @@ class MixerParameter(Parameter):
65
65
  },
66
66
  )
67
67
 
68
- async def create_refresh_request(self) -> Request:
69
- """Create a request to refresh the parameter."""
70
- return await Request.create(
71
- FrameType.REQUEST_MIXER_PARAMETERS, recipient=self.device.parent.address
72
- )
73
-
74
- @property
75
- def is_tracking_changes(self) -> bool:
76
- """Return True if remote's tracking changes, False otherwise."""
77
- return self.device.parent.has_frame_version(FrameType.REQUEST_MIXER_PARAMETERS)
78
-
79
68
 
80
69
  @dataslots
81
70
  @dataclass
@@ -107,17 +107,6 @@ class ScheduleParameter(Parameter):
107
107
  data=collect_schedule_data(schedule_name, self.device),
108
108
  )
109
109
 
110
- async def create_refresh_request(self) -> Request:
111
- """Create a request to refresh the parameter."""
112
- return await Request.create(
113
- FrameType.REQUEST_SCHEDULES, recipient=self.device.address
114
- )
115
-
116
- @property
117
- def is_tracking_changes(self) -> bool:
118
- """Return True if remote's tracking changes, False otherwise."""
119
- return self.device.has_frame_version(FrameType.REQUEST_SCHEDULES)
120
-
121
110
 
122
111
  @dataslots
123
112
  @dataclass
@@ -86,20 +86,6 @@ class ThermostatParameter(Parameter):
86
86
  },
87
87
  )
88
88
 
89
- async def create_refresh_request(self) -> Request:
90
- """Create a request to refresh the parameter."""
91
- return await Request.create(
92
- FrameType.REQUEST_THERMOSTAT_PARAMETERS,
93
- recipient=self.device.parent.address,
94
- )
95
-
96
- @property
97
- def is_tracking_changes(self) -> bool:
98
- """Return True if remote's tracking changes, False otherwise."""
99
- return self.device.parent.has_frame_version(
100
- FrameType.REQUEST_THERMOSTAT_PARAMETERS
101
- )
102
-
103
89
 
104
90
  @dataslots
105
91
  @dataclass