plugwise 0.38.0__py3-none-any.whl → 0.38.1__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.
plugwise/__init__.py CHANGED
@@ -324,7 +324,10 @@ class Smile(SmileComm):
324
324
  state: str | None = None,
325
325
  ) -> None:
326
326
  """Set the selected option for the applicable Select."""
327
- await self._smile_api.set_select(key, loc_id, option, state)
327
+ try:
328
+ await self._smile_api.set_select(key, loc_id, option, state)
329
+ except ConnectionFailedError as exc:
330
+ raise ConnectionFailedError(f"Failed to set select option '{option}': {str(exc)}") from exc
328
331
 
329
332
  async def set_schedule_state(
330
333
  self,
@@ -333,15 +336,25 @@ class Smile(SmileComm):
333
336
  name: str | None = None,
334
337
  ) -> None:
335
338
  """Activate/deactivate the Schedule, with the given name, on the relevant Thermostat."""
336
- await self._smile_api.set_schedule_state(loc_id, state, name)
339
+ try:
340
+ await self._smile_api.set_schedule_state(loc_id, state, name)
341
+ except ConnectionFailedError as exc: # pragma no cover
342
+ raise ConnectionFailedError(f"Failed to set schedule state: {str(exc)}") from exc # pragma no cover
343
+
337
344
 
338
345
  async def set_preset(self, loc_id: str, preset: str) -> None:
339
346
  """Set the given Preset on the relevant Thermostat."""
340
- await self._smile_api.set_preset(loc_id, preset)
347
+ try:
348
+ await self._smile_api.set_preset(loc_id, preset)
349
+ except ConnectionFailedError as exc:
350
+ raise ConnectionFailedError(f"Failed to set preset: {str(exc)}") from exc
341
351
 
342
352
  async def set_temperature(self, loc_id: str, items: dict[str, float]) -> None:
343
353
  """Set the given Temperature on the relevant Thermostat."""
344
- await self._smile_api.set_temperature(loc_id, items)
354
+ try:
355
+ await self._smile_api.set_temperature(loc_id, items)
356
+ except ConnectionFailedError as exc:
357
+ raise ConnectionFailedError(f"Failed to set temperature: {str(exc)}") from exc
345
358
 
346
359
  async def set_number(
347
360
  self,
@@ -350,40 +363,58 @@ class Smile(SmileComm):
350
363
  temperature: float,
351
364
  ) -> None:
352
365
  """Set the maximum boiler- or DHW-setpoint on the Central Heating boiler or the temperature-offset on a Thermostat."""
353
- await self._smile_api.set_number(dev_id, key, temperature)
366
+ try:
367
+ await self._smile_api.set_number(dev_id, key, temperature)
368
+ except ConnectionFailedError as exc:
369
+ raise ConnectionFailedError(f"Failed to set number '{key}': {str(exc)}") from exc
354
370
 
355
371
  async def set_temperature_offset(self, dev_id: str, offset: float) -> None:
356
372
  """Set the Temperature offset for thermostats that support this feature."""
357
- await self._smile_api.set_offset(dev_id, offset) # pragma: no cover
373
+ try: # pragma no cover
374
+ await self._smile_api.set_offset(dev_id, offset) # pragma: no cover
375
+ except ConnectionFailedError as exc: # pragma no cover
376
+ raise ConnectionFailedError(f"Failed to set temperature offset: {str(exc)}") from exc # pragma no cover
358
377
 
359
378
  async def set_switch_state(
360
379
  self, appl_id: str, members: list[str] | None, model: str, state: str
361
380
  ) -> None:
362
381
  """Set the given State of the relevant Switch."""
363
- await self._smile_api.set_switch_state(appl_id, members, model, state)
382
+ try:
383
+ await self._smile_api.set_switch_state(appl_id, members, model, state)
384
+ except ConnectionFailedError as exc:
385
+ raise ConnectionFailedError(f"Failed to set switch state: {str(exc)}") from exc
364
386
 
365
387
  async def set_gateway_mode(self, mode: str) -> None:
366
388
  """Set the gateway mode."""
367
- await self._smile_api.set_gateway_mode(mode) # pragma: no cover
389
+ try: # pragma no cover
390
+ await self._smile_api.set_gateway_mode(mode) # pragma: no cover
391
+ except ConnectionFailedError as exc: # pragma no cover
392
+ raise ConnectionFailedError(f"Failed to set gateway mode: {str(exc)}") from exc # pragma no cover
368
393
 
369
394
  async def set_regulation_mode(self, mode: str) -> None:
370
395
  """Set the heating regulation mode."""
371
- await self._smile_api.set_regulation_mode(mode) # pragma: no cover
396
+ try: # pragma no cover
397
+ await self._smile_api.set_regulation_mode(mode) # pragma: no cover
398
+ except ConnectionFailedError as exc: # pragma no cover
399
+ raise ConnectionFailedError(f"Failed to set regulation mode: {str(exc)}") from exc # pragma no cover
372
400
 
373
401
  async def set_dhw_mode(self, mode: str) -> None:
374
402
  """Set the domestic hot water heating regulation mode."""
375
- await self._smile_api.set_dhw_mode(mode) # pragma: no cover
403
+ try: # pragma no cover
404
+ await self._smile_api.set_dhw_mode(mode) # pragma: no cover
405
+ except ConnectionFailedError as exc: # pragma no cover
406
+ raise ConnectionFailedError(f"Failed to set dhw mode: {str(exc)}") from exc # pragma no cover
376
407
 
377
408
  async def delete_notification(self) -> None:
378
409
  """Delete the active Plugwise Notification."""
379
410
  try:
380
411
  await self._smile_api.delete_notification()
381
412
  except ConnectionFailedError as exc:
382
- raise PlugwiseError(f"Failed to delete notification: {str(exc)}") from exc
413
+ raise ConnectionFailedError(f"Failed to delete notification: {str(exc)}") from exc
383
414
 
384
415
  async def reboot_gateway(self) -> None:
385
416
  """Reboot the Plugwise Gateway."""
386
417
  try:
387
418
  await self._smile_api.reboot_gateway()
388
419
  except ConnectionFailedError as exc:
389
- raise PlugwiseError(f"Failed to reboot gateway: {str(exc)}") from exc
420
+ raise ConnectionFailedError(f"Failed to reboot gateway: {str(exc)}") from exc
plugwise/helper.py CHANGED
@@ -115,30 +115,31 @@ class SmileComm:
115
115
  use_headers = headers
116
116
 
117
117
  try:
118
- if method == "delete":
119
- resp = await self._websession.delete(url, auth=self._auth)
120
- if method == "get":
121
- # Work-around for Stretchv2, should not hurt the other smiles
122
- use_headers = {"Accept-Encoding": "gzip"}
123
- resp = await self._websession.get(
124
- url, headers=use_headers, auth=self._auth
125
- )
126
- if method == "post":
127
- use_headers = {"Content-type": "text/xml"}
128
- resp = await self._websession.post(
129
- url,
130
- headers=use_headers,
131
- data=data,
132
- auth=self._auth,
133
- )
134
- if method == "put":
135
- use_headers = {"Content-type": "text/xml"}
136
- resp = await self._websession.put(
137
- url,
138
- headers=use_headers,
139
- data=data,
140
- auth=self._auth,
141
- )
118
+ match method:
119
+ case "delete":
120
+ resp = await self._websession.delete(url, auth=self._auth)
121
+ case "get":
122
+ # Work-around for Stretchv2, should not hurt the other smiles
123
+ use_headers = {"Accept-Encoding": "gzip"}
124
+ resp = await self._websession.get(
125
+ url, headers=use_headers, auth=self._auth
126
+ )
127
+ case "post":
128
+ use_headers = {"Content-type": "text/xml"}
129
+ resp = await self._websession.post(
130
+ url,
131
+ headers=use_headers,
132
+ data=data,
133
+ auth=self._auth,
134
+ )
135
+ case "put":
136
+ use_headers = {"Content-type": "text/xml"}
137
+ resp = await self._websession.put(
138
+ url,
139
+ headers=use_headers,
140
+ data=data,
141
+ auth=self._auth,
142
+ )
142
143
  except (
143
144
  ClientError
144
145
  ) as exc: # ClientError is an ancestor class of ServerTimeoutError
@@ -167,23 +168,22 @@ class SmileComm:
167
168
 
168
169
  async def _request_validate(self, resp: ClientResponse, method: str) -> etree:
169
170
  """Helper-function for _request(): validate the returned data."""
170
- # Command accepted gives empty body with status 202
171
- if resp.status == 202:
172
- return
173
-
174
- # Cornercase for server not responding with 202
175
- if method in ("post", "put") and resp.status == 200:
176
- return
177
-
178
- if resp.status == 401:
179
- msg = "Invalid Plugwise login, please retry with the correct credentials."
180
- LOGGER.error("%s", msg)
181
- raise InvalidAuthentication
182
-
183
- if resp.status == 405:
184
- msg = "405 Method not allowed."
185
- LOGGER.error("%s", msg)
186
- raise ConnectionFailedError
171
+ match resp.status:
172
+ case 200:
173
+ # Cornercases for server not responding with 202
174
+ if method in ("post", "put"):
175
+ return
176
+ case 202:
177
+ # Command accepted gives empty body with status 202
178
+ return
179
+ case 401:
180
+ msg = "Invalid Plugwise login, please retry with the correct credentials."
181
+ LOGGER.error("%s", msg)
182
+ raise InvalidAuthentication
183
+ case 405:
184
+ msg = "405 Method not allowed."
185
+ LOGGER.error("%s", msg)
186
+ raise ConnectionFailedError
187
187
 
188
188
  if not (result := await resp.text()) or (
189
189
  "<error>" in result and "Not started" not in result
plugwise/legacy/smile.py CHANGED
@@ -5,6 +5,7 @@ Plugwise backend module for Home Assistant Core - covering the legacy P1, Anna,
5
5
  from __future__ import annotations
6
6
 
7
7
  import datetime as dt
8
+ from typing import Any
8
9
 
9
10
  from plugwise.constants import (
10
11
  APPLIANCES,
@@ -23,7 +24,7 @@ from plugwise.constants import (
23
24
  PlugwiseData,
24
25
  ThermoLoc,
25
26
  )
26
- from plugwise.exceptions import PlugwiseError
27
+ from plugwise.exceptions import ConnectionFailedError, PlugwiseError
27
28
  from plugwise.helper import SmileComm
28
29
  from plugwise.legacy.data import SmileLegacyData
29
30
 
@@ -180,7 +181,7 @@ class SmileLegacyAPI(SmileComm, SmileLegacyData):
180
181
  rule = self._domain_objects.find(locator)
181
182
  data = f'<rules><rule id="{rule.attrib["id"]}"><active>true</active></rule></rules>'
182
183
 
183
- await self._request(RULES, method="put", data=data)
184
+ await self.call_request(RULES, method="put", data=data)
184
185
 
185
186
  async def set_regulation_mode(self, mode: str) -> None:
186
187
  """Set-function placeholder for legacy devices."""
@@ -226,7 +227,7 @@ class SmileLegacyAPI(SmileComm, SmileLegacyData):
226
227
  f' id="{template_id}" /><active>{new_state}</active></rule></rules>'
227
228
  )
228
229
 
229
- await self._request(uri, method="put", data=data)
230
+ await self.call_request(uri, method="put", data=data)
230
231
 
231
232
  async def set_switch_state(
232
233
  self, appl_id: str, members: list[str] | None, model: str, state: str
@@ -254,7 +255,7 @@ class SmileLegacyAPI(SmileComm, SmileLegacyData):
254
255
  if self._appliances.find(locator).text == "true":
255
256
  raise PlugwiseError("Plugwise: the locked Relay was not switched.")
256
257
 
257
- await self._request(uri, method="put", data=data)
258
+ await self.call_request(uri, method="put", data=data)
258
259
 
259
260
  async def _set_groupswitch_member_state(
260
261
  self, members: list[str], state: str, switch: Munch
@@ -267,7 +268,7 @@ class SmileLegacyAPI(SmileComm, SmileLegacyData):
267
268
  uri = f"{APPLIANCES};id={member}/{switch.func_type}"
268
269
  data = f"<{switch.func_type}><{switch.func}>{state}</{switch.func}></{switch.func_type}>"
269
270
 
270
- await self._request(uri, method="put", data=data)
271
+ await self.call_request(uri, method="put", data=data)
271
272
 
272
273
  async def set_temperature(self, _: str, items: dict[str, float]) -> None:
273
274
  """Set the given Temperature on the relevant Thermostat."""
@@ -287,4 +288,13 @@ class SmileLegacyAPI(SmileComm, SmileLegacyData):
287
288
  f"{temperature}</setpoint></thermostat_functionality>"
288
289
  )
289
290
 
290
- await self._request(uri, method="put", data=data)
291
+ await self.call_request(uri, method="put", data=data)
292
+
293
+ async def call_request(self, uri: str, **kwargs: Any) -> None:
294
+ """ConnectionFailedError wrapper for calling _request()."""
295
+ method: str = kwargs["method"]
296
+ data: str | None = kwargs.get("data")
297
+ try:
298
+ await self._request(uri, method=method, data=data)
299
+ except ConnectionFailedError as exc:
300
+ raise ConnectionFailedError from exc
plugwise/smile.py CHANGED
@@ -149,14 +149,6 @@ class SmileAPI(SmileComm, SmileData):
149
149
  ### API Set and HA Service-related Functions ###
150
150
  ########################################################################################################
151
151
 
152
- async def call_request(self, uri: str, **kwargs: Any) -> None:
153
- """ConnectionFailedError wrapper for calling _request()."""
154
- method: str = kwargs["method"]
155
- try:
156
- await self._request(uri, method=method)
157
- except ConnectionFailedError as exc:
158
- raise ConnectionFailedError from exc
159
-
160
152
  async def delete_notification(self) -> None:
161
153
  """Delete the active Plugwise Notification."""
162
154
  await self.call_request(NOTIFICATIONS, method="delete")
@@ -189,7 +181,7 @@ class SmileAPI(SmileComm, SmileData):
189
181
 
190
182
  uri = f"{APPLIANCES};id={self._heater_id}/thermostat;id={thermostat_id}"
191
183
  data = f"<thermostat_functionality><setpoint>{temp}</setpoint></thermostat_functionality>"
192
- await self._request(uri, method="put", data=data)
184
+ await self.call_request(uri, method="put", data=data)
193
185
 
194
186
  async def set_offset(self, dev_id: str, offset: float) -> None:
195
187
  """Set the Temperature offset for thermostats that support this feature."""
@@ -202,7 +194,7 @@ class SmileAPI(SmileComm, SmileData):
202
194
  uri = f"{APPLIANCES};id={dev_id}/offset;type=temperature_offset"
203
195
  data = f"<offset_functionality><offset>{value}</offset></offset_functionality>"
204
196
 
205
- await self._request(uri, method="put", data=data)
197
+ await self.call_request(uri, method="put", data=data)
206
198
 
207
199
  async def set_preset(self, loc_id: str, preset: str) -> None:
208
200
  """Set the given Preset on the relevant Thermostat - from LOCATIONS."""
@@ -222,7 +214,7 @@ class SmileAPI(SmileComm, SmileData):
222
214
  f"</type><preset>{preset}</preset></location></locations>"
223
215
  )
224
216
 
225
- await self._request(uri, method="put", data=data)
217
+ await self.call_request(uri, method="put", data=data)
226
218
 
227
219
  async def set_select(self, key: str, loc_id: str, option: str, state: str | None) -> None:
228
220
  """Set a dhw/gateway/regulation mode or the thermostat schedule option."""
@@ -245,7 +237,7 @@ class SmileAPI(SmileComm, SmileData):
245
237
  uri = f"{APPLIANCES};type=heater_central/domestic_hot_water_mode_control"
246
238
  data = f"<domestic_hot_water_mode_control_functionality><mode>{mode}</mode></domestic_hot_water_mode_control_functionality>"
247
239
 
248
- await self._request(uri, method="put", data=data)
240
+ await self.call_request(uri, method="put", data=data)
249
241
 
250
242
  async def set_gateway_mode(self, mode: str) -> None:
251
243
  """Set the gateway mode."""
@@ -268,7 +260,7 @@ class SmileAPI(SmileComm, SmileData):
268
260
  uri = f"{APPLIANCES};id={self.gateway_id}/gateway_mode_control"
269
261
  data = f"<gateway_mode_control_functionality><mode>{mode}</mode>{valid}</gateway_mode_control_functionality>"
270
262
 
271
- await self._request(uri, method="put", data=data)
263
+ await self.call_request(uri, method="put", data=data)
272
264
 
273
265
  async def set_regulation_mode(self, mode: str) -> None:
274
266
  """Set the heating regulation mode."""
@@ -281,7 +273,7 @@ class SmileAPI(SmileComm, SmileData):
281
273
  duration = "<duration>300</duration>"
282
274
  data = f"<regulation_mode_control_functionality>{duration}<mode>{mode}</mode></regulation_mode_control_functionality>"
283
275
 
284
- await self._request(uri, method="put", data=data)
276
+ await self.call_request(uri, method="put", data=data)
285
277
 
286
278
  async def set_schedule_state(
287
279
  self,
@@ -335,7 +327,7 @@ class SmileAPI(SmileComm, SmileData):
335
327
  f"{template}{contexts}</rule></rules>"
336
328
  )
337
329
 
338
- await self._request(uri, method="put", data=data)
330
+ await self.call_request(uri, method="put", data=data)
339
331
  self._schedule_old_states[loc_id][name] = new_state
340
332
 
341
333
  def determine_contexts(
@@ -404,7 +396,7 @@ class SmileAPI(SmileComm, SmileData):
404
396
  if self._domain_objects.find(locator).text == "true":
405
397
  raise PlugwiseError("Plugwise: the locked Relay was not switched.")
406
398
 
407
- await self._request(uri, method="put", data=data)
399
+ await self.call_request(uri, method="put", data=data)
408
400
 
409
401
  async def _set_groupswitch_member_state(
410
402
  self, members: list[str], state: str, switch: Munch
@@ -419,7 +411,7 @@ class SmileAPI(SmileComm, SmileData):
419
411
  uri = f"{APPLIANCES};id={member}/{switch.device};id={switch_id}"
420
412
  data = f"<{switch.func_type}><{switch.func}>{state}</{switch.func}></{switch.func_type}>"
421
413
 
422
- await self._request(uri, method="put", data=data)
414
+ await self.call_request(uri, method="put", data=data)
423
415
 
424
416
  async def set_temperature(self, loc_id: str, items: dict[str, float]) -> None:
425
417
  """Set the given Temperature on the relevant Thermostat."""
@@ -460,4 +452,13 @@ class SmileAPI(SmileComm, SmileData):
460
452
  f"{temperature}</setpoint></thermostat_functionality>"
461
453
  )
462
454
 
463
- await self._request(uri, method="put", data=data)
455
+ await self.call_request(uri, method="put", data=data)
456
+
457
+ async def call_request(self, uri: str, **kwargs: Any) -> None:
458
+ """ConnectionFailedError wrapper for calling _request()."""
459
+ method: str = kwargs["method"]
460
+ data: str | None = kwargs.get("data")
461
+ try:
462
+ await self._request(uri, method=method, data=data)
463
+ except ConnectionFailedError as exc:
464
+ raise ConnectionFailedError from exc
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: plugwise
3
- Version: 0.38.0
3
+ Version: 0.38.1
4
4
  Summary: Plugwise Smile (Adam/Anna/P1) and Stretch module for Python 3.
5
5
  Home-page: https://github.com/plugwise/python-plugwise
6
6
  Author: Plugwise device owners
@@ -1,17 +1,17 @@
1
- plugwise/__init__.py,sha256=yJu-PvXj2gov6G85fCptfNAbMkAb_tMfiv8Uc9PgnQ8,14936
1
+ plugwise/__init__.py,sha256=zo6whZ4QeZxymEWO_nQ2A4d_XpaXExjKJWZjJzaAxwk,16773
2
2
  plugwise/common.py,sha256=P4sUYzgVcFsIR2DmQxeVeOiZvFZWpZXgwHA3XRc1Sx0,12538
3
3
  plugwise/constants.py,sha256=aP2ifDFIRuzYzuhJk1cOdqN84yR135eqCzAATrhxMo4,16646
4
4
  plugwise/data.py,sha256=HA3OoLrTad4ytns6_rfygwu8eGfopHJBNADGs-hvaQk,9054
5
5
  plugwise/exceptions.py,sha256=Ce-tO9uNsMB-8FP6VAxBvsHNJ-NIM9F0onUZOdZI4Ys,1110
6
- plugwise/helper.py,sha256=ctx5VbM9xQpNzHfL03WDP3H0yhhpC3MPI08LnhVUPxQ,43714
6
+ plugwise/helper.py,sha256=NFcxVtY9qdM2TtBbGs-_eh7xKO6G_M3Q4W9bXUCpH84,43861
7
7
  plugwise/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- plugwise/smile.py,sha256=Dldh70NxbOrOPY6sIV79lb4YADsUOVR1vXr8m98aWd4,18520
8
+ plugwise/smile.py,sha256=mPQsq4qjxZ9cpUmGi_FvYrguj7GGoeqfSQjQNmq5ybU,18617
9
9
  plugwise/util.py,sha256=9ld46KJHWFze2eUrVSgUYn0g3zNerlpboM0iUa0H3ak,7830
10
10
  plugwise/legacy/data.py,sha256=DsHR9xgiFDg_Vh_6ZpOskw8ZhNQ3CmwjstI3yiH6MEk,3048
11
11
  plugwise/legacy/helper.py,sha256=6-tYQMEXepE5rec-hn6lt2EeknADI3J8UFuBSLgu8dk,17878
12
- plugwise/legacy/smile.py,sha256=O8LzM1yCfdu2tiebUcm73bd7f39PIjGbwMxgDeZ_FkE,10864
13
- plugwise-0.38.0.dist-info/LICENSE,sha256=mL22BjmXtg_wnoDnnaqps5_Bg_VGj_yHueX5lsKwbCc,1144
14
- plugwise-0.38.0.dist-info/METADATA,sha256=5VGoiUgUS66yHXqvzJNupesOviaRbtyxS1z3OUMcnCs,9098
15
- plugwise-0.38.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
16
- plugwise-0.38.0.dist-info/top_level.txt,sha256=MYOmktMFf8ZmX6_OE1y9MoCZFfY-L8DA0F2tA2IvE4s,9
17
- plugwise-0.38.0.dist-info/RECORD,,
12
+ plugwise/legacy/smile.py,sha256=E5Ub5TtQcfcbB7AUVf1zwxonpkGuMHELITf5td5HEXw,11321
13
+ plugwise-0.38.1.dist-info/LICENSE,sha256=mL22BjmXtg_wnoDnnaqps5_Bg_VGj_yHueX5lsKwbCc,1144
14
+ plugwise-0.38.1.dist-info/METADATA,sha256=moQq3lGIMmw36rfewCiQB_GCyolvSkUu4WZs-QJUNMs,9098
15
+ plugwise-0.38.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
16
+ plugwise-0.38.1.dist-info/top_level.txt,sha256=MYOmktMFf8ZmX6_OE1y9MoCZFfY-L8DA0F2tA2IvE4s,9
17
+ plugwise-0.38.1.dist-info/RECORD,,