PyPlumIO 0.5.32__py3-none-any.whl → 0.5.34__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.32.dist-info → PyPlumIO-0.5.34.dist-info}/METADATA +1 -1
- {PyPlumIO-0.5.32.dist-info → PyPlumIO-0.5.34.dist-info}/RECORD +12 -12
- pyplumio/_version.py +2 -2
- pyplumio/devices/__init__.py +11 -11
- pyplumio/devices/ecomax.py +5 -2
- pyplumio/helpers/factory.py +5 -2
- pyplumio/helpers/parameter.py +5 -3
- pyplumio/helpers/schedule.py +6 -3
- pyplumio/stream.py +14 -9
- {PyPlumIO-0.5.32.dist-info → PyPlumIO-0.5.34.dist-info}/LICENSE +0 -0
- {PyPlumIO-0.5.32.dist-info → PyPlumIO-0.5.34.dist-info}/WHEEL +0 -0
- {PyPlumIO-0.5.32.dist-info → PyPlumIO-0.5.34.dist-info}/top_level.txt +0 -0
@@ -1,16 +1,16 @@
|
|
1
1
|
pyplumio/__init__.py,sha256=ditJTIOFGJDg60atHzOpiggdUrZHpSynno7MtpZUGVk,3299
|
2
2
|
pyplumio/__main__.py,sha256=3IwHHSq-iay5FaeMc95klobe-xv82yydSKcBE7BFZ6M,500
|
3
|
-
pyplumio/_version.py,sha256=
|
3
|
+
pyplumio/_version.py,sha256=NdVLEG4QoQ2gCknxsIGvrBsx6YVY3lCufzs3YmFEJws,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
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
|
-
pyplumio/stream.py,sha256=
|
10
|
+
pyplumio/stream.py,sha256=Ne-mWkO6FpILAjGdagbAh_VL3QEla-eDiT2N-kOc5o4,4883
|
11
11
|
pyplumio/utils.py,sha256=TnBzRopinyp92wruguijxcIYmaeyNVTFX0dygI5FCMU,823
|
12
|
-
pyplumio/devices/__init__.py,sha256=
|
13
|
-
pyplumio/devices/ecomax.py,sha256=
|
12
|
+
pyplumio/devices/__init__.py,sha256=aOn9G7uo-CXM8BPqfm1GjmBLmWuekw-qyiEXjYG30Ps,8083
|
13
|
+
pyplumio/devices/ecomax.py,sha256=LWDIlnC2lIOF2L5obLwpHKY0KTxp81TbrMGAzk7GlSw,15528
|
14
14
|
pyplumio/devices/ecoster.py,sha256=jNWli7ye9T6yfkcFJZhhUHH7KOv-L6AgYFp_dKyv3OM,263
|
15
15
|
pyplumio/devices/mixer.py,sha256=CnHWrJELtFgs2YTHGpQwKr2UTRdetX76OvLBA2PH-fs,3207
|
16
16
|
pyplumio/devices/thermostat.py,sha256=-CZNRyywoDU6csFu85KSmQ5woVXY0x6peXkeOsi_fqg,2617
|
@@ -21,9 +21,9 @@ pyplumio/frames/responses.py,sha256=Ch1AVBmD6Ek7BazoEMDDEa6ad_fUdUXf4bNssQOu0sI,
|
|
21
21
|
pyplumio/helpers/__init__.py,sha256=H2xxdkF-9uADLwEbfBUoxNTdwru3L5Z2cfJjgsuRsn0,31
|
22
22
|
pyplumio/helpers/data_types.py,sha256=nB3afOLmppgSCWkZoX1-1yWPNMMNSem77x7XQ1Mi8H8,9103
|
23
23
|
pyplumio/helpers/event_manager.py,sha256=xQOfiP_nP1Pz5zhB6HU5gXyyJXjhisYshL8_HRxDgt8,6412
|
24
|
-
pyplumio/helpers/factory.py,sha256=
|
25
|
-
pyplumio/helpers/parameter.py,sha256=
|
26
|
-
pyplumio/helpers/schedule.py,sha256=
|
24
|
+
pyplumio/helpers/factory.py,sha256=v07s9DyihfkNUzt7ndyJbNd_DLS8UpRkut_xkGrbi6c,1123
|
25
|
+
pyplumio/helpers/parameter.py,sha256=UWv4cQ-Mk2hBD3F2amS-6OIL0ulcMmEZcnogOXcXhng,12373
|
26
|
+
pyplumio/helpers/schedule.py,sha256=rlq3O2Xflqks6V1rMoHKy_lww8zJJpuHFFouM2pikJw,5417
|
27
27
|
pyplumio/helpers/task_manager.py,sha256=HAd69yGTRL0zQsu-ywnbLu1UXiJzgHWuhYWA--vs4lQ,1181
|
28
28
|
pyplumio/helpers/timeout.py,sha256=JAhWNtIpcXyVILIwHWVy5mYofqbbRDGKLdTUKkQuajs,772
|
29
29
|
pyplumio/helpers/uid.py,sha256=J7gN8i8LE0g6tfL66BJbwsQQqzBBxWx7giyvqaJh4BM,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.
|
57
|
-
PyPlumIO-0.5.
|
58
|
-
PyPlumIO-0.5.
|
59
|
-
PyPlumIO-0.5.
|
60
|
-
PyPlumIO-0.5.
|
56
|
+
PyPlumIO-0.5.34.dist-info/LICENSE,sha256=m-UuZFjXJ22uPTGm9kSHS8bqjsf5T8k2wL9bJn1Y04o,1088
|
57
|
+
PyPlumIO-0.5.34.dist-info/METADATA,sha256=fKpSdOn-36ISpqOsoM7wiwnbJn0jHfvdHnwyIge5KQM,5510
|
58
|
+
PyPlumIO-0.5.34.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
59
|
+
PyPlumIO-0.5.34.dist-info/top_level.txt,sha256=kNBz9UPPkPD9teDn3U_sEy5LjzwLm9KfADCXtBlbw8A,9
|
60
|
+
PyPlumIO-0.5.34.dist-info/RECORD,,
|
pyplumio/_version.py
CHANGED
pyplumio/devices/__init__.py
CHANGED
@@ -82,7 +82,7 @@ class Device(ABC, EventManager):
|
|
82
82
|
"""
|
83
83
|
parameter = await self.get(name, timeout)
|
84
84
|
if not isinstance(parameter, Parameter):
|
85
|
-
raise TypeError(f"{name} is not valid
|
85
|
+
raise TypeError(f"The parameter '{name}' is not valid or does not exist.")
|
86
86
|
|
87
87
|
return await parameter.set(value, retries=retries)
|
88
88
|
|
@@ -143,7 +143,7 @@ class PhysicalDevice(Device, ABC):
|
|
143
143
|
and not self.has_frame_version(frame_type, version)
|
144
144
|
):
|
145
145
|
_LOGGER.debug(
|
146
|
-
"Updating frame %s to version %i",
|
146
|
+
"Updating frame %s to version %i", frame_type, version
|
147
147
|
)
|
148
148
|
request = await Request.create(frame_type, recipient=self.address)
|
149
149
|
self.queue.put_nowait(request)
|
@@ -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
|
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
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
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."""
|
@@ -206,7 +203,10 @@ class PhysicalDevice(Device, ABC):
|
|
206
203
|
except asyncio.TimeoutError:
|
207
204
|
retries -= 1
|
208
205
|
|
209
|
-
raise ValueError(
|
206
|
+
raise ValueError(
|
207
|
+
f"Failed to request parameter '{name}' with frame type '{frame_type}' "
|
208
|
+
f"after {retries} retries."
|
209
|
+
)
|
210
210
|
|
211
211
|
@classmethod
|
212
212
|
async def create(cls, device_type: int, **kwargs: Any) -> PhysicalDevice:
|
pyplumio/devices/ecomax.py
CHANGED
@@ -98,6 +98,8 @@ SETUP_FRAME_TYPES: tuple[DataFrameDescription, ...] = (
|
|
98
98
|
|
99
99
|
_LOGGER = logging.getLogger(__name__)
|
100
100
|
|
101
|
+
ecomax_control_error = "ecoMAX control is not available. Please try again later."
|
102
|
+
|
101
103
|
|
102
104
|
class EcoMAX(PhysicalDevice):
|
103
105
|
"""Represents an ecoMAX controller."""
|
@@ -192,6 +194,7 @@ class EcoMAX(PhysicalDevice):
|
|
192
194
|
values,
|
193
195
|
product.model,
|
194
196
|
)
|
197
|
+
return
|
195
198
|
|
196
199
|
handler = (
|
197
200
|
EcomaxSwitch
|
@@ -393,7 +396,7 @@ class EcoMAX(PhysicalDevice):
|
|
393
396
|
ecomax_control: EcomaxSwitch = self.data[ATTR_ECOMAX_CONTROL]
|
394
397
|
return await ecomax_control.turn_on()
|
395
398
|
except KeyError:
|
396
|
-
_LOGGER.error(
|
399
|
+
_LOGGER.error(ecomax_control_error)
|
397
400
|
return False
|
398
401
|
|
399
402
|
async def turn_off(self) -> bool:
|
@@ -402,7 +405,7 @@ class EcoMAX(PhysicalDevice):
|
|
402
405
|
ecomax_control: EcomaxSwitch = self.data[ATTR_ECOMAX_CONTROL]
|
403
406
|
return await ecomax_control.turn_off()
|
404
407
|
except KeyError:
|
405
|
-
_LOGGER.error(
|
408
|
+
_LOGGER.error(ecomax_control_error)
|
406
409
|
return False
|
407
410
|
|
408
411
|
def turn_on_nowait(self) -> None:
|
pyplumio/helpers/factory.py
CHANGED
@@ -26,9 +26,12 @@ async def create_instance(class_path: str, cls: type[T], **kwargs: Any) -> T:
|
|
26
26
|
module = await _import_module(module_name)
|
27
27
|
instance = getattr(module, class_name)(**kwargs)
|
28
28
|
if not isinstance(instance, cls):
|
29
|
-
raise TypeError(
|
29
|
+
raise TypeError(
|
30
|
+
f"Expected instance of '{cls.__name__}', but got "
|
31
|
+
f"'{type(instance).__name__}' from '{class_name}'"
|
32
|
+
)
|
30
33
|
|
31
34
|
return instance
|
32
35
|
except Exception:
|
33
|
-
_LOGGER.
|
36
|
+
_LOGGER.exception("Failed to create instance for class path '%s'", class_path)
|
34
37
|
raise
|
pyplumio/helpers/parameter.py
CHANGED
@@ -189,7 +189,8 @@ class Parameter(ABC):
|
|
189
189
|
value = _normalize_parameter_value(value)
|
190
190
|
if value < self.values.min_value or value > self.values.max_value:
|
191
191
|
raise ValueError(
|
192
|
-
f"
|
192
|
+
f"Invalid value: {value}. Must be between "
|
193
|
+
f"{self.min_value} and {self.max_value}."
|
193
194
|
)
|
194
195
|
|
195
196
|
return value
|
@@ -215,9 +216,10 @@ class Parameter(ABC):
|
|
215
216
|
self._pending_update = True
|
216
217
|
while self.pending_update:
|
217
218
|
if retries <= 0:
|
218
|
-
_LOGGER.
|
219
|
-
"
|
219
|
+
_LOGGER.warning(
|
220
|
+
"Failed to set parameter '%s' after %d retries",
|
220
221
|
self.description.name,
|
222
|
+
retries,
|
221
223
|
)
|
222
224
|
return False
|
223
225
|
|
pyplumio/helpers/schedule.py
CHANGED
@@ -50,8 +50,8 @@ def _get_time_range(
|
|
50
50
|
|
51
51
|
if end_dt <= start_dt:
|
52
52
|
raise ValueError(
|
53
|
-
f"Invalid
|
54
|
-
"
|
53
|
+
f"Invalid time range: start time ({start}) must be earlier "
|
54
|
+
f"than end time ({end})."
|
55
55
|
)
|
56
56
|
|
57
57
|
def _dt_to_index(dt: dt.datetime) -> int:
|
@@ -107,7 +107,10 @@ class ScheduleDay(MutableMapping):
|
|
107
107
|
) -> None:
|
108
108
|
"""Set a schedule interval state."""
|
109
109
|
if state not in get_args(ScheduleState):
|
110
|
-
raise ValueError(
|
110
|
+
raise ValueError(
|
111
|
+
f"Invalid state '{state}'. Allowed states are: "
|
112
|
+
f"{', '.join(get_args(ScheduleState))}"
|
113
|
+
)
|
111
114
|
|
112
115
|
for index in _get_time_range(start, end):
|
113
116
|
self._intervals[index] = True if state in ON_STATES else False
|
pyplumio/stream.py
CHANGED
@@ -45,7 +45,7 @@ class FrameWriter:
|
|
45
45
|
"""Send the frame and wait until send buffer is empty."""
|
46
46
|
self._writer.write(frame.bytes)
|
47
47
|
await self._writer.drain()
|
48
|
-
_LOGGER.debug("Sent frame: %s", frame)
|
48
|
+
_LOGGER.debug("Sent frame: %s, bytes: %s", frame, frame.bytes)
|
49
49
|
|
50
50
|
async def close(self) -> None:
|
51
51
|
"""Close the frame writer."""
|
@@ -53,7 +53,9 @@ class FrameWriter:
|
|
53
53
|
self._writer.close()
|
54
54
|
await self.wait_closed()
|
55
55
|
except (OSError, asyncio.TimeoutError):
|
56
|
-
_LOGGER.exception(
|
56
|
+
_LOGGER.exception(
|
57
|
+
"Failed to close the frame writer due to an unexpected error"
|
58
|
+
)
|
57
59
|
|
58
60
|
@timeout(WRITER_TIMEOUT)
|
59
61
|
async def wait_closed(self) -> None:
|
@@ -96,7 +98,7 @@ class FrameReader:
|
|
96
98
|
buffer += await self._reader.readexactly(HEADER_SIZE - DELIMITER_SIZE)
|
97
99
|
except IncompleteReadError as e:
|
98
100
|
raise ReadError(
|
99
|
-
f"
|
101
|
+
f"Incomplete header, expected {e.expected} bytes"
|
100
102
|
) from e
|
101
103
|
|
102
104
|
return Header(*struct_header.unpack_from(buffer)[DELIMITER_SIZE:]), buffer
|
@@ -123,18 +125,21 @@ class FrameReader:
|
|
123
125
|
raise UnknownDeviceError(f"Unknown sender type ({sender})")
|
124
126
|
|
125
127
|
if frame_length > MAX_FRAME_LENGTH or frame_length < MIN_FRAME_LENGTH:
|
126
|
-
raise ReadError(
|
128
|
+
raise ReadError(
|
129
|
+
f"Unexpected frame length ({frame_length}), expected between "
|
130
|
+
f"{MIN_FRAME_LENGTH} and {MAX_FRAME_LENGTH}"
|
131
|
+
)
|
127
132
|
|
128
133
|
try:
|
129
134
|
buffer += await self._reader.readexactly(frame_length - HEADER_SIZE)
|
130
135
|
except IncompleteReadError as e:
|
131
|
-
raise ReadError(
|
132
|
-
f"Got incomplete frame, while trying to read {e.expected} bytes"
|
133
|
-
) from e
|
136
|
+
raise ReadError(f"Incomplete frame, expected {e.expected} bytes") from e
|
134
137
|
|
135
138
|
if (checksum := bcc(buffer[:-2])) and checksum != buffer[-2]:
|
136
139
|
raise ChecksumError(
|
137
|
-
f"Incorrect frame checksum
|
140
|
+
f"Incorrect frame checksum: calculated {checksum}, "
|
141
|
+
f"expected {buffer[-2]}. "
|
142
|
+
f"Frame data: {buffer.hex()}"
|
138
143
|
)
|
139
144
|
|
140
145
|
frame = await Frame.create(
|
@@ -145,6 +150,6 @@ class FrameReader:
|
|
145
150
|
econet_version=econet_version,
|
146
151
|
message=buffer[HEADER_SIZE + 1 : -2],
|
147
152
|
)
|
148
|
-
_LOGGER.debug("Received frame: %s", frame)
|
153
|
+
_LOGGER.debug("Received frame: %s, bytes: %s", frame, buffer.hex())
|
149
154
|
|
150
155
|
return frame
|
File without changes
|
File without changes
|
File without changes
|