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