python-tado 0.18.3__tar.gz → 0.18.4__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.18.3/python_tado.egg-info → python_tado-0.18.4}/PKG-INFO +1 -1
- {python_tado-0.18.3 → python_tado-0.18.4}/PyTado/const.py +2 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/PyTado/http.py +2 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/PyTado/interface/api/hops_tado.py +76 -22
- {python_tado-0.18.3 → python_tado-0.18.4}/PyTado/interface/api/my_tado.py +32 -35
- {python_tado-0.18.3 → python_tado-0.18.4}/PyTado/zone/hops_zone.py +17 -10
- {python_tado-0.18.3 → python_tado-0.18.4}/PyTado/zone/my_zone.py +17 -14
- {python_tado-0.18.3 → python_tado-0.18.4}/pyproject.toml +1 -1
- {python_tado-0.18.3 → python_tado-0.18.4/python_tado.egg-info}/PKG-INFO +1 -1
- {python_tado-0.18.3 → python_tado-0.18.4}/python_tado.egg-info/SOURCES.txt +1 -0
- python_tado-0.18.4/tests/test_hops_zone.py +147 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/tests/test_http.py +12 -7
- {python_tado-0.18.3 → python_tado-0.18.4}/tests/test_my_zone.py +32 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/AUTHORS +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/LICENSE +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/PyTado/__init__.py +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/PyTado/__main__.py +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/PyTado/exceptions.py +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/PyTado/interface/__init__.py +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/PyTado/interface/api/__init__.py +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/PyTado/interface/interface.py +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/PyTado/logger.py +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/PyTado/zone/__init__.py +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/README.md +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/python_tado.egg-info/dependency_links.txt +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/python_tado.egg-info/entry_points.txt +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/python_tado.egg-info/not-zip-safe +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/python_tado.egg-info/requires.txt +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/python_tado.egg-info/top_level.txt +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/setup.cfg +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/tests/test_my_tado.py +0 -0
- {python_tado-0.18.3 → python_tado-0.18.4}/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
|
+
Version: 0.18.4
|
|
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
|
|
@@ -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"
|
|
@@ -25,6 +25,8 @@ class Endpoint(enum.StrEnum):
|
|
|
25
25
|
HOPS_API = "https://hops.tado.com/"
|
|
26
26
|
MOBILE = "https://my.tado.com/mobile/1.9/"
|
|
27
27
|
EIQ = "https://energy-insights.tado.com/api/"
|
|
28
|
+
TARIFF = "https://tariff-experience.tado.com/api/"
|
|
29
|
+
GENIE = "https://genie.tado.com/api/v2/"
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
class Domain(enum.StrEnum):
|
|
@@ -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,
|
|
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 =
|
|
65
|
+
request = TadoXRequest()
|
|
68
66
|
request.command = "roomsAndDevices"
|
|
69
67
|
|
|
70
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
"
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
"
|
|
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
|
-
|
|
270
|
-
|
|
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 =
|
|
332
|
+
request = TadoXRequest()
|
|
279
333
|
request.command = f"roomsAndDevices/devices/{device_id}"
|
|
280
334
|
request.action = Action.CHANGE
|
|
281
335
|
request.payload = {"temperatureOffset": offset}
|
|
@@ -65,15 +65,12 @@ class Tado:
|
|
|
65
65
|
# set to None until explicitly set
|
|
66
66
|
self._auto_geofencing_supported = None
|
|
67
67
|
|
|
68
|
-
def _create_request(self) -> TadoRequest:
|
|
69
|
-
return TadoRequest()
|
|
70
|
-
|
|
71
68
|
def get_me(self):
|
|
72
69
|
"""
|
|
73
70
|
Gets home information.
|
|
74
71
|
"""
|
|
75
72
|
|
|
76
|
-
request =
|
|
73
|
+
request = TadoRequest()
|
|
77
74
|
request.action = Action.GET
|
|
78
75
|
request.domain = Domain.ME
|
|
79
76
|
|
|
@@ -84,7 +81,7 @@ class Tado:
|
|
|
84
81
|
Gets device information.
|
|
85
82
|
"""
|
|
86
83
|
|
|
87
|
-
request =
|
|
84
|
+
request = TadoRequest()
|
|
88
85
|
request.command = "devices"
|
|
89
86
|
return self._http.request(request)
|
|
90
87
|
|
|
@@ -93,7 +90,7 @@ class Tado:
|
|
|
93
90
|
Gets zones information.
|
|
94
91
|
"""
|
|
95
92
|
|
|
96
|
-
request =
|
|
93
|
+
request = TadoRequest()
|
|
97
94
|
request.command = "zones"
|
|
98
95
|
|
|
99
96
|
return self._http.request(request)
|
|
@@ -110,7 +107,7 @@ class Tado:
|
|
|
110
107
|
Gets current states of all zones.
|
|
111
108
|
"""
|
|
112
109
|
|
|
113
|
-
request =
|
|
110
|
+
request = TadoRequest()
|
|
114
111
|
request.command = "zoneStates"
|
|
115
112
|
|
|
116
113
|
return self._http.request(request)
|
|
@@ -120,7 +117,7 @@ class Tado:
|
|
|
120
117
|
Gets current state of Zone.
|
|
121
118
|
"""
|
|
122
119
|
|
|
123
|
-
request =
|
|
120
|
+
request = TadoRequest()
|
|
124
121
|
request.command = f"zones/{zone}/state"
|
|
125
122
|
data = {
|
|
126
123
|
**self._http.request(request),
|
|
@@ -150,7 +147,7 @@ class Tado:
|
|
|
150
147
|
# indicates whether presence is current locked (manually set) to
|
|
151
148
|
# HOME or AWAY or not locked (automatically set based on geolocation)
|
|
152
149
|
|
|
153
|
-
request =
|
|
150
|
+
request = TadoRequest()
|
|
154
151
|
request.command = "state"
|
|
155
152
|
data = self._http.request(request)
|
|
156
153
|
|
|
@@ -186,7 +183,7 @@ class Tado:
|
|
|
186
183
|
Gets current capabilities of zone.
|
|
187
184
|
"""
|
|
188
185
|
|
|
189
|
-
request =
|
|
186
|
+
request = TadoRequest()
|
|
190
187
|
request.command = f"zones/{zone:d}/capabilities"
|
|
191
188
|
|
|
192
189
|
return self._http.request(request)
|
|
@@ -207,7 +204,7 @@ class Tado:
|
|
|
207
204
|
Get the Timetable type currently active
|
|
208
205
|
"""
|
|
209
206
|
|
|
210
|
-
request =
|
|
207
|
+
request = TadoRequest()
|
|
211
208
|
request.command = f"zones/{zone:d}/schedule/activeTimetable"
|
|
212
209
|
request.mode = Mode.PLAIN
|
|
213
210
|
data = self._http.request(request)
|
|
@@ -231,7 +228,7 @@ class Tado:
|
|
|
231
228
|
"Incorrect date format, should be YYYY-MM-DD"
|
|
232
229
|
) from err
|
|
233
230
|
|
|
234
|
-
request =
|
|
231
|
+
request = TadoRequest()
|
|
235
232
|
request.command = (
|
|
236
233
|
f"zones/{zone:d}/dayReport?date={day.strftime('%Y-%m-%d')}"
|
|
237
234
|
)
|
|
@@ -245,7 +242,7 @@ class Tado:
|
|
|
245
242
|
id = 3 : SEVEN_DAY (MONDAY, TUESDAY, WEDNESDAY ...)
|
|
246
243
|
"""
|
|
247
244
|
|
|
248
|
-
request =
|
|
245
|
+
request = TadoRequest()
|
|
249
246
|
request.command = f"zones/{zone:d}/schedule/activeTimetable"
|
|
250
247
|
request.action = Action.CHANGE
|
|
251
248
|
request.payload = {"id": timetable}
|
|
@@ -260,7 +257,7 @@ class Tado:
|
|
|
260
257
|
Get the JSON representation of the schedule for a zone.
|
|
261
258
|
Zone has 3 different schedules, one for each timetable (see setTimetable)
|
|
262
259
|
"""
|
|
263
|
-
request =
|
|
260
|
+
request = TadoRequest()
|
|
264
261
|
if day:
|
|
265
262
|
request.command = (
|
|
266
263
|
f"zones/{zone:d}/schedule/timetables/{timetable:d}/blocks/{day}"
|
|
@@ -278,7 +275,7 @@ class Tado:
|
|
|
278
275
|
Set the schedule for a zone, day is required
|
|
279
276
|
"""
|
|
280
277
|
|
|
281
|
-
request =
|
|
278
|
+
request = TadoRequest()
|
|
282
279
|
request.command = (
|
|
283
280
|
f"zones/{zone:d}/schedule/timetables/{timetable:d}/blocks/{day}"
|
|
284
281
|
)
|
|
@@ -293,7 +290,7 @@ class Tado:
|
|
|
293
290
|
Gets outside weather data
|
|
294
291
|
"""
|
|
295
292
|
|
|
296
|
-
request =
|
|
293
|
+
request = TadoRequest()
|
|
297
294
|
request.command = "weather"
|
|
298
295
|
|
|
299
296
|
return self._http.request(request)
|
|
@@ -303,7 +300,7 @@ class Tado:
|
|
|
303
300
|
Gets air quality information
|
|
304
301
|
"""
|
|
305
302
|
|
|
306
|
-
request =
|
|
303
|
+
request = TadoRequest()
|
|
307
304
|
request.command = "airComfort"
|
|
308
305
|
|
|
309
306
|
return self._http.request(request)
|
|
@@ -313,7 +310,7 @@ class Tado:
|
|
|
313
310
|
Gets active users in home
|
|
314
311
|
"""
|
|
315
312
|
|
|
316
|
-
request =
|
|
313
|
+
request = TadoRequest()
|
|
317
314
|
request.command = "users"
|
|
318
315
|
|
|
319
316
|
return self._http.request(request)
|
|
@@ -323,7 +320,7 @@ class Tado:
|
|
|
323
320
|
Gets information about mobile devices
|
|
324
321
|
"""
|
|
325
322
|
|
|
326
|
-
request =
|
|
323
|
+
request = TadoRequest()
|
|
327
324
|
request.command = "mobileDevices"
|
|
328
325
|
|
|
329
326
|
return self._http.request(request)
|
|
@@ -333,7 +330,7 @@ class Tado:
|
|
|
333
330
|
Delete current overlay
|
|
334
331
|
"""
|
|
335
332
|
|
|
336
|
-
request =
|
|
333
|
+
request = TadoRequest()
|
|
337
334
|
request.command = f"zones/{zone:d}/overlay"
|
|
338
335
|
request.action = Action.RESET
|
|
339
336
|
request.mode = Mode.PLAIN
|
|
@@ -384,7 +381,7 @@ class Tado:
|
|
|
384
381
|
if duration is not None:
|
|
385
382
|
post_data["termination"]["durationInSeconds"] = duration
|
|
386
383
|
|
|
387
|
-
request =
|
|
384
|
+
request = TadoRequest()
|
|
388
385
|
request.command = f"zones/{zone:d}/overlay"
|
|
389
386
|
request.action = Action.CHANGE
|
|
390
387
|
request.payload = post_data
|
|
@@ -396,7 +393,7 @@ class Tado:
|
|
|
396
393
|
Get current overlay default settings for zone.
|
|
397
394
|
"""
|
|
398
395
|
|
|
399
|
-
request =
|
|
396
|
+
request = TadoRequest()
|
|
400
397
|
request.command = f"zones/{zone:d}/defaultOverlay"
|
|
401
398
|
|
|
402
399
|
return self._http.request(request)
|
|
@@ -420,7 +417,7 @@ class Tado:
|
|
|
420
417
|
Sets HomeState to presence
|
|
421
418
|
"""
|
|
422
419
|
|
|
423
|
-
request =
|
|
420
|
+
request = TadoRequest()
|
|
424
421
|
request.command = "presenceLock"
|
|
425
422
|
request.action = Action.CHANGE
|
|
426
423
|
request.payload = {"homePresence": presence}
|
|
@@ -434,7 +431,7 @@ class Tado:
|
|
|
434
431
|
|
|
435
432
|
# Only attempt to set Auto Geofencing if it is believed to be supported
|
|
436
433
|
if self._auto_geofencing_supported:
|
|
437
|
-
request =
|
|
434
|
+
request = TadoRequest()
|
|
438
435
|
request.command = "presenceLock"
|
|
439
436
|
request.action = Action.RESET
|
|
440
437
|
|
|
@@ -469,7 +466,7 @@ class Tado:
|
|
|
469
466
|
Note: This can only be set if an open window was detected in this zone
|
|
470
467
|
"""
|
|
471
468
|
|
|
472
|
-
request =
|
|
469
|
+
request = TadoRequest()
|
|
473
470
|
request.command = f"zones/{zone:d}/state/openWindow/activate"
|
|
474
471
|
request.action = Action.SET
|
|
475
472
|
request.mode = Mode.PLAIN
|
|
@@ -481,7 +478,7 @@ class Tado:
|
|
|
481
478
|
Sets the window in zone to closed
|
|
482
479
|
"""
|
|
483
480
|
|
|
484
|
-
request =
|
|
481
|
+
request = TadoRequest()
|
|
485
482
|
request.command = f"zones/{zone:d}/state/openWindow"
|
|
486
483
|
request.action = Action.RESET
|
|
487
484
|
request.mode = Mode.PLAIN
|
|
@@ -494,7 +491,7 @@ class Tado:
|
|
|
494
491
|
with option to get specific info i.e. cmd='temperatureOffset'
|
|
495
492
|
"""
|
|
496
493
|
|
|
497
|
-
request =
|
|
494
|
+
request = TadoRequest()
|
|
498
495
|
request.command = cmd
|
|
499
496
|
request.action = Action.GET
|
|
500
497
|
request.domain = Domain.DEVICES
|
|
@@ -507,7 +504,7 @@ class Tado:
|
|
|
507
504
|
Set the Temperature offset on the device.
|
|
508
505
|
"""
|
|
509
506
|
|
|
510
|
-
request =
|
|
507
|
+
request = TadoRequest()
|
|
511
508
|
request.command = "temperatureOffset"
|
|
512
509
|
request.action = Action.CHANGE
|
|
513
510
|
request.domain = Domain.DEVICES
|
|
@@ -521,7 +518,7 @@ class Tado:
|
|
|
521
518
|
Get Energy IQ tariff history
|
|
522
519
|
"""
|
|
523
520
|
|
|
524
|
-
request =
|
|
521
|
+
request = TadoRequest()
|
|
525
522
|
request.command = "tariffs"
|
|
526
523
|
request.action = Action.GET
|
|
527
524
|
request.endpoint = Endpoint.EIQ
|
|
@@ -533,7 +530,7 @@ class Tado:
|
|
|
533
530
|
Get Energy IQ meter readings
|
|
534
531
|
"""
|
|
535
532
|
|
|
536
|
-
request =
|
|
533
|
+
request = TadoRequest()
|
|
537
534
|
request.command = "meterReadings"
|
|
538
535
|
request.action = Action.GET
|
|
539
536
|
request.endpoint = Endpoint.EIQ
|
|
@@ -547,7 +544,7 @@ class Tado:
|
|
|
547
544
|
Send Meter Readings to Tado, date format is YYYY-MM-DD, reading is without decimals
|
|
548
545
|
"""
|
|
549
546
|
|
|
550
|
-
request =
|
|
547
|
+
request = TadoRequest()
|
|
551
548
|
request.command = "meterReadings"
|
|
552
549
|
request.action = Action.SET
|
|
553
550
|
request.endpoint = Endpoint.EIQ
|
|
@@ -585,7 +582,7 @@ class Tado:
|
|
|
585
582
|
"startDate": from_date,
|
|
586
583
|
}
|
|
587
584
|
|
|
588
|
-
request =
|
|
585
|
+
request = TadoRequest()
|
|
589
586
|
request.command = "tariffs"
|
|
590
587
|
request.action = Action.SET
|
|
591
588
|
request.endpoint = Endpoint.EIQ
|
|
@@ -598,7 +595,7 @@ class Tado:
|
|
|
598
595
|
Gets available heating circuits
|
|
599
596
|
"""
|
|
600
597
|
|
|
601
|
-
request =
|
|
598
|
+
request = TadoRequest()
|
|
602
599
|
request.command = "heatingCircuits"
|
|
603
600
|
|
|
604
601
|
return self._http.request(request)
|
|
@@ -608,7 +605,7 @@ class Tado:
|
|
|
608
605
|
Get zone control information
|
|
609
606
|
"""
|
|
610
607
|
|
|
611
|
-
request =
|
|
608
|
+
request = TadoRequest()
|
|
612
609
|
request.command = f"zones/{zone:d}/control"
|
|
613
610
|
|
|
614
611
|
return self._http.request(request)
|
|
@@ -618,7 +615,7 @@ class Tado:
|
|
|
618
615
|
Sets the heating circuit for a zone
|
|
619
616
|
"""
|
|
620
617
|
|
|
621
|
-
request =
|
|
618
|
+
request = TadoRequest()
|
|
622
619
|
request.command = f"zones/{zone:d}/control/heatingCircuit"
|
|
623
620
|
request.action = Action.CHANGE
|
|
624
621
|
request.payload = {"circuitNumber": heating_circuit}
|
|
@@ -7,14 +7,16 @@ import logging
|
|
|
7
7
|
from typing import Any, Self
|
|
8
8
|
|
|
9
9
|
from PyTado.const import (
|
|
10
|
-
CONST_HORIZONTAL_SWING_OFF,
|
|
11
10
|
CONST_HVAC_HEAT,
|
|
12
11
|
CONST_HVAC_IDLE,
|
|
13
12
|
CONST_HVAC_OFF,
|
|
14
|
-
|
|
13
|
+
CONST_CONNECTION_OFFLINE,
|
|
15
14
|
CONST_MODE_HEAT,
|
|
16
15
|
CONST_MODE_OFF,
|
|
16
|
+
CONST_MODE_SMART_SCHEDULE,
|
|
17
17
|
CONST_VERTICAL_SWING_OFF,
|
|
18
|
+
CONST_HORIZONTAL_SWING_OFF,
|
|
19
|
+
DEFAULT_TADOX_PRECISION,
|
|
18
20
|
)
|
|
19
21
|
from .my_zone import TadoZone
|
|
20
22
|
|
|
@@ -26,6 +28,8 @@ _LOGGER = logging.getLogger(__name__)
|
|
|
26
28
|
class TadoXZone(TadoZone):
|
|
27
29
|
"""Tado Zone data structure for hops.tado.com (Tado X) API."""
|
|
28
30
|
|
|
31
|
+
precision: float = DEFAULT_TADOX_PRECISION
|
|
32
|
+
|
|
29
33
|
@classmethod
|
|
30
34
|
def from_data(cls, zone_id: int, data: dict[str, Any]) -> Self:
|
|
31
35
|
"""Handle update callbacks for X zones with specific parsing."""
|
|
@@ -37,9 +41,9 @@ class TadoXZone(TadoZone):
|
|
|
37
41
|
sensor_data = data["sensorDataPoints"]
|
|
38
42
|
|
|
39
43
|
if "insideTemperature" in sensor_data:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
inside_temp = sensor_data["insideTemperature"]
|
|
45
|
+
if "value" in inside_temp:
|
|
46
|
+
kwargs["current_temp"] = float(inside_temp["value"])
|
|
43
47
|
kwargs["current_temp_timestamp"] = None
|
|
44
48
|
if "precision" in sensor_data["insideTemperature"]:
|
|
45
49
|
kwargs["precision"] = sensor_data["insideTemperature"][
|
|
@@ -123,20 +127,23 @@ class TadoXZone(TadoZone):
|
|
|
123
127
|
manual_termination["projectedExpiry"]
|
|
124
128
|
)
|
|
125
129
|
else:
|
|
130
|
+
kwargs["current_hvac_mode"] = CONST_MODE_SMART_SCHEDULE
|
|
126
131
|
kwargs["overlay_termination_type"] = None
|
|
127
132
|
kwargs["overlay_termination_timestamp"] = None
|
|
133
|
+
else:
|
|
134
|
+
kwargs["current_hvac_mode"] = CONST_MODE_SMART_SCHEDULE
|
|
128
135
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
136
|
+
kwargs["available"] = (
|
|
137
|
+
kwargs.get("connection") != CONST_CONNECTION_OFFLINE
|
|
138
|
+
)
|
|
132
139
|
|
|
133
140
|
# Termination conditions
|
|
134
141
|
if "terminationCondition" in data:
|
|
135
142
|
kwargs["default_overlay_termination_type"] = data[
|
|
136
143
|
"terminationCondition"
|
|
137
|
-
].get("type")
|
|
144
|
+
].get("type", None)
|
|
138
145
|
kwargs["default_overlay_termination_duration"] = data[
|
|
139
146
|
"terminationCondition"
|
|
140
|
-
].get("durationInSeconds")
|
|
147
|
+
].get("durationInSeconds", None)
|
|
141
148
|
|
|
142
149
|
return cls(zone_id=zone_id, **kwargs)
|
|
@@ -60,13 +60,13 @@ class TadoZone:
|
|
|
60
60
|
tado_mode: str | None = None
|
|
61
61
|
overlay_termination_type: str | None = None
|
|
62
62
|
overlay_termination_timestamp: str | None = None
|
|
63
|
+
default_overlay_termination_type: str | None = None
|
|
64
|
+
default_overlay_termination_duration: str | None = None
|
|
63
65
|
preparation: bool = False
|
|
64
66
|
open_window: bool = False
|
|
65
67
|
open_window_detected: bool = False
|
|
66
68
|
open_window_attr: dict[str, Any] = dataclasses.field(default_factory=dict)
|
|
67
69
|
precision: float = DEFAULT_TADO_PRECISION
|
|
68
|
-
default_overlay_termination_type = None
|
|
69
|
-
default_overlay_termination_duration = None
|
|
70
70
|
|
|
71
71
|
@property
|
|
72
72
|
def overlay_active(self) -> bool:
|
|
@@ -82,8 +82,9 @@ class TadoZone:
|
|
|
82
82
|
sensor_data = data["sensorDataPoints"]
|
|
83
83
|
|
|
84
84
|
if "insideTemperature" in sensor_data:
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
kwargs["current_temp"] = float(
|
|
86
|
+
sensor_data["insideTemperature"]["celsius"]
|
|
87
|
+
)
|
|
87
88
|
kwargs["current_temp_timestamp"] = sensor_data[
|
|
88
89
|
"insideTemperature"
|
|
89
90
|
]["timestamp"]
|
|
@@ -115,21 +116,23 @@ class TadoZone:
|
|
|
115
116
|
"temperature" in data["setting"]
|
|
116
117
|
and data["setting"]["temperature"] is not None
|
|
117
118
|
):
|
|
118
|
-
|
|
119
|
+
kwargs["target_temp"] = float(
|
|
119
120
|
data["setting"]["temperature"]["celsius"]
|
|
120
121
|
)
|
|
121
|
-
kwargs["target_temp"] = target_temperature
|
|
122
122
|
|
|
123
123
|
setting = data["setting"]
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
kwargs
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
125
|
+
# Reset modes and settings
|
|
126
|
+
kwargs.update(
|
|
127
|
+
{
|
|
128
|
+
"current_fan_speed": None,
|
|
129
|
+
"current_fan_level": None,
|
|
130
|
+
"current_hvac_mode": CONST_MODE_OFF,
|
|
131
|
+
"current_swing_mode": CONST_MODE_OFF,
|
|
132
|
+
"current_vertical_swing_mode": CONST_VERTICAL_SWING_OFF,
|
|
133
|
+
"current_horizontal_swing_mode": CONST_HORIZONTAL_SWING_OFF,
|
|
134
|
+
}
|
|
135
|
+
)
|
|
133
136
|
|
|
134
137
|
if "mode" in setting:
|
|
135
138
|
# v3 devices use mode
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-tado"
|
|
7
|
-
version = "0.18.
|
|
7
|
+
version = "0.18.4"
|
|
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.1
|
|
2
2
|
Name: python-tado
|
|
3
|
-
Version: 0.18.
|
|
3
|
+
Version: 0.18.4
|
|
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
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""Test the TadoZone object."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import unittest
|
|
5
|
+
from unittest import mock
|
|
6
|
+
|
|
7
|
+
from . import common
|
|
8
|
+
|
|
9
|
+
from PyTado.http import Http
|
|
10
|
+
from PyTado.interface.api import TadoX
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TadoZoneTestCase(unittest.TestCase):
|
|
14
|
+
"""Test cases for zone class"""
|
|
15
|
+
|
|
16
|
+
def setUp(self) -> None:
|
|
17
|
+
super().setUp()
|
|
18
|
+
login_patch = mock.patch(
|
|
19
|
+
"PyTado.http.Http._login", return_value=(1, "foo")
|
|
20
|
+
)
|
|
21
|
+
is_x_line_patch = mock.patch(
|
|
22
|
+
"PyTado.http.Http._check_x_line_generation", return_value=True
|
|
23
|
+
)
|
|
24
|
+
get_me_patch = mock.patch("PyTado.interface.api.Tado.get_me")
|
|
25
|
+
login_patch.start()
|
|
26
|
+
is_x_line_patch.start()
|
|
27
|
+
get_me_patch.start()
|
|
28
|
+
self.addCleanup(login_patch.stop)
|
|
29
|
+
self.addCleanup(is_x_line_patch.stop)
|
|
30
|
+
self.addCleanup(get_me_patch.stop)
|
|
31
|
+
|
|
32
|
+
self.http = Http("my@username.com", "mypassword")
|
|
33
|
+
self.tado_client = TadoX(self.http)
|
|
34
|
+
|
|
35
|
+
def set_fixture(self, filename: str) -> None:
|
|
36
|
+
def check_get_state(zone_id):
|
|
37
|
+
assert zone_id == 1
|
|
38
|
+
return json.loads(common.load_fixture(filename))
|
|
39
|
+
|
|
40
|
+
get_state_patch = mock.patch(
|
|
41
|
+
"PyTado.interface.api.TadoX.get_state",
|
|
42
|
+
side_effect=check_get_state,
|
|
43
|
+
)
|
|
44
|
+
get_state_patch.start()
|
|
45
|
+
self.addCleanup(get_state_patch.stop)
|
|
46
|
+
|
|
47
|
+
def test_tadox_heating_auto_mode(self):
|
|
48
|
+
"""Test general homes response."""
|
|
49
|
+
|
|
50
|
+
self.set_fixture("home_1234/tadox.heating.auto_mode.json")
|
|
51
|
+
mode = self.tado_client.get_zone_state(1)
|
|
52
|
+
|
|
53
|
+
assert mode.ac_power is None
|
|
54
|
+
assert mode.ac_power_timestamp is None
|
|
55
|
+
assert mode.available is True
|
|
56
|
+
assert mode.connection == "CONNECTED"
|
|
57
|
+
assert mode.current_fan_speed is None
|
|
58
|
+
assert mode.current_humidity == 38.00
|
|
59
|
+
assert mode.current_humidity_timestamp is None
|
|
60
|
+
assert mode.current_hvac_action == "HEATING"
|
|
61
|
+
assert mode.current_hvac_mode == "SMART_SCHEDULE"
|
|
62
|
+
assert mode.current_swing_mode == "OFF"
|
|
63
|
+
assert mode.current_temp == 24.00
|
|
64
|
+
assert mode.current_temp_timestamp is None
|
|
65
|
+
assert mode.heating_power is None
|
|
66
|
+
assert mode.heating_power_percentage == 100.0
|
|
67
|
+
assert mode.heating_power_timestamp is None
|
|
68
|
+
assert mode.is_away is None
|
|
69
|
+
assert mode.link is None
|
|
70
|
+
assert mode.open_window is False
|
|
71
|
+
assert not mode.open_window_attr
|
|
72
|
+
assert mode.overlay_active is False
|
|
73
|
+
assert mode.overlay_termination_type is None
|
|
74
|
+
assert mode.power == "ON"
|
|
75
|
+
assert mode.precision == 0.01
|
|
76
|
+
assert mode.preparation is False
|
|
77
|
+
assert mode.tado_mode is None
|
|
78
|
+
assert mode.target_temp == 22.0
|
|
79
|
+
assert mode.zone_id == 1
|
|
80
|
+
|
|
81
|
+
def test_tadox_heating_manual_mode(self):
|
|
82
|
+
"""Test general homes response."""
|
|
83
|
+
|
|
84
|
+
self.set_fixture("home_1234/tadox.heating.manual_mode.json")
|
|
85
|
+
mode = self.tado_client.get_zone_state(1)
|
|
86
|
+
|
|
87
|
+
assert mode.ac_power is None
|
|
88
|
+
assert mode.ac_power_timestamp is None
|
|
89
|
+
assert mode.available is True
|
|
90
|
+
assert mode.connection == "CONNECTED"
|
|
91
|
+
assert mode.current_fan_speed is None
|
|
92
|
+
assert mode.current_humidity == 38.00
|
|
93
|
+
assert mode.current_humidity_timestamp is None
|
|
94
|
+
assert mode.current_hvac_action == "HEATING"
|
|
95
|
+
assert mode.current_hvac_mode == "HEAT"
|
|
96
|
+
assert mode.current_swing_mode == "OFF"
|
|
97
|
+
assert mode.current_temp == 24.07
|
|
98
|
+
assert mode.current_temp_timestamp is None
|
|
99
|
+
assert mode.heating_power is None
|
|
100
|
+
assert mode.heating_power_percentage == 100.0
|
|
101
|
+
assert mode.heating_power_timestamp is None
|
|
102
|
+
assert mode.is_away is None
|
|
103
|
+
assert mode.link is None
|
|
104
|
+
assert mode.open_window is False
|
|
105
|
+
assert not mode.open_window_attr
|
|
106
|
+
assert mode.overlay_active is True
|
|
107
|
+
assert mode.overlay_termination_type == "NEXT_TIME_BLOCK"
|
|
108
|
+
assert mode.power == "ON"
|
|
109
|
+
assert mode.precision == 0.01
|
|
110
|
+
assert mode.preparation is False
|
|
111
|
+
assert mode.tado_mode is None
|
|
112
|
+
assert mode.target_temp == 25.5
|
|
113
|
+
assert mode.zone_id == 1
|
|
114
|
+
|
|
115
|
+
def test_tadox_heating_manual_off(self):
|
|
116
|
+
"""Test general homes response."""
|
|
117
|
+
|
|
118
|
+
self.set_fixture("home_1234/tadox.heating.manual_off.json")
|
|
119
|
+
mode = self.tado_client.get_zone_state(1)
|
|
120
|
+
|
|
121
|
+
assert mode.ac_power is None
|
|
122
|
+
assert mode.ac_power_timestamp is None
|
|
123
|
+
assert mode.available is True
|
|
124
|
+
assert mode.connection == "CONNECTED"
|
|
125
|
+
assert mode.current_fan_speed is None
|
|
126
|
+
assert mode.current_humidity == 38.00
|
|
127
|
+
assert mode.current_humidity_timestamp is None
|
|
128
|
+
assert mode.current_hvac_action == "OFF"
|
|
129
|
+
assert mode.current_hvac_mode == "OFF"
|
|
130
|
+
assert mode.current_swing_mode == "OFF"
|
|
131
|
+
assert mode.current_temp == 24.08
|
|
132
|
+
assert mode.current_temp_timestamp is None
|
|
133
|
+
assert mode.heating_power is None
|
|
134
|
+
assert mode.heating_power_percentage == 0.0
|
|
135
|
+
assert mode.heating_power_timestamp is None
|
|
136
|
+
assert mode.is_away is None
|
|
137
|
+
assert mode.link is None
|
|
138
|
+
assert mode.open_window is False
|
|
139
|
+
assert not mode.open_window_attr
|
|
140
|
+
assert mode.overlay_active is True
|
|
141
|
+
assert mode.overlay_termination_type == "NEXT_TIME_BLOCK"
|
|
142
|
+
assert mode.power == "OFF"
|
|
143
|
+
assert mode.precision == 0.01
|
|
144
|
+
assert mode.preparation is False
|
|
145
|
+
assert mode.tado_mode is None
|
|
146
|
+
assert mode.target_temp is None
|
|
147
|
+
assert mode.zone_id == 1
|
|
@@ -25,7 +25,7 @@ class TestHttp(unittest.TestCase):
|
|
|
25
25
|
"https://auth.tado.com/oauth/token",
|
|
26
26
|
json={
|
|
27
27
|
"access_token": "value",
|
|
28
|
-
"expires_in":
|
|
28
|
+
"expires_in": 1000,
|
|
29
29
|
"refresh_token": "another_value",
|
|
30
30
|
},
|
|
31
31
|
status=200,
|
|
@@ -33,16 +33,19 @@ class TestHttp(unittest.TestCase):
|
|
|
33
33
|
|
|
34
34
|
responses.add(
|
|
35
35
|
responses.GET,
|
|
36
|
-
"https://my.tado.com/api/v2/
|
|
37
|
-
json=
|
|
36
|
+
"https://my.tado.com/api/v2/me",
|
|
37
|
+
json=json.loads(common.load_fixture("home_1234/my_api_v2_me.json")),
|
|
38
38
|
status=200,
|
|
39
39
|
)
|
|
40
40
|
|
|
41
|
-
# Mock the get me response
|
|
42
41
|
responses.add(
|
|
43
42
|
responses.GET,
|
|
44
|
-
"https://my.tado.com/api/v2/
|
|
45
|
-
json=
|
|
43
|
+
"https://my.tado.com/api/v2/homes/1234/",
|
|
44
|
+
json=json.loads(
|
|
45
|
+
common.load_fixture(
|
|
46
|
+
"home_1234/tadov2.my_api_v2_home_state.json"
|
|
47
|
+
)
|
|
48
|
+
),
|
|
46
49
|
status=200,
|
|
47
50
|
)
|
|
48
51
|
|
|
@@ -102,7 +105,9 @@ class TestHttp(unittest.TestCase):
|
|
|
102
105
|
responses.replace(
|
|
103
106
|
responses.GET,
|
|
104
107
|
"https://my.tado.com/api/v2/homes/1234/",
|
|
105
|
-
json=json.loads(
|
|
108
|
+
json=json.loads(
|
|
109
|
+
common.load_fixture("home_1234/tadox.my_api_v2_home_state.json")
|
|
110
|
+
),
|
|
106
111
|
status=200,
|
|
107
112
|
)
|
|
108
113
|
|
|
@@ -67,6 +67,38 @@ class TadoZoneTestCase(unittest.TestCase):
|
|
|
67
67
|
assert mode.precision == 0.1
|
|
68
68
|
assert mode.current_swing_mode == "OFF"
|
|
69
69
|
|
|
70
|
+
def test_my_api_issue_88(self):
|
|
71
|
+
"""Test smart ac cool mode."""
|
|
72
|
+
self.set_fixture("my_api_issue_88.termination_condition.json")
|
|
73
|
+
mode = self.tado_client.get_zone_state(1)
|
|
74
|
+
|
|
75
|
+
assert mode.ac_power is None
|
|
76
|
+
assert mode.ac_power_timestamp is None
|
|
77
|
+
assert mode.available is True
|
|
78
|
+
assert mode.connection is None
|
|
79
|
+
assert mode.current_fan_speed is None
|
|
80
|
+
assert mode.current_humidity == 64.40
|
|
81
|
+
assert mode.current_humidity_timestamp == "2024-12-19T14:14:52.404Z"
|
|
82
|
+
assert mode.current_hvac_action == "HEATING"
|
|
83
|
+
assert mode.current_hvac_mode == "HEAT"
|
|
84
|
+
assert mode.current_swing_mode == "OFF"
|
|
85
|
+
assert mode.current_temp == 16.2
|
|
86
|
+
assert mode.current_temp_timestamp == "2024-12-19T14:14:52.404Z"
|
|
87
|
+
assert mode.heating_power is None
|
|
88
|
+
assert mode.heating_power_percentage == 100.0
|
|
89
|
+
assert mode.heating_power_timestamp == "2024-12-19T14:14:15.558Z"
|
|
90
|
+
assert mode.is_away is False
|
|
91
|
+
assert mode.link == "ONLINE"
|
|
92
|
+
assert mode.open_window is False
|
|
93
|
+
assert not mode.open_window_attr
|
|
94
|
+
assert mode.overlay_active
|
|
95
|
+
assert mode.overlay_termination_type == "TIMER"
|
|
96
|
+
assert mode.power == "ON"
|
|
97
|
+
assert mode.precision == 0.1
|
|
98
|
+
assert mode.preparation is False
|
|
99
|
+
assert mode.tado_mode == "HOME"
|
|
100
|
+
assert mode.target_temp == 22.0
|
|
101
|
+
|
|
70
102
|
def test_smartac3_smart_mode(self):
|
|
71
103
|
"""Test smart ac smart mode."""
|
|
72
104
|
self.set_fixture("smartac3.smart_mode.json")
|
|
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
|
|
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
|
|
File without changes
|