-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SOC Modul über SkodaConnect #762
Merged
Merged
Changes from 7 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
6278108
skodaconnect inital version
vuffiraa72 900aacf
handle refresh tokens
vuffiraa72 6600685
implement api as class
vuffiraa72 4dcd5ba
implement config to dict in class
vuffiraa72 e1c3e41
Update packages/modules/vehicles/skodaconnect/soc.py
vuffiraa72 1d698f0
Update packages/modules/vehicles/skodaconnect/api.py
vuffiraa72 bcdcb33
add logging for communication errors
vuffiraa72 9d5311e
keep name in Json config
vuffiraa72 ab0f9c4
create JSON directly
vuffiraa72 5adb9ce
test config with Optional of dict
vuffiraa72 File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import aiohttp | ||
import asyncio | ||
import logging | ||
from helpermodules.pub import Pub | ||
from modules.vehicles.skodaconnect.config import SkodaConnect, SkodaConnectConfiguration | ||
from skodaconnect import Connection | ||
from typing import Union | ||
|
||
|
||
log = logging.getLogger("soc."+__name__) | ||
|
||
|
||
class SkodaConnectApi(): | ||
|
||
def __init__(self, conf: SkodaConnect, vehicle: int) -> None: | ||
self.user_id = conf.configuration.user_id | ||
self.password = conf.configuration.password | ||
self.vin = conf.configuration.vin | ||
self.refresh_token = conf.configuration.refresh_token | ||
self.vehicle = vehicle | ||
|
||
def fetch_soc(self) -> Union[int, float]: | ||
# prepare and call async method | ||
loop = asyncio.new_event_loop() | ||
asyncio.set_event_loop(loop) | ||
|
||
soc, range = loop.run_until_complete(self._fetch_soc()) | ||
return soc, range | ||
|
||
async def _fetch_soc(self) -> Union[int, float]: | ||
async with aiohttp.ClientSession(headers={'Connection': 'keep-alive'}) as session: | ||
soc = 0 | ||
range = 0.0 | ||
login_success = False | ||
|
||
log.debug(f"Initiating new session to Skoda Connect with {self.user_id} as username") | ||
try: | ||
connection = Connection(session, self.user_id, self.password) | ||
if self.refresh_token is not None: | ||
log.debug("Attempting restore of tokens") | ||
if await connection.restore_tokens(self.refresh_token): | ||
log.debug("Token restore succeeded") | ||
login_success = True | ||
|
||
if not login_success: | ||
log.debug("Attempting to login to the Skoda Connect service") | ||
login_success = await connection.doLogin() | ||
except Exception: | ||
log.exception("Login failed!") | ||
|
||
if login_success: | ||
log.debug('Login success!') | ||
tokens = await connection.save_tokens() | ||
log.debug('Fetching charging data.') | ||
chargingState = await connection.getCharging(self.vin) | ||
if chargingState: | ||
if 'error_description' in chargingState: | ||
log.error(f"Failed to fetch charging data: {chargingState.get('error_description')}") | ||
if 'battery' in chargingState: | ||
batteryState = chargingState.get('battery') | ||
soc = batteryState.get('stateOfChargeInPercent') | ||
log.debug(f"Battery level: {soc}") | ||
range = int(batteryState.get('cruisingRangeElectricInMeters'))/1000 | ||
log.debug(f"Electric range: {range}") | ||
if tokens: | ||
self._persist_refresh_tokens(tokens) | ||
elif self.refresh_token is not None: | ||
# token seems to be invalid | ||
self._persist_refresh_tokens(None) | ||
return soc, range | ||
|
||
def _persist_refresh_tokens(self, tokens: dict) -> None: | ||
log.debug('Persist refresh tokens.') | ||
conf = SkodaConnect( | ||
configuration=SkodaConnectConfiguration( | ||
self.user_id, | ||
self.password, | ||
self.vin, | ||
tokens)) | ||
self._publish_refresh_tokens(conf.as_dict()) | ||
|
||
def _publish_refresh_tokens(self, config={}) -> None: | ||
try: | ||
Pub().pub("openWB/set/vehicle/" + self.vehicle + "/soc_module/config", config) | ||
except Exception as e: | ||
log.exception('Token mqtt write exception ' + str(e)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from typing import Optional | ||
from dataclass_utils import asdict | ||
|
||
|
||
class SkodaConnectConfiguration: | ||
def __init__(self, | ||
user_id: Optional[str] = None, # show in UI | ||
password: Optional[str] = None, # show in UI | ||
vin: Optional[str] = None, # show in UI | ||
refresh_token: Optional[dict] = None # DON'T show in UI! | ||
): | ||
self.user_id = user_id | ||
self.password = password | ||
self.vin = vin | ||
self.refresh_token = refresh_token | ||
|
||
|
||
class SkodaConnect: | ||
def __init__(self, | ||
name: str = "SkodaConnect", | ||
type: str = "skodaconnect", | ||
configuration: SkodaConnectConfiguration = None) -> None: | ||
self.name = name | ||
self.type = type | ||
self.configuration = configuration or SkodaConnectConfiguration() | ||
|
||
def as_dict(self) -> dict: | ||
confDict = asdict(self) | ||
confDict.pop('name') | ||
vuffiraa72 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return confDict |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
from typing import Union, List | ||
|
||
import logging | ||
|
||
from dataclass_utils import dataclass_from_dict | ||
from helpermodules.cli import run_using_positional_cli_args | ||
from modules.common import store | ||
from modules.common.abstract_device import DeviceDescriptor | ||
from modules.common.abstract_soc import AbstractSoc | ||
from modules.common.component_context import SingleComponentUpdateContext | ||
from modules.common.fault_state import ComponentInfo | ||
from modules.vehicles.skodaconnect.api import SkodaConnectApi | ||
from modules.vehicles.skodaconnect.config import SkodaConnect, SkodaConnectConfiguration | ||
|
||
|
||
log = logging.getLogger("soc."+__name__) | ||
|
||
|
||
class Soc(AbstractSoc): | ||
def __init__(self, device_config: Union[dict, SkodaConnect], vehicle: int): | ||
self.config = dataclass_from_dict(SkodaConnect, device_config) | ||
self.vehicle = vehicle | ||
self.store = store.get_car_value_store(self.vehicle) | ||
self.component_info = ComponentInfo(self.vehicle, self.config.name, "vehicle") | ||
|
||
def update(self, charge_state: bool = False) -> None: | ||
with SingleComponentUpdateContext(self.component_info): | ||
soc, range = SkodaConnectApi(self.config, self.vehicle).fetch_soc() | ||
|
||
|
||
def skodaconnect_update(user_id: str, password: str, vin: str, refresh_token: str, charge_point: int): | ||
log.debug("skodaconnect: userid="+user_id+"vin="+vin+"charge_point="+str(charge_point)) | ||
Soc( | ||
SkodaConnect(configuration=SkodaConnectConfiguration(user_id, password, vin, refresh_token)), | ||
charge_point).update() | ||
|
||
|
||
def main(argv: List[str]): | ||
run_using_positional_cli_args(skodaconnect_update, argv) | ||
|
||
|
||
device_descriptor = DeviceDescriptor(configuration_factory=SkodaConnect) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,3 +10,4 @@ PyJWT==2.6.0 | |
ipparser==0.3.8 | ||
bs4==0.0.1 | ||
pkce==1.0.3 | ||
skodaconnect==1.3.4 |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nach der Anmerkung von Lutz kann das nun weg oder?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nein, hier ist etwas anderes gemeint. In der Konfiguration werden Refresh-Tokens gespeichert, soweit sie verfügbar ist. Damit diese Tokens wieder wieder gepasst werden können, ist diese Anpassung nötig.
Ich habe mal zum Verständnis einen Test hinzugefügt.