Skip to content

Commit f2269f3

Browse files
authored
Merge pull request #317 from robinostlund/v5.4.5
v5.4.5
2 parents 0b8f979 + aa830c7 commit f2269f3

File tree

4 files changed

+66
-152
lines changed

4 files changed

+66
-152
lines changed

tests/vw_vehicle_test.py

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ async def test_init(self):
4545

4646
expected_services = {
4747
Services.ACCESS: {"active": False},
48-
Services.AUXILIARY_HEATING: {"active": False},
4948
Services.BATTERY_CHARGING_CARE: {"active": False},
5049
Services.BATTERY_SUPPORT: {"active": False},
5150
Services.CHARGING: {"active": False},
@@ -60,8 +59,6 @@ async def test_init(self):
6059
Services.TRIP_STATISTICS: {"active": False},
6160
Services.READINESS: {"active": False},
6261
Services.USER_CAPABILITIES: {"active": False},
63-
Services.VEHICLE_HEALTH_INSPECTION: {"active": False},
64-
Services.VEHICLE_LIGHTS: {"active": False},
6562
Services.PARAMETERS: {},
6663
}
6764

@@ -73,52 +70,42 @@ def test_str(self):
7370
vehicle = Vehicle(None, "XYZ1234567890")
7471
assert str(vehicle) == "XYZ1234567890"
7572

73+
def test_discover(self):
74+
"""Test the discovery process."""
75+
76+
@pytest.mark.asyncio
77+
async def test_update_deactivated(self):
78+
"""Test that calling update on a deactivated Vehicle does nothing."""
79+
vehicle = MagicMock(spec=Vehicle, name="MockDeactivatedVehicle")
80+
vehicle.update = lambda: Vehicle.update(vehicle)
81+
vehicle._discovered = True
82+
vehicle._deactivated = True
83+
84+
await vehicle.update()
85+
86+
vehicle.discover.assert_not_called()
87+
# Verify that no other methods were called
88+
assert len(vehicle.method_calls) == 0, (
89+
f"Expected none, got {vehicle.method_calls}"
90+
)
91+
7692
async def test_update(self):
7793
"""Test that update calls the wanted methods and nothing else."""
7894
vehicle = MagicMock(spec=Vehicle, name="MockUpdateVehicle")
7995
vehicle.update = lambda: Vehicle.update(vehicle)
8096

8197
vehicle._discovered = False
8298
vehicle.deactivated = False
83-
84-
# Add class constants to mock so the update logic can access them
85-
vehicle.SUPPORTED_SERVICES = Vehicle.SUPPORTED_SERVICES
86-
vehicle.UPDATE_EXCLUDED_SERVICES = Vehicle.UPDATE_EXCLUDED_SERVICES
87-
vehicle.SERVICE_FETCH_REPLACEMENTS = Vehicle.SERVICE_FETCH_REPLACEMENTS
88-
89-
# Mock _services with active services for dynamic service checking
90-
vehicle._services = {
91-
Services.ACCESS: {"active": True},
92-
Services.BATTERY_CHARGING_CARE: {"active": True},
93-
Services.BATTERY_SUPPORT: {"active": True},
94-
Services.CHARGING: {"active": True},
95-
Services.CLIMATISATION: {"active": True},
96-
Services.CLIMATISATION_TIMERS: {"active": True},
97-
Services.DEPARTURE_PROFILES: {"active": True},
98-
Services.DEPARTURE_TIMERS: {"active": True},
99-
Services.FUEL_STATUS: {"active": True},
100-
Services.MEASUREMENTS: {"active": True},
101-
Services.READINESS: {"active": True},
102-
Services.VEHICLE_LIGHTS: {"active": True},
103-
Services.VEHICLE_HEALTH_INSPECTION: {"active": True},
104-
Services.USER_CAPABILITIES: {"active": True},
105-
Services.PARKING_POSITION: {"active": True},
106-
Services.TRIP_STATISTICS: {"active": True},
107-
}
108-
10999
await vehicle.update()
110100

111101
vehicle.discover.assert_called_once()
112102
vehicle.get_selectivestatus.assert_called_once()
113103
vehicle.get_vehicle.assert_called_once()
114104
vehicle.get_parkingposition.assert_called_once()
115105
vehicle.get_trip_last.assert_called_once()
116-
vehicle.get_trip_refuel.assert_called_once()
117-
vehicle.get_trip_longterm.assert_called_once()
118106
vehicle.get_service_status.assert_called_once()
119107

120-
# 8 method calls: discover, get_vehicle, get_selectivestatus, get_parkingposition,
121-
# get_trip_last, get_trip_refuel, get_trip_longterm, get_service_status
108+
# Verify that only the expected functions above were called
122109
assert len(vehicle.method_calls) == 8, (
123110
f"Wrong number of methods called. Expected 8, got {len(vehicle.method_calls)}"
124111
)

volkswagencarnet/vw_connection.py

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,8 @@ def _clear_cookies(self):
8787
self._session._cookie_jar._cookies.clear() # pylint: disable=protected-access
8888

8989
# API Login
90-
async def doLogin(self, tries: int = 1, vin: str = None):
91-
"""Login method, clean login.
92-
93-
Args:
94-
tries: Number of login attempts
95-
vin: Optional VIN to load only a specific vehicle. If None, loads all vehicles.
96-
"""
90+
async def doLogin(self, tries: int = 1):
91+
"""Login method, clean login."""
9792
async with self._login_lock:
9893
_LOGGER.debug("Initiating new login")
9994

@@ -115,42 +110,18 @@ async def doLogin(self, tries: int = 1, vin: str = None):
115110
_LOGGER.debug("Fetching vehicles associated with account")
116111
self._session_headers.pop("Content-Type", None)
117112
loaded_vehicles = await self.get(url=f"{BASE_API}/vehicle/v2/vehicles")
118-
119-
# Add Vehicle class object for all or specific VIN-numbers from account
113+
# Add Vehicle class object for all VIN-numbers from account
120114
if loaded_vehicles.get("data") is not None:
115+
_LOGGER.debug("Found vehicle(s) associated with account")
121116
self._vehicles = []
122-
123-
if vin:
124-
# Only load the specified vehicle
125-
vin_upper = vin.upper()
126-
_LOGGER.debug("Looking for vehicle with VIN %s", vin_upper)
127-
for vehicle_data in loaded_vehicles.get("data"):
128-
if vehicle_data.get("vin").upper() == vin_upper:
129-
self._vehicles.append(
130-
Vehicle(self, vehicle_data.get("vin"))
131-
)
132-
_LOGGER.debug("Loaded vehicle with VIN %s", vin_upper)
133-
break
134-
135-
if not self._vehicles:
136-
_LOGGER.warning(
137-
"Vehicle with VIN %s not found in account", vin_upper
138-
)
139-
self._session_logged_in = False
140-
return False
141-
142-
_LOGGER.info("Found configured vehicle in account")
143-
else:
144-
# Load all vehicles (default behavior for config flow)
145-
_LOGGER.debug("Found vehicle(s) associated with account")
146-
for vehicle_data in loaded_vehicles.get("data"):
147-
self._vehicles.append(Vehicle(self, vehicle_data.get("vin")))
117+
for vehicle in loaded_vehicles.get("data"):
118+
self._vehicles.append(Vehicle(self, vehicle.get("vin")))
148119
else:
149120
_LOGGER.warning("Failed to login to Volkswagen Connect API")
150121
self._session_logged_in = False
151122
return False
152123

153-
# Update all loaded vehicles data before returning
124+
# Update all vehicles data before returning
154125
await self.update()
155126
return True
156127

volkswagencarnet/vw_const.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ class Services:
124124
# callable via `selectivestatus`
125125
ACCESS = "access"
126126
AUTOMATION = "automation"
127-
AUXILIARY_HEATING = "auxiliaryHeating"
128127
BATTERY_CHARGING_CARE = "batteryChargingCare"
129128
BATTERY_SUPPORT = "batterySupport"
130129
CHARGING = "charging"

volkswagencarnet/vw_vehicle.py

Lines changed: 39 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -40,45 +40,6 @@
4040
class Vehicle:
4141
"""Vehicle contains the state of sensors and methods for interacting with the car."""
4242

43-
# Single source of truth for all supported services
44-
SUPPORTED_SERVICES = [
45-
Services.ACCESS,
46-
Services.AUXILIARY_HEATING,
47-
Services.BATTERY_CHARGING_CARE,
48-
Services.BATTERY_SUPPORT,
49-
Services.CHARGING,
50-
Services.CLIMATISATION,
51-
Services.CLIMATISATION_TIMERS,
52-
Services.DEPARTURE_PROFILES,
53-
Services.DEPARTURE_TIMERS,
54-
Services.FUEL_STATUS,
55-
Services.HONK_AND_FLASH,
56-
Services.MEASUREMENTS,
57-
Services.PARKING_POSITION,
58-
Services.READINESS,
59-
Services.TRIP_STATISTICS,
60-
Services.USER_CAPABILITIES,
61-
Services.VEHICLE_LIGHTS,
62-
Services.VEHICLE_HEALTH_INSPECTION,
63-
]
64-
65-
# Services that should not be queried during regular updates
66-
UPDATE_EXCLUDED_SERVICES = [
67-
Services.PARKING_POSITION, # Has dedicated method call
68-
Services.TRIP_STATISTICS, # Has dedicated method calls
69-
Services.HONK_AND_FLASH, # Action service, not data service
70-
]
71-
72-
# Service replacements - when fetching data, replace key with value
73-
SERVICE_FETCH_REPLACEMENTS = {
74-
Services.AUXILIARY_HEATING: Services.CLIMATISATION,
75-
}
76-
77-
# Services that must always be included in updates regardless of active status
78-
MANDATORY_FETCH_SERVICES = [
79-
Services.ACCESS,
80-
]
81-
8243
def __init__(self, conn, url) -> None:
8344
"""Initialize the Vehicle with default values."""
8445
self._connection = conn
@@ -97,12 +58,24 @@ def __init__(self, conn, url) -> None:
9758
}
9859

9960
# API Endpoints that might be enabled for car (that we support)
100-
# Initialize from SUPPORTED_SERVICES constant
10161
self._services: dict[str, dict[str, object]] = {
102-
service: {"active": False} for service in self.SUPPORTED_SERVICES
62+
Services.ACCESS: {"active": False},
63+
Services.BATTERY_CHARGING_CARE: {"active": False},
64+
Services.BATTERY_SUPPORT: {"active": False},
65+
Services.CHARGING: {"active": False},
66+
Services.CLIMATISATION: {"active": False},
67+
Services.CLIMATISATION_TIMERS: {"active": False},
68+
Services.DEPARTURE_PROFILES: {"active": False},
69+
Services.DEPARTURE_TIMERS: {"active": False},
70+
Services.FUEL_STATUS: {"active": False},
71+
Services.HONK_AND_FLASH: {"active": False},
72+
Services.MEASUREMENTS: {"active": False},
73+
Services.PARKING_POSITION: {"active": False},
74+
Services.READINESS: {"active": False},
75+
Services.TRIP_STATISTICS: {"active": False},
76+
Services.USER_CAPABILITIES: {"active": False},
77+
Services.PARAMETERS: {},
10378
}
104-
# Add PARAMETERS as special case
105-
self._services[Services.PARAMETERS] = {}
10679

10780
def _in_progress(self, topic: str, unknown_offset: int = 0) -> bool:
10881
"""Check if request is already in progress."""
@@ -224,47 +197,31 @@ async def update(self) -> None:
224197
if not self._discovered:
225198
await self.discover()
226199
if not self.deactivated:
227-
# Build list of active services to fetch
228-
active_services = [
229-
service_name
230-
for service_name in self.SUPPORTED_SERVICES
231-
if service_name not in self.UPDATE_EXCLUDED_SERVICES
232-
and self._services.get(service_name, {}).get("active", False)
233-
]
234-
235-
# Add mandatory services that must always be fetched
236-
for service in self.MANDATORY_FETCH_SERVICES:
237-
if (
238-
service not in active_services
239-
and service not in self.UPDATE_EXCLUDED_SERVICES
240-
):
241-
active_services.append(service)
242-
243-
# Apply service fetch replacements
244-
for original, replacement in self.SERVICE_FETCH_REPLACEMENTS.items():
245-
if original in active_services:
246-
active_services.remove(original)
247-
if replacement not in active_services:
248-
active_services.append(replacement)
249-
250-
# Only fetch if there are active services
251-
tasks = [self.get_vehicle()]
252-
if active_services:
253-
tasks.insert(0, self.get_selectivestatus(active_services))
254-
255-
# Add conditional service calls
256-
if self._services.get(Services.PARKING_POSITION, {}).get("active", False):
257-
tasks.append(self.get_parkingposition())
258-
if self._services.get(Services.TRIP_STATISTICS, {}).get("active", False):
259-
tasks.extend(
200+
await asyncio.gather(
201+
self.get_selectivestatus(
260202
[
261-
self.get_trip_last(),
262-
self.get_trip_refuel(),
263-
self.get_trip_longterm(),
203+
Services.ACCESS,
204+
Services.BATTERY_CHARGING_CARE,
205+
Services.BATTERY_SUPPORT,
206+
Services.CHARGING,
207+
Services.CLIMATISATION,
208+
Services.CLIMATISATION_TIMERS,
209+
Services.DEPARTURE_PROFILES,
210+
Services.DEPARTURE_TIMERS,
211+
Services.FUEL_STATUS,
212+
Services.MEASUREMENTS,
213+
Services.READINESS,
214+
Services.VEHICLE_LIGHTS,
215+
Services.VEHICLE_HEALTH_INSPECTION,
216+
Services.USER_CAPABILITIES,
264217
]
265-
)
266-
267-
await asyncio.gather(*tasks)
218+
),
219+
self.get_vehicle(),
220+
self.get_parkingposition(),
221+
self.get_trip_last(),
222+
self.get_trip_refuel(),
223+
self.get_trip_longterm(),
224+
)
268225
await asyncio.gather(self.get_service_status())
269226
else:
270227
_LOGGER.info("Vehicle with VIN %s is deactivated", self.vin)

0 commit comments

Comments
 (0)