From 5d78330827ff653a2423c092b46cfc7635071118 Mon Sep 17 00:00:00 2001 From: Richard Kroegel <42204099+rikroe@users.noreply.github.com> Date: Sun, 11 Feb 2024 19:14:03 +0100 Subject: [PATCH] Adjust URLs (#591) * Update to 3.11.1 * Update tests * Fix get_vehicle_image request * Update calculation of fingerprint count in tests --- .pre-commit-config.yaml | 6 +- bimmer_connected/account.py | 28 ++++--- bimmer_connected/api/authentication.py | 5 +- bimmer_connected/api/client.py | 3 +- bimmer_connected/const.py | 19 ++--- bimmer_connected/tests/__init__.py | 36 ++++++--- bimmer_connected/tests/common.py | 23 +++++- bimmer_connected/tests/conftest.py | 2 + .../F31/bmw-eadrax-vcs_v4_vehicles.json | 45 ----------- ...s_v4_vehicles_state_WBA00000000000F31.json | 75 ++++++------------- ...ehicle-data_profile_WBA00000000000F31.json | 35 +++++++++ .../F31/bmw-eadrax-vcs_v5_vehicle-list.json | 13 ++++ .../G01/bmw-eadrax-vcs_v4_vehicles.json | 32 -------- ...ehicle-data_profile_WBA00000000DEMO04.json | 18 +++++ .../G01/bmw-eadrax-vcs_v5_vehicle-list.json | 13 ++++ .../G20/bmw-eadrax-vcs_v4_vehicles.json | 50 ------------- ...ehicle-data_profile_WBA00000000DEMO03.json | 36 +++++++++ .../G20/bmw-eadrax-vcs_v5_vehicle-list.json | 13 ++++ .../G26/bmw-eadrax-vcs_v4_vehicles.json | 50 ------------- ...ehicle-data_profile_WBA00000000DEMO02.json | 36 +++++++++ .../G26/bmw-eadrax-vcs_v5_vehicle-list.json | 13 ++++ .../G70/bmw-eadrax-vcs_v4_vehicles.json | 50 ------------- ...ehicle-data_profile_WBA00000000DEMO05.json | 36 +++++++++ .../G70/bmw-eadrax-vcs_v5_vehicle-list.json | 13 ++++ .../I01_NOREX/bmw-eadrax-vcs_v4_vehicles.json | 45 ----------- ...ehicle-data_profile_WBY000000NOREXI01.json | 36 +++++++++ .../bmw-eadrax-vcs_v5_vehicle-list.json | 13 ++++ .../I01_REX/bmw-eadrax-vcs_v4_vehicles.json | 45 ----------- ...ehicle-data_profile_WBY00000000REXI01.json | 36 +++++++++ .../bmw-eadrax-vcs_v5_vehicle-list.json | 13 ++++ .../I20/bmw-eadrax-vcs_v4_vehicles.json | 50 ------------- ...ehicle-data_profile_WBA00000000DEMO01.json | 36 +++++++++ .../I20/bmw-eadrax-vcs_v5_vehicle-list.json | 13 ++++ .../bmw-eadrax-vcs_v5_vehicle-list.json | 4 + .../mini-eadrax-vcs_v5_vehicle-list.json | 4 + bimmer_connected/tests/test_account.py | 61 +++++++++------ bimmer_connected/tests/test_api.py | 25 +++---- bimmer_connected/tests/test_vehicle.py | 10 +-- bimmer_connected/tests/test_vehicle_status.py | 17 +++-- bimmer_connected/vehicle/vehicle.py | 10 +-- 40 files changed, 552 insertions(+), 516 deletions(-) delete mode 100644 bimmer_connected/tests/responses/F31/bmw-eadrax-vcs_v4_vehicles.json create mode 100644 bimmer_connected/tests/responses/F31/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000000F31.json create mode 100644 bimmer_connected/tests/responses/F31/bmw-eadrax-vcs_v5_vehicle-list.json delete mode 100644 bimmer_connected/tests/responses/G01/bmw-eadrax-vcs_v4_vehicles.json create mode 100644 bimmer_connected/tests/responses/G01/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO04.json create mode 100644 bimmer_connected/tests/responses/G01/bmw-eadrax-vcs_v5_vehicle-list.json delete mode 100644 bimmer_connected/tests/responses/G20/bmw-eadrax-vcs_v4_vehicles.json create mode 100644 bimmer_connected/tests/responses/G20/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO03.json create mode 100644 bimmer_connected/tests/responses/G20/bmw-eadrax-vcs_v5_vehicle-list.json delete mode 100644 bimmer_connected/tests/responses/G26/bmw-eadrax-vcs_v4_vehicles.json create mode 100644 bimmer_connected/tests/responses/G26/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO02.json create mode 100644 bimmer_connected/tests/responses/G26/bmw-eadrax-vcs_v5_vehicle-list.json delete mode 100644 bimmer_connected/tests/responses/G70/bmw-eadrax-vcs_v4_vehicles.json create mode 100644 bimmer_connected/tests/responses/G70/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO05.json create mode 100644 bimmer_connected/tests/responses/G70/bmw-eadrax-vcs_v5_vehicle-list.json delete mode 100644 bimmer_connected/tests/responses/I01_NOREX/bmw-eadrax-vcs_v4_vehicles.json create mode 100644 bimmer_connected/tests/responses/I01_NOREX/bmw-eadrax-vcs_v5_vehicle-data_profile_WBY000000NOREXI01.json create mode 100644 bimmer_connected/tests/responses/I01_NOREX/bmw-eadrax-vcs_v5_vehicle-list.json delete mode 100644 bimmer_connected/tests/responses/I01_REX/bmw-eadrax-vcs_v4_vehicles.json create mode 100644 bimmer_connected/tests/responses/I01_REX/bmw-eadrax-vcs_v5_vehicle-data_profile_WBY00000000REXI01.json create mode 100644 bimmer_connected/tests/responses/I01_REX/bmw-eadrax-vcs_v5_vehicle-list.json delete mode 100644 bimmer_connected/tests/responses/I20/bmw-eadrax-vcs_v4_vehicles.json create mode 100644 bimmer_connected/tests/responses/I20/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO01.json create mode 100644 bimmer_connected/tests/responses/I20/bmw-eadrax-vcs_v5_vehicle-list.json create mode 100644 bimmer_connected/tests/responses/bmw-eadrax-vcs_v5_vehicle-list.json create mode 100644 bimmer_connected/tests/responses/mini-eadrax-vcs_v5_vehicle-list.json diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 18074a01..1646abc8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,12 +1,12 @@ repos: - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.1.5 + rev: v0.1.14 hooks: - id: ruff args: - --fix - repo: https://github.com/psf/black - rev: 23.11.0 + rev: 23.12.1 hooks: - id: black args: @@ -24,7 +24,7 @@ repos: exclude_types: [csv, json] exclude: ^test/responses/ - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.7.0 + rev: v1.8.0 hooks: - id: mypy name: mypy diff --git a/bimmer_connected/account.py b/bimmer_connected/account.py index 0f3d2da6..dc1f466a 100644 --- a/bimmer_connected/account.py +++ b/bimmer_connected/account.py @@ -6,14 +6,14 @@ from dataclasses import InitVar, dataclass, field from typing import List, Optional -import httpx - from bimmer_connected.api.authentication import MyBMWAuthentication from bimmer_connected.api.client import RESPONSE_STORE, MyBMWClient, MyBMWClientConfiguration from bimmer_connected.api.regions import Regions from bimmer_connected.const import ( + ATTR_ATTRIBUTES, ATTR_CAPABILITIES, VEHICLE_CHARGING_DETAILS_URL, + VEHICLE_PROFILE_URL, VEHICLE_STATE_URL, VEHICLES_URL, CarBrands, @@ -76,18 +76,24 @@ async def _init_vehicles(self) -> None: fetched_at = datetime.datetime.now(datetime.timezone.utc) async with MyBMWClient(self.config) as client: - vehicles_responses: List[httpx.Response] = [ - await client.get( + for brand in CarBrands: + request_headers = client.generate_default_header(brand) + vehicle_list_response = await client.post( VEHICLES_URL, - headers={ - **client.generate_default_header(brand), - }, + headers=request_headers, ) - for brand in CarBrands - ] - for response in vehicles_responses: - for vehicle_base in response.json(): + for vehicle in vehicle_list_response.json()["mappingInfos"]: + vehicle_profile_response = await client.get( + VEHICLE_PROFILE_URL, headers=dict(request_headers, **{"bmw-vin": vehicle["vin"]}) + ) + vehicle_profile = vehicle_profile_response.json() + + vehicle_base = dict( + {ATTR_ATTRIBUTES: {k: v for k, v in vehicle_profile.items() if k != "vin"}}, + **{"vin": vehicle_profile["vin"]} + ) + self.add_vehicle(vehicle_base, None, None, fetched_at) async def get_vehicles(self, force_init: bool = False) -> None: diff --git a/bimmer_connected/api/authentication.py b/bimmer_connected/api/authentication.py index ceca4790..66c5469b 100644 --- a/bimmer_connected/api/authentication.py +++ b/bimmer_connected/api/authentication.py @@ -164,16 +164,17 @@ async def _login_row_na(self): code_challenge = create_s256_code_challenge(code_verifier) state = generate_token(22) + nonce = generate_token(22) # Set up authenticate endpoint authenticate_url = oauth_settings["tokenEndpoint"].replace("/token", "/authenticate") oauth_base_values = { "client_id": oauth_settings["clientId"], "response_type": "code", + "scope": " ".join(oauth_settings["scopes"]), "redirect_uri": oauth_settings["returnUrl"], "state": state, - "nonce": "login_nonce", - "scope": " ".join(oauth_settings["scopes"]), + "nonce": nonce, "code_challenge": code_challenge, "code_challenge_method": "S256", } diff --git a/bimmer_connected/api/client.py b/bimmer_connected/api/client.py index 5c1fa24c..007cc49a 100644 --- a/bimmer_connected/api/client.py +++ b/bimmer_connected/api/client.py @@ -81,6 +81,7 @@ def generate_default_header(self, brand: Optional[CarBrands] = None) -> Dict[str return { "accept": "application/json", "accept-language": "en", + "x-raw-locale": "en-US", "user-agent": get_user_agent(self.config.authentication.region), "x-user-agent": X_USER_AGENT.format( brand=(brand or CarBrands.BMW).value, @@ -88,6 +89,6 @@ def generate_default_header(self, brand: Optional[CarBrands] = None) -> Dict[str region=self.config.authentication.region.value, ), **get_correlation_id(), - "bmw-units-preferences": "d=KM;v=L", + "bmw-units-preferences": "d=KM;v=L;p=B;ec=KWH100KM;fc=L100KM;em=GKM;", "24-hour-format": "true", } diff --git a/bimmer_connected/const.py b/bimmer_connected/const.py index ad2a8985..3dde449e 100644 --- a/bimmer_connected/const.py +++ b/bimmer_connected/const.py @@ -37,17 +37,17 @@ class Regions(str, Enum): } APP_VERSIONS = { - Regions.NORTH_AMERICA: "3.9.0(27760)", - Regions.REST_OF_WORLD: "3.9.0(27760)", - Regions.CHINA: "3.6.1(23634)", + Regions.NORTH_AMERICA: "3.11.1(29513)", + Regions.REST_OF_WORLD: "3.11.1(29513)", + Regions.CHINA: "3.11.1(29513)", } HTTPX_TIMEOUT = 30.0 USER_AGENTS = { - Regions.NORTH_AMERICA: "Dart/2.19 (dart:io)", - Regions.REST_OF_WORLD: "Dart/2.19 (dart:io)", - Regions.CHINA: "Dart/2.18 (dart:io)", + Regions.NORTH_AMERICA: "Dart/3.0 (dart:io)", + Regions.REST_OF_WORLD: "Dart/3.0 (dart:io)", + Regions.CHINA: "Dart/3.0 (dart:io)", } X_USER_AGENT = "android(TQ2A.230405.003.B2);{brand};{app_version};{region}" @@ -60,8 +60,9 @@ class Regions(str, Enum): OAUTH_CONFIG_URL = "/eadrax-ucs/v1/presentation/oauth/config" -VEHICLES_URL = "/eadrax-vcs/v4/vehicles" -VEHICLE_STATE_URL = VEHICLES_URL + "/state" +VEHICLES_URL = "/eadrax-vcs/v5/vehicle-list" +VEHICLE_PROFILE_URL = "/eadrax-vcs/v5/vehicle-data/profile" +VEHICLE_STATE_URL = "/eadrax-vcs/v4/vehicles/state" REMOTE_SERVICE_BASE_URL = "/eadrax-vrccs/v3/presentation/remote-commands" REMOTE_SERVICE_URL = REMOTE_SERVICE_BASE_URL + "/{vin}/{service_type}" @@ -74,7 +75,7 @@ class Regions(str, Enum): VEHICLE_CHARGING_PROFILE_SET_URL = VEHICLE_CHARGING_BASE_URL + "/charging-profile" VEHICLE_CHARGING_START_STOP_URL = VEHICLE_CHARGING_BASE_URL + "/{service_type}" -VEHICLE_IMAGE_URL = "/eadrax-ics/v3/presentation/vehicles/{vin}/images?carView={view}" +VEHICLE_IMAGE_URL = "/eadrax-ics/v5/presentation/vehicles/images" VEHICLE_POI_URL = "/eadrax-dcs/v1/send-to-car/send-to-car" VEHICLE_CHARGING_STATISTICS_URL = "/eadrax-chs/v1/charging-statistics" diff --git a/bimmer_connected/tests/__init__.py b/bimmer_connected/tests/__init__.py index 39a7f5e1..d7fe4dd1 100644 --- a/bimmer_connected/tests/__init__.py +++ b/bimmer_connected/tests/__init__.py @@ -2,7 +2,7 @@ import json from pathlib import Path -from typing import Any, Dict, List, Union +from typing import Any, Dict, Union from bimmer_connected.api.regions import Regions from bimmer_connected.const import CarBrands @@ -23,7 +23,8 @@ VIN_I01_REX = "WBY00000000REXI01" VIN_I20 = "WBA00000000DEMO01" -ALL_VEHICLES: Dict[str, List[Dict]] = {brand.value: [] for brand in CarBrands} +ALL_VEHICLES: Dict[str, Dict] = {brand.value: {} for brand in CarBrands} +ALL_PROFILES: Dict[str, Dict] = {} ALL_STATES: Dict[str, Dict] = {} ALL_CHARGING_SETTINGS: Dict[str, Dict] = {} @@ -35,14 +36,18 @@ REMOTE_SERVICE_RESPONSE_EVENTPOSITION = RESPONSE_DIR / "remote_services" / "eadrax_service_eventposition.json" -def get_fingerprint_state_count() -> int: - """Return number of loaded vehicles.""" - return sum([len(vehicles) for vehicles in ALL_VEHICLES.values()]) +def get_fingerprint_count(type: str) -> int: + """Return number of requests/fingerprints for a given type.""" - -def get_fingerprint_charging_settings_count() -> int: - """Return number of loaded vehicles.""" - return len(ALL_CHARGING_SETTINGS) + if type == "vehicles": + return len(CarBrands) + if type == "states": + return len(ALL_STATES) + if type == "profiles": + return len(ALL_PROFILES) + if type == "charging_settings": + return len(ALL_CHARGING_SETTINGS) + return 0 def load_response(path: Union[Path, str]) -> Any: @@ -53,10 +58,17 @@ def load_response(path: Union[Path, str]) -> Any: return file.read().decode("UTF-8") -for fingerprint in RESPONSE_DIR.rglob("*-eadrax-vcs_v4_vehicles.json"): +for fingerprint in RESPONSE_DIR.rglob("*-eadrax-vcs_v5_vehicle-list.json"): brand = fingerprint.stem.split("-")[0] - for vehicle in load_response(fingerprint): - ALL_VEHICLES[brand].append(vehicle) + response = load_response(fingerprint) + + if ALL_VEHICLES[brand].get("mappingInfos"): + ALL_VEHICLES[brand]["mappingInfos"].extend(response["mappingInfos"]) + else: + ALL_VEHICLES[brand] = response + +for profile in RESPONSE_DIR.rglob("*-eadrax-vcs_v5_vehicle-data_profile_*.json"): + ALL_PROFILES[profile.stem.split("_")[-1]] = load_response(profile) for state in RESPONSE_DIR.rglob("*-eadrax-vcs_v4_vehicles_state_*.json"): ALL_STATES[state.stem.split("_")[-1]] = load_response(state) diff --git a/bimmer_connected/tests/common.py b/bimmer_connected/tests/common.py index 31d30abc..89890654 100644 --- a/bimmer_connected/tests/common.py +++ b/bimmer_connected/tests/common.py @@ -61,12 +61,14 @@ class MyBMWMockRouter(respx.MockRouter): def __init__( self, vehicles_to_load: Optional[List[str]] = None, + profiles: Optional[Dict[str, Dict]] = None, states: Optional[Dict[str, Dict]] = None, charging_settings: Optional[Dict[str, Dict]] = None, ) -> None: """Initialize the MyBMWMockRouter with clean responses.""" super().__init__(assert_all_called=False) self.vehicles_to_load = vehicles_to_load or [] + self.profiles = deepcopy(profiles) if profiles else {} self.states = deepcopy(states) if states else {} self.charging_settings = deepcopy(charging_settings) if charging_settings else {} @@ -110,7 +112,8 @@ def add_login_routes(self) -> None: def add_vehicle_routes(self) -> None: """Add routes for vehicle requests.""" - self.get("/eadrax-vcs/v4/vehicles").mock(side_effect=self.vehicles_sideeffect) + self.post("/eadrax-vcs/v5/vehicle-list").mock(side_effect=self.vehicles_sideeffect) + self.get("/eadrax-vcs/v5/vehicle-data/profile").mock(side_effect=self.vehicle_profile_sideeffect) self.get("/eadrax-vcs/v4/vehicles/state", name="state").mock(side_effect=self.vehicle_state_sideeffect) self.get("/eadrax-crccs/v2/vehicles").mock(side_effect=self.vehicle_charging_settings_sideeffect) @@ -171,15 +174,27 @@ def vehicles_sideeffect(self, request: httpx.Request) -> httpx.Response: # Test if given region is valid _ = Regions(x_user_agent[3]) - fingerprints = ALL_VEHICLES.get(brand, []) + fingerprints = deepcopy(ALL_VEHICLES.get(brand, {"mappingInfos": []})) if self.vehicles_to_load: - fingerprints = [f for f in fingerprints if f["vin"] in self.vehicles_to_load] + fingerprints["mappingInfos"] = [ + f for f in fingerprints["mappingInfos"] if f["vin"] in self.vehicles_to_load + ] # Ensure order - fingerprints = sorted(fingerprints, key=lambda v: v["vin"]) + fingerprints["mappingInfos"] = sorted(fingerprints["mappingInfos"], key=lambda v: v["vin"]) return httpx.Response(200, json=fingerprints) + def vehicle_profile_sideeffect(self, request: httpx.Request) -> httpx.Response: + """Return /vehicle-data/profile response based on vin.""" + x_user_agent = request.headers.get("x-user-agent", "").split(";") + assert len(x_user_agent) == 4 + + try: + return httpx.Response(200, json=self.profiles[request.headers["bmw-vin"]]) + except KeyError: + return httpx.Response(404) + def vehicle_state_sideeffect(self, request: httpx.Request) -> httpx.Response: """Return /vehicles response based on x-user-agent.""" x_user_agent = request.headers.get("x-user-agent", "").split(";") diff --git a/bimmer_connected/tests/conftest.py b/bimmer_connected/tests/conftest.py index 035ad900..ca9532b5 100644 --- a/bimmer_connected/tests/conftest.py +++ b/bimmer_connected/tests/conftest.py @@ -11,6 +11,7 @@ from . import ( ALL_CHARGING_SETTINGS, + ALL_PROFILES, ALL_STATES, TEST_PASSWORD, TEST_REGION, @@ -25,6 +26,7 @@ def bmw_fixture(request: pytest.FixtureRequest) -> Generator[respx.MockRouter, N # Now we can start patching the API calls router = MyBMWMockRouter( vehicles_to_load=getattr(request, "param", []), + profiles=ALL_PROFILES, states=ALL_STATES, charging_settings=ALL_CHARGING_SETTINGS, ) diff --git a/bimmer_connected/tests/responses/F31/bmw-eadrax-vcs_v4_vehicles.json b/bimmer_connected/tests/responses/F31/bmw-eadrax-vcs_v4_vehicles.json deleted file mode 100644 index d7bd3098..00000000 --- a/bimmer_connected/tests/responses/F31/bmw-eadrax-vcs_v4_vehicles.json +++ /dev/null @@ -1,45 +0,0 @@ -[ - { - "appVehicleType": "CONNECTED", - "attributes": { - "a4aType": "USB_ONLY", - "bodyType": "F31", - "brand": "BMW", - "color": 4281545523, - "countryOfOrigin": "DE", - "driveTrain": "COMBUSTION", - "driverGuideInfo": { - "androidAppScheme": "com.bmwgroup.driversguide.row", - "androidStoreUrl": "https://play.google.com/store/apps/details?id=com.bmwgroup.driversguide.row", - "iosAppScheme": "bmwdriversguide:///open", - "iosStoreUrl": "https://apps.apple.com/de/app/id714042749?mt=8" - }, - "headUnitType": "NBT", - "hmiVersion": "ID4", - "lastFetched": "2022-06-01T19:18:52.940Z", - "model": "320d xDrive", - "softwareVersionCurrent": { - "iStep": 502, - "puStep": { - "month": 11, - "year": 13 - }, - "seriesCluster": "F020" - }, - "softwareVersionExFactory": { - "iStep": 502, - "puStep": { - "month": 11, - "year": 13 - }, - "seriesCluster": "F020" - }, - "year": 2013 - }, - "mappingInfo": { - "isPrimaryUser": true, - "mappingStatus": "CONFIRMED" - }, - "vin": "WBA00000000000F31" - } -] \ No newline at end of file diff --git a/bimmer_connected/tests/responses/F31/bmw-eadrax-vcs_v4_vehicles_state_WBA00000000000F31.json b/bimmer_connected/tests/responses/F31/bmw-eadrax-vcs_v4_vehicles_state_WBA00000000000F31.json index 2361fbae..15668a3d 100644 --- a/bimmer_connected/tests/responses/F31/bmw-eadrax-vcs_v4_vehicles_state_WBA00000000000F31.json +++ b/bimmer_connected/tests/responses/F31/bmw-eadrax-vcs_v4_vehicles_state_WBA00000000000F31.json @@ -1,13 +1,15 @@ { "capabilities": { "a4aType": "USB_ONLY", - "checkSustainabilityDPP": false, + "alarmSystem": false, "climateFunction": "VENTILATION", "climateNow": true, "climateTimerTrigger": "START_TIMER", "digitalKey": { "bookedServicePackage": "NONE", - "state": "NOT_AVAILABLE" + "isDigitalKeyFirstSupported": false, + "state": "NOT_AVAILABLE", + "vehicleSoftwareUpgradeRequired": false }, "horn": true, "isBmwChargingSupported": false, @@ -27,9 +29,12 @@ "isDataPrivacyEnabled": false, "isEasyChargeEnabled": false, "isEvGoChargingSupported": false, + "isLocationBasedChargingSettingsSupported": false, "isMiniChargingSupported": false, "isNonLscFeatureEnabled": true, + "isOptimizedChargingSupported": false, "isPersonalPictureUploadSupported": false, + "isPlugAndChargeSupported": false, "isRemoteEngineStartSupported": false, "isRemoteHistoryDeletionSupported": false, "isRemoteHistorySupported": true, @@ -46,7 +51,7 @@ "sendPoi": true, "specialThemeSupport": [], "unlock": true, - "vehicleFinder": true, + "vehicleFinder": false, "vehicleStateSource": "A4A" }, "state": { @@ -59,76 +64,44 @@ "climateTimers": [ { "departureTime": { - "hour": 6, - "minute": 40 + "hour": 7, + "minute": 0 }, - "isWeeklyTimer": true, - "timerAction": "ACTIVATE", - "timerWeekDays": [ - "THURSDAY", - "SUNDAY" - ] + "isWeeklyTimer": false, + "timerAction": "DEACTIVATE", + "timerWeekDays": [] }, { "departureTime": { - "hour": 12, - "minute": 50 + "hour": 7, + "minute": 0 }, - "isWeeklyTimer": false, - "timerAction": "ACTIVATE", + "isWeeklyTimer": true, + "timerAction": "DEACTIVATE", "timerWeekDays": [ "MONDAY" ] }, { "departureTime": { - "hour": 18, - "minute": 59 + "hour": 7, + "minute": 0 }, "isWeeklyTimer": true, "timerAction": "DEACTIVATE", "timerWeekDays": [ - "WEDNESDAY" + "MONDAY" ] } ], - "combustionFuelLevel": { - "remainingFuelLiters": 14 - }, "driverPreferences": { "lscPrivacyMode": "OFF" }, "isLeftSteering": true, "isLscSupported": false, - "lastFetched": "2022-06-01T19:18:54.528Z", - "lastUpdatedAt": "2021-11-01T16:02:44Z", - "requiredServices": [ - { - "dateTime": "2021-11-01T00:00:00.000Z", - "description": "Wechsel demnächst fällig. Bitte Termin mit Ihrem Servicepartner vereinbaren.", - "status": "PENDING", - "type": "BRAKE_FLUID" - }, - { - "dateTime": "2022-07-01T00:00:00.000Z", - "description": "Nächster Service nach der angegebenen Fahrstrecke oder zum angegebenen Termin.", - "mileage": 9000, - "status": "OK", - "type": "OIL" - }, - { - "dateTime": "2022-07-01T00:00:00.000Z", - "description": "Nächste Sichtprüfung nach der angegebenen Fahrstrecke oder zum angegebenen Termin.", - "mileage": 9000, - "status": "OK", - "type": "VEHICLE_CHECK" - }, - { - "dateTime": "2023-02-01T00:00:00.000Z", - "description": "Nächste gesetzliche Fahrzeuguntersuchung zum angegebenen Termin.", - "status": "OK", - "type": "VEHICLE_TUV" - } - ] + "lastFetched": "2024-01-20T10:18:57.283Z", + "lastUpdatedAt": "0001-01-01T00:00:00Z", + "requiredServices": [], + "securityOverviewMode": null } } \ No newline at end of file diff --git a/bimmer_connected/tests/responses/F31/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000000F31.json b/bimmer_connected/tests/responses/F31/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000000F31.json new file mode 100644 index 00000000..1679d71b --- /dev/null +++ b/bimmer_connected/tests/responses/F31/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000000F31.json @@ -0,0 +1,35 @@ +{ + "bodyType": "F31", + "brand": "BMW", + "color": 4281545523, + "countryOfOrigin": "DE", + "driveTrain": "COMBUSTION", + "driverGuideInfo": { + "androidAppScheme": "com.bmwgroup.driversguide.row", + "androidStoreUrl": "https://play.google.com/store/apps/details?id=com.bmwgroup.driversguide.row", + "iosAppScheme": "bmwdriversguide:///open", + "iosStoreUrl": "https://apps.apple.com/de/app/id714042749?mt=8" + }, + "headUnitRaw": "NBT", + "headUnitType": "NBT", + "hmiVersion": "ID4", + "model": "320d xDrive", + "softwareVersionCurrent": { + "iStep": 502, + "puStep": { + "month": 11, + "year": 13 + }, + "seriesCluster": "F020" + }, + "softwareVersionExFactory": { + "iStep": 502, + "puStep": { + "month": 11, + "year": 13 + }, + "seriesCluster": "F020" + }, + "vin": "WBA00000000000F31", + "year": 2013 +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/F31/bmw-eadrax-vcs_v5_vehicle-list.json b/bimmer_connected/tests/responses/F31/bmw-eadrax-vcs_v5_vehicle-list.json new file mode 100644 index 00000000..6fe787cb --- /dev/null +++ b/bimmer_connected/tests/responses/F31/bmw-eadrax-vcs_v5_vehicle-list.json @@ -0,0 +1,13 @@ +{ + "gcid": "ceb64158-d2ca-47e9-9ee6-cbffb881434e", + "mappingInfos": [ + { + "isAssociated": false, + "isLmmEnabled": false, + "isPrimaryUser": true, + "mappingStatus": "CONFIRMED", + "vehicleMappingType": "CONNECTED", + "vin": "WBA00000000000F31" + } + ] +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/G01/bmw-eadrax-vcs_v4_vehicles.json b/bimmer_connected/tests/responses/G01/bmw-eadrax-vcs_v4_vehicles.json deleted file mode 100644 index 787623ba..00000000 --- a/bimmer_connected/tests/responses/G01/bmw-eadrax-vcs_v4_vehicles.json +++ /dev/null @@ -1,32 +0,0 @@ -[ - { - "appVehicleType": "DEMO", - "attributes": { - "a4aType": "BLUETOOTH", - "bodyType": "G01", - "brand": "BMW", - "color": 4284900966, - "countryOfOrigin": "DE", - "driveTrain": "PLUGIN_HYBRID", - "driverGuideInfo": { - "androidAppScheme": "com.bmwgroup.driversguide.row", - "androidStoreUrl": "https://play.google.com/store/apps/details?id=com.bmwgroup.driversguide.row", - "iosAppScheme": "bmwdriversguide:///open", - "iosStoreUrl": "https://apps.apple.com/de/app/id714042749?mt=8" - }, - "headUnitRaw": "MGU", - "hmiVersion": "ID7", - "lastFetched": "2023-01-04T14:57:06.019Z", - "model": "X3 xDrive30e", - "year": 2021 - }, - "mappingInfo": { - "isAssociated": false, - "isLmmEnabled": false, - "isPrimaryUser": true, - "lmmStatusReasons": [], - "mappingStatus": "CONFIRMED" - }, - "vin": "WBA00000000DEMO04" - } -] \ No newline at end of file diff --git a/bimmer_connected/tests/responses/G01/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO04.json b/bimmer_connected/tests/responses/G01/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO04.json new file mode 100644 index 00000000..dd76b4d9 --- /dev/null +++ b/bimmer_connected/tests/responses/G01/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO04.json @@ -0,0 +1,18 @@ +{ + "bodyType": "G01", + "brand": "BMW", + "color": 4284900966, + "countryOfOrigin": "DE", + "driveTrain": "PLUGIN_HYBRID", + "driverGuideInfo": { + "androidAppScheme": "com.bmwgroup.driversguide.row", + "androidStoreUrl": "https://play.google.com/store/apps/details?id=com.bmwgroup.driversguide.row", + "iosAppScheme": "bmwdriversguide:///open", + "iosStoreUrl": "https://apps.apple.com/de/app/id714042749?mt=8" + }, + "headUnitRaw": "MGU", + "hmiVersion": "ID7", + "model": "X3 xDrive30e", + "vin": "WBA00000000DEMO04", + "year": 2021 +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/G01/bmw-eadrax-vcs_v5_vehicle-list.json b/bimmer_connected/tests/responses/G01/bmw-eadrax-vcs_v5_vehicle-list.json new file mode 100644 index 00000000..f2f0b32e --- /dev/null +++ b/bimmer_connected/tests/responses/G01/bmw-eadrax-vcs_v5_vehicle-list.json @@ -0,0 +1,13 @@ +{ + "gcid": "ceb64158-d2ca-47e9-9ee6-cbffb881434e", + "mappingInfos": [ + { + "isAssociated": false, + "isLmmEnabled": false, + "isPrimaryUser": true, + "mappingStatus": "CONFIRMED", + "vehicleMappingType": "CONNECTED", + "vin": "WBA00000000DEMO04" + } + ] +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/G20/bmw-eadrax-vcs_v4_vehicles.json b/bimmer_connected/tests/responses/G20/bmw-eadrax-vcs_v4_vehicles.json deleted file mode 100644 index 466c5da8..00000000 --- a/bimmer_connected/tests/responses/G20/bmw-eadrax-vcs_v4_vehicles.json +++ /dev/null @@ -1,50 +0,0 @@ -[ - { - "appVehicleType": "DEMO", - "attributes": { - "a4aType": "NOT_SUPPORTED", - "bodyType": "G20", - "brand": "BMW", - "color": 4280233344, - "countryOfOrigin": "PT", - "driveTrain": "COMBUSTION", - "driverGuideInfo": { - "androidAppScheme": "com.bmwgroup.driversguide.row", - "androidStoreUrl": "https://play.google.com/store/apps/details?id=com.bmwgroup.driversguide.row", - "iosAppScheme": "bmwdriversguide:///open", - "iosStoreUrl": "https://apps.apple.com/de/app/id714042749?mt=8" - }, - "headUnitRaw": "HU_MGU", - "headUnitType": "MGU", - "hmiVersion": "ID7", - "lastFetched": "2023-01-04T14:57:06.019Z", - "model": "M340i xDrive", - "softwareVersionCurrent": { - "iStep": 470, - "puStep": { - "month": 7, - "year": 21 - }, - "seriesCluster": "S18A" - }, - "softwareVersionExFactory": { - "iStep": 420, - "puStep": { - "month": 7, - "year": 20 - }, - "seriesCluster": "S18A" - }, - "telematicsUnit": "ATM2", - "year": 2022 - }, - "mappingInfo": { - "isAssociated": false, - "isLmmEnabled": false, - "isPrimaryUser": true, - "lmmStatusReasons": [], - "mappingStatus": "CONFIRMED" - }, - "vin": "WBA00000000DEMO03" - } -] \ No newline at end of file diff --git a/bimmer_connected/tests/responses/G20/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO03.json b/bimmer_connected/tests/responses/G20/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO03.json new file mode 100644 index 00000000..03d5e672 --- /dev/null +++ b/bimmer_connected/tests/responses/G20/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO03.json @@ -0,0 +1,36 @@ +{ + "bodyType": "G20", + "brand": "BMW", + "color": 4280233344, + "countryOfOrigin": "PT", + "driveTrain": "COMBUSTION", + "driverGuideInfo": { + "androidAppScheme": "com.bmwgroup.driversguide.row", + "androidStoreUrl": "https://play.google.com/store/apps/details?id=com.bmwgroup.driversguide.row", + "iosAppScheme": "bmwdriversguide:///open", + "iosStoreUrl": "https://apps.apple.com/de/app/id714042749?mt=8" + }, + "headUnitRaw": "HU_MGU", + "headUnitType": "MGU", + "hmiVersion": "ID7", + "model": "M340i xDrive", + "softwareVersionCurrent": { + "iStep": 470, + "puStep": { + "month": 7, + "year": 21 + }, + "seriesCluster": "S18A" + }, + "softwareVersionExFactory": { + "iStep": 420, + "puStep": { + "month": 7, + "year": 20 + }, + "seriesCluster": "S18A" + }, + "telematicsUnit": "ATM2", + "vin": "WBA00000000DEMO03", + "year": 2022 +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/G20/bmw-eadrax-vcs_v5_vehicle-list.json b/bimmer_connected/tests/responses/G20/bmw-eadrax-vcs_v5_vehicle-list.json new file mode 100644 index 00000000..63aaa0d4 --- /dev/null +++ b/bimmer_connected/tests/responses/G20/bmw-eadrax-vcs_v5_vehicle-list.json @@ -0,0 +1,13 @@ +{ + "gcid": "ceb64158-d2ca-47e9-9ee6-cbffb881434e", + "mappingInfos": [ + { + "isAssociated": false, + "isLmmEnabled": false, + "isPrimaryUser": true, + "mappingStatus": "CONFIRMED", + "vehicleMappingType": "CONNECTED", + "vin": "WBA00000000DEMO03" + } + ] +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/G26/bmw-eadrax-vcs_v4_vehicles.json b/bimmer_connected/tests/responses/G26/bmw-eadrax-vcs_v4_vehicles.json deleted file mode 100644 index e9dac061..00000000 --- a/bimmer_connected/tests/responses/G26/bmw-eadrax-vcs_v4_vehicles.json +++ /dev/null @@ -1,50 +0,0 @@ -[ - { - "appVehicleType": "DEMO", - "attributes": { - "a4aType": "NOT_SUPPORTED", - "bodyType": "G26", - "brand": "BMW", - "color": 4284245350, - "countryOfOrigin": "DE", - "driveTrain": "ELECTRIC", - "driverGuideInfo": { - "androidAppScheme": "com.bmwgroup.driversguide.row", - "androidStoreUrl": "https://play.google.com/store/apps/details?id=com.bmwgroup.driversguide.row", - "iosAppScheme": "bmwdriversguide:///open", - "iosStoreUrl": "https://apps.apple.com/de/app/id714042749?mt=8" - }, - "headUnitRaw": "HU_MGU", - "headUnitType": "MGU", - "hmiVersion": "ID8", - "lastFetched": "2023-01-04T14:57:06.019Z", - "model": "i4 eDrive40", - "softwareVersionCurrent": { - "iStep": 470, - "puStep": { - "month": 11, - "year": 21 - }, - "seriesCluster": "G026" - }, - "softwareVersionExFactory": { - "iStep": 470, - "puStep": { - "month": 11, - "year": 21 - }, - "seriesCluster": "G026" - }, - "telematicsUnit": "WAVE01", - "year": 2021 - }, - "mappingInfo": { - "isAssociated": false, - "isLmmEnabled": false, - "isPrimaryUser": true, - "lmmStatusReasons": [], - "mappingStatus": "CONFIRMED" - }, - "vin": "WBA00000000DEMO02" - } -] \ No newline at end of file diff --git a/bimmer_connected/tests/responses/G26/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO02.json b/bimmer_connected/tests/responses/G26/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO02.json new file mode 100644 index 00000000..ee4f13d3 --- /dev/null +++ b/bimmer_connected/tests/responses/G26/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO02.json @@ -0,0 +1,36 @@ +{ + "bodyType": "G26", + "brand": "BMW", + "color": 4284245350, + "countryOfOrigin": "DE", + "driveTrain": "ELECTRIC", + "driverGuideInfo": { + "androidAppScheme": "com.bmwgroup.driversguide.row", + "androidStoreUrl": "https://play.google.com/store/apps/details?id=com.bmwgroup.driversguide.row", + "iosAppScheme": "bmwdriversguide:///open", + "iosStoreUrl": "https://apps.apple.com/de/app/id714042749?mt=8" + }, + "headUnitRaw": "HU_MGU", + "headUnitType": "MGU", + "hmiVersion": "ID8", + "model": "i4 eDrive40", + "softwareVersionCurrent": { + "iStep": 470, + "puStep": { + "month": 11, + "year": 21 + }, + "seriesCluster": "G026" + }, + "softwareVersionExFactory": { + "iStep": 470, + "puStep": { + "month": 11, + "year": 21 + }, + "seriesCluster": "G026" + }, + "telematicsUnit": "WAVE01", + "vin": "WBA00000000DEMO02", + "year": 2021 +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/G26/bmw-eadrax-vcs_v5_vehicle-list.json b/bimmer_connected/tests/responses/G26/bmw-eadrax-vcs_v5_vehicle-list.json new file mode 100644 index 00000000..762444b8 --- /dev/null +++ b/bimmer_connected/tests/responses/G26/bmw-eadrax-vcs_v5_vehicle-list.json @@ -0,0 +1,13 @@ +{ + "gcid": "ceb64158-d2ca-47e9-9ee6-cbffb881434e", + "mappingInfos": [ + { + "isAssociated": false, + "isLmmEnabled": false, + "isPrimaryUser": true, + "mappingStatus": "CONFIRMED", + "vehicleMappingType": "CONNECTED", + "vin": "WBA00000000DEMO02" + } + ] +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/G70/bmw-eadrax-vcs_v4_vehicles.json b/bimmer_connected/tests/responses/G70/bmw-eadrax-vcs_v4_vehicles.json deleted file mode 100644 index afb1e1f9..00000000 --- a/bimmer_connected/tests/responses/G70/bmw-eadrax-vcs_v4_vehicles.json +++ /dev/null @@ -1,50 +0,0 @@ -[ - { - "appVehicleType": "DEMO", - "attributes": { - "a4aType": "BLUETOOTH", - "bodyType": "G70", - "brand": "BMW", - "color": 4284900182, - "countryOfOrigin": "DE", - "driveTrain": "ELECTRIC", - "driverGuideInfo": { - "androidAppScheme": "com.bmwgroup.driversguide.row", - "androidStoreUrl": "https://play.google.com/store/apps/details?id=com.bmwgroup.driversguide.row", - "iosAppScheme": "bmwdriversguide:///open", - "iosStoreUrl": "https://apps.apple.com/de/app/id714042749?mt=8" - }, - "headUnitRaw": "MGU_02_L", - "headUnitType": "MGU", - "hmiVersion": "ID8", - "lastFetched": "2023-01-04T15:03:07.150Z", - "model": "i7 xDrive60", - "softwareVersionCurrent": { - "iStep": 505, - "puStep": { - "month": 7, - "year": 22 - }, - "seriesCluster": "G070" - }, - "softwareVersionExFactory": { - "iStep": 450, - "puStep": { - "month": 7, - "year": 22 - }, - "seriesCluster": "G070" - }, - "telematicsUnit": "WAVE01", - "year": 2022 - }, - "mappingInfo": { - "isAssociated": false, - "isLmmEnabled": false, - "isPrimaryUser": true, - "lmmStatusReasons": [], - "mappingStatus": "CONFIRMED" - }, - "vin": "WBA00000000DEMO05" - } -] \ No newline at end of file diff --git a/bimmer_connected/tests/responses/G70/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO05.json b/bimmer_connected/tests/responses/G70/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO05.json new file mode 100644 index 00000000..b6273e69 --- /dev/null +++ b/bimmer_connected/tests/responses/G70/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO05.json @@ -0,0 +1,36 @@ +{ + "bodyType": "G70", + "brand": "BMW", + "color": 4284900182, + "countryOfOrigin": "DE", + "driveTrain": "ELECTRIC", + "driverGuideInfo": { + "androidAppScheme": "com.bmwgroup.driversguide.row", + "androidStoreUrl": "https://play.google.com/store/apps/details?id=com.bmwgroup.driversguide.row", + "iosAppScheme": "bmwdriversguide:///open", + "iosStoreUrl": "https://apps.apple.com/de/app/id714042749?mt=8" + }, + "headUnitRaw": "MGU_02_L", + "headUnitType": "MGU", + "hmiVersion": "ID8", + "model": "i7 xDrive60", + "softwareVersionCurrent": { + "iStep": 505, + "puStep": { + "month": 7, + "year": 22 + }, + "seriesCluster": "G070" + }, + "softwareVersionExFactory": { + "iStep": 450, + "puStep": { + "month": 7, + "year": 22 + }, + "seriesCluster": "G070" + }, + "telematicsUnit": "WAVE01", + "vin": "WBA00000000DEMO05", + "year": 2022 +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/G70/bmw-eadrax-vcs_v5_vehicle-list.json b/bimmer_connected/tests/responses/G70/bmw-eadrax-vcs_v5_vehicle-list.json new file mode 100644 index 00000000..12aa8d49 --- /dev/null +++ b/bimmer_connected/tests/responses/G70/bmw-eadrax-vcs_v5_vehicle-list.json @@ -0,0 +1,13 @@ +{ + "gcid": "ceb64158-d2ca-47e9-9ee6-cbffb881434e", + "mappingInfos": [ + { + "isAssociated": false, + "isLmmEnabled": false, + "isPrimaryUser": true, + "mappingStatus": "CONFIRMED", + "vehicleMappingType": "CONNECTED", + "vin": "WBA00000000DEMO05" + } + ] +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/I01_NOREX/bmw-eadrax-vcs_v4_vehicles.json b/bimmer_connected/tests/responses/I01_NOREX/bmw-eadrax-vcs_v4_vehicles.json deleted file mode 100644 index a95c0b97..00000000 --- a/bimmer_connected/tests/responses/I01_NOREX/bmw-eadrax-vcs_v4_vehicles.json +++ /dev/null @@ -1,45 +0,0 @@ -[ - { - "vin": "WBY000000NOREXI01", - "mappingInfo": { - "mappingStatus": "CONFIRMED", - "isPrimaryUser": true - }, - "appVehicleType": "CONNECTED", - "attributes": { - "lastFetched": "2022-06-01T19:48:46.540Z", - "model": "i3", - "year": 2015, - "color": 4282858822, - "brand": "BMW_I", - "driveTrain": "ELECTRIC", - "headUnitType": "ENTRY", - "hmiVersion": "ID4", - "softwareVersionCurrent": { - "puStep": { - "month": 3, - "year": 21 - }, - "iStep": 530, - "seriesCluster": "I001" - }, - "softwareVersionExFactory": { - "puStep": { - "month": 7, - "year": 15 - }, - "iStep": 502, - "seriesCluster": "I001" - }, - "bodyType": "I01", - "countryOfOrigin": "CZ", - "a4aType": "USB_ONLY", - "driverGuideInfo": { - "androidAppScheme": "com.bmwgroup.driversguide.row", - "iosAppScheme": "bmwdriversguide:///open", - "androidStoreUrl": "https://play.google.com/store/apps/details?id=com.bmwgroup.driversguide.row", - "iosStoreUrl": "https://apps.apple.com/de/app/id714042749?mt=8" - } - } - } -] \ No newline at end of file diff --git a/bimmer_connected/tests/responses/I01_NOREX/bmw-eadrax-vcs_v5_vehicle-data_profile_WBY000000NOREXI01.json b/bimmer_connected/tests/responses/I01_NOREX/bmw-eadrax-vcs_v5_vehicle-data_profile_WBY000000NOREXI01.json new file mode 100644 index 00000000..2b05a94b --- /dev/null +++ b/bimmer_connected/tests/responses/I01_NOREX/bmw-eadrax-vcs_v5_vehicle-data_profile_WBY000000NOREXI01.json @@ -0,0 +1,36 @@ +{ + "bodyType": "I01", + "brand": "BMW_I", + "color": 4282858822, + "countryOfOrigin": "CZ", + "driveTrain": "ELECTRIC", + "driverGuideInfo": { + "androidAppScheme": "com.bmwgroup.driversguide.row", + "iosAppScheme": "bmwdriversguide:///open", + "androidStoreUrl": "https://play.google.com/store/apps/details?id=com.bmwgroup.driversguide.row", + "iosStoreUrl": "https://apps.apple.com/de/app/id714042749?mt=8" + }, + "headUnitRaw": "MGU_02_L", + "headUnitType": "ENTRY", + "hmiVersion": "ID4", + "model": "i3", + "softwareVersionCurrent": { + "puStep": { + "month": 3, + "year": 21 + }, + "iStep": 530, + "seriesCluster": "I001" + }, + "softwareVersionExFactory": { + "puStep": { + "month": 7, + "year": 15 + }, + "iStep": 502, + "seriesCluster": "I001" + }, + "telematicsUnit": "WAVE01", + "vin": "WBY000000NOREXI01", + "year": 2015 +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/I01_NOREX/bmw-eadrax-vcs_v5_vehicle-list.json b/bimmer_connected/tests/responses/I01_NOREX/bmw-eadrax-vcs_v5_vehicle-list.json new file mode 100644 index 00000000..4f38487f --- /dev/null +++ b/bimmer_connected/tests/responses/I01_NOREX/bmw-eadrax-vcs_v5_vehicle-list.json @@ -0,0 +1,13 @@ +{ + "gcid": "ceb64158-d2ca-47e9-9ee6-cbffb881434e", + "mappingInfos": [ + { + "isAssociated": false, + "isLmmEnabled": false, + "isPrimaryUser": true, + "mappingStatus": "CONFIRMED", + "vehicleMappingType": "CONNECTED", + "vin": "WBY000000NOREXI01" + } + ] +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/I01_REX/bmw-eadrax-vcs_v4_vehicles.json b/bimmer_connected/tests/responses/I01_REX/bmw-eadrax-vcs_v4_vehicles.json deleted file mode 100644 index f0060ec5..00000000 --- a/bimmer_connected/tests/responses/I01_REX/bmw-eadrax-vcs_v4_vehicles.json +++ /dev/null @@ -1,45 +0,0 @@ -[ - { - "vin": "WBY00000000REXI01", - "mappingInfo": { - "mappingStatus": "CONFIRMED", - "isPrimaryUser": true - }, - "appVehicleType": "CONNECTED", - "attributes": { - "lastFetched": "2022-06-01T19:48:46.540Z", - "model": "i3 (+ REX)", - "year": 2015, - "color": 4284110934, - "brand": "BMW_I", - "driveTrain": "ELECTRIC_WITH_RANGE_EXTENDER", - "headUnitType": "NBT", - "hmiVersion": "ID4", - "softwareVersionCurrent": { - "puStep": { - "month": 11, - "year": 21 - }, - "iStep": 510, - "seriesCluster": "I001" - }, - "softwareVersionExFactory": { - "puStep": { - "month": 3, - "year": 15 - }, - "iStep": 502, - "seriesCluster": "I001" - }, - "bodyType": "I01", - "countryOfOrigin": "CZ", - "a4aType": "USB_ONLY", - "driverGuideInfo": { - "androidAppScheme": "com.bmwgroup.driversguide.row", - "iosAppScheme": "bmwdriversguide:///open", - "androidStoreUrl": "https://play.google.com/store/apps/details?id=com.bmwgroup.driversguide.row", - "iosStoreUrl": "https://apps.apple.com/de/app/id714042749?mt=8" - } - } - } -] \ No newline at end of file diff --git a/bimmer_connected/tests/responses/I01_REX/bmw-eadrax-vcs_v5_vehicle-data_profile_WBY00000000REXI01.json b/bimmer_connected/tests/responses/I01_REX/bmw-eadrax-vcs_v5_vehicle-data_profile_WBY00000000REXI01.json new file mode 100644 index 00000000..db6f9e68 --- /dev/null +++ b/bimmer_connected/tests/responses/I01_REX/bmw-eadrax-vcs_v5_vehicle-data_profile_WBY00000000REXI01.json @@ -0,0 +1,36 @@ +{ + "bodyType": "I01", + "brand": "BMW_I", + "color": 4284110934, + "countryOfOrigin": "CZ", + "driveTrain": "ELECTRIC_WITH_RANGE_EXTENDER", + "driverGuideInfo": { + "androidAppScheme": "com.bmwgroup.driversguide.row", + "iosAppScheme": "bmwdriversguide:///open", + "androidStoreUrl": "https://play.google.com/store/apps/details?id=com.bmwgroup.driversguide.row", + "iosStoreUrl": "https://apps.apple.com/de/app/id714042749?mt=8" + }, + "headUnitRaw": "MGU_02_L", + "headUnitType": "NBT", + "hmiVersion": "ID4", + "model": "i3 (+ REX)", + "softwareVersionCurrent": { + "puStep": { + "month": 11, + "year": 21 + }, + "iStep": 510, + "seriesCluster": "I001" + }, + "softwareVersionExFactory": { + "puStep": { + "month": 3, + "year": 15 + }, + "iStep": 502, + "seriesCluster": "I001" + }, + "telematicsUnit": "WAVE01", + "vin": "WBY00000000REXI01", + "year": 2015 +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/I01_REX/bmw-eadrax-vcs_v5_vehicle-list.json b/bimmer_connected/tests/responses/I01_REX/bmw-eadrax-vcs_v5_vehicle-list.json new file mode 100644 index 00000000..7182952a --- /dev/null +++ b/bimmer_connected/tests/responses/I01_REX/bmw-eadrax-vcs_v5_vehicle-list.json @@ -0,0 +1,13 @@ +{ + "gcid": "ceb64158-d2ca-47e9-9ee6-cbffb881434e", + "mappingInfos": [ + { + "isAssociated": false, + "isLmmEnabled": false, + "isPrimaryUser": true, + "mappingStatus": "CONFIRMED", + "vehicleMappingType": "CONNECTED", + "vin": "WBY00000000REXI01" + } + ] +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/I20/bmw-eadrax-vcs_v4_vehicles.json b/bimmer_connected/tests/responses/I20/bmw-eadrax-vcs_v4_vehicles.json deleted file mode 100644 index 480582d0..00000000 --- a/bimmer_connected/tests/responses/I20/bmw-eadrax-vcs_v4_vehicles.json +++ /dev/null @@ -1,50 +0,0 @@ -[ - { - "appVehicleType": "DEMO", - "attributes": { - "a4aType": "BLUETOOTH", - "bodyType": "I20", - "brand": "BMW_I", - "color": 4285537312, - "countryOfOrigin": "DE", - "driveTrain": "ELECTRIC", - "driverGuideInfo": { - "androidAppScheme": "com.bmwgroup.driversguide.row", - "androidStoreUrl": "https://play.google.com/store/apps/details?id=com.bmwgroup.driversguide.row", - "iosAppScheme": "bmwdriversguide:///open", - "iosStoreUrl": "https://apps.apple.com/de/app/id714042749?mt=8" - }, - "headUnitRaw": "HU_MGU", - "headUnitType": "MGU", - "hmiVersion": "ID8", - "lastFetched": "2023-01-04T14:57:06.019Z", - "model": "iX xDrive50", - "softwareVersionCurrent": { - "iStep": 300, - "puStep": { - "month": 7, - "year": 21 - }, - "seriesCluster": "S21A" - }, - "softwareVersionExFactory": { - "iStep": 300, - "puStep": { - "month": 7, - "year": 21 - }, - "seriesCluster": "S21A" - }, - "telematicsUnit": "WAVE01", - "year": 2021 - }, - "mappingInfo": { - "isAssociated": false, - "isLmmEnabled": false, - "isPrimaryUser": true, - "lmmStatusReasons": [], - "mappingStatus": "CONFIRMED" - }, - "vin": "WBA00000000DEMO01" - } -] \ No newline at end of file diff --git a/bimmer_connected/tests/responses/I20/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO01.json b/bimmer_connected/tests/responses/I20/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO01.json new file mode 100644 index 00000000..368ad94a --- /dev/null +++ b/bimmer_connected/tests/responses/I20/bmw-eadrax-vcs_v5_vehicle-data_profile_WBA00000000DEMO01.json @@ -0,0 +1,36 @@ +{ + "bodyType": "I20", + "brand": "BMW_I", + "color": 4285537312, + "countryOfOrigin": "DE", + "driveTrain": "ELECTRIC", + "driverGuideInfo": { + "androidAppScheme": "com.bmwgroup.driversguide.row", + "androidStoreUrl": "https://play.google.com/store/apps/details?id=com.bmwgroup.driversguide.row", + "iosAppScheme": "bmwdriversguide:///open", + "iosStoreUrl": "https://apps.apple.com/de/app/id714042749?mt=8" + }, + "headUnitRaw": "HU_MGU", + "headUnitType": "MGU", + "hmiVersion": "ID8", + "model": "iX xDrive50", + "softwareVersionCurrent": { + "iStep": 300, + "puStep": { + "month": 7, + "year": 21 + }, + "seriesCluster": "S21A" + }, + "softwareVersionExFactory": { + "iStep": 300, + "puStep": { + "month": 7, + "year": 21 + }, + "seriesCluster": "S21A" + }, + "telematicsUnit": "WAVE01", + "vin": "WBA00000000DEMO01", + "year": 2021 +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/I20/bmw-eadrax-vcs_v5_vehicle-list.json b/bimmer_connected/tests/responses/I20/bmw-eadrax-vcs_v5_vehicle-list.json new file mode 100644 index 00000000..dbcbd26f --- /dev/null +++ b/bimmer_connected/tests/responses/I20/bmw-eadrax-vcs_v5_vehicle-list.json @@ -0,0 +1,13 @@ +{ + "gcid": "ceb64158-d2ca-47e9-9ee6-cbffb881434e", + "mappingInfos": [ + { + "isAssociated": false, + "isLmmEnabled": false, + "isPrimaryUser": true, + "mappingStatus": "CONFIRMED", + "vehicleMappingType": "CONNECTED", + "vin": "WBA00000000DEMO01" + } + ] +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/bmw-eadrax-vcs_v5_vehicle-list.json b/bimmer_connected/tests/responses/bmw-eadrax-vcs_v5_vehicle-list.json new file mode 100644 index 00000000..0c546925 --- /dev/null +++ b/bimmer_connected/tests/responses/bmw-eadrax-vcs_v5_vehicle-list.json @@ -0,0 +1,4 @@ +{ + "gcid": "ceb64158-d2ca-47e9-9ee6-cbffb881434e", + "mappingInfos": [] +} \ No newline at end of file diff --git a/bimmer_connected/tests/responses/mini-eadrax-vcs_v5_vehicle-list.json b/bimmer_connected/tests/responses/mini-eadrax-vcs_v5_vehicle-list.json new file mode 100644 index 00000000..0c546925 --- /dev/null +++ b/bimmer_connected/tests/responses/mini-eadrax-vcs_v5_vehicle-list.json @@ -0,0 +1,4 @@ +{ + "gcid": "ceb64158-d2ca-47e9-9ee6-cbffb881434e", + "mappingInfos": [] +} \ No newline at end of file diff --git a/bimmer_connected/tests/test_account.py b/bimmer_connected/tests/test_account.py index 609d6166..c5067ebc 100644 --- a/bimmer_connected/tests/test_account.py +++ b/bimmer_connected/tests/test_account.py @@ -13,7 +13,7 @@ from bimmer_connected.api.authentication import MyBMWAuthentication, MyBMWLoginRetry from bimmer_connected.api.client import MyBMWClient from bimmer_connected.api.regions import get_region_from_name -from bimmer_connected.const import ATTR_CAPABILITIES +from bimmer_connected.const import ATTR_CAPABILITIES, VEHICLES_URL from bimmer_connected.models import GPSPosition, MyBMWAPIError, MyBMWAuthError, MyBMWQuotaError from . import ( @@ -24,8 +24,7 @@ TEST_USERNAME, VIN_G26, VIN_I20, - get_fingerprint_charging_settings_count, - get_fingerprint_state_count, + get_fingerprint_count, load_response, ) from .conftest import prepare_account_with_vehicles @@ -177,7 +176,7 @@ async def test_vehicles(bmw_fixture: respx.Router): await account.get_vehicles() assert account.config.authentication.access_token is not None - assert get_fingerprint_state_count() == len(account.vehicles) + assert get_fingerprint_count("profiles") == len(account.vehicles) vehicle = account.get_vehicle(VIN_G26) assert vehicle is not None @@ -198,15 +197,15 @@ async def test_vehicle_init(bmw_fixture: respx.Router): # First call on init await account.get_vehicles() - assert len(account.vehicles) == get_fingerprint_state_count() + assert len(account.vehicles) == get_fingerprint_count("profiles") # No call to _init_vehicles() await account.get_vehicles() - assert len(account.vehicles) == get_fingerprint_state_count() + assert len(account.vehicles) == get_fingerprint_count("profiles") # Second, forced call _init_vehicles() await account.get_vehicles(force_init=True) - assert len(account.vehicles) == get_fingerprint_state_count() + assert len(account.vehicles) == get_fingerprint_count("profiles") assert mock_listener.call_count == 2 @@ -259,9 +258,14 @@ async def test_vehicle_search_case(bmw_fixture: respx.Router): async def test_get_fingerprints(monkeypatch: pytest.MonkeyPatch, bmw_fixture: respx.Router, bmw_log_all_responses): """Test getting fingerprints.""" - # Prepare Number of good responses (vehicle states, charging settings per vehicle) + # Prepare Number of good responses (vehicle profiles + vehicle states, charging settings per vehicle) # and 2x vehicle list - json_count = get_fingerprint_state_count() + get_fingerprint_charging_settings_count() + 2 + json_count = ( + get_fingerprint_count("vehicles") + + get_fingerprint_count("profiles") + + get_fingerprint_count("states") + + get_fingerprint_count("charging_settings") + ) account = MyBMWAccount(TEST_USERNAME, TEST_PASSWORD, TEST_REGION, log_responses=True) await account.get_vehicles() @@ -339,21 +343,27 @@ async def test_set_use_metric_units(caplog): account = MyBMWAccount(TEST_USERNAME, TEST_PASSWORD, TEST_REGION) assert len(caplog.records) == 0 metric_client = MyBMWClient(account.config) - assert metric_client.generate_default_header()["bmw-units-preferences"] == "d=KM;v=L" + assert ( + metric_client.generate_default_header()["bmw-units-preferences"] == "d=KM;v=L;p=B;ec=KWH100KM;fc=L100KM;em=GKM;" + ) # Set to true caplog.clear() account = MyBMWAccount(TEST_USERNAME, TEST_PASSWORD, TEST_REGION, use_metric_units=True) assert len(caplog.records) == 1 metric_client = MyBMWClient(account.config) - assert metric_client.generate_default_header()["bmw-units-preferences"] == "d=KM;v=L" + assert ( + metric_client.generate_default_header()["bmw-units-preferences"] == "d=KM;v=L;p=B;ec=KWH100KM;fc=L100KM;em=GKM;" + ) # Set to false caplog.clear() account = MyBMWAccount(TEST_USERNAME, TEST_PASSWORD, TEST_REGION, use_metric_units=True) assert len(caplog.records) == 1 metric_client = MyBMWClient(account.config) - assert metric_client.generate_default_header()["bmw-units-preferences"] == "d=KM;v=L" + assert ( + metric_client.generate_default_header()["bmw-units-preferences"] == "d=KM;v=L;p=B;ec=KWH100KM;fc=L100KM;em=GKM;" + ) @pytest.mark.asyncio @@ -434,11 +444,12 @@ async def test_429_retry_ok_vehicles(caplog, bmw_fixture: respx.Router): json_429 = {"statusCode": 429, "message": "Rate limit is exceeded. Try again in 2 seconds."} - bmw_fixture.get("/eadrax-vcs/v4/vehicles").mock( + bmw_fixture.post(VEHICLES_URL).mock( side_effect=[ httpx.Response(429, json=json_429), httpx.Response(429, json=json_429), - *[httpx.Response(200, json=[])] * 2, + httpx.Response(200, json=load_response(RESPONSE_DIR / "bmw-eadrax-vcs_v5_vehicle-list.json")), + httpx.Response(200, json=load_response(RESPONSE_DIR / "mini-eadrax-vcs_v5_vehicle-list.json")), ] ) caplog.set_level(logging.DEBUG) @@ -461,7 +472,7 @@ async def test_429_retry_raise_vehicles(caplog, bmw_fixture: respx.Router): json_429 = {"statusCode": 429, "message": "Rate limit is exceeded. Try again in 2 seconds."} - bmw_fixture.get("/eadrax-vcs/v4/vehicles").mock(return_value=httpx.Response(429, json=json_429)) + bmw_fixture.post(VEHICLES_URL).mock(return_value=httpx.Response(429, json=json_429)) caplog.set_level(logging.DEBUG) with mock.patch("asyncio.sleep", new_callable=mock.AsyncMock): @@ -483,11 +494,12 @@ async def test_429_retry_with_login_ok_vehicles(bmw_fixture: respx.Router): json_429 = {"statusCode": 429, "message": "Rate limit is exceeded. Try again in 2 seconds."} - bmw_fixture.get("/eadrax-vcs/v4/vehicles").mock( + bmw_fixture.post(VEHICLES_URL).mock( side_effect=[ httpx.Response(429, json=json_429), httpx.Response(429, json=json_429), - *[httpx.Response(200, json=[])] * 2, + httpx.Response(200, json=load_response(RESPONSE_DIR / "bmw-eadrax-vcs_v5_vehicle-list.json")), + httpx.Response(200, json=load_response(RESPONSE_DIR / "mini-eadrax-vcs_v5_vehicle-list.json")), ] ) @@ -502,7 +514,7 @@ async def test_429_retry_with_login_raise_vehicles(bmw_fixture: respx.Router): json_429 = {"statusCode": 429, "message": "Rate limit is exceeded. Try again in 2 seconds."} - bmw_fixture.get("/eadrax-vcs/v4/vehicles").mock( + bmw_fixture.post(VEHICLES_URL).mock( side_effect=[ httpx.Response(429, json=json_429), httpx.Response(401), @@ -524,7 +536,7 @@ async def test_multiple_401(bmw_fixture: respx.Router): """Test the error handling, when multiple 401 are received in sequence.""" account = MyBMWAccount(TEST_USERNAME, TEST_PASSWORD, TEST_REGION) - bmw_fixture.get("/eadrax-vcs/v4/vehicles").mock( + bmw_fixture.post(VEHICLES_URL).mock( side_effect=[ httpx.Response(401), httpx.Response(401), @@ -545,18 +557,19 @@ async def test_401_after_429_ok(bmw_fixture: respx.Router): json_429 = {"statusCode": 429, "message": "Rate limit is exceeded. Try again in 2 seconds."} # Recover after 3 429 and 1 401 - bmw_fixture.get("/eadrax-vcs/v4/vehicles").mock( + bmw_fixture.post(VEHICLES_URL).mock( side_effect=[ httpx.Response(429, json=json_429), httpx.Response(429, json=json_429), httpx.Response(429, json=json_429), httpx.Response(401), - *[httpx.Response(200, json={})] * 100, # Just simulate OK responses from now on + # Just simulate OK responses from now on + *[httpx.Response(200, json=load_response(RESPONSE_DIR / "bmw-eadrax-vcs_v5_vehicle-list.json"))] * 100, ] ) with mock.patch("asyncio.sleep", new_callable=mock.AsyncMock): await account.get_vehicles() - assert len(account.vehicles) == get_fingerprint_state_count() + assert len(account.vehicles) == get_fingerprint_count("profiles") @pytest.mark.asyncio @@ -567,7 +580,7 @@ async def test_401_after_429_fail(bmw_fixture: respx.Router): json_429 = {"statusCode": 429, "message": "Rate limit is exceeded. Try again in 2 seconds."} # Fail after 3 429 and 1 401 with another 429 - bmw_fixture.get("/eadrax-vcs/v4/vehicles").mock( + bmw_fixture.post(VEHICLES_URL).mock( side_effect=[ httpx.Response(429, json=json_429), httpx.Response(429, json=json_429), @@ -647,7 +660,7 @@ async def test_no_vehicle_details(caplog, bmw_fixture: respx.Router): await account.get_vehicles() log_error = [r for r in caplog.records if "Unable to get details" in r.message] - assert len(log_error) == get_fingerprint_state_count() + assert len(log_error) == get_fingerprint_count("profiles") @pytest.mark.asyncio diff --git a/bimmer_connected/tests/test_api.py b/bimmer_connected/tests/test_api.py index 043f3050..c9102786 100644 --- a/bimmer_connected/tests/test_api.py +++ b/bimmer_connected/tests/test_api.py @@ -17,9 +17,7 @@ TEST_REGION, TEST_USERNAME, VIN_G26, - get_fingerprint_charging_settings_count, - get_fingerprint_state_count, - # get_fingerprint_count, + get_fingerprint_count, load_response, ) @@ -85,22 +83,21 @@ async def test_storing_fingerprints(tmp_path, bmw_fixture: respx.Router, bmw_log json_files = [f for f in files if f.suffix == ".json"] txt_files = [f for f in files if f.suffix == ".txt"] - assert len(json_files) == (get_fingerprint_state_count() + get_fingerprint_charging_settings_count() + 2 - 2) - assert len(txt_files) == 1 + assert len(json_files) == ( + get_fingerprint_count("vehicles") + + get_fingerprint_count("profiles") + + get_fingerprint_count("states") + - 1 # state with error 500 + + get_fingerprint_count("charging_settings") + - 1 # not loaded due to state with error 500 + ) + assert len(txt_files) == 1 # state with error 500 @pytest.mark.asyncio async def test_fingerprint_deque(monkeypatch: pytest.MonkeyPatch, bmw_fixture: respx.Router): """Test storing fingerprints to file.""" - # Increase length of response store for local testing - - # temp_store = deque(maxlen=100) - # monkeypatch.setattr("bimmer_connected.api.client.RESPONSE_STORE", temp_store) - # monkeypatch.setattr("bimmer_connected.account.RESPONSE_STORE", temp_store) - - # Prepare Number of good responses (vehicle states, charging settings per vehicle) - # # and 2x vehicle list - # json_count = get_fingerprint_state_count() + get_fingerprint_charging_settings_count() + 2 + # Prepare Number of good responses account = MyBMWAccount(TEST_USERNAME, TEST_PASSWORD, TEST_REGION, log_responses=True) await account.get_vehicles() diff --git a/bimmer_connected/tests/test_vehicle.py b/bimmer_connected/tests/test_vehicle.py index 38b73704..fc18340e 100644 --- a/bimmer_connected/tests/test_vehicle.py +++ b/bimmer_connected/tests/test_vehicle.py @@ -130,7 +130,7 @@ async def test_get_is_tracking_enabled(caplog, bmw_fixture: respx.Router): vehicle = account.get_vehicle(VIN_I01_REX) assert vehicle.is_vehicle_tracking_enabled is False - vehicle = account.get_vehicle(VIN_F31) + vehicle = account.get_vehicle(VIN_G20) assert vehicle.is_vehicle_tracking_enabled is True assert len(get_deprecation_warning_count(caplog)) == 0 @@ -212,9 +212,9 @@ async def test_vehicle_image(caplog, bmw_fixture: respx.Router): vehicle = (await prepare_account_with_vehicles()).get_vehicle(VIN_G01) bmw_fixture.get( - path__regex=r"(.*)/eadrax-ics/v3/presentation/vehicles/\w*/images", + path="/eadrax-ics/v5/presentation/vehicles/images", params={"carView": "FrontView"}, - headers={"accept": "image/png"}, + headers={"accept": "image/png", "bmw-app-vehicle-type": "connected", "bmw-vin": VIN_G01}, ).respond(200, content="png_image") assert b"png_image" == await vehicle.get_vehicle_image(VehicleViewDirection.FRONT) @@ -225,8 +225,8 @@ async def test_vehicle_image(caplog, bmw_fixture: respx.Router): async def test_no_timestamp(bmw_fixture: respx.Router): """Test no timestamp available.""" vehicle = (await prepare_account_with_vehicles()).get_vehicle(VIN_F31) - vehicle.data[ATTR_STATE].pop("lastFetched") - vehicle.data[ATTR_ATTRIBUTES].pop("lastFetched") + vehicle.data[ATTR_STATE].pop("lastFetched", None) + vehicle.data[ATTR_ATTRIBUTES].pop("lastFetched", None) assert vehicle.timestamp is None diff --git a/bimmer_connected/tests/test_vehicle_status.py b/bimmer_connected/tests/test_vehicle_status.py index 3f9ebbc3..491071e1 100644 --- a/bimmer_connected/tests/test_vehicle_status.py +++ b/bimmer_connected/tests/test_vehicle_status.py @@ -81,11 +81,11 @@ async def test_generic_error_handling(caplog, bmw_fixture: respx.Router): @pytest.mark.asyncio async def test_range_combustion_no_info(caplog, bmw_fixture: respx.Router): - """Test if the parsing of mileage and range is working.""" + """Test if the parsing of very old vehicles.""" vehicle = (await prepare_account_with_vehicles()).get_vehicle(VIN_F31) status = vehicle.fuel_and_battery - assert (14, "L") == status.remaining_fuel + assert status.remaining_fuel == (None, None) assert status.remaining_range_fuel == (None, None) assert status.remaining_fuel_percent is None @@ -94,18 +94,14 @@ async def test_range_combustion_no_info(caplog, bmw_fixture: respx.Router): assert status.remaining_range_total == (None, None) - status_from_vehicle_data = FuelAndBattery.from_vehicle_data(vehicle.data) - status_from_vehicle_data.account_timezone = status.account_timezone - assert status_from_vehicle_data == status - assert FuelAndBattery.from_vehicle_data({}) is None - assert len(get_deprecation_warning_count(caplog)) == 0 @pytest.mark.asyncio async def test_range_combustion(caplog, bmw_fixture: respx.Router): """Test if the parsing of mileage and range is working.""" - status = (await prepare_account_with_vehicles()).get_vehicle(VIN_G20).fuel_and_battery + vehicle = (await prepare_account_with_vehicles()).get_vehicle(VIN_G20) + status = vehicle.fuel_and_battery assert (40, "L") == status.remaining_fuel assert (629, "km") == status.remaining_range_fuel @@ -116,6 +112,11 @@ async def test_range_combustion(caplog, bmw_fixture: respx.Router): assert (629, "km") == status.remaining_range_total + status_from_vehicle_data = FuelAndBattery.from_vehicle_data(vehicle.data) + status_from_vehicle_data.account_timezone = status.account_timezone + assert status_from_vehicle_data == status + assert FuelAndBattery.from_vehicle_data({}) is None + assert len(get_deprecation_warning_count(caplog)) == 0 diff --git a/bimmer_connected/vehicle/vehicle.py b/bimmer_connected/vehicle/vehicle.py index 6a783f25..be2bb6ab 100644 --- a/bimmer_connected/vehicle/vehicle.py +++ b/bimmer_connected/vehicle/vehicle.py @@ -351,11 +351,11 @@ async def get_vehicle_image(self, direction: VehicleViewDirection) -> bytes: :returns bytes containing the image in PNG format. """ - url = VEHICLE_IMAGE_URL.format( - vin=self.vin, - view=direction.value, - ) # the accept field of the header needs to be updated as we want a png not the usual JSON async with MyBMWClient(self.account.config, brand=self.brand) as client: - response = await client.get(url, headers={"accept": "image/png"}) + response = await client.get( + VEHICLE_IMAGE_URL, + params={"carView": direction.value, "toCrop": True}, + headers={"accept": "image/png", "bmw-app-vehicle-type": "connected", "bmw-vin": self.vin}, + ) return response.content