python-tado 0.18.3__tar.gz → 0.18.5__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 (34) hide show
  1. {python_tado-0.18.3/python_tado.egg-info → python_tado-0.18.5}/PKG-INFO +101 -18
  2. {python_tado-0.18.3 → python_tado-0.18.5}/PyTado/const.py +2 -0
  3. {python_tado-0.18.3 → python_tado-0.18.5}/PyTado/http.py +10 -0
  4. {python_tado-0.18.3 → python_tado-0.18.5}/PyTado/interface/api/hops_tado.py +76 -22
  5. {python_tado-0.18.3 → python_tado-0.18.5}/PyTado/interface/api/my_tado.py +47 -35
  6. python_tado-0.18.5/PyTado/interface/interface.py +298 -0
  7. {python_tado-0.18.3 → python_tado-0.18.5}/PyTado/zone/hops_zone.py +17 -10
  8. {python_tado-0.18.3 → python_tado-0.18.5}/PyTado/zone/my_zone.py +17 -14
  9. python_tado-0.18.5/README.md +111 -0
  10. {python_tado-0.18.3 → python_tado-0.18.5}/pyproject.toml +6 -2
  11. {python_tado-0.18.3 → python_tado-0.18.5/python_tado.egg-info}/PKG-INFO +101 -18
  12. {python_tado-0.18.3 → python_tado-0.18.5}/python_tado.egg-info/SOURCES.txt +1 -0
  13. {python_tado-0.18.3 → python_tado-0.18.5}/python_tado.egg-info/requires.txt +5 -0
  14. python_tado-0.18.5/tests/test_hops_zone.py +147 -0
  15. {python_tado-0.18.3 → python_tado-0.18.5}/tests/test_http.py +12 -7
  16. {python_tado-0.18.3 → python_tado-0.18.5}/tests/test_my_tado.py +13 -0
  17. {python_tado-0.18.3 → python_tado-0.18.5}/tests/test_my_zone.py +32 -0
  18. python_tado-0.18.3/PyTado/interface/interface.py +0 -39
  19. python_tado-0.18.3/README.md +0 -32
  20. {python_tado-0.18.3 → python_tado-0.18.5}/AUTHORS +0 -0
  21. {python_tado-0.18.3 → python_tado-0.18.5}/LICENSE +0 -0
  22. {python_tado-0.18.3 → python_tado-0.18.5}/PyTado/__init__.py +0 -0
  23. {python_tado-0.18.3 → python_tado-0.18.5}/PyTado/__main__.py +0 -0
  24. {python_tado-0.18.3 → python_tado-0.18.5}/PyTado/exceptions.py +0 -0
  25. {python_tado-0.18.3 → python_tado-0.18.5}/PyTado/interface/__init__.py +0 -0
  26. {python_tado-0.18.3 → python_tado-0.18.5}/PyTado/interface/api/__init__.py +0 -0
  27. {python_tado-0.18.3 → python_tado-0.18.5}/PyTado/logger.py +0 -0
  28. {python_tado-0.18.3 → python_tado-0.18.5}/PyTado/zone/__init__.py +0 -0
  29. {python_tado-0.18.3 → python_tado-0.18.5}/python_tado.egg-info/dependency_links.txt +0 -0
  30. {python_tado-0.18.3 → python_tado-0.18.5}/python_tado.egg-info/entry_points.txt +0 -0
  31. {python_tado-0.18.3 → python_tado-0.18.5}/python_tado.egg-info/not-zip-safe +0 -0
  32. {python_tado-0.18.3 → python_tado-0.18.5}/python_tado.egg-info/top_level.txt +0 -0
  33. {python_tado-0.18.3 → python_tado-0.18.5}/setup.cfg +0 -0
  34. {python_tado-0.18.3 → python_tado-0.18.5}/tests/test_tado_interface.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-tado
3
- Version: 0.18.3
3
+ Version: 0.18.5
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
@@ -696,43 +696,126 @@ License-File: AUTHORS
696
696
  Requires-Dist: requests
697
697
  Provides-Extra: dev
698
698
  Requires-Dist: black>=24.3; extra == "dev"
699
+ Requires-Dist: pre-commit; extra == "dev"
699
700
  Requires-Dist: pytype; extra == "dev"
700
701
  Requires-Dist: pylint; extra == "dev"
701
702
  Requires-Dist: types-requests; extra == "dev"
703
+ Requires-Dist: requests; extra == "dev"
702
704
  Requires-Dist: responses; extra == "dev"
703
705
  Requires-Dist: coverage; extra == "dev"
704
706
  Requires-Dist: pytest; extra == "dev"
705
707
  Requires-Dist: pytest-cov; extra == "dev"
708
+ Provides-Extra: all
709
+ Requires-Dist: python-tado[dev]; extra == "all"
706
710
 
707
- PyTado -- Pythonize your central heating
708
- ========================================
711
+ # PyTado -- Pythonize your central heating
709
712
 
710
- Author: Chris Jewell <chrism0dwk@gmail.com>
711
- Modified: Wolfgang Malgadey <wolfgang@malgadey.de>
713
+ [![Linting and testing](https://github.com/wmalgadey/PyTado/actions/workflows/lint-and-test-matrix.yml/badge.svg)](https://github.com/wmalgadey/PyTado/actions/workflows/lint-and-test-matrix.yml)
714
+ [![Build and deploy to pypi](https://github.com/wmalgadey/PyTado/actions/workflows/publish-to-pypi.yml/badge.svg)](https://github.com/wmalgadey/PyTado/actions/workflows/publish-to-pypi.yml)
715
+ [![PyPI version](https://badge.fury.io/py/python-tado.svg)](https://badge.fury.io/py/python-tado)
716
+
717
+ PyTado is a Python module implementing an interface to the Tado web API. It allows a user to interact with their
718
+ Tado heating system for the purposes of monitoring or controlling their heating system, beyond what Tado themselves
719
+ currently offer.
720
+
721
+ It is hoped that this module might be used by those who wish to tweak their Tado systems, and further optimise their
722
+ heating setups.
723
+
724
+ ---
725
+
726
+ Original author: Chris Jewell <chrism0dwk@gmail.com>
712
727
 
713
728
  Licence: GPL v3
714
729
 
715
730
  Copyright: Chris Jewell 2016-2018
716
731
 
717
- PyTado is a Python module implementing an interface to the Tado web API. It allows a user to interact with their Tado heating system for the purposes of monitoring or controlling their heating system, beyond what Tado themselves currently offer.
732
+ ## Disclaimer
718
733
 
719
- It is hoped that this module might be used by those who wish to tweak their Tado systems, and further optimise their heating setups.
734
+ Besides owning a Tado system, I have no connection with the Tado company themselves. PyTado was created for my own use,
735
+ and for others who may wish to experiment with personal Internet of Things systems. I receive no help (financial or
736
+ otherwise) from Tado, and have no business interest with them. This software is provided without warranty, according to
737
+ the GNU Public Licence version 3, and should therefore not be used where it may endanger life, financial stakes, or
738
+ cause discomfort and inconvenience to others.
720
739
 
721
- Disclaimer
722
- ----------
723
- Besides owning a Tado system, I have no connection with the Tado company themselves. PyTado was created for my own use, and for others who may wish to experiment with personal Internet of Things systems. I receive no help (financial or otherwise) from Tado, and have no business interest with them. This software is provided without warranty, according to the GNU Public Licence version 3, and should therefore not be used where it may endanger life, financial stakes, or cause discomfort and inconvenience to others.
724
-
725
- Example basic usage
726
- -------------------
740
+ ## Example basic usage
727
741
 
728
742
  >>> from PyTado.interface import Tado
729
743
  >>> t = Tado('my@username.com', 'mypassword')
730
744
  >>> climate = t.get_climate(zone=1)
731
745
 
732
- Development
733
- -----------
734
- This software is at a purely experimental stage. If you're interested and can write Python, clone the Github repo, drop me a line, and get involved!
746
+ ## Contributing
747
+
748
+ We are very open to the community's contributions - be it a quick fix of a typo, or a completely new feature!
749
+
750
+ You don't need to be a Python expert to provide meaningful improvements. To learn how to get started, check out our
751
+ [Contributor Guidelines](https://github.com/wmalgadey/econnect-python/blob/main/CONTRIBUTING.md) first, and ask for help
752
+ in [GitHub Discussions](https://github.com/wmalgadey/PyTado/discussions) if you have questions.
753
+
754
+ ## Development
755
+
756
+ We welcome external contributions, even though the project was initially intended for personal use. If you think some
757
+ parts could be exposed with a more generic interface, please open a [GitHub issue](https://github.com/wmalgadey/PyTado/issues)
758
+ to discuss your suggestion.
759
+
760
+ ### Dev Environment
761
+
762
+ To contribute to this repository, you should first clone your fork and then setup your development environment. Clone
763
+ your repository as follows (replace yourusername with your GitHub account name):
764
+
765
+ ```bash
766
+ git clone https://github.com/yourusername/PyTado.git
767
+ cd PyTado
768
+ ```
769
+
770
+ Then, to create your development environment and install the project with its dependencies, execute the following
771
+ commands in your terminal:
772
+
773
+ ```bash
774
+ # Create and activate a new virtual environment
775
+ python3 -m venv venv
776
+ source venv/bin/activate
777
+
778
+ # Upgrade pip and install all projects and their dependencies
779
+ pip install --upgrade pip
780
+ pip install -e '.[all]'
781
+
782
+ # Install pre-commit hooks
783
+ pre-commit install
784
+ ```
785
+
786
+ ### Coding Guidelines
787
+
788
+ To maintain a consistent codebase, we utilize [black][1]. Consistency is crucial as it helps readability, reduces errors,
789
+ and facilitates collaboration among developers.
790
+
791
+ To ensure that every commit adheres to our coding standards, we've integrated [pre-commit hooks][2]. These hooks
792
+ automatically run `black` before each commit, ensuring that all code changes are automatically checked and formatted.
793
+
794
+ For details on how to set up your development environment to make use of these hooks, please refer to the
795
+ [Development][3] section of our documentation.
796
+
797
+ [1]: https://github.com/ambv/black
798
+ [2]: https://pre-commit.com/
799
+ [3]: https://github.com/wmalgadey/PyTado#development
800
+
801
+ ### Testing
802
+
803
+ Ensuring the robustness and reliability of our code is paramount. Therefore, all contributions must include at least one
804
+ test to verify the intended behavior.
805
+
806
+ To run tests locally, execute the test suite using `pytest` with the following command:
807
+
808
+ ```bash
809
+ pytest tests/ --cov --cov-branch -vv
810
+ ```
811
+
812
+ ---
735
813
 
736
- Best wishes and a warm winter to all!
814
+ A message from the original author:
737
815
 
738
- Chris Jewell
816
+ > This software is at a purely experimental stage. If you're interested and can write Python, clone the Github repo,
817
+ > drop me a line, and get involved!
818
+ >
819
+ > Best wishes and a warm winter to all!
820
+ >
821
+ > Chris Jewell
@@ -21,6 +21,7 @@ CONST_MODE_DRY = "DRY"
21
21
  CONST_MODE_FAN = "FAN"
22
22
 
23
23
  CONST_LINK_OFFLINE = "OFFLINE"
24
+ CONST_CONNECTION_OFFLINE = "OFFLINE"
24
25
 
25
26
  CONST_FAN_OFF = "OFF"
26
27
  CONST_FAN_AUTO = "AUTO"
@@ -99,6 +100,7 @@ TADO_MODES_WITH_NO_TEMP_SETTING = [
99
100
  ]
100
101
 
101
102
  DEFAULT_TADO_PRECISION = 0.1
103
+ DEFAULT_TADOX_PRECISION = 0.01
102
104
 
103
105
  HOME_DOMAIN = "homes"
104
106
  DEVICE_DOMAIN = "devices"
@@ -8,6 +8,7 @@ import logging
8
8
  import pprint
9
9
  from datetime import datetime, timedelta
10
10
  from typing import Any
11
+ from urllib.parse import urlencode
11
12
 
12
13
  import requests
13
14
 
@@ -25,6 +26,9 @@ class Endpoint(enum.StrEnum):
25
26
  HOPS_API = "https://hops.tado.com/"
26
27
  MOBILE = "https://my.tado.com/mobile/1.9/"
27
28
  EIQ = "https://energy-insights.tado.com/api/"
29
+ TARIFF = "https://tariff-experience.tado.com/api/"
30
+ GENIE = "https://genie.tado.com/api/v2/"
31
+ MINDER = "https://minder.tado.com/v1/"
28
32
 
29
33
 
30
34
  class Domain(enum.StrEnum):
@@ -63,6 +67,7 @@ class TadoRequest:
63
67
  domain: Domain = Domain.HOME,
64
68
  device: int | None = None,
65
69
  mode: Mode = Mode.OBJECT,
70
+ params: dict[str, Any] | None = None,
66
71
  ):
67
72
  self.endpoint = endpoint
68
73
  self.command = command
@@ -71,6 +76,7 @@ class TadoRequest:
71
76
  self.domain = domain
72
77
  self.device = device
73
78
  self.mode = mode
79
+ self.params = params
74
80
 
75
81
 
76
82
  class TadoXRequest(TadoRequest):
@@ -85,6 +91,7 @@ class TadoXRequest(TadoRequest):
85
91
  domain: Domain = Domain.HOME,
86
92
  device: int | None = None,
87
93
  mode: Mode = Mode.OBJECT,
94
+ params: dict[str, Any] | None = None,
88
95
  ):
89
96
  super().__init__(
90
97
  endpoint=endpoint,
@@ -94,6 +101,7 @@ class TadoXRequest(TadoRequest):
94
101
  domain=domain,
95
102
  device=device,
96
103
  mode=mode,
104
+ params=params,
97
105
  )
98
106
  self._action = action
99
107
 
@@ -212,6 +220,8 @@ class Http:
212
220
  url = f"{request.endpoint}{request.domain}/{request.device}/{request.command}"
213
221
  elif request.domain == Domain.ME:
214
222
  url = f"{request.endpoint}{request.domain}"
223
+ elif request.endpoint == Endpoint.MINDER:
224
+ url = f"{request.endpoint}{request.domain}/{self.id:d}/{request.command}?{urlencode(request.params)}"
215
225
  else:
216
226
  url = f"{request.endpoint}{request.domain}/{self._id:d}/{request.command}"
217
227
  return url
@@ -12,6 +12,7 @@ from ...logger import Logger
12
12
  from ...exceptions import TadoNotSupportedException
13
13
  from ...http import (
14
14
  Action,
15
+ Domain,
15
16
  Http,
16
17
  Mode,
17
18
  TadoRequest,
@@ -28,7 +29,7 @@ class TadoX(Tado):
28
29
 
29
30
  Example usage: http = Http('me@somewhere.com', 'mypasswd')
30
31
  t = TadoX(http)
31
- t.get_climate(1) # Get climate, zone 1.
32
+ t.get_climate(1) # Get climate, room 1.
32
33
  """
33
34
 
34
35
  def __init__(
@@ -56,28 +57,36 @@ class TadoX(Tado):
56
57
  # set to None until explicitly set
57
58
  self._auto_geofencing_supported = None
58
59
 
59
- def _create_x_request(self) -> TadoRequest:
60
- return TadoXRequest()
61
-
62
60
  def get_devices(self):
63
61
  """
64
62
  Gets device information.
65
63
  """
66
64
 
67
- request = self._create_x_request()
65
+ request = TadoXRequest()
68
66
  request.command = "roomsAndDevices"
69
67
 
70
- rooms: list[dict[str, Any]] = self._http.request(request)["rooms"]
68
+ rooms_and_devices: list[dict[str, Any]] = self._http.request(request)
69
+ rooms = rooms_and_devices["rooms"]
70
+
71
71
  devices = [device for room in rooms for device in room["devices"]]
72
72
 
73
+ for device in devices:
74
+ request = TadoXRequest()
75
+ request.domain = Domain.DEVICES
76
+ request.device = device["serialNo"]
77
+ device.update(self._http.request(request))
78
+
79
+ if "otherDevices" in rooms_and_devices:
80
+ devices.append(rooms_and_devices["otherDevices"])
81
+
73
82
  return devices
74
83
 
75
84
  def get_zones(self):
76
85
  """
77
- Gets zones information.
86
+ Gets zones (or rooms in Tado X API) information.
78
87
  """
79
88
 
80
- request = self._create_x_request()
89
+ request = TadoXRequest()
81
90
  request.command = "roomsAndDevices"
82
91
 
83
92
  return self._http.request(request)["rooms"]
@@ -94,7 +103,7 @@ class TadoX(Tado):
94
103
  Gets current states of all zones.
95
104
  """
96
105
 
97
- request = self._create_x_request()
106
+ request = TadoXRequest()
98
107
  request.command = "rooms"
99
108
 
100
109
  return self._http.request(request)
@@ -104,7 +113,7 @@ class TadoX(Tado):
104
113
  Gets current state of Zone.
105
114
  """
106
115
 
107
- request = self._create_x_request()
116
+ request = TadoXRequest()
108
117
  request.command = f"rooms/{zone:d}"
109
118
  data = self._http.request(request)
110
119
 
@@ -139,7 +148,7 @@ class TadoX(Tado):
139
148
  """
140
149
 
141
150
  raise TadoNotSupportedException(
142
- "This method is not currently supported by the Tado X API"
151
+ "Tado X API only support seven days timetable"
143
152
  )
144
153
 
145
154
  def get_schedule(
@@ -150,17 +159,54 @@ class TadoX(Tado):
150
159
  Zone has 3 different schedules, one for each timetable (see setTimetable)
151
160
  """
152
161
 
153
- request = self._create_x_request()
162
+ request = TadoXRequest()
154
163
  request.command = f"rooms/{zone:d}/schedule"
155
164
 
156
165
  return self._http.request(request)
157
166
 
158
167
  def set_schedule(self, zone, timetable: Timetable, day, data):
159
168
  """
160
- Set the schedule for a zone, day is required
169
+ Set the schedule for a zone, day is not required for Tado X API.
170
+
171
+ example data
172
+ [
173
+ {
174
+ "start": "00:00",
175
+ "end": "07:05",
176
+ "dayType": "MONDAY",
177
+ "setting": {
178
+ "power": "ON",
179
+ "temperature": {
180
+ "value": 18
181
+ }
182
+ }
183
+ },
184
+ {
185
+ "start": "07:05",
186
+ "end": "22:05",
187
+ "dayType": "MONDAY",
188
+ "setting": {
189
+ "power": "ON",
190
+ "temperature": {
191
+ "value": 22
192
+ }
193
+ }
194
+ },
195
+ {
196
+ "start": "22:05",
197
+ "end": "24:00",
198
+ "dayType": "MONDAY",
199
+ "setting": {
200
+ "power": "ON",
201
+ "temperature": {
202
+ "value": 18
203
+ }
204
+ }
205
+ }
206
+ ]
161
207
  """
162
208
 
163
- request = self._create_x_request()
209
+ request = TadoXRequest()
164
210
  request.command = f"rooms/{zone:d}/schedule"
165
211
  request.action = Action.SET
166
212
  request.payload = data
@@ -173,7 +219,7 @@ class TadoX(Tado):
173
219
  Delete current overlay
174
220
  """
175
221
 
176
- request = self._create_x_request()
222
+ request = TadoXRequest()
177
223
  request.command = f"rooms/{zone:d}/resumeSchedule"
178
224
  request.action = Action.SET
179
225
 
@@ -195,7 +241,7 @@ class TadoX(Tado):
195
241
  horizontal_swing=None,
196
242
  ):
197
243
  """
198
- Set current overlay for a zone
244
+ Set current overlay for a zone, a room in Tado X API.
199
245
  """
200
246
 
201
247
  post_data = {
@@ -213,7 +259,7 @@ class TadoX(Tado):
213
259
  if duration is not None:
214
260
  post_data["termination"]["durationInSeconds"] = duration
215
261
 
216
- request = self._create_x_request()
262
+ request = TadoXRequest()
217
263
  request.command = f"rooms/{zone:d}/manualControl"
218
264
  request.action = Action.SET
219
265
  request.payload = post_data
@@ -226,7 +272,7 @@ class TadoX(Tado):
226
272
  """
227
273
 
228
274
  raise TadoNotSupportedException(
229
- "This method is not currently supported by the Tado X API"
275
+ "Concept of zones is not available by Tado X API, they use rooms"
230
276
  )
231
277
 
232
278
  def get_open_window_detected(self, zone):
@@ -266,16 +312,24 @@ class TadoX(Tado):
266
312
  with option to get specific info i.e. cmd='temperatureOffset'
267
313
  """
268
314
 
269
- raise TadoNotSupportedException(
270
- "This method is not currently supported by the Tado X API"
271
- )
315
+ if cmd:
316
+ request = TadoRequest()
317
+ request.command = cmd
318
+ else:
319
+ request = TadoXRequest()
320
+
321
+ request.action = Action.GET
322
+ request.domain = Domain.DEVICES
323
+ request.device = device_id
324
+
325
+ return self._http.request(request)
272
326
 
273
327
  def set_temp_offset(self, device_id, offset=0, measure="celsius"):
274
328
  """
275
329
  Set the Temperature offset on the device.
276
330
  """
277
331
 
278
- request = self._create_x_request()
332
+ request = TadoXRequest()
279
333
  request.command = f"roomsAndDevices/devices/{device_id}"
280
334
  request.action = Action.CHANGE
281
335
  request.payload = {"temperatureOffset": offset}