volkswagencarnet 5.0.0b2__py3-none-any.whl → 5.0.0b4__py3-none-any.whl
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.
Potentially problematic release.
This version of volkswagencarnet might be problematic. Click here for more details.
- volkswagencarnet/version.py +1 -1
- volkswagencarnet/vw_connection.py +398 -489
- volkswagencarnet/vw_const.py +1 -1
- volkswagencarnet/vw_dashboard.py +139 -450
- volkswagencarnet/vw_exceptions.py +7 -0
- volkswagencarnet/vw_utilities.py +40 -24
- volkswagencarnet/vw_vehicle.py +678 -1646
- {volkswagencarnet-5.0.0b2.dist-info → volkswagencarnet-5.0.0b4.dist-info}/METADATA +5 -5
- volkswagencarnet-5.0.0b4.dist-info/RECORD +13 -0
- volkswagencarnet-5.0.0b2.dist-info/RECORD +0 -12
- {volkswagencarnet-5.0.0b2.dist-info → volkswagencarnet-5.0.0b4.dist-info}/LICENSE.txt +0 -0
- {volkswagencarnet-5.0.0b2.dist-info → volkswagencarnet-5.0.0b4.dist-info}/WHEEL +0 -0
- {volkswagencarnet-5.0.0b2.dist-info → volkswagencarnet-5.0.0b4.dist-info}/top_level.txt +0 -0
volkswagencarnet/vw_vehicle.py
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Vehicle class for
|
|
3
|
-
|
|
2
|
+
"""Vehicle class for We Connect."""
|
|
4
3
|
from __future__ import annotations
|
|
5
4
|
|
|
6
5
|
import asyncio
|
|
6
|
+
import logging
|
|
7
7
|
from collections import OrderedDict
|
|
8
|
-
from datetime import
|
|
8
|
+
from datetime import datetime, timedelta, timezone
|
|
9
9
|
from json import dumps as to_json
|
|
10
|
-
import logging
|
|
11
10
|
|
|
12
|
-
from .vw_const import
|
|
11
|
+
from .vw_const import VehicleStatusParameter as P, Services
|
|
13
12
|
from .vw_utilities import find_path, is_valid_path
|
|
14
13
|
|
|
15
14
|
# TODO
|
|
@@ -25,21 +24,15 @@ _LOGGER = logging.getLogger(__name__)
|
|
|
25
24
|
ENGINE_TYPE_ELECTRIC = "electric"
|
|
26
25
|
ENGINE_TYPE_DIESEL = "diesel"
|
|
27
26
|
ENGINE_TYPE_GASOLINE = "gasoline"
|
|
28
|
-
ENGINE_TYPE_CNG = "cng"
|
|
29
27
|
ENGINE_TYPE_HYBRID = "hybrid"
|
|
30
|
-
ENGINE_TYPE_COMBUSTION = [
|
|
31
|
-
ENGINE_TYPE_DIESEL,
|
|
32
|
-
ENGINE_TYPE_GASOLINE,
|
|
33
|
-
ENGINE_TYPE_CNG,
|
|
34
|
-
]
|
|
35
|
-
ENGINE_TYPE_GAS = [ENGINE_TYPE_CNG]
|
|
28
|
+
ENGINE_TYPE_COMBUSTION = [ENGINE_TYPE_DIESEL, ENGINE_TYPE_GASOLINE]
|
|
36
29
|
DEFAULT_TARGET_TEMP = 24
|
|
37
30
|
|
|
38
31
|
|
|
39
32
|
class Vehicle:
|
|
40
33
|
"""Vehicle contains the state of sensors and methods for interacting with the car."""
|
|
41
34
|
|
|
42
|
-
def __init__(self, conn, url)
|
|
35
|
+
def __init__(self, conn, url):
|
|
43
36
|
"""Initialize the Vehicle with default values."""
|
|
44
37
|
self._connection = conn
|
|
45
38
|
self._url = url
|
|
@@ -47,17 +40,18 @@ class Vehicle:
|
|
|
47
40
|
self._discovered = False
|
|
48
41
|
self._states = {}
|
|
49
42
|
self._requests: dict[str, object] = {
|
|
50
|
-
"departuretimer": {"status": "", "timestamp": datetime.now(
|
|
51
|
-
"batterycharge": {"status": "", "timestamp": datetime.now(
|
|
52
|
-
"climatisation": {"status": "", "timestamp": datetime.now(
|
|
53
|
-
"refresh": {"status": "", "timestamp": datetime.now(
|
|
54
|
-
"lock": {"status": "", "timestamp": datetime.now(
|
|
43
|
+
"departuretimer": {"status": "", "timestamp": datetime.now(timezone.utc)},
|
|
44
|
+
"batterycharge": {"status": "", "timestamp": datetime.now(timezone.utc)},
|
|
45
|
+
"climatisation": {"status": "", "timestamp": datetime.now(timezone.utc)},
|
|
46
|
+
"refresh": {"status": "", "timestamp": datetime.now(timezone.utc)},
|
|
47
|
+
"lock": {"status": "", "timestamp": datetime.now(timezone.utc)},
|
|
55
48
|
"latest": "",
|
|
56
49
|
"state": "",
|
|
57
50
|
}
|
|
58
51
|
|
|
59
52
|
# API Endpoints that might be enabled for car (that we support)
|
|
60
53
|
self._services: dict[str, dict[str, object]] = {
|
|
54
|
+
# TODO needs a complete rework...
|
|
61
55
|
Services.ACCESS: {"active": False},
|
|
62
56
|
Services.BATTERY_CHARGING_CARE: {"active": False},
|
|
63
57
|
Services.BATTERY_SUPPORT: {"active": False},
|
|
@@ -79,50 +73,33 @@ class Vehicle:
|
|
|
79
73
|
"""Check if request is already in progress."""
|
|
80
74
|
if self._requests.get(topic, {}).get("id", False):
|
|
81
75
|
timestamp = self._requests.get(topic, {}).get(
|
|
82
|
-
"timestamp",
|
|
83
|
-
datetime.now(UTC) - timedelta(minutes=unknown_offset),
|
|
76
|
+
"timestamp", datetime.now(timezone.utc) - timedelta(minutes=unknown_offset)
|
|
84
77
|
)
|
|
85
|
-
if timestamp + timedelta(minutes=3) < datetime.now(
|
|
78
|
+
if timestamp + timedelta(minutes=3) < datetime.now(timezone.utc):
|
|
86
79
|
self._requests.get(topic, {}).pop("id")
|
|
87
80
|
else:
|
|
88
|
-
_LOGGER.info("Action (
|
|
81
|
+
_LOGGER.info(f"Action ({topic}) already in progress")
|
|
89
82
|
return True
|
|
90
83
|
return False
|
|
91
84
|
|
|
92
|
-
async def _handle_response(
|
|
93
|
-
self, response, topic: str, error_msg: str | None = None
|
|
94
|
-
) -> bool:
|
|
85
|
+
async def _handle_response(self, response, topic: str, error_msg: str | None = None) -> bool:
|
|
95
86
|
"""Handle errors in response and get requests remaining."""
|
|
96
87
|
if not response:
|
|
88
|
+
self._requests[topic] = {"status": "Failed", "timestamp": datetime.now(timezone.utc)}
|
|
89
|
+
_LOGGER.error(error_msg if error_msg is not None else f"Failed to perform {topic} action")
|
|
90
|
+
raise Exception(error_msg if error_msg is not None else f"Failed to perform {topic} action")
|
|
91
|
+
else:
|
|
97
92
|
self._requests[topic] = {
|
|
98
|
-
"
|
|
99
|
-
"
|
|
93
|
+
"timestamp": datetime.now(timezone.utc),
|
|
94
|
+
"status": response.get("state", "Unknown"),
|
|
95
|
+
"id": response.get("id", 0),
|
|
100
96
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
raise Exception(
|
|
108
|
-
error_msg
|
|
109
|
-
if error_msg is not None
|
|
110
|
-
else f"Failed to perform {topic} action"
|
|
111
|
-
)
|
|
112
|
-
self._requests[topic] = {
|
|
113
|
-
"timestamp": datetime.now(UTC),
|
|
114
|
-
"status": response.get("state", "Unknown"),
|
|
115
|
-
"id": response.get("id", 0),
|
|
116
|
-
}
|
|
117
|
-
if response.get("state", None) == "Throttled":
|
|
118
|
-
status = "Throttled"
|
|
119
|
-
_LOGGER.warning("Request throttled (%s)", topic)
|
|
120
|
-
else:
|
|
121
|
-
status = await self.wait_for_request(request=response.get("id", 0))
|
|
122
|
-
self._requests[topic] = {
|
|
123
|
-
"status": status,
|
|
124
|
-
"timestamp": datetime.now(UTC),
|
|
125
|
-
}
|
|
97
|
+
if response.get("state", None) == "Throttled":
|
|
98
|
+
status = "Throttled"
|
|
99
|
+
_LOGGER.warning(f"Request throttled ({topic}")
|
|
100
|
+
else:
|
|
101
|
+
status = await self.wait_for_request(request=response.get("id", 0))
|
|
102
|
+
self._requests[topic] = {"status": status, "timestamp": datetime.now(timezone.utc)}
|
|
126
103
|
return True
|
|
127
104
|
|
|
128
105
|
# API get and set functions #
|
|
@@ -130,64 +107,43 @@ class Vehicle:
|
|
|
130
107
|
async def discover(self):
|
|
131
108
|
"""Discover vehicle and initial data."""
|
|
132
109
|
|
|
133
|
-
_LOGGER.debug("Attempting discovery of supported API endpoints for vehicle")
|
|
134
|
-
|
|
110
|
+
_LOGGER.debug("Attempting discovery of supported API endpoints for vehicle.")
|
|
135
111
|
capabilities_response = await self._connection.getOperationList(self.vin)
|
|
136
112
|
parameters_list = capabilities_response.get("parameters", {})
|
|
137
113
|
capabilities_list = capabilities_response.get("capabilities", {})
|
|
138
|
-
|
|
139
|
-
# Update services with parameters
|
|
140
114
|
if parameters_list:
|
|
141
115
|
self._services[Services.PARAMETERS].update(parameters_list)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
reason = service.get("status", "Unknown reason")
|
|
174
|
-
_LOGGER.debug(
|
|
175
|
-
"Service: %s is disabled due to: %s", service_name, reason
|
|
176
|
-
)
|
|
177
|
-
data["active"] = False
|
|
178
|
-
|
|
179
|
-
# Update the service data
|
|
180
|
-
try:
|
|
181
|
-
self._services[service_name].update(data)
|
|
182
|
-
except Exception as error: # pylint: disable=broad-exception-caught
|
|
183
|
-
_LOGGER.warning(
|
|
184
|
-
'Exception "%s" while updating service "%s": %s',
|
|
185
|
-
error,
|
|
186
|
-
service_name,
|
|
187
|
-
data,
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
_LOGGER.debug("API endpoints: %s", self._services)
|
|
116
|
+
if capabilities_list:
|
|
117
|
+
for service_id in capabilities_list.keys():
|
|
118
|
+
try:
|
|
119
|
+
if service_id in self._services.keys():
|
|
120
|
+
service = capabilities_list[service_id]
|
|
121
|
+
data = {}
|
|
122
|
+
service_name = service.get("id", None)
|
|
123
|
+
if service.get("isEnabled", False):
|
|
124
|
+
_LOGGER.debug(f"Discovered enabled service: {service_name}")
|
|
125
|
+
data["active"] = True
|
|
126
|
+
if service.get("expirationDate", False):
|
|
127
|
+
data["expiration"] = service.get("expirationDate", None)
|
|
128
|
+
if service.get("operations", False):
|
|
129
|
+
data.update({"operations": []})
|
|
130
|
+
for operation_id in service.get("operations", []).keys():
|
|
131
|
+
operation = service.get("operations").get(operation_id)
|
|
132
|
+
data["operations"].append(operation.get("id", None))
|
|
133
|
+
if service.get("parameters", False):
|
|
134
|
+
data.update({"parameters": []})
|
|
135
|
+
for parameter in service.get("parameters", []):
|
|
136
|
+
data["parameters"].append(parameter)
|
|
137
|
+
else:
|
|
138
|
+
reason = service.get("status", "Unknown")
|
|
139
|
+
_LOGGER.debug(f"Service: {service_name} is disabled because of reason: {reason}")
|
|
140
|
+
data["active"] = False
|
|
141
|
+
self._services[service_name].update(data)
|
|
142
|
+
except Exception as error:
|
|
143
|
+
_LOGGER.warning(f'Encountered exception: "{error}" while parsing service item: {service}')
|
|
144
|
+
else:
|
|
145
|
+
_LOGGER.warning(f"Could not determine available API endpoints for {self.vin}")
|
|
146
|
+
_LOGGER.debug(f"API endpoints: {self._services}")
|
|
191
147
|
self._discovered = True
|
|
192
148
|
|
|
193
149
|
async def update(self):
|
|
@@ -219,7 +175,7 @@ class Vehicle:
|
|
|
219
175
|
)
|
|
220
176
|
await asyncio.gather(self.get_service_status())
|
|
221
177
|
else:
|
|
222
|
-
_LOGGER.info("Vehicle with VIN
|
|
178
|
+
_LOGGER.info(f"Vehicle with VIN {self.vin} is deactivated.")
|
|
223
179
|
|
|
224
180
|
# Data collection functions
|
|
225
181
|
async def get_selectivestatus(self, services):
|
|
@@ -258,28 +214,26 @@ class Vehicle:
|
|
|
258
214
|
"""Update status of outstanding requests."""
|
|
259
215
|
retry_count -= 1
|
|
260
216
|
if retry_count == 0:
|
|
261
|
-
_LOGGER.info("Timeout while waiting for result of
|
|
217
|
+
_LOGGER.info(f"Timeout while waiting for result of {request.requestId}.")
|
|
262
218
|
return "Timeout"
|
|
263
219
|
try:
|
|
264
220
|
status = await self._connection.get_request_status(self.vin, request)
|
|
265
|
-
_LOGGER.debug("Request ID
|
|
221
|
+
_LOGGER.debug(f"Request ID {request}: {status}")
|
|
266
222
|
self._requests["state"] = status
|
|
267
223
|
if status == "In Progress":
|
|
268
224
|
await asyncio.sleep(10)
|
|
269
225
|
return await self.wait_for_request(request, retry_count)
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
)
|
|
226
|
+
else:
|
|
227
|
+
return status
|
|
228
|
+
except Exception as error:
|
|
229
|
+
_LOGGER.warning(f"Exception encountered while waiting for request status: {error}")
|
|
274
230
|
return "Exception"
|
|
275
|
-
else:
|
|
276
|
-
return status
|
|
277
231
|
|
|
278
232
|
async def wait_for_data_refresh(self, retry_count=18):
|
|
279
233
|
"""Update status of outstanding requests."""
|
|
280
234
|
retry_count -= 1
|
|
281
235
|
if retry_count == 0:
|
|
282
|
-
_LOGGER.info("Timeout while waiting for data refresh")
|
|
236
|
+
_LOGGER.info("Timeout while waiting for data refresh.")
|
|
283
237
|
return "Timeout"
|
|
284
238
|
try:
|
|
285
239
|
await self.get_selectivestatus([Services.MEASUREMENTS])
|
|
@@ -287,14 +241,11 @@ class Vehicle:
|
|
|
287
241
|
if self.last_connected < refresh_trigger_time:
|
|
288
242
|
await asyncio.sleep(10)
|
|
289
243
|
return await self.wait_for_data_refresh(retry_count)
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
)
|
|
244
|
+
else:
|
|
245
|
+
return "successful"
|
|
246
|
+
except Exception as error:
|
|
247
|
+
_LOGGER.warning(f"Exception encountered while waiting for data refresh: {error}")
|
|
295
248
|
return "Exception"
|
|
296
|
-
else:
|
|
297
|
-
return "successful"
|
|
298
249
|
|
|
299
250
|
# Data set functions
|
|
300
251
|
# Charging (BATTERYCHARGE)
|
|
@@ -302,39 +253,29 @@ class Vehicle:
|
|
|
302
253
|
"""Set charger current."""
|
|
303
254
|
if self.is_charging_supported:
|
|
304
255
|
if 1 <= int(value) <= 255:
|
|
305
|
-
data = {
|
|
306
|
-
"action": {
|
|
307
|
-
"settings": {"maxChargeCurrent": int(value)},
|
|
308
|
-
"type": "setSettings",
|
|
309
|
-
}
|
|
310
|
-
}
|
|
256
|
+
data = {"action": {"settings": {"maxChargeCurrent": int(value)}, "type": "setSettings"}}
|
|
311
257
|
else:
|
|
312
|
-
_LOGGER.error(
|
|
313
|
-
|
|
314
|
-
)
|
|
315
|
-
# pylint: disable=broad-exception-raised
|
|
316
|
-
raise Exception(
|
|
317
|
-
f"Set charger maximum current to {value} is not supported."
|
|
318
|
-
)
|
|
258
|
+
_LOGGER.error(f"Set charger maximum current to {value} is not supported.")
|
|
259
|
+
raise Exception(f"Set charger maximum current to {value} is not supported.")
|
|
319
260
|
return await self.set_charger(data)
|
|
320
|
-
|
|
321
|
-
|
|
261
|
+
else:
|
|
262
|
+
_LOGGER.error("No charger support.")
|
|
263
|
+
raise Exception("No charger support.")
|
|
322
264
|
|
|
323
265
|
async def set_charger(self, action) -> bool:
|
|
324
266
|
"""Turn on/off charging."""
|
|
325
267
|
if self.is_charging_supported:
|
|
326
268
|
if action not in ["start", "stop"]:
|
|
327
|
-
_LOGGER.error('Charging action "
|
|
328
|
-
raise Exception(f'Charging action "{action}" is not supported.')
|
|
269
|
+
_LOGGER.error(f'Charging action "{action}" is not supported.')
|
|
270
|
+
raise Exception(f'Charging action "{action}" is not supported.')
|
|
329
271
|
self._requests["latest"] = "Batterycharge"
|
|
330
272
|
response = await self._connection.setCharging(self.vin, (action == "start"))
|
|
331
273
|
return await self._handle_response(
|
|
332
|
-
response=response,
|
|
333
|
-
topic="charging",
|
|
334
|
-
error_msg=f"Failed to {action} charging",
|
|
274
|
+
response=response, topic="charging", error_msg=f"Failed to {action} charging"
|
|
335
275
|
)
|
|
336
|
-
|
|
337
|
-
|
|
276
|
+
else:
|
|
277
|
+
_LOGGER.error("No charging support.")
|
|
278
|
+
raise Exception("No charging support.")
|
|
338
279
|
|
|
339
280
|
async def set_charging_settings(self, setting, value):
|
|
340
281
|
"""Set charging settings."""
|
|
@@ -344,73 +285,60 @@ class Vehicle:
|
|
|
344
285
|
or self.is_battery_target_charge_level_supported
|
|
345
286
|
):
|
|
346
287
|
if setting == "reduced_ac_charging" and value not in ["reduced", "maximum"]:
|
|
347
|
-
_LOGGER.error('Charging setting "
|
|
348
|
-
raise Exception(f'Charging setting "{value}" is not supported.')
|
|
288
|
+
_LOGGER.error(f'Charging setting "{value}" is not supported.')
|
|
289
|
+
raise Exception(f'Charging setting "{value}" is not supported.')
|
|
349
290
|
data = {}
|
|
350
291
|
if self.is_charge_max_ac_setting_supported:
|
|
351
|
-
data["maxChargeCurrentAC"] =
|
|
352
|
-
value
|
|
353
|
-
if setting == "reduced_ac_charging"
|
|
354
|
-
else self.charge_max_ac_setting
|
|
355
|
-
)
|
|
292
|
+
data["maxChargeCurrentAC"] = value if setting == "reduced_ac_charging" else self.charge_max_ac_setting
|
|
356
293
|
if self.is_auto_release_ac_connector_supported:
|
|
357
294
|
data["autoUnlockPlugWhenChargedAC"] = (
|
|
358
|
-
value
|
|
359
|
-
if setting == "auto_release_ac_connector"
|
|
360
|
-
else self.auto_release_ac_connector_state
|
|
295
|
+
value if setting == "auto_release_ac_connector" else self.auto_release_ac_connector_state
|
|
361
296
|
)
|
|
362
297
|
if self.is_battery_target_charge_level_supported:
|
|
363
|
-
self.
|
|
298
|
+
self._battery_target_charge_level = value
|
|
364
299
|
data["targetSOC_pct"] = (
|
|
365
|
-
value
|
|
366
|
-
if setting == "battery_target_charge_level"
|
|
367
|
-
else self.battery_target_charge_level
|
|
300
|
+
value if setting == "battery_target_charge_level" else self.battery_target_charge_level
|
|
368
301
|
)
|
|
369
302
|
self._requests["latest"] = "Batterycharge"
|
|
370
303
|
response = await self._connection.setChargingSettings(self.vin, data)
|
|
371
304
|
return await self._handle_response(
|
|
372
|
-
response=response,
|
|
373
|
-
topic="charging",
|
|
374
|
-
error_msg="Failed to change charging settings",
|
|
305
|
+
response=response, topic="charging", error_msg="Failed to change charging settings"
|
|
375
306
|
)
|
|
376
|
-
|
|
377
|
-
|
|
307
|
+
else:
|
|
308
|
+
_LOGGER.error("Charging settings are not supported.")
|
|
309
|
+
raise Exception("Charging settings are not supported.")
|
|
378
310
|
|
|
379
311
|
async def set_charging_care_settings(self, value):
|
|
380
312
|
"""Set charging care settings."""
|
|
381
313
|
if self.is_battery_care_mode_supported:
|
|
382
314
|
if value not in ["activated", "deactivated"]:
|
|
383
|
-
_LOGGER.error('Charging care mode "
|
|
384
|
-
raise Exception(f'Charging care mode "{value}" is not supported.')
|
|
315
|
+
_LOGGER.error(f'Charging care mode "{value}" is not supported.')
|
|
316
|
+
raise Exception(f'Charging care mode "{value}" is not supported.')
|
|
385
317
|
data = {"batteryCareMode": value}
|
|
386
318
|
self._requests["latest"] = "Batterycharge"
|
|
387
|
-
response = await self._connection.setChargingCareModeSettings(
|
|
388
|
-
self.vin, data
|
|
389
|
-
)
|
|
319
|
+
response = await self._connection.setChargingCareModeSettings(self.vin, data)
|
|
390
320
|
return await self._handle_response(
|
|
391
|
-
response=response,
|
|
392
|
-
topic="charging",
|
|
393
|
-
error_msg="Failed to change charging care settings",
|
|
321
|
+
response=response, topic="charging", error_msg="Failed to change charging care settings"
|
|
394
322
|
)
|
|
395
|
-
|
|
396
|
-
|
|
323
|
+
else:
|
|
324
|
+
_LOGGER.error("Charging care settings are not supported.")
|
|
325
|
+
raise Exception("Charging care settings are not supported.")
|
|
397
326
|
|
|
398
327
|
async def set_readiness_battery_support(self, value):
|
|
399
328
|
"""Set readiness battery support settings."""
|
|
400
329
|
if self.is_optimised_battery_use_supported:
|
|
401
330
|
if value not in [True, False]:
|
|
402
|
-
_LOGGER.error('Battery support mode "
|
|
403
|
-
raise Exception(f'Battery support mode "{value}" is not supported.')
|
|
331
|
+
_LOGGER.error(f'Battery support mode "{value}" is not supported.')
|
|
332
|
+
raise Exception(f'Battery support mode "{value}" is not supported.')
|
|
404
333
|
data = {"batterySupportEnabled": value}
|
|
405
334
|
self._requests["latest"] = "Batterycharge"
|
|
406
335
|
response = await self._connection.setReadinessBatterySupport(self.vin, data)
|
|
407
336
|
return await self._handle_response(
|
|
408
|
-
response=response,
|
|
409
|
-
topic="charging",
|
|
410
|
-
error_msg="Failed to change battery support settings",
|
|
337
|
+
response=response, topic="charging", error_msg="Failed to change battery support settings"
|
|
411
338
|
)
|
|
412
|
-
|
|
413
|
-
|
|
339
|
+
else:
|
|
340
|
+
_LOGGER.error("Battery support settings are not supported.")
|
|
341
|
+
raise Exception("Battery support settings are not supported.")
|
|
414
342
|
|
|
415
343
|
# Climatisation electric/auxiliary/windows (CLIMATISATION)
|
|
416
344
|
async def set_climatisation_settings(self, setting, value):
|
|
@@ -457,26 +385,16 @@ class Vehicle:
|
|
|
457
385
|
)
|
|
458
386
|
if self.is_auxiliary_air_conditioning_supported:
|
|
459
387
|
data["climatizationAtUnlock"] = (
|
|
460
|
-
value
|
|
461
|
-
if setting == "auxiliary_air_conditioning"
|
|
462
|
-
else self.auxiliary_air_conditioning
|
|
388
|
+
value if setting == "auxiliary_air_conditioning" else self.auxiliary_air_conditioning
|
|
463
389
|
)
|
|
464
390
|
if self.is_automatic_window_heating_supported:
|
|
465
391
|
data["windowHeatingEnabled"] = (
|
|
466
|
-
value
|
|
467
|
-
if setting == "automatic_window_heating"
|
|
468
|
-
else self.automatic_window_heating
|
|
392
|
+
value if setting == "automatic_window_heating" else self.automatic_window_heating
|
|
469
393
|
)
|
|
470
394
|
if self.is_zone_front_left_supported:
|
|
471
|
-
data["zoneFrontLeftEnabled"] =
|
|
472
|
-
value if setting == "zone_front_left" else self.zone_front_left
|
|
473
|
-
)
|
|
395
|
+
data["zoneFrontLeftEnabled"] = value if setting == "zone_front_left" else self.zone_front_left
|
|
474
396
|
if self.is_zone_front_right_supported:
|
|
475
|
-
data["zoneFrontRightEnabled"] =
|
|
476
|
-
value
|
|
477
|
-
if setting == "zone_front_right"
|
|
478
|
-
else self.zone_front_right
|
|
479
|
-
)
|
|
397
|
+
data["zoneFrontRightEnabled"] = value if setting == "zone_front_right" else self.zone_front_right
|
|
480
398
|
self._requests["latest"] = "Climatisation"
|
|
481
399
|
response = await self._connection.setClimaterSettings(self.vin, data)
|
|
482
400
|
return await self._handle_response(
|
|
@@ -484,28 +402,27 @@ class Vehicle:
|
|
|
484
402
|
topic="climatisation",
|
|
485
403
|
error_msg="Failed to set climatisation settings",
|
|
486
404
|
)
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
405
|
+
else:
|
|
406
|
+
_LOGGER.error(f'Set climatisation setting to "{value}" is not supported.')
|
|
407
|
+
raise Exception(f'Set climatisation setting to "{value}" is not supported.')
|
|
408
|
+
else:
|
|
409
|
+
_LOGGER.error("Climatisation settings are not supported.")
|
|
410
|
+
raise Exception("Climatisation settings are not supported.")
|
|
491
411
|
|
|
492
412
|
async def set_window_heating(self, action="stop"):
|
|
493
413
|
"""Turn on/off window heater."""
|
|
494
414
|
if self.is_window_heater_supported:
|
|
495
415
|
if action not in ["start", "stop"]:
|
|
496
|
-
_LOGGER.error('Window heater action "
|
|
497
|
-
raise Exception(f'Window heater action "{action}" is not supported.')
|
|
416
|
+
_LOGGER.error(f'Window heater action "{action}" is not supported.')
|
|
417
|
+
raise Exception(f'Window heater action "{action}" is not supported.')
|
|
498
418
|
self._requests["latest"] = "Climatisation"
|
|
499
|
-
response = await self._connection.setWindowHeater(
|
|
500
|
-
self.vin, (action == "start")
|
|
501
|
-
)
|
|
419
|
+
response = await self._connection.setWindowHeater(self.vin, (action == "start"))
|
|
502
420
|
return await self._handle_response(
|
|
503
|
-
response=response,
|
|
504
|
-
topic="climatisation",
|
|
505
|
-
error_msg=f"Failed to {action} window heating",
|
|
421
|
+
response=response, topic="climatisation", error_msg=f"Failed to {action} window heating"
|
|
506
422
|
)
|
|
507
|
-
|
|
508
|
-
|
|
423
|
+
else:
|
|
424
|
+
_LOGGER.error("No climatisation support.")
|
|
425
|
+
raise Exception("No climatisation support.")
|
|
509
426
|
|
|
510
427
|
async def set_climatisation(self, action="stop"):
|
|
511
428
|
"""Turn on/off climatisation with electric heater."""
|
|
@@ -516,9 +433,7 @@ class Vehicle:
|
|
|
516
433
|
"targetTemperatureUnit": "celsius",
|
|
517
434
|
}
|
|
518
435
|
if self.is_climatisation_without_external_power_supported:
|
|
519
|
-
data["climatisationWithoutExternalPower"] =
|
|
520
|
-
self.climatisation_without_external_power
|
|
521
|
-
)
|
|
436
|
+
data["climatisationWithoutExternalPower"] = self.climatisation_without_external_power
|
|
522
437
|
if self.is_auxiliary_air_conditioning_supported:
|
|
523
438
|
data["climatizationAtUnlock"] = self.auxiliary_air_conditioning
|
|
524
439
|
if self.is_automatic_window_heating_supported:
|
|
@@ -530,19 +445,18 @@ class Vehicle:
|
|
|
530
445
|
elif action == "stop":
|
|
531
446
|
data = {}
|
|
532
447
|
else:
|
|
533
|
-
_LOGGER.error("Invalid climatisation action:
|
|
534
|
-
raise Exception(f"Invalid climatisation action: {action}")
|
|
448
|
+
_LOGGER.error(f"Invalid climatisation action: {action}")
|
|
449
|
+
raise Exception(f"Invalid climatisation action: {action}")
|
|
535
450
|
self._requests["latest"] = "Climatisation"
|
|
536
|
-
response = await self._connection.setClimater(
|
|
537
|
-
self.vin, data, (action == "start")
|
|
538
|
-
)
|
|
451
|
+
response = await self._connection.setClimater(self.vin, data, (action == "start"))
|
|
539
452
|
return await self._handle_response(
|
|
540
453
|
response=response,
|
|
541
454
|
topic="climatisation",
|
|
542
455
|
error_msg=f"Failed to {action} climatisation with electric heater.",
|
|
543
456
|
)
|
|
544
|
-
|
|
545
|
-
|
|
457
|
+
else:
|
|
458
|
+
_LOGGER.error("No climatisation support.")
|
|
459
|
+
raise Exception("No climatisation support.")
|
|
546
460
|
|
|
547
461
|
async def set_auxiliary_climatisation(self, action, spin):
|
|
548
462
|
"""Turn on/off climatisation with auxiliary heater."""
|
|
@@ -554,102 +468,72 @@ class Vehicle:
|
|
|
554
468
|
elif action == "stop":
|
|
555
469
|
data = {}
|
|
556
470
|
else:
|
|
557
|
-
_LOGGER.error("Invalid auxiliary heater action:
|
|
558
|
-
raise Exception(f"Invalid auxiliary heater action: {action}")
|
|
471
|
+
_LOGGER.error(f"Invalid auxiliary heater action: {action}")
|
|
472
|
+
raise Exception(f"Invalid auxiliary heater action: {action}")
|
|
559
473
|
self._requests["latest"] = "Climatisation"
|
|
560
|
-
response = await self._connection.setAuxiliary(
|
|
561
|
-
self.vin, data, (action == "start")
|
|
562
|
-
)
|
|
474
|
+
response = await self._connection.setAuxiliary(self.vin, data, (action == "start"))
|
|
563
475
|
return await self._handle_response(
|
|
564
476
|
response=response,
|
|
565
477
|
topic="climatisation",
|
|
566
478
|
error_msg=f"Failed to {action} climatisation with auxiliary heater.",
|
|
567
479
|
)
|
|
568
|
-
|
|
569
|
-
|
|
480
|
+
else:
|
|
481
|
+
_LOGGER.error("No climatisation support.")
|
|
482
|
+
raise Exception("No climatisation support.")
|
|
570
483
|
|
|
571
484
|
async def set_departure_timer(self, timer_id, spin, enable) -> bool:
|
|
572
485
|
"""Turn on/off departure timer."""
|
|
573
486
|
if self.is_departure_timer_supported(timer_id):
|
|
574
|
-
if
|
|
575
|
-
_LOGGER.error("Charging departure timers setting is not supported")
|
|
576
|
-
raise Exception("Charging departure timers setting is not supported.")
|
|
487
|
+
if type(enable) is not bool:
|
|
488
|
+
_LOGGER.error("Charging departure timers setting is not supported.")
|
|
489
|
+
raise Exception("Charging departure timers setting is not supported.")
|
|
577
490
|
data = None
|
|
578
491
|
response = None
|
|
579
492
|
if is_valid_path(
|
|
580
|
-
self.attrs,
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
self.attrs,
|
|
584
|
-
f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.profiles",
|
|
585
|
-
):
|
|
586
|
-
timers = find_path(
|
|
587
|
-
self.attrs,
|
|
588
|
-
f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.timers",
|
|
589
|
-
)
|
|
493
|
+
self.attrs, f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.timers"
|
|
494
|
+
) and is_valid_path(self.attrs, f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.profiles"):
|
|
495
|
+
timers = find_path(self.attrs, f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.timers")
|
|
590
496
|
profiles = find_path(
|
|
591
|
-
self.attrs,
|
|
592
|
-
f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.profiles",
|
|
497
|
+
self.attrs, f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.profiles"
|
|
593
498
|
)
|
|
594
|
-
for
|
|
595
|
-
if
|
|
596
|
-
timers[
|
|
499
|
+
for i in range(len(timers)):
|
|
500
|
+
if timers[i].get("id", 0) == timer_id:
|
|
501
|
+
timers[i]["enabled"] = enable
|
|
597
502
|
data = {"timers": timers, "profiles": profiles}
|
|
598
503
|
response = await self._connection.setDepartureProfiles(self.vin, data)
|
|
599
|
-
if is_valid_path(
|
|
600
|
-
self.attrs,
|
|
601
|
-
f"{Services.CLIMATISATION_TIMERS}.auxiliaryHeatingTimersStatus.value.timers",
|
|
602
|
-
):
|
|
504
|
+
if is_valid_path(self.attrs, f"{Services.CLIMATISATION_TIMERS}.auxiliaryHeatingTimersStatus.value.timers"):
|
|
603
505
|
timers = find_path(
|
|
604
|
-
self.attrs,
|
|
605
|
-
f"{Services.CLIMATISATION_TIMERS}.auxiliaryHeatingTimersStatus.value.timers",
|
|
506
|
+
self.attrs, f"{Services.CLIMATISATION_TIMERS}.auxiliaryHeatingTimersStatus.value.timers"
|
|
606
507
|
)
|
|
607
|
-
for
|
|
608
|
-
if
|
|
609
|
-
timers[
|
|
508
|
+
for i in range(len(timers)):
|
|
509
|
+
if timers[i].get("id", 0) == timer_id:
|
|
510
|
+
timers[i]["enabled"] = enable
|
|
610
511
|
data = {"spin": spin, "timers": timers}
|
|
611
|
-
response = await self._connection.setAuxiliaryHeatingTimers(
|
|
612
|
-
|
|
613
|
-
)
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
):
|
|
618
|
-
timers = find_path(
|
|
619
|
-
self.attrs,
|
|
620
|
-
f"{Services.DEPARTURE_TIMERS}.departureTimersStatus.value.timers",
|
|
621
|
-
)
|
|
622
|
-
for index, timer in enumerate(timers):
|
|
623
|
-
if timer.get("id", 0) == timer_id:
|
|
624
|
-
timers[index]["enabled"] = enable
|
|
512
|
+
response = await self._connection.setAuxiliaryHeatingTimers(self.vin, data)
|
|
513
|
+
if is_valid_path(self.attrs, f"{Services.DEPARTURE_TIMERS}.departureTimersStatus.value.timers"):
|
|
514
|
+
timers = find_path(self.attrs, f"{Services.DEPARTURE_TIMERS}.departureTimersStatus.value.timers")
|
|
515
|
+
for i in range(len(timers)):
|
|
516
|
+
if timers[i].get("id", 0) == timer_id:
|
|
517
|
+
timers[i]["enabled"] = enable
|
|
625
518
|
data = {"timers": timers}
|
|
626
519
|
response = await self._connection.setDepartureTimers(self.vin, data)
|
|
627
520
|
return await self._handle_response(
|
|
628
|
-
response=response,
|
|
629
|
-
topic="departuretimer",
|
|
630
|
-
error_msg="Failed to change departure timers setting.",
|
|
521
|
+
response=response, topic="departuretimer", error_msg="Failed to change departure timers setting."
|
|
631
522
|
)
|
|
632
|
-
|
|
633
|
-
|
|
523
|
+
else:
|
|
524
|
+
_LOGGER.error("Departure timers are not supported.")
|
|
525
|
+
raise Exception("Departure timers are not supported.")
|
|
634
526
|
|
|
635
527
|
async def set_ac_departure_timer(self, timer_id, enable) -> bool:
|
|
636
528
|
"""Turn on/off ac departure timer."""
|
|
637
529
|
if self.is_ac_departure_timer_supported(timer_id):
|
|
638
|
-
if
|
|
639
|
-
_LOGGER.error(
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
"
|
|
645
|
-
)
|
|
646
|
-
timers = find_path(
|
|
647
|
-
self.attrs,
|
|
648
|
-
f"{Services.CLIMATISATION_TIMERS}.climatisationTimersStatus.value.timers",
|
|
649
|
-
)
|
|
650
|
-
for index, timer in enumerate(timers):
|
|
651
|
-
if timer.get("id", 0) == timer_id:
|
|
652
|
-
timers[index]["enabled"] = enable
|
|
530
|
+
if type(enable) is not bool:
|
|
531
|
+
_LOGGER.error("Charging climatisation departure timers setting is not supported.")
|
|
532
|
+
raise Exception("Charging climatisation departure timers setting is not supported.")
|
|
533
|
+
timers = find_path(self.attrs, f"{Services.CLIMATISATION_TIMERS}.climatisationTimersStatus.value.timers")
|
|
534
|
+
for i in range(len(timers)):
|
|
535
|
+
if timers[i].get("id", 0) == timer_id:
|
|
536
|
+
timers[i]["enabled"] = enable
|
|
653
537
|
data = {"timers": timers}
|
|
654
538
|
response = await self._connection.setClimatisationTimers(self.vin, data)
|
|
655
539
|
return await self._handle_response(
|
|
@@ -657,38 +541,32 @@ class Vehicle:
|
|
|
657
541
|
topic="departuretimer",
|
|
658
542
|
error_msg="Failed to change climatisation departure timers setting.",
|
|
659
543
|
)
|
|
660
|
-
|
|
661
|
-
|
|
544
|
+
else:
|
|
545
|
+
_LOGGER.error("Climatisation departure timers are not supported.")
|
|
546
|
+
raise Exception("Climatisation departure timers are not supported.")
|
|
662
547
|
|
|
663
548
|
# Lock (RLU)
|
|
664
549
|
async def set_lock(self, action, spin):
|
|
665
550
|
"""Remote lock and unlock actions."""
|
|
666
551
|
if not self._services.get(Services.ACCESS, {}).get("active", False):
|
|
667
|
-
_LOGGER.info("Remote lock/unlock is not supported")
|
|
668
|
-
raise Exception("Remote lock/unlock is not supported.")
|
|
552
|
+
_LOGGER.info("Remote lock/unlock is not supported.")
|
|
553
|
+
raise Exception("Remote lock/unlock is not supported.")
|
|
669
554
|
if self._in_progress("lock", unknown_offset=-5):
|
|
670
555
|
return False
|
|
671
556
|
if action not in ["lock", "unlock"]:
|
|
672
|
-
_LOGGER.error("Invalid lock action:
|
|
673
|
-
raise Exception(f"Invalid lock action: {action}")
|
|
557
|
+
_LOGGER.error(f"Invalid lock action: {action}")
|
|
558
|
+
raise Exception(f"Invalid lock action: {action}")
|
|
674
559
|
|
|
675
560
|
try:
|
|
676
561
|
self._requests["latest"] = "Lock"
|
|
677
|
-
response = await self._connection.setLock(
|
|
678
|
-
self.vin, (action == "lock"), spin
|
|
679
|
-
)
|
|
562
|
+
response = await self._connection.setLock(self.vin, (action == "lock"), spin)
|
|
680
563
|
return await self._handle_response(
|
|
681
|
-
response=response,
|
|
682
|
-
topic="access",
|
|
683
|
-
error_msg=f"Failed to {action} vehicle",
|
|
564
|
+
response=response, topic="access", error_msg=f"Failed to {action} vehicle"
|
|
684
565
|
)
|
|
685
|
-
except Exception as error:
|
|
686
|
-
_LOGGER.warning("Failed to
|
|
687
|
-
self._requests["lock"] = {
|
|
688
|
-
|
|
689
|
-
"timestamp": datetime.now(UTC),
|
|
690
|
-
}
|
|
691
|
-
raise Exception("Lock action failed") # pylint: disable=broad-exception-raised
|
|
566
|
+
except Exception as error:
|
|
567
|
+
_LOGGER.warning(f"Failed to {action} vehicle - {error}")
|
|
568
|
+
self._requests["lock"] = {"status": "Exception", "timestamp": datetime.now(timezone.utc)}
|
|
569
|
+
raise Exception("Lock action failed")
|
|
692
570
|
|
|
693
571
|
# Refresh vehicle data (VSR)
|
|
694
572
|
async def set_refresh(self):
|
|
@@ -702,46 +580,40 @@ class Vehicle:
|
|
|
702
580
|
if response.status == 204:
|
|
703
581
|
self._requests["state"] = "in_progress"
|
|
704
582
|
self._requests["refresh"] = {
|
|
705
|
-
"timestamp": datetime.now(
|
|
583
|
+
"timestamp": datetime.now(timezone.utc),
|
|
706
584
|
"status": "in_progress",
|
|
707
585
|
"id": 0,
|
|
708
586
|
}
|
|
709
587
|
status = await self.wait_for_data_refresh()
|
|
710
588
|
elif response.status == 429:
|
|
711
589
|
status = "Throttled"
|
|
712
|
-
_LOGGER.debug("Server side throttled. Try again later")
|
|
590
|
+
_LOGGER.debug("Server side throttled. Try again later.")
|
|
713
591
|
else:
|
|
714
|
-
_LOGGER.debug(
|
|
715
|
-
"Unable to refresh the data. Incorrect response code: %s",
|
|
716
|
-
response.status,
|
|
717
|
-
)
|
|
592
|
+
_LOGGER.debug(f"Unable to refresh the data. Incorrect response code: {response.status}")
|
|
718
593
|
self._requests["state"] = status
|
|
719
|
-
self._requests["refresh"] = {
|
|
720
|
-
"status": status,
|
|
721
|
-
"timestamp": datetime.now(UTC),
|
|
722
|
-
}
|
|
594
|
+
self._requests["refresh"] = {"status": status, "timestamp": datetime.now(timezone.utc)}
|
|
723
595
|
return True
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
}
|
|
731
|
-
raise Exception("Data refresh failed") # pylint: disable=broad-exception-raised
|
|
596
|
+
else:
|
|
597
|
+
_LOGGER.debug("Unable to refresh the data.")
|
|
598
|
+
except Exception as error:
|
|
599
|
+
_LOGGER.warning(f"Failed to execute data refresh - {error}")
|
|
600
|
+
self._requests["refresh"] = {"status": "Exception", "timestamp": datetime.now(timezone.utc)}
|
|
601
|
+
raise Exception("Data refresh failed")
|
|
732
602
|
|
|
733
603
|
# Vehicle class helpers #
|
|
734
604
|
# Vehicle info
|
|
735
605
|
@property
|
|
736
606
|
def attrs(self):
|
|
737
|
-
"""
|
|
607
|
+
"""
|
|
608
|
+
Return all attributes.
|
|
738
609
|
|
|
739
610
|
:return:
|
|
740
611
|
"""
|
|
741
612
|
return self._states
|
|
742
613
|
|
|
743
614
|
def has_attr(self, attr) -> bool:
|
|
744
|
-
"""
|
|
615
|
+
"""
|
|
616
|
+
Return true if attribute exists.
|
|
745
617
|
|
|
746
618
|
:param attr:
|
|
747
619
|
:return:
|
|
@@ -749,7 +621,8 @@ class Vehicle:
|
|
|
749
621
|
return is_valid_path(self.attrs, attr)
|
|
750
622
|
|
|
751
623
|
def get_attr(self, attr):
|
|
752
|
-
"""
|
|
624
|
+
"""
|
|
625
|
+
Return a specific attribute.
|
|
753
626
|
|
|
754
627
|
:param attr:
|
|
755
628
|
:return:
|
|
@@ -759,44 +632,41 @@ class Vehicle:
|
|
|
759
632
|
async def expired(self, service):
|
|
760
633
|
"""Check if access to service has expired."""
|
|
761
634
|
try:
|
|
762
|
-
now = datetime.
|
|
635
|
+
now = datetime.utcnow()
|
|
763
636
|
if self._services.get(service, {}).get("expiration", False):
|
|
764
637
|
expiration = self._services.get(service, {}).get("expiration", False)
|
|
765
638
|
if not expiration:
|
|
766
|
-
expiration = datetime.
|
|
639
|
+
expiration = datetime.utcnow() + timedelta(days=1)
|
|
767
640
|
else:
|
|
768
|
-
_LOGGER.debug(
|
|
769
|
-
|
|
770
|
-
service,
|
|
771
|
-
)
|
|
772
|
-
expiration = datetime.now(UTC) + timedelta(days=1)
|
|
641
|
+
_LOGGER.debug(f"Could not determine end of access for service {service}, assuming it is valid")
|
|
642
|
+
expiration = datetime.utcnow() + timedelta(days=1)
|
|
773
643
|
expiration = expiration.replace(tzinfo=None)
|
|
774
644
|
if now >= expiration:
|
|
775
|
-
_LOGGER.warning("Access to
|
|
645
|
+
_LOGGER.warning(f"Access to {service} has expired!")
|
|
776
646
|
self._discovered = False
|
|
777
647
|
return True
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
)
|
|
783
|
-
return False
|
|
784
|
-
else:
|
|
648
|
+
else:
|
|
649
|
+
return False
|
|
650
|
+
except Exception:
|
|
651
|
+
_LOGGER.debug(f"Exception. Could not determine end of access for service {service}, assuming it is valid")
|
|
785
652
|
return False
|
|
786
653
|
|
|
787
654
|
def dashboard(self, **config):
|
|
788
|
-
"""
|
|
655
|
+
"""
|
|
656
|
+
Return dashboard with specified configuration.
|
|
789
657
|
|
|
790
658
|
:param config:
|
|
791
659
|
:return:
|
|
792
660
|
"""
|
|
793
|
-
|
|
661
|
+
# Classic python notation
|
|
662
|
+
from .vw_dashboard import Dashboard
|
|
794
663
|
|
|
795
664
|
return Dashboard(self, **config)
|
|
796
665
|
|
|
797
666
|
@property
|
|
798
667
|
def vin(self) -> str:
|
|
799
|
-
"""
|
|
668
|
+
"""
|
|
669
|
+
Vehicle identification number.
|
|
800
670
|
|
|
801
671
|
:return:
|
|
802
672
|
"""
|
|
@@ -804,7 +674,8 @@ class Vehicle:
|
|
|
804
674
|
|
|
805
675
|
@property
|
|
806
676
|
def unique_id(self) -> str:
|
|
807
|
-
"""
|
|
677
|
+
"""
|
|
678
|
+
Return unique id for the vehicle (vin).
|
|
808
679
|
|
|
809
680
|
:return:
|
|
810
681
|
"""
|
|
@@ -814,7 +685,8 @@ class Vehicle:
|
|
|
814
685
|
# Car information
|
|
815
686
|
@property
|
|
816
687
|
def nickname(self) -> str | None:
|
|
817
|
-
"""
|
|
688
|
+
"""
|
|
689
|
+
Return nickname of the vehicle.
|
|
818
690
|
|
|
819
691
|
:return:
|
|
820
692
|
"""
|
|
@@ -822,7 +694,8 @@ class Vehicle:
|
|
|
822
694
|
|
|
823
695
|
@property
|
|
824
696
|
def is_nickname_supported(self) -> bool:
|
|
825
|
-
"""
|
|
697
|
+
"""
|
|
698
|
+
Return true if naming the vehicle is supported.
|
|
826
699
|
|
|
827
700
|
:return:
|
|
828
701
|
"""
|
|
@@ -830,7 +703,8 @@ class Vehicle:
|
|
|
830
703
|
|
|
831
704
|
@property
|
|
832
705
|
def deactivated(self) -> bool | None:
|
|
833
|
-
"""
|
|
706
|
+
"""
|
|
707
|
+
Return true if service is deactivated.
|
|
834
708
|
|
|
835
709
|
:return:
|
|
836
710
|
"""
|
|
@@ -838,7 +712,8 @@ class Vehicle:
|
|
|
838
712
|
|
|
839
713
|
@property
|
|
840
714
|
def is_deactivated_supported(self) -> bool:
|
|
841
|
-
"""
|
|
715
|
+
"""
|
|
716
|
+
Return true if service deactivation status is supported.
|
|
842
717
|
|
|
843
718
|
:return:
|
|
844
719
|
"""
|
|
@@ -872,7 +747,8 @@ class Vehicle:
|
|
|
872
747
|
|
|
873
748
|
@property
|
|
874
749
|
def is_model_image_supported(self) -> bool:
|
|
875
|
-
"""
|
|
750
|
+
"""
|
|
751
|
+
Return true if vehicle model image is supported.
|
|
876
752
|
|
|
877
753
|
:return:
|
|
878
754
|
"""
|
|
@@ -883,12 +759,7 @@ class Vehicle:
|
|
|
883
759
|
@property
|
|
884
760
|
def parking_light(self) -> bool:
|
|
885
761
|
"""Return true if parking light is on."""
|
|
886
|
-
lights = (
|
|
887
|
-
self.attrs.get(Services.VEHICLE_LIGHTS)
|
|
888
|
-
.get("lightsStatus")
|
|
889
|
-
.get("value")
|
|
890
|
-
.get("lights")
|
|
891
|
-
)
|
|
762
|
+
lights = self.attrs.get(Services.VEHICLE_LIGHTS).get("lightsStatus").get("value").get("lights")
|
|
892
763
|
lights_on_count = 0
|
|
893
764
|
for light in lights:
|
|
894
765
|
if light["status"] == "on":
|
|
@@ -898,12 +769,7 @@ class Vehicle:
|
|
|
898
769
|
@property
|
|
899
770
|
def parking_light_last_updated(self) -> datetime:
|
|
900
771
|
"""Return attribute last updated timestamp."""
|
|
901
|
-
return (
|
|
902
|
-
self.attrs.get(Services.VEHICLE_LIGHTS)
|
|
903
|
-
.get("lightsStatus")
|
|
904
|
-
.get("value")
|
|
905
|
-
.get("carCapturedTimestamp")
|
|
906
|
-
)
|
|
772
|
+
return self.attrs.get(Services.VEHICLE_LIGHTS).get("lightsStatus").get("value").get("carCapturedTimestamp")
|
|
907
773
|
|
|
908
774
|
@property
|
|
909
775
|
def is_parking_light_supported(self) -> bool:
|
|
@@ -919,35 +785,33 @@ class Vehicle:
|
|
|
919
785
|
# this field is only a dirty hack, because there is no overarching information for the car anymore,
|
|
920
786
|
# only information per service, so we just use the one for fuelStatus.rangeStatus when car is ideling
|
|
921
787
|
# and charing.batteryStatus when electic car is charging
|
|
922
|
-
|
|
788
|
+
"""Return attribute last updated timestamp."""
|
|
923
789
|
if self.is_battery_level_supported and self.charging:
|
|
924
790
|
return self.battery_level_last_updated
|
|
925
|
-
|
|
926
|
-
if
|
|
791
|
+
elif self.is_distance_supported:
|
|
792
|
+
if type(self.distance_last_updated) is str:
|
|
927
793
|
return (
|
|
928
|
-
datetime.strptime(
|
|
929
|
-
self.distance_last_updated, "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
930
|
-
)
|
|
794
|
+
datetime.strptime(self.distance_last_updated, "%Y-%m-%dT%H:%M:%S.%fZ")
|
|
931
795
|
.replace(microsecond=0)
|
|
932
|
-
.replace(tzinfo=
|
|
796
|
+
.replace(tzinfo=timezone.utc)
|
|
933
797
|
)
|
|
934
|
-
|
|
798
|
+
else:
|
|
799
|
+
return self.distance_last_updated
|
|
935
800
|
|
|
936
801
|
@property
|
|
937
802
|
def last_connected_last_updated(self) -> datetime:
|
|
938
803
|
"""Return attribute last updated timestamp."""
|
|
939
804
|
if self.is_battery_level_supported and self.charging:
|
|
940
805
|
return self.battery_level_last_updated
|
|
941
|
-
|
|
942
|
-
if
|
|
806
|
+
elif self.is_distance_supported:
|
|
807
|
+
if type(self.distance_last_updated) is str:
|
|
943
808
|
return (
|
|
944
|
-
datetime.strptime(
|
|
945
|
-
self.distance_last_updated, "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
946
|
-
)
|
|
809
|
+
datetime.strptime(self.distance_last_updated, "%Y-%m-%dT%H:%M:%S.%fZ")
|
|
947
810
|
.replace(microsecond=0)
|
|
948
|
-
.replace(tzinfo=
|
|
811
|
+
.replace(tzinfo=timezone.utc)
|
|
949
812
|
)
|
|
950
|
-
|
|
813
|
+
else:
|
|
814
|
+
return self.distance_last_updated
|
|
951
815
|
|
|
952
816
|
@property
|
|
953
817
|
def is_last_connected_supported(self) -> bool:
|
|
@@ -958,437 +822,326 @@ class Vehicle:
|
|
|
958
822
|
@property
|
|
959
823
|
def distance(self) -> int | None:
|
|
960
824
|
"""Return vehicle odometer."""
|
|
961
|
-
return find_path(
|
|
962
|
-
self.attrs, f"{Services.MEASUREMENTS}.odometerStatus.value.odometer"
|
|
963
|
-
)
|
|
825
|
+
return find_path(self.attrs, f"{Services.MEASUREMENTS}.odometerStatus.value.odometer")
|
|
964
826
|
|
|
965
827
|
@property
|
|
966
828
|
def distance_last_updated(self) -> datetime:
|
|
967
829
|
"""Return last updated timestamp."""
|
|
968
|
-
return find_path(
|
|
969
|
-
self.attrs,
|
|
970
|
-
f"{Services.MEASUREMENTS}.odometerStatus.value.carCapturedTimestamp",
|
|
971
|
-
)
|
|
830
|
+
return find_path(self.attrs, f"{Services.MEASUREMENTS}.odometerStatus.value.carCapturedTimestamp")
|
|
972
831
|
|
|
973
832
|
@property
|
|
974
833
|
def is_distance_supported(self) -> bool:
|
|
975
834
|
"""Return true if odometer is supported."""
|
|
976
|
-
return is_valid_path(
|
|
977
|
-
self.attrs, f"{Services.MEASUREMENTS}.odometerStatus.value.odometer"
|
|
978
|
-
)
|
|
835
|
+
return is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.odometerStatus.value.odometer")
|
|
979
836
|
|
|
980
837
|
@property
|
|
981
838
|
def service_inspection(self):
|
|
982
839
|
"""Return time left for service inspection."""
|
|
983
|
-
return find_path(
|
|
984
|
-
self.attrs,
|
|
985
|
-
f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.inspectionDue_days",
|
|
986
|
-
)
|
|
840
|
+
return find_path(self.attrs, f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.inspectionDue_days")
|
|
987
841
|
|
|
988
842
|
@property
|
|
989
843
|
def service_inspection_last_updated(self) -> datetime:
|
|
990
844
|
"""Return attribute last updated timestamp."""
|
|
991
845
|
return find_path(
|
|
992
|
-
self.attrs,
|
|
993
|
-
f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.carCapturedTimestamp",
|
|
846
|
+
self.attrs, f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.carCapturedTimestamp"
|
|
994
847
|
)
|
|
995
848
|
|
|
996
849
|
@property
|
|
997
850
|
def is_service_inspection_supported(self) -> bool:
|
|
998
|
-
"""
|
|
851
|
+
"""
|
|
852
|
+
Return true if days to service inspection is supported.
|
|
999
853
|
|
|
1000
854
|
:return:
|
|
1001
855
|
"""
|
|
1002
856
|
return is_valid_path(
|
|
1003
|
-
self.attrs,
|
|
1004
|
-
f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.inspectionDue_days",
|
|
857
|
+
self.attrs, f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.inspectionDue_days"
|
|
1005
858
|
)
|
|
1006
859
|
|
|
1007
860
|
@property
|
|
1008
861
|
def service_inspection_distance(self):
|
|
1009
862
|
"""Return distance left for service inspection."""
|
|
1010
|
-
return find_path(
|
|
1011
|
-
self.attrs,
|
|
1012
|
-
f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.inspectionDue_km",
|
|
1013
|
-
)
|
|
863
|
+
return find_path(self.attrs, f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.inspectionDue_km")
|
|
1014
864
|
|
|
1015
865
|
@property
|
|
1016
866
|
def service_inspection_distance_last_updated(self) -> datetime:
|
|
1017
867
|
"""Return attribute last updated timestamp."""
|
|
1018
868
|
return find_path(
|
|
1019
|
-
self.attrs,
|
|
1020
|
-
f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.carCapturedTimestamp",
|
|
869
|
+
self.attrs, f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.carCapturedTimestamp"
|
|
1021
870
|
)
|
|
1022
871
|
|
|
1023
872
|
@property
|
|
1024
873
|
def is_service_inspection_distance_supported(self) -> bool:
|
|
1025
|
-
"""
|
|
874
|
+
"""
|
|
875
|
+
Return true if distance to service inspection is supported.
|
|
1026
876
|
|
|
1027
877
|
:return:
|
|
1028
878
|
"""
|
|
1029
879
|
return is_valid_path(
|
|
1030
|
-
self.attrs,
|
|
1031
|
-
f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.inspectionDue_km",
|
|
880
|
+
self.attrs, f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.inspectionDue_km"
|
|
1032
881
|
)
|
|
1033
882
|
|
|
1034
883
|
@property
|
|
1035
884
|
def oil_inspection(self):
|
|
1036
885
|
"""Return time left for oil inspection."""
|
|
1037
|
-
return find_path(
|
|
1038
|
-
self.attrs,
|
|
1039
|
-
f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.oilServiceDue_days",
|
|
1040
|
-
)
|
|
886
|
+
return find_path(self.attrs, f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.oilServiceDue_days")
|
|
1041
887
|
|
|
1042
888
|
@property
|
|
1043
889
|
def oil_inspection_last_updated(self) -> datetime:
|
|
1044
890
|
"""Return attribute last updated timestamp."""
|
|
1045
891
|
return find_path(
|
|
1046
|
-
self.attrs,
|
|
1047
|
-
f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.carCapturedTimestamp",
|
|
892
|
+
self.attrs, f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.carCapturedTimestamp"
|
|
1048
893
|
)
|
|
1049
894
|
|
|
1050
895
|
@property
|
|
1051
896
|
def is_oil_inspection_supported(self) -> bool:
|
|
1052
|
-
"""
|
|
897
|
+
"""
|
|
898
|
+
Return true if days to oil inspection is supported.
|
|
1053
899
|
|
|
1054
900
|
:return:
|
|
1055
901
|
"""
|
|
1056
902
|
if not self.has_combustion_engine:
|
|
1057
903
|
return False
|
|
1058
904
|
return is_valid_path(
|
|
1059
|
-
self.attrs,
|
|
1060
|
-
f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.oilServiceDue_days",
|
|
905
|
+
self.attrs, f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.oilServiceDue_days"
|
|
1061
906
|
)
|
|
1062
907
|
|
|
1063
908
|
@property
|
|
1064
909
|
def oil_inspection_distance(self):
|
|
1065
910
|
"""Return distance left for oil inspection."""
|
|
1066
|
-
return find_path(
|
|
1067
|
-
self.attrs,
|
|
1068
|
-
f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.oilServiceDue_km",
|
|
1069
|
-
)
|
|
911
|
+
return find_path(self.attrs, f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.oilServiceDue_km")
|
|
1070
912
|
|
|
1071
913
|
@property
|
|
1072
914
|
def oil_inspection_distance_last_updated(self) -> datetime:
|
|
1073
915
|
"""Return attribute last updated timestamp."""
|
|
1074
916
|
return find_path(
|
|
1075
|
-
self.attrs,
|
|
1076
|
-
f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.carCapturedTimestamp",
|
|
917
|
+
self.attrs, f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.carCapturedTimestamp"
|
|
1077
918
|
)
|
|
1078
919
|
|
|
1079
920
|
@property
|
|
1080
921
|
def is_oil_inspection_distance_supported(self) -> bool:
|
|
1081
|
-
"""
|
|
922
|
+
"""
|
|
923
|
+
Return true if oil inspection distance is supported.
|
|
1082
924
|
|
|
1083
925
|
:return:
|
|
1084
926
|
"""
|
|
1085
927
|
if not self.has_combustion_engine:
|
|
1086
928
|
return False
|
|
1087
929
|
return is_valid_path(
|
|
1088
|
-
self.attrs,
|
|
1089
|
-
f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.oilServiceDue_km",
|
|
930
|
+
self.attrs, f"{Services.VEHICLE_HEALTH_INSPECTION}.maintenanceStatus.value.oilServiceDue_km"
|
|
1090
931
|
)
|
|
1091
932
|
|
|
1092
933
|
@property
|
|
1093
934
|
def adblue_level(self) -> int:
|
|
1094
935
|
"""Return adblue level."""
|
|
1095
|
-
return find_path(
|
|
1096
|
-
self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.adBlueRange"
|
|
1097
|
-
)
|
|
936
|
+
return find_path(self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.adBlueRange")
|
|
1098
937
|
|
|
1099
938
|
@property
|
|
1100
939
|
def adblue_level_last_updated(self) -> datetime:
|
|
1101
940
|
"""Return attribute last updated timestamp."""
|
|
1102
|
-
return find_path(
|
|
1103
|
-
self.attrs,
|
|
1104
|
-
f"{Services.MEASUREMENTS}.rangeStatus.value.carCapturedTimestamp",
|
|
1105
|
-
)
|
|
941
|
+
return find_path(self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.carCapturedTimestamp")
|
|
1106
942
|
|
|
1107
943
|
@property
|
|
1108
944
|
def is_adblue_level_supported(self) -> bool:
|
|
1109
945
|
"""Return true if adblue level is supported."""
|
|
1110
|
-
return is_valid_path(
|
|
1111
|
-
self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.adBlueRange"
|
|
1112
|
-
)
|
|
946
|
+
return is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.adBlueRange")
|
|
1113
947
|
|
|
1114
948
|
# Charger related states for EV and PHEV
|
|
1115
949
|
@property
|
|
1116
950
|
def charging(self) -> bool:
|
|
1117
951
|
"""Return charging state."""
|
|
1118
|
-
cstate = find_path(
|
|
1119
|
-
self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargingState"
|
|
1120
|
-
)
|
|
952
|
+
cstate = find_path(self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargingState")
|
|
1121
953
|
return cstate == "charging"
|
|
1122
954
|
|
|
1123
955
|
@property
|
|
1124
956
|
def charging_last_updated(self) -> datetime:
|
|
1125
957
|
"""Return attribute last updated timestamp."""
|
|
1126
|
-
return find_path(
|
|
1127
|
-
self.attrs, f"{Services.CHARGING}.chargingStatus.value.carCapturedTimestamp"
|
|
1128
|
-
)
|
|
958
|
+
return find_path(self.attrs, f"{Services.CHARGING}.chargingStatus.value.carCapturedTimestamp")
|
|
1129
959
|
|
|
1130
960
|
@property
|
|
1131
961
|
def is_charging_supported(self) -> bool:
|
|
1132
962
|
"""Return true if charging is supported."""
|
|
1133
|
-
return is_valid_path(
|
|
1134
|
-
self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargingState"
|
|
1135
|
-
)
|
|
963
|
+
return is_valid_path(self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargingState")
|
|
1136
964
|
|
|
1137
965
|
@property
|
|
1138
966
|
def charging_power(self) -> int:
|
|
1139
967
|
"""Return charging power."""
|
|
1140
|
-
return find_path(
|
|
1141
|
-
self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargePower_kW"
|
|
1142
|
-
)
|
|
968
|
+
return find_path(self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargePower_kW")
|
|
1143
969
|
|
|
1144
970
|
@property
|
|
1145
971
|
def charging_power_last_updated(self) -> datetime:
|
|
1146
972
|
"""Return attribute last updated timestamp."""
|
|
1147
|
-
return find_path(
|
|
1148
|
-
self.attrs, f"{Services.CHARGING}.chargingStatus.value.carCapturedTimestamp"
|
|
1149
|
-
)
|
|
973
|
+
return find_path(self.attrs, f"{Services.CHARGING}.chargingStatus.value.carCapturedTimestamp")
|
|
1150
974
|
|
|
1151
975
|
@property
|
|
1152
976
|
def is_charging_power_supported(self) -> bool:
|
|
1153
977
|
"""Return true if charging power is supported."""
|
|
1154
|
-
return is_valid_path(
|
|
1155
|
-
self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargePower_kW"
|
|
1156
|
-
)
|
|
978
|
+
return is_valid_path(self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargePower_kW")
|
|
1157
979
|
|
|
1158
980
|
@property
|
|
1159
981
|
def charging_rate(self) -> int:
|
|
1160
982
|
"""Return charging rate."""
|
|
1161
|
-
return find_path(
|
|
1162
|
-
self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargeRate_kmph"
|
|
1163
|
-
)
|
|
983
|
+
return find_path(self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargeRate_kmph")
|
|
1164
984
|
|
|
1165
985
|
@property
|
|
1166
986
|
def charging_rate_last_updated(self) -> datetime:
|
|
1167
987
|
"""Return attribute last updated timestamp."""
|
|
1168
|
-
return find_path(
|
|
1169
|
-
self.attrs, f"{Services.CHARGING}.chargingStatus.value.carCapturedTimestamp"
|
|
1170
|
-
)
|
|
988
|
+
return find_path(self.attrs, f"{Services.CHARGING}.chargingStatus.value.carCapturedTimestamp")
|
|
1171
989
|
|
|
1172
990
|
@property
|
|
1173
991
|
def is_charging_rate_supported(self) -> bool:
|
|
1174
992
|
"""Return true if charging rate is supported."""
|
|
1175
|
-
return is_valid_path(
|
|
1176
|
-
self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargeRate_kmph"
|
|
1177
|
-
)
|
|
993
|
+
return is_valid_path(self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargeRate_kmph")
|
|
1178
994
|
|
|
1179
995
|
@property
|
|
1180
996
|
def charger_type(self) -> str:
|
|
1181
997
|
"""Return charger type."""
|
|
1182
|
-
charger_type = find_path(
|
|
1183
|
-
self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargeType"
|
|
1184
|
-
)
|
|
998
|
+
charger_type = find_path(self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargeType")
|
|
1185
999
|
if charger_type == "ac":
|
|
1186
1000
|
return "AC"
|
|
1187
|
-
|
|
1001
|
+
elif charger_type == "dc":
|
|
1188
1002
|
return "DC"
|
|
1189
1003
|
return "Unknown"
|
|
1190
1004
|
|
|
1191
1005
|
@property
|
|
1192
1006
|
def charger_type_last_updated(self) -> datetime:
|
|
1193
1007
|
"""Return attribute last updated timestamp."""
|
|
1194
|
-
return find_path(
|
|
1195
|
-
self.attrs, f"{Services.CHARGING}.chargingStatus.value.carCapturedTimestamp"
|
|
1196
|
-
)
|
|
1008
|
+
return find_path(self.attrs, f"{Services.CHARGING}.chargingStatus.value.carCapturedTimestamp")
|
|
1197
1009
|
|
|
1198
1010
|
@property
|
|
1199
1011
|
def is_charger_type_supported(self) -> bool:
|
|
1200
1012
|
"""Return true if charger type is supported."""
|
|
1201
|
-
return is_valid_path(
|
|
1202
|
-
self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargeType"
|
|
1203
|
-
)
|
|
1013
|
+
return is_valid_path(self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargeType")
|
|
1204
1014
|
|
|
1205
1015
|
@property
|
|
1206
1016
|
def battery_level(self) -> int:
|
|
1207
1017
|
"""Return battery level."""
|
|
1208
|
-
return find_path(
|
|
1209
|
-
self.attrs, f"{Services.CHARGING}.batteryStatus.value.currentSOC_pct"
|
|
1210
|
-
)
|
|
1018
|
+
return find_path(self.attrs, f"{Services.CHARGING}.batteryStatus.value.currentSOC_pct")
|
|
1211
1019
|
|
|
1212
1020
|
@property
|
|
1213
1021
|
def battery_level_last_updated(self) -> datetime:
|
|
1214
1022
|
"""Return attribute last updated timestamp."""
|
|
1215
|
-
return find_path(
|
|
1216
|
-
self.attrs, f"{Services.CHARGING}.batteryStatus.value.carCapturedTimestamp"
|
|
1217
|
-
)
|
|
1023
|
+
return find_path(self.attrs, f"{Services.CHARGING}.batteryStatus.value.carCapturedTimestamp")
|
|
1218
1024
|
|
|
1219
1025
|
@property
|
|
1220
1026
|
def is_battery_level_supported(self) -> bool:
|
|
1221
1027
|
"""Return true if battery level is supported."""
|
|
1222
|
-
return is_valid_path(
|
|
1223
|
-
self.attrs, f"{Services.CHARGING}.batteryStatus.value.currentSOC_pct"
|
|
1224
|
-
)
|
|
1028
|
+
return is_valid_path(self.attrs, f"{Services.CHARGING}.batteryStatus.value.currentSOC_pct")
|
|
1225
1029
|
|
|
1226
1030
|
@property
|
|
1227
1031
|
def battery_target_charge_level(self) -> int:
|
|
1228
1032
|
"""Return target charge level."""
|
|
1229
|
-
return find_path(
|
|
1230
|
-
self.attrs, f"{Services.CHARGING}.chargingSettings.value.targetSOC_pct"
|
|
1231
|
-
)
|
|
1033
|
+
return find_path(self.attrs, f"{Services.CHARGING}.chargingSettings.value.targetSOC_pct")
|
|
1232
1034
|
|
|
1233
1035
|
@property
|
|
1234
1036
|
def battery_target_charge_level_last_updated(self) -> datetime:
|
|
1235
1037
|
"""Return attribute last updated timestamp."""
|
|
1236
|
-
return find_path(
|
|
1237
|
-
self.attrs,
|
|
1238
|
-
f"{Services.CHARGING}.chargingSettings.value.carCapturedTimestamp",
|
|
1239
|
-
)
|
|
1038
|
+
return find_path(self.attrs, f"{Services.CHARGING}.chargingSettings.value.carCapturedTimestamp")
|
|
1240
1039
|
|
|
1241
1040
|
@property
|
|
1242
1041
|
def is_battery_target_charge_level_supported(self) -> bool:
|
|
1243
1042
|
"""Return true if target charge level is supported."""
|
|
1244
|
-
return is_valid_path(
|
|
1245
|
-
self.attrs, f"{Services.CHARGING}.chargingSettings.value.targetSOC_pct"
|
|
1246
|
-
)
|
|
1043
|
+
return is_valid_path(self.attrs, f"{Services.CHARGING}.chargingSettings.value.targetSOC_pct")
|
|
1247
1044
|
|
|
1248
1045
|
@property
|
|
1249
1046
|
def charge_max_ac_setting(self) -> str | int:
|
|
1250
1047
|
"""Return charger max ampere setting."""
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
)
|
|
1048
|
+
value = find_path(self.attrs, f"{Services.CHARGING}.chargingSettings.value.maxChargeCurrentAC")
|
|
1049
|
+
return value
|
|
1254
1050
|
|
|
1255
1051
|
@property
|
|
1256
1052
|
def charge_max_ac_setting_last_updated(self) -> datetime:
|
|
1257
1053
|
"""Return charger max ampere last updated."""
|
|
1258
|
-
return find_path(
|
|
1259
|
-
self.attrs,
|
|
1260
|
-
f"{Services.CHARGING}.chargingSettings.value.carCapturedTimestamp",
|
|
1261
|
-
)
|
|
1054
|
+
return find_path(self.attrs, f"{Services.CHARGING}.chargingSettings.value.carCapturedTimestamp")
|
|
1262
1055
|
|
|
1263
1056
|
@property
|
|
1264
1057
|
def is_charge_max_ac_setting_supported(self) -> bool:
|
|
1265
1058
|
"""Return true if Charger Max Ampere is supported."""
|
|
1266
|
-
if is_valid_path(
|
|
1267
|
-
self.attrs, f"{Services.CHARGING}.chargingSettings.value.maxChargeCurrentAC"
|
|
1268
|
-
):
|
|
1269
|
-
value = find_path(
|
|
1270
|
-
self.attrs,
|
|
1271
|
-
f"{Services.CHARGING}.chargingSettings.value.maxChargeCurrentAC",
|
|
1272
|
-
)
|
|
1059
|
+
if is_valid_path(self.attrs, f"{Services.CHARGING}.chargingSettings.value.maxChargeCurrentAC"):
|
|
1060
|
+
value = find_path(self.attrs, f"{Services.CHARGING}.chargingSettings.value.maxChargeCurrentAC")
|
|
1273
1061
|
return value in ["reduced", "maximum", "invalid"]
|
|
1274
1062
|
return False
|
|
1275
1063
|
|
|
1276
1064
|
@property
|
|
1277
1065
|
def charge_max_ac_ampere(self) -> str | int:
|
|
1278
1066
|
"""Return charger max ampere setting."""
|
|
1279
|
-
return find_path(
|
|
1280
|
-
self.attrs,
|
|
1281
|
-
f"{Services.CHARGING}.chargingSettings.value.maxChargeCurrentAC_A",
|
|
1282
|
-
)
|
|
1067
|
+
return find_path(self.attrs, f"{Services.CHARGING}.chargingSettings.value.maxChargeCurrentAC_A")
|
|
1283
1068
|
|
|
1284
1069
|
@property
|
|
1285
1070
|
def charge_max_ac_ampere_last_updated(self) -> datetime:
|
|
1286
1071
|
"""Return charger max ampere last updated."""
|
|
1287
|
-
return find_path(
|
|
1288
|
-
self.attrs,
|
|
1289
|
-
f"{Services.CHARGING}.chargingSettings.value.carCapturedTimestamp",
|
|
1290
|
-
)
|
|
1072
|
+
return find_path(self.attrs, f"{Services.CHARGING}.chargingSettings.value.carCapturedTimestamp")
|
|
1291
1073
|
|
|
1292
1074
|
@property
|
|
1293
1075
|
def is_charge_max_ac_ampere_supported(self) -> bool:
|
|
1294
1076
|
"""Return true if Charger Max Ampere is supported."""
|
|
1295
|
-
return is_valid_path(
|
|
1296
|
-
self.attrs,
|
|
1297
|
-
f"{Services.CHARGING}.chargingSettings.value.maxChargeCurrentAC_A",
|
|
1298
|
-
)
|
|
1077
|
+
return is_valid_path(self.attrs, f"{Services.CHARGING}.chargingSettings.value.maxChargeCurrentAC_A")
|
|
1299
1078
|
|
|
1300
1079
|
@property
|
|
1301
1080
|
def charging_cable_locked(self) -> bool:
|
|
1302
1081
|
"""Return plug locked state."""
|
|
1303
|
-
response = find_path(
|
|
1304
|
-
self.attrs, f"{Services.CHARGING}.plugStatus.value.plugLockState"
|
|
1305
|
-
)
|
|
1082
|
+
response = find_path(self.attrs, f"{Services.CHARGING}.plugStatus.value.plugLockState")
|
|
1306
1083
|
return response == "locked"
|
|
1307
1084
|
|
|
1308
1085
|
@property
|
|
1309
1086
|
def charging_cable_locked_last_updated(self) -> datetime:
|
|
1310
1087
|
"""Return plug locked state."""
|
|
1311
|
-
return find_path(
|
|
1312
|
-
self.attrs, f"{Services.CHARGING}.plugStatus.value.carCapturedTimestamp"
|
|
1313
|
-
)
|
|
1088
|
+
return find_path(self.attrs, f"{Services.CHARGING}.plugStatus.value.carCapturedTimestamp")
|
|
1314
1089
|
|
|
1315
1090
|
@property
|
|
1316
1091
|
def is_charging_cable_locked_supported(self) -> bool:
|
|
1317
1092
|
"""Return true if plug locked state is supported."""
|
|
1318
|
-
return is_valid_path(
|
|
1319
|
-
self.attrs, f"{Services.CHARGING}.plugStatus.value.plugLockState"
|
|
1320
|
-
)
|
|
1093
|
+
return is_valid_path(self.attrs, f"{Services.CHARGING}.plugStatus.value.plugLockState")
|
|
1321
1094
|
|
|
1322
1095
|
@property
|
|
1323
1096
|
def charging_cable_connected(self) -> bool:
|
|
1324
1097
|
"""Return plug connected state."""
|
|
1325
|
-
response = find_path(
|
|
1326
|
-
self.attrs, f"{Services.CHARGING}.plugStatus.value.plugConnectionState"
|
|
1327
|
-
)
|
|
1098
|
+
response = find_path(self.attrs, f"{Services.CHARGING}.plugStatus.value.plugConnectionState")
|
|
1328
1099
|
return response == "connected"
|
|
1329
1100
|
|
|
1330
1101
|
@property
|
|
1331
1102
|
def charging_cable_connected_last_updated(self) -> datetime:
|
|
1332
1103
|
"""Return plug connected state last updated."""
|
|
1333
|
-
return find_path(
|
|
1334
|
-
self.attrs, f"{Services.CHARGING}.plugStatus.value.carCapturedTimestamp"
|
|
1335
|
-
)
|
|
1104
|
+
return find_path(self.attrs, f"{Services.CHARGING}.plugStatus.value.carCapturedTimestamp")
|
|
1336
1105
|
|
|
1337
1106
|
@property
|
|
1338
1107
|
def is_charging_cable_connected_supported(self) -> bool:
|
|
1339
1108
|
"""Return true if supported."""
|
|
1340
|
-
return is_valid_path(
|
|
1341
|
-
self.attrs, f"{Services.CHARGING}.plugStatus.value.plugConnectionState"
|
|
1342
|
-
)
|
|
1109
|
+
return is_valid_path(self.attrs, f"{Services.CHARGING}.plugStatus.value.plugConnectionState")
|
|
1343
1110
|
|
|
1344
1111
|
@property
|
|
1345
1112
|
def charging_time_left(self) -> int:
|
|
1346
1113
|
"""Return minutes to charging complete."""
|
|
1347
|
-
if is_valid_path(
|
|
1348
|
-
self.attrs,
|
|
1349
|
-
f"{Services.CHARGING}.chargingStatus.value.remainingChargingTimeToComplete_min",
|
|
1350
|
-
):
|
|
1114
|
+
if is_valid_path(self.attrs, f"{Services.CHARGING}.chargingStatus.value.remainingChargingTimeToComplete_min"):
|
|
1351
1115
|
return find_path(
|
|
1352
|
-
self.attrs,
|
|
1353
|
-
f"{Services.CHARGING}.chargingStatus.value.remainingChargingTimeToComplete_min",
|
|
1116
|
+
self.attrs, f"{Services.CHARGING}.chargingStatus.value.remainingChargingTimeToComplete_min"
|
|
1354
1117
|
)
|
|
1355
1118
|
return None
|
|
1356
1119
|
|
|
1357
1120
|
@property
|
|
1358
1121
|
def charging_time_left_last_updated(self) -> datetime:
|
|
1359
1122
|
"""Return minutes to charging complete last updated."""
|
|
1360
|
-
return find_path(
|
|
1361
|
-
self.attrs, f"{Services.CHARGING}.chargingStatus.value.carCapturedTimestamp"
|
|
1362
|
-
)
|
|
1123
|
+
return find_path(self.attrs, f"{Services.CHARGING}.chargingStatus.value.carCapturedTimestamp")
|
|
1363
1124
|
|
|
1364
1125
|
@property
|
|
1365
1126
|
def is_charging_time_left_supported(self) -> bool:
|
|
1366
1127
|
"""Return true if charging is supported."""
|
|
1367
|
-
return is_valid_path(
|
|
1368
|
-
self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargingState"
|
|
1369
|
-
)
|
|
1128
|
+
return is_valid_path(self.attrs, f"{Services.CHARGING}.chargingStatus.value.chargingState")
|
|
1370
1129
|
|
|
1371
1130
|
@property
|
|
1372
1131
|
def external_power(self) -> bool:
|
|
1373
1132
|
"""Return true if external power is connected."""
|
|
1374
|
-
check = find_path(
|
|
1375
|
-
self.attrs, f"{Services.CHARGING}.plugStatus.value.externalPower"
|
|
1376
|
-
)
|
|
1133
|
+
check = find_path(self.attrs, f"{Services.CHARGING}.plugStatus.value.externalPower")
|
|
1377
1134
|
return check in ["stationConnected", "available", "ready"]
|
|
1378
1135
|
|
|
1379
1136
|
@property
|
|
1380
1137
|
def external_power_last_updated(self) -> datetime:
|
|
1381
1138
|
"""Return external power last updated."""
|
|
1382
|
-
return find_path(
|
|
1383
|
-
self.attrs, f"{Services.CHARGING}.plugStatus.value.carCapturedTimestamp"
|
|
1384
|
-
)
|
|
1139
|
+
return find_path(self.attrs, f"{Services.CHARGING}.plugStatus.value.carCapturedTimestamp")
|
|
1385
1140
|
|
|
1386
1141
|
@property
|
|
1387
1142
|
def is_external_power_supported(self) -> bool:
|
|
1388
1143
|
"""External power supported."""
|
|
1389
|
-
return is_valid_path(
|
|
1390
|
-
self.attrs, f"{Services.CHARGING}.plugStatus.value.externalPower"
|
|
1391
|
-
)
|
|
1144
|
+
return is_valid_path(self.attrs, f"{Services.CHARGING}.plugStatus.value.externalPower")
|
|
1392
1145
|
|
|
1393
1146
|
@property
|
|
1394
1147
|
def reduced_ac_charging(self) -> bool:
|
|
@@ -1408,89 +1161,64 @@ class Vehicle:
|
|
|
1408
1161
|
@property
|
|
1409
1162
|
def auto_release_ac_connector_state(self) -> str:
|
|
1410
1163
|
"""Return auto release ac connector state value."""
|
|
1411
|
-
return find_path(
|
|
1412
|
-
self.attrs,
|
|
1413
|
-
f"{Services.CHARGING}.chargingSettings.value.autoUnlockPlugWhenChargedAC",
|
|
1414
|
-
)
|
|
1164
|
+
return find_path(self.attrs, f"{Services.CHARGING}.chargingSettings.value.autoUnlockPlugWhenChargedAC")
|
|
1415
1165
|
|
|
1416
1166
|
@property
|
|
1417
1167
|
def auto_release_ac_connector(self) -> bool:
|
|
1418
1168
|
"""Return auto release ac connector state."""
|
|
1419
1169
|
return (
|
|
1420
|
-
find_path(
|
|
1421
|
-
self.attrs,
|
|
1422
|
-
f"{Services.CHARGING}.chargingSettings.value.autoUnlockPlugWhenChargedAC",
|
|
1423
|
-
)
|
|
1170
|
+
find_path(self.attrs, f"{Services.CHARGING}.chargingSettings.value.autoUnlockPlugWhenChargedAC")
|
|
1424
1171
|
== "permanent"
|
|
1425
1172
|
)
|
|
1426
1173
|
|
|
1427
1174
|
@property
|
|
1428
1175
|
def auto_release_ac_connector_last_updated(self) -> datetime:
|
|
1429
1176
|
"""Return attribute last updated timestamp."""
|
|
1430
|
-
return find_path(
|
|
1431
|
-
self.attrs,
|
|
1432
|
-
f"{Services.CHARGING}.chargingSettings.value.carCapturedTimestamp",
|
|
1433
|
-
)
|
|
1177
|
+
return find_path(self.attrs, f"{Services.CHARGING}.chargingSettings.value.carCapturedTimestamp")
|
|
1434
1178
|
|
|
1435
1179
|
@property
|
|
1436
1180
|
def is_auto_release_ac_connector_supported(self) -> bool:
|
|
1437
1181
|
"""Return true if auto release ac connector is supported."""
|
|
1438
|
-
return is_valid_path(
|
|
1439
|
-
self.attrs,
|
|
1440
|
-
f"{Services.CHARGING}.chargingSettings.value.autoUnlockPlugWhenChargedAC",
|
|
1441
|
-
)
|
|
1182
|
+
return is_valid_path(self.attrs, f"{Services.CHARGING}.chargingSettings.value.autoUnlockPlugWhenChargedAC")
|
|
1442
1183
|
|
|
1443
1184
|
@property
|
|
1444
1185
|
def battery_care_mode(self) -> bool:
|
|
1445
1186
|
"""Return battery care mode state."""
|
|
1446
1187
|
return (
|
|
1447
|
-
find_path(
|
|
1448
|
-
self.attrs,
|
|
1449
|
-
f"{Services.BATTERY_CHARGING_CARE}.chargingCareSettings.value.batteryCareMode",
|
|
1450
|
-
)
|
|
1188
|
+
find_path(self.attrs, f"{Services.BATTERY_CHARGING_CARE}.chargingCareSettings.value.batteryCareMode")
|
|
1451
1189
|
== "activated"
|
|
1452
1190
|
)
|
|
1453
1191
|
|
|
1454
1192
|
@property
|
|
1455
1193
|
def battery_care_mode_last_updated(self) -> datetime:
|
|
1456
1194
|
"""Return attribute last updated timestamp."""
|
|
1457
|
-
return datetime.now(
|
|
1195
|
+
return datetime.now(timezone.utc)
|
|
1458
1196
|
|
|
1459
1197
|
@property
|
|
1460
1198
|
def is_battery_care_mode_supported(self) -> bool:
|
|
1461
1199
|
"""Return true if battery care mode is supported."""
|
|
1462
|
-
return is_valid_path(
|
|
1463
|
-
self.attrs,
|
|
1464
|
-
f"{Services.BATTERY_CHARGING_CARE}.chargingCareSettings.value.batteryCareMode",
|
|
1465
|
-
)
|
|
1200
|
+
return is_valid_path(self.attrs, f"{Services.BATTERY_CHARGING_CARE}.chargingCareSettings.value.batteryCareMode")
|
|
1466
1201
|
|
|
1467
1202
|
@property
|
|
1468
1203
|
def optimised_battery_use(self) -> bool:
|
|
1469
1204
|
"""Return optimised battery use state."""
|
|
1470
1205
|
return (
|
|
1471
|
-
find_path(
|
|
1472
|
-
self.attrs,
|
|
1473
|
-
f"{Services.BATTERY_SUPPORT}.batterySupportStatus.value.batterySupport",
|
|
1474
|
-
)
|
|
1475
|
-
== "enabled"
|
|
1206
|
+
find_path(self.attrs, f"{Services.BATTERY_SUPPORT}.batterySupportStatus.value.batterySupport") == "enabled"
|
|
1476
1207
|
)
|
|
1477
1208
|
|
|
1478
1209
|
@property
|
|
1479
1210
|
def optimised_battery_use_last_updated(self) -> datetime:
|
|
1480
1211
|
"""Return attribute last updated timestamp."""
|
|
1481
|
-
return datetime.now(
|
|
1212
|
+
return datetime.now(timezone.utc)
|
|
1482
1213
|
|
|
1483
1214
|
@property
|
|
1484
1215
|
def is_optimised_battery_use_supported(self) -> bool:
|
|
1485
1216
|
"""Return true if optimised battery use is supported."""
|
|
1486
|
-
return is_valid_path(
|
|
1487
|
-
self.attrs,
|
|
1488
|
-
f"{Services.BATTERY_SUPPORT}.batterySupportStatus.value.batterySupport",
|
|
1489
|
-
)
|
|
1217
|
+
return is_valid_path(self.attrs, f"{Services.BATTERY_SUPPORT}.batterySupportStatus.value.batterySupport")
|
|
1490
1218
|
|
|
1491
1219
|
@property
|
|
1492
1220
|
def energy_flow(self):
|
|
1493
|
-
# TODO untouched
|
|
1221
|
+
# TODO untouched
|
|
1494
1222
|
"""Return true if energy is flowing through charging port."""
|
|
1495
1223
|
check = (
|
|
1496
1224
|
self.attrs.get("charger", {})
|
|
@@ -1503,7 +1231,7 @@ class Vehicle:
|
|
|
1503
1231
|
|
|
1504
1232
|
@property
|
|
1505
1233
|
def energy_flow_last_updated(self) -> datetime:
|
|
1506
|
-
# TODO untouched
|
|
1234
|
+
# TODO untouched
|
|
1507
1235
|
"""Return energy flow last updated."""
|
|
1508
1236
|
return (
|
|
1509
1237
|
self.attrs.get("charger", {})
|
|
@@ -1515,14 +1243,9 @@ class Vehicle:
|
|
|
1515
1243
|
|
|
1516
1244
|
@property
|
|
1517
1245
|
def is_energy_flow_supported(self) -> bool:
|
|
1518
|
-
# TODO untouched
|
|
1246
|
+
# TODO untouched
|
|
1519
1247
|
"""Energy flow supported."""
|
|
1520
|
-
return (
|
|
1521
|
-
self.attrs.get("charger", {})
|
|
1522
|
-
.get("status", {})
|
|
1523
|
-
.get("chargingStatusData", {})
|
|
1524
|
-
.get("energyFlow", False)
|
|
1525
|
-
)
|
|
1248
|
+
return self.attrs.get("charger", {}).get("status", {}).get("chargingStatusData", {}).get("energyFlow", False)
|
|
1526
1249
|
|
|
1527
1250
|
# Vehicle location states
|
|
1528
1251
|
@property
|
|
@@ -1535,11 +1258,9 @@ class Vehicle:
|
|
|
1535
1258
|
else:
|
|
1536
1259
|
lat = float(find_path(self.attrs, "parkingposition.lat"))
|
|
1537
1260
|
lng = float(find_path(self.attrs, "parkingposition.lon"))
|
|
1538
|
-
parking_time = find_path(
|
|
1539
|
-
self.attrs, "parkingposition.carCapturedTimestamp"
|
|
1540
|
-
)
|
|
1261
|
+
parking_time = find_path(self.attrs, "parkingposition.carCapturedTimestamp")
|
|
1541
1262
|
output = {"lat": lat, "lng": lng, "timestamp": parking_time}
|
|
1542
|
-
except Exception:
|
|
1263
|
+
except Exception:
|
|
1543
1264
|
output = {
|
|
1544
1265
|
"lat": "?",
|
|
1545
1266
|
"lng": "?",
|
|
@@ -1549,16 +1270,12 @@ class Vehicle:
|
|
|
1549
1270
|
@property
|
|
1550
1271
|
def position_last_updated(self) -> datetime:
|
|
1551
1272
|
"""Return position last updated."""
|
|
1552
|
-
return self.attrs.get("parkingposition", {}).get(
|
|
1553
|
-
"carCapturedTimestamp", "Unknown"
|
|
1554
|
-
)
|
|
1273
|
+
return self.attrs.get("parkingposition", {}).get("carCapturedTimestamp", "Unknown")
|
|
1555
1274
|
|
|
1556
1275
|
@property
|
|
1557
1276
|
def is_position_supported(self) -> bool:
|
|
1558
1277
|
"""Return true if position is available."""
|
|
1559
|
-
return is_valid_path(
|
|
1560
|
-
self.attrs, "parkingposition.carCapturedTimestamp"
|
|
1561
|
-
) or self.attrs.get("isMoving", False)
|
|
1278
|
+
return is_valid_path(self.attrs, "parkingposition.carCapturedTimestamp") or self.attrs.get("isMoving", False)
|
|
1562
1279
|
|
|
1563
1280
|
@property
|
|
1564
1281
|
def vehicle_moving(self) -> bool:
|
|
@@ -1596,64 +1313,43 @@ class Vehicle:
|
|
|
1596
1313
|
# Vehicle fuel level and range
|
|
1597
1314
|
@property
|
|
1598
1315
|
def electric_range(self) -> int:
|
|
1599
|
-
"""
|
|
1316
|
+
"""
|
|
1317
|
+
Return electric range.
|
|
1600
1318
|
|
|
1601
1319
|
:return:
|
|
1602
1320
|
"""
|
|
1603
|
-
if is_valid_path(
|
|
1604
|
-
self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.electricRange"
|
|
1605
|
-
)
|
|
1606
|
-
return find_path(
|
|
1607
|
-
self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.electricRange"
|
|
1608
|
-
)
|
|
1609
|
-
return find_path(
|
|
1610
|
-
self.attrs,
|
|
1611
|
-
f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.remainingRange_km",
|
|
1612
|
-
)
|
|
1321
|
+
if is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.electricRange"):
|
|
1322
|
+
return find_path(self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.electricRange")
|
|
1323
|
+
return find_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.remainingRange_km")
|
|
1613
1324
|
|
|
1614
1325
|
@property
|
|
1615
1326
|
def electric_range_last_updated(self) -> datetime:
|
|
1616
1327
|
"""Return electric range last updated."""
|
|
1617
|
-
if is_valid_path(
|
|
1618
|
-
self.attrs,
|
|
1619
|
-
|
|
1620
|
-
):
|
|
1621
|
-
return find_path(
|
|
1622
|
-
self.attrs,
|
|
1623
|
-
f"{Services.MEASUREMENTS}.rangeStatus.value.carCapturedTimestamp",
|
|
1624
|
-
)
|
|
1625
|
-
return find_path(
|
|
1626
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carCapturedTimestamp"
|
|
1627
|
-
)
|
|
1328
|
+
if is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.carCapturedTimestamp"):
|
|
1329
|
+
return find_path(self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.carCapturedTimestamp")
|
|
1330
|
+
return find_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carCapturedTimestamp")
|
|
1628
1331
|
|
|
1629
1332
|
@property
|
|
1630
1333
|
def is_electric_range_supported(self) -> bool:
|
|
1631
|
-
"""
|
|
1334
|
+
"""
|
|
1335
|
+
Return true if electric range is supported.
|
|
1632
1336
|
|
|
1633
1337
|
:return:
|
|
1634
1338
|
"""
|
|
1635
|
-
return is_valid_path(
|
|
1636
|
-
self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.electricRange"
|
|
1637
|
-
) or (
|
|
1339
|
+
return is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.electricRange") or (
|
|
1638
1340
|
self.is_car_type_electric
|
|
1639
|
-
and is_valid_path(
|
|
1640
|
-
self.attrs,
|
|
1641
|
-
f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.remainingRange_km",
|
|
1642
|
-
)
|
|
1341
|
+
and is_valid_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.remainingRange_km")
|
|
1643
1342
|
)
|
|
1644
1343
|
|
|
1645
1344
|
@property
|
|
1646
1345
|
def combustion_range(self) -> int:
|
|
1647
|
-
"""
|
|
1346
|
+
"""
|
|
1347
|
+
Return combustion engine range.
|
|
1648
1348
|
|
|
1649
1349
|
:return:
|
|
1650
1350
|
"""
|
|
1651
1351
|
DIESEL_RANGE = f"{Services.MEASUREMENTS}.rangeStatus.value.dieselRange"
|
|
1652
1352
|
GASOLINE_RANGE = f"{Services.MEASUREMENTS}.rangeStatus.value.gasolineRange"
|
|
1653
|
-
CNG_RANGE = f"{Services.MEASUREMENTS}.rangeStatus.value.cngRange"
|
|
1654
|
-
TOTAL_RANGE = f"{Services.MEASUREMENTS}.rangeStatus.value.totalRange_km"
|
|
1655
|
-
if is_valid_path(self.attrs, CNG_RANGE):
|
|
1656
|
-
return find_path(self.attrs, TOTAL_RANGE)
|
|
1657
1353
|
if is_valid_path(self.attrs, DIESEL_RANGE):
|
|
1658
1354
|
return find_path(self.attrs, DIESEL_RANGE)
|
|
1659
1355
|
if is_valid_path(self.attrs, GASOLINE_RANGE):
|
|
@@ -1663,179 +1359,83 @@ class Vehicle:
|
|
|
1663
1359
|
@property
|
|
1664
1360
|
def combustion_range_last_updated(self) -> datetime | None:
|
|
1665
1361
|
"""Return combustion engine range last updated."""
|
|
1666
|
-
return find_path(
|
|
1667
|
-
self.attrs,
|
|
1668
|
-
f"{Services.MEASUREMENTS}.rangeStatus.value.carCapturedTimestamp",
|
|
1669
|
-
)
|
|
1362
|
+
return find_path(self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.carCapturedTimestamp")
|
|
1670
1363
|
|
|
1671
1364
|
@property
|
|
1672
1365
|
def is_combustion_range_supported(self) -> bool:
|
|
1673
|
-
"""Return true if combustion range is supported, i.e. false for EVs.
|
|
1674
|
-
|
|
1675
|
-
:return:
|
|
1676
1366
|
"""
|
|
1677
|
-
|
|
1678
|
-
is_valid_path(
|
|
1679
|
-
self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.dieselRange"
|
|
1680
|
-
)
|
|
1681
|
-
or is_valid_path(
|
|
1682
|
-
self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.gasolineRange"
|
|
1683
|
-
)
|
|
1684
|
-
or is_valid_path(
|
|
1685
|
-
self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.cngRange"
|
|
1686
|
-
)
|
|
1687
|
-
)
|
|
1688
|
-
|
|
1689
|
-
@property
|
|
1690
|
-
def fuel_range(self) -> int:
|
|
1691
|
-
"""Return fuel engine range.
|
|
1692
|
-
|
|
1693
|
-
:return:
|
|
1694
|
-
"""
|
|
1695
|
-
DIESEL_RANGE = f"{Services.MEASUREMENTS}.rangeStatus.value.dieselRange"
|
|
1696
|
-
GASOLINE_RANGE = f"{Services.MEASUREMENTS}.rangeStatus.value.gasolineRange"
|
|
1697
|
-
if is_valid_path(self.attrs, DIESEL_RANGE):
|
|
1698
|
-
return find_path(self.attrs, DIESEL_RANGE)
|
|
1699
|
-
if is_valid_path(self.attrs, GASOLINE_RANGE):
|
|
1700
|
-
return find_path(self.attrs, GASOLINE_RANGE)
|
|
1701
|
-
return -1
|
|
1702
|
-
|
|
1703
|
-
@property
|
|
1704
|
-
def fuel_range_last_updated(self) -> datetime | None:
|
|
1705
|
-
"""Return fuel engine range last updated."""
|
|
1706
|
-
return find_path(
|
|
1707
|
-
self.attrs,
|
|
1708
|
-
f"{Services.MEASUREMENTS}.rangeStatus.value.carCapturedTimestamp",
|
|
1709
|
-
)
|
|
1710
|
-
|
|
1711
|
-
@property
|
|
1712
|
-
def is_fuel_range_supported(self) -> bool:
|
|
1713
|
-
"""Return true if fuel range is supported, i.e. false for EVs.
|
|
1367
|
+
Return true if combustion range is supported, i.e. false for EVs.
|
|
1714
1368
|
|
|
1715
1369
|
:return:
|
|
1716
1370
|
"""
|
|
1717
|
-
return is_valid_path(
|
|
1718
|
-
self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.dieselRange"
|
|
1719
|
-
) or is_valid_path(
|
|
1371
|
+
return is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.dieselRange") or is_valid_path(
|
|
1720
1372
|
self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.gasolineRange"
|
|
1721
1373
|
)
|
|
1722
1374
|
|
|
1723
|
-
@property
|
|
1724
|
-
def gas_range(self) -> int:
|
|
1725
|
-
"""Return gas engine range.
|
|
1726
|
-
|
|
1727
|
-
:return:
|
|
1728
|
-
"""
|
|
1729
|
-
CNG_RANGE = f"{Services.MEASUREMENTS}.rangeStatus.value.cngRange"
|
|
1730
|
-
if is_valid_path(self.attrs, CNG_RANGE):
|
|
1731
|
-
return find_path(self.attrs, CNG_RANGE)
|
|
1732
|
-
return -1
|
|
1733
|
-
|
|
1734
|
-
@property
|
|
1735
|
-
def gas_range_last_updated(self) -> datetime | None:
|
|
1736
|
-
"""Return gas engine range last updated."""
|
|
1737
|
-
return find_path(
|
|
1738
|
-
self.attrs,
|
|
1739
|
-
f"{Services.MEASUREMENTS}.rangeStatus.value.carCapturedTimestamp",
|
|
1740
|
-
)
|
|
1741
|
-
|
|
1742
|
-
@property
|
|
1743
|
-
def is_gas_range_supported(self) -> bool:
|
|
1744
|
-
"""Return true if gas range is supported, i.e. false for EVs.
|
|
1745
|
-
|
|
1746
|
-
:return:
|
|
1747
|
-
"""
|
|
1748
|
-
return is_valid_path(
|
|
1749
|
-
self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.cngRange"
|
|
1750
|
-
)
|
|
1751
|
-
|
|
1752
1375
|
@property
|
|
1753
1376
|
def combined_range(self) -> int:
|
|
1754
|
-
"""
|
|
1377
|
+
"""
|
|
1378
|
+
Return combined range.
|
|
1755
1379
|
|
|
1756
1380
|
:return:
|
|
1757
1381
|
"""
|
|
1758
|
-
return find_path(
|
|
1759
|
-
self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.totalRange_km"
|
|
1760
|
-
)
|
|
1382
|
+
return find_path(self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.totalRange_km")
|
|
1761
1383
|
|
|
1762
1384
|
@property
|
|
1763
1385
|
def combined_range_last_updated(self) -> datetime | None:
|
|
1764
1386
|
"""Return combined range last updated."""
|
|
1765
|
-
return find_path(
|
|
1766
|
-
self.attrs,
|
|
1767
|
-
f"{Services.MEASUREMENTS}.rangeStatus.value.carCapturedTimestamp",
|
|
1768
|
-
)
|
|
1387
|
+
return find_path(self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.carCapturedTimestamp")
|
|
1769
1388
|
|
|
1770
1389
|
@property
|
|
1771
1390
|
def is_combined_range_supported(self) -> bool:
|
|
1772
|
-
"""
|
|
1391
|
+
"""
|
|
1392
|
+
Return true if combined range is supported.
|
|
1773
1393
|
|
|
1774
1394
|
:return:
|
|
1775
1395
|
"""
|
|
1776
|
-
if is_valid_path(
|
|
1777
|
-
self.
|
|
1778
|
-
):
|
|
1779
|
-
return (
|
|
1780
|
-
self.is_electric_range_supported and self.is_combustion_range_supported
|
|
1781
|
-
)
|
|
1396
|
+
if is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.rangeStatus.value.totalRange_km"):
|
|
1397
|
+
return self.is_electric_range_supported and self.is_combustion_range_supported
|
|
1782
1398
|
return False
|
|
1783
1399
|
|
|
1784
1400
|
@property
|
|
1785
1401
|
def battery_cruising_range(self) -> int:
|
|
1786
|
-
"""
|
|
1402
|
+
"""
|
|
1403
|
+
Return battery cruising range.
|
|
1787
1404
|
|
|
1788
1405
|
:return:
|
|
1789
1406
|
"""
|
|
1790
|
-
return find_path(
|
|
1791
|
-
self.attrs,
|
|
1792
|
-
f"{Services.CHARGING}.batteryStatus.value.cruisingRangeElectric_km",
|
|
1793
|
-
)
|
|
1407
|
+
return find_path(self.attrs, f"{Services.CHARGING}.batteryStatus.value.cruisingRangeElectric_km")
|
|
1794
1408
|
|
|
1795
1409
|
@property
|
|
1796
1410
|
def battery_cruising_range_last_updated(self) -> datetime | None:
|
|
1797
1411
|
"""Return battery cruising range last updated."""
|
|
1798
|
-
return find_path(
|
|
1799
|
-
self.attrs, f"{Services.CHARGING}.batteryStatus.value.carCapturedTimestamp"
|
|
1800
|
-
)
|
|
1412
|
+
return find_path(self.attrs, f"{Services.CHARGING}.batteryStatus.value.carCapturedTimestamp")
|
|
1801
1413
|
|
|
1802
1414
|
@property
|
|
1803
1415
|
def is_battery_cruising_range_supported(self) -> bool:
|
|
1804
|
-
"""
|
|
1416
|
+
"""
|
|
1417
|
+
Return true if battery cruising range is supported.
|
|
1805
1418
|
|
|
1806
1419
|
:return:
|
|
1807
1420
|
"""
|
|
1808
|
-
return is_valid_path(
|
|
1809
|
-
self.attrs,
|
|
1810
|
-
f"{Services.CHARGING}.batteryStatus.value.cruisingRangeElectric_km",
|
|
1811
|
-
)
|
|
1421
|
+
return is_valid_path(self.attrs, f"{Services.CHARGING}.batteryStatus.value.cruisingRangeElectric_km")
|
|
1812
1422
|
|
|
1813
1423
|
@property
|
|
1814
1424
|
def fuel_level(self) -> int:
|
|
1815
|
-
"""
|
|
1425
|
+
"""
|
|
1426
|
+
Return fuel level.
|
|
1816
1427
|
|
|
1817
1428
|
:return:
|
|
1818
1429
|
"""
|
|
1819
1430
|
fuel_level_pct = ""
|
|
1820
|
-
if (
|
|
1821
|
-
is_valid_path(
|
|
1822
|
-
self.attrs,
|
|
1823
|
-
f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.currentFuelLevel_pct",
|
|
1824
|
-
)
|
|
1825
|
-
and not self.is_primary_drive_gas()
|
|
1826
|
-
):
|
|
1431
|
+
if is_valid_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.currentFuelLevel_pct"):
|
|
1827
1432
|
fuel_level_pct = find_path(
|
|
1828
|
-
self.attrs,
|
|
1829
|
-
f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.currentFuelLevel_pct",
|
|
1433
|
+
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.currentFuelLevel_pct"
|
|
1830
1434
|
)
|
|
1831
1435
|
|
|
1832
|
-
if is_valid_path(
|
|
1833
|
-
self.attrs,
|
|
1834
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.currentFuelLevel_pct",
|
|
1835
|
-
):
|
|
1436
|
+
if is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.currentFuelLevel_pct"):
|
|
1836
1437
|
fuel_level_pct = find_path(
|
|
1837
|
-
self.attrs,
|
|
1838
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.currentFuelLevel_pct",
|
|
1438
|
+
self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.currentFuelLevel_pct"
|
|
1839
1439
|
)
|
|
1840
1440
|
return fuel_level_pct
|
|
1841
1441
|
|
|
@@ -1843,162 +1443,58 @@ class Vehicle:
|
|
|
1843
1443
|
def fuel_level_last_updated(self) -> datetime:
|
|
1844
1444
|
"""Return fuel level last updated."""
|
|
1845
1445
|
fuel_level_lastupdated = ""
|
|
1846
|
-
if is_valid_path(
|
|
1847
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carCapturedTimestamp"
|
|
1848
|
-
):
|
|
1446
|
+
if is_valid_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carCapturedTimestamp"):
|
|
1849
1447
|
fuel_level_lastupdated = find_path(
|
|
1850
|
-
self.attrs,
|
|
1851
|
-
f"{Services.FUEL_STATUS}.rangeStatus.value.carCapturedTimestamp",
|
|
1448
|
+
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carCapturedTimestamp"
|
|
1852
1449
|
)
|
|
1853
1450
|
|
|
1854
|
-
if is_valid_path(
|
|
1855
|
-
self.attrs,
|
|
1856
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carCapturedTimestamp",
|
|
1857
|
-
):
|
|
1451
|
+
if is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carCapturedTimestamp"):
|
|
1858
1452
|
fuel_level_lastupdated = find_path(
|
|
1859
|
-
self.attrs,
|
|
1860
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carCapturedTimestamp",
|
|
1453
|
+
self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carCapturedTimestamp"
|
|
1861
1454
|
)
|
|
1862
1455
|
return fuel_level_lastupdated
|
|
1863
1456
|
|
|
1864
1457
|
@property
|
|
1865
1458
|
def is_fuel_level_supported(self) -> bool:
|
|
1866
|
-
"""Return true if fuel level reporting is supported.
|
|
1867
|
-
|
|
1868
|
-
:return:
|
|
1869
|
-
"""
|
|
1870
|
-
return (
|
|
1871
|
-
is_valid_path(
|
|
1872
|
-
self.attrs,
|
|
1873
|
-
f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.currentFuelLevel_pct",
|
|
1874
|
-
)
|
|
1875
|
-
and not self.is_primary_drive_gas()
|
|
1876
|
-
) or is_valid_path(
|
|
1877
|
-
self.attrs,
|
|
1878
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.currentFuelLevel_pct",
|
|
1879
|
-
)
|
|
1880
|
-
|
|
1881
|
-
@property
|
|
1882
|
-
def gas_level(self) -> int:
|
|
1883
|
-
"""Return gas level.
|
|
1884
|
-
|
|
1885
|
-
:return:
|
|
1886
1459
|
"""
|
|
1887
|
-
|
|
1888
|
-
if (
|
|
1889
|
-
is_valid_path(
|
|
1890
|
-
self.attrs,
|
|
1891
|
-
f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.currentFuelLevel_pct",
|
|
1892
|
-
)
|
|
1893
|
-
and self.is_primary_drive_gas()
|
|
1894
|
-
):
|
|
1895
|
-
gas_level_pct = find_path(
|
|
1896
|
-
self.attrs,
|
|
1897
|
-
f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.currentFuelLevel_pct",
|
|
1898
|
-
)
|
|
1899
|
-
|
|
1900
|
-
if is_valid_path(
|
|
1901
|
-
self.attrs,
|
|
1902
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.currentCngLevel_pct",
|
|
1903
|
-
):
|
|
1904
|
-
gas_level_pct = find_path(
|
|
1905
|
-
self.attrs,
|
|
1906
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.currentCngLevel_pct",
|
|
1907
|
-
)
|
|
1908
|
-
return gas_level_pct
|
|
1909
|
-
|
|
1910
|
-
@property
|
|
1911
|
-
def gas_level_last_updated(self) -> datetime:
|
|
1912
|
-
"""Return gas level last updated."""
|
|
1913
|
-
gas_level_lastupdated = ""
|
|
1914
|
-
if (
|
|
1915
|
-
is_valid_path(
|
|
1916
|
-
self.attrs,
|
|
1917
|
-
f"{Services.FUEL_STATUS}.rangeStatus.value.carCapturedTimestamp",
|
|
1918
|
-
)
|
|
1919
|
-
and self.is_primary_drive_gas()
|
|
1920
|
-
):
|
|
1921
|
-
gas_level_lastupdated = find_path(
|
|
1922
|
-
self.attrs,
|
|
1923
|
-
f"{Services.FUEL_STATUS}.rangeStatus.value.carCapturedTimestamp",
|
|
1924
|
-
)
|
|
1925
|
-
|
|
1926
|
-
if is_valid_path(
|
|
1927
|
-
self.attrs,
|
|
1928
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carCapturedTimestamp",
|
|
1929
|
-
):
|
|
1930
|
-
gas_level_lastupdated = find_path(
|
|
1931
|
-
self.attrs,
|
|
1932
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carCapturedTimestamp",
|
|
1933
|
-
)
|
|
1934
|
-
return gas_level_lastupdated
|
|
1935
|
-
|
|
1936
|
-
@property
|
|
1937
|
-
def is_gas_level_supported(self) -> bool:
|
|
1938
|
-
"""Return true if gas level reporting is supported.
|
|
1460
|
+
Return true if fuel level reporting is supported.
|
|
1939
1461
|
|
|
1940
1462
|
:return:
|
|
1941
1463
|
"""
|
|
1942
|
-
return (
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.currentFuelLevel_pct",
|
|
1946
|
-
)
|
|
1947
|
-
and self.is_primary_drive_gas()
|
|
1948
|
-
) or is_valid_path(
|
|
1949
|
-
self.attrs,
|
|
1950
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.currentCngLevel_pct",
|
|
1951
|
-
)
|
|
1464
|
+
return is_valid_path(
|
|
1465
|
+
self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.currentFuelLevel_pct"
|
|
1466
|
+
) or is_valid_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.currentFuelLevel_pct")
|
|
1952
1467
|
|
|
1953
1468
|
@property
|
|
1954
1469
|
def car_type(self) -> str:
|
|
1955
|
-
"""
|
|
1470
|
+
"""
|
|
1471
|
+
Return car type.
|
|
1956
1472
|
|
|
1957
1473
|
:return:
|
|
1958
1474
|
"""
|
|
1959
|
-
if is_valid_path(
|
|
1960
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"
|
|
1961
|
-
):
|
|
1962
|
-
return find_path(
|
|
1963
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"
|
|
1964
|
-
).capitalize()
|
|
1965
|
-
if is_valid_path(
|
|
1966
|
-
self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"
|
|
1967
|
-
):
|
|
1968
|
-
return find_path(
|
|
1969
|
-
self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"
|
|
1970
|
-
).capitalize()
|
|
1475
|
+
if is_valid_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"):
|
|
1476
|
+
return find_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType").capitalize()
|
|
1477
|
+
if is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"):
|
|
1478
|
+
return find_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType").capitalize()
|
|
1971
1479
|
return "Unknown"
|
|
1972
1480
|
|
|
1973
1481
|
@property
|
|
1974
1482
|
def car_type_last_updated(self) -> datetime | None:
|
|
1975
1483
|
"""Return car type last updated."""
|
|
1976
|
-
if is_valid_path(
|
|
1977
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carCapturedTimestamp"
|
|
1978
|
-
):
|
|
1979
|
-
return find_path(
|
|
1980
|
-
self.attrs,
|
|
1981
|
-
f"{Services.FUEL_STATUS}.rangeStatus.value.carCapturedTimestamp",
|
|
1982
|
-
)
|
|
1983
|
-
if is_valid_path(
|
|
1984
|
-
self.attrs,
|
|
1985
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carCapturedTimestamp",
|
|
1986
|
-
):
|
|
1987
|
-
return find_path(
|
|
1988
|
-
self.attrs,
|
|
1989
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carCapturedTimestamp",
|
|
1990
|
-
)
|
|
1484
|
+
if is_valid_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carCapturedTimestamp"):
|
|
1485
|
+
return find_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carCapturedTimestamp")
|
|
1486
|
+
if is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carCapturedTimestamp"):
|
|
1487
|
+
return find_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carCapturedTimestamp")
|
|
1991
1488
|
return None
|
|
1992
1489
|
|
|
1993
1490
|
@property
|
|
1994
1491
|
def is_car_type_supported(self) -> bool:
|
|
1995
|
-
"""
|
|
1492
|
+
"""
|
|
1493
|
+
Return true if car type is supported.
|
|
1996
1494
|
|
|
1997
1495
|
:return:
|
|
1998
1496
|
"""
|
|
1999
|
-
return is_valid_path(
|
|
2000
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"
|
|
2001
|
-
) or is_valid_path(
|
|
1497
|
+
return is_valid_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType") or is_valid_path(
|
|
2002
1498
|
self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"
|
|
2003
1499
|
)
|
|
2004
1500
|
|
|
@@ -2006,167 +1502,109 @@ class Vehicle:
|
|
|
2006
1502
|
@property
|
|
2007
1503
|
def climatisation_target_temperature(self) -> float | None:
|
|
2008
1504
|
"""Return the target temperature from climater."""
|
|
2009
|
-
# TODO should we handle Fahrenheit??
|
|
2010
|
-
return float(
|
|
2011
|
-
find_path(
|
|
2012
|
-
self.attrs,
|
|
2013
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.targetTemperature_C",
|
|
2014
|
-
)
|
|
2015
|
-
)
|
|
1505
|
+
# TODO should we handle Fahrenheit??
|
|
1506
|
+
return float(find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.targetTemperature_C"))
|
|
2016
1507
|
|
|
2017
1508
|
@property
|
|
2018
1509
|
def climatisation_target_temperature_last_updated(self) -> datetime:
|
|
2019
1510
|
"""Return the target temperature from climater last updated."""
|
|
2020
|
-
return find_path(
|
|
2021
|
-
self.attrs,
|
|
2022
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.carCapturedTimestamp",
|
|
2023
|
-
)
|
|
1511
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.carCapturedTimestamp")
|
|
2024
1512
|
|
|
2025
1513
|
@property
|
|
2026
1514
|
def is_climatisation_target_temperature_supported(self) -> bool:
|
|
2027
1515
|
"""Return true if climatisation target temperature is supported."""
|
|
2028
|
-
return is_valid_path(
|
|
2029
|
-
self.attrs,
|
|
2030
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.targetTemperature_C",
|
|
2031
|
-
)
|
|
1516
|
+
return is_valid_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.targetTemperature_C")
|
|
2032
1517
|
|
|
2033
1518
|
@property
|
|
2034
1519
|
def climatisation_without_external_power(self):
|
|
2035
1520
|
"""Return state of climatisation from battery power."""
|
|
2036
1521
|
return find_path(
|
|
2037
|
-
self.attrs,
|
|
2038
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.climatisationWithoutExternalPower",
|
|
1522
|
+
self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.climatisationWithoutExternalPower"
|
|
2039
1523
|
)
|
|
2040
1524
|
|
|
2041
1525
|
@property
|
|
2042
1526
|
def climatisation_without_external_power_last_updated(self) -> datetime:
|
|
2043
1527
|
"""Return state of climatisation from battery power last updated."""
|
|
2044
|
-
return find_path(
|
|
2045
|
-
self.attrs,
|
|
2046
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.carCapturedTimestamp",
|
|
2047
|
-
)
|
|
1528
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.carCapturedTimestamp")
|
|
2048
1529
|
|
|
2049
1530
|
@property
|
|
2050
1531
|
def is_climatisation_without_external_power_supported(self) -> bool:
|
|
2051
1532
|
"""Return true if climatisation on battery power is supported."""
|
|
2052
1533
|
return is_valid_path(
|
|
2053
|
-
self.attrs,
|
|
2054
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.climatisationWithoutExternalPower",
|
|
1534
|
+
self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.climatisationWithoutExternalPower"
|
|
2055
1535
|
)
|
|
2056
1536
|
|
|
2057
1537
|
@property
|
|
2058
1538
|
def auxiliary_air_conditioning(self):
|
|
2059
1539
|
"""Return state of auxiliary air conditioning."""
|
|
2060
|
-
return find_path(
|
|
2061
|
-
self.attrs,
|
|
2062
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.climatizationAtUnlock",
|
|
2063
|
-
)
|
|
1540
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.climatizationAtUnlock")
|
|
2064
1541
|
|
|
2065
1542
|
@property
|
|
2066
1543
|
def auxiliary_air_conditioning_last_updated(self) -> datetime:
|
|
2067
1544
|
"""Return state of auxiliary air conditioning last updated."""
|
|
2068
|
-
return find_path(
|
|
2069
|
-
self.attrs,
|
|
2070
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.carCapturedTimestamp",
|
|
2071
|
-
)
|
|
1545
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.carCapturedTimestamp")
|
|
2072
1546
|
|
|
2073
1547
|
@property
|
|
2074
1548
|
def is_auxiliary_air_conditioning_supported(self) -> bool:
|
|
2075
1549
|
"""Return true if auxiliary air conditioning is supported."""
|
|
2076
|
-
return is_valid_path(
|
|
2077
|
-
self.attrs,
|
|
2078
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.climatizationAtUnlock",
|
|
2079
|
-
)
|
|
1550
|
+
return is_valid_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.climatizationAtUnlock")
|
|
2080
1551
|
|
|
2081
1552
|
@property
|
|
2082
1553
|
def automatic_window_heating(self):
|
|
2083
1554
|
"""Return state of automatic window heating."""
|
|
2084
|
-
return find_path(
|
|
2085
|
-
self.attrs,
|
|
2086
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.windowHeatingEnabled",
|
|
2087
|
-
)
|
|
1555
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.windowHeatingEnabled")
|
|
2088
1556
|
|
|
2089
1557
|
@property
|
|
2090
1558
|
def automatic_window_heating_last_updated(self) -> datetime:
|
|
2091
1559
|
"""Return state of automatic window heating last updated."""
|
|
2092
|
-
return find_path(
|
|
2093
|
-
self.attrs,
|
|
2094
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.carCapturedTimestamp",
|
|
2095
|
-
)
|
|
1560
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.carCapturedTimestamp")
|
|
2096
1561
|
|
|
2097
1562
|
@property
|
|
2098
1563
|
def is_automatic_window_heating_supported(self) -> bool:
|
|
2099
1564
|
"""Return true if automatic window heating is supported."""
|
|
2100
|
-
return is_valid_path(
|
|
2101
|
-
self.attrs,
|
|
2102
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.windowHeatingEnabled",
|
|
2103
|
-
)
|
|
1565
|
+
return is_valid_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.windowHeatingEnabled")
|
|
2104
1566
|
|
|
2105
1567
|
@property
|
|
2106
1568
|
def zone_front_left(self):
|
|
2107
1569
|
"""Return state of zone front left."""
|
|
2108
|
-
return find_path(
|
|
2109
|
-
self.attrs,
|
|
2110
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.zoneFrontLeftEnabled",
|
|
2111
|
-
)
|
|
1570
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.zoneFrontLeftEnabled")
|
|
2112
1571
|
|
|
2113
1572
|
@property
|
|
2114
1573
|
def zone_front_left_last_updated(self) -> datetime:
|
|
2115
1574
|
"""Return state of zone front left last updated."""
|
|
2116
|
-
return find_path(
|
|
2117
|
-
self.attrs,
|
|
2118
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.carCapturedTimestamp",
|
|
2119
|
-
)
|
|
1575
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.carCapturedTimestamp")
|
|
2120
1576
|
|
|
2121
1577
|
@property
|
|
2122
1578
|
def is_zone_front_left_supported(self) -> bool:
|
|
2123
1579
|
"""Return true if zone front left is supported."""
|
|
2124
|
-
return is_valid_path(
|
|
2125
|
-
self.attrs,
|
|
2126
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.zoneFrontLeftEnabled",
|
|
2127
|
-
)
|
|
1580
|
+
return is_valid_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.zoneFrontLeftEnabled")
|
|
2128
1581
|
|
|
2129
1582
|
@property
|
|
2130
1583
|
def zone_front_right(self):
|
|
2131
1584
|
"""Return state of zone front left."""
|
|
2132
|
-
return find_path(
|
|
2133
|
-
self.attrs,
|
|
2134
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.zoneFrontRightEnabled",
|
|
2135
|
-
)
|
|
1585
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.zoneFrontRightEnabled")
|
|
2136
1586
|
|
|
2137
1587
|
@property
|
|
2138
1588
|
def zone_front_right_last_updated(self) -> datetime:
|
|
2139
1589
|
"""Return state of zone front left last updated."""
|
|
2140
|
-
return find_path(
|
|
2141
|
-
self.attrs,
|
|
2142
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.carCapturedTimestamp",
|
|
2143
|
-
)
|
|
1590
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.carCapturedTimestamp")
|
|
2144
1591
|
|
|
2145
1592
|
@property
|
|
2146
1593
|
def is_zone_front_right_supported(self) -> bool:
|
|
2147
1594
|
"""Return true if zone front left is supported."""
|
|
2148
|
-
return is_valid_path(
|
|
2149
|
-
self.attrs,
|
|
2150
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.zoneFrontRightEnabled",
|
|
2151
|
-
)
|
|
1595
|
+
return is_valid_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.zoneFrontRightEnabled")
|
|
2152
1596
|
|
|
2153
1597
|
# Climatisation, electric
|
|
2154
1598
|
@property
|
|
2155
1599
|
def electric_climatisation(self) -> bool:
|
|
2156
1600
|
"""Return status of climatisation."""
|
|
2157
|
-
status = find_path(
|
|
2158
|
-
self.attrs,
|
|
2159
|
-
f"{Services.CLIMATISATION}.climatisationStatus.value.climatisationState",
|
|
2160
|
-
)
|
|
1601
|
+
status = find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationStatus.value.climatisationState")
|
|
2161
1602
|
return status in ["ventilation", "heating", "cooling", "on"]
|
|
2162
1603
|
|
|
2163
1604
|
@property
|
|
2164
1605
|
def electric_climatisation_last_updated(self) -> datetime:
|
|
2165
1606
|
"""Return status of climatisation last updated."""
|
|
2166
|
-
return find_path(
|
|
2167
|
-
self.attrs,
|
|
2168
|
-
f"{Services.CLIMATISATION}.climatisationStatus.value.carCapturedTimestamp",
|
|
2169
|
-
)
|
|
1607
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationStatus.value.carCapturedTimestamp")
|
|
2170
1608
|
|
|
2171
1609
|
@property
|
|
2172
1610
|
def is_electric_climatisation_supported(self) -> bool:
|
|
@@ -2185,45 +1623,32 @@ class Vehicle:
|
|
|
2185
1623
|
def electric_remaining_climatisation_time(self) -> int:
|
|
2186
1624
|
"""Return remaining climatisation time for electric climatisation."""
|
|
2187
1625
|
return find_path(
|
|
2188
|
-
self.attrs,
|
|
2189
|
-
f"{Services.CLIMATISATION}.climatisationStatus.value.remainingClimatisationTime_min",
|
|
1626
|
+
self.attrs, f"{Services.CLIMATISATION}.climatisationStatus.value.remainingClimatisationTime_min"
|
|
2190
1627
|
)
|
|
2191
1628
|
|
|
2192
1629
|
@property
|
|
2193
1630
|
def electric_remaining_climatisation_time_last_updated(self) -> bool:
|
|
2194
1631
|
"""Return status of electric climatisation remaining climatisation time last updated."""
|
|
2195
|
-
return find_path(
|
|
2196
|
-
self.attrs,
|
|
2197
|
-
f"{Services.CLIMATISATION}.climatisationStatus.value.carCapturedTimestamp",
|
|
2198
|
-
)
|
|
1632
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationStatus.value.carCapturedTimestamp")
|
|
2199
1633
|
|
|
2200
1634
|
@property
|
|
2201
1635
|
def is_electric_remaining_climatisation_time_supported(self) -> bool:
|
|
2202
1636
|
"""Return true if electric climatisation remaining climatisation time is supported."""
|
|
2203
1637
|
return is_valid_path(
|
|
2204
|
-
self.attrs,
|
|
2205
|
-
f"{Services.CLIMATISATION}.climatisationStatus.value.remainingClimatisationTime_min",
|
|
1638
|
+
self.attrs, f"{Services.CLIMATISATION}.climatisationStatus.value.remainingClimatisationTime_min"
|
|
2206
1639
|
)
|
|
2207
1640
|
|
|
2208
1641
|
@property
|
|
2209
1642
|
def auxiliary_climatisation(self) -> bool:
|
|
2210
1643
|
"""Return status of auxiliary climatisation."""
|
|
2211
1644
|
climatisation_state = None
|
|
2212
|
-
if is_valid_path(
|
|
2213
|
-
self.attrs,
|
|
2214
|
-
f"{Services.CLIMATISATION}.auxiliaryHeatingStatus.value.climatisationState",
|
|
2215
|
-
):
|
|
1645
|
+
if is_valid_path(self.attrs, f"{Services.CLIMATISATION}.auxiliaryHeatingStatus.value.climatisationState"):
|
|
2216
1646
|
climatisation_state = find_path(
|
|
2217
|
-
self.attrs,
|
|
2218
|
-
f"{Services.CLIMATISATION}.auxiliaryHeatingStatus.value.climatisationState",
|
|
1647
|
+
self.attrs, f"{Services.CLIMATISATION}.auxiliaryHeatingStatus.value.climatisationState"
|
|
2219
1648
|
)
|
|
2220
|
-
if is_valid_path(
|
|
2221
|
-
self.attrs,
|
|
2222
|
-
f"{Services.CLIMATISATION}.climatisationStatus.value.climatisationState",
|
|
2223
|
-
):
|
|
1649
|
+
if is_valid_path(self.attrs, f"{Services.CLIMATISATION}.climatisationStatus.value.climatisationState"):
|
|
2224
1650
|
climatisation_state = find_path(
|
|
2225
|
-
self.attrs,
|
|
2226
|
-
f"{Services.CLIMATISATION}.climatisationStatus.value.climatisationState",
|
|
1651
|
+
self.attrs, f"{Services.CLIMATISATION}.climatisationStatus.value.climatisationState"
|
|
2227
1652
|
)
|
|
2228
1653
|
if climatisation_state in ["heating", "heatingAuxiliary", "on"]:
|
|
2229
1654
|
return True
|
|
@@ -2232,115 +1657,80 @@ class Vehicle:
|
|
|
2232
1657
|
@property
|
|
2233
1658
|
def auxiliary_climatisation_last_updated(self) -> datetime:
|
|
2234
1659
|
"""Return status of auxiliary climatisation last updated."""
|
|
2235
|
-
if is_valid_path(
|
|
2236
|
-
self.attrs,
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
return find_path(
|
|
2240
|
-
self.attrs,
|
|
2241
|
-
f"{Services.CLIMATISATION}.auxiliaryHeatingStatus.value.carCapturedTimestamp",
|
|
2242
|
-
)
|
|
2243
|
-
if is_valid_path(
|
|
2244
|
-
self.attrs,
|
|
2245
|
-
f"{Services.CLIMATISATION}.climatisationStatus.value.carCapturedTimestamp",
|
|
2246
|
-
):
|
|
2247
|
-
return find_path(
|
|
2248
|
-
self.attrs,
|
|
2249
|
-
f"{Services.CLIMATISATION}.climatisationStatus.value.carCapturedTimestamp",
|
|
2250
|
-
)
|
|
1660
|
+
if is_valid_path(self.attrs, f"{Services.CLIMATISATION}.auxiliaryHeatingStatus.value.carCapturedTimestamp"):
|
|
1661
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.auxiliaryHeatingStatus.value.carCapturedTimestamp")
|
|
1662
|
+
if is_valid_path(self.attrs, f"{Services.CLIMATISATION}.climatisationStatus.value.carCapturedTimestamp"):
|
|
1663
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationStatus.value.carCapturedTimestamp")
|
|
2251
1664
|
return None
|
|
2252
1665
|
|
|
2253
1666
|
@property
|
|
2254
1667
|
def is_auxiliary_climatisation_supported(self) -> bool:
|
|
2255
1668
|
"""Return true if vehicle has auxiliary climatisation."""
|
|
2256
|
-
if is_valid_path(
|
|
2257
|
-
self.attrs,
|
|
2258
|
-
f"{Services.CLIMATISATION}.auxiliaryHeatingStatus.value.climatisationState",
|
|
2259
|
-
):
|
|
1669
|
+
if is_valid_path(self.attrs, f"{Services.CLIMATISATION}.auxiliaryHeatingStatus.value.climatisationState"):
|
|
2260
1670
|
return True
|
|
2261
|
-
if is_valid_path(
|
|
2262
|
-
self.attrs, f"{Services.USER_CAPABILITIES}.capabilitiesStatus.value"
|
|
2263
|
-
):
|
|
2264
|
-
capabilities = find_path(
|
|
2265
|
-
self.attrs, f"{Services.USER_CAPABILITIES}.capabilitiesStatus.value"
|
|
2266
|
-
)
|
|
1671
|
+
if is_valid_path(self.attrs, f"{Services.USER_CAPABILITIES}.capabilitiesStatus.value"):
|
|
1672
|
+
capabilities = find_path(self.attrs, f"{Services.USER_CAPABILITIES}.capabilitiesStatus.value")
|
|
2267
1673
|
for capability in capabilities:
|
|
2268
1674
|
if capability.get("id", None) == "hybridCarAuxiliaryHeating":
|
|
2269
1675
|
if 1007 in capability.get("status", []):
|
|
2270
1676
|
return False
|
|
2271
|
-
|
|
1677
|
+
else:
|
|
1678
|
+
return True
|
|
2272
1679
|
return False
|
|
2273
1680
|
|
|
2274
1681
|
@property
|
|
2275
1682
|
def auxiliary_duration(self) -> int:
|
|
2276
1683
|
"""Return heating duration for auxiliary heater."""
|
|
2277
1684
|
return find_path(
|
|
2278
|
-
self.attrs,
|
|
2279
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.auxiliaryHeatingSettings.duration_min",
|
|
1685
|
+
self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.auxiliaryHeatingSettings.duration_min"
|
|
2280
1686
|
)
|
|
2281
1687
|
|
|
2282
1688
|
@property
|
|
2283
1689
|
def auxiliary_duration_last_updated(self) -> bool:
|
|
2284
1690
|
"""Return status of auxiliary heater last updated."""
|
|
2285
|
-
return find_path(
|
|
2286
|
-
self.attrs,
|
|
2287
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.carCapturedTimestamp",
|
|
2288
|
-
)
|
|
1691
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.carCapturedTimestamp")
|
|
2289
1692
|
|
|
2290
1693
|
@property
|
|
2291
1694
|
def is_auxiliary_duration_supported(self) -> bool:
|
|
2292
1695
|
"""Return true if auxiliary heater is supported."""
|
|
2293
1696
|
return is_valid_path(
|
|
2294
|
-
self.attrs,
|
|
2295
|
-
f"{Services.CLIMATISATION}.climatisationSettings.value.auxiliaryHeatingSettings.duration_min",
|
|
1697
|
+
self.attrs, f"{Services.CLIMATISATION}.climatisationSettings.value.auxiliaryHeatingSettings.duration_min"
|
|
2296
1698
|
)
|
|
2297
1699
|
|
|
2298
1700
|
@property
|
|
2299
1701
|
def auxiliary_remaining_climatisation_time(self) -> int:
|
|
2300
1702
|
"""Return remaining climatisation time for auxiliary heater."""
|
|
2301
1703
|
return find_path(
|
|
2302
|
-
self.attrs,
|
|
2303
|
-
f"{Services.CLIMATISATION}.auxiliaryHeatingStatus.value.remainingClimatisationTime_min",
|
|
1704
|
+
self.attrs, f"{Services.CLIMATISATION}.auxiliaryHeatingStatus.value.remainingClimatisationTime_min"
|
|
2304
1705
|
)
|
|
2305
1706
|
|
|
2306
1707
|
@property
|
|
2307
1708
|
def auxiliary_remaining_climatisation_time_last_updated(self) -> bool:
|
|
2308
1709
|
"""Return status of auxiliary heater remaining climatisation time last updated."""
|
|
2309
|
-
return find_path(
|
|
2310
|
-
self.attrs,
|
|
2311
|
-
f"{Services.CLIMATISATION}.auxiliaryHeatingStatus.value.carCapturedTimestamp",
|
|
2312
|
-
)
|
|
1710
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.auxiliaryHeatingStatus.value.carCapturedTimestamp")
|
|
2313
1711
|
|
|
2314
1712
|
@property
|
|
2315
1713
|
def is_auxiliary_remaining_climatisation_time_supported(self) -> bool:
|
|
2316
1714
|
"""Return true if auxiliary heater remaining climatisation time is supported."""
|
|
2317
1715
|
return is_valid_path(
|
|
2318
|
-
self.attrs,
|
|
2319
|
-
f"{Services.CLIMATISATION}.auxiliaryHeatingStatus.value.remainingClimatisationTime_min",
|
|
1716
|
+
self.attrs, f"{Services.CLIMATISATION}.auxiliaryHeatingStatus.value.remainingClimatisationTime_min"
|
|
2320
1717
|
)
|
|
2321
1718
|
|
|
2322
1719
|
@property
|
|
2323
1720
|
def is_climatisation_supported(self) -> bool:
|
|
2324
1721
|
"""Return true if climatisation has State."""
|
|
2325
|
-
return is_valid_path(
|
|
2326
|
-
self.attrs,
|
|
2327
|
-
f"{Services.CLIMATISATION}.climatisationStatus.value.climatisationState",
|
|
2328
|
-
)
|
|
1722
|
+
return is_valid_path(self.attrs, f"{Services.CLIMATISATION}.climatisationStatus.value.climatisationState")
|
|
2329
1723
|
|
|
2330
1724
|
@property
|
|
2331
1725
|
def is_climatisation_supported_last_updated(self) -> datetime:
|
|
2332
1726
|
"""Return attribute last updated timestamp."""
|
|
2333
|
-
return find_path(
|
|
2334
|
-
self.attrs,
|
|
2335
|
-
f"{Services.CLIMATISATION}.climatisationStatus.value.carCapturedTimestamp",
|
|
2336
|
-
)
|
|
1727
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.climatisationStatus.value.carCapturedTimestamp")
|
|
2337
1728
|
|
|
2338
1729
|
@property
|
|
2339
1730
|
def window_heater_front(self) -> bool:
|
|
2340
1731
|
"""Return status of front window heater."""
|
|
2341
1732
|
window_heating_status = find_path(
|
|
2342
|
-
self.attrs,
|
|
2343
|
-
f"{Services.CLIMATISATION}.windowHeatingStatus.value.windowHeatingStatus",
|
|
1733
|
+
self.attrs, f"{Services.CLIMATISATION}.windowHeatingStatus.value.windowHeatingStatus"
|
|
2344
1734
|
)
|
|
2345
1735
|
for window_heating_state in window_heating_status:
|
|
2346
1736
|
if window_heating_state["windowLocation"] == "front":
|
|
@@ -2351,25 +1741,18 @@ class Vehicle:
|
|
|
2351
1741
|
@property
|
|
2352
1742
|
def window_heater_front_last_updated(self) -> datetime:
|
|
2353
1743
|
"""Return front window heater last updated."""
|
|
2354
|
-
return find_path(
|
|
2355
|
-
self.attrs,
|
|
2356
|
-
f"{Services.CLIMATISATION}.windowHeatingStatus.value.carCapturedTimestamp",
|
|
2357
|
-
)
|
|
1744
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.windowHeatingStatus.value.carCapturedTimestamp")
|
|
2358
1745
|
|
|
2359
1746
|
@property
|
|
2360
1747
|
def is_window_heater_front_supported(self) -> bool:
|
|
2361
1748
|
"""Return true if vehicle has heater."""
|
|
2362
|
-
return is_valid_path(
|
|
2363
|
-
self.attrs,
|
|
2364
|
-
f"{Services.CLIMATISATION}.windowHeatingStatus.value.windowHeatingStatus",
|
|
2365
|
-
)
|
|
1749
|
+
return is_valid_path(self.attrs, f"{Services.CLIMATISATION}.windowHeatingStatus.value.windowHeatingStatus")
|
|
2366
1750
|
|
|
2367
1751
|
@property
|
|
2368
1752
|
def window_heater_back(self) -> bool:
|
|
2369
1753
|
"""Return status of rear window heater."""
|
|
2370
1754
|
window_heating_status = find_path(
|
|
2371
|
-
self.attrs,
|
|
2372
|
-
f"{Services.CLIMATISATION}.windowHeatingStatus.value.windowHeatingStatus",
|
|
1755
|
+
self.attrs, f"{Services.CLIMATISATION}.windowHeatingStatus.value.windowHeatingStatus"
|
|
2373
1756
|
)
|
|
2374
1757
|
for window_heating_state in window_heating_status:
|
|
2375
1758
|
if window_heating_state["windowLocation"] == "rear":
|
|
@@ -2380,18 +1763,12 @@ class Vehicle:
|
|
|
2380
1763
|
@property
|
|
2381
1764
|
def window_heater_back_last_updated(self) -> datetime:
|
|
2382
1765
|
"""Return front window heater last updated."""
|
|
2383
|
-
return find_path(
|
|
2384
|
-
self.attrs,
|
|
2385
|
-
f"{Services.CLIMATISATION}.windowHeatingStatus.value.carCapturedTimestamp",
|
|
2386
|
-
)
|
|
1766
|
+
return find_path(self.attrs, f"{Services.CLIMATISATION}.windowHeatingStatus.value.carCapturedTimestamp")
|
|
2387
1767
|
|
|
2388
1768
|
@property
|
|
2389
1769
|
def is_window_heater_back_supported(self) -> bool:
|
|
2390
1770
|
"""Return true if vehicle has heater."""
|
|
2391
|
-
return is_valid_path(
|
|
2392
|
-
self.attrs,
|
|
2393
|
-
f"{Services.CLIMATISATION}.windowHeatingStatus.value.windowHeatingStatus",
|
|
2394
|
-
)
|
|
1771
|
+
return is_valid_path(self.attrs, f"{Services.CLIMATISATION}.windowHeatingStatus.value.windowHeatingStatus")
|
|
2395
1772
|
|
|
2396
1773
|
@property
|
|
2397
1774
|
def window_heater(self) -> bool:
|
|
@@ -2407,50 +1784,29 @@ class Vehicle:
|
|
|
2407
1784
|
def is_window_heater_supported(self) -> bool:
|
|
2408
1785
|
"""Return true if vehicle has heater."""
|
|
2409
1786
|
# ID models detection
|
|
2410
|
-
if (
|
|
2411
|
-
self._services.get(Services.PARAMETERS, {}).get(
|
|
2412
|
-
"supportsStartWindowHeating", "false"
|
|
2413
|
-
)
|
|
2414
|
-
== "true"
|
|
2415
|
-
):
|
|
1787
|
+
if self._services.get(Services.PARAMETERS, {}).get("supportsStartWindowHeating", "false") == "true":
|
|
2416
1788
|
return True
|
|
2417
1789
|
# "Legacy" models detection
|
|
2418
|
-
parameters = self._services.get(Services.CLIMATISATION, {}).get(
|
|
2419
|
-
"parameters", None
|
|
2420
|
-
)
|
|
1790
|
+
parameters = self._services.get(Services.CLIMATISATION, {}).get("parameters", None)
|
|
2421
1791
|
if parameters:
|
|
2422
1792
|
for parameter in parameters:
|
|
2423
|
-
if
|
|
2424
|
-
parameter["key"] == "supportsStartWindowHeating"
|
|
2425
|
-
and parameter["value"] == "true"
|
|
2426
|
-
):
|
|
1793
|
+
if parameter["key"] == "supportsStartWindowHeating" and parameter["value"] == "true":
|
|
2427
1794
|
return True
|
|
2428
1795
|
return False
|
|
2429
1796
|
|
|
2430
1797
|
# Windows
|
|
2431
1798
|
@property
|
|
2432
1799
|
def windows_closed(self) -> bool:
|
|
2433
|
-
"""
|
|
1800
|
+
"""
|
|
1801
|
+
Return true if all supported windows are closed.
|
|
2434
1802
|
|
|
2435
1803
|
:return:
|
|
2436
1804
|
"""
|
|
2437
1805
|
return (
|
|
2438
|
-
(
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
)
|
|
2442
|
-
and (
|
|
2443
|
-
not self.is_window_closed_left_back_supported
|
|
2444
|
-
or self.window_closed_left_back
|
|
2445
|
-
)
|
|
2446
|
-
and (
|
|
2447
|
-
not self.is_window_closed_right_front_supported
|
|
2448
|
-
or self.window_closed_right_front
|
|
2449
|
-
)
|
|
2450
|
-
and (
|
|
2451
|
-
not self.is_window_closed_right_back_supported
|
|
2452
|
-
or self.window_closed_right_back
|
|
2453
|
-
)
|
|
1806
|
+
(not self.is_window_closed_left_front_supported or self.window_closed_left_front)
|
|
1807
|
+
and (not self.is_window_closed_left_back_supported or self.window_closed_left_back)
|
|
1808
|
+
and (not self.is_window_closed_right_front_supported or self.window_closed_right_front)
|
|
1809
|
+
and (not self.is_window_closed_right_back_supported or self.window_closed_right_back)
|
|
2454
1810
|
)
|
|
2455
1811
|
|
|
2456
1812
|
@property
|
|
@@ -2470,17 +1826,15 @@ class Vehicle:
|
|
|
2470
1826
|
|
|
2471
1827
|
@property
|
|
2472
1828
|
def window_closed_left_front(self) -> bool:
|
|
2473
|
-
"""
|
|
1829
|
+
"""
|
|
1830
|
+
Return left front window closed state.
|
|
2474
1831
|
|
|
2475
1832
|
:return:
|
|
2476
1833
|
"""
|
|
2477
1834
|
windows = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows")
|
|
2478
1835
|
for window in windows:
|
|
2479
1836
|
if window["name"] == "frontLeft":
|
|
2480
|
-
if not any(
|
|
2481
|
-
valid_status in window["status"]
|
|
2482
|
-
for valid_status in P.VALID_WINDOW_STATUS
|
|
2483
|
-
):
|
|
1837
|
+
if not any(valid_status in window["status"] for valid_status in P.VALID_WINDOW_STATUS):
|
|
2484
1838
|
return None
|
|
2485
1839
|
return "closed" in window["status"]
|
|
2486
1840
|
return False
|
|
@@ -2488,38 +1842,29 @@ class Vehicle:
|
|
|
2488
1842
|
@property
|
|
2489
1843
|
def window_closed_left_front_last_updated(self) -> datetime:
|
|
2490
1844
|
"""Return attribute last updated timestamp."""
|
|
2491
|
-
return find_path(
|
|
2492
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
2493
|
-
)
|
|
1845
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
2494
1846
|
|
|
2495
1847
|
@property
|
|
2496
1848
|
def is_window_closed_left_front_supported(self) -> bool:
|
|
2497
1849
|
"""Return true if supported."""
|
|
2498
1850
|
if is_valid_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows"):
|
|
2499
|
-
windows = find_path(
|
|
2500
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.windows"
|
|
2501
|
-
)
|
|
1851
|
+
windows = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows")
|
|
2502
1852
|
for window in windows:
|
|
2503
|
-
if
|
|
2504
|
-
window["name"] == "frontLeft"
|
|
2505
|
-
and "unsupported" not in window["status"]
|
|
2506
|
-
):
|
|
1853
|
+
if window["name"] == "frontLeft" and "unsupported" not in window["status"]:
|
|
2507
1854
|
return True
|
|
2508
1855
|
return False
|
|
2509
1856
|
|
|
2510
1857
|
@property
|
|
2511
1858
|
def window_closed_right_front(self) -> bool:
|
|
2512
|
-
"""
|
|
1859
|
+
"""
|
|
1860
|
+
Return right front window closed state.
|
|
2513
1861
|
|
|
2514
1862
|
:return:
|
|
2515
1863
|
"""
|
|
2516
1864
|
windows = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows")
|
|
2517
1865
|
for window in windows:
|
|
2518
1866
|
if window["name"] == "frontRight":
|
|
2519
|
-
if not any(
|
|
2520
|
-
valid_status in window["status"]
|
|
2521
|
-
for valid_status in P.VALID_WINDOW_STATUS
|
|
2522
|
-
):
|
|
1867
|
+
if not any(valid_status in window["status"] for valid_status in P.VALID_WINDOW_STATUS):
|
|
2523
1868
|
return None
|
|
2524
1869
|
return "closed" in window["status"]
|
|
2525
1870
|
return False
|
|
@@ -2527,38 +1872,29 @@ class Vehicle:
|
|
|
2527
1872
|
@property
|
|
2528
1873
|
def window_closed_right_front_last_updated(self) -> datetime:
|
|
2529
1874
|
"""Return attribute last updated timestamp."""
|
|
2530
|
-
return find_path(
|
|
2531
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
2532
|
-
)
|
|
1875
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
2533
1876
|
|
|
2534
1877
|
@property
|
|
2535
1878
|
def is_window_closed_right_front_supported(self) -> bool:
|
|
2536
1879
|
"""Return true if supported."""
|
|
2537
1880
|
if is_valid_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows"):
|
|
2538
|
-
windows = find_path(
|
|
2539
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.windows"
|
|
2540
|
-
)
|
|
1881
|
+
windows = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows")
|
|
2541
1882
|
for window in windows:
|
|
2542
|
-
if
|
|
2543
|
-
window["name"] == "frontRight"
|
|
2544
|
-
and "unsupported" not in window["status"]
|
|
2545
|
-
):
|
|
1883
|
+
if window["name"] == "frontRight" and "unsupported" not in window["status"]:
|
|
2546
1884
|
return True
|
|
2547
1885
|
return False
|
|
2548
1886
|
|
|
2549
1887
|
@property
|
|
2550
1888
|
def window_closed_left_back(self) -> bool:
|
|
2551
|
-
"""
|
|
1889
|
+
"""
|
|
1890
|
+
Return left back window closed state.
|
|
2552
1891
|
|
|
2553
1892
|
:return:
|
|
2554
1893
|
"""
|
|
2555
1894
|
windows = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows")
|
|
2556
1895
|
for window in windows:
|
|
2557
1896
|
if window["name"] == "rearLeft":
|
|
2558
|
-
if not any(
|
|
2559
|
-
valid_status in window["status"]
|
|
2560
|
-
for valid_status in P.VALID_WINDOW_STATUS
|
|
2561
|
-
):
|
|
1897
|
+
if not any(valid_status in window["status"] for valid_status in P.VALID_WINDOW_STATUS):
|
|
2562
1898
|
return None
|
|
2563
1899
|
return "closed" in window["status"]
|
|
2564
1900
|
return False
|
|
@@ -2566,38 +1902,29 @@ class Vehicle:
|
|
|
2566
1902
|
@property
|
|
2567
1903
|
def window_closed_left_back_last_updated(self) -> datetime:
|
|
2568
1904
|
"""Return attribute last updated timestamp."""
|
|
2569
|
-
return find_path(
|
|
2570
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
2571
|
-
)
|
|
1905
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
2572
1906
|
|
|
2573
1907
|
@property
|
|
2574
1908
|
def is_window_closed_left_back_supported(self) -> bool:
|
|
2575
1909
|
"""Return true if supported."""
|
|
2576
1910
|
if is_valid_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows"):
|
|
2577
|
-
windows = find_path(
|
|
2578
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.windows"
|
|
2579
|
-
)
|
|
1911
|
+
windows = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows")
|
|
2580
1912
|
for window in windows:
|
|
2581
|
-
if
|
|
2582
|
-
window["name"] == "rearLeft"
|
|
2583
|
-
and "unsupported" not in window["status"]
|
|
2584
|
-
):
|
|
1913
|
+
if window["name"] == "rearLeft" and "unsupported" not in window["status"]:
|
|
2585
1914
|
return True
|
|
2586
1915
|
return False
|
|
2587
1916
|
|
|
2588
1917
|
@property
|
|
2589
1918
|
def window_closed_right_back(self) -> bool:
|
|
2590
|
-
"""
|
|
1919
|
+
"""
|
|
1920
|
+
Return right back window closed state.
|
|
2591
1921
|
|
|
2592
1922
|
:return:
|
|
2593
1923
|
"""
|
|
2594
1924
|
windows = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows")
|
|
2595
1925
|
for window in windows:
|
|
2596
1926
|
if window["name"] == "rearRight":
|
|
2597
|
-
if not any(
|
|
2598
|
-
valid_status in window["status"]
|
|
2599
|
-
for valid_status in P.VALID_WINDOW_STATUS
|
|
2600
|
-
):
|
|
1927
|
+
if not any(valid_status in window["status"] for valid_status in P.VALID_WINDOW_STATUS):
|
|
2601
1928
|
return None
|
|
2602
1929
|
return "closed" in window["status"]
|
|
2603
1930
|
return False
|
|
@@ -2605,38 +1932,29 @@ class Vehicle:
|
|
|
2605
1932
|
@property
|
|
2606
1933
|
def window_closed_right_back_last_updated(self) -> datetime:
|
|
2607
1934
|
"""Return attribute last updated timestamp."""
|
|
2608
|
-
return find_path(
|
|
2609
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
2610
|
-
)
|
|
1935
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
2611
1936
|
|
|
2612
1937
|
@property
|
|
2613
1938
|
def is_window_closed_right_back_supported(self) -> bool:
|
|
2614
1939
|
"""Return true if supported."""
|
|
2615
1940
|
if is_valid_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows"):
|
|
2616
|
-
windows = find_path(
|
|
2617
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.windows"
|
|
2618
|
-
)
|
|
1941
|
+
windows = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows")
|
|
2619
1942
|
for window in windows:
|
|
2620
|
-
if
|
|
2621
|
-
window["name"] == "rearRight"
|
|
2622
|
-
and "unsupported" not in window["status"]
|
|
2623
|
-
):
|
|
1943
|
+
if window["name"] == "rearRight" and "unsupported" not in window["status"]:
|
|
2624
1944
|
return True
|
|
2625
1945
|
return False
|
|
2626
1946
|
|
|
2627
1947
|
@property
|
|
2628
1948
|
def sunroof_closed(self) -> bool:
|
|
2629
|
-
"""
|
|
1949
|
+
"""
|
|
1950
|
+
Return sunroof closed state.
|
|
2630
1951
|
|
|
2631
1952
|
:return:
|
|
2632
1953
|
"""
|
|
2633
1954
|
windows = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows")
|
|
2634
1955
|
for window in windows:
|
|
2635
1956
|
if window["name"] == "sunRoof":
|
|
2636
|
-
if not any(
|
|
2637
|
-
valid_status in window["status"]
|
|
2638
|
-
for valid_status in P.VALID_WINDOW_STATUS
|
|
2639
|
-
):
|
|
1957
|
+
if not any(valid_status in window["status"] for valid_status in P.VALID_WINDOW_STATUS):
|
|
2640
1958
|
return None
|
|
2641
1959
|
return "closed" in window["status"]
|
|
2642
1960
|
return False
|
|
@@ -2644,38 +1962,29 @@ class Vehicle:
|
|
|
2644
1962
|
@property
|
|
2645
1963
|
def sunroof_closed_last_updated(self) -> datetime:
|
|
2646
1964
|
"""Return attribute last updated timestamp."""
|
|
2647
|
-
return find_path(
|
|
2648
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
2649
|
-
)
|
|
1965
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
2650
1966
|
|
|
2651
1967
|
@property
|
|
2652
1968
|
def is_sunroof_closed_supported(self) -> bool:
|
|
2653
1969
|
"""Return true if supported."""
|
|
2654
1970
|
if is_valid_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows"):
|
|
2655
|
-
windows = find_path(
|
|
2656
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.windows"
|
|
2657
|
-
)
|
|
1971
|
+
windows = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows")
|
|
2658
1972
|
for window in windows:
|
|
2659
|
-
if
|
|
2660
|
-
window["name"] == "sunRoof"
|
|
2661
|
-
and "unsupported" not in window["status"]
|
|
2662
|
-
):
|
|
1973
|
+
if window["name"] == "sunRoof" and "unsupported" not in window["status"]:
|
|
2663
1974
|
return True
|
|
2664
1975
|
return False
|
|
2665
1976
|
|
|
2666
1977
|
@property
|
|
2667
1978
|
def sunroof_rear_closed(self) -> bool:
|
|
2668
|
-
"""
|
|
1979
|
+
"""
|
|
1980
|
+
Return sunroof rear closed state.
|
|
2669
1981
|
|
|
2670
1982
|
:return:
|
|
2671
1983
|
"""
|
|
2672
1984
|
windows = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows")
|
|
2673
1985
|
for window in windows:
|
|
2674
1986
|
if window["name"] == "sunRoofRear":
|
|
2675
|
-
if not any(
|
|
2676
|
-
valid_status in window["status"]
|
|
2677
|
-
for valid_status in P.VALID_WINDOW_STATUS
|
|
2678
|
-
):
|
|
1987
|
+
if not any(valid_status in window["status"] for valid_status in P.VALID_WINDOW_STATUS):
|
|
2679
1988
|
return None
|
|
2680
1989
|
return "closed" in window["status"]
|
|
2681
1990
|
return False
|
|
@@ -2683,38 +1992,29 @@ class Vehicle:
|
|
|
2683
1992
|
@property
|
|
2684
1993
|
def sunroof_rear_closed_last_updated(self) -> datetime:
|
|
2685
1994
|
"""Return attribute last updated timestamp."""
|
|
2686
|
-
return find_path(
|
|
2687
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
2688
|
-
)
|
|
1995
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
2689
1996
|
|
|
2690
1997
|
@property
|
|
2691
1998
|
def is_sunroof_rear_closed_supported(self) -> bool:
|
|
2692
1999
|
"""Return true if supported."""
|
|
2693
2000
|
if is_valid_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows"):
|
|
2694
|
-
windows = find_path(
|
|
2695
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.windows"
|
|
2696
|
-
)
|
|
2001
|
+
windows = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows")
|
|
2697
2002
|
for window in windows:
|
|
2698
|
-
if
|
|
2699
|
-
window["name"] == "sunRoofRear"
|
|
2700
|
-
and "unsupported" not in window["status"]
|
|
2701
|
-
):
|
|
2003
|
+
if window["name"] == "sunRoofRear" and "unsupported" not in window["status"]:
|
|
2702
2004
|
return True
|
|
2703
2005
|
return False
|
|
2704
2006
|
|
|
2705
2007
|
@property
|
|
2706
2008
|
def roof_cover_closed(self) -> bool:
|
|
2707
|
-
"""
|
|
2009
|
+
"""
|
|
2010
|
+
Return roof cover closed state.
|
|
2708
2011
|
|
|
2709
2012
|
:return:
|
|
2710
2013
|
"""
|
|
2711
2014
|
windows = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows")
|
|
2712
2015
|
for window in windows:
|
|
2713
2016
|
if window["name"] == "roofCover":
|
|
2714
|
-
if not any(
|
|
2715
|
-
valid_status in window["status"]
|
|
2716
|
-
for valid_status in P.VALID_WINDOW_STATUS
|
|
2717
|
-
):
|
|
2017
|
+
if not any(valid_status in window["status"] for valid_status in P.VALID_WINDOW_STATUS):
|
|
2718
2018
|
return None
|
|
2719
2019
|
return "closed" in window["status"]
|
|
2720
2020
|
return False
|
|
@@ -2722,22 +2022,15 @@ class Vehicle:
|
|
|
2722
2022
|
@property
|
|
2723
2023
|
def roof_cover_closed_last_updated(self) -> datetime:
|
|
2724
2024
|
"""Return attribute last updated timestamp."""
|
|
2725
|
-
return find_path(
|
|
2726
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
2727
|
-
)
|
|
2025
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
2728
2026
|
|
|
2729
2027
|
@property
|
|
2730
2028
|
def is_roof_cover_closed_supported(self) -> bool:
|
|
2731
2029
|
"""Return true if supported."""
|
|
2732
2030
|
if is_valid_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.doors"):
|
|
2733
|
-
windows = find_path(
|
|
2734
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.windows"
|
|
2735
|
-
)
|
|
2031
|
+
windows = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.windows")
|
|
2736
2032
|
for window in windows:
|
|
2737
|
-
if
|
|
2738
|
-
window["name"] == "roofCover"
|
|
2739
|
-
and "unsupported" not in window["status"]
|
|
2740
|
-
):
|
|
2033
|
+
if window["name"] == "roofCover" and "unsupported" not in window["status"]:
|
|
2741
2034
|
return True
|
|
2742
2035
|
return False
|
|
2743
2036
|
|
|
@@ -2749,60 +2042,51 @@ class Vehicle:
|
|
|
2749
2042
|
|
|
2750
2043
|
@property
|
|
2751
2044
|
def door_locked(self) -> bool:
|
|
2752
|
-
"""
|
|
2045
|
+
"""
|
|
2046
|
+
Return true if all doors are locked.
|
|
2753
2047
|
|
|
2754
2048
|
:return:
|
|
2755
2049
|
"""
|
|
2756
|
-
return (
|
|
2757
|
-
find_path(
|
|
2758
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.doorLockStatus"
|
|
2759
|
-
)
|
|
2760
|
-
== "locked"
|
|
2761
|
-
)
|
|
2050
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.doorLockStatus") == "locked"
|
|
2762
2051
|
|
|
2763
2052
|
@property
|
|
2764
2053
|
def door_locked_last_updated(self) -> datetime:
|
|
2765
2054
|
"""Return door lock last updated."""
|
|
2766
|
-
return find_path(
|
|
2767
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
2768
|
-
)
|
|
2055
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
2769
2056
|
|
|
2770
2057
|
@property
|
|
2771
2058
|
def door_locked_sensor_last_updated(self) -> datetime:
|
|
2772
2059
|
"""Return door lock last updated."""
|
|
2773
|
-
return find_path(
|
|
2774
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
2775
|
-
)
|
|
2060
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
2776
2061
|
|
|
2777
2062
|
@property
|
|
2778
2063
|
def is_door_locked_supported(self) -> bool:
|
|
2779
|
-
"""
|
|
2064
|
+
"""
|
|
2065
|
+
Return true if supported.
|
|
2780
2066
|
|
|
2781
2067
|
:return:
|
|
2782
2068
|
"""
|
|
2783
2069
|
# First check that the service is actually enabled
|
|
2784
2070
|
if not self._services.get(Services.ACCESS, {}).get("active", False):
|
|
2785
2071
|
return False
|
|
2786
|
-
return is_valid_path(
|
|
2787
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.doorLockStatus"
|
|
2788
|
-
)
|
|
2072
|
+
return is_valid_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.doorLockStatus")
|
|
2789
2073
|
|
|
2790
2074
|
@property
|
|
2791
2075
|
def is_door_locked_sensor_supported(self) -> bool:
|
|
2792
|
-
"""
|
|
2076
|
+
"""
|
|
2077
|
+
Return true if supported.
|
|
2793
2078
|
|
|
2794
2079
|
:return:
|
|
2795
2080
|
"""
|
|
2796
2081
|
# Use real lock if the service is actually enabled
|
|
2797
2082
|
if self._services.get(Services.ACCESS, {}).get("active", False):
|
|
2798
2083
|
return False
|
|
2799
|
-
return is_valid_path(
|
|
2800
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.doorLockStatus"
|
|
2801
|
-
)
|
|
2084
|
+
return is_valid_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.doorLockStatus")
|
|
2802
2085
|
|
|
2803
2086
|
@property
|
|
2804
2087
|
def trunk_locked(self) -> bool:
|
|
2805
|
-
"""
|
|
2088
|
+
"""
|
|
2089
|
+
Return trunk locked state.
|
|
2806
2090
|
|
|
2807
2091
|
:return:
|
|
2808
2092
|
"""
|
|
@@ -2815,13 +2099,12 @@ class Vehicle:
|
|
|
2815
2099
|
@property
|
|
2816
2100
|
def trunk_locked_last_updated(self) -> datetime:
|
|
2817
2101
|
"""Return attribute last updated timestamp."""
|
|
2818
|
-
return find_path(
|
|
2819
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
2820
|
-
)
|
|
2102
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
2821
2103
|
|
|
2822
2104
|
@property
|
|
2823
2105
|
def is_trunk_locked_supported(self) -> bool:
|
|
2824
|
-
"""
|
|
2106
|
+
"""
|
|
2107
|
+
Return true if supported.
|
|
2825
2108
|
|
|
2826
2109
|
:return:
|
|
2827
2110
|
"""
|
|
@@ -2836,7 +2119,8 @@ class Vehicle:
|
|
|
2836
2119
|
|
|
2837
2120
|
@property
|
|
2838
2121
|
def trunk_locked_sensor(self) -> bool:
|
|
2839
|
-
"""
|
|
2122
|
+
"""
|
|
2123
|
+
Return trunk locked state.
|
|
2840
2124
|
|
|
2841
2125
|
:return:
|
|
2842
2126
|
"""
|
|
@@ -2849,13 +2133,12 @@ class Vehicle:
|
|
|
2849
2133
|
@property
|
|
2850
2134
|
def trunk_locked_sensor_last_updated(self) -> datetime:
|
|
2851
2135
|
"""Return attribute last updated timestamp."""
|
|
2852
|
-
return find_path(
|
|
2853
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
2854
|
-
)
|
|
2136
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
2855
2137
|
|
|
2856
2138
|
@property
|
|
2857
2139
|
def is_trunk_locked_sensor_supported(self) -> bool:
|
|
2858
|
-
"""
|
|
2140
|
+
"""
|
|
2141
|
+
Return true if supported.
|
|
2859
2142
|
|
|
2860
2143
|
:return:
|
|
2861
2144
|
"""
|
|
@@ -2871,17 +2154,15 @@ class Vehicle:
|
|
|
2871
2154
|
# Doors, hood and trunk
|
|
2872
2155
|
@property
|
|
2873
2156
|
def hood_closed(self) -> bool:
|
|
2874
|
-
"""
|
|
2157
|
+
"""
|
|
2158
|
+
Return hood closed state.
|
|
2875
2159
|
|
|
2876
2160
|
:return:
|
|
2877
2161
|
"""
|
|
2878
2162
|
doors = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.doors")
|
|
2879
2163
|
for door in doors:
|
|
2880
2164
|
if door["name"] == "bonnet":
|
|
2881
|
-
if not any(
|
|
2882
|
-
valid_status in door["status"]
|
|
2883
|
-
for valid_status in P.VALID_DOOR_STATUS
|
|
2884
|
-
):
|
|
2165
|
+
if not any(valid_status in door["status"] for valid_status in P.VALID_DOOR_STATUS):
|
|
2885
2166
|
return None
|
|
2886
2167
|
return "closed" in door["status"]
|
|
2887
2168
|
return False
|
|
@@ -2889,9 +2170,7 @@ class Vehicle:
|
|
|
2889
2170
|
@property
|
|
2890
2171
|
def hood_closed_last_updated(self) -> datetime:
|
|
2891
2172
|
"""Return attribute last updated timestamp."""
|
|
2892
|
-
return find_path(
|
|
2893
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
2894
|
-
)
|
|
2173
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
2895
2174
|
|
|
2896
2175
|
@property
|
|
2897
2176
|
def is_hood_closed_supported(self) -> bool:
|
|
@@ -2905,17 +2184,15 @@ class Vehicle:
|
|
|
2905
2184
|
|
|
2906
2185
|
@property
|
|
2907
2186
|
def door_closed_left_front(self) -> bool:
|
|
2908
|
-
"""
|
|
2187
|
+
"""
|
|
2188
|
+
Return left front door closed state.
|
|
2909
2189
|
|
|
2910
2190
|
:return:
|
|
2911
2191
|
"""
|
|
2912
2192
|
doors = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.doors")
|
|
2913
2193
|
for door in doors:
|
|
2914
2194
|
if door["name"] == "frontLeft":
|
|
2915
|
-
if not any(
|
|
2916
|
-
valid_status in door["status"]
|
|
2917
|
-
for valid_status in P.VALID_DOOR_STATUS
|
|
2918
|
-
):
|
|
2195
|
+
if not any(valid_status in door["status"] for valid_status in P.VALID_DOOR_STATUS):
|
|
2919
2196
|
return None
|
|
2920
2197
|
return "closed" in door["status"]
|
|
2921
2198
|
return False
|
|
@@ -2923,9 +2200,7 @@ class Vehicle:
|
|
|
2923
2200
|
@property
|
|
2924
2201
|
def door_closed_left_front_last_updated(self) -> datetime:
|
|
2925
2202
|
"""Return attribute last updated timestamp."""
|
|
2926
|
-
return find_path(
|
|
2927
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
2928
|
-
)
|
|
2203
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
2929
2204
|
|
|
2930
2205
|
@property
|
|
2931
2206
|
def is_door_closed_left_front_supported(self) -> bool:
|
|
@@ -2939,17 +2214,15 @@ class Vehicle:
|
|
|
2939
2214
|
|
|
2940
2215
|
@property
|
|
2941
2216
|
def door_closed_right_front(self) -> bool:
|
|
2942
|
-
"""
|
|
2217
|
+
"""
|
|
2218
|
+
Return right front door closed state.
|
|
2943
2219
|
|
|
2944
2220
|
:return:
|
|
2945
2221
|
"""
|
|
2946
2222
|
doors = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.doors")
|
|
2947
2223
|
for door in doors:
|
|
2948
2224
|
if door["name"] == "frontRight":
|
|
2949
|
-
if not any(
|
|
2950
|
-
valid_status in door["status"]
|
|
2951
|
-
for valid_status in P.VALID_DOOR_STATUS
|
|
2952
|
-
):
|
|
2225
|
+
if not any(valid_status in door["status"] for valid_status in P.VALID_DOOR_STATUS):
|
|
2953
2226
|
return None
|
|
2954
2227
|
return "closed" in door["status"]
|
|
2955
2228
|
return False
|
|
@@ -2957,9 +2230,7 @@ class Vehicle:
|
|
|
2957
2230
|
@property
|
|
2958
2231
|
def door_closed_right_front_last_updated(self) -> datetime:
|
|
2959
2232
|
"""Return attribute last updated timestamp."""
|
|
2960
|
-
return find_path(
|
|
2961
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
2962
|
-
)
|
|
2233
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
2963
2234
|
|
|
2964
2235
|
@property
|
|
2965
2236
|
def is_door_closed_right_front_supported(self) -> bool:
|
|
@@ -2973,17 +2244,15 @@ class Vehicle:
|
|
|
2973
2244
|
|
|
2974
2245
|
@property
|
|
2975
2246
|
def door_closed_left_back(self) -> bool:
|
|
2976
|
-
"""
|
|
2247
|
+
"""
|
|
2248
|
+
Return left back door closed state.
|
|
2977
2249
|
|
|
2978
2250
|
:return:
|
|
2979
2251
|
"""
|
|
2980
2252
|
doors = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.doors")
|
|
2981
2253
|
for door in doors:
|
|
2982
2254
|
if door["name"] == "rearLeft":
|
|
2983
|
-
if not any(
|
|
2984
|
-
valid_status in door["status"]
|
|
2985
|
-
for valid_status in P.VALID_DOOR_STATUS
|
|
2986
|
-
):
|
|
2255
|
+
if not any(valid_status in door["status"] for valid_status in P.VALID_DOOR_STATUS):
|
|
2987
2256
|
return None
|
|
2988
2257
|
return "closed" in door["status"]
|
|
2989
2258
|
return False
|
|
@@ -2991,9 +2260,7 @@ class Vehicle:
|
|
|
2991
2260
|
@property
|
|
2992
2261
|
def door_closed_left_back_last_updated(self) -> datetime:
|
|
2993
2262
|
"""Return attribute last updated timestamp."""
|
|
2994
|
-
return find_path(
|
|
2995
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
2996
|
-
)
|
|
2263
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
2997
2264
|
|
|
2998
2265
|
@property
|
|
2999
2266
|
def is_door_closed_left_back_supported(self) -> bool:
|
|
@@ -3007,17 +2274,15 @@ class Vehicle:
|
|
|
3007
2274
|
|
|
3008
2275
|
@property
|
|
3009
2276
|
def door_closed_right_back(self) -> bool:
|
|
3010
|
-
"""
|
|
2277
|
+
"""
|
|
2278
|
+
Return right back door closed state.
|
|
3011
2279
|
|
|
3012
2280
|
:return:
|
|
3013
2281
|
"""
|
|
3014
2282
|
doors = find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.doors")
|
|
3015
2283
|
for door in doors:
|
|
3016
2284
|
if door["name"] == "rearRight":
|
|
3017
|
-
if not any(
|
|
3018
|
-
valid_status in door["status"]
|
|
3019
|
-
for valid_status in P.VALID_DOOR_STATUS
|
|
3020
|
-
):
|
|
2285
|
+
if not any(valid_status in door["status"] for valid_status in P.VALID_DOOR_STATUS):
|
|
3021
2286
|
return None
|
|
3022
2287
|
return "closed" in door["status"]
|
|
3023
2288
|
return False
|
|
@@ -3025,9 +2290,7 @@ class Vehicle:
|
|
|
3025
2290
|
@property
|
|
3026
2291
|
def door_closed_right_back_last_updated(self) -> datetime:
|
|
3027
2292
|
"""Return attribute last updated timestamp."""
|
|
3028
|
-
return find_path(
|
|
3029
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
3030
|
-
)
|
|
2293
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
3031
2294
|
|
|
3032
2295
|
@property
|
|
3033
2296
|
def is_door_closed_right_back_supported(self) -> bool:
|
|
@@ -3041,7 +2304,8 @@ class Vehicle:
|
|
|
3041
2304
|
|
|
3042
2305
|
@property
|
|
3043
2306
|
def trunk_closed(self) -> bool:
|
|
3044
|
-
"""
|
|
2307
|
+
"""
|
|
2308
|
+
Return trunk closed state.
|
|
3045
2309
|
|
|
3046
2310
|
:return:
|
|
3047
2311
|
"""
|
|
@@ -3054,9 +2318,7 @@ class Vehicle:
|
|
|
3054
2318
|
@property
|
|
3055
2319
|
def trunk_closed_last_updated(self) -> datetime:
|
|
3056
2320
|
"""Return attribute last updated timestamp."""
|
|
3057
|
-
return find_path(
|
|
3058
|
-
self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp"
|
|
3059
|
-
)
|
|
2321
|
+
return find_path(self.attrs, f"{Services.ACCESS}.accessStatus.value.carCapturedTimestamp")
|
|
3060
2322
|
|
|
3061
2323
|
@property
|
|
3062
2324
|
def is_trunk_closed_supported(self) -> bool:
|
|
@@ -3088,28 +2350,20 @@ class Vehicle:
|
|
|
3088
2350
|
def departure_timer1_last_updated(self) -> datetime:
|
|
3089
2351
|
"""Return last updated timestamp."""
|
|
3090
2352
|
if is_valid_path(
|
|
3091
|
-
self.attrs,
|
|
3092
|
-
f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.carCapturedTimestamp",
|
|
2353
|
+
self.attrs, f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.carCapturedTimestamp"
|
|
3093
2354
|
):
|
|
3094
2355
|
return find_path(
|
|
3095
|
-
self.attrs,
|
|
3096
|
-
f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.carCapturedTimestamp",
|
|
2356
|
+
self.attrs, f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.carCapturedTimestamp"
|
|
3097
2357
|
)
|
|
3098
2358
|
if is_valid_path(
|
|
3099
|
-
self.attrs,
|
|
3100
|
-
f"{Services.CLIMATISATION_TIMERS}.auxiliaryHeatingTimersStatus.value.carCapturedTimestamp",
|
|
2359
|
+
self.attrs, f"{Services.CLIMATISATION_TIMERS}.auxiliaryHeatingTimersStatus.value.carCapturedTimestamp"
|
|
3101
2360
|
):
|
|
3102
2361
|
return find_path(
|
|
3103
|
-
self.attrs,
|
|
3104
|
-
f"{Services.CLIMATISATION_TIMERS}.auxiliaryHeatingTimersStatus.value.carCapturedTimestamp",
|
|
2362
|
+
self.attrs, f"{Services.CLIMATISATION_TIMERS}.auxiliaryHeatingTimersStatus.value.carCapturedTimestamp"
|
|
3105
2363
|
)
|
|
3106
|
-
if is_valid_path(
|
|
3107
|
-
self.attrs,
|
|
3108
|
-
f"{Services.DEPARTURE_TIMERS}.departureTimersStatus.value.carCapturedTimestamp",
|
|
3109
|
-
):
|
|
2364
|
+
if is_valid_path(self.attrs, f"{Services.DEPARTURE_TIMERS}.departureTimersStatus.value.carCapturedTimestamp"):
|
|
3110
2365
|
return find_path(
|
|
3111
|
-
self.attrs,
|
|
3112
|
-
f"{Services.DEPARTURE_TIMERS}.departureTimersStatus.value.carCapturedTimestamp",
|
|
2366
|
+
self.attrs, f"{Services.DEPARTURE_TIMERS}.departureTimersStatus.value.carCapturedTimestamp"
|
|
3113
2367
|
)
|
|
3114
2368
|
return None
|
|
3115
2369
|
|
|
@@ -3156,61 +2410,40 @@ class Vehicle:
|
|
|
3156
2410
|
if timer.get("singleTimer", None):
|
|
3157
2411
|
timer_type = "single"
|
|
3158
2412
|
if timer.get("singleTimer", None).get("startDateTime", None):
|
|
3159
|
-
start_date_time = timer.get("singleTimer", None).get(
|
|
3160
|
-
"startDateTime", None
|
|
3161
|
-
)
|
|
2413
|
+
start_date_time = timer.get("singleTimer", None).get("startDateTime", None)
|
|
3162
2414
|
start_time = (
|
|
3163
|
-
start_date_time.replace(tzinfo=
|
|
3164
|
-
.astimezone(tz=None)
|
|
3165
|
-
.strftime("%Y-%m-%dT%H:%M:%S")
|
|
2415
|
+
start_date_time.replace(tzinfo=timezone.utc).astimezone(tz=None).strftime("%Y-%m-%dT%H:%M:%S")
|
|
3166
2416
|
)
|
|
3167
2417
|
if timer.get("singleTimer", None).get("startDateTimeLocal", None):
|
|
3168
|
-
start_date_time = timer.get("singleTimer", None).get(
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
if isinstance(start_date_time, str):
|
|
3172
|
-
start_date_time = datetime.strptime(
|
|
3173
|
-
start_date_time, "%Y-%m-%dT%H:%M:%S"
|
|
3174
|
-
)
|
|
2418
|
+
start_date_time = timer.get("singleTimer", None).get("startDateTimeLocal", None)
|
|
2419
|
+
if type(start_date_time) is str:
|
|
2420
|
+
start_date_time = datetime.strptime(start_date_time, "%Y-%m-%dT%H:%M:%S")
|
|
3175
2421
|
start_time = start_date_time
|
|
3176
2422
|
if timer.get("singleTimer", None).get("departureDateTimeLocal", None):
|
|
3177
|
-
start_date_time = timer.get("singleTimer", None).get(
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
if isinstance(start_date_time, str):
|
|
3181
|
-
start_date_time = datetime.strptime(
|
|
3182
|
-
start_date_time, "%Y-%m-%dT%H:%M:%S"
|
|
3183
|
-
)
|
|
2423
|
+
start_date_time = timer.get("singleTimer", None).get("departureDateTimeLocal", None)
|
|
2424
|
+
if type(start_date_time) is str:
|
|
2425
|
+
start_date_time = datetime.strptime(start_date_time, "%Y-%m-%dT%H:%M:%S")
|
|
3184
2426
|
start_time = start_date_time
|
|
3185
2427
|
elif timer.get("recurringTimer", None):
|
|
3186
2428
|
timer_type = "recurring"
|
|
3187
2429
|
if timer.get("recurringTimer", None).get("startTime", None):
|
|
3188
|
-
start_date_time = timer.get("recurringTimer", None).get(
|
|
3189
|
-
"startTime", None
|
|
3190
|
-
)
|
|
2430
|
+
start_date_time = timer.get("recurringTimer", None).get("startTime", None)
|
|
3191
2431
|
start_time = (
|
|
3192
2432
|
datetime.strptime(start_date_time, "%H:%M")
|
|
3193
|
-
.replace(tzinfo=
|
|
2433
|
+
.replace(tzinfo=timezone.utc)
|
|
3194
2434
|
.astimezone(tz=None)
|
|
3195
2435
|
.strftime("%H:%M")
|
|
3196
2436
|
)
|
|
3197
2437
|
if timer.get("recurringTimer", None).get("startTimeLocal", None):
|
|
3198
|
-
start_date_time = timer.get("recurringTimer", None).get(
|
|
3199
|
-
|
|
3200
|
-
)
|
|
3201
|
-
start_time = datetime.strptime(start_date_time, "%H:%M").strftime(
|
|
3202
|
-
"%H:%M"
|
|
3203
|
-
)
|
|
2438
|
+
start_date_time = timer.get("recurringTimer", None).get("startTimeLocal", None)
|
|
2439
|
+
start_time = datetime.strptime(start_date_time, "%H:%M").strftime("%H:%M")
|
|
3204
2440
|
if timer.get("recurringTimer", None).get("departureTimeLocal", None):
|
|
3205
|
-
start_date_time = timer.get("recurringTimer", None).get(
|
|
3206
|
-
|
|
3207
|
-
)
|
|
3208
|
-
start_time = datetime.strptime(start_date_time, "%H:%M").strftime(
|
|
3209
|
-
"%H:%M"
|
|
3210
|
-
)
|
|
2441
|
+
start_date_time = timer.get("recurringTimer", None).get("departureTimeLocal", None)
|
|
2442
|
+
start_time = datetime.strptime(start_date_time, "%H:%M").strftime("%H:%M")
|
|
3211
2443
|
recurring_days = timer.get("recurringTimer", None).get("recurringOn", None)
|
|
3212
|
-
|
|
3213
|
-
|
|
2444
|
+
for day in recurring_days:
|
|
2445
|
+
if recurring_days.get(day) is True:
|
|
2446
|
+
recurring_on.append(day)
|
|
3214
2447
|
data = {
|
|
3215
2448
|
"timer_id": timer.get("id", None),
|
|
3216
2449
|
"timer_type": timer_type,
|
|
@@ -3230,46 +2463,24 @@ class Vehicle:
|
|
|
3230
2463
|
data["climatisation_enabled"] = timer.get("climatisation", False)
|
|
3231
2464
|
if timer.get("preferredChargingTimes", None):
|
|
3232
2465
|
preferred_charging_times = timer.get("preferredChargingTimes", None)[0]
|
|
3233
|
-
data["preferred_charging_start_time"] = preferred_charging_times.get(
|
|
3234
|
-
|
|
3235
|
-
)
|
|
3236
|
-
data["preferred_charging_end_time"] = preferred_charging_times.get(
|
|
3237
|
-
"endTimeLocal", None
|
|
3238
|
-
)
|
|
2466
|
+
data["preferred_charging_start_time"] = preferred_charging_times.get("startTimeLocal", None)
|
|
2467
|
+
data["preferred_charging_end_time"] = preferred_charging_times.get("endTimeLocal", None)
|
|
3239
2468
|
return data
|
|
3240
2469
|
|
|
3241
2470
|
def departure_timer(self, timer_id: str | int):
|
|
3242
2471
|
"""Return departure timer."""
|
|
3243
|
-
if is_valid_path(
|
|
3244
|
-
self.attrs,
|
|
3245
|
-
f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.timers",
|
|
3246
|
-
):
|
|
3247
|
-
timers = find_path(
|
|
3248
|
-
self.attrs,
|
|
3249
|
-
f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.timers",
|
|
3250
|
-
)
|
|
2472
|
+
if is_valid_path(self.attrs, f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.timers"):
|
|
2473
|
+
timers = find_path(self.attrs, f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.timers")
|
|
3251
2474
|
for timer in timers:
|
|
3252
2475
|
if timer.get("id", 0) == timer_id:
|
|
3253
2476
|
return timer
|
|
3254
|
-
if is_valid_path(
|
|
3255
|
-
self.attrs,
|
|
3256
|
-
f"{Services.CLIMATISATION_TIMERS}.auxiliaryHeatingTimersStatus.value.timers",
|
|
3257
|
-
):
|
|
3258
|
-
timers = find_path(
|
|
3259
|
-
self.attrs,
|
|
3260
|
-
f"{Services.CLIMATISATION_TIMERS}.auxiliaryHeatingTimersStatus.value.timers",
|
|
3261
|
-
)
|
|
2477
|
+
if is_valid_path(self.attrs, f"{Services.CLIMATISATION_TIMERS}.auxiliaryHeatingTimersStatus.value.timers"):
|
|
2478
|
+
timers = find_path(self.attrs, f"{Services.CLIMATISATION_TIMERS}.auxiliaryHeatingTimersStatus.value.timers")
|
|
3262
2479
|
for timer in timers:
|
|
3263
2480
|
if timer.get("id", 0) == timer_id:
|
|
3264
2481
|
return timer
|
|
3265
|
-
if is_valid_path(
|
|
3266
|
-
self.attrs,
|
|
3267
|
-
f"{Services.DEPARTURE_TIMERS}.departureTimersStatus.value.timers",
|
|
3268
|
-
):
|
|
3269
|
-
timers = find_path(
|
|
3270
|
-
self.attrs,
|
|
3271
|
-
f"{Services.DEPARTURE_TIMERS}.departureTimersStatus.value.timers",
|
|
3272
|
-
)
|
|
2482
|
+
if is_valid_path(self.attrs, f"{Services.DEPARTURE_TIMERS}.departureTimersStatus.value.timers"):
|
|
2483
|
+
timers = find_path(self.attrs, f"{Services.DEPARTURE_TIMERS}.departureTimersStatus.value.timers")
|
|
3273
2484
|
for timer in timers:
|
|
3274
2485
|
if timer.get("id", 0) == timer_id:
|
|
3275
2486
|
return timer
|
|
@@ -3277,14 +2488,8 @@ class Vehicle:
|
|
|
3277
2488
|
|
|
3278
2489
|
def departure_profile(self, profile_id: str | int):
|
|
3279
2490
|
"""Return departure profile."""
|
|
3280
|
-
if is_valid_path(
|
|
3281
|
-
self.attrs,
|
|
3282
|
-
f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.profiles",
|
|
3283
|
-
):
|
|
3284
|
-
profiles = find_path(
|
|
3285
|
-
self.attrs,
|
|
3286
|
-
f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.profiles",
|
|
3287
|
-
)
|
|
2491
|
+
if is_valid_path(self.attrs, f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.profiles"):
|
|
2492
|
+
profiles = find_path(self.attrs, f"{Services.DEPARTURE_PROFILES}.departureProfilesStatus.value.profiles")
|
|
3288
2493
|
for profile in profiles:
|
|
3289
2494
|
if profile.get("id", 0) == profile_id:
|
|
3290
2495
|
return profile
|
|
@@ -3305,8 +2510,7 @@ class Vehicle:
|
|
|
3305
2510
|
def ac_departure_timer1_last_updated(self) -> datetime:
|
|
3306
2511
|
"""Return last updated timestamp."""
|
|
3307
2512
|
return find_path(
|
|
3308
|
-
self.attrs,
|
|
3309
|
-
f"{Services.CLIMATISATION_TIMERS}.climatisationTimersStatus.value.carCapturedTimestamp",
|
|
2513
|
+
self.attrs, f"{Services.CLIMATISATION_TIMERS}.climatisationTimersStatus.value.carCapturedTimestamp"
|
|
3310
2514
|
)
|
|
3311
2515
|
|
|
3312
2516
|
@property
|
|
@@ -3334,14 +2538,8 @@ class Vehicle:
|
|
|
3334
2538
|
|
|
3335
2539
|
def ac_departure_timer(self, timer_id: str | int):
|
|
3336
2540
|
"""Return ac departure timer."""
|
|
3337
|
-
if is_valid_path(
|
|
3338
|
-
self.attrs,
|
|
3339
|
-
f"{Services.CLIMATISATION_TIMERS}.climatisationTimersStatus.value.timers",
|
|
3340
|
-
):
|
|
3341
|
-
timers = find_path(
|
|
3342
|
-
self.attrs,
|
|
3343
|
-
f"{Services.CLIMATISATION_TIMERS}.climatisationTimersStatus.value.timers",
|
|
3344
|
-
)
|
|
2541
|
+
if is_valid_path(self.attrs, f"{Services.CLIMATISATION_TIMERS}.climatisationTimersStatus.value.timers"):
|
|
2542
|
+
timers = find_path(self.attrs, f"{Services.CLIMATISATION_TIMERS}.climatisationTimersStatus.value.timers")
|
|
3345
2543
|
for timer in timers:
|
|
3346
2544
|
if timer.get("id", 0) == timer_id:
|
|
3347
2545
|
return timer
|
|
@@ -3356,33 +2554,33 @@ class Vehicle:
|
|
|
3356
2554
|
if timer.get("singleTimer", None):
|
|
3357
2555
|
timer_type = "single"
|
|
3358
2556
|
start_date_time = timer.get("singleTimer", None).get("startDateTime", None)
|
|
3359
|
-
start_time = (
|
|
3360
|
-
start_date_time.replace(tzinfo=UTC)
|
|
3361
|
-
.astimezone(tz=None)
|
|
3362
|
-
.strftime("%Y-%m-%dT%H:%M:%S")
|
|
3363
|
-
)
|
|
2557
|
+
start_time = start_date_time.replace(tzinfo=timezone.utc).astimezone(tz=None).strftime("%Y-%m-%dT%H:%M:%S")
|
|
3364
2558
|
elif timer.get("recurringTimer", None):
|
|
3365
2559
|
timer_type = "recurring"
|
|
3366
2560
|
start_date_time = timer.get("recurringTimer", None).get("startTime", None)
|
|
3367
2561
|
start_time = (
|
|
3368
2562
|
datetime.strptime(start_date_time, "%H:%M")
|
|
3369
|
-
.replace(tzinfo=
|
|
2563
|
+
.replace(tzinfo=timezone.utc)
|
|
3370
2564
|
.astimezone(tz=None)
|
|
3371
2565
|
.strftime("%H:%M")
|
|
3372
2566
|
)
|
|
3373
2567
|
recurring_days = timer.get("recurringTimer", None).get("recurringOn", None)
|
|
3374
|
-
|
|
3375
|
-
|
|
2568
|
+
for day in recurring_days:
|
|
2569
|
+
if recurring_days.get(day) is True:
|
|
2570
|
+
recurring_on.append(day)
|
|
2571
|
+
data = {
|
|
3376
2572
|
"timer_id": timer.get("id", None),
|
|
3377
2573
|
"timer_type": timer_type,
|
|
3378
2574
|
"start_time": start_time,
|
|
3379
2575
|
"recurring_on": recurring_on,
|
|
3380
2576
|
}
|
|
2577
|
+
return data
|
|
3381
2578
|
|
|
3382
2579
|
# Trip data
|
|
3383
2580
|
@property
|
|
3384
2581
|
def trip_last_entry(self):
|
|
3385
|
-
"""
|
|
2582
|
+
"""
|
|
2583
|
+
Return last trip data entry.
|
|
3386
2584
|
|
|
3387
2585
|
:return:
|
|
3388
2586
|
"""
|
|
@@ -3390,7 +2588,8 @@ class Vehicle:
|
|
|
3390
2588
|
|
|
3391
2589
|
@property
|
|
3392
2590
|
def trip_last_average_speed(self):
|
|
3393
|
-
"""
|
|
2591
|
+
"""
|
|
2592
|
+
Return last trip average speed.
|
|
3394
2593
|
|
|
3395
2594
|
:return:
|
|
3396
2595
|
"""
|
|
@@ -3403,25 +2602,23 @@ class Vehicle:
|
|
|
3403
2602
|
|
|
3404
2603
|
@property
|
|
3405
2604
|
def is_trip_last_average_speed_supported(self) -> bool:
|
|
3406
|
-
"""
|
|
2605
|
+
"""
|
|
2606
|
+
Return true if supported.
|
|
3407
2607
|
|
|
3408
2608
|
:return:
|
|
3409
2609
|
"""
|
|
3410
|
-
return is_valid_path(
|
|
3411
|
-
self.attrs, f"{Services.TRIP_LAST}.averageSpeed_kmph"
|
|
3412
|
-
) and type(
|
|
2610
|
+
return is_valid_path(self.attrs, f"{Services.TRIP_LAST}.averageSpeed_kmph") and type(
|
|
3413
2611
|
find_path(self.attrs, f"{Services.TRIP_LAST}.averageSpeed_kmph")
|
|
3414
2612
|
) in (float, int)
|
|
3415
2613
|
|
|
3416
2614
|
@property
|
|
3417
2615
|
def trip_last_average_electric_engine_consumption(self):
|
|
3418
|
-
"""
|
|
2616
|
+
"""
|
|
2617
|
+
Return last trip average electric consumption.
|
|
3419
2618
|
|
|
3420
2619
|
:return:
|
|
3421
2620
|
"""
|
|
3422
|
-
return float(
|
|
3423
|
-
find_path(self.attrs, f"{Services.TRIP_LAST}.averageElectricConsumption")
|
|
3424
|
-
)
|
|
2621
|
+
return float(find_path(self.attrs, f"{Services.TRIP_LAST}.averageElectricConsumption"))
|
|
3425
2622
|
|
|
3426
2623
|
@property
|
|
3427
2624
|
def trip_last_average_electric_engine_consumption_last_updated(self) -> datetime:
|
|
@@ -3430,25 +2627,23 @@ class Vehicle:
|
|
|
3430
2627
|
|
|
3431
2628
|
@property
|
|
3432
2629
|
def is_trip_last_average_electric_engine_consumption_supported(self) -> bool:
|
|
3433
|
-
"""
|
|
2630
|
+
"""
|
|
2631
|
+
Return true if supported.
|
|
3434
2632
|
|
|
3435
2633
|
:return:
|
|
3436
2634
|
"""
|
|
3437
|
-
return is_valid_path(
|
|
3438
|
-
self.attrs, f"{Services.TRIP_LAST}.averageElectricConsumption"
|
|
3439
|
-
) and type(
|
|
2635
|
+
return is_valid_path(self.attrs, f"{Services.TRIP_LAST}.averageElectricConsumption") and type(
|
|
3440
2636
|
find_path(self.attrs, f"{Services.TRIP_LAST}.averageElectricConsumption")
|
|
3441
2637
|
) in (float, int)
|
|
3442
2638
|
|
|
3443
2639
|
@property
|
|
3444
2640
|
def trip_last_average_fuel_consumption(self):
|
|
3445
|
-
"""
|
|
2641
|
+
"""
|
|
2642
|
+
Return last trip average fuel consumption.
|
|
3446
2643
|
|
|
3447
2644
|
:return:
|
|
3448
2645
|
"""
|
|
3449
|
-
return float(
|
|
3450
|
-
find_path(self.attrs, f"{Services.TRIP_LAST}.averageFuelConsumption")
|
|
3451
|
-
)
|
|
2646
|
+
return float(find_path(self.attrs, f"{Services.TRIP_LAST}.averageFuelConsumption"))
|
|
3452
2647
|
|
|
3453
2648
|
@property
|
|
3454
2649
|
def trip_last_average_fuel_consumption_last_updated(self) -> datetime:
|
|
@@ -3457,46 +2652,19 @@ class Vehicle:
|
|
|
3457
2652
|
|
|
3458
2653
|
@property
|
|
3459
2654
|
def is_trip_last_average_fuel_consumption_supported(self) -> bool:
|
|
3460
|
-
"""Return true if supported.
|
|
3461
|
-
|
|
3462
|
-
:return:
|
|
3463
|
-
"""
|
|
3464
|
-
return is_valid_path(
|
|
3465
|
-
self.attrs, f"{Services.TRIP_LAST}.averageFuelConsumption"
|
|
3466
|
-
) and type(
|
|
3467
|
-
find_path(self.attrs, f"{Services.TRIP_LAST}.averageFuelConsumption")
|
|
3468
|
-
) in (float, int)
|
|
3469
|
-
|
|
3470
|
-
@property
|
|
3471
|
-
def trip_last_average_gas_consumption(self):
|
|
3472
|
-
"""Return last trip average gas consumption.
|
|
3473
|
-
|
|
3474
|
-
:return:
|
|
3475
2655
|
"""
|
|
3476
|
-
|
|
3477
|
-
find_path(self.attrs, f"{Services.TRIP_LAST}.averageGasConsumption")
|
|
3478
|
-
)
|
|
3479
|
-
|
|
3480
|
-
@property
|
|
3481
|
-
def trip_last_average_gas_consumption_last_updated(self) -> datetime:
|
|
3482
|
-
"""Return last updated timestamp."""
|
|
3483
|
-
return find_path(self.attrs, f"{Services.TRIP_LAST}.tripEndTimestamp")
|
|
3484
|
-
|
|
3485
|
-
@property
|
|
3486
|
-
def is_trip_last_average_gas_consumption_supported(self) -> bool:
|
|
3487
|
-
"""Return true if supported.
|
|
2656
|
+
Return true if supported.
|
|
3488
2657
|
|
|
3489
2658
|
:return:
|
|
3490
2659
|
"""
|
|
3491
|
-
return is_valid_path(
|
|
3492
|
-
self.attrs, f"{Services.TRIP_LAST}.
|
|
3493
|
-
) and type(
|
|
3494
|
-
find_path(self.attrs, f"{Services.TRIP_LAST}.averageGasConsumption")
|
|
2660
|
+
return is_valid_path(self.attrs, f"{Services.TRIP_LAST}.averageFuelConsumption") and type(
|
|
2661
|
+
find_path(self.attrs, f"{Services.TRIP_LAST}.averageFuelConsumption")
|
|
3495
2662
|
) in (float, int)
|
|
3496
2663
|
|
|
3497
2664
|
@property
|
|
3498
2665
|
def trip_last_average_auxillary_consumption(self):
|
|
3499
|
-
"""
|
|
2666
|
+
"""
|
|
2667
|
+
Return last trip average auxiliary consumption.
|
|
3500
2668
|
|
|
3501
2669
|
:return:
|
|
3502
2670
|
"""
|
|
@@ -3510,19 +2678,19 @@ class Vehicle:
|
|
|
3510
2678
|
|
|
3511
2679
|
@property
|
|
3512
2680
|
def is_trip_last_average_auxillary_consumption_supported(self) -> bool:
|
|
3513
|
-
"""
|
|
2681
|
+
"""
|
|
2682
|
+
Return true if supported.
|
|
3514
2683
|
|
|
3515
2684
|
:return:
|
|
3516
2685
|
"""
|
|
3517
|
-
return is_valid_path(
|
|
3518
|
-
self.attrs, f"{Services.TRIP_LAST}.averageAuxiliaryConsumption"
|
|
3519
|
-
) and type(
|
|
2686
|
+
return is_valid_path(self.attrs, f"{Services.TRIP_LAST}.averageAuxiliaryConsumption") and type(
|
|
3520
2687
|
find_path(self.attrs, f"{Services.TRIP_LAST}.averageAuxiliaryConsumption")
|
|
3521
2688
|
) in (float, int)
|
|
3522
2689
|
|
|
3523
2690
|
@property
|
|
3524
2691
|
def trip_last_average_aux_consumer_consumption(self):
|
|
3525
|
-
"""
|
|
2692
|
+
"""
|
|
2693
|
+
Return last trip average auxiliary consumer consumption.
|
|
3526
2694
|
|
|
3527
2695
|
:return:
|
|
3528
2696
|
"""
|
|
@@ -3536,19 +2704,19 @@ class Vehicle:
|
|
|
3536
2704
|
|
|
3537
2705
|
@property
|
|
3538
2706
|
def is_trip_last_average_aux_consumer_consumption_supported(self) -> bool:
|
|
3539
|
-
"""
|
|
2707
|
+
"""
|
|
2708
|
+
Return true if supported.
|
|
3540
2709
|
|
|
3541
2710
|
:return:
|
|
3542
2711
|
"""
|
|
3543
|
-
return is_valid_path(
|
|
3544
|
-
self.attrs, f"{Services.TRIP_LAST}.averageAuxConsumerConsumption"
|
|
3545
|
-
) and type(
|
|
2712
|
+
return is_valid_path(self.attrs, f"{Services.TRIP_LAST}.averageAuxConsumerConsumption") and type(
|
|
3546
2713
|
find_path(self.attrs, f"{Services.TRIP_LAST}.averageAuxConsumerConsumption")
|
|
3547
2714
|
) in (float, int)
|
|
3548
2715
|
|
|
3549
2716
|
@property
|
|
3550
2717
|
def trip_last_duration(self):
|
|
3551
|
-
"""
|
|
2718
|
+
"""
|
|
2719
|
+
Return last trip duration in minutes(?).
|
|
3552
2720
|
|
|
3553
2721
|
:return:
|
|
3554
2722
|
"""
|
|
@@ -3561,7 +2729,8 @@ class Vehicle:
|
|
|
3561
2729
|
|
|
3562
2730
|
@property
|
|
3563
2731
|
def is_trip_last_duration_supported(self) -> bool:
|
|
3564
|
-
"""
|
|
2732
|
+
"""
|
|
2733
|
+
Return true if supported.
|
|
3565
2734
|
|
|
3566
2735
|
:return:
|
|
3567
2736
|
"""
|
|
@@ -3571,7 +2740,8 @@ class Vehicle:
|
|
|
3571
2740
|
|
|
3572
2741
|
@property
|
|
3573
2742
|
def trip_last_length(self):
|
|
3574
|
-
"""
|
|
2743
|
+
"""
|
|
2744
|
+
Return last trip length.
|
|
3575
2745
|
|
|
3576
2746
|
:return:
|
|
3577
2747
|
"""
|
|
@@ -3584,7 +2754,8 @@ class Vehicle:
|
|
|
3584
2754
|
|
|
3585
2755
|
@property
|
|
3586
2756
|
def is_trip_last_length_supported(self) -> bool:
|
|
3587
|
-
"""
|
|
2757
|
+
"""
|
|
2758
|
+
Return true if supported.
|
|
3588
2759
|
|
|
3589
2760
|
:return:
|
|
3590
2761
|
"""
|
|
@@ -3594,7 +2765,8 @@ class Vehicle:
|
|
|
3594
2765
|
|
|
3595
2766
|
@property
|
|
3596
2767
|
def trip_last_recuperation(self):
|
|
3597
|
-
"""
|
|
2768
|
+
"""
|
|
2769
|
+
Return last trip recuperation.
|
|
3598
2770
|
|
|
3599
2771
|
:return:
|
|
3600
2772
|
"""
|
|
@@ -3608,7 +2780,8 @@ class Vehicle:
|
|
|
3608
2780
|
|
|
3609
2781
|
@property
|
|
3610
2782
|
def is_trip_last_recuperation_supported(self) -> bool:
|
|
3611
|
-
"""
|
|
2783
|
+
"""
|
|
2784
|
+
Return true if supported.
|
|
3612
2785
|
|
|
3613
2786
|
:return:
|
|
3614
2787
|
"""
|
|
@@ -3618,7 +2791,8 @@ class Vehicle:
|
|
|
3618
2791
|
|
|
3619
2792
|
@property
|
|
3620
2793
|
def trip_last_average_recuperation(self):
|
|
3621
|
-
"""
|
|
2794
|
+
"""
|
|
2795
|
+
Return last trip total recuperation.
|
|
3622
2796
|
|
|
3623
2797
|
:return:
|
|
3624
2798
|
"""
|
|
@@ -3631,19 +2805,18 @@ class Vehicle:
|
|
|
3631
2805
|
|
|
3632
2806
|
@property
|
|
3633
2807
|
def is_trip_last_average_recuperation_supported(self) -> bool:
|
|
3634
|
-
"""
|
|
2808
|
+
"""
|
|
2809
|
+
Return true if supported.
|
|
3635
2810
|
|
|
3636
2811
|
:return:
|
|
3637
2812
|
"""
|
|
3638
2813
|
response = self.trip_last_entry
|
|
3639
|
-
return response and type(response.get("averageRecuperation", None)) in (
|
|
3640
|
-
float,
|
|
3641
|
-
int,
|
|
3642
|
-
)
|
|
2814
|
+
return response and type(response.get("averageRecuperation", None)) in (float, int)
|
|
3643
2815
|
|
|
3644
2816
|
@property
|
|
3645
2817
|
def trip_last_total_electric_consumption(self):
|
|
3646
|
-
"""
|
|
2818
|
+
"""
|
|
2819
|
+
Return last trip total electric consumption.
|
|
3647
2820
|
|
|
3648
2821
|
:return:
|
|
3649
2822
|
"""
|
|
@@ -3657,16 +2830,14 @@ class Vehicle:
|
|
|
3657
2830
|
|
|
3658
2831
|
@property
|
|
3659
2832
|
def is_trip_last_total_electric_consumption_supported(self) -> bool:
|
|
3660
|
-
"""
|
|
2833
|
+
"""
|
|
2834
|
+
Return true if supported.
|
|
3661
2835
|
|
|
3662
2836
|
:return:
|
|
3663
2837
|
"""
|
|
3664
2838
|
# Not implemented
|
|
3665
2839
|
response = self.trip_last_entry
|
|
3666
|
-
return response and type(response.get("totalElectricConsumption", None)) in (
|
|
3667
|
-
float,
|
|
3668
|
-
int,
|
|
3669
|
-
)
|
|
2840
|
+
return response and type(response.get("totalElectricConsumption", None)) in (float, int)
|
|
3670
2841
|
|
|
3671
2842
|
# Status of set data requests
|
|
3672
2843
|
@property
|
|
@@ -3709,11 +2880,9 @@ class Vehicle:
|
|
|
3709
2880
|
def request_in_progress(self) -> bool:
|
|
3710
2881
|
"""Check of any requests are currently in progress."""
|
|
3711
2882
|
try:
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
)
|
|
3716
|
-
except Exception as e: # pylint: disable=broad-exception-caught
|
|
2883
|
+
for section in self._requests:
|
|
2884
|
+
return self._requests[section].get("id", False)
|
|
2885
|
+
except Exception as e:
|
|
3717
2886
|
_LOGGER.warning(e)
|
|
3718
2887
|
return False
|
|
3719
2888
|
|
|
@@ -3721,18 +2890,11 @@ class Vehicle:
|
|
|
3721
2890
|
def request_in_progress_last_updated(self) -> datetime:
|
|
3722
2891
|
"""Return attribute last updated timestamp."""
|
|
3723
2892
|
try:
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
for item in self._requests.values()
|
|
3728
|
-
if isinstance(item, dict) and "timestamp" in item
|
|
3729
|
-
]
|
|
3730
|
-
|
|
3731
|
-
# Return the most recent timestamp
|
|
3732
|
-
return max(timestamps) if timestamps else datetime.now(UTC)
|
|
3733
|
-
except Exception as e: # pylint: disable=broad-exception-caught
|
|
2893
|
+
for section in self._requests:
|
|
2894
|
+
return self._requests[section].get("timestamp")
|
|
2895
|
+
except Exception as e:
|
|
3734
2896
|
_LOGGER.warning(e)
|
|
3735
|
-
return datetime.now(
|
|
2897
|
+
return datetime.now(timezone.utc)
|
|
3736
2898
|
|
|
3737
2899
|
@property
|
|
3738
2900
|
def is_request_in_progress_supported(self):
|
|
@@ -3742,18 +2904,9 @@ class Vehicle:
|
|
|
3742
2904
|
@property
|
|
3743
2905
|
def request_results(self) -> dict:
|
|
3744
2906
|
"""Get last request result."""
|
|
3745
|
-
data = {
|
|
3746
|
-
"latest": self._requests.get("latest", None),
|
|
3747
|
-
"state": self._requests.get("state", None),
|
|
3748
|
-
}
|
|
2907
|
+
data = {"latest": self._requests.get("latest", None), "state": self._requests.get("state", None)}
|
|
3749
2908
|
for section in self._requests:
|
|
3750
|
-
if section in [
|
|
3751
|
-
"departuretimer",
|
|
3752
|
-
"batterycharge",
|
|
3753
|
-
"climatisation",
|
|
3754
|
-
"refresh",
|
|
3755
|
-
"lock",
|
|
3756
|
-
]:
|
|
2909
|
+
if section in ["departuretimer", "batterycharge", "climatisation", "refresh", "lock"]:
|
|
3757
2910
|
data[section] = self._requests[section].get("status", "Unknown")
|
|
3758
2911
|
return data
|
|
3759
2912
|
|
|
@@ -3761,18 +2914,10 @@ class Vehicle:
|
|
|
3761
2914
|
def request_results_last_updated(self) -> datetime | None:
|
|
3762
2915
|
"""Get last updated time."""
|
|
3763
2916
|
if self._requests.get("latest", "") != "":
|
|
3764
|
-
return self._requests.get(str(self._requests.get("latest")), {}).get(
|
|
3765
|
-
"timestamp"
|
|
3766
|
-
)
|
|
2917
|
+
return self._requests.get(str(self._requests.get("latest")), {}).get("timestamp")
|
|
3767
2918
|
# all requests should have more or less the same timestamp anyway, so
|
|
3768
2919
|
# just return the first one
|
|
3769
|
-
for section in [
|
|
3770
|
-
"departuretimer",
|
|
3771
|
-
"batterycharge",
|
|
3772
|
-
"climatisation",
|
|
3773
|
-
"refresh",
|
|
3774
|
-
"lock",
|
|
3775
|
-
]:
|
|
2920
|
+
for section in ["departuretimer", "batterycharge", "climatisation", "refresh", "lock"]:
|
|
3776
2921
|
if section in self._requests:
|
|
3777
2922
|
return self._requests[section].get("timestamp")
|
|
3778
2923
|
return None
|
|
@@ -3794,211 +2939,104 @@ class Vehicle:
|
|
|
3794
2939
|
|
|
3795
2940
|
@property
|
|
3796
2941
|
def json(self):
|
|
3797
|
-
"""
|
|
2942
|
+
"""
|
|
2943
|
+
Return vehicle data in JSON format.
|
|
3798
2944
|
|
|
3799
2945
|
:return:
|
|
3800
2946
|
"""
|
|
3801
2947
|
|
|
3802
2948
|
def serialize(obj):
|
|
3803
|
-
"""
|
|
2949
|
+
"""
|
|
2950
|
+
Convert datetime instances back to JSON compatible format.
|
|
3804
2951
|
|
|
3805
2952
|
:param obj:
|
|
3806
2953
|
:return:
|
|
3807
2954
|
"""
|
|
3808
2955
|
return obj.isoformat() if isinstance(obj, datetime) else obj
|
|
3809
2956
|
|
|
3810
|
-
return to_json(
|
|
3811
|
-
OrderedDict(sorted(self.attrs.items())), indent=4, default=serialize
|
|
3812
|
-
)
|
|
2957
|
+
return to_json(OrderedDict(sorted(self.attrs.items())), indent=4, default=serialize)
|
|
3813
2958
|
|
|
3814
2959
|
def is_primary_drive_electric(self):
|
|
3815
2960
|
"""Check if primary engine is electric."""
|
|
3816
2961
|
return (
|
|
3817
|
-
find_path(
|
|
3818
|
-
self.attrs,
|
|
3819
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.primaryEngineType",
|
|
3820
|
-
)
|
|
2962
|
+
find_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.primaryEngineType")
|
|
3821
2963
|
== ENGINE_TYPE_ELECTRIC
|
|
3822
2964
|
)
|
|
3823
2965
|
|
|
3824
2966
|
def is_secondary_drive_electric(self):
|
|
3825
2967
|
"""Check if secondary engine is electric."""
|
|
3826
2968
|
return (
|
|
3827
|
-
is_valid_path(
|
|
3828
|
-
|
|
3829
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.secondaryEngineType",
|
|
3830
|
-
)
|
|
3831
|
-
and find_path(
|
|
3832
|
-
self.attrs,
|
|
3833
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.secondaryEngineType",
|
|
3834
|
-
)
|
|
2969
|
+
is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.primaryEngineType")
|
|
2970
|
+
and find_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.primaryEngineType")
|
|
3835
2971
|
== ENGINE_TYPE_ELECTRIC
|
|
3836
2972
|
)
|
|
3837
2973
|
|
|
3838
2974
|
def is_primary_drive_combustion(self):
|
|
3839
2975
|
"""Check if primary engine is combustion."""
|
|
3840
2976
|
engine_type = ""
|
|
3841
|
-
if is_valid_path(
|
|
3842
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.type"
|
|
3843
|
-
):
|
|
3844
|
-
engine_type = find_path(
|
|
3845
|
-
self.attrs,
|
|
3846
|
-
f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.type",
|
|
3847
|
-
)
|
|
2977
|
+
if is_valid_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.type"):
|
|
2978
|
+
engine_type = find_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.primaryEngine.type")
|
|
3848
2979
|
|
|
3849
|
-
if is_valid_path(
|
|
3850
|
-
self.attrs,
|
|
3851
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.primaryEngineType",
|
|
3852
|
-
):
|
|
3853
|
-
engine_type = find_path(
|
|
3854
|
-
self.attrs,
|
|
3855
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.primaryEngineType",
|
|
3856
|
-
)
|
|
2980
|
+
if is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.primaryEngineType"):
|
|
2981
|
+
engine_type = find_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.primaryEngineType")
|
|
3857
2982
|
|
|
3858
2983
|
return engine_type in ENGINE_TYPE_COMBUSTION
|
|
3859
2984
|
|
|
3860
2985
|
def is_secondary_drive_combustion(self):
|
|
3861
2986
|
"""Check if secondary engine is combustion."""
|
|
3862
2987
|
engine_type = ""
|
|
3863
|
-
if is_valid_path(
|
|
3864
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.secondaryEngine.type"
|
|
3865
|
-
):
|
|
3866
|
-
engine_type = find_path(
|
|
3867
|
-
self.attrs,
|
|
3868
|
-
f"{Services.FUEL_STATUS}.rangeStatus.value.secondaryEngine.type",
|
|
3869
|
-
)
|
|
2988
|
+
if is_valid_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.secondaryEngine.type"):
|
|
2989
|
+
engine_type = find_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.secondaryEngine.type")
|
|
3870
2990
|
|
|
3871
|
-
if is_valid_path(
|
|
3872
|
-
self.attrs,
|
|
3873
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.secondaryEngineType",
|
|
3874
|
-
):
|
|
3875
|
-
engine_type = find_path(
|
|
3876
|
-
self.attrs,
|
|
3877
|
-
f"{Services.MEASUREMENTS}.fuelLevelStatus.value.secondaryEngineType",
|
|
3878
|
-
)
|
|
2991
|
+
if is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.secondaryEngineType"):
|
|
2992
|
+
engine_type = find_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.secondaryEngineType")
|
|
3879
2993
|
|
|
3880
2994
|
return engine_type in ENGINE_TYPE_COMBUSTION
|
|
3881
2995
|
|
|
3882
|
-
def is_primary_drive_gas(self):
|
|
3883
|
-
"""Check if primary engine is gas."""
|
|
3884
|
-
if is_valid_path(
|
|
3885
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"
|
|
3886
|
-
):
|
|
3887
|
-
return (
|
|
3888
|
-
find_path(
|
|
3889
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"
|
|
3890
|
-
)
|
|
3891
|
-
== ENGINE_TYPE_GAS
|
|
3892
|
-
)
|
|
3893
|
-
if is_valid_path(
|
|
3894
|
-
self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"
|
|
3895
|
-
):
|
|
3896
|
-
return (
|
|
3897
|
-
find_path(
|
|
3898
|
-
self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"
|
|
3899
|
-
)
|
|
3900
|
-
== ENGINE_TYPE_GAS
|
|
3901
|
-
)
|
|
3902
|
-
return False
|
|
3903
|
-
|
|
3904
2996
|
@property
|
|
3905
2997
|
def is_car_type_electric(self):
|
|
3906
2998
|
"""Check if car type is electric."""
|
|
3907
|
-
if is_valid_path(
|
|
3908
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"
|
|
3909
|
-
):
|
|
3910
|
-
return (
|
|
3911
|
-
find_path(
|
|
3912
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"
|
|
3913
|
-
)
|
|
3914
|
-
== ENGINE_TYPE_ELECTRIC
|
|
3915
|
-
)
|
|
3916
|
-
if is_valid_path(
|
|
3917
|
-
self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"
|
|
3918
|
-
):
|
|
2999
|
+
if is_valid_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"):
|
|
3000
|
+
return find_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType") == ENGINE_TYPE_ELECTRIC
|
|
3001
|
+
if is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"):
|
|
3919
3002
|
return (
|
|
3920
|
-
find_path(
|
|
3921
|
-
self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"
|
|
3922
|
-
)
|
|
3923
|
-
== ENGINE_TYPE_ELECTRIC
|
|
3003
|
+
find_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType") == ENGINE_TYPE_ELECTRIC
|
|
3924
3004
|
)
|
|
3925
3005
|
return False
|
|
3926
3006
|
|
|
3927
3007
|
@property
|
|
3928
3008
|
def is_car_type_diesel(self):
|
|
3929
3009
|
"""Check if car type is diesel."""
|
|
3930
|
-
if is_valid_path(
|
|
3931
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"
|
|
3932
|
-
):
|
|
3933
|
-
return (
|
|
3934
|
-
find_path(
|
|
3935
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"
|
|
3936
|
-
)
|
|
3937
|
-
== ENGINE_TYPE_DIESEL
|
|
3938
|
-
)
|
|
3939
|
-
if is_valid_path(
|
|
3940
|
-
self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"
|
|
3941
|
-
):
|
|
3942
|
-
return (
|
|
3943
|
-
find_path(
|
|
3944
|
-
self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"
|
|
3945
|
-
)
|
|
3946
|
-
== ENGINE_TYPE_DIESEL
|
|
3947
|
-
)
|
|
3010
|
+
if is_valid_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"):
|
|
3011
|
+
return find_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType") == ENGINE_TYPE_DIESEL
|
|
3012
|
+
if is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"):
|
|
3013
|
+
return find_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType") == ENGINE_TYPE_DIESEL
|
|
3948
3014
|
return False
|
|
3949
3015
|
|
|
3950
3016
|
@property
|
|
3951
3017
|
def is_car_type_gasoline(self):
|
|
3952
3018
|
"""Check if car type is gasoline."""
|
|
3953
|
-
if is_valid_path(
|
|
3954
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"
|
|
3955
|
-
):
|
|
3956
|
-
return (
|
|
3957
|
-
find_path(
|
|
3958
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"
|
|
3959
|
-
)
|
|
3960
|
-
== ENGINE_TYPE_GASOLINE
|
|
3961
|
-
)
|
|
3962
|
-
if is_valid_path(
|
|
3963
|
-
self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"
|
|
3964
|
-
):
|
|
3019
|
+
if is_valid_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"):
|
|
3020
|
+
return find_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType") == ENGINE_TYPE_GASOLINE
|
|
3021
|
+
if is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"):
|
|
3965
3022
|
return (
|
|
3966
|
-
find_path(
|
|
3967
|
-
self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"
|
|
3968
|
-
)
|
|
3969
|
-
== ENGINE_TYPE_GASOLINE
|
|
3023
|
+
find_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType") == ENGINE_TYPE_GASOLINE
|
|
3970
3024
|
)
|
|
3971
3025
|
return False
|
|
3972
3026
|
|
|
3973
3027
|
@property
|
|
3974
3028
|
def is_car_type_hybrid(self):
|
|
3975
3029
|
"""Check if car type is hybrid."""
|
|
3976
|
-
if is_valid_path(
|
|
3977
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"
|
|
3978
|
-
):
|
|
3979
|
-
return (
|
|
3980
|
-
find_path(
|
|
3981
|
-
self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"
|
|
3982
|
-
)
|
|
3983
|
-
== ENGINE_TYPE_HYBRID
|
|
3984
|
-
)
|
|
3985
|
-
if is_valid_path(
|
|
3986
|
-
self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"
|
|
3987
|
-
):
|
|
3988
|
-
return (
|
|
3989
|
-
find_path(
|
|
3990
|
-
self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"
|
|
3991
|
-
)
|
|
3992
|
-
== ENGINE_TYPE_HYBRID
|
|
3993
|
-
)
|
|
3030
|
+
if is_valid_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType"):
|
|
3031
|
+
return find_path(self.attrs, f"{Services.FUEL_STATUS}.rangeStatus.value.carType") == ENGINE_TYPE_HYBRID
|
|
3032
|
+
if is_valid_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType"):
|
|
3033
|
+
return find_path(self.attrs, f"{Services.MEASUREMENTS}.fuelLevelStatus.value.carType") == ENGINE_TYPE_HYBRID
|
|
3994
3034
|
return False
|
|
3995
3035
|
|
|
3996
3036
|
@property
|
|
3997
3037
|
def has_combustion_engine(self):
|
|
3998
3038
|
"""Return true if car has a combustion engine."""
|
|
3999
|
-
return (
|
|
4000
|
-
self.is_primary_drive_combustion() or self.is_secondary_drive_combustion()
|
|
4001
|
-
)
|
|
3039
|
+
return self.is_primary_drive_combustion() or self.is_secondary_drive_combustion()
|
|
4002
3040
|
|
|
4003
3041
|
@property
|
|
4004
3042
|
def api_vehicles_status(self) -> bool:
|
|
@@ -4008,7 +3046,7 @@ class Vehicle:
|
|
|
4008
3046
|
@property
|
|
4009
3047
|
def api_vehicles_status_last_updated(self) -> datetime:
|
|
4010
3048
|
"""Return attribute last updated timestamp."""
|
|
4011
|
-
return datetime.now(
|
|
3049
|
+
return datetime.now(timezone.utc)
|
|
4012
3050
|
|
|
4013
3051
|
@property
|
|
4014
3052
|
def is_api_vehicles_status_supported(self):
|
|
@@ -4018,14 +3056,12 @@ class Vehicle:
|
|
|
4018
3056
|
@property
|
|
4019
3057
|
def api_capabilities_status(self) -> bool:
|
|
4020
3058
|
"""Check capabilities API status."""
|
|
4021
|
-
return self.attrs.get(Services.SERVICE_STATUS, {}).get(
|
|
4022
|
-
"capabilities", "Unknown"
|
|
4023
|
-
)
|
|
3059
|
+
return self.attrs.get(Services.SERVICE_STATUS, {}).get("capabilities", "Unknown")
|
|
4024
3060
|
|
|
4025
3061
|
@property
|
|
4026
3062
|
def api_capabilities_status_last_updated(self) -> datetime:
|
|
4027
3063
|
"""Return attribute last updated timestamp."""
|
|
4028
|
-
return datetime.now(
|
|
3064
|
+
return datetime.now(timezone.utc)
|
|
4029
3065
|
|
|
4030
3066
|
@property
|
|
4031
3067
|
def is_api_capabilities_status_supported(self):
|
|
@@ -4040,7 +3076,7 @@ class Vehicle:
|
|
|
4040
3076
|
@property
|
|
4041
3077
|
def api_trips_status_last_updated(self) -> datetime:
|
|
4042
3078
|
"""Return attribute last updated timestamp."""
|
|
4043
|
-
return datetime.now(
|
|
3079
|
+
return datetime.now(timezone.utc)
|
|
4044
3080
|
|
|
4045
3081
|
@property
|
|
4046
3082
|
def is_api_trips_status_supported(self):
|
|
@@ -4052,14 +3088,12 @@ class Vehicle:
|
|
|
4052
3088
|
@property
|
|
4053
3089
|
def api_selectivestatus_status(self) -> bool:
|
|
4054
3090
|
"""Check selectivestatus API status."""
|
|
4055
|
-
return self.attrs.get(Services.SERVICE_STATUS, {}).get(
|
|
4056
|
-
"selectivestatus", "Unknown"
|
|
4057
|
-
)
|
|
3091
|
+
return self.attrs.get(Services.SERVICE_STATUS, {}).get("selectivestatus", "Unknown")
|
|
4058
3092
|
|
|
4059
3093
|
@property
|
|
4060
3094
|
def api_selectivestatus_status_last_updated(self) -> datetime:
|
|
4061
3095
|
"""Return attribute last updated timestamp."""
|
|
4062
|
-
return datetime.now(
|
|
3096
|
+
return datetime.now(timezone.utc)
|
|
4063
3097
|
|
|
4064
3098
|
@property
|
|
4065
3099
|
def is_api_selectivestatus_status_supported(self):
|
|
@@ -4069,14 +3103,12 @@ class Vehicle:
|
|
|
4069
3103
|
@property
|
|
4070
3104
|
def api_parkingposition_status(self) -> bool:
|
|
4071
3105
|
"""Check parkingposition API status."""
|
|
4072
|
-
return self.attrs.get(Services.SERVICE_STATUS, {}).get(
|
|
4073
|
-
"parkingposition", "Unknown"
|
|
4074
|
-
)
|
|
3106
|
+
return self.attrs.get(Services.SERVICE_STATUS, {}).get("parkingposition", "Unknown")
|
|
4075
3107
|
|
|
4076
3108
|
@property
|
|
4077
3109
|
def api_parkingposition_status_last_updated(self) -> datetime:
|
|
4078
3110
|
"""Return attribute last updated timestamp."""
|
|
4079
|
-
return datetime.now(
|
|
3111
|
+
return datetime.now(timezone.utc)
|
|
4080
3112
|
|
|
4081
3113
|
@property
|
|
4082
3114
|
def is_api_parkingposition_status_supported(self):
|
|
@@ -4093,7 +3125,7 @@ class Vehicle:
|
|
|
4093
3125
|
@property
|
|
4094
3126
|
def api_token_status_last_updated(self) -> datetime:
|
|
4095
3127
|
"""Return attribute last updated timestamp."""
|
|
4096
|
-
return datetime.now(
|
|
3128
|
+
return datetime.now(timezone.utc)
|
|
4097
3129
|
|
|
4098
3130
|
@property
|
|
4099
3131
|
def is_api_token_status_supported(self):
|
|
@@ -4111,7 +3143,7 @@ class Vehicle:
|
|
|
4111
3143
|
@property
|
|
4112
3144
|
def last_data_refresh_last_updated(self) -> datetime:
|
|
4113
3145
|
"""Return attribute last updated timestamp."""
|
|
4114
|
-
return datetime.now(
|
|
3146
|
+
return datetime.now(timezone.utc)
|
|
4115
3147
|
|
|
4116
3148
|
@property
|
|
4117
3149
|
def is_last_data_refresh_supported(self):
|