carconnectivity-connector-skoda 0.1a8__tar.gz → 0.1a10__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of carconnectivity-connector-skoda might be problematic. Click here for more details.
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/PKG-INFO +2 -2
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/setup_requirements.txt +1 -1
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connector_skoda.egg-info/PKG-INFO +2 -2
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connector_skoda.egg-info/SOURCES.txt +1 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connectors/skoda/_version.py +1 -1
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connectors/skoda/auth/openid_session.py +4 -0
- carconnectivity_connector_skoda-0.1a10/src/carconnectivity_connectors/skoda/charging.py +67 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connectors/skoda/connector.py +255 -12
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connectors/skoda/mqtt_client.py +84 -18
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/.flake8 +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/.github/dependabot.yml +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/.github/workflows/build.yml +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/.github/workflows/build_and_publish.yml +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/.github/workflows/codeql-analysis.yml +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/.gitignore +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/LICENSE +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/Makefile +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/README.md +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/doc/Config.md +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/pyproject.toml +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/setup.cfg +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connector_skoda.egg-info/dependency_links.txt +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connector_skoda.egg-info/requires.txt +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connector_skoda.egg-info/top_level.txt +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connectors/skoda/__init__.py +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connectors/skoda/auth/__init__.py +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connectors/skoda/auth/auth_util.py +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connectors/skoda/auth/helpers/blacklist_retry.py +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connectors/skoda/auth/my_skoda_session.py +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connectors/skoda/auth/session_manager.py +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connectors/skoda/auth/skoda_web_session.py +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connectors/skoda/capability.py +0 -0
- {carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/src/carconnectivity_connectors/skoda/vehicle.py +0 -0
|
@@ -20,6 +20,7 @@ src/carconnectivity_connector_skoda.egg-info/top_level.txt
|
|
|
20
20
|
src/carconnectivity_connectors/skoda/__init__.py
|
|
21
21
|
src/carconnectivity_connectors/skoda/_version.py
|
|
22
22
|
src/carconnectivity_connectors/skoda/capability.py
|
|
23
|
+
src/carconnectivity_connectors/skoda/charging.py
|
|
23
24
|
src/carconnectivity_connectors/skoda/connector.py
|
|
24
25
|
src/carconnectivity_connectors/skoda/mqtt_client.py
|
|
25
26
|
src/carconnectivity_connectors/skoda/vehicle.py
|
|
@@ -112,6 +112,10 @@ class OpenIDSession(requests.Session):
|
|
|
112
112
|
if new_retries_value:
|
|
113
113
|
# Retry on internal server error (500)
|
|
114
114
|
retries = BlacklistRetry(total=new_retries_value,
|
|
115
|
+
connect=new_retries_value,
|
|
116
|
+
read=new_retries_value,
|
|
117
|
+
status=new_retries_value,
|
|
118
|
+
other=new_retries_value,
|
|
115
119
|
backoff_factor=0.1,
|
|
116
120
|
status_forcelist=[500],
|
|
117
121
|
status_blacklist=[429],
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module for charging for skoda vehicles.
|
|
3
|
+
"""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from enum import Enum
|
|
8
|
+
|
|
9
|
+
from carconnectivity.charging import Charging
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from typing import Dict
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class SkodaCharging(Charging): # pylint: disable=too-many-instance-attributes
|
|
16
|
+
"""
|
|
17
|
+
SkodaCharging class for handling Skoda vehicle charging information.
|
|
18
|
+
|
|
19
|
+
This class extends the Charging class and includes an enumeration of various
|
|
20
|
+
charging states specific to Skoda vehicles.
|
|
21
|
+
"""
|
|
22
|
+
class SkodaChargingState(Enum,):
|
|
23
|
+
"""
|
|
24
|
+
Enum representing the various charging states for a Skoda vehicle.
|
|
25
|
+
|
|
26
|
+
Attributes:
|
|
27
|
+
OFF: The vehicle is not charging.
|
|
28
|
+
READY_FOR_CHARGING: The vehicle is ready to start charging.
|
|
29
|
+
NOT_READY_FOR_CHARGING: The vehicle is not ready to start charging.
|
|
30
|
+
CONSERVATION: The vehicle is in conservation mode.
|
|
31
|
+
CHARGE_PURPOSE_REACHED_NOT_CONSERVATION_CHARGING: The vehicle has reached its charging purpose and is not in conservation charging mode.
|
|
32
|
+
CHARGE_PURPOSE_REACHED_CONSERVATION: The vehicle has reached its charging purpose and is in conservation charging mode.
|
|
33
|
+
CHARGING: The vehicle is currently charging.
|
|
34
|
+
ERROR: There is an error in the charging process.
|
|
35
|
+
UNSUPPORTED: The charging state is unsupported.
|
|
36
|
+
DISCHARGING: The vehicle is discharging.
|
|
37
|
+
UNKNOWN: The charging state is unknown.
|
|
38
|
+
"""
|
|
39
|
+
OFF = 'off'
|
|
40
|
+
CONNECT_CABLE = 'connectCable'
|
|
41
|
+
READY_FOR_CHARGING = 'readyForCharging'
|
|
42
|
+
NOT_READY_FOR_CHARGING = 'notReadyForCharging'
|
|
43
|
+
CONSERVATION = 'conservation'
|
|
44
|
+
CHARGE_PURPOSE_REACHED_NOT_CONSERVATION_CHARGING = 'chargePurposeReachedAndNotConservationCharging'
|
|
45
|
+
CHARGE_PURPOSE_REACHED_CONSERVATION = 'chargePurposeReachedAndConservation'
|
|
46
|
+
CHARGING = 'charging'
|
|
47
|
+
ERROR = 'error'
|
|
48
|
+
UNSUPPORTED = 'unsupported'
|
|
49
|
+
DISCHARGING = 'discharging'
|
|
50
|
+
UNKNOWN = 'unknown charging state'
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Mapping of Skoda charging states to generic charging states
|
|
54
|
+
mapping_skoda_charging_state: Dict[SkodaCharging.SkodaChargingState, Charging.ChargingState] = {
|
|
55
|
+
SkodaCharging.SkodaChargingState.OFF: Charging.ChargingState.OFF,
|
|
56
|
+
SkodaCharging.SkodaChargingState.CONNECT_CABLE: Charging.ChargingState.OFF,
|
|
57
|
+
SkodaCharging.SkodaChargingState.READY_FOR_CHARGING: Charging.ChargingState.READY_FOR_CHARGING,
|
|
58
|
+
SkodaCharging.SkodaChargingState.NOT_READY_FOR_CHARGING: Charging.ChargingState.OFF,
|
|
59
|
+
SkodaCharging.SkodaChargingState.CONSERVATION: Charging.ChargingState.CONSERVATION,
|
|
60
|
+
SkodaCharging.SkodaChargingState.CHARGE_PURPOSE_REACHED_NOT_CONSERVATION_CHARGING: Charging.ChargingState.READY_FOR_CHARGING,
|
|
61
|
+
SkodaCharging.SkodaChargingState.CHARGE_PURPOSE_REACHED_CONSERVATION: Charging.ChargingState.CONSERVATION,
|
|
62
|
+
SkodaCharging.SkodaChargingState.CHARGING: Charging.ChargingState.CHARGING,
|
|
63
|
+
SkodaCharging.SkodaChargingState.ERROR: Charging.ChargingState.ERROR,
|
|
64
|
+
SkodaCharging.SkodaChargingState.UNSUPPORTED: Charging.ChargingState.UNSUPPORTED,
|
|
65
|
+
SkodaCharging.SkodaChargingState.DISCHARGING: Charging.ChargingState.DISCHARGING,
|
|
66
|
+
SkodaCharging.SkodaChargingState.UNKNOWN: Charging.ChargingState.UNKNOWN
|
|
67
|
+
}
|
|
@@ -6,7 +6,7 @@ import threading
|
|
|
6
6
|
import os
|
|
7
7
|
import logging
|
|
8
8
|
import netrc
|
|
9
|
-
from datetime import datetime, timedelta
|
|
9
|
+
from datetime import datetime, timedelta, timezone
|
|
10
10
|
import requests
|
|
11
11
|
|
|
12
12
|
from carconnectivity.garage import Garage
|
|
@@ -14,18 +14,22 @@ from carconnectivity.vehicle import GenericVehicle
|
|
|
14
14
|
from carconnectivity.errors import AuthenticationError, TooManyRequestsError, RetrievalError, APIError, APICompatibilityError, \
|
|
15
15
|
TemporaryAuthenticationError, ConfigurationError
|
|
16
16
|
from carconnectivity.util import robust_time_parse, log_extra_keys, config_remove_credentials
|
|
17
|
-
from carconnectivity.units import Length, Speed, Power
|
|
17
|
+
from carconnectivity.units import Length, Speed, Power, Temperature
|
|
18
18
|
from carconnectivity.doors import Doors
|
|
19
19
|
from carconnectivity.windows import Windows
|
|
20
20
|
from carconnectivity.lights import Lights
|
|
21
21
|
from carconnectivity.drive import GenericDrive, ElectricDrive, CombustionDrive
|
|
22
22
|
from carconnectivity.attributes import BooleanAttribute, DurationAttribute
|
|
23
|
+
from carconnectivity.charging import Charging
|
|
24
|
+
from carconnectivity.position import Position
|
|
25
|
+
from carconnectivity.climatization import Climatization
|
|
23
26
|
|
|
24
27
|
from carconnectivity_connectors.base.connector import BaseConnector
|
|
25
28
|
from carconnectivity_connectors.skoda.auth.session_manager import SessionManager, SessionUser, Service
|
|
26
29
|
from carconnectivity_connectors.skoda.auth.my_skoda_session import MySkodaSession
|
|
27
30
|
from carconnectivity_connectors.skoda.vehicle import SkodaVehicle, SkodaElectricVehicle, SkodaCombustionVehicle, SkodaHybridVehicle
|
|
28
31
|
from carconnectivity_connectors.skoda.capability import Capability
|
|
32
|
+
from carconnectivity_connectors.skoda.charging import SkodaCharging, mapping_skoda_charging_state
|
|
29
33
|
from carconnectivity_connectors.skoda._version import __version__
|
|
30
34
|
from carconnectivity_connectors.skoda.mqtt_client import SkodaMQTTClient
|
|
31
35
|
|
|
@@ -150,12 +154,17 @@ class Connector(BaseConnector):
|
|
|
150
154
|
|
|
151
155
|
def _background_loop(self) -> None:
|
|
152
156
|
self._stop_event.clear()
|
|
157
|
+
fetch: bool = True
|
|
153
158
|
while not self._stop_event.is_set():
|
|
154
159
|
interval = 300
|
|
155
160
|
try:
|
|
156
161
|
try:
|
|
157
|
-
|
|
158
|
-
|
|
162
|
+
if fetch:
|
|
163
|
+
self.fetch_all()
|
|
164
|
+
fetch = False
|
|
165
|
+
else:
|
|
166
|
+
self.update_vehicles()
|
|
167
|
+
self.last_update._set_value(value=datetime.now(tz=timezone.utc)) # pylint: disable=protected-access
|
|
159
168
|
if self.interval.value is not None:
|
|
160
169
|
interval: int = self.interval.value.total_seconds()
|
|
161
170
|
except Exception:
|
|
@@ -267,15 +276,41 @@ class Connector(BaseConnector):
|
|
|
267
276
|
vehicle.license_plate._set_value(None) # pylint: disable=protected-access
|
|
268
277
|
|
|
269
278
|
log_extra_keys(LOG_API, 'vehicles', vehicle_dict, {'vin', 'licensePlate'})
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
vehicle = self.fetch_charging(vehicle)
|
|
279
|
+
|
|
280
|
+
vehicle = self.fetch_vehicle_details(vehicle)
|
|
273
281
|
else:
|
|
274
282
|
raise APIError('Could not parse vehicle, vin missing')
|
|
275
283
|
for vin in set(garage.list_vehicle_vins()) - seen_vehicle_vins:
|
|
276
284
|
vehicle_to_remove = garage.get_vehicle(vin)
|
|
277
285
|
if vehicle_to_remove is not None and vehicle_to_remove.is_managed_by_connector(self):
|
|
278
286
|
garage.remove_vehicle(vin)
|
|
287
|
+
self.update_vehicles()
|
|
288
|
+
|
|
289
|
+
def update_vehicles(self) -> None:
|
|
290
|
+
"""
|
|
291
|
+
Updates the status of all vehicles in the garage managed by this connector.
|
|
292
|
+
|
|
293
|
+
This method iterates through all vehicle VINs in the garage, and for each vehicle that is
|
|
294
|
+
managed by this connector and is an instance of SkodaVehicle, it updates the vehicle's status
|
|
295
|
+
by fetching data from various APIs. If the vehicle is an instance of SkodaElectricVehicle,
|
|
296
|
+
it also fetches charging information.
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
None
|
|
300
|
+
"""
|
|
301
|
+
garage: Garage = self.car_connectivity.garage
|
|
302
|
+
for vin in set(garage.list_vehicle_vins()):
|
|
303
|
+
vehicle_to_update: Optional[GenericVehicle] = garage.get_vehicle(vin)
|
|
304
|
+
if vehicle_to_update is not None and isinstance(vehicle_to_update, SkodaVehicle) and vehicle_to_update.is_managed_by_connector(self):
|
|
305
|
+
vehicle_to_update = self.fetch_vehicle_status_second_api(vehicle_to_update)
|
|
306
|
+
vehicle_to_update = self.fetch_driving_range(vehicle_to_update)
|
|
307
|
+
if vehicle_to_update.capabilities is not None and vehicle_to_update.capabilities.enabled:
|
|
308
|
+
if vehicle_to_update.capabilities.has_capability('PARKING_POSITION'):
|
|
309
|
+
vehicle_to_update = self.fetch_position(vehicle_to_update)
|
|
310
|
+
if vehicle_to_update.capabilities.has_capability('CHARGING') and isinstance(vehicle_to_update, SkodaElectricVehicle):
|
|
311
|
+
vehicle_to_update = self.fetch_charging(vehicle_to_update)
|
|
312
|
+
if vehicle_to_update.capabilities.has_capability('AIR_CONDITIONING'):
|
|
313
|
+
vehicle_to_update = self.fetch_air_conditioning(vehicle_to_update)
|
|
279
314
|
|
|
280
315
|
def fetch_charging(self, vehicle: SkodaElectricVehicle) -> SkodaElectricVehicle:
|
|
281
316
|
"""
|
|
@@ -301,6 +336,18 @@ class Connector(BaseConnector):
|
|
|
301
336
|
else:
|
|
302
337
|
raise APIError('Could not fetch charging, carCapturedTimestamp missing')
|
|
303
338
|
if 'status' in data and data['status'] is not None:
|
|
339
|
+
if 'state' in data['status'] and data['status']['state'] is not None:
|
|
340
|
+
if data['status']['state'] in [item.name for item in SkodaCharging.SkodaChargingState]:
|
|
341
|
+
skoda_charging_state = SkodaCharging.SkodaChargingState[data['status']['state']]
|
|
342
|
+
charging_state: Charging.ChargingState = mapping_skoda_charging_state[skoda_charging_state]
|
|
343
|
+
else:
|
|
344
|
+
LOG_API.info('Unkown charging state %s not in %s', data['status']['state'], str(SkodaCharging.SkodaChargingState))
|
|
345
|
+
charging_state = Charging.ChargingState.UNKNOWN
|
|
346
|
+
|
|
347
|
+
# pylint: disable-next=protected-access
|
|
348
|
+
vehicle.charging.state._set_value(value=charging_state, measured=captured_at)
|
|
349
|
+
else:
|
|
350
|
+
vehicle.charging.state._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
|
304
351
|
if 'chargingRateInKilometersPerHour' in data['status'] and data['status']['chargingRateInKilometersPerHour'] is not None:
|
|
305
352
|
# pylint: disable-next=protected-access
|
|
306
353
|
vehicle.charging.rate._set_value(value=data['status']['chargingRateInKilometersPerHour'], measured=captured_at, unit=Speed.KMH)
|
|
@@ -313,19 +360,178 @@ class Connector(BaseConnector):
|
|
|
313
360
|
vehicle.charging.power._set_value(None, measured=captured_at, unit=Power.KW) # pylint: disable=protected-access
|
|
314
361
|
if 'remainingTimeToFullyChargedInMinutes' in data['status'] and data['status']['remainingTimeToFullyChargedInMinutes'] is not None:
|
|
315
362
|
remaining_duration: timedelta = timedelta(minutes=data['status']['remainingTimeToFullyChargedInMinutes'])
|
|
363
|
+
estimated_date_reached: datetime = captured_at + remaining_duration
|
|
316
364
|
# pylint: disable-next=protected-access
|
|
317
|
-
vehicle.charging.
|
|
365
|
+
vehicle.charging.estimated_date_reached._set_value(value=estimated_date_reached, measured=captured_at)
|
|
318
366
|
else:
|
|
319
|
-
vehicle.charging.
|
|
367
|
+
vehicle.charging.estimated_date_reached._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
|
320
368
|
log_extra_keys(LOG_API, 'status', data['status'], {'chargingRateInKilometersPerHour',
|
|
321
369
|
'chargePowerInKw',
|
|
322
|
-
'remainingTimeToFullyChargedInMinutes'
|
|
370
|
+
'remainingTimeToFullyChargedInMinutes',
|
|
371
|
+
'state'})
|
|
323
372
|
log_extra_keys(LOG_API, 'charging data', data, {'carCapturedTimestamp', 'status'})
|
|
324
373
|
return vehicle
|
|
325
374
|
|
|
326
|
-
def
|
|
375
|
+
def fetch_position(self, vehicle: SkodaVehicle) -> SkodaVehicle:
|
|
376
|
+
"""
|
|
377
|
+
Fetches the position of the given Skoda vehicle and updates its position attributes.
|
|
378
|
+
|
|
379
|
+
Args:
|
|
380
|
+
vehicle (SkodaVehicle): The Skoda vehicle object containing the VIN and position attributes.
|
|
381
|
+
|
|
382
|
+
Returns:
|
|
383
|
+
SkodaVehicle: The updated Skoda vehicle object with the fetched position data.
|
|
384
|
+
|
|
385
|
+
Raises:
|
|
386
|
+
APIError: If the VIN is missing.
|
|
387
|
+
ValueError: If the vehicle has no position object.
|
|
388
|
+
"""
|
|
389
|
+
vin = vehicle.vin.value
|
|
390
|
+
if vin is None:
|
|
391
|
+
raise APIError('VIN is missing')
|
|
392
|
+
if vehicle.position is None:
|
|
393
|
+
raise ValueError('Vehicle has no charging object')
|
|
394
|
+
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v1/maps/positions?vin={vin}'
|
|
395
|
+
data: Dict[str, Any] | None = self._fetch_data(url, session=self.session)
|
|
396
|
+
if data is not None:
|
|
397
|
+
if 'positions' in data and data['positions'] is not None:
|
|
398
|
+
for position_dict in data['positions']:
|
|
399
|
+
if 'type' in position_dict and position_dict['type'] == 'VEHICLE':
|
|
400
|
+
if 'gpsCoordinates' in position_dict and position_dict['gpsCoordinates'] is not None:
|
|
401
|
+
if 'latitude' in position_dict['gpsCoordinates'] and position_dict['gpsCoordinates']['latitude'] is not None:
|
|
402
|
+
latitude: Optional[float] = position_dict['gpsCoordinates']['latitude']
|
|
403
|
+
else:
|
|
404
|
+
latitude = None
|
|
405
|
+
if 'longitude' in position_dict['gpsCoordinates'] and position_dict['gpsCoordinates']['longitude'] is not None:
|
|
406
|
+
longitude: Optional[float] = position_dict['gpsCoordinates']['longitude']
|
|
407
|
+
else:
|
|
408
|
+
longitude = None
|
|
409
|
+
vehicle.position.latitude._set_value(latitude) # pylint: disable=protected-access
|
|
410
|
+
vehicle.position.longitude._set_value(longitude) # pylint: disable=protected-access
|
|
411
|
+
vehicle.position.position_type._set_value(Position.PositionType.PARKING) # pylint: disable=protected-access
|
|
412
|
+
else:
|
|
413
|
+
vehicle.position.latitude._set_value(None) # pylint: disable=protected-access
|
|
414
|
+
vehicle.position.longitude._set_value(None) # pylint: disable=protected-access
|
|
415
|
+
vehicle.position.position_type._set_value(None) # pylint: disable=protected-access
|
|
416
|
+
else:
|
|
417
|
+
vehicle.position.latitude._set_value(None) # pylint: disable=protected-access
|
|
418
|
+
vehicle.position.longitude._set_value(None) # pylint: disable=protected-access
|
|
419
|
+
vehicle.position.position_type._set_value(None) # pylint: disable=protected-access
|
|
420
|
+
log_extra_keys(LOG_API, 'positions', position_dict, {'type',
|
|
421
|
+
'gpsCoordinates',
|
|
422
|
+
'address'})
|
|
423
|
+
else:
|
|
424
|
+
vehicle.position.latitude._set_value(None) # pylint: disable=protected-access
|
|
425
|
+
vehicle.position.longitude._set_value(None) # pylint: disable=protected-access
|
|
426
|
+
vehicle.position.position_type._set_value(None) # pylint: disable=protected-access
|
|
427
|
+
return vehicle
|
|
428
|
+
|
|
429
|
+
def fetch_air_conditioning(self, vehicle: SkodaVehicle) -> SkodaVehicle:
|
|
327
430
|
"""
|
|
328
|
-
Fetches the
|
|
431
|
+
Fetches the air conditioning data for a given Skoda vehicle and updates the vehicle object with the retrieved data.
|
|
432
|
+
|
|
433
|
+
Args:
|
|
434
|
+
vehicle (SkodaVehicle): The vehicle object for which to fetch air conditioning data.
|
|
435
|
+
|
|
436
|
+
Returns:
|
|
437
|
+
SkodaVehicle: The updated vehicle object with the fetched air conditioning data.
|
|
438
|
+
|
|
439
|
+
Raises:
|
|
440
|
+
APIError: If the VIN is missing or if the carCapturedTimestamp is missing in the response data.
|
|
441
|
+
ValueError: If the vehicle has no charging object.
|
|
442
|
+
|
|
443
|
+
Notes:
|
|
444
|
+
- The method fetches data from the Skoda API using the vehicle's VIN.
|
|
445
|
+
- It updates the vehicle's climatization state, estimated date to reach target temperature, target temperature, and outside temperature.
|
|
446
|
+
- Logs additional keys found in the response data for debugging purposes.
|
|
447
|
+
"""
|
|
448
|
+
vin = vehicle.vin.value
|
|
449
|
+
if vin is None:
|
|
450
|
+
raise APIError('VIN is missing')
|
|
451
|
+
if vehicle.position is None:
|
|
452
|
+
raise ValueError('Vehicle has no charging object')
|
|
453
|
+
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v2/air-conditioning/{vin}'
|
|
454
|
+
data: Dict[str, Any] | None = self._fetch_data(url, session=self.session)
|
|
455
|
+
if data is not None:
|
|
456
|
+
if 'carCapturedTimestamp' in data and data['carCapturedTimestamp'] is not None:
|
|
457
|
+
captured_at: datetime = robust_time_parse(data['carCapturedTimestamp'])
|
|
458
|
+
else:
|
|
459
|
+
raise APIError('Could not fetch air conditioning, carCapturedTimestamp missing')
|
|
460
|
+
if 'state' in data and data['state'] is not None:
|
|
461
|
+
if data['state'] in [item.name for item in Climatization.ClimatizationState]:
|
|
462
|
+
climatization_state: Climatization.ClimatizationState = Climatization.ClimatizationState[data['state']]
|
|
463
|
+
else:
|
|
464
|
+
LOG_API.info('Unknown climatization state %s not in %s', data['state'], str(Climatization.ClimatizationState))
|
|
465
|
+
climatization_state = Climatization.ClimatizationState.UNKNOWN
|
|
466
|
+
vehicle.climatization.state._set_value(value=climatization_state, measured=captured_at) # pylint: disable=protected-access
|
|
467
|
+
else:
|
|
468
|
+
vehicle.climatization.state._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
|
469
|
+
if 'estimatedDateTimeToReachTargetTemperature' in data and data['estimatedDateTimeToReachTargetTemperature'] is not None:
|
|
470
|
+
estimated_reach: datetime = robust_time_parse(data['estimatedDateTimeToReachTargetTemperature'])
|
|
471
|
+
if estimated_reach is not None:
|
|
472
|
+
vehicle.climatization.estimated_date_reached._set_value(value=estimated_reach, measured=captured_at) # pylint: disable=protected-access
|
|
473
|
+
else:
|
|
474
|
+
vehicle.climatization.estimated_date_reached._set_value(value=None, measured=captured_at) # pylint: disable=protected-access
|
|
475
|
+
else:
|
|
476
|
+
vehicle.climatization.estimated_date_reached._set_value(value=None, measured=captured_at) # pylint: disable=protected-access
|
|
477
|
+
if 'targetTemperature' in data and data['targetTemperature'] is not None:
|
|
478
|
+
unit: Temperature = Temperature.UNKNOWN
|
|
479
|
+
if 'unitInCar' in data['targetTemperature'] and data['targetTemperature']['unitInCar'] is not None:
|
|
480
|
+
if data['targetTemperature']['unitInCar'] == 'CELSIUS':
|
|
481
|
+
unit = Temperature.C
|
|
482
|
+
elif data['targetTemperature']['unitInCar'] == 'FAHRENHEIT':
|
|
483
|
+
unit = Temperature.F
|
|
484
|
+
elif data['targetTemperature']['unitInCar'] == 'KELVIN':
|
|
485
|
+
unit = Temperature.K
|
|
486
|
+
else:
|
|
487
|
+
LOG_API.info('Unknown temperature unit for targetTemperature in air-conditioning %s', data['targetTemperature']['unitInCar'])
|
|
488
|
+
if 'temperatureValue' in data['targetTemperature'] and data['targetTemperature']['temperatureValue'] is not None:
|
|
489
|
+
# pylint: disable-next=protected-access
|
|
490
|
+
vehicle.climatization.target_temperature._set_value(value=data['targetTemperature']['temperatureValue'],
|
|
491
|
+
measured=captured_at,
|
|
492
|
+
unit=unit)
|
|
493
|
+
else:
|
|
494
|
+
vehicle.climatization.target_temperature._set_value(value=None, measured=captured_at, unit=unit) # pylint: disable=protected-access
|
|
495
|
+
log_extra_keys(LOG_API, 'targetTemperature', data['targetTemperature'], {'unitInCar', 'temperatureValue'})
|
|
496
|
+
else:
|
|
497
|
+
# pylint: disable-next=protected-access
|
|
498
|
+
vehicle.climatization.target_temperature._set_value(value=None, measured=captured_at, unit=Temperature.UNKNOWN)
|
|
499
|
+
if 'outsideTemperature' in data and data['outsideTemperature'] is not None:
|
|
500
|
+
if 'carCapturedTimestamp' in data['outsideTemperature'] and data['outsideTemperature']['carCapturedTimestamp'] is not None:
|
|
501
|
+
outside_captured_at: datetime = robust_time_parse(data['outsideTemperature']['carCapturedTimestamp'])
|
|
502
|
+
else:
|
|
503
|
+
outside_captured_at = captured_at
|
|
504
|
+
if 'temperatureUnit' in data['outsideTemperature'] and data['outsideTemperature']['temperatureUnit'] is not None:
|
|
505
|
+
unit: Temperature = Temperature.UNKNOWN
|
|
506
|
+
if data['outsideTemperature']['temperatureUnit'] == 'CELSIUS':
|
|
507
|
+
unit = Temperature.C
|
|
508
|
+
elif data['outsideTemperature']['temperatureUnit'] == 'FAHRENHEIT':
|
|
509
|
+
unit = Temperature.F
|
|
510
|
+
elif data['outsideTemperature']['temperatureUnit'] == 'KELVIN':
|
|
511
|
+
unit = Temperature.K
|
|
512
|
+
else:
|
|
513
|
+
LOG_API.info('Unknown temperature unit for outsideTemperature in air-conditioning %s', data['targetTemperature']['temperatureUnit'])
|
|
514
|
+
if 'temperatureValue' in data['outsideTemperature'] and data['outsideTemperature']['temperatureValue'] is not None:
|
|
515
|
+
# pylint: disable-next=protected-access
|
|
516
|
+
vehicle.outside_temperature._set_value(value=data['outsideTemperature']['temperatureValue'],
|
|
517
|
+
measured=outside_captured_at,
|
|
518
|
+
unit=unit)
|
|
519
|
+
else:
|
|
520
|
+
# pylint: disable-next=protected-access
|
|
521
|
+
vehicle.outside_temperature._set_value(value=None, measured=outside_captured_at, unit=Temperature.UNKNOWN)
|
|
522
|
+
else:
|
|
523
|
+
# pylint: disable-next=protected-access
|
|
524
|
+
vehicle.outside_temperature._set_value(value=None, measured=outside_captured_at, unit=Temperature.UNKNOWN)
|
|
525
|
+
log_extra_keys(LOG_API, 'targetTemperature', data['outsideTemperature'], {'carCapturedTimestamp', 'temperatureUnit', 'temperatureValue'})
|
|
526
|
+
else:
|
|
527
|
+
vehicle.outside_temperature._set_value(value=None, measured=None, unit=Temperature.UNKNOWN) # pylint: disable=protected-access
|
|
528
|
+
log_extra_keys(LOG_API, 'air-condition', data, {'carCapturedTimestamp', 'state', 'estimatedDateTimeToReachTargetTemperature'
|
|
529
|
+
'targetTemperature', 'outsideTemperature'})
|
|
530
|
+
return vehicle
|
|
531
|
+
|
|
532
|
+
def fetch_vehicle_details(self, vehicle: SkodaVehicle) -> SkodaVehicle:
|
|
533
|
+
"""
|
|
534
|
+
Fetches the details of a vehicle from the Skoda API.
|
|
329
535
|
|
|
330
536
|
Args:
|
|
331
537
|
vehicle (GenericVehicle): The vehicle object containing the VIN.
|
|
@@ -374,7 +580,30 @@ class Connector(BaseConnector):
|
|
|
374
580
|
else:
|
|
375
581
|
vehicle.model._set_value(None) # pylint: disable=protected-access
|
|
376
582
|
log_extra_keys(LOG_API, 'api/v2/garage/vehicles/VIN', vehicle_data, {'softwareVersion'})
|
|
583
|
+
return vehicle
|
|
377
584
|
|
|
585
|
+
def fetch_driving_range(self, vehicle: SkodaVehicle) -> SkodaVehicle:
|
|
586
|
+
"""
|
|
587
|
+
Fetches the driving range data for a given Skoda vehicle and updates the vehicle object accordingly.
|
|
588
|
+
|
|
589
|
+
Args:
|
|
590
|
+
vehicle (SkodaVehicle): The Skoda vehicle object for which to fetch the driving range data.
|
|
591
|
+
|
|
592
|
+
Returns:
|
|
593
|
+
SkodaVehicle: The updated Skoda vehicle object with the fetched driving range data.
|
|
594
|
+
|
|
595
|
+
Raises:
|
|
596
|
+
APIError: If the vehicle's VIN is missing.
|
|
597
|
+
|
|
598
|
+
Notes:
|
|
599
|
+
- The method fetches data from the Skoda API using the vehicle's VIN.
|
|
600
|
+
- It updates the vehicle's type if the fetched data indicates a different type (e.g., electric, combustion, hybrid).
|
|
601
|
+
- It updates the vehicle's total range and individual drive ranges (primary and secondary) based on the fetched data.
|
|
602
|
+
- It logs warnings for unknown car types and engine types.
|
|
603
|
+
"""
|
|
604
|
+
vin = vehicle.vin.value
|
|
605
|
+
if vin is None:
|
|
606
|
+
raise APIError('VIN is missing')
|
|
378
607
|
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v2/vehicle-status/{vin}/driving-range'
|
|
379
608
|
range_data: Dict[str, Any] | None = self._fetch_data(url, self.session)
|
|
380
609
|
if range_data:
|
|
@@ -461,7 +690,21 @@ class Connector(BaseConnector):
|
|
|
461
690
|
'totalRangeInKm',
|
|
462
691
|
'primaryEngineRange',
|
|
463
692
|
'secondaryEngineRange'})
|
|
693
|
+
return vehicle
|
|
694
|
+
|
|
695
|
+
def fetch_vehicle_status_second_api(self, vehicle: SkodaVehicle) -> SkodaVehicle:
|
|
696
|
+
"""
|
|
697
|
+
Fetches the status of a vehicle from other Skoda API.
|
|
698
|
+
|
|
699
|
+
Args:
|
|
700
|
+
vehicle (GenericVehicle): The vehicle object containing the VIN.
|
|
464
701
|
|
|
702
|
+
Returns:
|
|
703
|
+
None
|
|
704
|
+
"""
|
|
705
|
+
vin = vehicle.vin.value
|
|
706
|
+
if vin is None:
|
|
707
|
+
raise APIError('VIN is missing')
|
|
465
708
|
url = f'https://api.connect.skoda-auto.cz/api/v2/vehicle-status/{vin}'
|
|
466
709
|
vehicle_status_data: Dict[str, Any] | None = self._fetch_data(url, self.session)
|
|
467
710
|
if vehicle_status_data:
|
|
@@ -7,15 +7,21 @@ import logging
|
|
|
7
7
|
import uuid
|
|
8
8
|
import ssl
|
|
9
9
|
import json
|
|
10
|
-
from datetime import timedelta
|
|
10
|
+
from datetime import timedelta, timezone
|
|
11
11
|
|
|
12
12
|
from paho.mqtt.client import Client
|
|
13
13
|
from paho.mqtt.enums import MQTTProtocolVersion, CallbackAPIVersion, MQTTErrorCode
|
|
14
14
|
|
|
15
|
+
from carconnectivity.errors import CarConnectivityError
|
|
15
16
|
from carconnectivity.observable import Observable
|
|
16
|
-
from carconnectivity.vehicle import GenericVehicle
|
|
17
|
+
from carconnectivity.vehicle import GenericVehicle
|
|
18
|
+
|
|
17
19
|
from carconnectivity.drive import ElectricDrive
|
|
18
20
|
from carconnectivity.util import robust_time_parse, log_extra_keys
|
|
21
|
+
from carconnectivity.charging import Charging
|
|
22
|
+
|
|
23
|
+
from carconnectivity_connectors.skoda.vehicle import SkodaVehicle, SkodaElectricVehicle
|
|
24
|
+
from carconnectivity_connectors.skoda.charging import SkodaCharging, mapping_skoda_charging_state
|
|
19
25
|
|
|
20
26
|
|
|
21
27
|
if TYPE_CHECKING:
|
|
@@ -101,7 +107,7 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
101
107
|
if (flags & Observable.ObserverEvent.ENABLED) and isinstance(element, GenericVehicle):
|
|
102
108
|
self._subscribe_vehicle(element)
|
|
103
109
|
elif (flags & Observable.ObserverEvent.DISABLED) and isinstance(element, GenericVehicle):
|
|
104
|
-
self.
|
|
110
|
+
self._unsubscribe_vehicle(element)
|
|
105
111
|
|
|
106
112
|
def _subscribe_vehicles(self) -> None:
|
|
107
113
|
"""
|
|
@@ -235,15 +241,12 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
235
241
|
- Warning if the vehicle's VIN is not enabled or is None.
|
|
236
242
|
- Info for each topic successfully unsubscribed.
|
|
237
243
|
"""
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
self.unsubscribe(topic)
|
|
245
|
-
self.subscribed_topics.remove(topic)
|
|
246
|
-
LOG.debug('Unsubscribed from topic %s', topic)
|
|
244
|
+
vin: str = vehicle.id
|
|
245
|
+
for topic in self.subscribed_topics:
|
|
246
|
+
if vin in topic:
|
|
247
|
+
self.unsubscribe(topic)
|
|
248
|
+
self.subscribed_topics.remove(topic)
|
|
249
|
+
LOG.debug('Unsubscribed from topic %s', topic)
|
|
247
250
|
|
|
248
251
|
def _on_connect_callback(self, mqttc, obj, flags, reason_code, properties) -> None:
|
|
249
252
|
"""
|
|
@@ -434,7 +437,7 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
434
437
|
return
|
|
435
438
|
|
|
436
439
|
# service_events
|
|
437
|
-
match = re.match(r'^(?P<user_id>[0-9a-fA-F-]+)/(?P<vin>[A-Z0-9]+)/service-event/(?P<service_event
|
|
440
|
+
match = re.match(r'^(?P<user_id>[0-9a-fA-F-]+)/(?P<vin>[A-Z0-9]+)/service-event/(?P<service_event>[a-zA-Z0-9-_]+)$', msg.topic)
|
|
438
441
|
if match:
|
|
439
442
|
user_id: str = match.group('user_id')
|
|
440
443
|
vin: str = match.group('vin')
|
|
@@ -444,30 +447,93 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
444
447
|
if 'timestamp' in data and data['timestamp'] is not None:
|
|
445
448
|
measured_at: datetime = robust_time_parse(data['timestamp'])
|
|
446
449
|
else:
|
|
447
|
-
measured_at: datetime = datetime.now()
|
|
450
|
+
measured_at: datetime = datetime.now(tz=timezone.utc)
|
|
448
451
|
if service_event == 'charging':
|
|
449
452
|
if 'name' in data and data['name'] == 'change-charge-mode' or data['name'] == 'change-soc':
|
|
450
453
|
if 'data' in data and data['data'] is not None:
|
|
451
454
|
vehicle: Optional[GenericVehicle] = self._skoda_connector.car_connectivity.garage.get_vehicle(vin)
|
|
452
|
-
if isinstance(vehicle,
|
|
455
|
+
if isinstance(vehicle, SkodaElectricVehicle):
|
|
453
456
|
electric_drive: ElectricDrive = vehicle.get_electric_drive()
|
|
454
457
|
if electric_drive is not None:
|
|
458
|
+
charging_state: Optional[Charging.ChargingState] = vehicle.charging.state.value
|
|
459
|
+
old_charging_state: Optional[Charging.ChargingState] = charging_state
|
|
460
|
+
if 'state' in data['data'] and data['data']['state'] is not None:
|
|
461
|
+
if data['data']['state'] in [item.value for item in SkodaCharging.SkodaChargingState]:
|
|
462
|
+
skoda_charging_state = SkodaCharging.SkodaChargingState(data['data']['state'])
|
|
463
|
+
charging_state = mapping_skoda_charging_state[skoda_charging_state]
|
|
464
|
+
else:
|
|
465
|
+
LOG_API.info('Unkown charging state %s not in %s', data['data']['state'], str(SkodaCharging.SkodaChargingState))
|
|
466
|
+
charging_state = Charging.ChargingState.UNKNOWN
|
|
467
|
+
# pylint: disable-next=protected-access
|
|
468
|
+
vehicle.charging.state._set_value(value=charging_state, measured=measured_at)
|
|
469
|
+
if charging_state == Charging.ChargingState.OFF:
|
|
470
|
+
# pylint: disable-next=protected-access
|
|
471
|
+
vehicle.charging.type._set_value(value=Charging.ChargingType.OFF, measured=measured_at)
|
|
472
|
+
# pylint: disable-next=protected-access
|
|
473
|
+
vehicle.charging.rate._set_value(value=0, measured=measured_at)
|
|
474
|
+
# pylint: disable-next=protected-access
|
|
475
|
+
vehicle.charging.power._set_value(value=0, measured=measured_at)
|
|
455
476
|
if 'soc' in data['data'] and data['data']['soc'] is not None:
|
|
456
477
|
electric_drive.level._set_value(measured=measured_at, value=data['data']['soc']) # pylint: disable=protected-access
|
|
457
478
|
if 'chargedRange' in data['data'] and data['data']['chargedRange'] is not None:
|
|
458
479
|
# pylint: disable-next=protected-access
|
|
459
480
|
electric_drive.range._set_value(measured=measured_at, value=data['data']['chargedRange'])
|
|
481
|
+
# If charging state changed, fetch charging again
|
|
482
|
+
if old_charging_state != charging_state:
|
|
483
|
+
try:
|
|
484
|
+
self._skoda_connector.fetch_charging(vehicle)
|
|
485
|
+
except CarConnectivityError as e:
|
|
486
|
+
LOG.error('Error while fetching charging: %s', e)
|
|
460
487
|
if 'timeToFinish' in data['data'] and data['data']['timeToFinish'] is not None \
|
|
461
488
|
and vehicle.charging is not None:
|
|
462
|
-
|
|
489
|
+
try:
|
|
490
|
+
remaining_duration: Optional[timedelta] = timedelta(minutes=int(data['data']['timeToFinish']))
|
|
491
|
+
estimated_date_reached: Optional[datetime] = measured_at + remaining_duration
|
|
492
|
+
except ValueError:
|
|
493
|
+
estimated_date_reached: Optional[datetime] = None
|
|
463
494
|
# pylint: disable-next=protected-access
|
|
464
|
-
vehicle.charging.
|
|
465
|
-
log_extra_keys(LOG_API, 'data', data['data'], {'vin', 'userId', 'soc', 'chargedRange', 'timeToFinish'})
|
|
495
|
+
vehicle.charging.estimated_date_reached._set_value(measured=measured_at, value=estimated_date_reached)
|
|
496
|
+
log_extra_keys(LOG_API, 'data', data['data'], {'vin', 'userId', 'soc', 'chargedRange', 'timeToFinish', 'state'})
|
|
466
497
|
LOG.debug('Received %s event for vehicle %s from user %s', data['name'], vin, user_id)
|
|
467
498
|
return
|
|
499
|
+
else:
|
|
500
|
+
LOG.debug('Discarded %s event for vehicle %s from user %s: vehicle is not an electric vehicle', data['name'], vin, user_id)
|
|
501
|
+
LOG_API.info('Received event name %s service event %s for vehicle %s from user %s: %s', data['name'],
|
|
502
|
+
service_event, vin, user_id, msg.payload)
|
|
503
|
+
return
|
|
504
|
+
elif service_event == 'air-conditioning':
|
|
505
|
+
if 'name' in data and data['name'] == 'change-remaining-time':
|
|
506
|
+
if 'data' in data and data['data'] is not None:
|
|
507
|
+
vehicle: Optional[GenericVehicle] = self._skoda_connector.car_connectivity.garage.get_vehicle(vin)
|
|
508
|
+
if isinstance(vehicle, SkodaVehicle):
|
|
509
|
+
try:
|
|
510
|
+
self._skoda_connector.fetch_air_conditioning(vehicle)
|
|
511
|
+
except CarConnectivityError as e:
|
|
512
|
+
LOG.error('Error while fetching charging: %s', e)
|
|
468
513
|
LOG_API.info('Received event name %s service event %s for vehicle %s from user %s: %s', data['name'],
|
|
469
514
|
service_event, vin, user_id, msg.payload)
|
|
470
515
|
return
|
|
471
516
|
LOG_API.info('Received unknown service event %s for vehicle %s from user %s: %s', service_event, vin, user_id, msg.payload)
|
|
472
517
|
return
|
|
518
|
+
# service_events
|
|
519
|
+
match = re.match(r'^(?P<user_id>[0-9a-fA-F-]+)/(?P<vin>[A-Z0-9]+)/operation-request/(?P<operation_request>[a-zA-Z0-9-_/]+)$', msg.topic)
|
|
520
|
+
if match:
|
|
521
|
+
user_id: str = match.group('user_id')
|
|
522
|
+
vin: str = match.group('vin')
|
|
523
|
+
operation_request: str = match.group('operation_request')
|
|
524
|
+
data: Dict[str, Any] = json.loads(msg.payload)
|
|
525
|
+
if data is not None:
|
|
526
|
+
if operation_request == 'air-conditioning/start-stop-air-conditioning':
|
|
527
|
+
vehicle: Optional[GenericVehicle] = self._skoda_connector.car_connectivity.garage.get_vehicle(vin)
|
|
528
|
+
if isinstance(vehicle, SkodaVehicle):
|
|
529
|
+
if 'status' in data and data['status'] is not None:
|
|
530
|
+
if data['status'] == 'COMPLETED_SUCCESS':
|
|
531
|
+
LOG.debug('Received %s operation request for vehicle %s from user %s', operation_request, vin, user_id)
|
|
532
|
+
try:
|
|
533
|
+
self._skoda_connector.fetch_air_conditioning(vehicle)
|
|
534
|
+
except CarConnectivityError as e:
|
|
535
|
+
LOG.error('Error while fetching air-conditioning: %s', e)
|
|
536
|
+
return
|
|
537
|
+
LOG_API.info('Received unknown operation request %s for vehicle %s from user %s: %s', operation_request, vin, user_id, msg.payload)
|
|
538
|
+
return
|
|
473
539
|
LOG_API.info('I don\'t understand message %s: %s', msg.topic, msg.payload)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/doc/Config.md
RENAMED
|
File without changes
|
{carconnectivity_connector_skoda-0.1a8 → carconnectivity_connector_skoda-0.1a10}/pyproject.toml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|