plugwise 0.38.0__tar.gz → 0.38.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 (32) hide show
  1. {plugwise-0.38.0 → plugwise-0.38.2}/PKG-INFO +1 -1
  2. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise/__init__.py +50 -15
  3. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise/constants.py +2 -1
  4. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise/helper.py +41 -41
  5. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise/legacy/smile.py +18 -8
  6. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise/smile.py +21 -21
  7. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise.egg-info/PKG-INFO +1 -1
  8. {plugwise-0.38.0 → plugwise-0.38.2}/pyproject.toml +1 -1
  9. {plugwise-0.38.0 → plugwise-0.38.2}/tests/test_adam.py +32 -7
  10. {plugwise-0.38.0 → plugwise-0.38.2}/tests/test_anna.py +19 -2
  11. {plugwise-0.38.0 → plugwise-0.38.2}/tests/test_init.py +85 -21
  12. {plugwise-0.38.0 → plugwise-0.38.2}/tests/test_legacy_anna.py +1 -1
  13. {plugwise-0.38.0 → plugwise-0.38.2}/LICENSE +0 -0
  14. {plugwise-0.38.0 → plugwise-0.38.2}/README.md +0 -0
  15. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise/common.py +0 -0
  16. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise/data.py +0 -0
  17. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise/exceptions.py +0 -0
  18. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise/legacy/data.py +0 -0
  19. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise/legacy/helper.py +0 -0
  20. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise/py.typed +0 -0
  21. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise/util.py +0 -0
  22. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise.egg-info/SOURCES.txt +0 -0
  23. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise.egg-info/dependency_links.txt +0 -0
  24. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise.egg-info/requires.txt +0 -0
  25. {plugwise-0.38.0 → plugwise-0.38.2}/plugwise.egg-info/top_level.txt +0 -0
  26. {plugwise-0.38.0 → plugwise-0.38.2}/setup.cfg +0 -0
  27. {plugwise-0.38.0 → plugwise-0.38.2}/setup.py +0 -0
  28. {plugwise-0.38.0 → plugwise-0.38.2}/tests/test_generic.py +0 -0
  29. {plugwise-0.38.0 → plugwise-0.38.2}/tests/test_legacy_generic.py +0 -0
  30. {plugwise-0.38.0 → plugwise-0.38.2}/tests/test_legacy_p1.py +0 -0
  31. {plugwise-0.38.0 → plugwise-0.38.2}/tests/test_legacy_stretch.py +0 -0
  32. {plugwise-0.38.0 → plugwise-0.38.2}/tests/test_p1.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: plugwise
3
- Version: 0.38.0
3
+ Version: 0.38.2
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
@@ -5,6 +5,7 @@ Plugwise backend module for Home Assistant Core.
5
5
  from __future__ import annotations
6
6
 
7
7
  from plugwise.constants import (
8
+ DEFAULT_LEGACY_TIMEOUT,
8
9
  DEFAULT_PORT,
9
10
  DEFAULT_TIMEOUT,
10
11
  DEFAULT_USERNAME,
@@ -46,7 +47,7 @@ class Smile(SmileComm):
46
47
  websession: aiohttp.ClientSession,
47
48
  username: str = DEFAULT_USERNAME,
48
49
  port: int = DEFAULT_PORT,
49
- timeout: float = DEFAULT_TIMEOUT,
50
+ timeout: float = DEFAULT_LEGACY_TIMEOUT,
50
51
 
51
52
  ) -> None:
52
53
  """Set the constructor for this class."""
@@ -128,6 +129,7 @@ class Smile(SmileComm):
128
129
  self._smile_api = SmileAPI(
129
130
  self._host,
130
131
  self._passwd,
132
+ self._timeout,
131
133
  self._websession,
132
134
  self._cooling_present,
133
135
  self._elga,
@@ -147,10 +149,10 @@ class Smile(SmileComm):
147
149
  self.smile_type,
148
150
  self._user,
149
151
  self._port,
150
- self._timeout,
151
152
  ) if not self.smile_legacy else SmileLegacyAPI(
152
153
  self._host,
153
154
  self._passwd,
155
+ self._timeout,
154
156
  self._websession,
155
157
  self._is_thermostat,
156
158
  self._on_off_device,
@@ -168,7 +170,6 @@ class Smile(SmileComm):
168
170
  self.smile_zigbee_mac_address,
169
171
  self._user,
170
172
  self._port,
171
- self._timeout,
172
173
  )
173
174
 
174
175
  # Update all endpoints on first connect
@@ -192,6 +193,9 @@ class Smile(SmileComm):
192
193
  else:
193
194
  model = await self._smile_detect_legacy(result, dsmrmain, model)
194
195
 
196
+ if not self.smile_legacy:
197
+ self._timeout = DEFAULT_TIMEOUT
198
+
195
199
  if model == "Unknown" or self.smile_fw_version is None: # pragma: no cover
196
200
  # Corner case check
197
201
  LOGGER.error(
@@ -324,7 +328,10 @@ class Smile(SmileComm):
324
328
  state: str | None = None,
325
329
  ) -> None:
326
330
  """Set the selected option for the applicable Select."""
327
- await self._smile_api.set_select(key, loc_id, option, state)
331
+ try:
332
+ await self._smile_api.set_select(key, loc_id, option, state)
333
+ except ConnectionFailedError as exc:
334
+ raise ConnectionFailedError(f"Failed to set select option '{option}': {str(exc)}") from exc
328
335
 
329
336
  async def set_schedule_state(
330
337
  self,
@@ -333,15 +340,25 @@ class Smile(SmileComm):
333
340
  name: str | None = None,
334
341
  ) -> None:
335
342
  """Activate/deactivate the Schedule, with the given name, on the relevant Thermostat."""
336
- await self._smile_api.set_schedule_state(loc_id, state, name)
343
+ try:
344
+ await self._smile_api.set_schedule_state(loc_id, state, name)
345
+ except ConnectionFailedError as exc: # pragma no cover
346
+ raise ConnectionFailedError(f"Failed to set schedule state: {str(exc)}") from exc # pragma no cover
347
+
337
348
 
338
349
  async def set_preset(self, loc_id: str, preset: str) -> None:
339
350
  """Set the given Preset on the relevant Thermostat."""
340
- await self._smile_api.set_preset(loc_id, preset)
351
+ try:
352
+ await self._smile_api.set_preset(loc_id, preset)
353
+ except ConnectionFailedError as exc:
354
+ raise ConnectionFailedError(f"Failed to set preset: {str(exc)}") from exc
341
355
 
342
356
  async def set_temperature(self, loc_id: str, items: dict[str, float]) -> None:
343
357
  """Set the given Temperature on the relevant Thermostat."""
344
- await self._smile_api.set_temperature(loc_id, items)
358
+ try:
359
+ await self._smile_api.set_temperature(loc_id, items)
360
+ except ConnectionFailedError as exc:
361
+ raise ConnectionFailedError(f"Failed to set temperature: {str(exc)}") from exc
345
362
 
346
363
  async def set_number(
347
364
  self,
@@ -350,40 +367,58 @@ class Smile(SmileComm):
350
367
  temperature: float,
351
368
  ) -> None:
352
369
  """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)
370
+ try:
371
+ await self._smile_api.set_number(dev_id, key, temperature)
372
+ except ConnectionFailedError as exc:
373
+ raise ConnectionFailedError(f"Failed to set number '{key}': {str(exc)}") from exc
354
374
 
355
375
  async def set_temperature_offset(self, dev_id: str, offset: float) -> None:
356
376
  """Set the Temperature offset for thermostats that support this feature."""
357
- await self._smile_api.set_offset(dev_id, offset) # pragma: no cover
377
+ try: # pragma no cover
378
+ await self._smile_api.set_offset(dev_id, offset) # pragma: no cover
379
+ except ConnectionFailedError as exc: # pragma no cover
380
+ raise ConnectionFailedError(f"Failed to set temperature offset: {str(exc)}") from exc # pragma no cover
358
381
 
359
382
  async def set_switch_state(
360
383
  self, appl_id: str, members: list[str] | None, model: str, state: str
361
384
  ) -> None:
362
385
  """Set the given State of the relevant Switch."""
363
- await self._smile_api.set_switch_state(appl_id, members, model, state)
386
+ try:
387
+ await self._smile_api.set_switch_state(appl_id, members, model, state)
388
+ except ConnectionFailedError as exc:
389
+ raise ConnectionFailedError(f"Failed to set switch state: {str(exc)}") from exc
364
390
 
365
391
  async def set_gateway_mode(self, mode: str) -> None:
366
392
  """Set the gateway mode."""
367
- await self._smile_api.set_gateway_mode(mode) # pragma: no cover
393
+ try: # pragma no cover
394
+ await self._smile_api.set_gateway_mode(mode) # pragma: no cover
395
+ except ConnectionFailedError as exc: # pragma no cover
396
+ raise ConnectionFailedError(f"Failed to set gateway mode: {str(exc)}") from exc # pragma no cover
368
397
 
369
398
  async def set_regulation_mode(self, mode: str) -> None:
370
399
  """Set the heating regulation mode."""
371
- await self._smile_api.set_regulation_mode(mode) # pragma: no cover
400
+ try: # pragma no cover
401
+ await self._smile_api.set_regulation_mode(mode) # pragma: no cover
402
+ except ConnectionFailedError as exc: # pragma no cover
403
+ raise ConnectionFailedError(f"Failed to set regulation mode: {str(exc)}") from exc # pragma no cover
372
404
 
373
405
  async def set_dhw_mode(self, mode: str) -> None:
374
406
  """Set the domestic hot water heating regulation mode."""
375
- await self._smile_api.set_dhw_mode(mode) # pragma: no cover
407
+ try: # pragma no cover
408
+ await self._smile_api.set_dhw_mode(mode) # pragma: no cover
409
+ except ConnectionFailedError as exc: # pragma no cover
410
+ raise ConnectionFailedError(f"Failed to set dhw mode: {str(exc)}") from exc # pragma no cover
376
411
 
377
412
  async def delete_notification(self) -> None:
378
413
  """Delete the active Plugwise Notification."""
379
414
  try:
380
415
  await self._smile_api.delete_notification()
381
416
  except ConnectionFailedError as exc:
382
- raise PlugwiseError(f"Failed to delete notification: {str(exc)}") from exc
417
+ raise ConnectionFailedError(f"Failed to delete notification: {str(exc)}") from exc
383
418
 
384
419
  async def reboot_gateway(self) -> None:
385
420
  """Reboot the Plugwise Gateway."""
386
421
  try:
387
422
  await self._smile_api.reboot_gateway()
388
423
  except ConnectionFailedError as exc:
389
- raise PlugwiseError(f"Failed to reboot gateway: {str(exc)}") from exc
424
+ raise ConnectionFailedError(f"Failed to reboot gateway: {str(exc)}") from exc
@@ -32,7 +32,8 @@ VOLUME_CUBIC_METERS_PER_HOUR: Final = "m³/h"
32
32
 
33
33
  ADAM: Final = "Adam"
34
34
  ANNA: Final = "Smile Anna"
35
- DEFAULT_TIMEOUT: Final = 30
35
+ DEFAULT_TIMEOUT: Final = 10
36
+ DEFAULT_LEGACY_TIMEOUT: Final = 30
36
37
  DEFAULT_USERNAME: Final = "smile"
37
38
  DEFAULT_PORT: Final = 80
38
39
  DEFAULT_PW_MAX: Final = 30.0
@@ -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
@@ -5,11 +5,11 @@ 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,
11
12
  DEFAULT_PORT,
12
- DEFAULT_TIMEOUT,
13
13
  DEFAULT_USERNAME,
14
14
  DOMAIN_OBJECTS,
15
15
  LOCATIONS,
@@ -23,7 +23,7 @@ from plugwise.constants import (
23
23
  PlugwiseData,
24
24
  ThermoLoc,
25
25
  )
26
- from plugwise.exceptions import PlugwiseError
26
+ from plugwise.exceptions import ConnectionFailedError, PlugwiseError
27
27
  from plugwise.helper import SmileComm
28
28
  from plugwise.legacy.data import SmileLegacyData
29
29
 
@@ -40,6 +40,7 @@ class SmileLegacyAPI(SmileComm, SmileLegacyData):
40
40
  self,
41
41
  host: str,
42
42
  password: str,
43
+ timeout: float,
43
44
  websession: aiohttp.ClientSession,
44
45
  _is_thermostat: bool,
45
46
  _on_off_device: bool,
@@ -57,7 +58,6 @@ class SmileLegacyAPI(SmileComm, SmileLegacyData):
57
58
  smile_zigbee_mac_address: str | None,
58
59
  username: str = DEFAULT_USERNAME,
59
60
  port: int = DEFAULT_PORT,
60
- timeout: float = DEFAULT_TIMEOUT,
61
61
  ) -> None:
62
62
  """Set the constructor for this class."""
63
63
  super().__init__(
@@ -76,6 +76,7 @@ class SmileLegacyAPI(SmileComm, SmileLegacyData):
76
76
  self._opentherm_device = _opentherm_device
77
77
  self._stretch_v2 = _stretch_v2
78
78
  self._target_smile = _target_smile
79
+ self._timeout = timeout
79
80
  self.loc_data = loc_data
80
81
  self.smile_fw_version = smile_fw_version
81
82
  self.smile_hostname = smile_hostname
@@ -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
@@ -12,7 +12,6 @@ from plugwise.constants import (
12
12
  ANNA,
13
13
  APPLIANCES,
14
14
  DEFAULT_PORT,
15
- DEFAULT_TIMEOUT,
16
15
  DEFAULT_USERNAME,
17
16
  DOMAIN_OBJECTS,
18
17
  GATEWAY_REBOOT,
@@ -47,6 +46,7 @@ class SmileAPI(SmileComm, SmileData):
47
46
  self,
48
47
  host: str,
49
48
  password: str,
49
+ timeout: float,
50
50
  websession: aiohttp.ClientSession,
51
51
  _cooling_present: bool,
52
52
  _elga: bool,
@@ -66,8 +66,6 @@ class SmileAPI(SmileComm, SmileData):
66
66
  smile_type: str,
67
67
  username: str = DEFAULT_USERNAME,
68
68
  port: int = DEFAULT_PORT,
69
- timeout: float = DEFAULT_TIMEOUT,
70
-
71
69
  ) -> None:
72
70
  """Set the constructor for this class."""
73
71
  super().__init__(
@@ -87,6 +85,7 @@ class SmileAPI(SmileComm, SmileData):
87
85
  self._on_off_device = _on_off_device
88
86
  self._opentherm_device = _opentherm_device
89
87
  self._schedule_old_states = _schedule_old_states
88
+ self._timeout = timeout
90
89
  self.gateway_id = gateway_id
91
90
  self.loc_data = loc_data
92
91
  self.smile_fw_version = smile_fw_version
@@ -149,14 +148,6 @@ class SmileAPI(SmileComm, SmileData):
149
148
  ### API Set and HA Service-related Functions ###
150
149
  ########################################################################################################
151
150
 
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
151
  async def delete_notification(self) -> None:
161
152
  """Delete the active Plugwise Notification."""
162
153
  await self.call_request(NOTIFICATIONS, method="delete")
@@ -189,7 +180,7 @@ class SmileAPI(SmileComm, SmileData):
189
180
 
190
181
  uri = f"{APPLIANCES};id={self._heater_id}/thermostat;id={thermostat_id}"
191
182
  data = f"<thermostat_functionality><setpoint>{temp}</setpoint></thermostat_functionality>"
192
- await self._request(uri, method="put", data=data)
183
+ await self.call_request(uri, method="put", data=data)
193
184
 
194
185
  async def set_offset(self, dev_id: str, offset: float) -> None:
195
186
  """Set the Temperature offset for thermostats that support this feature."""
@@ -202,7 +193,7 @@ class SmileAPI(SmileComm, SmileData):
202
193
  uri = f"{APPLIANCES};id={dev_id}/offset;type=temperature_offset"
203
194
  data = f"<offset_functionality><offset>{value}</offset></offset_functionality>"
204
195
 
205
- await self._request(uri, method="put", data=data)
196
+ await self.call_request(uri, method="put", data=data)
206
197
 
207
198
  async def set_preset(self, loc_id: str, preset: str) -> None:
208
199
  """Set the given Preset on the relevant Thermostat - from LOCATIONS."""
@@ -222,7 +213,7 @@ class SmileAPI(SmileComm, SmileData):
222
213
  f"</type><preset>{preset}</preset></location></locations>"
223
214
  )
224
215
 
225
- await self._request(uri, method="put", data=data)
216
+ await self.call_request(uri, method="put", data=data)
226
217
 
227
218
  async def set_select(self, key: str, loc_id: str, option: str, state: str | None) -> None:
228
219
  """Set a dhw/gateway/regulation mode or the thermostat schedule option."""
@@ -245,7 +236,7 @@ class SmileAPI(SmileComm, SmileData):
245
236
  uri = f"{APPLIANCES};type=heater_central/domestic_hot_water_mode_control"
246
237
  data = f"<domestic_hot_water_mode_control_functionality><mode>{mode}</mode></domestic_hot_water_mode_control_functionality>"
247
238
 
248
- await self._request(uri, method="put", data=data)
239
+ await self.call_request(uri, method="put", data=data)
249
240
 
250
241
  async def set_gateway_mode(self, mode: str) -> None:
251
242
  """Set the gateway mode."""
@@ -268,7 +259,7 @@ class SmileAPI(SmileComm, SmileData):
268
259
  uri = f"{APPLIANCES};id={self.gateway_id}/gateway_mode_control"
269
260
  data = f"<gateway_mode_control_functionality><mode>{mode}</mode>{valid}</gateway_mode_control_functionality>"
270
261
 
271
- await self._request(uri, method="put", data=data)
262
+ await self.call_request(uri, method="put", data=data)
272
263
 
273
264
  async def set_regulation_mode(self, mode: str) -> None:
274
265
  """Set the heating regulation mode."""
@@ -281,7 +272,7 @@ class SmileAPI(SmileComm, SmileData):
281
272
  duration = "<duration>300</duration>"
282
273
  data = f"<regulation_mode_control_functionality>{duration}<mode>{mode}</mode></regulation_mode_control_functionality>"
283
274
 
284
- await self._request(uri, method="put", data=data)
275
+ await self.call_request(uri, method="put", data=data)
285
276
 
286
277
  async def set_schedule_state(
287
278
  self,
@@ -335,7 +326,7 @@ class SmileAPI(SmileComm, SmileData):
335
326
  f"{template}{contexts}</rule></rules>"
336
327
  )
337
328
 
338
- await self._request(uri, method="put", data=data)
329
+ await self.call_request(uri, method="put", data=data)
339
330
  self._schedule_old_states[loc_id][name] = new_state
340
331
 
341
332
  def determine_contexts(
@@ -404,7 +395,7 @@ class SmileAPI(SmileComm, SmileData):
404
395
  if self._domain_objects.find(locator).text == "true":
405
396
  raise PlugwiseError("Plugwise: the locked Relay was not switched.")
406
397
 
407
- await self._request(uri, method="put", data=data)
398
+ await self.call_request(uri, method="put", data=data)
408
399
 
409
400
  async def _set_groupswitch_member_state(
410
401
  self, members: list[str], state: str, switch: Munch
@@ -419,7 +410,7 @@ class SmileAPI(SmileComm, SmileData):
419
410
  uri = f"{APPLIANCES};id={member}/{switch.device};id={switch_id}"
420
411
  data = f"<{switch.func_type}><{switch.func}>{state}</{switch.func}></{switch.func_type}>"
421
412
 
422
- await self._request(uri, method="put", data=data)
413
+ await self.call_request(uri, method="put", data=data)
423
414
 
424
415
  async def set_temperature(self, loc_id: str, items: dict[str, float]) -> None:
425
416
  """Set the given Temperature on the relevant Thermostat."""
@@ -460,4 +451,13 @@ class SmileAPI(SmileComm, SmileData):
460
451
  f"{temperature}</setpoint></thermostat_functionality>"
461
452
  )
462
453
 
463
- await self._request(uri, method="put", data=data)
454
+ await self.call_request(uri, method="put", data=data)
455
+
456
+ async def call_request(self, uri: str, **kwargs: Any) -> None:
457
+ """ConnectionFailedError wrapper for calling _request()."""
458
+ method: str = kwargs["method"]
459
+ data: str | None = kwargs.get("data")
460
+ try:
461
+ await self._request(uri, method=method, data=data)
462
+ except ConnectionFailedError as exc:
463
+ 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.2
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "plugwise"
7
- version = "0.38.0"
7
+ version = "0.38.2"
8
8
  license = {file = "LICENSE"}
9
9
  description = "Plugwise Smile (Adam/Anna/P1) and Stretch module for Python 3."
10
10
  readme = "README.md"
@@ -63,7 +63,7 @@ class TestPlugwiseAdam(TestPlugwise): # pylint: disable=attribute-defined-outsi
63
63
  await self.disconnect(server, client)
64
64
 
65
65
  server, smile, client = await self.connect_wrapper(raise_timeout=True)
66
- await self.device_test(smile, "2022-05-16 00:00:01", testdata)
66
+ await self.device_test(smile, "2022-05-16 00:00:01", testdata, skip_testing=True)
67
67
  result = await self.tinker_thermostat(
68
68
  smile,
69
69
  "c50f167537524366a5af7aa3942feb1e",
@@ -79,15 +79,18 @@ class TestPlugwiseAdam(TestPlugwise): # pylint: disable=attribute-defined-outsi
79
79
  )
80
80
  assert result
81
81
 
82
+ tinkered = await self.tinker_max_boiler_temp(smile, unhappy=True)
83
+ assert not tinkered
84
+
82
85
  try:
83
86
  await smile.delete_notification()
84
87
  notification_deletion = False # pragma: no cover
85
- except pw_exceptions.PlugwiseError:
88
+ except pw_exceptions.ConnectionFailedError:
86
89
  notification_deletion = True
87
90
  assert notification_deletion
88
91
 
89
92
  reboot = await self.tinker_reboot(smile, unhappy=True)
90
- assert not reboot
93
+ assert reboot
91
94
 
92
95
  await smile.close_connection()
93
96
  await self.disconnect(server, client)
@@ -212,7 +215,7 @@ class TestPlugwiseAdam(TestPlugwise): # pylint: disable=attribute-defined-outsi
212
215
  await self.disconnect(server, client)
213
216
 
214
217
  server, smile, client = await self.connect_wrapper(raise_timeout=True)
215
- await self.device_test(smile, "2020-03-22 00:00:01", testdata)
218
+ await self.device_test(smile, "2020-03-22 00:00:01", testdata, skip_testing=True)
216
219
  result = await self.tinker_thermostat(
217
220
  smile,
218
221
  "009490cc2f674ce6b576863fbb64f867",
@@ -322,9 +325,14 @@ class TestPlugwiseAdam(TestPlugwise): # pylint: disable=attribute-defined-outsi
322
325
  )
323
326
  assert not switch_change
324
327
 
325
- await self.tinker_gateway_mode(smile)
326
- await self.tinker_regulation_mode(smile)
327
- await self.tinker_max_boiler_temp(smile)
328
+ tinkered = await self.tinker_gateway_mode(smile)
329
+ assert not tinkered
330
+
331
+ tinkered = await self.tinker_regulation_mode(smile)
332
+ assert not tinkered
333
+
334
+ tinkered = await self.tinker_max_boiler_temp(smile)
335
+ assert not tinkered
328
336
 
329
337
  # Now change some data and change directory reading xml from
330
338
  # emulating reading newer dataset after an update_interval
@@ -353,6 +361,23 @@ class TestPlugwiseAdam(TestPlugwise): # pylint: disable=attribute-defined-outsi
353
361
  await smile.close_connection()
354
362
  await self.disconnect(server, client)
355
363
 
364
+ self.smile_setup = "adam_plus_anna_new"
365
+ testdata = self.load_testdata(SMILE_TYPE, self.smile_setup)
366
+ server, smile, client = await self.connect_wrapper(raise_timeout=True)
367
+ await self.device_test(smile, "2023-12-17 00:00:01", testdata, skip_testing=True)
368
+
369
+ tinkered = await self.tinker_max_boiler_temp(smile, unhappy=True)
370
+ assert tinkered
371
+
372
+ tinkered = await self.tinker_gateway_mode(smile, unhappy=True)
373
+ assert tinkered
374
+
375
+ tinkered = await self.tinker_regulation_mode(smile, unhappy=True)
376
+ assert tinkered
377
+
378
+ await smile.close_connection()
379
+ await self.disconnect(server, client)
380
+
356
381
  @pytest.mark.asyncio
357
382
  async def test_adam_plus_jip(self):
358
383
  """Test Adam with Jip setup."""
@@ -70,7 +70,7 @@ class TestPlugwiseAnna(TestPlugwise): # pylint: disable=attribute-defined-outsi
70
70
  server, smile, client = await self.connect_wrapper(raise_timeout=True)
71
71
  # Reset self.smile_setup
72
72
  self.smile_setup = "anna_v4"
73
- await self.device_test(smile, "2020-04-05 00:00:01", testdata)
73
+ await self.device_test(smile, "2020-04-05 00:00:01", testdata, skip_testing=True)
74
74
  result = await self.tinker_thermostat(
75
75
  smile,
76
76
  "eb5309212bf5407bb143e5bfa3b18aee",
@@ -79,6 +79,12 @@ class TestPlugwiseAnna(TestPlugwise): # pylint: disable=attribute-defined-outsi
79
79
  unhappy=True,
80
80
  )
81
81
  assert result
82
+
83
+ result = await self.tinker_temp_offset(
84
+ smile, "01b85360fdd243d0aaad4d6ac2a5ba7e", unhappy=True,
85
+ )
86
+ assert result
87
+
82
88
  await smile.close_connection()
83
89
  await self.disconnect(server, client)
84
90
 
@@ -458,11 +464,22 @@ class TestPlugwiseAnna(TestPlugwise): # pylint: disable=attribute-defined-outsi
458
464
  "ERROR raised setting block cooling: %s", exc.value
459
465
  ) # pragma: no cover
460
466
 
461
- await self.tinker_dhw_mode(smile)
467
+ tinkered = await self.tinker_dhw_mode(smile)
468
+ assert not tinkered
462
469
 
463
470
  await smile.close_connection()
464
471
  await self.disconnect(server, client)
465
472
 
473
+ server, smile, client = await self.connect_wrapper(raise_timeout=True)
474
+ await self.device_test(smile, "2022-05-16 00:00:01", testdata, skip_testing=True)
475
+
476
+ tinkered = await self.tinker_dhw_mode(smile, unhappy=True)
477
+ assert tinkered
478
+
479
+ await smile.close_connection()
480
+ await self.disconnect(server, client)
481
+
482
+
466
483
  @pytest.mark.asyncio
467
484
  async def test_connect_anna_loria_cooling_active(self):
468
485
  """Test an Anna with a Loria in heating mode - state idle."""
@@ -536,6 +536,7 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
536
536
  test_time=None,
537
537
  testdata=None,
538
538
  initialize=True,
539
+ skip_testing=False,
539
540
  ):
540
541
  """Perform basic device tests."""
541
542
  bsw_list = ["binary_sensors", "central", "climate", "sensors", "switches"]
@@ -551,8 +552,10 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
551
552
  await smile.full_update_device()
552
553
  smile.get_all_devices()
553
554
  data = await smile.async_update()
555
+ assert smile._timeout == 30
554
556
  else:
555
557
  data = await smile.async_update()
558
+ assert smile._timeout == 10
556
559
  else:
557
560
  _LOGGER.info("Asserting updated testdata:")
558
561
  data = await smile.async_update()
@@ -588,6 +591,9 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
588
591
  _LOGGER.info("Device list = %s", data.devices)
589
592
  self.show_setup(location_list, data.devices)
590
593
 
594
+ if skip_testing:
595
+ return
596
+
591
597
  # Perform tests and asserts
592
598
  tests = 0
593
599
  asserts = 0
@@ -644,10 +650,10 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
644
650
  await smile.reboot_gateway()
645
651
  _LOGGER.info(" + worked as intended")
646
652
  return True
647
- except pw_exceptions.PlugwiseError:
653
+ except pw_exceptions.ConnectionFailedError:
648
654
  if unhappy:
649
655
  _LOGGER.info(" + failed as expected")
650
- return False
656
+ return True
651
657
  else: # pragma: no cover
652
658
  _LOGGER.info(" - failed unexpectedly")
653
659
  return False
@@ -659,8 +665,8 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
659
665
  """Turn a Switch on and off to test functionality."""
660
666
  _LOGGER.info("Asserting modifying settings for switch devices:")
661
667
  _LOGGER.info("- Devices (%s):", dev_id)
668
+ tinker_switch_passed = False
662
669
  for new_state in ["false", "true", "false"]:
663
- tinker_switch_passed = False
664
670
  _LOGGER.info("- Switching %s", new_state)
665
671
  try:
666
672
  await smile.set_switch_state(dev_id, members, model, new_state)
@@ -669,9 +675,9 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
669
675
  except pw_exceptions.PlugwiseError:
670
676
  _LOGGER.info(" + locked, not switched as expected")
671
677
  return False
672
- except pw_exceptions.ConnectionFailedError:
678
+ except pw_exceptions.ConnectionFailedError: # leave for-loop at connect-error
673
679
  if unhappy:
674
- tinker_switch_passed = True # test is pass!
680
+ return True # test is pass!
675
681
  _LOGGER.info(" + failed as expected")
676
682
  else: # pragma: no cover
677
683
  _LOGGER.info(" - failed unexpectedly")
@@ -697,18 +703,18 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
697
703
  except pw_exceptions.ConnectionFailedError:
698
704
  if unhappy:
699
705
  _LOGGER.info(" + tinker_thermostat_temp failed as expected")
700
- tinker_temp_passed = True
706
+ return True
701
707
  else: # pragma: no cover
702
708
  _LOGGER.info(" - tinker_thermostat_temp failed unexpectedly")
703
- tinker_temp_passed = False
709
+ return False
704
710
 
705
711
  return tinker_temp_passed
706
712
 
707
713
  @pytest.mark.asyncio
708
714
  async def tinker_thermostat_preset(self, smile, loc_id, unhappy=False):
709
715
  """Toggle preset to test functionality."""
716
+ tinker_preset_passed = False
710
717
  for new_preset in ["asleep", "home", BOGUS]:
711
- tinker_preset_passed = False
712
718
  warning = ""
713
719
  if new_preset[0] == "!":
714
720
  warning = " TTP Negative test"
@@ -721,10 +727,10 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
721
727
  except pw_exceptions.PlugwiseError:
722
728
  _LOGGER.info(" + found invalid preset, as expected")
723
729
  tinker_preset_passed = True
724
- except pw_exceptions.ConnectionFailedError:
730
+ except pw_exceptions.ConnectionFailedError: # leave for-loop at connect-error
725
731
  if unhappy:
726
- tinker_preset_passed = True
727
732
  _LOGGER.info(" + tinker_thermostat_preset failed as expected")
733
+ return True
728
734
  else: # pragma: no cover
729
735
  _LOGGER.info(" - tinker_thermostat_preset failed unexpectedly")
730
736
  return False
@@ -740,8 +746,9 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
740
746
  if good_schedules != []:
741
747
  if not single and ("!VeryBogusSchedule" not in good_schedules):
742
748
  good_schedules.append("!VeryBogusSchedule")
749
+
750
+ tinker_schedule_passed = False
743
751
  for new_schedule in good_schedules:
744
- tinker_schedule_passed = False
745
752
  warning = ""
746
753
  if new_schedule is not None and new_schedule[0] == "!":
747
754
  warning = " TTS Negative test"
@@ -754,11 +761,11 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
754
761
  except pw_exceptions.PlugwiseError:
755
762
  _LOGGER.info(" + failed as expected")
756
763
  tinker_schedule_passed = True
757
- except pw_exceptions.ConnectionFailedError:
764
+ except pw_exceptions.ConnectionFailedError: # leave for-loop at connect-error
758
765
  tinker_schedule_passed = False
759
766
  if unhappy:
760
767
  _LOGGER.info(" + failed as expected before intended failure")
761
- tinker_schedule_passed = True
768
+ return True
762
769
  else: # pragma: no cover
763
770
  _LOGGER.info(" - succeeded unexpectedly for some reason")
764
771
  return False
@@ -772,6 +779,7 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
772
779
  async def tinker_legacy_thermostat_schedule(self, smile, unhappy=False):
773
780
  """Toggle schedules to test functionality."""
774
781
  states = ["on", "off", "!Bogus"]
782
+ tinker_schedule_passed = False
775
783
  for state in states:
776
784
  _LOGGER.info("- Adjusting schedule to state %s", state)
777
785
  try:
@@ -781,11 +789,11 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
781
789
  except pw_exceptions.PlugwiseError:
782
790
  _LOGGER.info(" + failed as expected")
783
791
  tinker_schedule_passed = True
784
- except pw_exceptions.ConnectionFailedError:
792
+ except pw_exceptions.ConnectionFailedError: # leave for-loop at connect-error
785
793
  tinker_schedule_passed = False
786
794
  if unhappy:
787
795
  _LOGGER.info(" + failed as expected before intended failure")
788
- tinker_schedule_passed = True
796
+ return True
789
797
  else: # pragma: no cover
790
798
  _LOGGER.info(" - succeeded unexpectedly for some reason")
791
799
  return False
@@ -833,7 +841,7 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
833
841
  smile,
834
842
  schedule_on=True,
835
843
  block_cooling=False,
836
- unhappy=False
844
+ unhappy=False,
837
845
  ):
838
846
  """Toggle various climate settings to test functionality."""
839
847
  result_1 = await self.tinker_thermostat_temp(
@@ -847,8 +855,9 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
847
855
  return result_1 and result_2 and result_3
848
856
 
849
857
  @staticmethod
850
- async def tinker_dhw_mode(smile):
858
+ async def tinker_dhw_mode(smile, unhappy=False):
851
859
  """Toggle dhw to test functionality."""
860
+ tinker_dhw_mode_passed = False
852
861
  for mode in ["auto", "boost", BOGUS]:
853
862
  warning = ""
854
863
  if mode[0] == "!":
@@ -858,12 +867,24 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
858
867
  try:
859
868
  await smile.set_select("select_dhw_mode", "dummy", mode)
860
869
  _LOGGER.info(" + tinker_dhw_mode worked as intended")
870
+ tinker_dhw_mode_passed = True
861
871
  except pw_exceptions.PlugwiseError:
862
872
  _LOGGER.info(" + tinker_dhw_mode found invalid mode, as expected")
873
+ tinker_dhw_mode_passed = False
874
+ except pw_exceptions.ConnectionFailedError: # leave for-loop at connect-error
875
+ if unhappy:
876
+ _LOGGER.info(" + failed as expected before intended failure")
877
+ return True
878
+ else: # pragma: no cover
879
+ _LOGGER.info(" - succeeded unexpectedly for some reason")
880
+ return False
881
+
882
+ return tinker_dhw_mode_passed
863
883
 
864
884
  @staticmethod
865
- async def tinker_regulation_mode(smile):
885
+ async def tinker_regulation_mode(smile, unhappy=False):
866
886
  """Toggle regulation_mode to test functionality."""
887
+ tinker_reg_mode_passed = False
867
888
  for mode in ["off", "heating", "bleeding_cold", BOGUS]:
868
889
  warning = ""
869
890
  if mode[0] == "!":
@@ -873,25 +894,49 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
873
894
  try:
874
895
  await smile.set_select("select_regulation_mode", "dummy", mode)
875
896
  _LOGGER.info(" + tinker_regulation_mode worked as intended")
897
+ tinker_reg_mode_passed = True
876
898
  except pw_exceptions.PlugwiseError:
877
899
  _LOGGER.info(
878
900
  " + tinker_regulation_mode found invalid mode, as expected"
879
901
  )
902
+ tinker_reg_mode_passed = False
903
+ except pw_exceptions.ConnectionFailedError: # leave for-loop at connect-error
904
+ if unhappy:
905
+ _LOGGER.info(" + failed as expected before intended failure")
906
+ return True
907
+ else: # pragma: no cover
908
+ _LOGGER.info(" - succeeded unexpectedly for some reason")
909
+ return False
910
+
911
+ return tinker_reg_mode_passed
880
912
 
881
913
  @staticmethod
882
- async def tinker_max_boiler_temp(smile):
914
+ async def tinker_max_boiler_temp(smile, unhappy=False):
883
915
  """Change max boiler temp setpoint to test functionality."""
916
+ tinker_max_boiler_temp_passed = False
884
917
  new_temp = 60.0
885
918
  _LOGGER.info("- Adjusting temperature to %s", new_temp)
886
919
  for test in ["maximum_boiler_temperature", "bogus_temperature"]:
920
+ _LOGGER.info(" + for %s", test)
887
921
  try:
888
922
  await smile.set_number("dummy", test, new_temp)
889
923
  _LOGGER.info(" + tinker_max_boiler_temp worked as intended")
924
+ tinker_max_boiler_temp_passed = True
890
925
  except pw_exceptions.PlugwiseError:
891
926
  _LOGGER.info(" + tinker_max_boiler_temp failed as intended")
927
+ tinker_max_boiler_temp_passed = False
928
+ except pw_exceptions.ConnectionFailedError: # leave for-loop at connect-error
929
+ if unhappy:
930
+ _LOGGER.info(" + failed as expected before intended failure")
931
+ return True
932
+ else: # pragma: no cover
933
+ _LOGGER.info(" - succeeded unexpectedly for some reason")
934
+ return False
935
+
936
+ return tinker_max_boiler_temp_passed
892
937
 
893
938
  @staticmethod
894
- async def tinker_temp_offset(smile, dev_id):
939
+ async def tinker_temp_offset(smile, dev_id, unhappy=False):
895
940
  """Change temperature_offset to test functionality."""
896
941
  new_offset = 1.0
897
942
  _LOGGER.info("- Adjusting temperature offset to %s", new_offset)
@@ -902,10 +947,18 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
902
947
  except pw_exceptions.PlugwiseError:
903
948
  _LOGGER.info(" + tinker_temp_offset failed as intended")
904
949
  return False
950
+ except pw_exceptions.ConnectionFailedError:
951
+ if unhappy:
952
+ _LOGGER.info(" + failed as expected before intended failure")
953
+ return True
954
+ else: # pragma: no cover
955
+ _LOGGER.info(" - succeeded unexpectedly for some reason")
956
+ return False
905
957
 
906
958
  @staticmethod
907
- async def tinker_gateway_mode(smile):
959
+ async def tinker_gateway_mode(smile, unhappy=False):
908
960
  """Toggle gateway_mode to test functionality."""
961
+ tinker_gateway_mode_passed = False
909
962
  for mode in ["away", "full", "vacation", "!bogus"]:
910
963
  warning = ""
911
964
  if mode[0] == "!":
@@ -915,8 +968,19 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
915
968
  try:
916
969
  await smile.set_select("select_gateway_mode", "dummy", mode)
917
970
  _LOGGER.info(" + worked as intended")
971
+ tinker_gateway_mode_passed = True
918
972
  except pw_exceptions.PlugwiseError:
919
973
  _LOGGER.info(" + found invalid mode, as expected")
974
+ tinker_gateway_mode_passed = False
975
+ except pw_exceptions.ConnectionFailedError: # leave for-loop at connect-error
976
+ if unhappy:
977
+ _LOGGER.info(" + failed as expected before intended failure")
978
+ return True
979
+ else: # pragma: no cover
980
+ _LOGGER.info(" - succeeded unexpectedly for some reason")
981
+ return False
982
+
983
+ return tinker_gateway_mode_passed
920
984
 
921
985
  @staticmethod
922
986
  def validate_test_basics(
@@ -39,7 +39,7 @@ class TestPlugwiseAnna(TestPlugwise): # pylint: disable=attribute-defined-outsi
39
39
  await self.disconnect(server, client)
40
40
 
41
41
  server, smile, client = await self.connect_legacy_wrapper(raise_timeout=True)
42
- await self.device_test(smile, "2020-03-22 00:00:01", testdata)
42
+ await self.device_test(smile, "2020-03-22 00:00:01", testdata, skip_testing=True)
43
43
  result = await self.tinker_legacy_thermostat(smile, unhappy=True)
44
44
  assert result
45
45
  await smile.close_connection()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes