carconnectivity-connector-skoda 0.1a20__tar.gz → 0.1a22__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.1a20 → carconnectivity_connector_skoda-0.1a22}/PKG-INFO +1 -1
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/doc/Config.md +2 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connector_skoda.egg-info/PKG-INFO +1 -1
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connector_skoda.egg-info/SOURCES.txt +1 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connectors/skoda/_version.py +1 -1
- carconnectivity_connector_skoda-0.1a22/src/carconnectivity_connectors/skoda/command_impl.py +74 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connectors/skoda/connector.py +159 -17
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connectors/skoda/mqtt_client.py +2 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/.flake8 +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/.github/dependabot.yml +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/.github/workflows/build.yml +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/.github/workflows/build_and_publish.yml +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/.github/workflows/codeql-analysis.yml +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/.gitignore +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/LICENSE +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/Makefile +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/README.md +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/pyproject.toml +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/setup.cfg +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/setup_requirements.txt +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connector_skoda.egg-info/dependency_links.txt +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connector_skoda.egg-info/requires.txt +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connector_skoda.egg-info/top_level.txt +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connectors/skoda/__init__.py +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connectors/skoda/auth/__init__.py +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connectors/skoda/auth/auth_util.py +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connectors/skoda/auth/helpers/blacklist_retry.py +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connectors/skoda/auth/my_skoda_session.py +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connectors/skoda/auth/openid_session.py +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connectors/skoda/auth/session_manager.py +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connectors/skoda/auth/skoda_web_session.py +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connectors/skoda/capability.py +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connectors/skoda/charging.py +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connectors/skoda/climatization.py +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connectors/skoda/error.py +0 -0
- {carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/src/carconnectivity_connectors/skoda/vehicle.py +0 -0
{carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/doc/Config.md
RENAMED
|
@@ -10,11 +10,13 @@ These are the valid options for the MySkoda Connector
|
|
|
10
10
|
"connectors": [
|
|
11
11
|
{
|
|
12
12
|
"type": "skoda", // Definition for the MySkoda Connector
|
|
13
|
+
"disabled": false, // You can disable connectors without removing them from the config completely
|
|
13
14
|
"config": {
|
|
14
15
|
"log_level": "error", // set the connectos log level
|
|
15
16
|
"interval": 300, // Interval in which the server is checked in seconds
|
|
16
17
|
"username": "test@test.de", // Username of your Volkswagen Account
|
|
17
18
|
"password": "testpassword123", // Username of your Volkswagen Account
|
|
19
|
+
"spin": 1234, //S-Pin used for some special commands like locking/unlocking
|
|
18
20
|
"netrc": "~/.netr", // netrc file if to be used for passwords
|
|
19
21
|
"api_log_level": "debug", // Show debug information regarding the API
|
|
20
22
|
"max_age": 300 //Cache requests to the server vor MAX_AGE seconds
|
|
@@ -22,6 +22,7 @@ src/carconnectivity_connectors/skoda/_version.py
|
|
|
22
22
|
src/carconnectivity_connectors/skoda/capability.py
|
|
23
23
|
src/carconnectivity_connectors/skoda/charging.py
|
|
24
24
|
src/carconnectivity_connectors/skoda/climatization.py
|
|
25
|
+
src/carconnectivity_connectors/skoda/command_impl.py
|
|
25
26
|
src/carconnectivity_connectors/skoda/connector.py
|
|
26
27
|
src/carconnectivity_connectors/skoda/error.py
|
|
27
28
|
src/carconnectivity_connectors/skoda/mqtt_client.py
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""This module defines the classes that represent attributes in the CarConnectivity system."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from typing import TYPE_CHECKING, Dict, Union
|
|
4
|
+
|
|
5
|
+
from enum import Enum
|
|
6
|
+
import argparse
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
from carconnectivity.commands import GenericCommand
|
|
10
|
+
from carconnectivity.objects import GenericObject
|
|
11
|
+
from carconnectivity.errors import SetterError
|
|
12
|
+
from carconnectivity.util import ThrowingArgumentParser
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from carconnectivity.objects import Optional
|
|
16
|
+
|
|
17
|
+
LOG: logging.Logger = logging.getLogger("carconnectivity")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SpinCommand(GenericCommand):
|
|
21
|
+
"""
|
|
22
|
+
LockUnlockCommand is a command class for locking and unlocking the vehicle.
|
|
23
|
+
|
|
24
|
+
Command (Enum): Enum class representing different commands for locking.
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
def __init__(self, name: str = 'spin', parent: Optional[GenericObject] = None) -> None:
|
|
28
|
+
super().__init__(name=name, parent=parent)
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def value(self) -> Optional[Union[str, Dict]]:
|
|
32
|
+
return super().value
|
|
33
|
+
|
|
34
|
+
@value.setter
|
|
35
|
+
def value(self, new_value: Optional[Union[str, Dict]]) -> None:
|
|
36
|
+
if isinstance(new_value, str):
|
|
37
|
+
parser = ThrowingArgumentParser(prog='', add_help=False, exit_on_error=False)
|
|
38
|
+
parser.add_argument('command', help='Command to execute', type=SpinCommand.Command,
|
|
39
|
+
choices=list(SpinCommand.Command))
|
|
40
|
+
parser.add_argument('--spin', dest='spin', help='Spin to be used instead of spin from config or .netrc', type=str, required=False,
|
|
41
|
+
default=None)
|
|
42
|
+
try:
|
|
43
|
+
args = parser.parse_args(new_value.split(sep=' '))
|
|
44
|
+
except argparse.ArgumentError as e:
|
|
45
|
+
raise SetterError(f'Invalid format for SpinCommand: {e.message} {parser.format_usage()}') from e
|
|
46
|
+
|
|
47
|
+
newvalue_dict = {}
|
|
48
|
+
newvalue_dict['command'] = args.command
|
|
49
|
+
if args.spin is not None:
|
|
50
|
+
newvalue_dict['spin'] = args.spin
|
|
51
|
+
new_value = newvalue_dict
|
|
52
|
+
elif isinstance(new_value, dict):
|
|
53
|
+
if 'command' in new_value and isinstance(new_value['command'], str):
|
|
54
|
+
if new_value['command'] in SpinCommand.Command:
|
|
55
|
+
new_value['command'] = SpinCommand.Command(new_value['command'])
|
|
56
|
+
else:
|
|
57
|
+
raise ValueError('Invalid value for SpinCommand. '
|
|
58
|
+
f'Command must be one of {SpinCommand.Command}')
|
|
59
|
+
if self._is_changeable:
|
|
60
|
+
for hook in self._on_set_hooks:
|
|
61
|
+
new_value = hook(self, new_value)
|
|
62
|
+
self._set_value(new_value)
|
|
63
|
+
else:
|
|
64
|
+
raise TypeError('You cannot set this attribute. Attribute is not mutable.')
|
|
65
|
+
|
|
66
|
+
class Command(Enum):
|
|
67
|
+
"""
|
|
68
|
+
Enum class representing different commands for SPIN.
|
|
69
|
+
|
|
70
|
+
"""
|
|
71
|
+
VERIFY = 'verify'
|
|
72
|
+
|
|
73
|
+
def __str__(self) -> str:
|
|
74
|
+
return self.value
|
|
@@ -27,7 +27,8 @@ from carconnectivity.charging import Charging
|
|
|
27
27
|
from carconnectivity.position import Position
|
|
28
28
|
from carconnectivity.climatization import Climatization
|
|
29
29
|
from carconnectivity.charging_connector import ChargingConnector
|
|
30
|
-
from carconnectivity.
|
|
30
|
+
from carconnectivity.commands import Commands
|
|
31
|
+
from carconnectivity.command_impl import ClimatizationStartStopCommand, ChargingStartStopCommand, HonkAndFlashCommand, LockUnlockCommand
|
|
31
32
|
|
|
32
33
|
from carconnectivity_connectors.base.connector import BaseConnector
|
|
33
34
|
from carconnectivity_connectors.skoda.auth.session_manager import SessionManager, SessionUser, Service
|
|
@@ -39,6 +40,7 @@ from carconnectivity_connectors.skoda.climatization import SkodaClimatization
|
|
|
39
40
|
from carconnectivity_connectors.skoda.error import Error
|
|
40
41
|
from carconnectivity_connectors.skoda._version import __version__
|
|
41
42
|
from carconnectivity_connectors.skoda.mqtt_client import SkodaMQTTClient
|
|
43
|
+
from carconnectivity_connectors.skoda.command_impl import SpinCommand
|
|
42
44
|
|
|
43
45
|
if TYPE_CHECKING:
|
|
44
46
|
from typing import Dict, List, Optional, Any, Set, Union
|
|
@@ -69,6 +71,7 @@ class Connector(BaseConnector):
|
|
|
69
71
|
|
|
70
72
|
self.connected: BooleanAttribute = BooleanAttribute(name="connected", parent=self)
|
|
71
73
|
self.interval: DurationAttribute = DurationAttribute(name="interval", parent=self)
|
|
74
|
+
self.commands: Commands = Commands(parent=self)
|
|
72
75
|
|
|
73
76
|
self.user_id: Optional[str] = None
|
|
74
77
|
|
|
@@ -91,6 +94,11 @@ class Connector(BaseConnector):
|
|
|
91
94
|
raise ConfigurationError(f'Invalid log level: "{config["log_level"]}" not in {list(logging._nameToLevel.keys())}')
|
|
92
95
|
LOG.info("Loading skoda connector with config %s", config_remove_credentials(self.config))
|
|
93
96
|
|
|
97
|
+
if 'spin' in config and config['spin'] is not None:
|
|
98
|
+
self._spin: Optional[str] = config['spin']
|
|
99
|
+
else:
|
|
100
|
+
self._spin = None
|
|
101
|
+
|
|
94
102
|
username: Optional[str] = None
|
|
95
103
|
password: Optional[str] = None
|
|
96
104
|
if 'username' in self.config and 'password' in self.config:
|
|
@@ -106,7 +114,13 @@ class Connector(BaseConnector):
|
|
|
106
114
|
secret: tuple[str, str, str] | None = secrets.authenticators("skoda")
|
|
107
115
|
if secret is None:
|
|
108
116
|
raise AuthenticationError(f'Authentication using {netrc_filename} failed: skoda not found in netrc')
|
|
109
|
-
username,
|
|
117
|
+
username, account, password = secret
|
|
118
|
+
|
|
119
|
+
if self._spin is None and account is not None:
|
|
120
|
+
try:
|
|
121
|
+
self._spin = account
|
|
122
|
+
except ValueError as err:
|
|
123
|
+
LOG.error('Could not parse spin from netrc: %s', err)
|
|
110
124
|
except netrc.NetrcParseError as err:
|
|
111
125
|
LOG.error('Authentification using %s failed: %s', netrc_filename, err)
|
|
112
126
|
raise AuthenticationError(f'Authentication using {netrc_filename} failed: {err}') from err
|
|
@@ -348,10 +362,11 @@ class Connector(BaseConnector):
|
|
|
348
362
|
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v1/charging/{vin}'
|
|
349
363
|
data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
|
|
350
364
|
if data is not None:
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
365
|
+
if not vehicle.climatization.commands.contains_command('start-stop'):
|
|
366
|
+
start_stop_command: ChargingStartStopCommand = ChargingStartStopCommand(parent=vehicle.charging.commands)
|
|
367
|
+
start_stop_command._add_on_set_hook(self.__on_charging_start_stop) # pylint: disable=protected-access
|
|
368
|
+
start_stop_command.enabled = True
|
|
369
|
+
vehicle.charging.commands.add_command(start_stop_command)
|
|
355
370
|
if 'carCapturedTimestamp' in data and data['carCapturedTimestamp'] is not None:
|
|
356
371
|
captured_at: datetime = robust_time_parse(data['carCapturedTimestamp'])
|
|
357
372
|
else:
|
|
@@ -872,6 +887,32 @@ class Connector(BaseConnector):
|
|
|
872
887
|
else:
|
|
873
888
|
vehicle.capabilities.clear_capabilities()
|
|
874
889
|
|
|
890
|
+
# Add HONK_AND_FLASH command if necessary capabilities are available
|
|
891
|
+
if vehicle.capabilities.has_capability('HONK_AND_FLASH') and vehicle.capabilities.has_capability('PARKING_POSITION'):
|
|
892
|
+
if vehicle.commands is not None and vehicle.commands.commands is not None \
|
|
893
|
+
and not vehicle.commands.contains_command('honk-flash'):
|
|
894
|
+
honk_flash_command = HonkAndFlashCommand(parent=vehicle.commands)
|
|
895
|
+
honk_flash_command._add_on_set_hook(self.__on_honk_flash) # pylint: disable=protected-access
|
|
896
|
+
honk_flash_command.enabled = True
|
|
897
|
+
vehicle.commands.add_command(honk_flash_command)
|
|
898
|
+
|
|
899
|
+
# Add lock and unlock command
|
|
900
|
+
if vehicle.capabilities.has_capability('ACCESS'):
|
|
901
|
+
if vehicle.doors is not None and vehicle.doors.commands is not None and vehicle.doors.commands.commands is not None \
|
|
902
|
+
and not vehicle.doors.commands.contains_command('lock-unlock'):
|
|
903
|
+
lock_unlock_command = LockUnlockCommand(parent=vehicle.doors.commands)
|
|
904
|
+
lock_unlock_command._add_on_set_hook(self.__on_lock_unlock) # pylint: disable=protected-access
|
|
905
|
+
lock_unlock_command.enabled = True
|
|
906
|
+
vehicle.doors.commands.add_command(lock_unlock_command)
|
|
907
|
+
|
|
908
|
+
# Add spin command
|
|
909
|
+
if vehicle.commands is not None and vehicle.commands.commands is not None \
|
|
910
|
+
and not vehicle.commands.contains_command('spin'):
|
|
911
|
+
spin_command = SpinCommand(parent=self.commands)
|
|
912
|
+
spin_command._add_on_set_hook(self.__on_spin) # pylint: disable=protected-access
|
|
913
|
+
spin_command.enabled = True
|
|
914
|
+
vehicle.commands.add_command(spin_command)
|
|
915
|
+
|
|
875
916
|
if 'specification' in vehicle_data and vehicle_data['specification'] is not None:
|
|
876
917
|
if 'model' in vehicle_data['specification'] and vehicle_data['specification']['model'] is not None:
|
|
877
918
|
vehicle.model._set_value(vehicle_data['specification']['model']) # pylint: disable=protected-access
|
|
@@ -1009,7 +1050,10 @@ class Connector(BaseConnector):
|
|
|
1009
1050
|
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v2/vehicle-status/{vin}'
|
|
1010
1051
|
vehicle_status_data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
|
|
1011
1052
|
if vehicle_status_data:
|
|
1012
|
-
|
|
1053
|
+
if 'carCapturedTimestamp' in vehicle_status_data and vehicle_status_data['carCapturedTimestamp'] is not None:
|
|
1054
|
+
captured_at: Optional[datetime] = robust_time_parse(vehicle_status_data['carCapturedTimestamp'])
|
|
1055
|
+
else:
|
|
1056
|
+
captured_at: Optional[datetime] = None
|
|
1013
1057
|
if 'overall' in vehicle_status_data and vehicle_status_data['overall'] is not None:
|
|
1014
1058
|
if 'doorsLocked' in vehicle_status_data['overall'] and vehicle_status_data['overall']['doorsLocked'] is not None \
|
|
1015
1059
|
and vehicle.doors is not None:
|
|
@@ -1448,16 +1492,16 @@ class Connector(BaseConnector):
|
|
|
1448
1492
|
command_dict['targetTemperature']['temperatureValue'] = 25.0
|
|
1449
1493
|
command_dict['targetTemperature']['unitInCar'] = 'CELSIUS'
|
|
1450
1494
|
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v2/air-conditioning/{vin}/start'
|
|
1451
|
-
|
|
1495
|
+
command_response: requests.Response = self.session.post(url, data=json.dumps(command_dict), allow_redirects=True)
|
|
1452
1496
|
elif command_arguments['command'] == ClimatizationStartStopCommand.Command.STOP:
|
|
1453
1497
|
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v2/air-conditioning/{vin}/stop'
|
|
1454
|
-
|
|
1498
|
+
command_response: requests.Response = self.session.post(url, allow_redirects=True)
|
|
1455
1499
|
else:
|
|
1456
1500
|
raise SetterError(f'Unknown command {command_arguments["command"]}')
|
|
1457
1501
|
|
|
1458
|
-
if
|
|
1459
|
-
LOG.error('Could not start/stop air conditioning (%s: %s)',
|
|
1460
|
-
raise SetterError(f'Could not start/stop air conditioning ({
|
|
1502
|
+
if command_response.status_code != requests.codes['accepted']:
|
|
1503
|
+
LOG.error('Could not start/stop air conditioning (%s: %s)', command_response.status_code, command_response.text)
|
|
1504
|
+
raise SetterError(f'Could not start/stop air conditioning ({command_response.status_code}: {command_response.text})')
|
|
1461
1505
|
return command_arguments
|
|
1462
1506
|
|
|
1463
1507
|
def __on_charging_start_stop(self, start_stop_command: ChargingStartStopCommand, command_arguments: Union[str, Dict[str, Any]]) \
|
|
@@ -1475,14 +1519,112 @@ class Connector(BaseConnector):
|
|
|
1475
1519
|
raise SetterError('Command argument missing')
|
|
1476
1520
|
if command_arguments['command'] == ChargingStartStopCommand.Command.START:
|
|
1477
1521
|
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v1/charging/{vin}/start'
|
|
1478
|
-
|
|
1522
|
+
command_response: requests.Response = self.session.post(url, allow_redirects=True)
|
|
1479
1523
|
elif command_arguments['command'] == ChargingStartStopCommand.Command.STOP:
|
|
1480
1524
|
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v1/charging/{vin}/stop'
|
|
1481
|
-
|
|
1525
|
+
command_response: requests.Response = self.session.post(url, allow_redirects=True)
|
|
1482
1526
|
else:
|
|
1483
1527
|
raise SetterError(f'Unknown command {command_arguments["command"]}')
|
|
1484
1528
|
|
|
1485
|
-
if
|
|
1486
|
-
LOG.error('Could not start/stop charging (%s: %s)',
|
|
1487
|
-
raise SetterError(f'Could not start/stop charging ({
|
|
1529
|
+
if command_response.status_code != requests.codes['accepted']:
|
|
1530
|
+
LOG.error('Could not start/stop charging (%s: %s)', command_response.status_code, command_response.text)
|
|
1531
|
+
raise SetterError(f'Could not start/stop charging ({command_response.status_code}: {command_response.text})')
|
|
1532
|
+
return command_arguments
|
|
1533
|
+
|
|
1534
|
+
def __on_honk_flash(self, honk_flash_command: HonkAndFlashCommand, command_arguments: Union[str, Dict[str, Any]]) \
|
|
1535
|
+
-> Union[str, Dict[str, Any]]:
|
|
1536
|
+
if honk_flash_command.parent is None or honk_flash_command.parent.parent is None \
|
|
1537
|
+
or not isinstance(honk_flash_command.parent.parent, SkodaVehicle):
|
|
1538
|
+
raise SetterError('Object hierarchy is not as expected')
|
|
1539
|
+
if not isinstance(command_arguments, dict):
|
|
1540
|
+
raise SetterError('Command arguments are not a dictionary')
|
|
1541
|
+
vehicle: SkodaVehicle = honk_flash_command.parent.parent
|
|
1542
|
+
vin: Optional[str] = vehicle.vin.value
|
|
1543
|
+
if vin is None:
|
|
1544
|
+
raise SetterError('VIN in object hierarchy missing')
|
|
1545
|
+
if 'command' not in command_arguments:
|
|
1546
|
+
raise SetterError('Command argument missing')
|
|
1547
|
+
command_dict = {}
|
|
1548
|
+
if command_arguments['command'] in [HonkAndFlashCommand.Command.FLASH, HonkAndFlashCommand.Command.HONK_AND_FLASH]:
|
|
1549
|
+
command_dict['mode'] = command_arguments['command'].name
|
|
1550
|
+
command_dict['vehiclePosition'] = {}
|
|
1551
|
+
if vehicle.position is None or vehicle.position.latitude is None or vehicle.position.longitude is None \
|
|
1552
|
+
or vehicle.position.latitude.value is None or vehicle.position.longitude.value is None \
|
|
1553
|
+
or not vehicle.position.latitude.enabled or not vehicle.position.longitude.enabled:
|
|
1554
|
+
raise SetterError('Can only execute honk and flash commands if vehicle position is known')
|
|
1555
|
+
command_dict['vehiclePosition']['latitude'] = vehicle.position.latitude.value
|
|
1556
|
+
command_dict['vehiclePosition']['longitude'] = vehicle.position.longitude.value
|
|
1557
|
+
|
|
1558
|
+
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v1/vehicle-access/{vin}/honk-and-flash'
|
|
1559
|
+
command_response: requests.Response = self.session.post(url, data=json.dumps(command_dict), allow_redirects=True)
|
|
1560
|
+
if command_response.status_code != requests.codes['accepted']:
|
|
1561
|
+
LOG.error('Could not execute honk or flash command (%s: %s)', command_response.status_code, command_response.text)
|
|
1562
|
+
raise SetterError(f'Could not execute honk or flash command ({command_response.status_code}: {command_response.text})')
|
|
1563
|
+
else:
|
|
1564
|
+
raise SetterError(f'Unknown command {command_arguments["command"]}')
|
|
1565
|
+
return command_arguments
|
|
1566
|
+
|
|
1567
|
+
def __on_lock_unlock(self, lock_unlock_command: LockUnlockCommand, command_arguments: Union[str, Dict[str, Any]]) \
|
|
1568
|
+
-> Union[str, Dict[str, Any]]:
|
|
1569
|
+
if lock_unlock_command.parent is None or lock_unlock_command.parent.parent is None \
|
|
1570
|
+
or lock_unlock_command.parent.parent.parent is None or not isinstance(lock_unlock_command.parent.parent.parent, SkodaVehicle):
|
|
1571
|
+
raise SetterError('Object hierarchy is not as expected')
|
|
1572
|
+
if not isinstance(command_arguments, dict):
|
|
1573
|
+
raise SetterError('Command arguments are not a dictionary')
|
|
1574
|
+
vehicle: SkodaVehicle = lock_unlock_command.parent.parent.parent
|
|
1575
|
+
vin: Optional[str] = vehicle.vin.value
|
|
1576
|
+
if vin is None:
|
|
1577
|
+
raise SetterError('VIN in object hierarchy missing')
|
|
1578
|
+
if 'command' not in command_arguments:
|
|
1579
|
+
raise SetterError('Command argument missing')
|
|
1580
|
+
command_dict = {}
|
|
1581
|
+
if 'spin' in command_arguments:
|
|
1582
|
+
command_dict['currentSpin'] = command_arguments['spin']
|
|
1583
|
+
else:
|
|
1584
|
+
if self._spin is None:
|
|
1585
|
+
raise SetterError('S-PIN is missing, please add S-PIN to your configuration or .netrc file')
|
|
1586
|
+
command_dict['currentSpin'] = self._spin
|
|
1587
|
+
if command_arguments['command'] == LockUnlockCommand.Command.LOCK:
|
|
1588
|
+
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v1/vehicle-access/{vin}/lock'
|
|
1589
|
+
elif command_arguments['command'] == LockUnlockCommand.Command.UNLOCK:
|
|
1590
|
+
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v1/vehicle-access/{vin}/unlock'
|
|
1591
|
+
else:
|
|
1592
|
+
raise SetterError(f'Unknown command {command_arguments["command"]}')
|
|
1593
|
+
command_response: requests.Response = self.session.post(url, data=json.dumps(command_dict), allow_redirects=True)
|
|
1594
|
+
if command_response.status_code != requests.codes['accepted']:
|
|
1595
|
+
LOG.error('Could not execute locking command (%s: %s)', command_response.status_code, command_response.text)
|
|
1596
|
+
raise SetterError(f'Could not execute locking command ({command_response.status_code}: {command_response.text})')
|
|
1597
|
+
return command_arguments
|
|
1598
|
+
|
|
1599
|
+
def __on_spin(self, spin_command: SpinCommand, command_arguments: Union[str, Dict[str, Any]]) \
|
|
1600
|
+
-> Union[str, Dict[str, Any]]:
|
|
1601
|
+
if spin_command.parent is None or spin_command.parent.parent is None or not isinstance(spin_command.parent.parent, SkodaVehicle):
|
|
1602
|
+
raise SetterError('Object hierarchy is not as expected')
|
|
1603
|
+
if not isinstance(command_arguments, dict):
|
|
1604
|
+
raise SetterError('Command arguments are not a dictionary')
|
|
1605
|
+
vehicle: SkodaVehicle = spin_command.parent.parent
|
|
1606
|
+
vin: Optional[str] = vehicle.vin.value
|
|
1607
|
+
if vin is None:
|
|
1608
|
+
raise SetterError('VIN in object hierarchy missing')
|
|
1609
|
+
if 'command' not in command_arguments:
|
|
1610
|
+
raise SetterError('Command argument missing')
|
|
1611
|
+
command_dict = {}
|
|
1612
|
+
if self._spin is None:
|
|
1613
|
+
raise SetterError('S-PIN is missing, please add S-PIN to your configuration or .netrc file')
|
|
1614
|
+
if 'spin' in command_arguments:
|
|
1615
|
+
command_dict['currentSpin'] = command_arguments['spin']
|
|
1616
|
+
else:
|
|
1617
|
+
if self._spin is None:
|
|
1618
|
+
raise SetterError('S-PIN is missing, please add S-PIN to your configuration or .netrc file')
|
|
1619
|
+
command_dict['currentSpin'] = self._spin
|
|
1620
|
+
if command_arguments['command'] == SpinCommand.Command.VERIFY:
|
|
1621
|
+
url = 'https://mysmob.api.connect.skoda-auto.cz/v1/spin/verify'
|
|
1622
|
+
else:
|
|
1623
|
+
raise SetterError(f'Unknown command {command_arguments["command"]}')
|
|
1624
|
+
command_response: requests.Response = self.session.post(url, data=json.dumps(command_dict), allow_redirects=True)
|
|
1625
|
+
if command_response.status_code != requests.codes['accepted']:
|
|
1626
|
+
LOG.error('Could not execute spin command (%s: %s)', command_response.status_code, command_response.text)
|
|
1627
|
+
raise SetterError(f'Could not execute spin command ({command_response.status_code}: {command_response.text})')
|
|
1628
|
+
else:
|
|
1629
|
+
LOG.info('Spin verify command executed successfully')
|
|
1488
1630
|
return command_arguments
|
|
@@ -494,6 +494,8 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
494
494
|
# pylint: disable-next=protected-access
|
|
495
495
|
vehicle.charging.power._set_value(value=0, measured=measured_at, unit=Power.KW)
|
|
496
496
|
if 'soc' in data['data'] and data['data']['soc'] is not None:
|
|
497
|
+
if isinstance(data['data']['soc'], str):
|
|
498
|
+
data['data']['soc'] = int(data['data']['soc'])
|
|
497
499
|
electric_drive.level._set_value(measured=measured_at, value=data['data']['soc']) # pylint: disable=protected-access
|
|
498
500
|
if 'chargedRange' in data['data'] and data['data']['chargedRange'] is not None:
|
|
499
501
|
# pylint: disable-next=protected-access
|
|
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.1a20 → carconnectivity_connector_skoda-0.1a22}/.gitignore
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{carconnectivity_connector_skoda-0.1a20 → carconnectivity_connector_skoda-0.1a22}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|