PyPlumIO 0.5.22__py3-none-any.whl → 0.5.23__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.
- {PyPlumIO-0.5.22.dist-info → PyPlumIO-0.5.23.dist-info}/METADATA +10 -8
- {PyPlumIO-0.5.22.dist-info → PyPlumIO-0.5.23.dist-info}/RECORD +18 -18
- {PyPlumIO-0.5.22.dist-info → PyPlumIO-0.5.23.dist-info}/WHEEL +1 -1
- pyplumio/_version.py +2 -2
- pyplumio/connection.py +1 -2
- pyplumio/devices/__init__.py +2 -2
- pyplumio/devices/ecomax.py +17 -17
- pyplumio/devices/mixer.py +6 -6
- pyplumio/devices/thermostat.py +6 -6
- pyplumio/helpers/event_manager.py +19 -10
- pyplumio/helpers/parameter.py +114 -55
- pyplumio/protocol.py +4 -3
- pyplumio/structures/ecomax_parameters.py +229 -208
- pyplumio/structures/mixer_parameters.py +80 -61
- pyplumio/structures/schedules.py +35 -15
- pyplumio/structures/thermostat_parameters.py +61 -42
- {PyPlumIO-0.5.22.dist-info → PyPlumIO-0.5.23.dist-info}/LICENSE +0 -0
- {PyPlumIO-0.5.22.dist-info → PyPlumIO-0.5.23.dist-info}/top_level.txt +0 -0
pyplumio/helpers/parameter.py
CHANGED
@@ -2,12 +2,15 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
-
from abc import ABC
|
5
|
+
from abc import ABC, abstractmethod
|
6
6
|
import asyncio
|
7
7
|
from dataclasses import dataclass
|
8
8
|
import logging
|
9
9
|
from typing import TYPE_CHECKING, Any, Final, Literal, TypeVar, Union
|
10
10
|
|
11
|
+
from dataslots import dataslots
|
12
|
+
from typing_extensions import TypeAlias
|
13
|
+
|
11
14
|
from pyplumio.const import BYTE_UNDEFINED, STATE_OFF, STATE_ON, UnitOfMeasurement
|
12
15
|
from pyplumio.frames import Request
|
13
16
|
|
@@ -19,7 +22,8 @@ _LOGGER = logging.getLogger(__name__)
|
|
19
22
|
SET_TIMEOUT: Final = 5
|
20
23
|
SET_RETRIES: Final = 5
|
21
24
|
|
22
|
-
ParameterValueType = Union[int, float, bool, Literal["off"
|
25
|
+
ParameterValueType: TypeAlias = Union[int, float, bool, Literal["off", "on"]]
|
26
|
+
ParameterT = TypeVar("ParameterT", bound="Parameter")
|
23
27
|
|
24
28
|
|
25
29
|
def unpack_parameter(
|
@@ -46,13 +50,10 @@ def check_parameter(data: bytearray) -> bool:
|
|
46
50
|
|
47
51
|
|
48
52
|
def _normalize_parameter_value(value: ParameterValueType) -> int:
|
49
|
-
"""Normalize a parameter value
|
50
|
-
if
|
53
|
+
"""Normalize a parameter value."""
|
54
|
+
if value in (STATE_OFF, STATE_ON):
|
51
55
|
return 1 if value == STATE_ON else 0
|
52
56
|
|
53
|
-
if isinstance(value, ParameterValues):
|
54
|
-
value = value.value
|
55
|
-
|
56
57
|
return int(value)
|
57
58
|
|
58
59
|
|
@@ -67,21 +68,16 @@ class ParameterValues:
|
|
67
68
|
max_value: int
|
68
69
|
|
69
70
|
|
71
|
+
@dataslots
|
70
72
|
@dataclass
|
71
|
-
class ParameterDescription
|
73
|
+
class ParameterDescription:
|
72
74
|
"""Represents a parameter description."""
|
73
75
|
|
74
76
|
name: str
|
75
|
-
unit_of_measurement: UnitOfMeasurement | Literal["%"] | None = None
|
76
|
-
|
77
|
-
|
78
|
-
@dataclass
|
79
|
-
class BinaryParameterDescription(ParameterDescription, ABC):
|
80
|
-
"""Represent a binary parameter description."""
|
81
77
|
|
82
78
|
|
83
79
|
class Parameter(ABC):
|
84
|
-
"""Represents a parameter."""
|
80
|
+
"""Represents a base parameter."""
|
85
81
|
|
86
82
|
__slots__ = ("device", "description", "_pending_update", "_index", "_values")
|
87
83
|
|
@@ -118,6 +114,7 @@ class Parameter(ABC):
|
|
118
114
|
def _call_relational_method(self, method_to_call: str, other: Any) -> Any:
|
119
115
|
"""Call a specified relational method."""
|
120
116
|
handler = getattr(self.values.value, method_to_call)
|
117
|
+
other = other.value if isinstance(other, ParameterValues) else other
|
121
118
|
return handler(_normalize_parameter_value(other))
|
122
119
|
|
123
120
|
def __int__(self) -> int:
|
@@ -164,11 +161,7 @@ class Parameter(ABC):
|
|
164
161
|
"""Compare if parameter value is less that other."""
|
165
162
|
return self._call_relational_method("__lt__", other)
|
166
163
|
|
167
|
-
async def
|
168
|
-
"""Create a request to change the parameter."""
|
169
|
-
raise NotImplementedError
|
170
|
-
|
171
|
-
async def set(self, value: ParameterValueType, retries: int = SET_RETRIES) -> bool:
|
164
|
+
async def set(self, value: Any, retries: int = SET_RETRIES) -> bool:
|
172
165
|
"""Set a parameter value."""
|
173
166
|
if (value := _normalize_parameter_value(value)) == self.values.value:
|
174
167
|
return True
|
@@ -194,10 +187,6 @@ class Parameter(ABC):
|
|
194
187
|
|
195
188
|
return True
|
196
189
|
|
197
|
-
def set_nowait(self, value: ParameterValueType, retries: int = SET_RETRIES) -> None:
|
198
|
-
"""Set a parameter value without waiting."""
|
199
|
-
self.device.create_task(self.set(value, retries))
|
200
|
-
|
201
190
|
def update(self, values: ParameterValues) -> None:
|
202
191
|
"""Update the parameter values."""
|
203
192
|
self._values = values
|
@@ -213,26 +202,6 @@ class Parameter(ABC):
|
|
213
202
|
"""Return the parameter values."""
|
214
203
|
return self._values
|
215
204
|
|
216
|
-
@property
|
217
|
-
def value(self) -> ParameterValueType:
|
218
|
-
"""Return the parameter value."""
|
219
|
-
return self.values.value
|
220
|
-
|
221
|
-
@property
|
222
|
-
def min_value(self) -> ParameterValueType:
|
223
|
-
"""Return the minimum allowed value."""
|
224
|
-
return self.values.min_value
|
225
|
-
|
226
|
-
@property
|
227
|
-
def max_value(self) -> ParameterValueType:
|
228
|
-
"""Return the maximum allowed value."""
|
229
|
-
return self.values.max_value
|
230
|
-
|
231
|
-
@property
|
232
|
-
def unit_of_measurement(self) -> UnitOfMeasurement | Literal["%"] | None:
|
233
|
-
"""Return the unit of measurement."""
|
234
|
-
return self.description.unit_of_measurement
|
235
|
-
|
236
205
|
@classmethod
|
237
206
|
def create_or_update(
|
238
207
|
cls: type[ParameterT],
|
@@ -252,15 +221,101 @@ class Parameter(ABC):
|
|
252
221
|
|
253
222
|
return parameter
|
254
223
|
|
224
|
+
@property
|
225
|
+
@abstractmethod
|
226
|
+
def value(self) -> Any:
|
227
|
+
"""Return the value."""
|
228
|
+
|
229
|
+
@property
|
230
|
+
@abstractmethod
|
231
|
+
def min_value(self) -> Any:
|
232
|
+
"""Return the minimum allowed value."""
|
233
|
+
|
234
|
+
@property
|
235
|
+
@abstractmethod
|
236
|
+
def max_value(self) -> Any:
|
237
|
+
"""Return the maximum allowed value."""
|
238
|
+
|
239
|
+
@abstractmethod
|
240
|
+
async def create_request(self) -> Request:
|
241
|
+
"""Create a request to change the parameter."""
|
255
242
|
|
256
|
-
ParameterT = TypeVar("ParameterT", bound=Parameter)
|
257
243
|
|
244
|
+
@dataslots
|
245
|
+
@dataclass
|
246
|
+
class NumberDescription(ParameterDescription):
|
247
|
+
"""Represents a parameter description."""
|
258
248
|
|
259
|
-
|
260
|
-
|
249
|
+
unit_of_measurement: UnitOfMeasurement | Literal["%"] | None = None
|
250
|
+
|
251
|
+
|
252
|
+
class Number(Parameter):
|
253
|
+
"""Represents a number."""
|
254
|
+
|
255
|
+
__slots__ = ()
|
256
|
+
|
257
|
+
description: NumberDescription
|
258
|
+
|
259
|
+
async def set(self, value: int | float, retries: int = SET_RETRIES) -> bool:
|
260
|
+
"""Set a parameter value."""
|
261
|
+
return await super().set(value, retries)
|
262
|
+
|
263
|
+
def set_nowait(self, value: int | float, retries: int = SET_RETRIES) -> None:
|
264
|
+
"""Set a parameter value without waiting."""
|
265
|
+
self.device.create_task(self.set(value, retries))
|
266
|
+
|
267
|
+
async def create_request(self) -> Request:
|
268
|
+
"""Create a request to change the number."""
|
269
|
+
return Request()
|
270
|
+
|
271
|
+
@property
|
272
|
+
def value(self) -> int | float:
|
273
|
+
"""Return the value."""
|
274
|
+
return self.values.value
|
275
|
+
|
276
|
+
@property
|
277
|
+
def min_value(self) -> int | float:
|
278
|
+
"""Return the minimum allowed value."""
|
279
|
+
return self.values.min_value
|
280
|
+
|
281
|
+
@property
|
282
|
+
def max_value(self) -> int | float:
|
283
|
+
"""Return the maximum allowed value."""
|
284
|
+
return self.values.max_value
|
285
|
+
|
286
|
+
@property
|
287
|
+
def unit_of_measurement(self) -> UnitOfMeasurement | Literal["%"] | None:
|
288
|
+
"""Return the unit of measurement."""
|
289
|
+
return self.description.unit_of_measurement
|
290
|
+
|
291
|
+
|
292
|
+
@dataslots
|
293
|
+
@dataclass
|
294
|
+
class SwitchDescription(ParameterDescription):
|
295
|
+
"""Represents a switch description."""
|
296
|
+
|
297
|
+
|
298
|
+
class Switch(Parameter):
|
299
|
+
"""Represents a switch."""
|
300
|
+
|
301
|
+
__slots__ = ()
|
302
|
+
|
303
|
+
description: SwitchDescription
|
304
|
+
|
305
|
+
async def set(
|
306
|
+
self, value: bool | Literal["off", "on"], retries: int = SET_RETRIES
|
307
|
+
) -> bool:
|
308
|
+
"""Set a parameter value."""
|
309
|
+
return await super().set(value, retries)
|
310
|
+
|
311
|
+
def set_nowait(
|
312
|
+
self, value: bool | Literal["off", "on"], retries: int = SET_RETRIES
|
313
|
+
) -> None:
|
314
|
+
"""Set a switch value without waiting."""
|
315
|
+
self.device.create_task(self.set(value, retries))
|
261
316
|
|
262
317
|
async def turn_on(self) -> bool:
|
263
|
-
"""Set a
|
318
|
+
"""Set a switch value to 'on'.
|
264
319
|
|
265
320
|
:return: `True` if parameter was successfully turned on, `False`
|
266
321
|
otherwise.
|
@@ -269,7 +324,7 @@ class BinaryParameter(Parameter):
|
|
269
324
|
return await self.set(STATE_ON)
|
270
325
|
|
271
326
|
async def turn_off(self) -> bool:
|
272
|
-
"""Set a
|
327
|
+
"""Set a switch value to 'off'.
|
273
328
|
|
274
329
|
:return: `True` if parameter was successfully turned off, `False`
|
275
330
|
otherwise.
|
@@ -278,24 +333,28 @@ class BinaryParameter(Parameter):
|
|
278
333
|
return await self.set(STATE_OFF)
|
279
334
|
|
280
335
|
def turn_on_nowait(self) -> None:
|
281
|
-
"""Set a
|
336
|
+
"""Set a switch value to 'on' without waiting."""
|
282
337
|
self.set_nowait(STATE_ON)
|
283
338
|
|
284
339
|
def turn_off_nowait(self) -> None:
|
285
|
-
"""Set a
|
340
|
+
"""Set a switch value to 'off' without waiting."""
|
286
341
|
self.set_nowait(STATE_OFF)
|
287
342
|
|
343
|
+
async def create_request(self) -> Request:
|
344
|
+
"""Create a request to change the switch."""
|
345
|
+
return Request()
|
346
|
+
|
288
347
|
@property
|
289
|
-
def value(self) ->
|
290
|
-
"""Return the
|
348
|
+
def value(self) -> Literal["off", "on"]:
|
349
|
+
"""Return the value."""
|
291
350
|
return STATE_ON if self.values.value == 1 else STATE_OFF
|
292
351
|
|
293
352
|
@property
|
294
|
-
def min_value(self) ->
|
353
|
+
def min_value(self) -> Literal["off"]:
|
295
354
|
"""Return the minimum allowed value."""
|
296
355
|
return STATE_OFF
|
297
356
|
|
298
357
|
@property
|
299
|
-
def max_value(self) ->
|
358
|
+
def max_value(self) -> Literal["on"]:
|
300
359
|
"""Return the maximum allowed value."""
|
301
360
|
return STATE_ON
|
pyplumio/protocol.py
CHANGED
@@ -8,6 +8,8 @@ from collections.abc import Awaitable, Callable
|
|
8
8
|
from dataclasses import dataclass
|
9
9
|
import logging
|
10
10
|
|
11
|
+
from typing_extensions import TypeAlias
|
12
|
+
|
11
13
|
from pyplumio.const import ATTR_CONNECTED, DeviceType
|
12
14
|
from pyplumio.devices import AddressableDevice
|
13
15
|
from pyplumio.exceptions import ProtocolError
|
@@ -23,7 +25,7 @@ from pyplumio.structures.network_info import (
|
|
23
25
|
|
24
26
|
_LOGGER = logging.getLogger(__name__)
|
25
27
|
|
26
|
-
_Callback = Callable[[], Awaitable[None]]
|
28
|
+
_Callback: TypeAlias = Callable[[], Awaitable[None]]
|
27
29
|
|
28
30
|
|
29
31
|
class Protocol(ABC):
|
@@ -111,7 +113,7 @@ class Queues:
|
|
111
113
|
await asyncio.gather(self.read.join(), self.write.join())
|
112
114
|
|
113
115
|
|
114
|
-
class AsyncProtocol(Protocol, EventManager):
|
116
|
+
class AsyncProtocol(Protocol, EventManager[AddressableDevice]):
|
115
117
|
"""Represents an async protocol.
|
116
118
|
|
117
119
|
This protocol implements producer-consumers pattern using
|
@@ -128,7 +130,6 @@ class AsyncProtocol(Protocol, EventManager):
|
|
128
130
|
"""
|
129
131
|
|
130
132
|
consumers_count: int
|
131
|
-
data: dict[str, AddressableDevice]
|
132
133
|
_network: NetworkInfo
|
133
134
|
_queues: Queues
|
134
135
|
|