PyPlumIO 0.5.17__py3-none-any.whl → 0.5.18__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.1
2
2
  Name: PyPlumIO
3
- Version: 0.5.17
3
+ Version: 0.5.18
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
@@ -33,12 +33,12 @@ Requires-Dist: sphinx-rtd-theme ==2.0.0 ; extra == 'docs'
33
33
  Requires-Dist: readthedocs-sphinx-search ==0.3.2 ; extra == 'docs'
34
34
  Provides-Extra: test
35
35
  Requires-Dist: codespell ==2.2.6 ; extra == 'test'
36
- Requires-Dist: coverage ==7.5.0 ; extra == 'test'
37
- Requires-Dist: mypy ==1.9.0 ; extra == 'test'
36
+ Requires-Dist: coverage ==7.5.1 ; extra == 'test'
37
+ Requires-Dist: mypy ==1.10.0 ; extra == 'test'
38
38
  Requires-Dist: pyserial-asyncio-fast ==0.11 ; extra == 'test'
39
39
  Requires-Dist: pytest ==8.2.0 ; extra == 'test'
40
40
  Requires-Dist: pytest-asyncio ==0.23.6 ; extra == 'test'
41
- Requires-Dist: ruff ==0.4.2 ; extra == 'test'
41
+ Requires-Dist: ruff ==0.4.3 ; extra == 'test'
42
42
  Requires-Dist: tox ==4.15.0 ; extra == 'test'
43
43
  Requires-Dist: types-pyserial ==3.5.0.20240311 ; extra == 'test'
44
44
 
@@ -1,11 +1,11 @@
1
1
  pyplumio/__init__.py,sha256=4v9BaIkJ440qu2ITrcwVLOg9KO8k2W1gnGHe86sDLM8,3292
2
2
  pyplumio/__main__.py,sha256=oop76iR-XDHhMFhW4LO8-xTnBHsqzUQ5VVh__94OaqY,499
3
- pyplumio/_version.py,sha256=dQYxLlSh6o3oTwPaW5cCsGzUzw8dHq1HmpZtnNncm_0,413
3
+ pyplumio/_version.py,sha256=TJSWAybqN12Cw_kxmDDEn4jE4KWfkCe6C38YXdi-hN8,413
4
4
  pyplumio/connection.py,sha256=0PmpNOcV7RgSfEeM7Wnhtbw0TpdtMTyqpJPQ2h7IX9M,6199
5
5
  pyplumio/const.py,sha256=4_VRx5mY7qf5fwaUluVlhuK_NIb7bClzhnhRLA-3GkY,3914
6
6
  pyplumio/exceptions.py,sha256=3tgfe0GD-T-DV2TUybsv7dwsk9P9f2g-4Gd8jnXw6DI,698
7
7
  pyplumio/filters.py,sha256=kXR4SUS7YXGaljW35NpEB9prHgxDKpsf_U1ACMTnh5I,11174
8
- pyplumio/protocol.py,sha256=Gl3aUxdcK5Z_ZkO88bPwiv9dBR_JO8VQR_H7aKKbHiM,8756
8
+ pyplumio/protocol.py,sha256=btBJiCyB2ys-tiQOm8kj97_Y7yesO4cIOKrEGbrCrsk,8787
9
9
  pyplumio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  pyplumio/stream.py,sha256=UPqlUmNBobSS4SvS5BI19g_FeSTLpLj1k3l7OeE32bI,4374
11
11
  pyplumio/utils.py,sha256=h46IS7hOHFbAFGGmnyAUVwlfk0m_eSwa3U8oZq6-bJY,687
@@ -21,9 +21,9 @@ pyplumio/frames/responses.py,sha256=7MHwXkNVTcwYpWRAXBMiPxmaJw3vgX9kgoaBTXeRy60,
21
21
  pyplumio/helpers/__init__.py,sha256=H2xxdkF-9uADLwEbfBUoxNTdwru3L5Z2cfJjgsuRsn0,31
22
22
  pyplumio/helpers/data_types.py,sha256=UIbJu0JfXaNCiHlg8EnYOfeyKq9Mxiu6j_D8GyRudZk,8211
23
23
  pyplumio/helpers/event_manager.py,sha256=E9gMGCxOOBNZgnHCwpb8rtFgKsNIkjHvIN73XBgwQDk,6004
24
- pyplumio/helpers/factory.py,sha256=9U0vYy137nDI5Zl0CjlWhm6p0ztGeafOtkydZU0kA6I,694
24
+ pyplumio/helpers/factory.py,sha256=Ld_PbKnkj0HFnuYcoDwcitiMRa-88UQKXcsE5vdgLqs,824
25
25
  pyplumio/helpers/parameter.py,sha256=ihdom_tON2urYXmS7x_2-zk2I-PcogdjILE7tOiGR8M,8698
26
- pyplumio/helpers/schedule.py,sha256=zfVmawRjpKa5JpDGg2n9E985UtW-hEWEyn6cKSm6U6c,4911
26
+ pyplumio/helpers/schedule.py,sha256=395yTDAKV43so5vEG-q0mgqXGoFVWKpIyhdmqzKT-X4,4958
27
27
  pyplumio/helpers/task_manager.py,sha256=P17Nw9HDbA9NMSdkJo2WQRbEsykzzFSwQyyRzI3uFPk,1089
28
28
  pyplumio/helpers/timeout.py,sha256=bWBWvLPpgjCvdG5hlrSTXok_CsLme-jGnY9rHwupRc0,1286
29
29
  pyplumio/helpers/typing.py,sha256=V3uYCMyC4oePM7YzL0S-xEsyTgjgDbkOM0VNe-1LBPo,684
@@ -32,7 +32,7 @@ pyplumio/structures/__init__.py,sha256=-nbLcQvbWcs2EmnChqJmMVo1CUfj8lqMHb8yK1mV4
32
32
  pyplumio/structures/alerts.py,sha256=v--wbEKoB07r9KHMuZgMRT1dk4r8dPwxxB5cPv4lzZY,3259
33
33
  pyplumio/structures/boiler_load.py,sha256=HVPKt53VWvp2KDuSK1B9kcpX1h3Bz3GPBqBI4Oscm2Q,837
34
34
  pyplumio/structures/boiler_power.py,sha256=tP00IMz5qVQaePr70uTz_jCLoXHnmj_g3pvKxdNvenc,900
35
- pyplumio/structures/ecomax_parameters.py,sha256=D4IFbRzMtGK91XUCAzGp2VJ9LouYnRcPa-QP2mH2lnA,26184
35
+ pyplumio/structures/ecomax_parameters.py,sha256=Ywiabk0panLHSScv8SZC_cBmkdSXuXPEfDFyEsjR0ts,25895
36
36
  pyplumio/structures/fan_power.py,sha256=fGU_BTPTtAplnjmTQQHhMXdoiHVYOdLlZ_PDA9F5u9c,870
37
37
  pyplumio/structures/frame_versions.py,sha256=9lFnrlxkok_3CTbXz38cntacnubWYGcaubDnYq9NOAM,1559
38
38
  pyplumio/structures/fuel_consumption.py,sha256=H23GVw9s0fbURvJHAfReTEvGp5q-oPOidh1mToOO3ec,975
@@ -54,8 +54,8 @@ pyplumio/structures/statuses.py,sha256=zjDQTU5fdORRzRkvlkzplgVS8A3AdyHG2qihfkdOH
54
54
  pyplumio/structures/temperatures.py,sha256=O8rANFN-wz5NvTWqh_25oUfFajjVyI9hoOMmz8vkKHg,2336
55
55
  pyplumio/structures/thermostat_parameters.py,sha256=1SJzHguN12JE-e2utwA448VgUkFddQxBQy3m66qCobk,7934
56
56
  pyplumio/structures/thermostat_sensors.py,sha256=N9nm3Rp1Rhb8wUPUkJIX56olZztixoxyFxIxP4R5P2g,3176
57
- PyPlumIO-0.5.17.dist-info/LICENSE,sha256=m-UuZFjXJ22uPTGm9kSHS8bqjsf5T8k2wL9bJn1Y04o,1088
58
- PyPlumIO-0.5.17.dist-info/METADATA,sha256=hYBntfwRNAwg3Zdb_S0HailPnsFm9ewT99rRNys494U,5414
59
- PyPlumIO-0.5.17.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
60
- PyPlumIO-0.5.17.dist-info/top_level.txt,sha256=kNBz9UPPkPD9teDn3U_sEy5LjzwLm9KfADCXtBlbw8A,9
61
- PyPlumIO-0.5.17.dist-info/RECORD,,
57
+ PyPlumIO-0.5.18.dist-info/LICENSE,sha256=m-UuZFjXJ22uPTGm9kSHS8bqjsf5T8k2wL9bJn1Y04o,1088
58
+ PyPlumIO-0.5.18.dist-info/METADATA,sha256=fHzLAiOHlj3nYHmvnm4OZsFBUMyJcSnSgmRg7zbbr0s,5415
59
+ PyPlumIO-0.5.18.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
60
+ PyPlumIO-0.5.18.dist-info/top_level.txt,sha256=kNBz9UPPkPD9teDn3U_sEy5LjzwLm9KfADCXtBlbw8A,9
61
+ PyPlumIO-0.5.18.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.17'
16
- __version_tuple__ = version_tuple = (0, 5, 17)
15
+ __version__ = version = '0.5.18'
16
+ __version_tuple__ = version_tuple = (0, 5, 18)
@@ -2,21 +2,26 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  import asyncio
5
- from importlib import import_module
5
+ import importlib
6
6
  import logging
7
+ from types import ModuleType
7
8
  from typing import Any
8
9
 
9
10
  _LOGGER = logging.getLogger(__name__)
10
11
 
11
12
 
13
+ async def _load_module(module_name: str) -> ModuleType:
14
+ """Load a module by name."""
15
+ return await asyncio.get_running_loop().run_in_executor(
16
+ None, importlib.import_module, f".{module_name}", "pyplumio"
17
+ )
18
+
19
+
12
20
  async def create_instance(class_path: str, **kwargs: Any) -> Any:
13
21
  """Return a class instance from the class path."""
14
- loop = asyncio.get_running_loop()
15
22
  module_name, class_name = class_path.rsplit(".", 1)
16
23
  try:
17
- module = await loop.run_in_executor(
18
- None, import_module, "." + module_name, "pyplumio"
19
- )
24
+ module = await _load_module(module_name)
20
25
  return getattr(module, class_name)(**kwargs)
21
26
  except Exception:
22
27
  _LOGGER.error("Failed to load module (%s)", class_path)
@@ -9,7 +9,7 @@ from typing import Final, Literal
9
9
 
10
10
  from pyplumio.const import STATE_OFF, STATE_ON
11
11
  from pyplumio.devices import AddressableDevice
12
- from pyplumio.frames.requests import SetScheduleRequest
12
+ from pyplumio.helpers.factory import create_instance
13
13
  from pyplumio.structures.schedules import collect_schedule_data
14
14
 
15
15
  TIME_FORMAT: Final = "%H:%M"
@@ -158,11 +158,11 @@ class Schedule(Iterable):
158
158
  self.saturday,
159
159
  ).__iter__()
160
160
 
161
- def commit(self) -> None:
161
+ async def commit(self) -> None:
162
162
  """Commit a weekly schedule to the device."""
163
- self.device.queue.put_nowait(
164
- SetScheduleRequest(
165
- recipient=self.device.address,
166
- data=collect_schedule_data(self.name, self.device),
167
- )
163
+ request = await create_instance(
164
+ "frames.requests.SetScheduleRequest",
165
+ recipient=self.device.address,
166
+ data=collect_schedule_data(self.name, self.device),
168
167
  )
168
+ await self.device.queue.put(request)
pyplumio/protocol.py CHANGED
@@ -233,9 +233,10 @@ class AsyncProtocol(Protocol, EventManager):
233
233
  async def get_device_entry(self, device_type: DeviceType) -> AddressableDevice:
234
234
  """Set up device entry."""
235
235
  handler, name = get_device_handler_and_name(device_type)
236
- return self.data.setdefault(
237
- name, await self._create_device_entry(name, handler)
238
- )
236
+ if name not in self.data:
237
+ self.data[name] = await self._create_device_entry(name, handler)
238
+
239
+ return self.data[name]
239
240
 
240
241
  async def _create_device_entry(self, name: str, handler: str) -> AddressableDevice:
241
242
  """Create device entry."""
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
 
4
4
  from collections.abc import Generator
5
5
  from dataclasses import dataclass
6
- from typing import Any, Final
6
+ from typing import Any, Final, cast
7
7
 
8
8
  from pyplumio.const import (
9
9
  ATTR_INDEX,
@@ -47,37 +47,27 @@ class EcomaxParameter(Parameter):
47
47
  async def create_request(self) -> Request:
48
48
  """Create a request to change the parameter."""
49
49
  if self.description.name == ATTR_ECOMAX_CONTROL:
50
- request: Request = await create_instance(
51
- "frames.requests.EcomaxControlRequest",
52
- recipient=self.device.address,
53
- data={
54
- ATTR_VALUE: self.values.value,
55
- },
56
- )
57
-
50
+ cls = "frames.requests.EcomaxControlRequest"
51
+ data = {ATTR_VALUE: self.values.value}
58
52
  elif self.description.name == ATTR_THERMOSTAT_PROFILE:
59
- request = await create_instance(
60
- "frames.requests.SetThermostatParameterRequest",
61
- recipient=self.device.address,
62
- data={
63
- ATTR_INDEX: self._index,
64
- ATTR_VALUE: self.values.value,
65
- ATTR_OFFSET: 0,
66
- ATTR_SIZE: 1,
67
- },
68
- )
69
-
53
+ cls = "frames.requests.SetThermostatParameterRequest"
54
+ data = {
55
+ ATTR_INDEX: self._index,
56
+ ATTR_VALUE: self.values.value,
57
+ ATTR_OFFSET: 0,
58
+ ATTR_SIZE: 1,
59
+ }
70
60
  else:
71
- request = await create_instance(
72
- "frames.requests.SetEcomaxParameterRequest",
73
- recipient=self.device.address,
74
- data={
75
- ATTR_INDEX: self._index,
76
- ATTR_VALUE: self.values.value,
77
- },
78
- )
79
-
80
- return request
61
+ cls = "frames.requests.SetEcomaxParameterRequest"
62
+ data = {
63
+ ATTR_INDEX: self._index,
64
+ ATTR_VALUE: self.values.value,
65
+ }
66
+
67
+ return cast(
68
+ Request,
69
+ await create_instance(cls, recipient=self.device.address, data=data),
70
+ )
81
71
 
82
72
  async def set(self, value: ParameterValueType, retries: int = 5) -> bool:
83
73
  """Set a parameter value."""