server: replace carconnectivity with volkswagencarnet
Switches the VW API backend from carconnectivity + connector-volkswagen to volkswagencarnet (local fork with the cariad-hybrid-auth-fix patch applied), fixing authentication against the current CARIAD BFF endpoints. - requirements.txt: point at local volkswagencarnet git repo via git+file:// URL (editable path no longer needed now the patch is committed there) - we_connect.py: rewrite around the async volkswagencarnet Connection class; a persistent asyncio event loop held in _Session lets the rest of the code stay synchronous - data_model.py: remap all extractors to volkswagencarnet Vehicle properties and Paths constants; output shape preserved so apply_procedural and the GUI client continue to work unchanged - collect.py: swap carconnectivity error import, drop TemporaryAuthenticationError (no equivalent), fix vehicle.vin.value → vehicle.vin Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+48
-36
@@ -1,52 +1,64 @@
|
||||
import asyncio
|
||||
import logging
|
||||
import sys
|
||||
|
||||
try:
|
||||
from carconnectivity.carconnectivity import CarConnectivity
|
||||
except ImportError:
|
||||
print(
|
||||
"carconnectivity is not installed. Run: "
|
||||
"pip install carconnectivity carconnectivity-connector-volkswagen",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
import aiohttp
|
||||
from volkswagencarnet.vw_connection import Connection
|
||||
from volkswagencarnet.vw_exceptions import AuthenticationError # noqa: F401 — re-exported for collect.py
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def connect(username: str, password: str) -> CarConnectivity:
|
||||
config = {
|
||||
"carConnectivity": {
|
||||
"connectors": [
|
||||
{
|
||||
"type": "volkswagen",
|
||||
"config": {
|
||||
"username": username,
|
||||
"password": password,
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
cc = CarConnectivity(config=config)
|
||||
cc.startup()
|
||||
cc.fetch_all()
|
||||
return cc
|
||||
class _Session:
|
||||
"""Holds the asyncio event loop, aiohttp session, and Connection together."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
loop: asyncio.AbstractEventLoop,
|
||||
session: aiohttp.ClientSession,
|
||||
connection: Connection,
|
||||
) -> None:
|
||||
self._loop = loop
|
||||
self._http_session = session
|
||||
self.connection = connection
|
||||
|
||||
def run(self, coro):
|
||||
return self._loop.run_until_complete(coro)
|
||||
|
||||
@property
|
||||
def vehicles(self):
|
||||
return self.connection.vehicles
|
||||
|
||||
|
||||
def select_vehicle(cc: CarConnectivity, vin: str | None):
|
||||
def connect(username: str, password: str) -> _Session:
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
|
||||
async def _do():
|
||||
session = aiohttp.ClientSession(headers={"Connection": "keep-alive"})
|
||||
conn = Connection(session, username, password)
|
||||
ok = await conn.doLogin()
|
||||
if not ok:
|
||||
await session.close()
|
||||
raise AuthenticationError("Login failed")
|
||||
return session, conn
|
||||
|
||||
session, conn = loop.run_until_complete(_do())
|
||||
return _Session(loop, session, conn)
|
||||
|
||||
|
||||
def select_vehicle(wc: _Session, vin: str | None):
|
||||
"""Return (vehicle, error_message). error_message is None on success."""
|
||||
vehicles = list(cc.get_garage().list_vehicles())
|
||||
vehicles = wc.vehicles
|
||||
if not vehicles:
|
||||
return None, "No vehicles found in this CarConnectivity account"
|
||||
return None, "No vehicles found in this account"
|
||||
if vin:
|
||||
vehicle = next((v for v in vehicles if v.vin.value == vin), None)
|
||||
vehicle = next((v for v in vehicles if v.vin == vin), None)
|
||||
if not vehicle:
|
||||
available = [v.vin.value for v in vehicles]
|
||||
return None, f"VIN {vin} not found. Available: {available}"
|
||||
available = [v.vin for v in vehicles]
|
||||
return None, f"VIN {vin} not found. Available: {available}"
|
||||
return vehicle, None
|
||||
return vehicles[0], None
|
||||
|
||||
|
||||
def update(cc: CarConnectivity) -> None:
|
||||
cc.fetch_all()
|
||||
def update(wc: _Session) -> None:
|
||||
wc.run(wc.connection.update())
|
||||
|
||||
Reference in New Issue
Block a user