aioWiserHeatAPI 1.5.0__tar.gz → 1.5.2__tar.gz

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 (52) hide show
  1. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/PKG-INFO +20 -9
  2. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/README.md +13 -1
  3. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/__init__.py +1 -1
  4. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/rest_controller.py +38 -38
  5. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/schedule.py +138 -53
  6. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/wiserhub.py +18 -9
  7. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI.egg-info/PKG-INFO +20 -9
  8. aioWiserHeatAPI-1.5.2/aioWiserHeatAPI.egg-info/requires.txt +4 -0
  9. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/setup.py +6 -7
  10. aioWiserHeatAPI-1.5.0/aioWiserHeatAPI.egg-info/requires.txt +0 -5
  11. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/LICENSE +0 -0
  12. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/cli.py +0 -0
  13. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/const.py +0 -0
  14. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/devices.py +0 -0
  15. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/discovery.py +0 -0
  16. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/exceptions.py +0 -0
  17. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/heating.py +0 -0
  18. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/heating_actuator.py +0 -0
  19. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/__init__.py +0 -0
  20. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/automations.py +0 -0
  21. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/battery.py +0 -0
  22. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/capabilities.py +0 -0
  23. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/cloud.py +0 -0
  24. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/device.py +0 -0
  25. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/equipment.py +0 -0
  26. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/extra_config.py +0 -0
  27. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/firmware.py +0 -0
  28. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/gps.py +0 -0
  29. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/misc.py +0 -0
  30. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/network.py +0 -0
  31. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/opentherm.py +0 -0
  32. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/signal.py +0 -0
  33. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/special_times.py +0 -0
  34. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/status.py +0 -0
  35. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/temp.py +0 -0
  36. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/helpers/zigbee.py +0 -0
  37. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/hot_water.py +0 -0
  38. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/light.py +0 -0
  39. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/moments.py +0 -0
  40. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/pte.py +0 -0
  41. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/room.py +0 -0
  42. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/roomstat.py +0 -0
  43. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/shutter.py +0 -0
  44. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/smartplug.py +0 -0
  45. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/smartvalve.py +0 -0
  46. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/system.py +0 -0
  47. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI/ufh.py +0 -0
  48. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI.egg-info/SOURCES.txt +0 -0
  49. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI.egg-info/dependency_links.txt +0 -0
  50. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI.egg-info/entry_points.txt +0 -0
  51. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/aioWiserHeatAPI.egg-info/top_level.txt +0 -0
  52. {aioWiserHeatAPI-1.5.0 → aioWiserHeatAPI-1.5.2}/setup.cfg +0 -0
@@ -1,25 +1,24 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: aioWiserHeatAPI
3
- Version: 1.5.0
3
+ Version: 1.5.2
4
4
  Summary: An AsyncIO API for controlling the Drayton Wiser Heating system
5
5
  Home-page: https://github.com/msp1974/aioWiserHeatAPI
6
6
  Author: Mark Parker
7
7
  Author-email: msparker@sky.com
8
8
  Classifier: Development Status :: 5 - Production/Stable
9
9
  Classifier: Intended Audience :: Developers
10
- Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
11
  Classifier: License :: OSI Approved :: MIT License
12
12
  Classifier: Operating System :: OS Independent
13
- Requires-Python: >=3.10
13
+ Requires-Python: >=3.11
14
14
  Description-Content-Type: text/markdown
15
15
  License-File: LICENSE
16
- Requires-Dist: zeroconf>=0.47.1
17
- Requires-Dist: aiohttp>=3.8.1
18
- Requires-Dist: aiofiles>=0.8.0
19
- Requires-Dist: pyyaml>=6.0
20
- Requires-Dist: httpx>=0.25.0
16
+ Requires-Dist: zeroconf>=0.127.0
17
+ Requires-Dist: aiohttp>=3.9.1
18
+ Requires-Dist: aiofiles>=23.2.1
19
+ Requires-Dist: pyyaml>=6.0.1
21
20
 
22
- # Drayton Wiser Hub API Async v1.4.0
21
+ # Drayton Wiser Hub API Async v1.5.2
23
22
 
24
23
  This repository contains a simple API which queries the Drayton Wiser Heating sysystem used in the UK.
25
24
 
@@ -73,6 +72,18 @@ Documentation available in [info.md](https://github.com/msp1974/wiserHeatAPIv2/b
73
72
 
74
73
  ## Changelog
75
74
 
75
+ ### v1.5.2
76
+
77
+ * Revert to aiohttp and fix errors with v3.9.x that caused move to httpx
78
+
79
+ ### v1.5.1
80
+
81
+ * Fix nuances with httpx
82
+
83
+ ### v1.5.0
84
+
85
+ * Move to httpx instead of aiohttp
86
+
76
87
  ### v1.4.0
77
88
 
78
89
  * Add PowerTagE support
@@ -1,4 +1,4 @@
1
- # Drayton Wiser Hub API Async v1.4.0
1
+ # Drayton Wiser Hub API Async v1.5.2
2
2
 
3
3
  This repository contains a simple API which queries the Drayton Wiser Heating sysystem used in the UK.
4
4
 
@@ -52,6 +52,18 @@ Documentation available in [info.md](https://github.com/msp1974/wiserHeatAPIv2/b
52
52
 
53
53
  ## Changelog
54
54
 
55
+ ### v1.5.2
56
+
57
+ * Revert to aiohttp and fix errors with v3.9.x that caused move to httpx
58
+
59
+ ### v1.5.1
60
+
61
+ * Fix nuances with httpx
62
+
63
+ ### v1.5.0
64
+
65
+ * Move to httpx instead of aiohttp
66
+
55
67
  ### v1.4.0
56
68
 
57
69
  * Add PowerTagE support
@@ -3,6 +3,6 @@ import logging
3
3
  name = "aioWiserHeatAPI"
4
4
  __all__ = ["wiserAPI", "wiserDiscovery"]
5
5
 
6
- __VERSION__ = "1.5.0"
6
+ __VERSION__ = "1.5.2"
7
7
 
8
8
  _LOGGER = logging.getLogger(__name__)
@@ -1,12 +1,10 @@
1
1
  import asyncio
2
2
  import enum
3
3
  import json
4
- import re
5
4
  from dataclasses import dataclass
6
- from typing import Any, Optional, cast
5
+ from typing import Optional
7
6
 
8
7
  import aiohttp
9
- import httpx
10
8
 
11
9
  from aioWiserHeatAPI.helpers.extra_config import _WiserExtraConfig
12
10
 
@@ -57,14 +55,12 @@ class _WiserRestController(object):
57
55
 
58
56
  def __init__(
59
57
  self,
60
- session: Optional[aiohttp.ClientSession] = None,
61
58
  timeout: Optional[float] = REST_TIMEOUT,
62
59
  wiser_connection_info: Optional[_WiserConnectionInfo] = None,
63
60
  ):
64
61
  self._wiser_connection_info = wiser_connection_info
65
62
  self._api_parameters = WiserAPIParams()
66
-
67
- self._timeout = timeout # aiohttp.ClientTimeout(total=timeout)
63
+ self._timeout = aiohttp.ClientTimeout(total=timeout)
68
64
  self._hub_name = None
69
65
  self._extra_config_file = None
70
66
  self._extra_config: _WiserExtraConfig = None
@@ -88,12 +84,11 @@ class _WiserRestController(object):
88
84
  self._wiser_connection_info.port,
89
85
  )
90
86
 
91
- kwargs = {
92
- "headers": {
93
- "SECRET": self._wiser_connection_info.secret,
94
- "Content-Type": "application/json;charset=UTF-8",
95
- "Connection": "close",
96
- }
87
+ kwargs = {}
88
+
89
+ kwargs["headers"] = {
90
+ "SECRET": self._wiser_connection_info.secret,
91
+ "Content-Type": "application/json;charset=UTF-8",
97
92
  }
98
93
 
99
94
  if data is not None:
@@ -103,35 +98,40 @@ class _WiserRestController(object):
103
98
  kwargs["timeout"] = self._timeout
104
99
 
105
100
  try:
106
- async with httpx.AsyncClient() as client:
107
- response = await getattr(client, action.value)(
101
+ async with aiohttp.ClientSession(
102
+ version=aiohttp.HttpVersion10,
103
+ ) as session:
104
+ async with getattr(session, action.value)(
108
105
  url,
109
106
  **kwargs,
110
- )
111
-
112
- if response.status_code != 200:
113
- self._process_nok_response(
114
- response, url, data, raise_for_endpoint_error
115
- )
116
- else:
117
- content = await response.aread()
118
- if len(content) > 0:
119
- response = content.decode("utf-8", "ignore").encode(
120
- "utf-8"
107
+ ) as response:
108
+ if not response.ok:
109
+ self._process_nok_response(
110
+ response, url, data, raise_for_endpoint_error
121
111
  )
122
- return json.loads(response)
123
112
  else:
124
- return {}
125
- return {}
113
+ content = await response.read()
114
+ if len(content) > 0:
115
+ response = content.decode(
116
+ "utf-8", "ignore"
117
+ ).encode("utf-8")
118
+ return json.loads(response)
119
+ else:
120
+ return {}
121
+ return {}
126
122
 
127
- except httpx.TimeoutException as ex:
123
+ except asyncio.TimeoutError as ex:
128
124
  raise WiserHubConnectionError(
129
- f"Connection timeout trying to communicate with Wiser Hub {self._wiser_connection_info.host} for url {url}. Error is {ex}"
130
- ) from ex
131
- except httpx.NetworkError as ex:
125
+ f"Connection timeout trying to communicate with Wiser Hub {self._wiser_connection_info.host} for url {url}"
126
+ )
127
+ except aiohttp.ClientResponseError as ex:
128
+ raise WiserHubConnectionError(
129
+ f"Response error trying to communicate with Wiser Hub {self._wiser_connection_info.host} for url {url}. Error is {ex}"
130
+ )
131
+ except aiohttp.ClientConnectorError as ex:
132
132
  raise WiserHubConnectionError(
133
- f"Connection error trying to communicate with Wiser Hub {self._wiser_connection_info.host} for url {url}. Error is {ex}"
134
- ) from ex
133
+ f"Connection error trying to communicate with Wiser Hub {self._wiser_connection_info.host} for url {url}. Error is {ex}"
134
+ )
135
135
 
136
136
  def _process_nok_response(
137
137
  self,
@@ -140,21 +140,21 @@ class _WiserRestController(object):
140
140
  data: dict,
141
141
  raise_for_endpoint_error: bool = True,
142
142
  ):
143
- if response.status_code == 401:
143
+ if response.status == 401:
144
144
  raise WiserHubAuthenticationError(
145
145
  f"Error authenticating to Wiser Hub {self._wiser_connection_info.host}. Check your secret key"
146
146
  )
147
- elif response.status_code == 404 and raise_for_endpoint_error:
147
+ elif response.status == 404 and raise_for_endpoint_error:
148
148
  raise WiserHubRESTError(
149
149
  f"Rest endpoint not found on Wiser Hub {self._wiser_connection_info.host} for url {url}"
150
150
  )
151
- elif response.status_code == 408:
151
+ elif response.status == 408:
152
152
  raise WiserHubConnectionError(
153
153
  f"Connection timed out trying to communicate with Wiser Hub {self._wiser_connection_info.host} for url {url}"
154
154
  )
155
155
  elif raise_for_endpoint_error:
156
156
  raise WiserHubRESTError(
157
- f"Unknown error communicating with Wiser Hub {self._wiser_connection_info.host} for url {url} with data {data}. Error code is: {response.status_code}"
157
+ f"Unknown error communicating with Wiser Hub {self._wiser_connection_info.host} for url {url} with data {data}. Error code is: {response.status}"
158
158
  )
159
159
 
160
160
  async def _get_hub_data(
@@ -1,18 +1,10 @@
1
- import aiofiles
2
1
  import json
3
2
  import time
4
3
  from datetime import datetime, timedelta
5
4
 
5
+ import aiofiles
6
6
  import yaml
7
- from yaml import SafeLoader, SafeDumper
8
-
9
- from .exceptions import (
10
- WiserScheduleError,
11
- WiserScheduleInvalidSetting,
12
- WiserScheduleInvalidTime,
13
- )
14
-
15
- from .helpers.misc import file_exists
7
+ from yaml import SafeDumper, SafeLoader
16
8
 
17
9
  from .const import (
18
10
  DEFAULT_LEVEL_SCHEDULE,
@@ -38,7 +30,12 @@ from .const import (
38
30
  WEEKENDS,
39
31
  WiserScheduleTypeEnum,
40
32
  )
41
- from .helpers.misc import is_valid_level
33
+ from .exceptions import (
34
+ WiserScheduleError,
35
+ WiserScheduleInvalidSetting,
36
+ WiserScheduleInvalidTime,
37
+ )
38
+ from .helpers.misc import file_exists, is_valid_level
42
39
  from .helpers.temp import _WiserTemperatureFunctions as tf
43
40
  from .rest_controller import _WiserRestController
44
41
 
@@ -122,10 +119,14 @@ class _WiserSchedule(object):
122
119
  schedule_set_points = self._convert_wiser_to_yaml_day(
123
120
  day, sched, replace_special_times, generic_setpoint
124
121
  )
125
- schedule_output.update({day.capitalize(): schedule_set_points})
122
+ schedule_output.update(
123
+ {day.capitalize(): schedule_set_points}
124
+ )
126
125
  return schedule_output
127
126
  except Exception as ex:
128
- raise WiserScheduleError(f"Error converting from Wiser schedule: {ex}")
127
+ raise WiserScheduleError(
128
+ f"Error converting from Wiser schedule: {ex}"
129
+ )
129
130
 
130
131
  def _convert_to_wiser_schedule(self, schedule_data: dict) -> dict:
131
132
  """
@@ -145,7 +146,9 @@ class _WiserSchedule(object):
145
146
  schedule_output.update({weekday: schedule_day})
146
147
  elif day.title() == TEXT_WEEKENDS:
147
148
  for weekend_day in WEEKENDS:
148
- schedule_output.update({weekend_day: schedule_day})
149
+ schedule_output.update(
150
+ {weekend_day: schedule_day}
151
+ )
149
152
  elif day.title() == TEXT_ALL:
150
153
  for day in WEEKDAYS + WEEKENDS:
151
154
  schedule_output.update({day: schedule_day})
@@ -155,7 +158,9 @@ class _WiserSchedule(object):
155
158
  except (WiserScheduleInvalidTime, WiserScheduleInvalidSetting) as ex:
156
159
  raise WiserScheduleError(ex)
157
160
  except Exception as ex:
158
- raise WiserScheduleError(f"Error converting to Wiser schedule: {ex}")
161
+ raise WiserScheduleError(
162
+ f"Error converting to Wiser schedule: {ex}"
163
+ )
159
164
 
160
165
  async def _send_schedule_command(
161
166
  self, action: str, schedule_data: dict, id: int = 0
@@ -215,13 +220,17 @@ class _WiserSchedule(object):
215
220
 
216
221
  async def set_name(self, name: str):
217
222
  """Set name of schedule"""
218
- return await self._send_schedule_command("UPDATE", {"Name": name}, self.id)
223
+ return await self._send_schedule_command(
224
+ "UPDATE", {"Name": name}, self.id
225
+ )
219
226
 
220
227
  @property
221
228
  def next(self):
222
229
  """Get details of next schedule entry"""
223
230
  if self._schedule_data.get("Next"):
224
- return _WiserScheduleNext(self._type, self._schedule_data.get("Next"))
231
+ return _WiserScheduleNext(
232
+ self._type, self._schedule_data.get("Next")
233
+ )
225
234
 
226
235
  @property
227
236
  def schedule_data(self) -> str:
@@ -232,7 +241,9 @@ class _WiserSchedule(object):
232
241
  def ws_schedule_data(self) -> dict:
233
242
  """Get formatted schedule data for webservice support"""
234
243
  s = self._remove_schedule_elements(
235
- self._convert_from_wiser_schedule(self.schedule_data, generic_setpoint=True)
244
+ self._convert_from_wiser_schedule(
245
+ self.schedule_data, generic_setpoint=True
246
+ )
236
247
  )
237
248
  return {
238
249
  "Id": self.id,
@@ -271,10 +282,12 @@ class _WiserSchedule(object):
271
282
  """
272
283
  try:
273
284
  if self.id != 1000:
274
- await self._send_schedule_command("DELETE", {})
285
+ await self._send_schedule_command("DELETE", None)
275
286
  return True
276
287
  else:
277
- raise WiserScheduleError("You cannot delete the schedule for HotWater")
288
+ raise WiserScheduleError(
289
+ "You cannot delete the schedule for HotWater"
290
+ )
278
291
  except Exception as ex:
279
292
  raise WiserScheduleError(f"Error deleting schedule - {ex}")
280
293
 
@@ -286,13 +299,17 @@ class _WiserSchedule(object):
286
299
  """
287
300
  try:
288
301
  async with aiofiles.open(schedule_file, "w") as file:
289
- output = json.dumps(self._ensure_type(self._schedule_data), indent=4)
302
+ output = json.dumps(
303
+ self._ensure_type(self._schedule_data), indent=4
304
+ )
290
305
  await file.write(output)
291
306
  return True
292
307
  except Exception as ex:
293
308
  raise WiserScheduleError(f"Error saving schedule to file - {ex}")
294
309
 
295
- async def save_schedule_to_yaml_file(self, schedule_yaml_file: str) -> bool:
310
+ async def save_schedule_to_yaml_file(
311
+ self, schedule_yaml_file: str
312
+ ) -> bool:
296
313
  """
297
314
  Save this schedule to a file as yaml.
298
315
  param scheduleFile: file to write schedule to
@@ -310,7 +327,9 @@ class _WiserSchedule(object):
310
327
  await file.write(output)
311
328
  return True
312
329
  except Exception as ex:
313
- raise WiserScheduleError(f"Error saving schedule to yaml file - {ex}")
330
+ raise WiserScheduleError(
331
+ f"Error saving schedule to yaml file - {ex}"
332
+ )
314
333
 
315
334
  async def set_schedule(self, schedule_data: dict) -> bool:
316
335
  """
@@ -351,7 +370,9 @@ class _WiserSchedule(object):
351
370
  f"Error setting schedule from file. {schedule_file} does not exist"
352
371
  )
353
372
  except Exception as ex:
354
- raise WiserScheduleError(f"Error setting schedule from file - {ex}")
373
+ raise WiserScheduleError(
374
+ f"Error setting schedule from file - {ex}"
375
+ )
355
376
 
356
377
  async def set_schedule_from_yaml_data(self, schedule_data: str) -> bool:
357
378
  """
@@ -370,9 +391,13 @@ class _WiserSchedule(object):
370
391
  f"This is an incorrect schedule type for this device. It should be a {self.schedule_type} schedule."
371
392
  )
372
393
  except Exception as ex:
373
- raise WiserScheduleError(f"Error setting schedule from yaml data - {ex}")
394
+ raise WiserScheduleError(
395
+ f"Error setting schedule from yaml data - {ex}"
396
+ )
374
397
 
375
- async def set_schedule_from_yaml_file(self, schedule_yaml_file: str) -> bool:
398
+ async def set_schedule_from_yaml_file(
399
+ self, schedule_yaml_file: str
400
+ ) -> bool:
376
401
  """
377
402
  Set schedule from file.
378
403
  param schedule_file: file of yaml data respresenting a schedule
@@ -391,7 +416,9 @@ class _WiserSchedule(object):
391
416
  f"This is an incorrect schedule type for this device. It should be a {self.schedule_type} schedule."
392
417
  )
393
418
  except Exception as ex:
394
- raise WiserScheduleError(f"Error setting schedule from yaml file - {ex}")
419
+ raise WiserScheduleError(
420
+ f"Error setting schedule from yaml file - {ex}"
421
+ )
395
422
 
396
423
  async def set_schedule_from_ws_data(self, schedule_data: dict) -> bool:
397
424
  """
@@ -403,7 +430,9 @@ class _WiserSchedule(object):
403
430
  if self._validate_schedule_type(schedule_data):
404
431
  schedule_json = {}
405
432
  for entry in schedule_data.get("ScheduleData"):
406
- schedule_json.update({entry.get("day"): entry.get("slots")})
433
+ schedule_json.update(
434
+ {entry.get("day"): entry.get("slots")}
435
+ )
407
436
  schedule = self._convert_to_wiser_schedule(schedule_json)
408
437
  await self.set_schedule(schedule)
409
438
  return True
@@ -429,7 +458,11 @@ class _WiserHeatingSchedule(_WiserSchedule):
429
458
  sunsets,
430
459
  ):
431
460
  super().__init__(
432
- wiser_rest_controller, schedule_type, schedule_data, sunrises, sunsets
461
+ wiser_rest_controller,
462
+ schedule_type,
463
+ schedule_data,
464
+ sunrises,
465
+ sunsets,
433
466
  )
434
467
 
435
468
  async def assign_schedule(
@@ -452,7 +485,9 @@ class _WiserHeatingSchedule(_WiserSchedule):
452
485
  try:
453
486
  await self._send_schedule_command("ASSIGN", schedule_data)
454
487
  except Exception as ex:
455
- raise WiserScheduleError(f"Error assigning/unassigning schedule: {ex}")
488
+ raise WiserScheduleError(
489
+ f"Error assigning/unassigning schedule: {ex}"
490
+ )
456
491
 
457
492
  async def unassign_schedule(self, room_ids: list):
458
493
  if not isinstance(room_ids, list):
@@ -461,7 +496,9 @@ class _WiserHeatingSchedule(_WiserSchedule):
461
496
  remaining_rooms_ids = []
462
497
  if room_ids and self.assignment_ids:
463
498
  remaining_rooms_ids = [
464
- room_id for room_id in self.assignment_ids if room_id not in room_ids
499
+ room_id
500
+ for room_id in self.assignment_ids
501
+ if room_id not in room_ids
465
502
  ]
466
503
  return await self.assign_schedule(remaining_rooms_ids, False)
467
504
 
@@ -509,11 +546,15 @@ class _WiserHeatingSchedule(_WiserSchedule):
509
546
  time = str(value).replace(":", "")
510
547
  times.append(time)
511
548
  else:
512
- raise WiserScheduleInvalidTime(f"Invalid time value - {value}")
549
+ raise WiserScheduleInvalidTime(
550
+ f"Invalid time value - {value}"
551
+ )
513
552
  if key.title() in [TEXT_TEMP, TEXT_SETPOINT]:
514
553
  if tf._is_valid_temp(value):
515
554
  temp = tf._to_wiser_temp(
516
- float(value) if str(value).title() != TEXT_OFF else TEMP_OFF
555
+ float(value)
556
+ if str(value).title() != TEXT_OFF
557
+ else TEMP_OFF
517
558
  )
518
559
  temps.append(temp)
519
560
  else:
@@ -535,7 +576,11 @@ class _WiserOnOffSchedule(_WiserSchedule):
535
576
  sunsets,
536
577
  ):
537
578
  super().__init__(
538
- wiser_rest_controller, schedule_type, schedule_data, sunrises, sunsets
579
+ wiser_rest_controller,
580
+ schedule_type,
581
+ schedule_data,
582
+ sunrises,
583
+ sunsets,
539
584
  )
540
585
  self._device_type_ids = []
541
586
 
@@ -568,7 +613,9 @@ class _WiserOnOffSchedule(_WiserSchedule):
568
613
  try:
569
614
  return await self._send_schedule_command("ASSIGN", schedule_data)
570
615
  except Exception as ex:
571
- raise WiserScheduleError(f"Error assigning/unassigning schedule: {ex}")
616
+ raise WiserScheduleError(
617
+ f"Error assigning/unassigning schedule: {ex}"
618
+ )
572
619
 
573
620
  async def unassign_schedule(self, device_ids: list):
574
621
  if not isinstance(device_ids, list):
@@ -612,7 +659,9 @@ class _WiserOnOffSchedule(_WiserSchedule):
612
659
  "%H%M",
613
660
  )
614
661
  ).strftime("%H:%M"),
615
- (TEXT_SETPOINT if generic_setpoint else TEXT_STATE): TEXT_ON
662
+ (
663
+ TEXT_SETPOINT if generic_setpoint else TEXT_STATE
664
+ ): TEXT_ON
616
665
  if day_schedule[i] == abs(day_schedule[i])
617
666
  else TEXT_OFF,
618
667
  }
@@ -634,7 +683,9 @@ class _WiserOnOffSchedule(_WiserSchedule):
634
683
  if self._is_valid_time(value):
635
684
  time = int(str(value).replace(":", ""))
636
685
  else:
637
- raise WiserScheduleInvalidTime(f"Invalid time value - {value}")
686
+ raise WiserScheduleInvalidTime(
687
+ f"Invalid time value - {value}"
688
+ )
638
689
  if key.title() in [TEXT_STATE, TEXT_SETPOINT]:
639
690
  if value.title() in [TEXT_ON, TEXT_OFF]:
640
691
  if value.title() == TEXT_OFF:
@@ -662,7 +713,11 @@ class _WiserLevelSchedule(_WiserSchedule):
662
713
  sunsets,
663
714
  ):
664
715
  super().__init__(
665
- wiser_rest_controller, schedule_type, schedule_data, sunrises, sunsets
716
+ wiser_rest_controller,
717
+ schedule_type,
718
+ schedule_data,
719
+ sunrises,
720
+ sunsets,
666
721
  )
667
722
 
668
723
  @property
@@ -673,7 +728,9 @@ class _WiserLevelSchedule(_WiserSchedule):
673
728
  @property
674
729
  def level_type_id(self) -> int:
675
730
  """Get the schedule level type id"""
676
- return 2 if self.level_type == WiserScheduleTypeEnum.shutters.value else 1
731
+ return (
732
+ 2 if self.level_type == WiserScheduleTypeEnum.shutters.value else 1
733
+ )
677
734
 
678
735
  @property
679
736
  def next(self):
@@ -681,14 +738,18 @@ class _WiserLevelSchedule(_WiserSchedule):
681
738
  if self._schedule_data.get("Next"):
682
739
  return _WiserScheduleNext(
683
740
  self._type,
684
- self._schedule_data.get("Next", {"Day": "", "Time": 0, "Level": 0}),
741
+ self._schedule_data.get(
742
+ "Next", {"Day": "", "Time": 0, "Level": 0}
743
+ ),
685
744
  )
686
745
 
687
746
  @property
688
747
  def schedule_data(self) -> str:
689
748
  """Get json output of schedule data"""
690
749
  """ Fix for issue of level scheudle can be empty"""
691
- schedule_data = self._remove_schedule_elements(self._schedule_data.copy())
750
+ schedule_data = self._remove_schedule_elements(
751
+ self._schedule_data.copy()
752
+ )
692
753
  if schedule_data:
693
754
  return schedule_data
694
755
  return DEFAULT_LEVEL_SCHEDULE
@@ -717,12 +778,17 @@ class _WiserLevelSchedule(_WiserSchedule):
717
778
  "Type": self.level_type_id,
718
779
  }
719
780
  type_data.update(self.schedule_data)
720
- schedule_data = {"Assignments": list(set(device_ids)), self._type: type_data}
781
+ schedule_data = {
782
+ "Assignments": list(set(device_ids)),
783
+ self._type: type_data,
784
+ }
721
785
 
722
786
  try:
723
787
  return await self._send_schedule_command("ASSIGN", schedule_data)
724
788
  except Exception as ex:
725
- raise WiserScheduleError(f"Error assigning/unassigning schedule: {ex}")
789
+ raise WiserScheduleError(
790
+ f"Error assigning/unassigning schedule: {ex}"
791
+ )
726
792
 
727
793
  async def unassign_schedule(self, device_ids: list):
728
794
  if not isinstance(device_ids, list):
@@ -761,7 +827,9 @@ class _WiserLevelSchedule(_WiserSchedule):
761
827
  else self._sunsets.get(day)
762
828
  ),
763
829
  (
764
- TEXT_SETPOINT if generic_setpoint else TEXT_LEVEL
830
+ TEXT_SETPOINT
831
+ if generic_setpoint
832
+ else TEXT_LEVEL
765
833
  ): day_schedule[TEXT_LEVEL][i],
766
834
  }
767
835
  )
@@ -776,7 +844,9 @@ class _WiserLevelSchedule(_WiserSchedule):
776
844
  ][0]
777
845
  ),
778
846
  (
779
- TEXT_SETPOINT if generic_setpoint else TEXT_LEVEL
847
+ TEXT_SETPOINT
848
+ if generic_setpoint
849
+ else TEXT_LEVEL
780
850
  ): day_schedule[TEXT_LEVEL][i],
781
851
  }
782
852
  )
@@ -785,7 +855,8 @@ class _WiserLevelSchedule(_WiserSchedule):
785
855
  {
786
856
  TEXT_TIME: (
787
857
  datetime.strptime(
788
- format(day_schedule[TEXT_TIME][i], "04d"), "%H%M"
858
+ format(day_schedule[TEXT_TIME][i], "04d"),
859
+ "%H%M",
789
860
  )
790
861
  ).strftime("%H:%M"),
791
862
  (
@@ -865,7 +936,10 @@ class _WiserScheduleNext:
865
936
  )
866
937
  next_date = datetime.today() + timedelta(days=days_diff)
867
938
  return next_date.replace(
868
- hour=self.time.hour, minute=self.time.minute, second=0, microsecond=0
939
+ hour=self.time.hour,
940
+ minute=self.time.minute,
941
+ second=0,
942
+ microsecond=0,
869
943
  )
870
944
  except:
871
945
  return None
@@ -994,12 +1068,14 @@ class _WiserScheduleCollection(object):
994
1068
  return [
995
1069
  schedule
996
1070
  for schedule in self.all
997
- if schedule._type == schedule_type.value and schedule.id == id
1071
+ if schedule._type == schedule_type.value
1072
+ and schedule.id == id
998
1073
  ][0]
999
1074
  return [
1000
1075
  schedule
1001
1076
  for schedule in self.all
1002
- if schedule.schedule_type == schedule_type.value and schedule.id == id
1077
+ if schedule.schedule_type == schedule_type.value
1078
+ and schedule.id == id
1003
1079
  ][0]
1004
1080
  except IndexError:
1005
1081
  return None
@@ -1041,7 +1117,8 @@ class _WiserScheduleCollection(object):
1041
1117
  return [
1042
1118
  schedule
1043
1119
  for schedule in self.all
1044
- if schedule._type == schedule_type.value and schedule.name == name
1120
+ if schedule._type == schedule_type.value
1121
+ and schedule.name == name
1045
1122
  ][0]
1046
1123
  return [
1047
1124
  schedule
@@ -1066,7 +1143,9 @@ class _WiserScheduleCollection(object):
1066
1143
  return self._level_schedules
1067
1144
 
1068
1145
  return [
1069
- schedule for schedule in self.all if schedule.schedule_type == schedule_type
1146
+ schedule
1147
+ for schedule in self.all
1148
+ if schedule.schedule_type == schedule_type
1070
1149
  ]
1071
1150
 
1072
1151
  async def copy_schedule(
@@ -1095,7 +1174,10 @@ class _WiserScheduleCollection(object):
1095
1174
  return False
1096
1175
 
1097
1176
  async def create_schedule(
1098
- self, schedule_type: WiserScheduleTypeEnum, name: str, assignments: list = []
1177
+ self,
1178
+ schedule_type: WiserScheduleTypeEnum,
1179
+ name: str,
1180
+ assignments: list = [],
1099
1181
  ):
1100
1182
  """
1101
1183
  Create a new schedule entry
@@ -1117,6 +1199,9 @@ class _WiserScheduleCollection(object):
1117
1199
  type_data.update(DEFAULT_LEVEL_SCHEDULE)
1118
1200
  schedule_type = WiserScheduleTypeEnum.level
1119
1201
 
1120
- schedule_data = {"Assignments": assignments, schedule_type.value: type_data}
1202
+ schedule_data = {
1203
+ "Assignments": assignments,
1204
+ schedule_type.value: type_data,
1205
+ }
1121
1206
 
1122
1207
  return await self._send_schedule_command("CREATE", schedule_data)
@@ -115,7 +115,7 @@ class WiserAPI(object):
115
115
  ):
116
116
  # Create an instance of the rest controller
117
117
  self._wiser_rest_controller = _WiserRestController(
118
- self._session, wiser_connection_info=self._wiser_api_connection
118
+ wiser_connection_info=self._wiser_api_connection
119
119
  )
120
120
  else:
121
121
  raise WiserHubConnectionError(
@@ -147,8 +147,8 @@ class WiserAPI(object):
147
147
  WISERHUBSCHEDULES
148
148
  )
149
149
  try:
150
- self._status_data = await self._wiser_rest_controller._get_hub_data(
151
- WISERHUBSTATUS
150
+ self._status_data = (
151
+ await self._wiser_rest_controller._get_hub_data(WISERHUBSTATUS)
152
152
  )
153
153
  except WiserHubRESTError:
154
154
  self._status_data = {}
@@ -161,16 +161,22 @@ class WiserAPI(object):
161
161
  )
162
162
 
163
163
  # load extra data
164
- self._wiser_rest_controller._extra_config_file = self._extra_config_file
164
+ self._wiser_rest_controller._extra_config_file = (
165
+ self._extra_config_file
166
+ )
165
167
  await self._wiser_rest_controller._get_extra_config_data()
166
168
 
167
169
  # Only get opentherm data if connected
168
170
  if (
169
- self._domain_data.get("System", {}).get("OpenThermConnectionStatus", "")
171
+ self._domain_data.get("System", {}).get(
172
+ "OpenThermConnectionStatus", ""
173
+ )
170
174
  == "Connected"
171
175
  ):
172
- self._opentherm_data = await self._wiser_rest_controller._get_hub_data(
173
- WISERHUBOPENTHERM, False
176
+ self._opentherm_data = (
177
+ await self._wiser_rest_controller._get_hub_data(
178
+ WISERHUBOPENTHERM, False
179
+ )
174
180
  )
175
181
 
176
182
  if self._domain_data != {} and self._network_data != {}:
@@ -228,7 +234,8 @@ class WiserAPI(object):
228
234
  # Moments
229
235
  if self._domain_data.get("Moment"):
230
236
  self._moments = _WiserMomentCollection(
231
- self._wiser_rest_controller, self._domain_data.get("Moment")
237
+ self._wiser_rest_controller,
238
+ self._domain_data.get("Moment"),
232
239
  )
233
240
 
234
241
  # If gets here with no exceptions then success and return true
@@ -326,7 +333,9 @@ class WiserAPI(object):
326
333
  try:
327
334
  if data:
328
335
  # Write out to file
329
- log_response_to_file(data, filename, False, pathlib.Path(file_path))
336
+ log_response_to_file(
337
+ data, filename, False, pathlib.Path(file_path)
338
+ )
330
339
  return True
331
340
  except Exception as ex:
332
341
  _LOGGER.error(ex)
@@ -1,25 +1,24 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: aioWiserHeatAPI
3
- Version: 1.5.0
3
+ Version: 1.5.2
4
4
  Summary: An AsyncIO API for controlling the Drayton Wiser Heating system
5
5
  Home-page: https://github.com/msp1974/aioWiserHeatAPI
6
6
  Author: Mark Parker
7
7
  Author-email: msparker@sky.com
8
8
  Classifier: Development Status :: 5 - Production/Stable
9
9
  Classifier: Intended Audience :: Developers
10
- Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
11
  Classifier: License :: OSI Approved :: MIT License
12
12
  Classifier: Operating System :: OS Independent
13
- Requires-Python: >=3.10
13
+ Requires-Python: >=3.11
14
14
  Description-Content-Type: text/markdown
15
15
  License-File: LICENSE
16
- Requires-Dist: zeroconf>=0.47.1
17
- Requires-Dist: aiohttp>=3.8.1
18
- Requires-Dist: aiofiles>=0.8.0
19
- Requires-Dist: pyyaml>=6.0
20
- Requires-Dist: httpx>=0.25.0
16
+ Requires-Dist: zeroconf>=0.127.0
17
+ Requires-Dist: aiohttp>=3.9.1
18
+ Requires-Dist: aiofiles>=23.2.1
19
+ Requires-Dist: pyyaml>=6.0.1
21
20
 
22
- # Drayton Wiser Hub API Async v1.4.0
21
+ # Drayton Wiser Hub API Async v1.5.2
23
22
 
24
23
  This repository contains a simple API which queries the Drayton Wiser Heating sysystem used in the UK.
25
24
 
@@ -73,6 +72,18 @@ Documentation available in [info.md](https://github.com/msp1974/wiserHeatAPIv2/b
73
72
 
74
73
  ## Changelog
75
74
 
75
+ ### v1.5.2
76
+
77
+ * Revert to aiohttp and fix errors with v3.9.x that caused move to httpx
78
+
79
+ ### v1.5.1
80
+
81
+ * Fix nuances with httpx
82
+
83
+ ### v1.5.0
84
+
85
+ * Move to httpx instead of aiohttp
86
+
76
87
  ### v1.4.0
77
88
 
78
89
  * Add PowerTagE support
@@ -0,0 +1,4 @@
1
+ zeroconf>=0.127.0
2
+ aiohttp>=3.9.1
3
+ aiofiles>=23.2.1
4
+ pyyaml>=6.0.1
@@ -35,18 +35,17 @@ setuptools.setup(
35
35
  classifiers=[
36
36
  "Development Status :: 5 - Production/Stable",
37
37
  "Intended Audience :: Developers",
38
- "Programming Language :: Python :: 3.10",
38
+ "Programming Language :: Python :: 3.11",
39
39
  "License :: OSI Approved :: MIT License",
40
40
  "Operating System :: OS Independent",
41
41
  ],
42
42
  install_requires=[
43
- "zeroconf>=0.47.1",
44
- "aiohttp>=3.8.1",
45
- "aiofiles>=0.8.0",
46
- "pyyaml>=6.0",
47
- "httpx>=0.25.0",
43
+ "zeroconf>=0.127.0",
44
+ "aiohttp>=3.9.1",
45
+ "aiofiles>=23.2.1",
46
+ "pyyaml>=6.0.1",
48
47
  ],
49
- python_requires=">=3.10",
48
+ python_requires=">=3.11",
50
49
  entry_points={
51
50
  "console_scripts": ["wiser = aioWiserHeatAPI.cli:main"],
52
51
  },
@@ -1,5 +0,0 @@
1
- zeroconf>=0.47.1
2
- aiohttp>=3.8.1
3
- aiofiles>=0.8.0
4
- pyyaml>=6.0
5
- httpx>=0.25.0
File without changes