-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgetMySkodaData.py
More file actions
135 lines (121 loc) · 5.16 KB
/
getMySkodaData.py
File metadata and controls
135 lines (121 loc) · 5.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import asyncio
import sys
import orjson
import contextlib
import io
from aiohttp import ClientSession, ClientTimeout
from aiohttp.client_exceptions import ClientResponseError
from myskoda import MySkoda
from myskoda.models.info import Info
from myskoda.models.health import Health
from myskoda.models.driving_range import DrivingRange
# Basic info to show (use info or vehicle):
# - Type of car
# - Vehicle status
# - Driving Range
# - Vehicle image
#
# Check:
# - If VehicleStatus = VehicleStatus.ACTIVATED
#
# More advanced info:
# - Position
# - Service events
# - Status - doors
# - Trip Statistics
async def main(email, password, vin):
session = None
myskoda = None
# Entering try block to avoid not closing session when any exception happens
try:
session = ClientSession(timeout=ClientTimeout(total=60))
myskoda = MySkoda(session, mqtt_enabled=False)
await myskoda.connect(email, password)
# Get all needed data
info: Info = await myskoda.get_info(vin)
health: Health = await myskoda.get_health(vin)
driving_range: DrivingRange = await myskoda.get_driving_range(vin)
#Decode nested objects into JSON
infoJSON = orjson.dumps(info).decode()
healthJSON = orjson.dumps(health).decode()
drivingRangeJSON = orjson.dumps(driving_range).decode()
#Deserialize to Python dictionaries
infoDict = orjson.loads(infoJSON)
healthDict = orjson.loads(healthJSON)
drivingRangeDict = orjson.loads(drivingRangeJSON)
#Merge the dictionaries
mySkodaDict = {**infoDict, **healthDict, **drivingRangeDict}
# Fetch additional endpoints with error handling
# Status endpoint
try:
with contextlib.redirect_stderr(io.StringIO()):
status = await myskoda.get_status(vin)
statusJSON = orjson.dumps(status).decode()
statusDict = orjson.loads(statusJSON)
mySkodaDict.update(statusDict)
except (ClientResponseError, Exception):
# Status endpoint may fail for some vehicles, continue without it
pass
# Positions endpoint
try:
with contextlib.redirect_stderr(io.StringIO()):
positions = await myskoda.get_positions(vin)
positionsJSON = orjson.dumps(positions).decode()
positionsDict = orjson.loads(positionsJSON)
mySkodaDict.update(positionsDict)
except (ClientResponseError, Exception):
# Positions endpoint may fail, continue without it
pass
# Maintenance endpoint
try:
with contextlib.redirect_stderr(io.StringIO()):
maintenance = await myskoda.get_maintenance(vin)
maintenanceJSON = orjson.dumps(maintenance).decode()
maintenanceDict = orjson.loads(maintenanceJSON)
mySkodaDict.update(maintenanceDict)
except (ClientResponseError, Exception):
# Maintenance endpoint may fail, continue without it
pass
# Charging endpoint (EV only)
# Check if vehicle is electric before attempting to fetch charging data
is_electric = (
infoDict.get('specification', {}).get('engine', {}).get('type') == 'iV' or
drivingRangeDict.get('car_type') == 'electric' or
drivingRangeDict.get('primary_engine_range', {}).get('engine_type') == 'electric'
)
if is_electric:
try:
# Suppress stderr for this call to avoid noisy error logs for expected failures
with contextlib.redirect_stderr(io.StringIO()):
charging = await myskoda.get_charging(vin)
chargingJSON = orjson.dumps(charging).decode()
chargingDict = orjson.loads(chargingJSON)
mySkodaDict.update(chargingDict)
except (ClientResponseError, Exception) as e:
# Charging endpoint may fail even for EVs (500 errors, etc.), continue without it
# Suppress the error as it's expected in some cases
pass
#Serialize the merged dictionary back to a JSON string
mySkodaJSON = orjson.dumps(mySkodaDict).decode()
except Exception as e:
# If any critical error occurs, log it and return error info
error_msg = str(e)
error_type = type(e).__name__
print(f"ERROR: {error_type}: {error_msg}", file=sys.stderr)
# Return error info as JSON so node_helper can handle it
error_dict = {"error": f"{error_type}: {error_msg}"}
mySkodaJSON = orjson.dumps(error_dict).decode()
finally:
#Closing connection
try:
if myskoda:
await myskoda.disconnect()
if session:
await session.close()
except:
pass
#Data returning to JS
print(mySkodaJSON)
sys.stdout.flush()
#Invoking the main function in CLI style
asyncio.run(main(sys.argv[1], sys.argv[2], sys.argv[3]))