python-tado 0.19.2__tar.gz → 1.0.0__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.
- {python_tado-0.19.2 → python_tado-1.0.0}/PKG-INFO +12 -23
- python_tado-1.0.0/PyTado/__init__.py +6 -0
- {python_tado-0.19.2 → python_tado-1.0.0}/PyTado/__main__.py +15 -9
- python_tado-1.0.0/PyTado/const.py +72 -0
- {python_tado-0.19.2 → python_tado-1.0.0}/PyTado/exceptions.py +4 -0
- python_tado-1.0.0/PyTado/factory/__init__.py +7 -0
- python_tado-1.0.0/PyTado/factory/initializer.py +90 -0
- {python_tado-0.19.2 → python_tado-1.0.0}/PyTado/http.py +210 -105
- {python_tado-0.19.2 → python_tado-1.0.0}/PyTado/interface/api/__init__.py +2 -1
- python_tado-1.0.0/PyTado/interface/api/base_tado.py +601 -0
- python_tado-1.0.0/PyTado/interface/api/hops_tado.py +418 -0
- python_tado-1.0.0/PyTado/interface/api/my_tado.py +363 -0
- python_tado-1.0.0/PyTado/interface/interface.py +161 -0
- {python_tado-0.19.2 → python_tado-1.0.0}/PyTado/logger.py +1 -1
- python_tado-1.0.0/PyTado/models/__init__.py +8 -0
- python_tado-1.0.0/PyTado/models/common/schedule.py +52 -0
- python_tado-1.0.0/PyTado/models/historic.py +137 -0
- python_tado-1.0.0/PyTado/models/home.py +206 -0
- python_tado-1.0.0/PyTado/models/line_x/__init__.py +14 -0
- python_tado-1.0.0/PyTado/models/line_x/device.py +62 -0
- python_tado-1.0.0/PyTado/models/line_x/installation.py +8 -0
- python_tado-1.0.0/PyTado/models/line_x/room.py +90 -0
- python_tado-1.0.0/PyTado/models/line_x/schedule.py +31 -0
- python_tado-1.0.0/PyTado/models/pre_line_x/__init__.py +23 -0
- python_tado-1.0.0/PyTado/models/pre_line_x/boiler.py +36 -0
- python_tado-1.0.0/PyTado/models/pre_line_x/device.py +42 -0
- python_tado-1.0.0/PyTado/models/pre_line_x/flow_temperature_optimization.py +34 -0
- python_tado-1.0.0/PyTado/models/pre_line_x/home.py +7 -0
- python_tado-1.0.0/PyTado/models/pre_line_x/schedule.py +17 -0
- python_tado-1.0.0/PyTado/models/pre_line_x/zone.py +288 -0
- python_tado-1.0.0/PyTado/models/return_models.py +28 -0
- python_tado-1.0.0/PyTado/models/util.py +93 -0
- python_tado-1.0.0/PyTado/types.py +207 -0
- python_tado-1.0.0/PyTado/zone/__init__.py +6 -0
- python_tado-1.0.0/PyTado/zone/base_zone.py +471 -0
- python_tado-1.0.0/PyTado/zone/hops_zone.py +360 -0
- python_tado-1.0.0/PyTado/zone/my_zone.py +506 -0
- {python_tado-0.19.2 → python_tado-1.0.0}/README.md +5 -20
- {python_tado-0.19.2 → python_tado-1.0.0}/pyproject.toml +20 -10
- python_tado-0.19.2/PyTado/const.py +0 -99
- python_tado-0.19.2/PyTado/interface/api/hops_tado.py +0 -376
- python_tado-0.19.2/PyTado/interface/api/my_tado.py +0 -623
- python_tado-0.19.2/PyTado/interface/interface.py +0 -365
- python_tado-0.19.2/PyTado/zone/__init__.py +0 -6
- python_tado-0.19.2/PyTado/zone/hops_zone.py +0 -132
- python_tado-0.19.2/PyTado/zone/my_zone.py +0 -215
- {python_tado-0.19.2 → python_tado-1.0.0}/AUTHORS +0 -0
- {python_tado-0.19.2 → python_tado-1.0.0}/LICENSE +0 -0
- {python_tado-0.19.2 → python_tado-1.0.0}/PyTado/interface/__init__.py +0 -0
- {python_tado-0.19.2/PyTado → python_tado-1.0.0/PyTado/models/common}/__init__.py +0 -0
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: python-tado
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: PyTado from chrism0dwk, modified by w.malgadey, diplix, michaelarnauts, LenhartStephan, splifter, syssi, andersonshatch, Yippy, p0thi, Coffee2CodeNL, chiefdragon, FilBr, nikilase, albertomontesg, Moritz-Schmidt, palazzem
|
|
5
5
|
License: GPL-3.0-or-later
|
|
6
|
+
License-File: AUTHORS
|
|
7
|
+
License-File: LICENSE
|
|
6
8
|
Keywords: tado
|
|
7
9
|
Author: Chris Jewell
|
|
8
10
|
Author-email: chrism0dwk@gmail.com
|
|
@@ -16,13 +18,15 @@ Classifier: Programming Language :: Python :: 3
|
|
|
16
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
22
|
Classifier: Topic :: Home Automation
|
|
20
23
|
Provides-Extra: all
|
|
21
24
|
Provides-Extra: dev
|
|
22
25
|
Provides-Extra: lint
|
|
23
26
|
Provides-Extra: test
|
|
24
|
-
Requires-Dist: black (>=24.10) ; extra == "lint" or extra == "all"
|
|
25
27
|
Requires-Dist: pre-commit ; extra == "dev" or extra == "all"
|
|
28
|
+
Requires-Dist: pydantic (>=2.10.6,<3.0.0)
|
|
29
|
+
Requires-Dist: pydoc-markdown
|
|
26
30
|
Requires-Dist: pylint ; extra == "lint" or extra == "all"
|
|
27
31
|
Requires-Dist: pytest ; extra == "test" or extra == "all"
|
|
28
32
|
Requires-Dist: pytest-cov ; extra == "test" or extra == "all"
|
|
@@ -49,14 +53,14 @@ PyTado is a Python module implementing an interface to the Tado web API. It allo
|
|
|
49
53
|
Tado heating system for the purposes of monitoring or controlling their heating system, beyond what Tado themselves
|
|
50
54
|
currently offer.
|
|
51
55
|
|
|
52
|
-
It is hoped that this module might be used by those who wish to tweak their Tado systems, and further
|
|
56
|
+
It is hoped that this module might be used by those who wish to tweak their Tado systems, and further optimize their
|
|
53
57
|
heating setups.
|
|
54
58
|
|
|
55
59
|
---
|
|
56
60
|
|
|
57
61
|
Original author: Chris Jewell <chrism0dwk@gmail.com>
|
|
58
62
|
|
|
59
|
-
|
|
63
|
+
License: GPL v3
|
|
60
64
|
|
|
61
65
|
Copyright: Chris Jewell 2016-2018
|
|
62
66
|
|
|
@@ -65,7 +69,7 @@ Copyright: Chris Jewell 2016-2018
|
|
|
65
69
|
Besides owning a Tado system, I have no connection with the Tado company themselves. PyTado was created for my own use,
|
|
66
70
|
and for others who may wish to experiment with personal Internet of Things systems. I receive no help (financial or
|
|
67
71
|
otherwise) from Tado, and have no business interest with them. This software is provided without warranty, according to
|
|
68
|
-
the GNU Public
|
|
72
|
+
the GNU Public License version 3, and should therefore not be used where it may endanger life, financial stakes, or
|
|
69
73
|
cause discomfort and inconvenience to others.
|
|
70
74
|
|
|
71
75
|
## Usage
|
|
@@ -93,7 +97,7 @@ It is possible to save the refresh token and reuse to skip the next login.
|
|
|
93
97
|
|
|
94
98
|
The following code will use the `refresh_token` file to save the refresh-token after login, and load the refresh-token if you create the Tado interface class again.
|
|
95
99
|
|
|
96
|
-
If the file doesn't exists, the
|
|
100
|
+
If the file doesn't exists, the web browser is started and the device authentication url is automatically opened. You can activate the device in the browser. When you restart the program, the refresh-token is reused and no web browser will be opened.
|
|
97
101
|
|
|
98
102
|
```python
|
|
99
103
|
import webbrowser # only needed for direct web browser access
|
|
@@ -150,7 +154,6 @@ if __name__ == "__main__":
|
|
|
150
154
|
Note: For developers, there is an `example.py` script in `examples/` which is configured to fetch data from your account.
|
|
151
155
|
You can then invoke `python examples/example.py`.
|
|
152
156
|
|
|
153
|
-
|
|
154
157
|
## Contributing
|
|
155
158
|
|
|
156
159
|
We are very open to the community's contributions - be it a quick fix of a typo, or a completely new feature!
|
|
@@ -182,20 +185,7 @@ git clone https://github.com/yourusername/PyTado.git
|
|
|
182
185
|
cd PyTado
|
|
183
186
|
```
|
|
184
187
|
|
|
185
|
-
Then, to create your development environment and install the project with its dependencies, execute the
|
|
186
|
-
commands in your terminal:
|
|
187
|
-
|
|
188
|
-
```bash
|
|
189
|
-
# Create and activate a new virtual environment
|
|
190
|
-
python3 -m venv venv
|
|
191
|
-
source venv/bin/activate
|
|
192
|
-
|
|
193
|
-
# install all dependencies
|
|
194
|
-
poetry install
|
|
195
|
-
|
|
196
|
-
# Install pre-commit hooks
|
|
197
|
-
poetry run pre-commit install
|
|
198
|
-
```
|
|
188
|
+
Then, to create your development environment and install the project with its dependencies, execute the `./scripts/bootstrap` script.
|
|
199
189
|
|
|
200
190
|
### Coding Guidelines
|
|
201
191
|
|
|
@@ -234,7 +224,6 @@ A message from the original author:
|
|
|
234
224
|
>
|
|
235
225
|
> Chris Jewell
|
|
236
226
|
|
|
237
|
-
|
|
238
227
|
[devcontainer-shield]: https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode
|
|
239
228
|
[devcontainer]: https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/wmalgadey/PyTado
|
|
240
229
|
|
|
@@ -9,7 +9,7 @@ import sys
|
|
|
9
9
|
from PyTado.interface import Tado
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def log_in(args):
|
|
12
|
+
def log_in(args: argparse.Namespace) -> Tado:
|
|
13
13
|
"""
|
|
14
14
|
Log in to the Tado API by activating the current device.
|
|
15
15
|
|
|
@@ -27,7 +27,7 @@ def log_in(args):
|
|
|
27
27
|
return t
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def get_me(args):
|
|
30
|
+
def get_me(args: argparse.Namespace) -> None:
|
|
31
31
|
"""
|
|
32
32
|
Retrieve and print home information from the Tado API.
|
|
33
33
|
|
|
@@ -39,7 +39,7 @@ def get_me(args):
|
|
|
39
39
|
print(me)
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
def get_state(args):
|
|
42
|
+
def get_state(args: argparse.Namespace) -> None:
|
|
43
43
|
"""
|
|
44
44
|
Retrieve and print the state of a specific zone from the Tado API.
|
|
45
45
|
|
|
@@ -51,7 +51,7 @@ def get_state(args):
|
|
|
51
51
|
print(zone)
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
def get_states(args):
|
|
54
|
+
def get_states(args: argparse.Namespace) -> None:
|
|
55
55
|
"""
|
|
56
56
|
Retrieve and print the states of all zones from the Tado API.
|
|
57
57
|
|
|
@@ -63,7 +63,7 @@ def get_states(args):
|
|
|
63
63
|
print(zones)
|
|
64
64
|
|
|
65
65
|
|
|
66
|
-
def get_capabilities(args):
|
|
66
|
+
def get_capabilities(args: argparse.Namespace) -> None:
|
|
67
67
|
"""
|
|
68
68
|
Retrieve and print the capabilities of a specific zone from the Tado API.
|
|
69
69
|
|
|
@@ -75,7 +75,7 @@ def get_capabilities(args):
|
|
|
75
75
|
print(capabilities)
|
|
76
76
|
|
|
77
77
|
|
|
78
|
-
def main():
|
|
78
|
+
def main() -> None:
|
|
79
79
|
"""
|
|
80
80
|
Main method for the script.
|
|
81
81
|
|
|
@@ -109,17 +109,23 @@ def main():
|
|
|
109
109
|
show_config_parser = subparsers.add_parser("get_me", help="Get home information.")
|
|
110
110
|
show_config_parser.set_defaults(func=get_me)
|
|
111
111
|
|
|
112
|
-
start_activity_parser = subparsers.add_parser(
|
|
112
|
+
start_activity_parser = subparsers.add_parser(
|
|
113
|
+
"get_state", help="Get state of zone."
|
|
114
|
+
)
|
|
113
115
|
start_activity_parser.add_argument("--zone", help="Zone to get the state of.")
|
|
114
116
|
start_activity_parser.set_defaults(func=get_state)
|
|
115
117
|
|
|
116
|
-
start_activity_parser = subparsers.add_parser(
|
|
118
|
+
start_activity_parser = subparsers.add_parser(
|
|
119
|
+
"get_states", help="Get states of all zones."
|
|
120
|
+
)
|
|
117
121
|
start_activity_parser.set_defaults(func=get_states)
|
|
118
122
|
|
|
119
123
|
start_activity_parser = subparsers.add_parser(
|
|
120
124
|
"get_capabilities", help="Get capabilities of zone."
|
|
121
125
|
)
|
|
122
|
-
start_activity_parser.add_argument(
|
|
126
|
+
start_activity_parser.add_argument(
|
|
127
|
+
"--zone", help="Zone to get the capabilities of."
|
|
128
|
+
)
|
|
123
129
|
start_activity_parser.set_defaults(func=get_capabilities)
|
|
124
130
|
|
|
125
131
|
args = parser.parse_args()
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Constant values for the Tado component."""
|
|
2
|
+
|
|
3
|
+
from PyTado.types import FanLevel, FanSpeed, HvacAction, HvacMode
|
|
4
|
+
|
|
5
|
+
# API client ID
|
|
6
|
+
CLIENT_ID_DEVICE = "1bb50063-6b0c-4d11-bd99-387f4a91cc46" # nosec B105
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
CONST_LINK_OFFLINE = "OFFLINE"
|
|
10
|
+
CONST_CONNECTION_OFFLINE = "OFFLINE"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
FAN_SPEED_TO_FAN_LEVEL = {
|
|
14
|
+
FanSpeed.OFF: FanLevel.OFF,
|
|
15
|
+
FanSpeed.AUTO: FanLevel.AUTO,
|
|
16
|
+
FanSpeed.LOW: FanLevel.LEVEL1,
|
|
17
|
+
FanSpeed.MIDDLE: FanLevel.LEVEL2,
|
|
18
|
+
FanSpeed.HIGH: FanLevel.LEVEL3,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# When we change the temperature setting, we need an overlay mode
|
|
22
|
+
CONST_OVERLAY_TADO_MODE = (
|
|
23
|
+
"NEXT_TIME_BLOCK" # wait until tado changes the mode automatic
|
|
24
|
+
)
|
|
25
|
+
CONST_OVERLAY_MANUAL = "MANUAL" # the user has changed the temperature or mode manually
|
|
26
|
+
CONST_OVERLAY_TIMER = "TIMER" # the temperature will be reset after a timespan
|
|
27
|
+
|
|
28
|
+
# Heat always comes first since we get the
|
|
29
|
+
# min and max tempatures for the zone from
|
|
30
|
+
# it.
|
|
31
|
+
# Heat is preferred as it generally has a lower minimum temperature
|
|
32
|
+
ORDERED_KNOWN_TADO_MODES = [
|
|
33
|
+
HvacMode.HEAT,
|
|
34
|
+
HvacMode.COOL,
|
|
35
|
+
HvacMode.AUTO,
|
|
36
|
+
HvacMode.DRY,
|
|
37
|
+
HvacMode.FAN,
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
TADO_MODES_TO_HVAC_ACTION: dict[HvacMode, HvacAction] = {
|
|
41
|
+
HvacMode.HEAT: HvacAction.HEATING,
|
|
42
|
+
HvacMode.DRY: HvacAction.DRYING,
|
|
43
|
+
HvacMode.FAN: HvacAction.FAN,
|
|
44
|
+
HvacMode.COOL: HvacAction.COOLING,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
TADO_HVAC_ACTION_TO_MODES: dict[HvacAction, HvacMode | HvacAction] = {
|
|
48
|
+
HvacAction.HEATING: HvacMode.HEAT,
|
|
49
|
+
HvacAction.HOT_WATER: HvacAction.HEATING,
|
|
50
|
+
HvacAction.DRYING: HvacMode.DRY,
|
|
51
|
+
HvacAction.FAN: HvacMode.FAN,
|
|
52
|
+
HvacAction.COOLING: HvacMode.COOL,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# These modes will not allow a temp to be set
|
|
56
|
+
TADO_MODES_WITH_NO_TEMP_SETTING = [
|
|
57
|
+
HvacMode.AUTO,
|
|
58
|
+
HvacMode.DRY,
|
|
59
|
+
HvacMode.FAN,
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
DEFAULT_TADO_PRECISION = 0.1
|
|
63
|
+
DEFAULT_TADOX_PRECISION = 0.01
|
|
64
|
+
DEFAULT_DATE_FORMAT = "%Y-%m-%d"
|
|
65
|
+
|
|
66
|
+
DEFAULT_TADOX_MIN_TEMP = 5.0
|
|
67
|
+
DEFAULT_TADOX_MAX_TEMP = 30.0
|
|
68
|
+
|
|
69
|
+
HOME_DOMAIN = "homes"
|
|
70
|
+
DEVICE_DOMAIN = "devices"
|
|
71
|
+
|
|
72
|
+
HTTP_CODES_OK = [200, 201, 202, 204]
|
|
@@ -19,3 +19,7 @@ class TadoNoCredentialsException(TadoCredentialsException):
|
|
|
19
19
|
|
|
20
20
|
class TadoWrongCredentialsException(TadoCredentialsException):
|
|
21
21
|
"""Exception to indicate wrong credentials"""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TadoRateLimitException(TadoException):
|
|
25
|
+
"""Exception to indicate API rate limit has been exceeded."""
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""
|
|
2
|
+
PyTado API factory to use app.tado.com or hops.tado.com
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Self
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
import PyTado.interface.api as API
|
|
10
|
+
from PyTado.exceptions import TadoException
|
|
11
|
+
from PyTado.http import DeviceActivationStatus, Http
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TadoClientInitializer:
|
|
15
|
+
"""Class to authenticate and get the Tado client."""
|
|
16
|
+
|
|
17
|
+
http: Http
|
|
18
|
+
debug: bool = False
|
|
19
|
+
token_file_path: str | None = None
|
|
20
|
+
saved_refresh_token: str | None = None
|
|
21
|
+
http_session: requests.Session | None = None
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
token_file_path: str | None = None,
|
|
26
|
+
saved_refresh_token: str | None = None,
|
|
27
|
+
http_session: requests.Session | None = None,
|
|
28
|
+
debug: bool = False,
|
|
29
|
+
):
|
|
30
|
+
self.token_file_path = token_file_path
|
|
31
|
+
self.saved_refresh_token = saved_refresh_token
|
|
32
|
+
self.http_session = http_session
|
|
33
|
+
self.debug = debug
|
|
34
|
+
self.http = Http(
|
|
35
|
+
token_file_path=token_file_path,
|
|
36
|
+
saved_refresh_token=saved_refresh_token,
|
|
37
|
+
http_session=http_session,
|
|
38
|
+
debug=debug,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def get_verification_url(self) -> str | None:
|
|
42
|
+
"""Returns the URL for device verification."""
|
|
43
|
+
if self.http.device_activation_status == DeviceActivationStatus.NOT_STARTED:
|
|
44
|
+
self.device_activation()
|
|
45
|
+
|
|
46
|
+
return self.http.device_verification_url
|
|
47
|
+
|
|
48
|
+
def device_activation(self) -> Self:
|
|
49
|
+
"""Activates the device.
|
|
50
|
+
|
|
51
|
+
Caution: this method will block until the device is activated or the timeout is reached.
|
|
52
|
+
"""
|
|
53
|
+
self.http.device_activation()
|
|
54
|
+
|
|
55
|
+
return self
|
|
56
|
+
|
|
57
|
+
def get_client(self) -> API.TadoX | API.Tado:
|
|
58
|
+
"""Returns the client instance after device activation."""
|
|
59
|
+
if self.http.device_activation_status == DeviceActivationStatus.COMPLETED:
|
|
60
|
+
if self.http.is_x_line:
|
|
61
|
+
return API.TadoX.from_http(http=self.http, debug=self.debug)
|
|
62
|
+
|
|
63
|
+
return API.Tado.from_http(http=self.http, debug=self.debug)
|
|
64
|
+
|
|
65
|
+
raise TadoException(
|
|
66
|
+
"Authentication failed. Please check the device verification URL and try again."
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def authenticate_and_get_client(self) -> API.TadoX | API.Tado:
|
|
70
|
+
"""Authenticate and get the client instance, prompting for device activation if needed."""
|
|
71
|
+
print("Starting device activation process...")
|
|
72
|
+
print("Device activation status: ", self.http.device_activation_status)
|
|
73
|
+
|
|
74
|
+
if self.http.device_activation_status != DeviceActivationStatus.COMPLETED:
|
|
75
|
+
print("Click on the link to log in to your Tado account.")
|
|
76
|
+
print("Device verification URL: ", self.get_verification_url())
|
|
77
|
+
|
|
78
|
+
self.device_activation()
|
|
79
|
+
|
|
80
|
+
if (
|
|
81
|
+
self.http.device_activation_status == DeviceActivationStatus.COMPLETED
|
|
82
|
+
): # pyright: ignore[reportUnnecessaryComparison]
|
|
83
|
+
print("Device activation completed successfully.")
|
|
84
|
+
else:
|
|
85
|
+
raise TadoException(
|
|
86
|
+
"Device activation failed. "
|
|
87
|
+
"Please check the device verification URL and try again."
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
return self.get_client()
|