python-tado 0.18.12__tar.gz → 0.18.14__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. {python_tado-0.18.12/python_tado.egg-info → python_tado-0.18.14}/PKG-INFO +1 -1
  2. {python_tado-0.18.12 → python_tado-0.18.14}/PyTado/http.py +42 -38
  3. {python_tado-0.18.12 → python_tado-0.18.14}/PyTado/interface/api/hops_tado.py +59 -9
  4. {python_tado-0.18.12 → python_tado-0.18.14}/pyproject.toml +1 -1
  5. {python_tado-0.18.12 → python_tado-0.18.14/python_tado.egg-info}/PKG-INFO +1 -1
  6. {python_tado-0.18.12 → python_tado-0.18.14}/AUTHORS +0 -0
  7. {python_tado-0.18.12 → python_tado-0.18.14}/LICENSE +0 -0
  8. {python_tado-0.18.12 → python_tado-0.18.14}/PyTado/__init__.py +0 -0
  9. {python_tado-0.18.12 → python_tado-0.18.14}/PyTado/__main__.py +0 -0
  10. {python_tado-0.18.12 → python_tado-0.18.14}/PyTado/const.py +0 -0
  11. {python_tado-0.18.12 → python_tado-0.18.14}/PyTado/exceptions.py +0 -0
  12. {python_tado-0.18.12 → python_tado-0.18.14}/PyTado/interface/__init__.py +0 -0
  13. {python_tado-0.18.12 → python_tado-0.18.14}/PyTado/interface/api/__init__.py +0 -0
  14. {python_tado-0.18.12 → python_tado-0.18.14}/PyTado/interface/api/my_tado.py +0 -0
  15. {python_tado-0.18.12 → python_tado-0.18.14}/PyTado/interface/interface.py +0 -0
  16. {python_tado-0.18.12 → python_tado-0.18.14}/PyTado/logger.py +0 -0
  17. {python_tado-0.18.12 → python_tado-0.18.14}/PyTado/zone/__init__.py +0 -0
  18. {python_tado-0.18.12 → python_tado-0.18.14}/PyTado/zone/hops_zone.py +0 -0
  19. {python_tado-0.18.12 → python_tado-0.18.14}/PyTado/zone/my_zone.py +0 -0
  20. {python_tado-0.18.12 → python_tado-0.18.14}/README.md +0 -0
  21. {python_tado-0.18.12 → python_tado-0.18.14}/python_tado.egg-info/SOURCES.txt +0 -0
  22. {python_tado-0.18.12 → python_tado-0.18.14}/python_tado.egg-info/dependency_links.txt +0 -0
  23. {python_tado-0.18.12 → python_tado-0.18.14}/python_tado.egg-info/entry_points.txt +0 -0
  24. {python_tado-0.18.12 → python_tado-0.18.14}/python_tado.egg-info/not-zip-safe +0 -0
  25. {python_tado-0.18.12 → python_tado-0.18.14}/python_tado.egg-info/requires.txt +0 -0
  26. {python_tado-0.18.12 → python_tado-0.18.14}/python_tado.egg-info/top_level.txt +0 -0
  27. {python_tado-0.18.12 → python_tado-0.18.14}/setup.cfg +0 -0
  28. {python_tado-0.18.12 → python_tado-0.18.14}/tests/test_hops_zone.py +0 -0
  29. {python_tado-0.18.12 → python_tado-0.18.14}/tests/test_http.py +0 -0
  30. {python_tado-0.18.12 → python_tado-0.18.14}/tests/test_my_tado.py +0 -0
  31. {python_tado-0.18.12 → python_tado-0.18.14}/tests/test_my_zone.py +0 -0
  32. {python_tado-0.18.12 → python_tado-0.18.14}/tests/test_tado_interface.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-tado
3
- Version: 0.18.12
3
+ Version: 0.18.14
4
4
  Summary: PyTado from chrism0dwk, modfied by w.malgadey, diplix, michaelarnauts, LenhartStephan, splifter, syssi, andersonshatch, Yippy, p0thi, Coffee2CodeNL, chiefdragon, FilBr, nikilase, albertomontesg, Moritz-Schmidt, palazzem
5
5
  Author-email: Chris Jewell <chrism0dwk@gmail.com>, "w.malgadey" <w.malgadey@gmail.com>, FilBr <filippo.barba@protonmail.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -7,11 +7,13 @@ import json
7
7
  import logging
8
8
  import os
9
9
  import pprint
10
+ import threading
10
11
  import time
11
12
  from datetime import datetime, timedelta, timezone
12
13
  from json import dump as json_dump
13
14
  from json import load as json_load
14
15
  from pathlib import Path
16
+ from threading import Lock
15
17
  from typing import Any
16
18
  from urllib.parse import urlencode
17
19
 
@@ -146,6 +148,8 @@ _DEFAULT_RETRIES = 5
146
148
  class Http:
147
149
  """API Request Class"""
148
150
 
151
+ _lock: threading.Lock = Lock()
152
+
149
153
  def __init__(
150
154
  self,
151
155
  token_file_path: str | None = None,
@@ -396,51 +400,51 @@ class Http:
396
400
  TadoWrongCredentialsException: If the token refresh fails due to invalid credentials
397
401
  and force_refresh is False.
398
402
  """
403
+ with self._lock:
404
+ if self._refresh_at >= datetime.now(timezone.utc) and not force_refresh:
405
+ return True
406
+
407
+ url = "https://login.tado.com/oauth2/token"
408
+ data = {
409
+ "client_id": CLIENT_ID_DEVICE,
410
+ "grant_type": "refresh_token",
411
+ "refresh_token": refresh_token or self._token_refresh,
412
+ }
413
+ self._session.close()
414
+ self._session = self._create_session()
399
415
 
400
- if self._refresh_at >= datetime.now(timezone.utc) and not force_refresh:
401
- return True
402
-
403
- url = "https://login.tado.com/oauth2/token"
404
- data = {
405
- "client_id": CLIENT_ID_DEVICE,
406
- "grant_type": "refresh_token",
407
- "refresh_token": refresh_token or self._token_refresh,
408
- }
409
- self._session.close()
410
- self._session = self._create_session()
416
+ try:
417
+ response = self._session.request(
418
+ "post",
419
+ url,
420
+ params=data,
421
+ timeout=_DEFAULT_TIMEOUT,
422
+ data=json.dumps({}).encode("utf8"),
423
+ headers={
424
+ "Content-Type": "application/json",
425
+ "Referer": "https://app.tado.com/",
426
+ },
427
+ )
411
428
 
412
- try:
413
- response = self._session.request(
414
- "post",
415
- url,
416
- params=data,
417
- timeout=_DEFAULT_TIMEOUT,
418
- data=json.dumps({}).encode("utf8"),
419
- headers={
420
- "Content-Type": "application/json",
421
- "Referer": "https://app.tado.com/",
422
- },
423
- )
429
+ except requests.exceptions.ConnectionError as e:
430
+ _LOGGER.error("Connection error: %s", e)
431
+ raise TadoException(e) from e
424
432
 
425
- except requests.exceptions.ConnectionError as e:
426
- _LOGGER.error("Connection error: %s", e)
427
- raise TadoException(e) from e
433
+ if response.status_code != 200:
434
+ if force_refresh:
435
+ _LOGGER.error(
436
+ "Failed to refresh token, probably wrong credentials. Status code: %s",
437
+ response.status_code,
438
+ )
439
+ return False
428
440
 
429
- if response.status_code != 200:
430
- if force_refresh:
431
- _LOGGER.error(
432
- "Failed to refresh token, probably wrong credentials. Status code: %s",
433
- response.status_code,
441
+ raise TadoWrongCredentialsException(
442
+ f"Failed to refresh token, probably wrong credentials. Status code: {response.status_code}"
434
443
  )
435
- return False
436
444
 
437
- raise TadoWrongCredentialsException(
438
- f"Failed to refresh token, probably wrong credentials. Status code: {response.status_code}"
439
- )
440
-
441
- self._set_oauth_header(response.json())
445
+ self._set_oauth_header(response.json())
442
446
 
443
- return True
447
+ return True
444
448
 
445
449
  def _save_token(self):
446
450
  """Save the refresh token to a file."""
@@ -2,6 +2,7 @@
2
2
  PyTado interface implementation for hops.tado.com (Tado X).
3
3
  """
4
4
 
5
+ import functools
5
6
  import logging
6
7
  from typing import Any
7
8
 
@@ -11,6 +12,18 @@ from ...logger import Logger
11
12
  from ...zone import TadoXZone, TadoZone
12
13
  from .my_tado import Tado, Timetable
13
14
 
15
+
16
+ def not_supported(reason):
17
+ def decorator(func):
18
+ @functools.wraps(func)
19
+ def wrapper(*args, **kwargs):
20
+ raise TadoNotSupportedException(f"{func.__name__} is not supported: {reason}")
21
+
22
+ return wrapper
23
+
24
+ return decorator
25
+
26
+
14
27
  _LOGGER = Logger(__name__)
15
28
 
16
29
 
@@ -60,9 +73,13 @@ class TadoX(Tado):
60
73
  devices = [device for room in rooms for device in room["devices"]]
61
74
 
62
75
  for device in devices:
76
+ serial_number = device.get("serialNo", device.get("serialNumber"))
77
+ if not serial_number:
78
+ continue
79
+
63
80
  request = TadoXRequest()
64
81
  request.domain = Domain.DEVICES
65
- request.device = device["serialNo"]
82
+ request.device = serial_number
66
83
  device.update(self._http.request(request))
67
84
 
68
85
  if "otherDevices" in rooms_and_devices:
@@ -108,12 +125,12 @@ class TadoX(Tado):
108
125
 
109
126
  return data
110
127
 
128
+ @not_supported("This method is not currently supported by the Tado X API")
111
129
  def get_capabilities(self, zone):
112
130
  """
113
131
  Gets current capabilities of zone.
114
132
  """
115
-
116
- raise TadoNotSupportedException("This method is not currently supported by the Tado X API")
133
+ pass
117
134
 
118
135
  def get_climate(self, zone):
119
136
  """
@@ -126,6 +143,7 @@ class TadoX(Tado):
126
143
  "humidity": data["humidity"]["percentage"],
127
144
  }
128
145
 
146
+ @not_supported("Tado X API only support seven days timetable")
129
147
  def set_timetable(self, zone: int, timetable: Timetable) -> None:
130
148
  """
131
149
  Set the Timetable type currently active
@@ -133,8 +151,7 @@ class TadoX(Tado):
133
151
  id = 1 : THREE_DAY (MONDAY_TO_FRIDAY, SATURDAY, SUNDAY)
134
152
  id = 3 : SEVEN_DAY (MONDAY, TUESDAY, WEDNESDAY ...)
135
153
  """
136
-
137
- raise TadoNotSupportedException("Tado X API only support seven days timetable")
154
+ pass
138
155
 
139
156
  def get_schedule(self, zone: int, timetable: Timetable, day=None) -> dict[str, Any]:
140
157
  """
@@ -249,12 +266,12 @@ class TadoX(Tado):
249
266
 
250
267
  return self._http.request(request)
251
268
 
269
+ @not_supported("Concept of zones is not available by Tado X API, they use rooms")
252
270
  def get_zone_overlay_default(self, zone: int):
253
271
  """
254
272
  Get current overlay default settings for zone.
255
273
  """
256
-
257
- raise TadoNotSupportedException("Concept of zones is not available by Tado X API, they use rooms")
274
+ pass
258
275
 
259
276
  def get_open_window_detected(self, zone):
260
277
  """
@@ -273,15 +290,21 @@ class TadoX(Tado):
273
290
  Sets the window in zone to open
274
291
  Note: This can only be set if an open window was detected in this zone
275
292
  """
293
+ request = TadoXRequest()
294
+ request.command = f"rooms/{zone}/openWindow"
295
+ request.action = Action.SET
276
296
 
277
- raise TadoNotSupportedException("This method is not currently supported by the Tado X API")
297
+ return self._http.request(request)
278
298
 
279
299
  def reset_open_window(self, zone):
280
300
  """
281
301
  Sets the window in zone to closed
282
302
  """
303
+ request = TadoXRequest()
304
+ request.command = f"rooms/{zone}/openWindow"
305
+ request.action = Action.RESET
283
306
 
284
- raise TadoNotSupportedException("This method is not currently supported by the Tado X API")
307
+ return self._http.request(request)
285
308
 
286
309
  def get_device_info(self, device_id, cmd=""):
287
310
  """
@@ -324,3 +347,30 @@ class TadoX(Tado):
324
347
  request.payload = {"childLockEnabled": child_lock}
325
348
 
326
349
  self._http.request(request)
350
+
351
+ def set_flow_temperature_optimization(self, max_flow_temperature: float):
352
+ """
353
+ Set the flow temperature optimization.
354
+
355
+ max_flow_temperature: float, the maximum flow temperature in Celsius
356
+ """
357
+
358
+ request = TadoXRequest()
359
+ request.action = Action.CHANGE
360
+ request.domain = Domain.HOME
361
+ request.command = "settings/flowTemperatureOptimization"
362
+ request.payload = {"maxFlowTemperature": max_flow_temperature}
363
+
364
+ return self._http.request(request)
365
+
366
+ def get_flow_temperature_optimization(self):
367
+ """
368
+ Get the current flow temperature optimization
369
+ """
370
+
371
+ request = TadoXRequest()
372
+ request.action = Action.GET
373
+ request.domain = Domain.HOME
374
+ request.command = "settings/flowTemperatureOptimization"
375
+
376
+ return self._http.request(request)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-tado"
7
- version = "0.18.12"
7
+ version = "0.18.14"
8
8
  description = "PyTado from chrism0dwk, modfied by w.malgadey, diplix, michaelarnauts, LenhartStephan, splifter, syssi, andersonshatch, Yippy, p0thi, Coffee2CodeNL, chiefdragon, FilBr, nikilase, albertomontesg, Moritz-Schmidt, palazzem"
9
9
  authors = [
10
10
  { name = "Chris Jewell", email = "chrism0dwk@gmail.com" },
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-tado
3
- Version: 0.18.12
3
+ Version: 0.18.14
4
4
  Summary: PyTado from chrism0dwk, modfied by w.malgadey, diplix, michaelarnauts, LenhartStephan, splifter, syssi, andersonshatch, Yippy, p0thi, Coffee2CodeNL, chiefdragon, FilBr, nikilase, albertomontesg, Moritz-Schmidt, palazzem
5
5
  Author-email: Chris Jewell <chrism0dwk@gmail.com>, "w.malgadey" <w.malgadey@gmail.com>, FilBr <filippo.barba@protonmail.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
File without changes
File without changes
File without changes
File without changes