PyPlumIO 0.5.21__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.
Files changed (37) hide show
  1. {PyPlumIO-0.5.21.dist-info → PyPlumIO-0.5.23.dist-info}/METADATA +12 -10
  2. PyPlumIO-0.5.23.dist-info/RECORD +60 -0
  3. {PyPlumIO-0.5.21.dist-info → PyPlumIO-0.5.23.dist-info}/WHEEL +1 -1
  4. pyplumio/__init__.py +2 -2
  5. pyplumio/_version.py +2 -2
  6. pyplumio/connection.py +3 -12
  7. pyplumio/devices/__init__.py +16 -16
  8. pyplumio/devices/ecomax.py +126 -126
  9. pyplumio/devices/mixer.py +50 -44
  10. pyplumio/devices/thermostat.py +36 -35
  11. pyplumio/exceptions.py +9 -9
  12. pyplumio/filters.py +56 -37
  13. pyplumio/frames/__init__.py +6 -6
  14. pyplumio/frames/messages.py +4 -6
  15. pyplumio/helpers/data_types.py +8 -7
  16. pyplumio/helpers/event_manager.py +53 -33
  17. pyplumio/helpers/parameter.py +138 -52
  18. pyplumio/helpers/task_manager.py +7 -2
  19. pyplumio/helpers/timeout.py +0 -3
  20. pyplumio/helpers/uid.py +2 -2
  21. pyplumio/protocol.py +35 -28
  22. pyplumio/stream.py +2 -2
  23. pyplumio/structures/alerts.py +40 -31
  24. pyplumio/structures/ecomax_parameters.py +493 -282
  25. pyplumio/structures/frame_versions.py +5 -6
  26. pyplumio/structures/lambda_sensor.py +6 -6
  27. pyplumio/structures/mixer_parameters.py +136 -71
  28. pyplumio/structures/network_info.py +2 -3
  29. pyplumio/structures/product_info.py +0 -4
  30. pyplumio/structures/program_version.py +24 -17
  31. pyplumio/structures/schedules.py +35 -15
  32. pyplumio/structures/thermostat_parameters.py +82 -50
  33. pyplumio/utils.py +12 -7
  34. PyPlumIO-0.5.21.dist-info/RECORD +0 -61
  35. pyplumio/helpers/typing.py +0 -29
  36. {PyPlumIO-0.5.21.dist-info → PyPlumIO-0.5.23.dist-info}/LICENSE +0 -0
  37. {PyPlumIO-0.5.21.dist-info → PyPlumIO-0.5.23.dist-info}/top_level.txt +0 -0
@@ -6,6 +6,8 @@ from collections.abc import Generator
6
6
  from dataclasses import dataclass
7
7
  from typing import TYPE_CHECKING, Any, Final
8
8
 
9
+ from dataslots import dataslots
10
+
9
11
  from pyplumio.const import (
10
12
  ATTR_INDEX,
11
13
  ATTR_OFFSET,
@@ -16,14 +18,16 @@ from pyplumio.const import (
16
18
  )
17
19
  from pyplumio.frames import Request
18
20
  from pyplumio.helpers.parameter import (
19
- BinaryParameter,
20
- BinaryParameterDescription,
21
+ SET_TIMEOUT,
22
+ Number,
23
+ NumberDescription,
21
24
  Parameter,
22
25
  ParameterDescription,
23
26
  ParameterValues,
27
+ Switch,
28
+ SwitchDescription,
24
29
  unpack_parameter,
25
30
  )
26
- from pyplumio.helpers.typing import ParameterValueType
27
31
  from pyplumio.structures import StructureDecoder
28
32
  from pyplumio.structures.thermostat_sensors import ATTR_THERMOSTATS_AVAILABLE
29
33
  from pyplumio.utils import ensure_dict
@@ -38,6 +42,16 @@ ATTR_THERMOSTAT_PARAMETERS: Final = "thermostat_parameters"
38
42
  THERMOSTAT_PARAMETER_SIZE: Final = 3
39
43
 
40
44
 
45
+ @dataclass
46
+ class ThermostatParameterDescription(ParameterDescription):
47
+ """Represents a thermostat parameter description."""
48
+
49
+ __slots__ = ()
50
+
51
+ multiplier: float = 1.0
52
+ size: int = 1
53
+
54
+
41
55
  class ThermostatParameter(Parameter):
42
56
  """Represents a thermostat parameter."""
43
57
 
@@ -50,14 +64,14 @@ class ThermostatParameter(Parameter):
50
64
  def __init__(
51
65
  self,
52
66
  device: Thermostat,
53
- values: ParameterValues,
54
- description: ParameterDescription,
67
+ description: ThermostatParameterDescription,
68
+ values: ParameterValues | None = None,
55
69
  index: int = 0,
56
70
  offset: int = 0,
57
71
  ):
58
72
  """Initialize a new thermostat parameter."""
59
73
  self.offset = offset
60
- super().__init__(device, values, description, index)
74
+ super().__init__(device, description, values, index)
61
75
 
62
76
  async def create_request(self) -> Request:
63
77
  """Create a request to change the parameter."""
@@ -74,108 +88,126 @@ class ThermostatParameter(Parameter):
74
88
  },
75
89
  )
76
90
 
77
- async def set(self, value: ParameterValueType, retries: int = 5) -> bool:
78
- """Set a parameter value."""
79
- if isinstance(value, (int, float)):
80
- value = int(value / self.description.multiplier)
81
91
 
92
+ @dataslots
93
+ @dataclass
94
+ class ThermostatNumberDescription(ThermostatParameterDescription, NumberDescription):
95
+ """Represent a thermostat number description."""
96
+
97
+
98
+ class ThermostatNumber(ThermostatParameter, Number):
99
+ """Represents a thermostat number."""
100
+
101
+ __slots__ = ()
102
+
103
+ description: ThermostatNumberDescription
104
+
105
+ async def set(self, value: int | float, retries: int = SET_TIMEOUT) -> bool:
106
+ """Set a parameter value."""
107
+ value = value / self.description.multiplier
82
108
  return await super().set(value, retries)
83
109
 
84
110
  @property
85
- def value(self) -> ParameterValueType:
86
- """Return the parameter value."""
111
+ def value(self) -> float:
112
+ """Return the value."""
87
113
  return self.values.value * self.description.multiplier
88
114
 
89
115
  @property
90
- def min_value(self) -> ParameterValueType:
116
+ def min_value(self) -> float:
91
117
  """Return the minimum allowed value."""
92
118
  return self.values.min_value * self.description.multiplier
93
119
 
94
120
  @property
95
- def max_value(self) -> ParameterValueType:
121
+ def max_value(self) -> float:
96
122
  """Return the maximum allowed value."""
97
123
  return self.values.max_value * self.description.multiplier
98
124
 
99
125
 
100
- class ThermostatBinaryParameter(BinaryParameter, ThermostatParameter):
101
- """Represents a thermostat binary parameter."""
102
-
103
- __slots__ = ()
104
-
105
-
126
+ @dataslots
106
127
  @dataclass
107
- class ThermostatParameterDescription(ParameterDescription):
108
- """Represents a thermostat parameter description."""
128
+ class ThermostatSwitchDescription(ThermostatParameterDescription, SwitchDescription):
129
+ """Represents a thermostat switch description."""
109
130
 
110
- multiplier: float = 1.0
111
- size: int = 1
112
131
 
132
+ class ThermostatSwitch(ThermostatParameter, Switch):
133
+ """Represents a thermostat switch."""
113
134
 
114
- @dataclass
115
- class ThermostatBinaryParameterDescription(
116
- ThermostatParameterDescription, BinaryParameterDescription
117
- ):
118
- """Represents a thermostat binary parameter description."""
135
+ __slots__ = ()
136
+
137
+ description: ThermostatSwitchDescription
119
138
 
120
139
 
121
140
  THERMOSTAT_PARAMETERS: tuple[ThermostatParameterDescription, ...] = (
122
- ThermostatParameterDescription(name="mode"),
123
- ThermostatParameterDescription(
141
+ ThermostatNumberDescription(
142
+ name="mode",
143
+ ),
144
+ ThermostatNumberDescription(
124
145
  name="party_target_temp",
125
146
  size=2,
126
147
  multiplier=0.1,
127
148
  unit_of_measurement=UnitOfMeasurement.CELSIUS,
128
149
  ),
129
- ThermostatParameterDescription(
150
+ ThermostatNumberDescription(
130
151
  name="holidays_target_temp",
131
152
  size=2,
132
153
  multiplier=0.1,
133
154
  unit_of_measurement=UnitOfMeasurement.CELSIUS,
134
155
  ),
135
- ThermostatParameterDescription(
136
- name="correction", unit_of_measurement=UnitOfMeasurement.CELSIUS
156
+ ThermostatNumberDescription(
157
+ name="correction",
158
+ unit_of_measurement=UnitOfMeasurement.CELSIUS,
137
159
  ),
138
- ThermostatParameterDescription(
139
- name="away_timer", unit_of_measurement=UnitOfMeasurement.DAYS
160
+ ThermostatNumberDescription(
161
+ name="away_timer",
162
+ unit_of_measurement=UnitOfMeasurement.DAYS,
140
163
  ),
141
- ThermostatParameterDescription(
142
- name="airing_timer", unit_of_measurement=UnitOfMeasurement.DAYS
164
+ ThermostatNumberDescription(
165
+ name="airing_timer",
166
+ unit_of_measurement=UnitOfMeasurement.DAYS,
143
167
  ),
144
- ThermostatParameterDescription(
145
- name="party_timer", unit_of_measurement=UnitOfMeasurement.DAYS
168
+ ThermostatNumberDescription(
169
+ name="party_timer",
170
+ unit_of_measurement=UnitOfMeasurement.DAYS,
146
171
  ),
147
- ThermostatParameterDescription(
148
- name="holidays_timer", unit_of_measurement=UnitOfMeasurement.DAYS
172
+ ThermostatNumberDescription(
173
+ name="holidays_timer",
174
+ unit_of_measurement=UnitOfMeasurement.DAYS,
149
175
  ),
150
- ThermostatParameterDescription(
151
- name="hysteresis", multiplier=0.1, unit_of_measurement=UnitOfMeasurement.CELSIUS
176
+ ThermostatNumberDescription(
177
+ name="hysteresis",
178
+ multiplier=0.1,
179
+ unit_of_measurement=UnitOfMeasurement.CELSIUS,
152
180
  ),
153
- ThermostatParameterDescription(
181
+ ThermostatNumberDescription(
154
182
  name="day_target_temp",
155
183
  size=2,
156
184
  multiplier=0.1,
157
185
  unit_of_measurement=UnitOfMeasurement.CELSIUS,
158
186
  ),
159
- ThermostatParameterDescription(
187
+ ThermostatNumberDescription(
160
188
  name="night_target_temp",
161
189
  size=2,
162
190
  multiplier=0.1,
163
191
  unit_of_measurement=UnitOfMeasurement.CELSIUS,
164
192
  ),
165
- ThermostatParameterDescription(
193
+ ThermostatNumberDescription(
166
194
  name="antifreeze_target_temp",
167
195
  size=2,
168
196
  multiplier=0.1,
169
197
  unit_of_measurement=UnitOfMeasurement.CELSIUS,
170
198
  ),
171
- ThermostatParameterDescription(
199
+ ThermostatNumberDescription(
172
200
  name="heating_target_temp",
173
201
  size=2,
174
202
  multiplier=0.1,
175
203
  unit_of_measurement=UnitOfMeasurement.CELSIUS,
176
204
  ),
177
- ThermostatParameterDescription(name="heating_timer"),
178
- ThermostatParameterDescription(name="off_timer"),
205
+ ThermostatNumberDescription(
206
+ name="heating_timer",
207
+ ),
208
+ ThermostatNumberDescription(
209
+ name="off_timer",
210
+ ),
179
211
  )
180
212
 
181
213
 
pyplumio/utils.py CHANGED
@@ -2,12 +2,13 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Any
5
+ from collections.abc import Mapping
6
+ from typing import TypeVar
6
7
 
7
8
 
8
- def to_camelcase(text: str, overrides: dict[str, str] | None = None) -> str:
9
+ def to_camelcase(text: str, overrides: Mapping[str, str] | None = None) -> str:
9
10
  """Convert snake_case to CamelCase."""
10
- if overrides is None:
11
+ if not overrides:
11
12
  return "".join((x.capitalize() or "_") for x in text.split("_"))
12
13
 
13
14
  return "".join(
@@ -16,10 +17,14 @@ def to_camelcase(text: str, overrides: dict[str, str] | None = None) -> str:
16
17
  )
17
18
 
18
19
 
19
- def ensure_dict(data: dict | None, *args: Any) -> dict:
20
+ KT = TypeVar("KT") # Key type.
21
+ VT = TypeVar("VT") # Value type.
22
+
23
+
24
+ def ensure_dict(initial: dict[KT, VT] | None, *args: dict[KT, VT]) -> dict[KT, VT]:
20
25
  """Create or merge multiple dictionaries."""
21
- data = data if data is not None else {}
22
- for new_data in args:
23
- data |= new_data
26
+ data = initial if initial is not None else {}
27
+ for extra in args:
28
+ data |= extra
24
29
 
25
30
  return data
@@ -1,61 +0,0 @@
1
- pyplumio/__init__.py,sha256=cclyAwy7OsW673iHcwkVrJSNnf32oF51Y_0uEEF5cdI,3293
2
- pyplumio/__main__.py,sha256=3IwHHSq-iay5FaeMc95klobe-xv82yydSKcBE7BFZ6M,500
3
- pyplumio/_version.py,sha256=qwvYpiZ4pV_W2HOchGsudGTbl7hCvV-xhS0ii39Ac0I,413
4
- pyplumio/connection.py,sha256=ZZHXHFpbOBVd9DGZV_H8lpdYtYoc3nP9fRolKATKDnQ,6096
5
- pyplumio/const.py,sha256=8rpiVbVb5R_6Rm6J2sgCnaVrkD-2Fzhd1RYMz0MBgwo,3915
6
- pyplumio/exceptions.py,sha256=193z3zfnswYhIYPzCIpxCiWat4qI3cV85sqT4YOSo-4,699
7
- pyplumio/filters.py,sha256=bIonYc_QbGMsL8aWweSLUmP7gKqDD646zELf_PqqQBg,11161
8
- pyplumio/protocol.py,sha256=Ci4p4bqADfWeGk9fzcGMudRbe-dFFa1UNot9no5Lj3M,7845
9
- pyplumio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- pyplumio/stream.py,sha256=DqMqdi3HG9hODgfGo4eTKLkfoaSh5RS4kBHNn3ODvVg,4472
11
- pyplumio/utils.py,sha256=GV7P1hPLoQsx3uqYviQ15FXJmkmTxwtDibAc-yRarvo,688
12
- pyplumio/devices/__init__.py,sha256=O5SyEt_x1nJ1JYkG6v3dTZ54tu9sKIdj4l256JhvLHg,6585
13
- pyplumio/devices/ecomax.py,sha256=IPHyC8OjnGaQ_ZztcchgQjEJmNj8LfnP9sTJyslEQ14,16914
14
- pyplumio/devices/ecoster.py,sha256=J4YtPmFmFwaq4LzYf28aMmB97cRAbMsVyUdBLGki42g,313
15
- pyplumio/devices/mixer.py,sha256=qJAmar7DdsQL1Syg0WOCBVQn3GyBTWEVyr5ZfpGytCk,2975
16
- pyplumio/devices/thermostat.py,sha256=HCnLVBX8mn6lmpCgl1DbDoCMI6T97sqmK-36cYcjXVA,2430
17
- pyplumio/frames/__init__.py,sha256=BAMbMHbn4F9psrf3sv0eJQA2Jd86qf7LQ5vBQY59gjA,7462
18
- pyplumio/frames/messages.py,sha256=QLuvo1wlpDZR1MpOdu7s6fRUX20Dtt6EWFLkAsqyax4,3617
19
- pyplumio/frames/requests.py,sha256=Ra8xH5oKYhkEUtadN-9ZsJKkt5xZkz5O7edQVsDhNsM,7221
20
- pyplumio/frames/responses.py,sha256=j4awA2-MfsoPdENC4Fvae4_Oa70rDhH19ebmEoAqhh8,6532
21
- pyplumio/helpers/__init__.py,sha256=H2xxdkF-9uADLwEbfBUoxNTdwru3L5Z2cfJjgsuRsn0,31
22
- pyplumio/helpers/data_types.py,sha256=H_pYkLgIu30lDFU0UUZ1V3vYxa9A_-1nhiJu-HCLuoc,8212
23
- pyplumio/helpers/event_manager.py,sha256=dCNLnSRZgewZ9Ppi-JtkxtvOmNd4ZejA7UT4oAT8FWM,5865
24
- pyplumio/helpers/factory.py,sha256=eiTkYUCernUn0VNDDdEN4IyjNPrXK8vnJESXyLaqFzE,1017
25
- pyplumio/helpers/parameter.py,sha256=gYCA2SLU_lbdtQZq5U64yzpyLoEIa0R1wyJJGmgL63I,8699
26
- pyplumio/helpers/schedule.py,sha256=-IZJ-CU4PhFlsE586wTw--ovDrTo2Hs4JneCHhc0e-Y,5013
27
- pyplumio/helpers/task_manager.py,sha256=y5j7u31V6UE7g2ZhdsYsPykY-Awo73oWsNRUOrLSILg,1075
28
- pyplumio/helpers/timeout.py,sha256=k-829fBcHT5IR3isrMSgNbPYK-ubeY1BAwndCDIiX9E,824
29
- pyplumio/helpers/typing.py,sha256=y55UdpIpPIRuUBPgfPmZHAwPdIUjQO924-kO7AVXhes,685
30
- pyplumio/helpers/uid.py,sha256=yaBjcsFKuhOaznftk33kdIepQHpK-labEQr59QNKhPM,975
31
- pyplumio/structures/__init__.py,sha256=EjK-5qJZ0F7lpP2b6epvTMg9cIBl4Kn91nqNkEcLwTc,1299
32
- pyplumio/structures/alerts.py,sha256=a1CIf8vSEj5aefdqECIfCY5kV4tQ4kabMkp-_ixeWic,3260
33
- pyplumio/structures/boiler_load.py,sha256=p3mOzZUU-g7A2tG_yp8podEqpI81hlsOZmHELyPNRY8,838
34
- pyplumio/structures/boiler_power.py,sha256=72qsvccg49FdRdXv2f2K5sGpjT7wAOLFjlIGWpO-DVg,901
35
- pyplumio/structures/ecomax_parameters.py,sha256=6HVEh4aNw0CGZD3CVQeYyKXQ0pzueQR_Tpm5fF3_0hA,25815
36
- pyplumio/structures/fan_power.py,sha256=Q5fv-7_2NVuLeQPIVIylvgN7M8-a9D8rRUE0QGjyS3w,871
37
- pyplumio/structures/frame_versions.py,sha256=x_OSirGYopQYgsRZIM3b1YlKHNIPmCbvAzhzO1wqy5k,1560
38
- pyplumio/structures/fuel_consumption.py,sha256=_p2dI4H67Eopn7IF0Gj77A8c_8lNKhhDDAtmugxLd4s,976
39
- pyplumio/structures/fuel_level.py,sha256=mJpp1dnRD1wXi_6EyNX7TNXosjcr905rSHOnuZ5VD74,1069
40
- pyplumio/structures/lambda_sensor.py,sha256=6iUVyrPe6_QaGPo1lRzOfqorcTIIXRwnq3h861IJYGs,1587
41
- pyplumio/structures/mixer_parameters.py,sha256=ny7Ox94IooQd1ua22zGYkXLFaZQWGUYLEIM2_8vXk0U,8249
42
- pyplumio/structures/mixer_sensors.py,sha256=O91929Ts1YXFmKdPRc1r_BYDgrqkv5QVtE1nGzLpuAI,2260
43
- pyplumio/structures/modules.py,sha256=ukju4TQmRRJfgl94QU4zytZLU5px8nw3sgfSLn9JysU,2520
44
- pyplumio/structures/network_info.py,sha256=ws2UdOhB89oKqmtW1Vsmfj0InRW4Sp6_kL1d4psk-8w,4094
45
- pyplumio/structures/output_flags.py,sha256=07N0kxlvR5WZAURuChk_BqSiXR8eaQrtI5qlkgCf4Yc,1345
46
- pyplumio/structures/outputs.py,sha256=1xsJPkjN643-aFawqVoupGatUIUJfQG_g252n051Qi0,1916
47
- pyplumio/structures/pending_alerts.py,sha256=Uq9WpB4MW9AhDkqmDhk-g0J0h4pVq0Q50z12dYEv6kY,739
48
- pyplumio/structures/product_info.py,sha256=bVH7NvIOWwmmHcgbLfD-IIag4sgBRA6RMmuC6SKTrJE,2409
49
- pyplumio/structures/program_version.py,sha256=4h3u46l2btUcooDRHyrqN3Y9M8WNEzwCmkNVEzfi-V8,2359
50
- pyplumio/structures/regulator_data.py,sha256=Dun3RjfHHoV2W5RTSQcAimBL0Or3O957vYQj7Pbi7CM,2309
51
- pyplumio/structures/regulator_data_schema.py,sha256=BMshEpiP-lwTgSkbTuow9KlxCwKwQXV0nFPcBpW0SJg,1505
52
- pyplumio/structures/schedules.py,sha256=-koo05nLkpKuj1ZPiC1NB_21MAFn1FzQ6VLC0DboYeg,6346
53
- pyplumio/structures/statuses.py,sha256=wkoynyMRr1VREwfBC6vU48kPA8ZQ83pcXuciy2xHJrk,1166
54
- pyplumio/structures/temperatures.py,sha256=1CDzehNmbALz1Jyt_9gZNIk52q6Wv-xQXjijVDCVYec,2337
55
- pyplumio/structures/thermostat_parameters.py,sha256=pjbWsT6z7mlDiUrC5MWGqMtGP0deeVMYeeTa7yGEwJ8,7706
56
- pyplumio/structures/thermostat_sensors.py,sha256=ZmjWgYtTZ5M8Lnz_Q5N4JD8G3MvEmByPFjYsy6XZOmo,3177
57
- PyPlumIO-0.5.21.dist-info/LICENSE,sha256=m-UuZFjXJ22uPTGm9kSHS8bqjsf5T8k2wL9bJn1Y04o,1088
58
- PyPlumIO-0.5.21.dist-info/METADATA,sha256=mc-yvbFJArE1iYRxb8RCkL2MdoKZjkZKOn8nWgWD8t8,5415
59
- PyPlumIO-0.5.21.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
60
- PyPlumIO-0.5.21.dist-info/top_level.txt,sha256=kNBz9UPPkPD9teDn3U_sEy5LjzwLm9KfADCXtBlbw8A,9
61
- PyPlumIO-0.5.21.dist-info/RECORD,,
@@ -1,29 +0,0 @@
1
- """Contains type aliases."""
2
-
3
- from __future__ import annotations
4
-
5
- from typing import Literal, Protocol, Union, runtime_checkable
6
-
7
- ParameterValueType = Union[int, float, bool, Literal["off"], Literal["on"]]
8
-
9
-
10
- @runtime_checkable
11
- class SupportsSubtraction(Protocol):
12
- """Supports subtraction operation."""
13
-
14
- __slots__ = ()
15
-
16
- def __sub__(
17
- self: SupportsSubtraction, other: SupportsSubtraction
18
- ) -> SupportsSubtraction:
19
- """Subtract a value."""
20
-
21
-
22
- @runtime_checkable
23
- class SupportsComparison(Protocol):
24
- """Supports comparison."""
25
-
26
- __slots__ = ()
27
-
28
- def __eq__(self: SupportsComparison, other: SupportsComparison) -> bool:
29
- """Compare a value."""