From 021b14fc17379c7dccf865fb7242600665a62ad8 Mon Sep 17 00:00:00 2001 From: Richard Kroegel <42204099+rikroe@users.noreply.github.com> Date: Wed, 30 Aug 2023 11:45:09 +0200 Subject: [PATCH] Refactor & enhance BMW tests (#97895) Co-authored-by: rikroe --- .../bmw_connected_drive/__init__.py | 149 +- .../bmw_connected_drive/conftest.py | 47 +- .../remote_service/eventposition.json | 12 - ...x-crccs_v2_vehicles_WBA00000000DEMO02.json | 80 - .../G26/bmw-eadrax-vcs_v4_vehicles.json | 50 - ...s_v4_vehicles_state_WBA00000000DEMO02.json | 317 -- ...x-crccs_v2_vehicles_WBY00000000REXI01.json | 60 - .../I01_REX/bmw-eadrax-vcs_v4_vehicles.json | 47 - ...s_v4_vehicles_state_WBY00000000REXI01.json | 206 - .../snapshots/test_button.ambr | 120 + .../snapshots/test_diagnostics.ambr | 4147 ++++++++++++++++- .../snapshots/test_number.ambr | 17 + .../snapshots/test_select.ambr | 44 + .../snapshots/test_switch.ambr | 34 +- .../bmw_connected_drive/test_button.py | 144 +- .../bmw_connected_drive/test_number.py | 45 +- .../bmw_connected_drive/test_select.py | 58 +- .../bmw_connected_drive/test_sensor.py | 4 +- .../bmw_connected_drive/test_switch.py | 60 +- 19 files changed, 4557 insertions(+), 1084 deletions(-) delete mode 100644 tests/components/bmw_connected_drive/fixtures/remote_service/eventposition.json delete mode 100644 tests/components/bmw_connected_drive/fixtures/vehicles/G26/bmw-eadrax-crccs_v2_vehicles_WBA00000000DEMO02.json delete mode 100644 tests/components/bmw_connected_drive/fixtures/vehicles/G26/bmw-eadrax-vcs_v4_vehicles.json delete mode 100644 tests/components/bmw_connected_drive/fixtures/vehicles/G26/bmw-eadrax-vcs_v4_vehicles_state_WBA00000000DEMO02.json delete mode 100644 tests/components/bmw_connected_drive/fixtures/vehicles/I01_REX/bmw-eadrax-crccs_v2_vehicles_WBY00000000REXI01.json delete mode 100644 tests/components/bmw_connected_drive/fixtures/vehicles/I01_REX/bmw-eadrax-vcs_v4_vehicles.json delete mode 100644 tests/components/bmw_connected_drive/fixtures/vehicles/I01_REX/bmw-eadrax-vcs_v4_vehicles_state_WBY00000000REXI01.json diff --git a/tests/components/bmw_connected_drive/__init__.py b/tests/components/bmw_connected_drive/__init__.py index 89a34682c1b..020e4c978ed 100644 --- a/tests/components/bmw_connected_drive/__init__.py +++ b/tests/components/bmw_connected_drive/__init__.py @@ -1,16 +1,7 @@ """Tests for the for the BMW Connected Drive integration.""" -from pathlib import Path -from urllib.parse import urlparse -from bimmer_connected.api.authentication import MyBMWAuthentication -from bimmer_connected.const import ( - REMOTE_SERVICE_POSITION_URL, - VEHICLE_CHARGING_DETAILS_URL, - VEHICLE_STATE_URL, - VEHICLES_URL, -) -import httpx +from bimmer_connected.const import REMOTE_SERVICE_BASE_URL, VEHICLE_CHARGING_BASE_URL import respx from homeassistant import config_entries @@ -23,12 +14,7 @@ from homeassistant.components.bmw_connected_drive.const import ( from homeassistant.const import CONF_PASSWORD, CONF_REGION, CONF_USERNAME from homeassistant.core import HomeAssistant -from tests.common import ( - MockConfigEntry, - get_fixture_path, - load_json_array_fixture, - load_json_object_fixture, -) +from tests.common import MockConfigEntry FIXTURE_USER_INPUT = { CONF_USERNAME: "user@domain.com", @@ -54,88 +40,6 @@ FIXTURE_CONFIG_ENTRY = { "unique_id": f"{FIXTURE_USER_INPUT[CONF_REGION]}-{FIXTURE_USER_INPUT[CONF_REGION]}", } -FIXTURE_PATH = Path(get_fixture_path("", integration=BMW_DOMAIN)) -FIXTURE_FILES = { - "vehicles": sorted(FIXTURE_PATH.rglob("*-eadrax-vcs_v4_vehicles.json")), - "states": { - p.stem.split("_")[-1]: p - for p in FIXTURE_PATH.rglob("*-eadrax-vcs_v4_vehicles_state_*.json") - }, - "charging": { - p.stem.split("_")[-1]: p - for p in FIXTURE_PATH.rglob("*-eadrax-crccs_v2_vehicles_*.json") - }, -} - - -def vehicles_sideeffect(request: httpx.Request) -> httpx.Response: - """Return /vehicles response based on x-user-agent.""" - x_user_agent = request.headers.get("x-user-agent", "").split(";") - brand = x_user_agent[1] - vehicles = [] - for vehicle_file in FIXTURE_FILES["vehicles"]: - if vehicle_file.name.startswith(brand): - vehicles.extend( - load_json_array_fixture(vehicle_file, integration=BMW_DOMAIN) - ) - return httpx.Response(200, json=vehicles) - - -def vehicle_state_sideeffect(request: httpx.Request) -> httpx.Response: - """Return /vehicles/state response.""" - try: - state_file = FIXTURE_FILES["states"][request.headers["bmw-vin"]] - return httpx.Response( - 200, json=load_json_object_fixture(state_file, integration=BMW_DOMAIN) - ) - except KeyError: - return httpx.Response(404) - - -def vehicle_charging_sideeffect(request: httpx.Request) -> httpx.Response: - """Return /vehicles/state response.""" - try: - charging_file = FIXTURE_FILES["charging"][request.headers["bmw-vin"]] - return httpx.Response( - 200, json=load_json_object_fixture(charging_file, integration=BMW_DOMAIN) - ) - except KeyError: - return httpx.Response(404) - - -def mock_vehicles() -> respx.Router: - """Return mocked adapter for vehicles.""" - router = respx.mock(assert_all_called=False) - - # Get vehicle list - router.get(VEHICLES_URL).mock(side_effect=vehicles_sideeffect) - - # Get vehicle state - router.get(VEHICLE_STATE_URL).mock(side_effect=vehicle_state_sideeffect) - - # Get vehicle charging details - router.get(VEHICLE_CHARGING_DETAILS_URL).mock( - side_effect=vehicle_charging_sideeffect - ) - - # Get vehicle position after remote service - router.post(urlparse(REMOTE_SERVICE_POSITION_URL).netloc).mock( - httpx.Response( - 200, - json=load_json_object_fixture( - FIXTURE_PATH / "remote_service" / "eventposition.json", - integration=BMW_DOMAIN, - ), - ) - ) - - return router - - -async def mock_login(auth: MyBMWAuthentication) -> None: - """Mock a successful login.""" - auth.access_token = "SOME_ACCESS_TOKEN" - async def setup_mocked_integration(hass: HomeAssistant) -> MockConfigEntry: """Mock a fully setup config entry and all components based on fixtures.""" @@ -147,3 +51,52 @@ async def setup_mocked_integration(hass: HomeAssistant) -> MockConfigEntry: await hass.async_block_till_done() return mock_config_entry + + +def check_remote_service_call( + router: respx.MockRouter, + remote_service: str = None, + remote_service_params: dict = None, + remote_service_payload: dict = None, +): + """Check if the last call was a successful remote service call.""" + + # Check if remote service call was made correctly + if remote_service: + # Get remote service call + first_remote_service_call: respx.models.Call = next( + c + for c in router.calls + if c.request.url.path.startswith(REMOTE_SERVICE_BASE_URL) + or c.request.url.path.startswith( + VEHICLE_CHARGING_BASE_URL.replace("/{vin}", "") + ) + ) + assert ( + first_remote_service_call.request.url.path.endswith(remote_service) is True + ) + assert first_remote_service_call.has_response is True + assert first_remote_service_call.response.is_success is True + + # test params. + # we don't test payload as this creates a lot of noise in the tests + # and is end-to-end tested with the HA states + if remote_service_params: + assert ( + dict(first_remote_service_call.request.url.params.items()) + == remote_service_params + ) + + # Now check final result + last_event_status_call = next( + c for c in reversed(router.calls) if c.request.url.path.endswith("eventStatus") + ) + + assert last_event_status_call is not None + assert ( + last_event_status_call.request.url.path + == "/eadrax-vrccs/v3/presentation/remote-commands/eventStatus" + ) + assert last_event_status_call.has_response is True + assert last_event_status_call.response.is_success is True + assert last_event_status_call.response.json() == {"eventStatus": "EXECUTED"} diff --git a/tests/components/bmw_connected_drive/conftest.py b/tests/components/bmw_connected_drive/conftest.py index b65adb5b2c0..4191c7a4dd2 100644 --- a/tests/components/bmw_connected_drive/conftest.py +++ b/tests/components/bmw_connected_drive/conftest.py @@ -1,34 +1,39 @@ """Fixtures for BMW tests.""" -from unittest.mock import AsyncMock, Mock -from bimmer_connected.api.authentication import MyBMWAuthentication -from bimmer_connected.vehicle.remote_services import RemoteServices, RemoteServiceStatus +from collections.abc import Generator + +from bimmer_connected.tests import ALL_CHARGING_SETTINGS, ALL_STATES +from bimmer_connected.tests.common import MyBMWMockRouter +from bimmer_connected.vehicle import remote_services import pytest - -from homeassistant.components.bmw_connected_drive.coordinator import ( - BMWDataUpdateCoordinator, -) - -from . import mock_login, mock_vehicles +import respx @pytest.fixture -async def bmw_fixture(monkeypatch): - """Patch the MyBMW Login and mock HTTP calls.""" - monkeypatch.setattr(MyBMWAuthentication, "login", mock_login) +def bmw_fixture( + request: pytest.FixtureRequest, monkeypatch: pytest.MonkeyPatch +) -> Generator[respx.MockRouter, None, None]: + """Patch MyBMW login API calls.""" - monkeypatch.setattr( - RemoteServices, - "trigger_remote_service", - AsyncMock(return_value=RemoteServiceStatus({"eventStatus": "EXECUTED"})), + # we use the library's mock router to mock the API calls, but only with a subset of vehicles + router = MyBMWMockRouter( + vehicles_to_load=[ + "WBA00000000DEMO01", + "WBA00000000DEMO02", + "WBA00000000DEMO03", + "WBY00000000REXI01", + ], + states=ALL_STATES, + charging_settings=ALL_CHARGING_SETTINGS, ) + # we don't want to wait when triggering a remote service monkeypatch.setattr( - BMWDataUpdateCoordinator, - "async_update_listeners", - Mock(), + remote_services, + "_POLLING_CYCLE", + 0, ) - with mock_vehicles(): - yield mock_vehicles + with router: + yield router diff --git a/tests/components/bmw_connected_drive/fixtures/remote_service/eventposition.json b/tests/components/bmw_connected_drive/fixtures/remote_service/eventposition.json deleted file mode 100644 index 92d1a6a9db0..00000000000 --- a/tests/components/bmw_connected_drive/fixtures/remote_service/eventposition.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "positionData": { - "status": "OK", - "position": { - "latitude": 123.456, - "longitude": 34.5678, - "formattedAddress": "some_formatted_address", - "heading": 121 - } - }, - "errorDetails": null -} diff --git a/tests/components/bmw_connected_drive/fixtures/vehicles/G26/bmw-eadrax-crccs_v2_vehicles_WBA00000000DEMO02.json b/tests/components/bmw_connected_drive/fixtures/vehicles/G26/bmw-eadrax-crccs_v2_vehicles_WBA00000000DEMO02.json deleted file mode 100644 index af850f1ff2c..00000000000 --- a/tests/components/bmw_connected_drive/fixtures/vehicles/G26/bmw-eadrax-crccs_v2_vehicles_WBA00000000DEMO02.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "chargeAndClimateSettings": { - "chargeAndClimateTimer": { - "chargingMode": "Sofort laden", - "chargingModeSemantics": "Sofort laden", - "departureTimer": ["Aus"], - "departureTimerSemantics": "Aus", - "preconditionForDeparture": "Aus", - "showDepartureTimers": false - }, - "chargingFlap": { - "permanentlyUnlockLabel": "Aus" - }, - "chargingSettings": { - "acCurrentLimitLabel": "16A", - "acCurrentLimitLabelSemantics": "16 Ampere", - "chargingTargetLabel": "80%", - "dcLoudnessLabel": "Nicht begrenzt", - "unlockCableAutomaticallyLabel": "Aus" - } - }, - "chargeAndClimateTimerDetail": { - "chargingMode": { - "chargingPreference": "NO_PRESELECTION", - "endTimeSlot": "0001-01-01T00:00:00", - "startTimeSlot": "0001-01-01T00:00:00", - "type": "CHARGING_IMMEDIATELY" - }, - "departureTimer": { - "type": "WEEKLY_DEPARTURE_TIMER", - "weeklyTimers": [ - { - "daysOfTheWeek": [], - "id": 1, - "time": "0001-01-01T00:00:00", - "timerAction": "DEACTIVATE" - }, - { - "daysOfTheWeek": [], - "id": 2, - "time": "0001-01-01T00:00:00", - "timerAction": "DEACTIVATE" - }, - { - "daysOfTheWeek": [], - "id": 3, - "time": "0001-01-01T00:00:00", - "timerAction": "DEACTIVATE" - }, - { - "daysOfTheWeek": [], - "id": 4, - "time": "0001-01-01T00:00:00", - "timerAction": "DEACTIVATE" - } - ] - }, - "isPreconditionForDepartureActive": false - }, - "chargingFlapDetail": { - "isPermanentlyUnlock": false - }, - "chargingSettingsDetail": { - "acLimit": { - "current": { - "unit": "A", - "value": 16 - }, - "isUnlimited": false, - "max": 32, - "min": 6, - "values": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 32] - }, - "chargingTarget": 80, - "dcLoudness": "UNLIMITED_LOUD", - "isUnlockCableActive": false, - "minChargingTargetToWarning": 0 - }, - "servicePack": "WAVE_01" -} diff --git a/tests/components/bmw_connected_drive/fixtures/vehicles/G26/bmw-eadrax-vcs_v4_vehicles.json b/tests/components/bmw_connected_drive/fixtures/vehicles/G26/bmw-eadrax-vcs_v4_vehicles.json deleted file mode 100644 index f954fb103ae..00000000000 --- a/tests/components/bmw_connected_drive/fixtures/vehicles/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" - } -] diff --git a/tests/components/bmw_connected_drive/fixtures/vehicles/G26/bmw-eadrax-vcs_v4_vehicles_state_WBA00000000DEMO02.json b/tests/components/bmw_connected_drive/fixtures/vehicles/G26/bmw-eadrax-vcs_v4_vehicles_state_WBA00000000DEMO02.json deleted file mode 100644 index a0974854295..00000000000 --- a/tests/components/bmw_connected_drive/fixtures/vehicles/G26/bmw-eadrax-vcs_v4_vehicles_state_WBA00000000DEMO02.json +++ /dev/null @@ -1,317 +0,0 @@ -{ - "capabilities": { - "a4aType": "NOT_SUPPORTED", - "checkSustainabilityDPP": false, - "climateFunction": "AIR_CONDITIONING", - "climateNow": true, - "digitalKey": { - "bookedServicePackage": "SMACC_1_5", - "readerGraphics": "readerGraphics", - "state": "ACTIVATED" - }, - "horn": true, - "isBmwChargingSupported": true, - "isCarSharingSupported": false, - "isChargeNowForBusinessSupported": true, - "isChargingHistorySupported": true, - "isChargingHospitalityEnabled": true, - "isChargingLoudnessEnabled": true, - "isChargingPlanSupported": true, - "isChargingPowerLimitEnabled": true, - "isChargingSettingsEnabled": true, - "isChargingTargetSocEnabled": true, - "isClimateTimerWeeklyActive": false, - "isCustomerEsimSupported": true, - "isDCSContractManagementSupported": true, - "isDataPrivacyEnabled": false, - "isEasyChargeEnabled": true, - "isEvGoChargingSupported": false, - "isMiniChargingSupported": false, - "isNonLscFeatureEnabled": false, - "isPersonalPictureUploadSupported": false, - "isRemoteEngineStartSupported": false, - "isRemoteHistoryDeletionSupported": false, - "isRemoteHistorySupported": true, - "isRemoteParkingSupported": false, - "isRemoteServicesActivationRequired": false, - "isRemoteServicesBookingRequired": false, - "isScanAndChargeSupported": true, - "isSustainabilityAccumulatedViewEnabled": false, - "isSustainabilitySupported": false, - "isWifiHotspotServiceSupported": false, - "lastStateCallState": "ACTIVATED", - "lights": true, - "lock": true, - "remote360": true, - "remoteChargingCommands": { - "chargingControl": ["START", "STOP"], - "flapControl": ["NOT_SUPPORTED"], - "plugControl": ["NOT_SUPPORTED"] - }, - "remoteSoftwareUpgrade": true, - "sendPoi": true, - "specialThemeSupport": [], - "speechThirdPartyAlexa": false, - "speechThirdPartyAlexaSDK": false, - "unlock": true, - "vehicleFinder": true, - "vehicleStateSource": "LAST_STATE_CALL" - }, - "state": { - "chargingProfile": { - "chargingControlType": "WEEKLY_PLANNER", - "chargingMode": "IMMEDIATE_CHARGING", - "chargingPreference": "NO_PRESELECTION", - "chargingSettings": { - "acCurrentLimit": 16, - "hospitality": "NO_ACTION", - "idcc": "UNLIMITED_LOUD", - "targetSoc": 80 - }, - "departureTimes": [ - { - "action": "DEACTIVATE", - "id": 1, - "timeStamp": { - "hour": 0, - "minute": 0 - }, - "timerWeekDays": [] - }, - { - "action": "DEACTIVATE", - "id": 2, - "timeStamp": { - "hour": 0, - "minute": 0 - }, - "timerWeekDays": [] - }, - { - "action": "DEACTIVATE", - "id": 3, - "timeStamp": { - "hour": 0, - "minute": 0 - }, - "timerWeekDays": [] - }, - { - "action": "DEACTIVATE", - "id": 4, - "timeStamp": { - "hour": 0, - "minute": 0 - }, - "timerWeekDays": [] - } - ] - }, - "checkControlMessages": [ - { - "severity": "LOW", - "type": "TIRE_PRESSURE" - } - ], - "climateControlState": { - "activity": "STANDBY" - }, - "climateTimers": [ - { - "departureTime": { - "hour": 0, - "minute": 0 - }, - "isWeeklyTimer": false, - "timerAction": "DEACTIVATE", - "timerWeekDays": [] - }, - { - "departureTime": { - "hour": 0, - "minute": 0 - }, - "isWeeklyTimer": true, - "timerAction": "DEACTIVATE", - "timerWeekDays": [] - }, - { - "departureTime": { - "hour": 0, - "minute": 0 - }, - "isWeeklyTimer": true, - "timerAction": "DEACTIVATE", - "timerWeekDays": [] - } - ], - "combustionFuelLevel": {}, - "currentMileage": 1121, - "doorsState": { - "combinedSecurityState": "LOCKED", - "combinedState": "CLOSED", - "hood": "CLOSED", - "leftFront": "CLOSED", - "leftRear": "CLOSED", - "rightFront": "CLOSED", - "rightRear": "CLOSED", - "trunk": "CLOSED" - }, - "driverPreferences": { - "lscPrivacyMode": "OFF" - }, - "electricChargingState": { - "chargingConnectionType": "UNKNOWN", - "chargingLevelPercent": 80, - "chargingStatus": "CHARGING", - "chargingTarget": 80, - "isChargerConnected": true, - "range": 472, - "remainingChargingMinutes": 10 - }, - "isLeftSteering": true, - "isLscSupported": true, - "lastFetched": "2023-01-04T14:57:06.386Z", - "lastUpdatedAt": "2023-01-04T14:57:06.407Z", - "location": { - "address": { - "formatted": "Am Olympiapark 1, 80809 München" - }, - "coordinates": { - "latitude": 48.177334, - "longitude": 11.556274 - }, - "heading": 180 - }, - "range": 472, - "requiredServices": [ - { - "dateTime": "2024-12-01T00:00:00.000Z", - "description": "", - "mileage": 50000, - "status": "OK", - "type": "BRAKE_FLUID" - }, - { - "dateTime": "2024-12-01T00:00:00.000Z", - "description": "", - "mileage": 50000, - "status": "OK", - "type": "VEHICLE_TUV" - }, - { - "dateTime": "2024-12-01T00:00:00.000Z", - "description": "", - "mileage": 50000, - "status": "OK", - "type": "VEHICLE_CHECK" - }, - { - "status": "OK", - "type": "TIRE_WEAR_REAR" - }, - { - "status": "OK", - "type": "TIRE_WEAR_FRONT" - } - ], - "tireState": { - "frontLeft": { - "details": { - "dimension": "225/35 R20 90Y XL", - "isOptimizedForOemBmw": true, - "manufacturer": "Pirelli", - "manufacturingWeek": 4021, - "mountingDate": "2022-03-07T00:00:00.000Z", - "partNumber": "2461756", - "season": 2, - "speedClassification": { - "atLeast": false, - "speedRating": 300 - }, - "treadDesign": "P-ZERO" - }, - "status": { - "currentPressure": 241, - "pressureStatus": 0, - "targetPressure": 269, - "wearStatus": 0 - } - }, - "frontRight": { - "details": { - "dimension": "225/35 R20 90Y XL", - "isOptimizedForOemBmw": true, - "manufacturer": "Pirelli", - "manufacturingWeek": 2419, - "mountingDate": "2022-03-07T00:00:00.000Z", - "partNumber": "2461756", - "season": 2, - "speedClassification": { - "atLeast": false, - "speedRating": 300 - }, - "treadDesign": "P-ZERO" - }, - "status": { - "currentPressure": 255, - "pressureStatus": 0, - "targetPressure": 269, - "wearStatus": 0 - } - }, - "rearLeft": { - "details": { - "dimension": "255/30 R20 92Y XL", - "isOptimizedForOemBmw": true, - "manufacturer": "Pirelli", - "manufacturingWeek": 1219, - "mountingDate": "2022-03-07T00:00:00.000Z", - "partNumber": "2461757", - "season": 2, - "speedClassification": { - "atLeast": false, - "speedRating": 300 - }, - "treadDesign": "P-ZERO" - }, - "status": { - "currentPressure": 324, - "pressureStatus": 0, - "targetPressure": 303, - "wearStatus": 0 - } - }, - "rearRight": { - "details": { - "dimension": "255/30 R20 92Y XL", - "isOptimizedForOemBmw": true, - "manufacturer": "Pirelli", - "manufacturingWeek": 1219, - "mountingDate": "2022-03-07T00:00:00.000Z", - "partNumber": "2461757", - "season": 2, - "speedClassification": { - "atLeast": false, - "speedRating": 300 - }, - "treadDesign": "P-ZERO" - }, - "status": { - "currentPressure": 331, - "pressureStatus": 0, - "targetPressure": 303, - "wearStatus": 0 - } - } - }, - "windowsState": { - "combinedState": "CLOSED", - "leftFront": "CLOSED", - "leftRear": "CLOSED", - "rear": "CLOSED", - "rightFront": "CLOSED", - "rightRear": "CLOSED" - } - } -} diff --git a/tests/components/bmw_connected_drive/fixtures/vehicles/I01_REX/bmw-eadrax-crccs_v2_vehicles_WBY00000000REXI01.json b/tests/components/bmw_connected_drive/fixtures/vehicles/I01_REX/bmw-eadrax-crccs_v2_vehicles_WBY00000000REXI01.json deleted file mode 100644 index 03bfc1cae04..00000000000 --- a/tests/components/bmw_connected_drive/fixtures/vehicles/I01_REX/bmw-eadrax-crccs_v2_vehicles_WBY00000000REXI01.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "chargeAndClimateSettings": { - "chargeAndClimateTimer": { - "showDepartureTimers": false - } - }, - "chargeAndClimateTimerDetail": { - "chargingMode": { - "chargingPreference": "CHARGING_WINDOW", - "endTimeSlot": "0001-01-01T01:30:00", - "startTimeSlot": "0001-01-01T18:01:00", - "type": "TIME_SLOT" - }, - "departureTimer": { - "type": "WEEKLY_DEPARTURE_TIMER", - "weeklyTimers": [ - { - "daysOfTheWeek": [ - "MONDAY", - "TUESDAY", - "WEDNESDAY", - "THURSDAY", - "FRIDAY" - ], - "id": 1, - "time": "0001-01-01T07:35:00", - "timerAction": "DEACTIVATE" - }, - { - "daysOfTheWeek": [ - "MONDAY", - "TUESDAY", - "WEDNESDAY", - "THURSDAY", - "FRIDAY", - "SATURDAY", - "SUNDAY" - ], - "id": 2, - "time": "0001-01-01T18:00:00", - "timerAction": "DEACTIVATE" - }, - { - "daysOfTheWeek": [], - "id": 3, - "time": "0001-01-01T07:00:00", - "timerAction": "DEACTIVATE" - }, - { - "daysOfTheWeek": [], - "id": 4, - "time": "0001-01-01T00:00:00", - "timerAction": "DEACTIVATE" - } - ] - }, - "isPreconditionForDepartureActive": false - }, - "servicePack": "TCB1" -} diff --git a/tests/components/bmw_connected_drive/fixtures/vehicles/I01_REX/bmw-eadrax-vcs_v4_vehicles.json b/tests/components/bmw_connected_drive/fixtures/vehicles/I01_REX/bmw-eadrax-vcs_v4_vehicles.json deleted file mode 100644 index 145bc13378e..00000000000 --- a/tests/components/bmw_connected_drive/fixtures/vehicles/I01_REX/bmw-eadrax-vcs_v4_vehicles.json +++ /dev/null @@ -1,47 +0,0 @@ -[ - { - "appVehicleType": "CONNECTED", - "attributes": { - "a4aType": "USB_ONLY", - "bodyType": "I01", - "brand": "BMW_I", - "color": 4284110934, - "countryOfOrigin": "CZ", - "driveTrain": "ELECTRIC_WITH_RANGE_EXTENDER", - "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-07-10T09:25:53.104Z", - "model": "i3 (+ REX)", - "softwareVersionCurrent": { - "iStep": 510, - "puStep": { - "month": 11, - "year": 21 - }, - "seriesCluster": "I001" - }, - "softwareVersionExFactory": { - "iStep": 502, - "puStep": { - "month": 3, - "year": 15 - }, - "seriesCluster": "I001" - }, - "year": 2015 - }, - "mappingInfo": { - "isAssociated": false, - "isLmmEnabled": false, - "isPrimaryUser": true, - "mappingStatus": "CONFIRMED" - }, - "vin": "WBY00000000REXI01" - } -] diff --git a/tests/components/bmw_connected_drive/fixtures/vehicles/I01_REX/bmw-eadrax-vcs_v4_vehicles_state_WBY00000000REXI01.json b/tests/components/bmw_connected_drive/fixtures/vehicles/I01_REX/bmw-eadrax-vcs_v4_vehicles_state_WBY00000000REXI01.json deleted file mode 100644 index adc2bde3650..00000000000 --- a/tests/components/bmw_connected_drive/fixtures/vehicles/I01_REX/bmw-eadrax-vcs_v4_vehicles_state_WBY00000000REXI01.json +++ /dev/null @@ -1,206 +0,0 @@ -{ - "capabilities": { - "climateFunction": "AIR_CONDITIONING", - "climateNow": true, - "climateTimerTrigger": "DEPARTURE_TIMER", - "horn": true, - "isBmwChargingSupported": true, - "isCarSharingSupported": false, - "isChargeNowForBusinessSupported": false, - "isChargingHistorySupported": true, - "isChargingHospitalityEnabled": false, - "isChargingLoudnessEnabled": false, - "isChargingPlanSupported": true, - "isChargingPowerLimitEnabled": false, - "isChargingSettingsEnabled": false, - "isChargingTargetSocEnabled": false, - "isClimateTimerSupported": true, - "isCustomerEsimSupported": false, - "isDCSContractManagementSupported": true, - "isDataPrivacyEnabled": false, - "isEasyChargeEnabled": false, - "isEvGoChargingSupported": false, - "isMiniChargingSupported": false, - "isNonLscFeatureEnabled": false, - "isRemoteEngineStartSupported": false, - "isRemoteHistoryDeletionSupported": false, - "isRemoteHistorySupported": true, - "isRemoteParkingSupported": false, - "isRemoteServicesActivationRequired": false, - "isRemoteServicesBookingRequired": false, - "isScanAndChargeSupported": false, - "isSustainabilitySupported": false, - "isWifiHotspotServiceSupported": false, - "lastStateCallState": "ACTIVATED", - "lights": true, - "lock": true, - "remoteChargingCommands": {}, - "sendPoi": true, - "specialThemeSupport": [], - "unlock": true, - "vehicleFinder": false, - "vehicleStateSource": "LAST_STATE_CALL" - }, - "state": { - "chargingProfile": { - "chargingControlType": "WEEKLY_PLANNER", - "chargingMode": "DELAYED_CHARGING", - "chargingPreference": "CHARGING_WINDOW", - "chargingSettings": { - "hospitality": "NO_ACTION", - "idcc": "NO_ACTION", - "targetSoc": 100 - }, - "climatisationOn": false, - "departureTimes": [ - { - "action": "DEACTIVATE", - "id": 1, - "timeStamp": { - "hour": 7, - "minute": 35 - }, - "timerWeekDays": [ - "MONDAY", - "TUESDAY", - "WEDNESDAY", - "THURSDAY", - "FRIDAY" - ] - }, - { - "action": "DEACTIVATE", - "id": 2, - "timeStamp": { - "hour": 18, - "minute": 0 - }, - "timerWeekDays": [ - "MONDAY", - "TUESDAY", - "WEDNESDAY", - "THURSDAY", - "FRIDAY", - "SATURDAY", - "SUNDAY" - ] - }, - { - "action": "DEACTIVATE", - "id": 3, - "timeStamp": { - "hour": 7, - "minute": 0 - }, - "timerWeekDays": [] - }, - { - "action": "DEACTIVATE", - "id": 4, - "timerWeekDays": [] - } - ], - "reductionOfChargeCurrent": { - "end": { - "hour": 1, - "minute": 30 - }, - "start": { - "hour": 18, - "minute": 1 - } - } - }, - "checkControlMessages": [], - "climateTimers": [ - { - "departureTime": { - "hour": 6, - "minute": 40 - }, - "isWeeklyTimer": true, - "timerAction": "ACTIVATE", - "timerWeekDays": ["THURSDAY", "SUNDAY"] - }, - { - "departureTime": { - "hour": 12, - "minute": 50 - }, - "isWeeklyTimer": false, - "timerAction": "ACTIVATE", - "timerWeekDays": ["MONDAY"] - }, - { - "departureTime": { - "hour": 18, - "minute": 59 - }, - "isWeeklyTimer": true, - "timerAction": "DEACTIVATE", - "timerWeekDays": ["WEDNESDAY"] - } - ], - "combustionFuelLevel": { - "range": 105, - "remainingFuelLiters": 6, - "remainingFuelPercent": 65 - }, - "currentMileage": 137009, - "doorsState": { - "combinedSecurityState": "UNLOCKED", - "combinedState": "CLOSED", - "hood": "CLOSED", - "leftFront": "CLOSED", - "leftRear": "CLOSED", - "rightFront": "CLOSED", - "rightRear": "CLOSED", - "trunk": "CLOSED" - }, - "driverPreferences": { - "lscPrivacyMode": "OFF" - }, - "electricChargingState": { - "chargingConnectionType": "CONDUCTIVE", - "chargingLevelPercent": 82, - "chargingStatus": "WAITING_FOR_CHARGING", - "chargingTarget": 100, - "isChargerConnected": true, - "range": 174 - }, - "isLeftSteering": true, - "isLscSupported": true, - "lastFetched": "2022-06-22T14:24:23.982Z", - "lastUpdatedAt": "2022-06-22T13:58:52Z", - "range": 174, - "requiredServices": [ - { - "dateTime": "2022-10-01T00:00:00.000Z", - "description": "Next service due by the specified date.", - "status": "OK", - "type": "BRAKE_FLUID" - }, - { - "dateTime": "2023-05-01T00:00:00.000Z", - "description": "Next vehicle check due after the specified distance or date.", - "status": "OK", - "type": "VEHICLE_CHECK" - }, - { - "dateTime": "2023-05-01T00:00:00.000Z", - "description": "Next state inspection due by the specified date.", - "status": "OK", - "type": "VEHICLE_TUV" - } - ], - "roofState": { - "roofState": "CLOSED", - "roofStateType": "SUN_ROOF" - }, - "windowsState": { - "combinedState": "CLOSED", - "leftFront": "CLOSED", - "rightFront": "CLOSED" - } - } -} diff --git a/tests/components/bmw_connected_drive/snapshots/test_button.ambr b/tests/components/bmw_connected_drive/snapshots/test_button.ambr index af43f118a77..51e15e5ff43 100644 --- a/tests/components/bmw_connected_drive/snapshots/test_button.ambr +++ b/tests/components/bmw_connected_drive/snapshots/test_button.ambr @@ -1,6 +1,66 @@ # serializer version: 1 # name: test_entity_state_attrs list([ + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'iX xDrive50 Flash lights', + 'icon': 'mdi:car-light-alert', + }), + 'context': , + 'entity_id': 'button.ix_xdrive50_flash_lights', + 'last_changed': , + 'last_updated': , + 'state': 'unknown', + }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'iX xDrive50 Sound horn', + 'icon': 'mdi:bullhorn', + }), + 'context': , + 'entity_id': 'button.ix_xdrive50_sound_horn', + 'last_changed': , + 'last_updated': , + 'state': 'unknown', + }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'iX xDrive50 Activate air conditioning', + 'icon': 'mdi:hvac', + }), + 'context': , + 'entity_id': 'button.ix_xdrive50_activate_air_conditioning', + 'last_changed': , + 'last_updated': , + 'state': 'unknown', + }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'iX xDrive50 Deactivate air conditioning', + 'icon': 'mdi:hvac-off', + }), + 'context': , + 'entity_id': 'button.ix_xdrive50_deactivate_air_conditioning', + 'last_changed': , + 'last_updated': , + 'state': 'unknown', + }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'iX xDrive50 Find vehicle', + 'icon': 'mdi:crosshairs-question', + }), + 'context': , + 'entity_id': 'button.ix_xdrive50_find_vehicle', + 'last_changed': , + 'last_updated': , + 'state': 'unknown', + }), StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by MyBMW', @@ -61,6 +121,66 @@ 'last_updated': , 'state': 'unknown', }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'M340i xDrive Flash lights', + 'icon': 'mdi:car-light-alert', + }), + 'context': , + 'entity_id': 'button.m340i_xdrive_flash_lights', + 'last_changed': , + 'last_updated': , + 'state': 'unknown', + }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'M340i xDrive Sound horn', + 'icon': 'mdi:bullhorn', + }), + 'context': , + 'entity_id': 'button.m340i_xdrive_sound_horn', + 'last_changed': , + 'last_updated': , + 'state': 'unknown', + }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'M340i xDrive Activate air conditioning', + 'icon': 'mdi:hvac', + }), + 'context': , + 'entity_id': 'button.m340i_xdrive_activate_air_conditioning', + 'last_changed': , + 'last_updated': , + 'state': 'unknown', + }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'M340i xDrive Deactivate air conditioning', + 'icon': 'mdi:hvac-off', + }), + 'context': , + 'entity_id': 'button.m340i_xdrive_deactivate_air_conditioning', + 'last_changed': , + 'last_updated': , + 'state': 'unknown', + }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'M340i xDrive Find vehicle', + 'icon': 'mdi:crosshairs-question', + }), + 'context': , + 'entity_id': 'button.m340i_xdrive_find_vehicle', + 'last_changed': , + 'last_updated': , + 'state': 'unknown', + }), StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by MyBMW', diff --git a/tests/components/bmw_connected_drive/snapshots/test_diagnostics.ambr b/tests/components/bmw_connected_drive/snapshots/test_diagnostics.ambr index 5befe3f0dcf..70224b41ff5 100644 --- a/tests/components/bmw_connected_drive/snapshots/test_diagnostics.ambr +++ b/tests/components/bmw_connected_drive/snapshots/test_diagnostics.ambr @@ -150,7 +150,7 @@ 'UTC', ]), }), - 'activity': 'STANDBY', + 'activity': 'INACTIVE', 'activity_end_time': None, 'activity_end_time_no_tz': None, 'is_climate_on': False, @@ -205,6 +205,888 @@ }), ]), }), + 'data': dict({ + 'appVehicleType': 'DEMO', + 'attributes': dict({ + 'a4aType': 'BLUETOOTH', + 'bodyType': 'I20', + 'brand': 'BMW_I', + 'color': 4285537312, + 'countryOfOrigin': 'DE', + 'driveTrain': 'ELECTRIC', + 'driverGuideInfo': dict({ + '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': dict({ + 'iStep': 300, + 'puStep': dict({ + 'month': 7, + 'year': 21, + }), + 'seriesCluster': 'S21A', + }), + 'softwareVersionExFactory': dict({ + 'iStep': 300, + 'puStep': dict({ + 'month': 7, + 'year': 21, + }), + 'seriesCluster': 'S21A', + }), + 'telematicsUnit': 'WAVE01', + 'year': 2021, + }), + 'capabilities': dict({ + 'a4aType': 'BLUETOOTH', + 'checkSustainabilityDPP': False, + 'climateFunction': 'AIR_CONDITIONING', + 'climateNow': True, + 'digitalKey': dict({ + 'bookedServicePackage': 'SMACC_2_UWB', + 'readerGraphics': 'readerGraphics', + 'state': 'ACTIVATED', + }), + 'horn': True, + 'inCarCamera': True, + 'isBmwChargingSupported': True, + 'isCarSharingSupported': False, + 'isChargeNowForBusinessSupported': True, + 'isChargingHistorySupported': True, + 'isChargingHospitalityEnabled': True, + 'isChargingLoudnessEnabled': True, + 'isChargingPlanSupported': True, + 'isChargingPowerLimitEnabled': True, + 'isChargingSettingsEnabled': True, + 'isChargingTargetSocEnabled': True, + 'isClimateTimerWeeklyActive': False, + 'isCustomerEsimSupported': True, + 'isDCSContractManagementSupported': True, + 'isDataPrivacyEnabled': False, + 'isEasyChargeEnabled': True, + 'isEvGoChargingSupported': False, + 'isMiniChargingSupported': False, + 'isNonLscFeatureEnabled': False, + 'isPersonalPictureUploadSupported': False, + 'isRemoteEngineStartSupported': False, + 'isRemoteHistoryDeletionSupported': False, + 'isRemoteHistorySupported': True, + 'isRemoteParkingSupported': False, + 'isRemoteServicesActivationRequired': False, + 'isRemoteServicesBookingRequired': False, + 'isScanAndChargeSupported': True, + 'isSustainabilityAccumulatedViewEnabled': False, + 'isSustainabilitySupported': False, + 'isWifiHotspotServiceSupported': False, + 'lastStateCallState': 'ACTIVATED', + 'lights': True, + 'lock': True, + 'remote360': True, + 'remoteChargingCommands': dict({ + 'chargingControl': list([ + 'START', + 'STOP', + ]), + 'flapControl': list([ + 'NOT_SUPPORTED', + ]), + 'plugControl': list([ + 'NOT_SUPPORTED', + ]), + }), + 'remoteSoftwareUpgrade': True, + 'sendPoi': True, + 'specialThemeSupport': list([ + ]), + 'speechThirdPartyAlexa': False, + 'speechThirdPartyAlexaSDK': False, + 'surroundViewRecorder': True, + 'unlock': True, + 'vehicleFinder': True, + 'vehicleStateSource': 'LAST_STATE_CALL', + }), + 'charging_settings': dict({ + 'chargeAndClimateSettings': dict({ + 'chargeAndClimateTimer': dict({ + 'chargingMode': 'Sofort laden', + 'chargingModeSemantics': 'Sofort laden', + 'departureTimer': list([ + 'Aus', + ]), + 'departureTimerSemantics': 'Aus', + 'preconditionForDeparture': 'Aus', + 'showDepartureTimers': False, + }), + 'chargingFlap': dict({ + 'permanentlyUnlockLabel': 'Aus', + }), + 'chargingSettings': dict({ + 'acCurrentLimitLabel': '16A', + 'acCurrentLimitLabelSemantics': '16 Ampere', + 'chargingTargetLabel': '80%', + 'dcLoudnessLabel': 'Nicht begrenzt', + 'unlockCableAutomaticallyLabel': 'Aus', + }), + }), + 'chargeAndClimateTimerDetail': dict({ + 'chargingMode': dict({ + 'chargingPreference': 'NO_PRESELECTION', + 'endTimeSlot': '0001-01-01T00:00:00', + 'startTimeSlot': '0001-01-01T00:00:00', + 'type': 'CHARGING_IMMEDIATELY', + }), + 'departureTimer': dict({ + 'type': 'WEEKLY_DEPARTURE_TIMER', + 'weeklyTimers': list([ + dict({ + 'daysOfTheWeek': list([ + ]), + 'id': 1, + 'time': '0001-01-01T00:00:00', + 'timerAction': 'DEACTIVATE', + }), + dict({ + 'daysOfTheWeek': list([ + ]), + 'id': 2, + 'time': '0001-01-01T00:00:00', + 'timerAction': 'DEACTIVATE', + }), + dict({ + 'daysOfTheWeek': list([ + ]), + 'id': 3, + 'time': '0001-01-01T00:00:00', + 'timerAction': 'DEACTIVATE', + }), + dict({ + 'daysOfTheWeek': list([ + ]), + 'id': 4, + 'time': '0001-01-01T00:00:00', + 'timerAction': 'DEACTIVATE', + }), + ]), + }), + 'isPreconditionForDepartureActive': False, + }), + 'chargingFlapDetail': dict({ + 'isPermanentlyUnlock': False, + }), + 'chargingSettingsDetail': dict({ + 'acLimit': dict({ + 'current': dict({ + 'unit': 'A', + 'value': 16, + }), + 'isUnlimited': False, + 'max': 32, + 'min': 6, + 'values': list([ + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 20, + 32, + ]), + }), + 'chargingTarget': 80, + 'dcLoudness': 'UNLIMITED_LOUD', + 'isUnlockCableActive': False, + 'minChargingTargetToWarning': 70, + }), + 'servicePack': 'WAVE_01', + }), + 'fetched_at': '2022-07-10T11:00:00+00:00', + 'is_metric': True, + 'mappingInfo': dict({ + 'isAssociated': False, + 'isLmmEnabled': False, + 'isPrimaryUser': True, + 'lmmStatusReasons': list([ + ]), + 'mappingStatus': 'CONFIRMED', + }), + 'state': dict({ + 'chargingProfile': dict({ + 'chargingControlType': 'WEEKLY_PLANNER', + 'chargingMode': 'IMMEDIATE_CHARGING', + 'chargingPreference': 'NO_PRESELECTION', + 'chargingSettings': dict({ + 'acCurrentLimit': 16, + 'hospitality': 'NO_ACTION', + 'idcc': 'UNLIMITED_LOUD', + 'targetSoc': 80, + }), + 'departureTimes': list([ + dict({ + 'action': 'DEACTIVATE', + 'id': 1, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + dict({ + 'action': 'DEACTIVATE', + 'id': 2, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + dict({ + 'action': 'DEACTIVATE', + 'id': 3, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + dict({ + 'action': 'DEACTIVATE', + 'id': 4, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + ]), + }), + 'checkControlMessages': list([ + dict({ + 'severity': 'LOW', + 'type': 'TIRE_PRESSURE', + }), + ]), + 'climateControlState': dict({ + 'activity': 'INACTIVE', + }), + 'climateTimers': list([ + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': False, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': True, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': True, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + ]), + 'combustionFuelLevel': dict({ + 'remainingFuelPercent': 10, + }), + 'currentMileage': 1121, + 'doorsState': dict({ + 'combinedSecurityState': 'LOCKED', + 'combinedState': 'CLOSED', + 'hood': 'CLOSED', + 'leftFront': 'CLOSED', + 'leftRear': 'CLOSED', + 'rightFront': 'CLOSED', + 'rightRear': 'CLOSED', + 'trunk': 'CLOSED', + }), + 'driverPreferences': dict({ + 'lscPrivacyMode': 'OFF', + }), + 'electricChargingState': dict({ + 'chargingConnectionType': 'UNKNOWN', + 'chargingLevelPercent': 70, + 'chargingStatus': 'CHARGING', + 'chargingTarget': 80, + 'isChargerConnected': True, + 'range': 340, + 'remainingChargingMinutes': 10, + }), + 'isLeftSteering': True, + 'isLscSupported': True, + 'lastFetched': '2023-01-04T14:57:06.371Z', + 'lastUpdatedAt': '2023-01-04T14:57:06.383Z', + 'location': dict({ + 'address': dict({ + 'formatted': '**REDACTED**', + }), + 'coordinates': dict({ + 'latitude': '**REDACTED**', + 'longitude': '**REDACTED**', + }), + 'heading': '**REDACTED**', + }), + 'range': 340, + 'requiredServices': list([ + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'BRAKE_FLUID', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'VEHICLE_TUV', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'VEHICLE_CHECK', + }), + dict({ + 'status': 'OK', + 'type': 'TIRE_WEAR_REAR', + }), + dict({ + 'status': 'OK', + 'type': 'TIRE_WEAR_FRONT', + }), + ]), + 'roofState': dict({ + 'roofState': 'CLOSED', + 'roofStateType': 'SUN_ROOF', + }), + 'tireState': dict({ + 'frontLeft': dict({ + 'details': dict({ + 'dimension': '275/40 R22 107Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-04-20T00:00:00.000Z', + 'partNumber': '5A401A1', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 241, + 'pressureStatus': 0, + 'targetPressure': 241, + 'wearStatus': 0, + }), + }), + 'frontRight': dict({ + 'details': dict({ + 'dimension': '275/40 R22 107Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-04-20T00:00:00.000Z', + 'partNumber': '5A401A1', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 241, + 'pressureStatus': 0, + 'targetPressure': 241, + 'wearStatus': 0, + }), + }), + 'rearLeft': dict({ + 'details': dict({ + 'dimension': '275/40 R22 107Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-04-20T00:00:00.000Z', + 'partNumber': '5A401A1', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 261, + 'pressureStatus': 0, + 'targetPressure': 269, + 'wearStatus': 0, + }), + }), + 'rearRight': dict({ + 'details': dict({ + 'dimension': '275/40 R22 107Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-04-20T00:00:00.000Z', + 'partNumber': '5A401A1', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 269, + 'pressureStatus': 0, + 'targetPressure': 269, + 'wearStatus': 0, + }), + }), + }), + 'windowsState': dict({ + 'combinedState': 'CLOSED', + 'leftFront': 'CLOSED', + 'leftRear': 'CLOSED', + 'rear': 'CLOSED', + 'rightFront': 'CLOSED', + 'rightRear': 'CLOSED', + }), + }), + 'vin': '**REDACTED**', + }), + 'doors_and_windows': dict({ + 'all_lids_closed': True, + 'all_windows_closed': True, + 'door_lock_state': 'LOCKED', + 'lids': list([ + dict({ + 'is_closed': True, + 'name': 'hood', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'leftFront', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'leftRear', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'rightFront', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'rightRear', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'trunk', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'sunRoof', + 'state': 'CLOSED', + }), + ]), + 'open_lids': list([ + ]), + 'open_windows': list([ + ]), + 'windows': list([ + dict({ + 'is_closed': True, + 'name': 'leftFront', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'leftRear', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'rear', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'rightFront', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'rightRear', + 'state': 'CLOSED', + }), + ]), + }), + 'drive_train': 'ELECTRIC', + 'drive_train_attributes': list([ + 'remaining_range_total', + 'mileage', + 'charging_time_remaining', + 'charging_start_time', + 'charging_end_time', + 'charging_time_label', + 'charging_status', + 'connection_status', + 'remaining_battery_percent', + 'remaining_range_electric', + 'last_charging_end_result', + 'ac_current_limit', + 'charging_target', + 'charging_mode', + 'charging_preferences', + 'is_pre_entry_climatization_enabled', + ]), + 'fuel_and_battery': dict({ + 'account_timezone': dict({ + '_dst_offset': '0:00:00', + '_dst_saved': '0:00:00', + '_hasdst': False, + '_std_offset': '0:00:00', + '_tznames': list([ + 'UTC', + 'UTC', + ]), + }), + 'charging_end_time': '2022-07-10T11:10:00+00:00', + 'charging_start_time': None, + 'charging_start_time_no_tz': None, + 'charging_status': 'CHARGING', + 'charging_target': 80, + 'is_charger_connected': True, + 'remaining_battery_percent': 70, + 'remaining_fuel': list([ + None, + None, + ]), + 'remaining_fuel_percent': None, + 'remaining_range_electric': list([ + 340, + 'km', + ]), + 'remaining_range_fuel': list([ + None, + None, + ]), + 'remaining_range_total': list([ + 340, + 'km', + ]), + }), + 'has_combustion_drivetrain': False, + 'has_electric_drivetrain': True, + 'is_charging_plan_supported': True, + 'is_lsc_enabled': True, + 'is_remote_charge_start_enabled': True, + 'is_remote_charge_stop_enabled': True, + 'is_remote_climate_start_enabled': True, + 'is_remote_climate_stop_enabled': True, + 'is_remote_horn_enabled': True, + 'is_remote_lights_enabled': True, + 'is_remote_lock_enabled': True, + 'is_remote_sendpoi_enabled': True, + 'is_remote_set_ac_limit_enabled': True, + 'is_remote_set_target_soc_enabled': True, + 'is_remote_unlock_enabled': True, + 'is_vehicle_active': False, + 'is_vehicle_tracking_enabled': True, + 'lsc_type': 'ACTIVATED', + 'mileage': list([ + 1121, + 'km', + ]), + 'name': 'iX xDrive50', + 'timestamp': '2023-01-04T14:57:06+00:00', + 'tires': dict({ + 'front_left': dict({ + 'current_pressure': 241, + 'manufacturing_week': '2021-10-04T00:00:00', + 'season': 2, + 'target_pressure': 241, + }), + 'front_right': dict({ + 'current_pressure': 241, + 'manufacturing_week': '2021-10-04T00:00:00', + 'season': 2, + 'target_pressure': 241, + }), + 'rear_left': dict({ + 'current_pressure': 261, + 'manufacturing_week': '2021-10-04T00:00:00', + 'season': 2, + 'target_pressure': 269, + }), + 'rear_right': dict({ + 'current_pressure': 269, + 'manufacturing_week': '2021-10-04T00:00:00', + 'season': 2, + 'target_pressure': 269, + }), + }), + 'vehicle_location': dict({ + 'account_region': 'row', + 'heading': '**REDACTED**', + 'location': dict({ + 'latitude': '**REDACTED**', + 'longitude': '**REDACTED**', + }), + 'remote_service_position': None, + 'vehicle_update_timestamp': '2023-01-04T14:57:06+00:00', + }), + 'vin': '**REDACTED**', + }), + dict({ + 'available_attributes': list([ + 'gps_position', + 'vin', + 'remaining_range_total', + 'mileage', + 'charging_time_remaining', + 'charging_start_time', + 'charging_end_time', + 'charging_time_label', + 'charging_status', + 'connection_status', + 'remaining_battery_percent', + 'remaining_range_electric', + 'last_charging_end_result', + 'ac_current_limit', + 'charging_target', + 'charging_mode', + 'charging_preferences', + 'is_pre_entry_climatization_enabled', + 'condition_based_services', + 'check_control_messages', + 'door_lock_state', + 'timestamp', + 'lids', + 'windows', + ]), + 'brand': 'bmw', + 'charging_profile': dict({ + 'ac_available_limits': list([ + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 20, + 32, + ]), + 'ac_current_limit': 16, + 'charging_mode': 'IMMEDIATE_CHARGING', + 'charging_preferences': 'NO_PRESELECTION', + 'charging_preferences_service_pack': 'WAVE_01', + 'departure_times': list([ + dict({ + '_timer_dict': dict({ + 'action': 'DEACTIVATE', + 'id': 1, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + 'action': 'DEACTIVATE', + 'start_time': '00:00:00', + 'timer_id': 1, + 'weekdays': list([ + ]), + }), + dict({ + '_timer_dict': dict({ + 'action': 'DEACTIVATE', + 'id': 2, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + 'action': 'DEACTIVATE', + 'start_time': '00:00:00', + 'timer_id': 2, + 'weekdays': list([ + ]), + }), + dict({ + '_timer_dict': dict({ + 'action': 'DEACTIVATE', + 'id': 3, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + 'action': 'DEACTIVATE', + 'start_time': '00:00:00', + 'timer_id': 3, + 'weekdays': list([ + ]), + }), + dict({ + '_timer_dict': dict({ + 'action': 'DEACTIVATE', + 'id': 4, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + 'action': 'DEACTIVATE', + 'start_time': '00:00:00', + 'timer_id': 4, + 'weekdays': list([ + ]), + }), + ]), + 'is_pre_entry_climatization_enabled': False, + 'preferred_charging_window': dict({ + '_window_dict': dict({ + }), + 'end_time': '00:00:00', + 'start_time': '00:00:00', + }), + 'timer_type': 'WEEKLY_PLANNER', + }), + 'check_control_messages': dict({ + 'has_check_control_messages': False, + 'messages': list([ + dict({ + 'description_long': None, + 'description_short': 'TIRE_PRESSURE', + 'state': 'LOW', + }), + ]), + }), + 'climate': dict({ + 'account_timezone': dict({ + '_dst_offset': '0:00:00', + '_dst_saved': '0:00:00', + '_hasdst': False, + '_std_offset': '0:00:00', + '_tznames': list([ + 'UTC', + 'UTC', + ]), + }), + 'activity': 'HEATING', + 'activity_end_time': '2022-07-10T11:29:50+00:00', + 'activity_end_time_no_tz': '2022-07-10T11:29:50', + 'is_climate_on': True, + }), + 'condition_based_services': dict({ + 'is_service_required': False, + 'messages': list([ + dict({ + 'due_date': '2024-12-01T00:00:00+00:00', + 'due_distance': list([ + 50000, + 'km', + ]), + 'service_type': 'BRAKE_FLUID', + 'state': 'OK', + }), + dict({ + 'due_date': '2024-12-01T00:00:00+00:00', + 'due_distance': list([ + 50000, + 'km', + ]), + 'service_type': 'VEHICLE_TUV', + 'state': 'OK', + }), + dict({ + 'due_date': '2024-12-01T00:00:00+00:00', + 'due_distance': list([ + 50000, + 'km', + ]), + 'service_type': 'VEHICLE_CHECK', + 'state': 'OK', + }), + dict({ + 'due_date': None, + 'due_distance': list([ + None, + None, + ]), + 'service_type': 'TIRE_WEAR_REAR', + 'state': 'OK', + }), + dict({ + 'due_date': None, + 'due_distance': list([ + None, + None, + ]), + 'service_type': 'TIRE_WEAR_FRONT', + 'state': 'OK', + }), + ]), + }), 'data': dict({ 'appVehicleType': 'DEMO', 'attributes': dict({ @@ -289,16 +1171,6 @@ 'lock': True, 'remote360': True, 'remoteChargingCommands': dict({ - 'chargingControl': list([ - 'START', - 'STOP', - ]), - 'flapControl': list([ - 'NOT_SUPPORTED', - ]), - 'plugControl': list([ - 'NOT_SUPPORTED', - ]), }), 'remoteSoftwareUpgrade': True, 'sendPoi': True, @@ -481,7 +1353,8 @@ }), ]), 'climateControlState': dict({ - 'activity': 'STANDBY', + 'activity': 'HEATING', + 'remainingSeconds': 1790.846, }), 'climateTimers': list([ dict({ @@ -534,9 +1407,9 @@ 'electricChargingState': dict({ 'chargingConnectionType': 'UNKNOWN', 'chargingLevelPercent': 80, - 'chargingStatus': 'CHARGING', + 'chargingStatus': 'INVALID', 'chargingTarget': 80, - 'isChargerConnected': True, + 'isChargerConnected': False, 'range': 472, 'remainingChargingMinutes': 10, }), @@ -788,9 +1661,9 @@ 'charging_end_time': '2022-07-10T11:10:00+00:00', 'charging_start_time': None, 'charging_start_time_no_tz': None, - 'charging_status': 'CHARGING', + 'charging_status': 'NOT_CHARGING', 'charging_target': 80, - 'is_charger_connected': True, + 'is_charger_connected': False, 'remaining_battery_percent': 80, 'remaining_fuel': list([ None, @@ -814,8 +1687,8 @@ 'has_electric_drivetrain': True, 'is_charging_plan_supported': True, 'is_lsc_enabled': True, - 'is_remote_charge_start_enabled': True, - 'is_remote_charge_stop_enabled': True, + 'is_remote_charge_start_enabled': False, + 'is_remote_charge_stop_enabled': False, 'is_remote_climate_start_enabled': True, 'is_remote_climate_stop_enabled': True, 'is_remote_horn_enabled': True, @@ -872,6 +1745,639 @@ }), 'vin': '**REDACTED**', }), + dict({ + 'available_attributes': list([ + 'gps_position', + 'vin', + 'remaining_range_total', + 'mileage', + 'remaining_fuel', + 'remaining_range_fuel', + 'remaining_fuel_percent', + 'condition_based_services', + 'check_control_messages', + 'door_lock_state', + 'timestamp', + 'lids', + 'windows', + ]), + 'brand': 'bmw', + 'charging_profile': dict({ + 'ac_available_limits': None, + 'ac_current_limit': None, + 'charging_mode': 'IMMEDIATE_CHARGING', + 'charging_preferences': 'NO_PRESELECTION', + 'charging_preferences_service_pack': None, + 'departure_times': list([ + ]), + 'is_pre_entry_climatization_enabled': False, + 'preferred_charging_window': dict({ + '_window_dict': dict({ + }), + 'end_time': '00:00:00', + 'start_time': '00:00:00', + }), + 'timer_type': 'UNKNOWN', + }), + 'check_control_messages': dict({ + 'has_check_control_messages': False, + 'messages': list([ + dict({ + 'description_long': None, + 'description_short': 'TIRE_PRESSURE', + 'state': 'LOW', + }), + dict({ + 'description_long': None, + 'description_short': 'ENGINE_OIL', + 'state': 'LOW', + }), + ]), + }), + 'climate': dict({ + 'account_timezone': dict({ + '_dst_offset': '0:00:00', + '_dst_saved': '0:00:00', + '_hasdst': False, + '_std_offset': '0:00:00', + '_tznames': list([ + 'UTC', + 'UTC', + ]), + }), + 'activity': 'INACTIVE', + 'activity_end_time': None, + 'activity_end_time_no_tz': None, + 'is_climate_on': False, + }), + 'condition_based_services': dict({ + 'is_service_required': False, + 'messages': list([ + dict({ + 'due_date': '2024-12-01T00:00:00+00:00', + 'due_distance': list([ + 50000, + 'km', + ]), + 'service_type': 'OIL', + 'state': 'OK', + }), + dict({ + 'due_date': '2024-12-01T00:00:00+00:00', + 'due_distance': list([ + 50000, + 'km', + ]), + 'service_type': 'BRAKE_FLUID', + 'state': 'OK', + }), + dict({ + 'due_date': '2024-12-01T00:00:00+00:00', + 'due_distance': list([ + 50000, + 'km', + ]), + 'service_type': 'VEHICLE_TUV', + 'state': 'OK', + }), + dict({ + 'due_date': '2024-12-01T00:00:00+00:00', + 'due_distance': list([ + 50000, + 'km', + ]), + 'service_type': 'VEHICLE_CHECK', + 'state': 'OK', + }), + dict({ + 'due_date': None, + 'due_distance': list([ + None, + None, + ]), + 'service_type': 'TIRE_WEAR_REAR', + 'state': 'OK', + }), + dict({ + 'due_date': None, + 'due_distance': list([ + None, + None, + ]), + 'service_type': 'TIRE_WEAR_FRONT', + 'state': 'OK', + }), + ]), + }), + 'data': dict({ + 'appVehicleType': 'DEMO', + 'attributes': dict({ + 'a4aType': 'NOT_SUPPORTED', + 'bodyType': 'G20', + 'brand': 'BMW', + 'color': 4280233344, + 'countryOfOrigin': 'PT', + 'driveTrain': 'COMBUSTION', + 'driverGuideInfo': dict({ + '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': dict({ + 'iStep': 470, + 'puStep': dict({ + 'month': 7, + 'year': 21, + }), + 'seriesCluster': 'S18A', + }), + 'softwareVersionExFactory': dict({ + 'iStep': 420, + 'puStep': dict({ + 'month': 7, + 'year': 20, + }), + 'seriesCluster': 'S18A', + }), + 'telematicsUnit': 'ATM2', + 'year': 2022, + }), + 'capabilities': dict({ + 'a4aType': 'NOT_SUPPORTED', + 'checkSustainabilityDPP': False, + 'climateFunction': 'VENTILATION', + 'climateNow': True, + 'climateTimerTrigger': 'DEPARTURE_TIMER', + 'digitalKey': dict({ + 'bookedServicePackage': 'SMACC_1_5', + 'readerGraphics': 'readerGraphics', + 'state': 'ACTIVATED', + }), + 'horn': True, + 'isBmwChargingSupported': False, + 'isCarSharingSupported': False, + 'isChargeNowForBusinessSupported': False, + 'isChargingHistorySupported': False, + 'isChargingHospitalityEnabled': False, + 'isChargingLoudnessEnabled': False, + 'isChargingPlanSupported': False, + 'isChargingPowerLimitEnabled': False, + 'isChargingSettingsEnabled': False, + 'isChargingTargetSocEnabled': False, + 'isClimateTimerSupported': True, + 'isClimateTimerWeeklyActive': False, + 'isCustomerEsimSupported': False, + 'isDCSContractManagementSupported': False, + 'isDataPrivacyEnabled': False, + 'isEasyChargeEnabled': False, + 'isEvGoChargingSupported': False, + 'isMiniChargingSupported': False, + 'isNonLscFeatureEnabled': False, + 'isPersonalPictureUploadSupported': False, + 'isRemoteEngineStartSupported': False, + 'isRemoteHistoryDeletionSupported': False, + 'isRemoteHistorySupported': True, + 'isRemoteParkingSupported': False, + 'isRemoteServicesActivationRequired': False, + 'isRemoteServicesBookingRequired': False, + 'isScanAndChargeSupported': False, + 'isSustainabilityAccumulatedViewEnabled': False, + 'isSustainabilitySupported': False, + 'isWifiHotspotServiceSupported': True, + 'lastStateCallState': 'ACTIVATED', + 'lights': True, + 'lock': True, + 'remote360': True, + 'remoteChargingCommands': dict({ + }), + 'remoteSoftwareUpgrade': True, + 'sendPoi': True, + 'specialThemeSupport': list([ + ]), + 'speechThirdPartyAlexa': False, + 'speechThirdPartyAlexaSDK': False, + 'unlock': True, + 'vehicleFinder': True, + 'vehicleStateSource': 'LAST_STATE_CALL', + }), + 'charging_settings': dict({ + }), + 'fetched_at': '2022-07-10T11:00:00+00:00', + 'is_metric': True, + 'mappingInfo': dict({ + 'isAssociated': False, + 'isLmmEnabled': False, + 'isPrimaryUser': True, + 'lmmStatusReasons': list([ + ]), + 'mappingStatus': 'CONFIRMED', + }), + 'state': dict({ + 'chargingProfile': dict({ + 'chargingMode': 'IMMEDIATE_CHARGING', + 'chargingPreference': 'NO_PRESELECTION', + 'chargingSettings': dict({ + 'hospitality': 'NO_ACTION', + 'idcc': 'NO_ACTION', + 'targetSoc': 0, + }), + 'departureTimes': list([ + ]), + }), + 'checkControlMessages': list([ + dict({ + 'severity': 'LOW', + 'type': 'TIRE_PRESSURE', + }), + dict({ + 'severity': 'LOW', + 'type': 'ENGINE_OIL', + }), + ]), + 'climateControlState': dict({ + 'activity': 'INACTIVE', + }), + 'climateTimers': list([ + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': False, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': True, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': True, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + ]), + 'combustionFuelLevel': dict({ + 'range': 629, + 'remainingFuelLiters': 40, + 'remainingFuelPercent': 80, + }), + 'currentMileage': 1121, + 'doorsState': dict({ + 'combinedSecurityState': 'LOCKED', + 'combinedState': 'CLOSED', + 'hood': 'CLOSED', + 'leftFront': 'CLOSED', + 'leftRear': 'CLOSED', + 'rightFront': 'CLOSED', + 'rightRear': 'CLOSED', + 'trunk': 'CLOSED', + }), + 'driverPreferences': dict({ + 'lscPrivacyMode': 'OFF', + }), + 'isLeftSteering': True, + 'isLscSupported': True, + 'lastFetched': '2023-01-04T14:57:06.336Z', + 'lastUpdatedAt': '2023-01-04T14:57:06.348Z', + 'location': dict({ + 'address': dict({ + 'formatted': '**REDACTED**', + }), + 'coordinates': dict({ + 'latitude': '**REDACTED**', + 'longitude': '**REDACTED**', + }), + 'heading': '**REDACTED**', + }), + 'range': 629, + 'requiredServices': list([ + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'OIL', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'BRAKE_FLUID', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'VEHICLE_TUV', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'VEHICLE_CHECK', + }), + dict({ + 'status': 'OK', + 'type': 'TIRE_WEAR_REAR', + }), + dict({ + 'status': 'OK', + 'type': 'TIRE_WEAR_FRONT', + }), + ]), + 'tireState': dict({ + 'frontLeft': dict({ + 'details': dict({ + 'dimension': '225/35 R20 90Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-03-07T00:00:00.000Z', + 'partNumber': '2461756', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 241, + 'pressureStatus': 0, + 'wearStatus': 0, + }), + }), + 'frontRight': dict({ + 'details': dict({ + 'dimension': '225/35 R20 90Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 2419, + 'mountingDate': '2022-03-07T00:00:00.000Z', + 'partNumber': '2461756', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 255, + 'pressureStatus': 0, + 'wearStatus': 0, + }), + }), + 'rearLeft': dict({ + 'details': dict({ + 'dimension': '255/30 R20 92Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 1219, + 'mountingDate': '2022-03-07T00:00:00.000Z', + 'partNumber': '2461757', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 324, + 'pressureStatus': 0, + 'wearStatus': 0, + }), + }), + 'rearRight': dict({ + 'details': dict({ + 'dimension': '255/30 R20 92Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 1219, + 'mountingDate': '2022-03-07T00:00:00.000Z', + 'partNumber': '2461757', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 331, + 'pressureStatus': 0, + 'wearStatus': 0, + }), + }), + }), + 'windowsState': dict({ + 'combinedState': 'CLOSED', + 'leftFront': 'CLOSED', + 'leftRear': 'CLOSED', + 'rear': 'CLOSED', + 'rightFront': 'CLOSED', + 'rightRear': 'CLOSED', + }), + }), + 'vin': '**REDACTED**', + }), + 'doors_and_windows': dict({ + 'all_lids_closed': True, + 'all_windows_closed': True, + 'door_lock_state': 'LOCKED', + 'lids': list([ + dict({ + 'is_closed': True, + 'name': 'hood', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'leftFront', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'leftRear', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'rightFront', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'rightRear', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'trunk', + 'state': 'CLOSED', + }), + ]), + 'open_lids': list([ + ]), + 'open_windows': list([ + ]), + 'windows': list([ + dict({ + 'is_closed': True, + 'name': 'leftFront', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'leftRear', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'rear', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'rightFront', + 'state': 'CLOSED', + }), + dict({ + 'is_closed': True, + 'name': 'rightRear', + 'state': 'CLOSED', + }), + ]), + }), + 'drive_train': 'COMBUSTION', + 'drive_train_attributes': list([ + 'remaining_range_total', + 'mileage', + 'remaining_fuel', + 'remaining_range_fuel', + 'remaining_fuel_percent', + ]), + 'fuel_and_battery': dict({ + 'account_timezone': dict({ + '_dst_offset': '0:00:00', + '_dst_saved': '0:00:00', + '_hasdst': False, + '_std_offset': '0:00:00', + '_tznames': list([ + 'UTC', + 'UTC', + ]), + }), + 'charging_end_time': None, + 'charging_start_time': None, + 'charging_start_time_no_tz': None, + 'charging_status': None, + 'charging_target': None, + 'is_charger_connected': False, + 'remaining_battery_percent': None, + 'remaining_fuel': list([ + 40, + 'L', + ]), + 'remaining_fuel_percent': 80, + 'remaining_range_electric': list([ + None, + None, + ]), + 'remaining_range_fuel': list([ + 629, + 'km', + ]), + 'remaining_range_total': list([ + 629, + 'km', + ]), + }), + 'has_combustion_drivetrain': True, + 'has_electric_drivetrain': False, + 'is_charging_plan_supported': False, + 'is_lsc_enabled': True, + 'is_remote_charge_start_enabled': False, + 'is_remote_charge_stop_enabled': False, + 'is_remote_climate_start_enabled': True, + 'is_remote_climate_stop_enabled': True, + 'is_remote_horn_enabled': True, + 'is_remote_lights_enabled': True, + 'is_remote_lock_enabled': True, + 'is_remote_sendpoi_enabled': True, + 'is_remote_set_ac_limit_enabled': False, + 'is_remote_set_target_soc_enabled': False, + 'is_remote_unlock_enabled': True, + 'is_vehicle_active': False, + 'is_vehicle_tracking_enabled': True, + 'lsc_type': 'ACTIVATED', + 'mileage': list([ + 1121, + 'km', + ]), + 'name': 'M340i xDrive', + 'timestamp': '2023-01-04T14:57:06+00:00', + 'tires': dict({ + 'front_left': dict({ + 'current_pressure': 241, + 'manufacturing_week': '2021-10-04T00:00:00', + 'season': 2, + 'target_pressure': None, + }), + 'front_right': dict({ + 'current_pressure': 255, + 'manufacturing_week': '2019-06-10T00:00:00', + 'season': 2, + 'target_pressure': None, + }), + 'rear_left': dict({ + 'current_pressure': 324, + 'manufacturing_week': '2019-03-18T00:00:00', + 'season': 2, + 'target_pressure': None, + }), + 'rear_right': dict({ + 'current_pressure': 331, + 'manufacturing_week': '2019-03-18T00:00:00', + 'season': 2, + 'target_pressure': None, + }), + }), + 'vehicle_location': dict({ + 'account_region': 'row', + 'heading': '**REDACTED**', + 'location': dict({ + 'latitude': '**REDACTED**', + 'longitude': '**REDACTED**', + }), + 'remote_service_position': None, + 'vehicle_update_timestamp': '2023-01-04T14:57:06+00:00', + }), + 'vin': '**REDACTED**', + }), dict({ 'available_attributes': list([ 'gps_position', @@ -1086,7 +2592,7 @@ }), 'headUnitType': 'NBT', 'hmiVersion': 'ID4', - 'lastFetched': '2022-07-10T09:25:53.104Z', + 'lastFetched': '2022-06-01T19:48:46.540Z', 'model': 'i3 (+ REX)', 'softwareVersionCurrent': dict({ 'iStep': 510, @@ -1215,8 +2721,6 @@ 'fetched_at': '2022-07-10T11:00:00+00:00', 'is_metric': True, 'mappingInfo': dict({ - 'isAssociated': False, - 'isLmmEnabled': False, 'isPrimaryUser': True, 'mappingStatus': 'CONFIRMED', }), @@ -1333,7 +2837,6 @@ 'combustionFuelLevel': dict({ 'range': 105, 'remainingFuelLiters': 6, - 'remainingFuelPercent': 65, }), 'currentMileage': 137009, 'doorsState': dict({ @@ -1496,7 +2999,7 @@ 6, 'L', ]), - 'remaining_fuel_percent': 65, + 'remaining_fuel_percent': None, 'remaining_range_electric': list([ 174, 'km', @@ -1533,14 +3036,14 @@ 'km', ]), 'name': 'i3 (+ REX)', - 'timestamp': '2022-07-10T09:25:53+00:00', + 'timestamp': '2022-06-22T14:24:23+00:00', 'tires': None, 'vehicle_location': dict({ 'account_region': 'row', 'heading': None, 'location': None, 'remote_service_position': None, - 'vehicle_update_timestamp': '2022-07-10T09:25:53+00:00', + 'vehicle_update_timestamp': '2022-06-22T14:24:23+00:00', }), 'vin': '**REDACTED**', }), @@ -1548,6 +3051,55 @@ 'fingerprint': list([ dict({ 'content': list([ + dict({ + 'appVehicleType': 'DEMO', + 'attributes': dict({ + 'a4aType': 'BLUETOOTH', + 'bodyType': 'I20', + 'brand': 'BMW_I', + 'color': 4285537312, + 'countryOfOrigin': 'DE', + 'driveTrain': 'ELECTRIC', + 'driverGuideInfo': dict({ + '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': dict({ + 'iStep': 300, + 'puStep': dict({ + 'month': 7, + 'year': 21, + }), + 'seriesCluster': 'S21A', + }), + 'softwareVersionExFactory': dict({ + 'iStep': 300, + 'puStep': dict({ + 'month': 7, + 'year': 21, + }), + 'seriesCluster': 'S21A', + }), + 'telematicsUnit': 'WAVE01', + 'year': 2021, + }), + 'mappingInfo': dict({ + 'isAssociated': False, + 'isLmmEnabled': False, + 'isPrimaryUser': True, + 'lmmStatusReasons': list([ + ]), + 'mappingStatus': 'CONFIRMED', + }), + 'vin': '**REDACTED**', + }), dict({ 'appVehicleType': 'DEMO', 'attributes': dict({ @@ -1597,6 +3149,55 @@ }), 'vin': '**REDACTED**', }), + dict({ + 'appVehicleType': 'DEMO', + 'attributes': dict({ + 'a4aType': 'NOT_SUPPORTED', + 'bodyType': 'G20', + 'brand': 'BMW', + 'color': 4280233344, + 'countryOfOrigin': 'PT', + 'driveTrain': 'COMBUSTION', + 'driverGuideInfo': dict({ + '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': dict({ + 'iStep': 470, + 'puStep': dict({ + 'month': 7, + 'year': 21, + }), + 'seriesCluster': 'S18A', + }), + 'softwareVersionExFactory': dict({ + 'iStep': 420, + 'puStep': dict({ + 'month': 7, + 'year': 20, + }), + 'seriesCluster': 'S18A', + }), + 'telematicsUnit': 'ATM2', + 'year': 2022, + }), + 'mappingInfo': dict({ + 'isAssociated': False, + 'isLmmEnabled': False, + 'isPrimaryUser': True, + 'lmmStatusReasons': list([ + ]), + 'mappingStatus': 'CONFIRMED', + }), + 'vin': '**REDACTED**', + }), dict({ 'appVehicleType': 'CONNECTED', 'attributes': dict({ @@ -1614,7 +3215,7 @@ }), 'headUnitType': 'NBT', 'hmiVersion': 'ID4', - 'lastFetched': '2022-07-10T09:25:53.104Z', + 'lastFetched': '2022-06-01T19:48:46.540Z', 'model': 'i3 (+ REX)', 'softwareVersionCurrent': dict({ 'iStep': 510, @@ -1635,8 +3236,6 @@ 'year': 2015, }), 'mappingInfo': dict({ - 'isAssociated': False, - 'isLmmEnabled': False, 'isPrimaryUser': True, 'mappingStatus': 'CONFIRMED', }), @@ -1650,6 +3249,452 @@ ]), 'filename': 'mini-eadrax-vcs_v4_vehicles.json', }), + dict({ + 'content': dict({ + 'capabilities': dict({ + 'a4aType': 'BLUETOOTH', + 'checkSustainabilityDPP': False, + 'climateFunction': 'AIR_CONDITIONING', + 'climateNow': True, + 'digitalKey': dict({ + 'bookedServicePackage': 'SMACC_2_UWB', + 'readerGraphics': 'readerGraphics', + 'state': 'ACTIVATED', + }), + 'horn': True, + 'inCarCamera': True, + 'isBmwChargingSupported': True, + 'isCarSharingSupported': False, + 'isChargeNowForBusinessSupported': True, + 'isChargingHistorySupported': True, + 'isChargingHospitalityEnabled': True, + 'isChargingLoudnessEnabled': True, + 'isChargingPlanSupported': True, + 'isChargingPowerLimitEnabled': True, + 'isChargingSettingsEnabled': True, + 'isChargingTargetSocEnabled': True, + 'isClimateTimerWeeklyActive': False, + 'isCustomerEsimSupported': True, + 'isDCSContractManagementSupported': True, + 'isDataPrivacyEnabled': False, + 'isEasyChargeEnabled': True, + 'isEvGoChargingSupported': False, + 'isMiniChargingSupported': False, + 'isNonLscFeatureEnabled': False, + 'isPersonalPictureUploadSupported': False, + 'isRemoteEngineStartSupported': False, + 'isRemoteHistoryDeletionSupported': False, + 'isRemoteHistorySupported': True, + 'isRemoteParkingSupported': False, + 'isRemoteServicesActivationRequired': False, + 'isRemoteServicesBookingRequired': False, + 'isScanAndChargeSupported': True, + 'isSustainabilityAccumulatedViewEnabled': False, + 'isSustainabilitySupported': False, + 'isWifiHotspotServiceSupported': False, + 'lastStateCallState': 'ACTIVATED', + 'lights': True, + 'lock': True, + 'remote360': True, + 'remoteChargingCommands': dict({ + 'chargingControl': list([ + 'START', + 'STOP', + ]), + 'flapControl': list([ + 'NOT_SUPPORTED', + ]), + 'plugControl': list([ + 'NOT_SUPPORTED', + ]), + }), + 'remoteSoftwareUpgrade': True, + 'sendPoi': True, + 'specialThemeSupport': list([ + ]), + 'speechThirdPartyAlexa': False, + 'speechThirdPartyAlexaSDK': False, + 'surroundViewRecorder': True, + 'unlock': True, + 'vehicleFinder': True, + 'vehicleStateSource': 'LAST_STATE_CALL', + }), + 'state': dict({ + 'chargingProfile': dict({ + 'chargingControlType': 'WEEKLY_PLANNER', + 'chargingMode': 'IMMEDIATE_CHARGING', + 'chargingPreference': 'NO_PRESELECTION', + 'chargingSettings': dict({ + 'acCurrentLimit': 16, + 'hospitality': 'NO_ACTION', + 'idcc': 'UNLIMITED_LOUD', + 'targetSoc': 80, + }), + 'departureTimes': list([ + dict({ + 'action': 'DEACTIVATE', + 'id': 1, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + dict({ + 'action': 'DEACTIVATE', + 'id': 2, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + dict({ + 'action': 'DEACTIVATE', + 'id': 3, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + dict({ + 'action': 'DEACTIVATE', + 'id': 4, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + ]), + }), + 'checkControlMessages': list([ + dict({ + 'severity': 'LOW', + 'type': 'TIRE_PRESSURE', + }), + ]), + 'climateControlState': dict({ + 'activity': 'INACTIVE', + }), + 'climateTimers': list([ + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': False, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': True, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': True, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + ]), + 'combustionFuelLevel': dict({ + 'remainingFuelPercent': 10, + }), + 'currentMileage': 1121, + 'doorsState': dict({ + 'combinedSecurityState': 'LOCKED', + 'combinedState': 'CLOSED', + 'hood': 'CLOSED', + 'leftFront': 'CLOSED', + 'leftRear': 'CLOSED', + 'rightFront': 'CLOSED', + 'rightRear': 'CLOSED', + 'trunk': 'CLOSED', + }), + 'driverPreferences': dict({ + 'lscPrivacyMode': 'OFF', + }), + 'electricChargingState': dict({ + 'chargingConnectionType': 'UNKNOWN', + 'chargingLevelPercent': 70, + 'chargingStatus': 'CHARGING', + 'chargingTarget': 80, + 'isChargerConnected': True, + 'range': 340, + 'remainingChargingMinutes': 10, + }), + 'isLeftSteering': True, + 'isLscSupported': True, + 'lastFetched': '2023-01-04T14:57:06.371Z', + 'lastUpdatedAt': '2023-01-04T14:57:06.383Z', + 'location': dict({ + 'address': dict({ + 'formatted': '**REDACTED**', + }), + 'coordinates': dict({ + 'latitude': '**REDACTED**', + 'longitude': '**REDACTED**', + }), + 'heading': '**REDACTED**', + }), + 'range': 340, + 'requiredServices': list([ + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'BRAKE_FLUID', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'VEHICLE_TUV', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'VEHICLE_CHECK', + }), + dict({ + 'status': 'OK', + 'type': 'TIRE_WEAR_REAR', + }), + dict({ + 'status': 'OK', + 'type': 'TIRE_WEAR_FRONT', + }), + ]), + 'roofState': dict({ + 'roofState': 'CLOSED', + 'roofStateType': 'SUN_ROOF', + }), + 'tireState': dict({ + 'frontLeft': dict({ + 'details': dict({ + 'dimension': '275/40 R22 107Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-04-20T00:00:00.000Z', + 'partNumber': '5A401A1', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 241, + 'pressureStatus': 0, + 'targetPressure': 241, + 'wearStatus': 0, + }), + }), + 'frontRight': dict({ + 'details': dict({ + 'dimension': '275/40 R22 107Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-04-20T00:00:00.000Z', + 'partNumber': '5A401A1', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 241, + 'pressureStatus': 0, + 'targetPressure': 241, + 'wearStatus': 0, + }), + }), + 'rearLeft': dict({ + 'details': dict({ + 'dimension': '275/40 R22 107Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-04-20T00:00:00.000Z', + 'partNumber': '5A401A1', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 261, + 'pressureStatus': 0, + 'targetPressure': 269, + 'wearStatus': 0, + }), + }), + 'rearRight': dict({ + 'details': dict({ + 'dimension': '275/40 R22 107Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-04-20T00:00:00.000Z', + 'partNumber': '5A401A1', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 269, + 'pressureStatus': 0, + 'targetPressure': 269, + 'wearStatus': 0, + }), + }), + }), + 'windowsState': dict({ + 'combinedState': 'CLOSED', + 'leftFront': 'CLOSED', + 'leftRear': 'CLOSED', + 'rear': 'CLOSED', + 'rightFront': 'CLOSED', + 'rightRear': 'CLOSED', + }), + }), + }), + 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBA0FINGERPRINT01.json', + }), + dict({ + 'content': dict({ + 'chargeAndClimateSettings': dict({ + 'chargeAndClimateTimer': dict({ + 'chargingMode': 'Sofort laden', + 'chargingModeSemantics': 'Sofort laden', + 'departureTimer': list([ + 'Aus', + ]), + 'departureTimerSemantics': 'Aus', + 'preconditionForDeparture': 'Aus', + 'showDepartureTimers': False, + }), + 'chargingFlap': dict({ + 'permanentlyUnlockLabel': 'Aus', + }), + 'chargingSettings': dict({ + 'acCurrentLimitLabel': '16A', + 'acCurrentLimitLabelSemantics': '16 Ampere', + 'chargingTargetLabel': '80%', + 'dcLoudnessLabel': 'Nicht begrenzt', + 'unlockCableAutomaticallyLabel': 'Aus', + }), + }), + 'chargeAndClimateTimerDetail': dict({ + 'chargingMode': dict({ + 'chargingPreference': 'NO_PRESELECTION', + 'endTimeSlot': '0001-01-01T00:00:00', + 'startTimeSlot': '0001-01-01T00:00:00', + 'type': 'CHARGING_IMMEDIATELY', + }), + 'departureTimer': dict({ + 'type': 'WEEKLY_DEPARTURE_TIMER', + 'weeklyTimers': list([ + dict({ + 'daysOfTheWeek': list([ + ]), + 'id': 1, + 'time': '0001-01-01T00:00:00', + 'timerAction': 'DEACTIVATE', + }), + dict({ + 'daysOfTheWeek': list([ + ]), + 'id': 2, + 'time': '0001-01-01T00:00:00', + 'timerAction': 'DEACTIVATE', + }), + dict({ + 'daysOfTheWeek': list([ + ]), + 'id': 3, + 'time': '0001-01-01T00:00:00', + 'timerAction': 'DEACTIVATE', + }), + dict({ + 'daysOfTheWeek': list([ + ]), + 'id': 4, + 'time': '0001-01-01T00:00:00', + 'timerAction': 'DEACTIVATE', + }), + ]), + }), + 'isPreconditionForDepartureActive': False, + }), + 'chargingFlapDetail': dict({ + 'isPermanentlyUnlock': False, + }), + 'chargingSettingsDetail': dict({ + 'acLimit': dict({ + 'current': dict({ + 'unit': 'A', + 'value': 16, + }), + 'isUnlimited': False, + 'max': 32, + 'min': 6, + 'values': list([ + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 20, + 32, + ]), + }), + 'chargingTarget': 80, + 'dcLoudness': 'UNLIMITED_LOUD', + 'isUnlockCableActive': False, + 'minChargingTargetToWarning': 70, + }), + 'servicePack': 'WAVE_01', + }), + 'filename': 'bmw-eadrax-crccs_v2_vehicles_WBA0FINGERPRINT01.json', + }), dict({ 'content': dict({ 'capabilities': dict({ @@ -1697,16 +3742,6 @@ 'lock': True, 'remote360': True, 'remoteChargingCommands': dict({ - 'chargingControl': list([ - 'START', - 'STOP', - ]), - 'flapControl': list([ - 'NOT_SUPPORTED', - ]), - 'plugControl': list([ - 'NOT_SUPPORTED', - ]), }), 'remoteSoftwareUpgrade': True, 'sendPoi': True, @@ -1779,7 +3814,8 @@ }), ]), 'climateControlState': dict({ - 'activity': 'STANDBY', + 'activity': 'HEATING', + 'remainingSeconds': 1790.846, }), 'climateTimers': list([ dict({ @@ -1832,9 +3868,9 @@ 'electricChargingState': dict({ 'chargingConnectionType': 'UNKNOWN', 'chargingLevelPercent': 80, - 'chargingStatus': 'CHARGING', + 'chargingStatus': 'INVALID', 'chargingTarget': 80, - 'isChargerConnected': True, + 'isChargerConnected': False, 'range': 472, 'remainingChargingMinutes': 10, }), @@ -1984,7 +4020,7 @@ }), }), }), - 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBA0FINGERPRINT01.json', + 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBA0FINGERPRINT02.json', }), dict({ 'content': dict({ @@ -2087,7 +4123,294 @@ }), 'servicePack': 'WAVE_01', }), - 'filename': 'bmw-eadrax-crccs_v2_vehicles_WBA0FINGERPRINT01.json', + 'filename': 'bmw-eadrax-crccs_v2_vehicles_WBA0FINGERPRINT02.json', + }), + dict({ + 'content': dict({ + 'capabilities': dict({ + 'a4aType': 'NOT_SUPPORTED', + 'checkSustainabilityDPP': False, + 'climateFunction': 'VENTILATION', + 'climateNow': True, + 'climateTimerTrigger': 'DEPARTURE_TIMER', + 'digitalKey': dict({ + 'bookedServicePackage': 'SMACC_1_5', + 'readerGraphics': 'readerGraphics', + 'state': 'ACTIVATED', + }), + 'horn': True, + 'isBmwChargingSupported': False, + 'isCarSharingSupported': False, + 'isChargeNowForBusinessSupported': False, + 'isChargingHistorySupported': False, + 'isChargingHospitalityEnabled': False, + 'isChargingLoudnessEnabled': False, + 'isChargingPlanSupported': False, + 'isChargingPowerLimitEnabled': False, + 'isChargingSettingsEnabled': False, + 'isChargingTargetSocEnabled': False, + 'isClimateTimerSupported': True, + 'isClimateTimerWeeklyActive': False, + 'isCustomerEsimSupported': False, + 'isDCSContractManagementSupported': False, + 'isDataPrivacyEnabled': False, + 'isEasyChargeEnabled': False, + 'isEvGoChargingSupported': False, + 'isMiniChargingSupported': False, + 'isNonLscFeatureEnabled': False, + 'isPersonalPictureUploadSupported': False, + 'isRemoteEngineStartSupported': False, + 'isRemoteHistoryDeletionSupported': False, + 'isRemoteHistorySupported': True, + 'isRemoteParkingSupported': False, + 'isRemoteServicesActivationRequired': False, + 'isRemoteServicesBookingRequired': False, + 'isScanAndChargeSupported': False, + 'isSustainabilityAccumulatedViewEnabled': False, + 'isSustainabilitySupported': False, + 'isWifiHotspotServiceSupported': True, + 'lastStateCallState': 'ACTIVATED', + 'lights': True, + 'lock': True, + 'remote360': True, + 'remoteChargingCommands': dict({ + }), + 'remoteSoftwareUpgrade': True, + 'sendPoi': True, + 'specialThemeSupport': list([ + ]), + 'speechThirdPartyAlexa': False, + 'speechThirdPartyAlexaSDK': False, + 'unlock': True, + 'vehicleFinder': True, + 'vehicleStateSource': 'LAST_STATE_CALL', + }), + 'state': dict({ + 'chargingProfile': dict({ + 'chargingMode': 'IMMEDIATE_CHARGING', + 'chargingPreference': 'NO_PRESELECTION', + 'chargingSettings': dict({ + 'hospitality': 'NO_ACTION', + 'idcc': 'NO_ACTION', + 'targetSoc': 0, + }), + 'departureTimes': list([ + ]), + }), + 'checkControlMessages': list([ + dict({ + 'severity': 'LOW', + 'type': 'TIRE_PRESSURE', + }), + dict({ + 'severity': 'LOW', + 'type': 'ENGINE_OIL', + }), + ]), + 'climateControlState': dict({ + 'activity': 'INACTIVE', + }), + 'climateTimers': list([ + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': False, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': True, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': True, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + ]), + 'combustionFuelLevel': dict({ + 'range': 629, + 'remainingFuelLiters': 40, + 'remainingFuelPercent': 80, + }), + 'currentMileage': 1121, + 'doorsState': dict({ + 'combinedSecurityState': 'LOCKED', + 'combinedState': 'CLOSED', + 'hood': 'CLOSED', + 'leftFront': 'CLOSED', + 'leftRear': 'CLOSED', + 'rightFront': 'CLOSED', + 'rightRear': 'CLOSED', + 'trunk': 'CLOSED', + }), + 'driverPreferences': dict({ + 'lscPrivacyMode': 'OFF', + }), + 'isLeftSteering': True, + 'isLscSupported': True, + 'lastFetched': '2023-01-04T14:57:06.336Z', + 'lastUpdatedAt': '2023-01-04T14:57:06.348Z', + 'location': dict({ + 'address': dict({ + 'formatted': '**REDACTED**', + }), + 'coordinates': dict({ + 'latitude': '**REDACTED**', + 'longitude': '**REDACTED**', + }), + 'heading': '**REDACTED**', + }), + 'range': 629, + 'requiredServices': list([ + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'OIL', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'BRAKE_FLUID', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'VEHICLE_TUV', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'VEHICLE_CHECK', + }), + dict({ + 'status': 'OK', + 'type': 'TIRE_WEAR_REAR', + }), + dict({ + 'status': 'OK', + 'type': 'TIRE_WEAR_FRONT', + }), + ]), + 'tireState': dict({ + 'frontLeft': dict({ + 'details': dict({ + 'dimension': '225/35 R20 90Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-03-07T00:00:00.000Z', + 'partNumber': '2461756', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 241, + 'pressureStatus': 0, + 'wearStatus': 0, + }), + }), + 'frontRight': dict({ + 'details': dict({ + 'dimension': '225/35 R20 90Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 2419, + 'mountingDate': '2022-03-07T00:00:00.000Z', + 'partNumber': '2461756', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 255, + 'pressureStatus': 0, + 'wearStatus': 0, + }), + }), + 'rearLeft': dict({ + 'details': dict({ + 'dimension': '255/30 R20 92Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 1219, + 'mountingDate': '2022-03-07T00:00:00.000Z', + 'partNumber': '2461757', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 324, + 'pressureStatus': 0, + 'wearStatus': 0, + }), + }), + 'rearRight': dict({ + 'details': dict({ + 'dimension': '255/30 R20 92Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 1219, + 'mountingDate': '2022-03-07T00:00:00.000Z', + 'partNumber': '2461757', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 331, + 'pressureStatus': 0, + 'wearStatus': 0, + }), + }), + }), + 'windowsState': dict({ + 'combinedState': 'CLOSED', + 'leftFront': 'CLOSED', + 'leftRear': 'CLOSED', + 'rear': 'CLOSED', + 'rightFront': 'CLOSED', + 'rightRear': 'CLOSED', + }), + }), + }), + 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBA0FINGERPRINT03.json', }), dict({ 'content': dict({ @@ -2248,7 +4571,6 @@ 'combustionFuelLevel': dict({ 'range': 105, 'remainingFuelLiters': 6, - 'remainingFuelPercent': 65, }), 'currentMileage': 137009, 'doorsState': dict({ @@ -2308,7 +4630,7 @@ }), }), }), - 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBY0FINGERPRINT02.json', + 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBY0FINGERPRINT04.json', }), dict({ 'content': dict({ @@ -2373,7 +4695,7 @@ }), 'servicePack': 'TCB1', }), - 'filename': 'bmw-eadrax-crccs_v2_vehicles_WBY0FINGERPRINT02.json', + 'filename': 'bmw-eadrax-crccs_v2_vehicles_WBY0FINGERPRINT04.json', }), ]), 'info': dict({ @@ -2601,7 +4923,7 @@ }), 'headUnitType': 'NBT', 'hmiVersion': 'ID4', - 'lastFetched': '2022-07-10T09:25:53.104Z', + 'lastFetched': '2022-06-01T19:48:46.540Z', 'model': 'i3 (+ REX)', 'softwareVersionCurrent': dict({ 'iStep': 510, @@ -2730,8 +5052,6 @@ 'fetched_at': '2022-07-10T11:00:00+00:00', 'is_metric': True, 'mappingInfo': dict({ - 'isAssociated': False, - 'isLmmEnabled': False, 'isPrimaryUser': True, 'mappingStatus': 'CONFIRMED', }), @@ -2848,7 +5168,6 @@ 'combustionFuelLevel': dict({ 'range': 105, 'remainingFuelLiters': 6, - 'remainingFuelPercent': 65, }), 'currentMileage': 137009, 'doorsState': dict({ @@ -3011,7 +5330,7 @@ 6, 'L', ]), - 'remaining_fuel_percent': 65, + 'remaining_fuel_percent': None, 'remaining_range_electric': list([ 174, 'km', @@ -3048,20 +5367,69 @@ 'km', ]), 'name': 'i3 (+ REX)', - 'timestamp': '2022-07-10T09:25:53+00:00', + 'timestamp': '2022-06-22T14:24:23+00:00', 'tires': None, 'vehicle_location': dict({ 'account_region': 'row', 'heading': None, 'location': None, 'remote_service_position': None, - 'vehicle_update_timestamp': '2022-07-10T09:25:53+00:00', + 'vehicle_update_timestamp': '2022-06-22T14:24:23+00:00', }), 'vin': '**REDACTED**', }), 'fingerprint': list([ dict({ 'content': list([ + dict({ + 'appVehicleType': 'DEMO', + 'attributes': dict({ + 'a4aType': 'BLUETOOTH', + 'bodyType': 'I20', + 'brand': 'BMW_I', + 'color': 4285537312, + 'countryOfOrigin': 'DE', + 'driveTrain': 'ELECTRIC', + 'driverGuideInfo': dict({ + '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': dict({ + 'iStep': 300, + 'puStep': dict({ + 'month': 7, + 'year': 21, + }), + 'seriesCluster': 'S21A', + }), + 'softwareVersionExFactory': dict({ + 'iStep': 300, + 'puStep': dict({ + 'month': 7, + 'year': 21, + }), + 'seriesCluster': 'S21A', + }), + 'telematicsUnit': 'WAVE01', + 'year': 2021, + }), + 'mappingInfo': dict({ + 'isAssociated': False, + 'isLmmEnabled': False, + 'isPrimaryUser': True, + 'lmmStatusReasons': list([ + ]), + 'mappingStatus': 'CONFIRMED', + }), + 'vin': '**REDACTED**', + }), dict({ 'appVehicleType': 'DEMO', 'attributes': dict({ @@ -3111,6 +5479,55 @@ }), 'vin': '**REDACTED**', }), + dict({ + 'appVehicleType': 'DEMO', + 'attributes': dict({ + 'a4aType': 'NOT_SUPPORTED', + 'bodyType': 'G20', + 'brand': 'BMW', + 'color': 4280233344, + 'countryOfOrigin': 'PT', + 'driveTrain': 'COMBUSTION', + 'driverGuideInfo': dict({ + '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': dict({ + 'iStep': 470, + 'puStep': dict({ + 'month': 7, + 'year': 21, + }), + 'seriesCluster': 'S18A', + }), + 'softwareVersionExFactory': dict({ + 'iStep': 420, + 'puStep': dict({ + 'month': 7, + 'year': 20, + }), + 'seriesCluster': 'S18A', + }), + 'telematicsUnit': 'ATM2', + 'year': 2022, + }), + 'mappingInfo': dict({ + 'isAssociated': False, + 'isLmmEnabled': False, + 'isPrimaryUser': True, + 'lmmStatusReasons': list([ + ]), + 'mappingStatus': 'CONFIRMED', + }), + 'vin': '**REDACTED**', + }), dict({ 'appVehicleType': 'CONNECTED', 'attributes': dict({ @@ -3128,7 +5545,7 @@ }), 'headUnitType': 'NBT', 'hmiVersion': 'ID4', - 'lastFetched': '2022-07-10T09:25:53.104Z', + 'lastFetched': '2022-06-01T19:48:46.540Z', 'model': 'i3 (+ REX)', 'softwareVersionCurrent': dict({ 'iStep': 510, @@ -3149,8 +5566,6 @@ 'year': 2015, }), 'mappingInfo': dict({ - 'isAssociated': False, - 'isLmmEnabled': False, 'isPrimaryUser': True, 'mappingStatus': 'CONFIRMED', }), @@ -3164,6 +5579,452 @@ ]), 'filename': 'mini-eadrax-vcs_v4_vehicles.json', }), + dict({ + 'content': dict({ + 'capabilities': dict({ + 'a4aType': 'BLUETOOTH', + 'checkSustainabilityDPP': False, + 'climateFunction': 'AIR_CONDITIONING', + 'climateNow': True, + 'digitalKey': dict({ + 'bookedServicePackage': 'SMACC_2_UWB', + 'readerGraphics': 'readerGraphics', + 'state': 'ACTIVATED', + }), + 'horn': True, + 'inCarCamera': True, + 'isBmwChargingSupported': True, + 'isCarSharingSupported': False, + 'isChargeNowForBusinessSupported': True, + 'isChargingHistorySupported': True, + 'isChargingHospitalityEnabled': True, + 'isChargingLoudnessEnabled': True, + 'isChargingPlanSupported': True, + 'isChargingPowerLimitEnabled': True, + 'isChargingSettingsEnabled': True, + 'isChargingTargetSocEnabled': True, + 'isClimateTimerWeeklyActive': False, + 'isCustomerEsimSupported': True, + 'isDCSContractManagementSupported': True, + 'isDataPrivacyEnabled': False, + 'isEasyChargeEnabled': True, + 'isEvGoChargingSupported': False, + 'isMiniChargingSupported': False, + 'isNonLscFeatureEnabled': False, + 'isPersonalPictureUploadSupported': False, + 'isRemoteEngineStartSupported': False, + 'isRemoteHistoryDeletionSupported': False, + 'isRemoteHistorySupported': True, + 'isRemoteParkingSupported': False, + 'isRemoteServicesActivationRequired': False, + 'isRemoteServicesBookingRequired': False, + 'isScanAndChargeSupported': True, + 'isSustainabilityAccumulatedViewEnabled': False, + 'isSustainabilitySupported': False, + 'isWifiHotspotServiceSupported': False, + 'lastStateCallState': 'ACTIVATED', + 'lights': True, + 'lock': True, + 'remote360': True, + 'remoteChargingCommands': dict({ + 'chargingControl': list([ + 'START', + 'STOP', + ]), + 'flapControl': list([ + 'NOT_SUPPORTED', + ]), + 'plugControl': list([ + 'NOT_SUPPORTED', + ]), + }), + 'remoteSoftwareUpgrade': True, + 'sendPoi': True, + 'specialThemeSupport': list([ + ]), + 'speechThirdPartyAlexa': False, + 'speechThirdPartyAlexaSDK': False, + 'surroundViewRecorder': True, + 'unlock': True, + 'vehicleFinder': True, + 'vehicleStateSource': 'LAST_STATE_CALL', + }), + 'state': dict({ + 'chargingProfile': dict({ + 'chargingControlType': 'WEEKLY_PLANNER', + 'chargingMode': 'IMMEDIATE_CHARGING', + 'chargingPreference': 'NO_PRESELECTION', + 'chargingSettings': dict({ + 'acCurrentLimit': 16, + 'hospitality': 'NO_ACTION', + 'idcc': 'UNLIMITED_LOUD', + 'targetSoc': 80, + }), + 'departureTimes': list([ + dict({ + 'action': 'DEACTIVATE', + 'id': 1, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + dict({ + 'action': 'DEACTIVATE', + 'id': 2, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + dict({ + 'action': 'DEACTIVATE', + 'id': 3, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + dict({ + 'action': 'DEACTIVATE', + 'id': 4, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + ]), + }), + 'checkControlMessages': list([ + dict({ + 'severity': 'LOW', + 'type': 'TIRE_PRESSURE', + }), + ]), + 'climateControlState': dict({ + 'activity': 'INACTIVE', + }), + 'climateTimers': list([ + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': False, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': True, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': True, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + ]), + 'combustionFuelLevel': dict({ + 'remainingFuelPercent': 10, + }), + 'currentMileage': 1121, + 'doorsState': dict({ + 'combinedSecurityState': 'LOCKED', + 'combinedState': 'CLOSED', + 'hood': 'CLOSED', + 'leftFront': 'CLOSED', + 'leftRear': 'CLOSED', + 'rightFront': 'CLOSED', + 'rightRear': 'CLOSED', + 'trunk': 'CLOSED', + }), + 'driverPreferences': dict({ + 'lscPrivacyMode': 'OFF', + }), + 'electricChargingState': dict({ + 'chargingConnectionType': 'UNKNOWN', + 'chargingLevelPercent': 70, + 'chargingStatus': 'CHARGING', + 'chargingTarget': 80, + 'isChargerConnected': True, + 'range': 340, + 'remainingChargingMinutes': 10, + }), + 'isLeftSteering': True, + 'isLscSupported': True, + 'lastFetched': '2023-01-04T14:57:06.371Z', + 'lastUpdatedAt': '2023-01-04T14:57:06.383Z', + 'location': dict({ + 'address': dict({ + 'formatted': '**REDACTED**', + }), + 'coordinates': dict({ + 'latitude': '**REDACTED**', + 'longitude': '**REDACTED**', + }), + 'heading': '**REDACTED**', + }), + 'range': 340, + 'requiredServices': list([ + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'BRAKE_FLUID', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'VEHICLE_TUV', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'VEHICLE_CHECK', + }), + dict({ + 'status': 'OK', + 'type': 'TIRE_WEAR_REAR', + }), + dict({ + 'status': 'OK', + 'type': 'TIRE_WEAR_FRONT', + }), + ]), + 'roofState': dict({ + 'roofState': 'CLOSED', + 'roofStateType': 'SUN_ROOF', + }), + 'tireState': dict({ + 'frontLeft': dict({ + 'details': dict({ + 'dimension': '275/40 R22 107Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-04-20T00:00:00.000Z', + 'partNumber': '5A401A1', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 241, + 'pressureStatus': 0, + 'targetPressure': 241, + 'wearStatus': 0, + }), + }), + 'frontRight': dict({ + 'details': dict({ + 'dimension': '275/40 R22 107Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-04-20T00:00:00.000Z', + 'partNumber': '5A401A1', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 241, + 'pressureStatus': 0, + 'targetPressure': 241, + 'wearStatus': 0, + }), + }), + 'rearLeft': dict({ + 'details': dict({ + 'dimension': '275/40 R22 107Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-04-20T00:00:00.000Z', + 'partNumber': '5A401A1', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 261, + 'pressureStatus': 0, + 'targetPressure': 269, + 'wearStatus': 0, + }), + }), + 'rearRight': dict({ + 'details': dict({ + 'dimension': '275/40 R22 107Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-04-20T00:00:00.000Z', + 'partNumber': '5A401A1', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 269, + 'pressureStatus': 0, + 'targetPressure': 269, + 'wearStatus': 0, + }), + }), + }), + 'windowsState': dict({ + 'combinedState': 'CLOSED', + 'leftFront': 'CLOSED', + 'leftRear': 'CLOSED', + 'rear': 'CLOSED', + 'rightFront': 'CLOSED', + 'rightRear': 'CLOSED', + }), + }), + }), + 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBA0FINGERPRINT01.json', + }), + dict({ + 'content': dict({ + 'chargeAndClimateSettings': dict({ + 'chargeAndClimateTimer': dict({ + 'chargingMode': 'Sofort laden', + 'chargingModeSemantics': 'Sofort laden', + 'departureTimer': list([ + 'Aus', + ]), + 'departureTimerSemantics': 'Aus', + 'preconditionForDeparture': 'Aus', + 'showDepartureTimers': False, + }), + 'chargingFlap': dict({ + 'permanentlyUnlockLabel': 'Aus', + }), + 'chargingSettings': dict({ + 'acCurrentLimitLabel': '16A', + 'acCurrentLimitLabelSemantics': '16 Ampere', + 'chargingTargetLabel': '80%', + 'dcLoudnessLabel': 'Nicht begrenzt', + 'unlockCableAutomaticallyLabel': 'Aus', + }), + }), + 'chargeAndClimateTimerDetail': dict({ + 'chargingMode': dict({ + 'chargingPreference': 'NO_PRESELECTION', + 'endTimeSlot': '0001-01-01T00:00:00', + 'startTimeSlot': '0001-01-01T00:00:00', + 'type': 'CHARGING_IMMEDIATELY', + }), + 'departureTimer': dict({ + 'type': 'WEEKLY_DEPARTURE_TIMER', + 'weeklyTimers': list([ + dict({ + 'daysOfTheWeek': list([ + ]), + 'id': 1, + 'time': '0001-01-01T00:00:00', + 'timerAction': 'DEACTIVATE', + }), + dict({ + 'daysOfTheWeek': list([ + ]), + 'id': 2, + 'time': '0001-01-01T00:00:00', + 'timerAction': 'DEACTIVATE', + }), + dict({ + 'daysOfTheWeek': list([ + ]), + 'id': 3, + 'time': '0001-01-01T00:00:00', + 'timerAction': 'DEACTIVATE', + }), + dict({ + 'daysOfTheWeek': list([ + ]), + 'id': 4, + 'time': '0001-01-01T00:00:00', + 'timerAction': 'DEACTIVATE', + }), + ]), + }), + 'isPreconditionForDepartureActive': False, + }), + 'chargingFlapDetail': dict({ + 'isPermanentlyUnlock': False, + }), + 'chargingSettingsDetail': dict({ + 'acLimit': dict({ + 'current': dict({ + 'unit': 'A', + 'value': 16, + }), + 'isUnlimited': False, + 'max': 32, + 'min': 6, + 'values': list([ + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 20, + 32, + ]), + }), + 'chargingTarget': 80, + 'dcLoudness': 'UNLIMITED_LOUD', + 'isUnlockCableActive': False, + 'minChargingTargetToWarning': 70, + }), + 'servicePack': 'WAVE_01', + }), + 'filename': 'bmw-eadrax-crccs_v2_vehicles_WBA0FINGERPRINT01.json', + }), dict({ 'content': dict({ 'capabilities': dict({ @@ -3211,16 +6072,6 @@ 'lock': True, 'remote360': True, 'remoteChargingCommands': dict({ - 'chargingControl': list([ - 'START', - 'STOP', - ]), - 'flapControl': list([ - 'NOT_SUPPORTED', - ]), - 'plugControl': list([ - 'NOT_SUPPORTED', - ]), }), 'remoteSoftwareUpgrade': True, 'sendPoi': True, @@ -3293,7 +6144,8 @@ }), ]), 'climateControlState': dict({ - 'activity': 'STANDBY', + 'activity': 'HEATING', + 'remainingSeconds': 1790.846, }), 'climateTimers': list([ dict({ @@ -3346,9 +6198,9 @@ 'electricChargingState': dict({ 'chargingConnectionType': 'UNKNOWN', 'chargingLevelPercent': 80, - 'chargingStatus': 'CHARGING', + 'chargingStatus': 'INVALID', 'chargingTarget': 80, - 'isChargerConnected': True, + 'isChargerConnected': False, 'range': 472, 'remainingChargingMinutes': 10, }), @@ -3498,7 +6350,7 @@ }), }), }), - 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBA0FINGERPRINT01.json', + 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBA0FINGERPRINT02.json', }), dict({ 'content': dict({ @@ -3601,7 +6453,294 @@ }), 'servicePack': 'WAVE_01', }), - 'filename': 'bmw-eadrax-crccs_v2_vehicles_WBA0FINGERPRINT01.json', + 'filename': 'bmw-eadrax-crccs_v2_vehicles_WBA0FINGERPRINT02.json', + }), + dict({ + 'content': dict({ + 'capabilities': dict({ + 'a4aType': 'NOT_SUPPORTED', + 'checkSustainabilityDPP': False, + 'climateFunction': 'VENTILATION', + 'climateNow': True, + 'climateTimerTrigger': 'DEPARTURE_TIMER', + 'digitalKey': dict({ + 'bookedServicePackage': 'SMACC_1_5', + 'readerGraphics': 'readerGraphics', + 'state': 'ACTIVATED', + }), + 'horn': True, + 'isBmwChargingSupported': False, + 'isCarSharingSupported': False, + 'isChargeNowForBusinessSupported': False, + 'isChargingHistorySupported': False, + 'isChargingHospitalityEnabled': False, + 'isChargingLoudnessEnabled': False, + 'isChargingPlanSupported': False, + 'isChargingPowerLimitEnabled': False, + 'isChargingSettingsEnabled': False, + 'isChargingTargetSocEnabled': False, + 'isClimateTimerSupported': True, + 'isClimateTimerWeeklyActive': False, + 'isCustomerEsimSupported': False, + 'isDCSContractManagementSupported': False, + 'isDataPrivacyEnabled': False, + 'isEasyChargeEnabled': False, + 'isEvGoChargingSupported': False, + 'isMiniChargingSupported': False, + 'isNonLscFeatureEnabled': False, + 'isPersonalPictureUploadSupported': False, + 'isRemoteEngineStartSupported': False, + 'isRemoteHistoryDeletionSupported': False, + 'isRemoteHistorySupported': True, + 'isRemoteParkingSupported': False, + 'isRemoteServicesActivationRequired': False, + 'isRemoteServicesBookingRequired': False, + 'isScanAndChargeSupported': False, + 'isSustainabilityAccumulatedViewEnabled': False, + 'isSustainabilitySupported': False, + 'isWifiHotspotServiceSupported': True, + 'lastStateCallState': 'ACTIVATED', + 'lights': True, + 'lock': True, + 'remote360': True, + 'remoteChargingCommands': dict({ + }), + 'remoteSoftwareUpgrade': True, + 'sendPoi': True, + 'specialThemeSupport': list([ + ]), + 'speechThirdPartyAlexa': False, + 'speechThirdPartyAlexaSDK': False, + 'unlock': True, + 'vehicleFinder': True, + 'vehicleStateSource': 'LAST_STATE_CALL', + }), + 'state': dict({ + 'chargingProfile': dict({ + 'chargingMode': 'IMMEDIATE_CHARGING', + 'chargingPreference': 'NO_PRESELECTION', + 'chargingSettings': dict({ + 'hospitality': 'NO_ACTION', + 'idcc': 'NO_ACTION', + 'targetSoc': 0, + }), + 'departureTimes': list([ + ]), + }), + 'checkControlMessages': list([ + dict({ + 'severity': 'LOW', + 'type': 'TIRE_PRESSURE', + }), + dict({ + 'severity': 'LOW', + 'type': 'ENGINE_OIL', + }), + ]), + 'climateControlState': dict({ + 'activity': 'INACTIVE', + }), + 'climateTimers': list([ + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': False, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': True, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': True, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + ]), + 'combustionFuelLevel': dict({ + 'range': 629, + 'remainingFuelLiters': 40, + 'remainingFuelPercent': 80, + }), + 'currentMileage': 1121, + 'doorsState': dict({ + 'combinedSecurityState': 'LOCKED', + 'combinedState': 'CLOSED', + 'hood': 'CLOSED', + 'leftFront': 'CLOSED', + 'leftRear': 'CLOSED', + 'rightFront': 'CLOSED', + 'rightRear': 'CLOSED', + 'trunk': 'CLOSED', + }), + 'driverPreferences': dict({ + 'lscPrivacyMode': 'OFF', + }), + 'isLeftSteering': True, + 'isLscSupported': True, + 'lastFetched': '2023-01-04T14:57:06.336Z', + 'lastUpdatedAt': '2023-01-04T14:57:06.348Z', + 'location': dict({ + 'address': dict({ + 'formatted': '**REDACTED**', + }), + 'coordinates': dict({ + 'latitude': '**REDACTED**', + 'longitude': '**REDACTED**', + }), + 'heading': '**REDACTED**', + }), + 'range': 629, + 'requiredServices': list([ + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'OIL', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'BRAKE_FLUID', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'VEHICLE_TUV', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'VEHICLE_CHECK', + }), + dict({ + 'status': 'OK', + 'type': 'TIRE_WEAR_REAR', + }), + dict({ + 'status': 'OK', + 'type': 'TIRE_WEAR_FRONT', + }), + ]), + 'tireState': dict({ + 'frontLeft': dict({ + 'details': dict({ + 'dimension': '225/35 R20 90Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-03-07T00:00:00.000Z', + 'partNumber': '2461756', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 241, + 'pressureStatus': 0, + 'wearStatus': 0, + }), + }), + 'frontRight': dict({ + 'details': dict({ + 'dimension': '225/35 R20 90Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 2419, + 'mountingDate': '2022-03-07T00:00:00.000Z', + 'partNumber': '2461756', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 255, + 'pressureStatus': 0, + 'wearStatus': 0, + }), + }), + 'rearLeft': dict({ + 'details': dict({ + 'dimension': '255/30 R20 92Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 1219, + 'mountingDate': '2022-03-07T00:00:00.000Z', + 'partNumber': '2461757', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 324, + 'pressureStatus': 0, + 'wearStatus': 0, + }), + }), + 'rearRight': dict({ + 'details': dict({ + 'dimension': '255/30 R20 92Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 1219, + 'mountingDate': '2022-03-07T00:00:00.000Z', + 'partNumber': '2461757', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 331, + 'pressureStatus': 0, + 'wearStatus': 0, + }), + }), + }), + 'windowsState': dict({ + 'combinedState': 'CLOSED', + 'leftFront': 'CLOSED', + 'leftRear': 'CLOSED', + 'rear': 'CLOSED', + 'rightFront': 'CLOSED', + 'rightRear': 'CLOSED', + }), + }), + }), + 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBA0FINGERPRINT03.json', }), dict({ 'content': dict({ @@ -3762,7 +6901,6 @@ 'combustionFuelLevel': dict({ 'range': 105, 'remainingFuelLiters': 6, - 'remainingFuelPercent': 65, }), 'currentMileage': 137009, 'doorsState': dict({ @@ -3822,7 +6960,7 @@ }), }), }), - 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBY0FINGERPRINT02.json', + 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBY0FINGERPRINT04.json', }), dict({ 'content': dict({ @@ -3887,7 +7025,7 @@ }), 'servicePack': 'TCB1', }), - 'filename': 'bmw-eadrax-crccs_v2_vehicles_WBY0FINGERPRINT02.json', + 'filename': 'bmw-eadrax-crccs_v2_vehicles_WBY0FINGERPRINT04.json', }), ]), 'info': dict({ @@ -3905,6 +7043,55 @@ 'fingerprint': list([ dict({ 'content': list([ + dict({ + 'appVehicleType': 'DEMO', + 'attributes': dict({ + 'a4aType': 'BLUETOOTH', + 'bodyType': 'I20', + 'brand': 'BMW_I', + 'color': 4285537312, + 'countryOfOrigin': 'DE', + 'driveTrain': 'ELECTRIC', + 'driverGuideInfo': dict({ + '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': dict({ + 'iStep': 300, + 'puStep': dict({ + 'month': 7, + 'year': 21, + }), + 'seriesCluster': 'S21A', + }), + 'softwareVersionExFactory': dict({ + 'iStep': 300, + 'puStep': dict({ + 'month': 7, + 'year': 21, + }), + 'seriesCluster': 'S21A', + }), + 'telematicsUnit': 'WAVE01', + 'year': 2021, + }), + 'mappingInfo': dict({ + 'isAssociated': False, + 'isLmmEnabled': False, + 'isPrimaryUser': True, + 'lmmStatusReasons': list([ + ]), + 'mappingStatus': 'CONFIRMED', + }), + 'vin': '**REDACTED**', + }), dict({ 'appVehicleType': 'DEMO', 'attributes': dict({ @@ -3954,6 +7141,55 @@ }), 'vin': '**REDACTED**', }), + dict({ + 'appVehicleType': 'DEMO', + 'attributes': dict({ + 'a4aType': 'NOT_SUPPORTED', + 'bodyType': 'G20', + 'brand': 'BMW', + 'color': 4280233344, + 'countryOfOrigin': 'PT', + 'driveTrain': 'COMBUSTION', + 'driverGuideInfo': dict({ + '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': dict({ + 'iStep': 470, + 'puStep': dict({ + 'month': 7, + 'year': 21, + }), + 'seriesCluster': 'S18A', + }), + 'softwareVersionExFactory': dict({ + 'iStep': 420, + 'puStep': dict({ + 'month': 7, + 'year': 20, + }), + 'seriesCluster': 'S18A', + }), + 'telematicsUnit': 'ATM2', + 'year': 2022, + }), + 'mappingInfo': dict({ + 'isAssociated': False, + 'isLmmEnabled': False, + 'isPrimaryUser': True, + 'lmmStatusReasons': list([ + ]), + 'mappingStatus': 'CONFIRMED', + }), + 'vin': '**REDACTED**', + }), dict({ 'appVehicleType': 'CONNECTED', 'attributes': dict({ @@ -3971,7 +7207,7 @@ }), 'headUnitType': 'NBT', 'hmiVersion': 'ID4', - 'lastFetched': '2022-07-10T09:25:53.104Z', + 'lastFetched': '2022-06-01T19:48:46.540Z', 'model': 'i3 (+ REX)', 'softwareVersionCurrent': dict({ 'iStep': 510, @@ -3992,8 +7228,6 @@ 'year': 2015, }), 'mappingInfo': dict({ - 'isAssociated': False, - 'isLmmEnabled': False, 'isPrimaryUser': True, 'mappingStatus': 'CONFIRMED', }), @@ -4007,6 +7241,452 @@ ]), 'filename': 'mini-eadrax-vcs_v4_vehicles.json', }), + dict({ + 'content': dict({ + 'capabilities': dict({ + 'a4aType': 'BLUETOOTH', + 'checkSustainabilityDPP': False, + 'climateFunction': 'AIR_CONDITIONING', + 'climateNow': True, + 'digitalKey': dict({ + 'bookedServicePackage': 'SMACC_2_UWB', + 'readerGraphics': 'readerGraphics', + 'state': 'ACTIVATED', + }), + 'horn': True, + 'inCarCamera': True, + 'isBmwChargingSupported': True, + 'isCarSharingSupported': False, + 'isChargeNowForBusinessSupported': True, + 'isChargingHistorySupported': True, + 'isChargingHospitalityEnabled': True, + 'isChargingLoudnessEnabled': True, + 'isChargingPlanSupported': True, + 'isChargingPowerLimitEnabled': True, + 'isChargingSettingsEnabled': True, + 'isChargingTargetSocEnabled': True, + 'isClimateTimerWeeklyActive': False, + 'isCustomerEsimSupported': True, + 'isDCSContractManagementSupported': True, + 'isDataPrivacyEnabled': False, + 'isEasyChargeEnabled': True, + 'isEvGoChargingSupported': False, + 'isMiniChargingSupported': False, + 'isNonLscFeatureEnabled': False, + 'isPersonalPictureUploadSupported': False, + 'isRemoteEngineStartSupported': False, + 'isRemoteHistoryDeletionSupported': False, + 'isRemoteHistorySupported': True, + 'isRemoteParkingSupported': False, + 'isRemoteServicesActivationRequired': False, + 'isRemoteServicesBookingRequired': False, + 'isScanAndChargeSupported': True, + 'isSustainabilityAccumulatedViewEnabled': False, + 'isSustainabilitySupported': False, + 'isWifiHotspotServiceSupported': False, + 'lastStateCallState': 'ACTIVATED', + 'lights': True, + 'lock': True, + 'remote360': True, + 'remoteChargingCommands': dict({ + 'chargingControl': list([ + 'START', + 'STOP', + ]), + 'flapControl': list([ + 'NOT_SUPPORTED', + ]), + 'plugControl': list([ + 'NOT_SUPPORTED', + ]), + }), + 'remoteSoftwareUpgrade': True, + 'sendPoi': True, + 'specialThemeSupport': list([ + ]), + 'speechThirdPartyAlexa': False, + 'speechThirdPartyAlexaSDK': False, + 'surroundViewRecorder': True, + 'unlock': True, + 'vehicleFinder': True, + 'vehicleStateSource': 'LAST_STATE_CALL', + }), + 'state': dict({ + 'chargingProfile': dict({ + 'chargingControlType': 'WEEKLY_PLANNER', + 'chargingMode': 'IMMEDIATE_CHARGING', + 'chargingPreference': 'NO_PRESELECTION', + 'chargingSettings': dict({ + 'acCurrentLimit': 16, + 'hospitality': 'NO_ACTION', + 'idcc': 'UNLIMITED_LOUD', + 'targetSoc': 80, + }), + 'departureTimes': list([ + dict({ + 'action': 'DEACTIVATE', + 'id': 1, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + dict({ + 'action': 'DEACTIVATE', + 'id': 2, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + dict({ + 'action': 'DEACTIVATE', + 'id': 3, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + dict({ + 'action': 'DEACTIVATE', + 'id': 4, + 'timeStamp': dict({ + 'hour': 0, + 'minute': 0, + }), + 'timerWeekDays': list([ + ]), + }), + ]), + }), + 'checkControlMessages': list([ + dict({ + 'severity': 'LOW', + 'type': 'TIRE_PRESSURE', + }), + ]), + 'climateControlState': dict({ + 'activity': 'INACTIVE', + }), + 'climateTimers': list([ + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': False, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': True, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': True, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + ]), + 'combustionFuelLevel': dict({ + 'remainingFuelPercent': 10, + }), + 'currentMileage': 1121, + 'doorsState': dict({ + 'combinedSecurityState': 'LOCKED', + 'combinedState': 'CLOSED', + 'hood': 'CLOSED', + 'leftFront': 'CLOSED', + 'leftRear': 'CLOSED', + 'rightFront': 'CLOSED', + 'rightRear': 'CLOSED', + 'trunk': 'CLOSED', + }), + 'driverPreferences': dict({ + 'lscPrivacyMode': 'OFF', + }), + 'electricChargingState': dict({ + 'chargingConnectionType': 'UNKNOWN', + 'chargingLevelPercent': 70, + 'chargingStatus': 'CHARGING', + 'chargingTarget': 80, + 'isChargerConnected': True, + 'range': 340, + 'remainingChargingMinutes': 10, + }), + 'isLeftSteering': True, + 'isLscSupported': True, + 'lastFetched': '2023-01-04T14:57:06.371Z', + 'lastUpdatedAt': '2023-01-04T14:57:06.383Z', + 'location': dict({ + 'address': dict({ + 'formatted': '**REDACTED**', + }), + 'coordinates': dict({ + 'latitude': '**REDACTED**', + 'longitude': '**REDACTED**', + }), + 'heading': '**REDACTED**', + }), + 'range': 340, + 'requiredServices': list([ + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'BRAKE_FLUID', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'VEHICLE_TUV', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'VEHICLE_CHECK', + }), + dict({ + 'status': 'OK', + 'type': 'TIRE_WEAR_REAR', + }), + dict({ + 'status': 'OK', + 'type': 'TIRE_WEAR_FRONT', + }), + ]), + 'roofState': dict({ + 'roofState': 'CLOSED', + 'roofStateType': 'SUN_ROOF', + }), + 'tireState': dict({ + 'frontLeft': dict({ + 'details': dict({ + 'dimension': '275/40 R22 107Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-04-20T00:00:00.000Z', + 'partNumber': '5A401A1', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 241, + 'pressureStatus': 0, + 'targetPressure': 241, + 'wearStatus': 0, + }), + }), + 'frontRight': dict({ + 'details': dict({ + 'dimension': '275/40 R22 107Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-04-20T00:00:00.000Z', + 'partNumber': '5A401A1', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 241, + 'pressureStatus': 0, + 'targetPressure': 241, + 'wearStatus': 0, + }), + }), + 'rearLeft': dict({ + 'details': dict({ + 'dimension': '275/40 R22 107Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-04-20T00:00:00.000Z', + 'partNumber': '5A401A1', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 261, + 'pressureStatus': 0, + 'targetPressure': 269, + 'wearStatus': 0, + }), + }), + 'rearRight': dict({ + 'details': dict({ + 'dimension': '275/40 R22 107Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-04-20T00:00:00.000Z', + 'partNumber': '5A401A1', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 269, + 'pressureStatus': 0, + 'targetPressure': 269, + 'wearStatus': 0, + }), + }), + }), + 'windowsState': dict({ + 'combinedState': 'CLOSED', + 'leftFront': 'CLOSED', + 'leftRear': 'CLOSED', + 'rear': 'CLOSED', + 'rightFront': 'CLOSED', + 'rightRear': 'CLOSED', + }), + }), + }), + 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBA0FINGERPRINT01.json', + }), + dict({ + 'content': dict({ + 'chargeAndClimateSettings': dict({ + 'chargeAndClimateTimer': dict({ + 'chargingMode': 'Sofort laden', + 'chargingModeSemantics': 'Sofort laden', + 'departureTimer': list([ + 'Aus', + ]), + 'departureTimerSemantics': 'Aus', + 'preconditionForDeparture': 'Aus', + 'showDepartureTimers': False, + }), + 'chargingFlap': dict({ + 'permanentlyUnlockLabel': 'Aus', + }), + 'chargingSettings': dict({ + 'acCurrentLimitLabel': '16A', + 'acCurrentLimitLabelSemantics': '16 Ampere', + 'chargingTargetLabel': '80%', + 'dcLoudnessLabel': 'Nicht begrenzt', + 'unlockCableAutomaticallyLabel': 'Aus', + }), + }), + 'chargeAndClimateTimerDetail': dict({ + 'chargingMode': dict({ + 'chargingPreference': 'NO_PRESELECTION', + 'endTimeSlot': '0001-01-01T00:00:00', + 'startTimeSlot': '0001-01-01T00:00:00', + 'type': 'CHARGING_IMMEDIATELY', + }), + 'departureTimer': dict({ + 'type': 'WEEKLY_DEPARTURE_TIMER', + 'weeklyTimers': list([ + dict({ + 'daysOfTheWeek': list([ + ]), + 'id': 1, + 'time': '0001-01-01T00:00:00', + 'timerAction': 'DEACTIVATE', + }), + dict({ + 'daysOfTheWeek': list([ + ]), + 'id': 2, + 'time': '0001-01-01T00:00:00', + 'timerAction': 'DEACTIVATE', + }), + dict({ + 'daysOfTheWeek': list([ + ]), + 'id': 3, + 'time': '0001-01-01T00:00:00', + 'timerAction': 'DEACTIVATE', + }), + dict({ + 'daysOfTheWeek': list([ + ]), + 'id': 4, + 'time': '0001-01-01T00:00:00', + 'timerAction': 'DEACTIVATE', + }), + ]), + }), + 'isPreconditionForDepartureActive': False, + }), + 'chargingFlapDetail': dict({ + 'isPermanentlyUnlock': False, + }), + 'chargingSettingsDetail': dict({ + 'acLimit': dict({ + 'current': dict({ + 'unit': 'A', + 'value': 16, + }), + 'isUnlimited': False, + 'max': 32, + 'min': 6, + 'values': list([ + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 20, + 32, + ]), + }), + 'chargingTarget': 80, + 'dcLoudness': 'UNLIMITED_LOUD', + 'isUnlockCableActive': False, + 'minChargingTargetToWarning': 70, + }), + 'servicePack': 'WAVE_01', + }), + 'filename': 'bmw-eadrax-crccs_v2_vehicles_WBA0FINGERPRINT01.json', + }), dict({ 'content': dict({ 'capabilities': dict({ @@ -4054,16 +7734,6 @@ 'lock': True, 'remote360': True, 'remoteChargingCommands': dict({ - 'chargingControl': list([ - 'START', - 'STOP', - ]), - 'flapControl': list([ - 'NOT_SUPPORTED', - ]), - 'plugControl': list([ - 'NOT_SUPPORTED', - ]), }), 'remoteSoftwareUpgrade': True, 'sendPoi': True, @@ -4136,7 +7806,8 @@ }), ]), 'climateControlState': dict({ - 'activity': 'STANDBY', + 'activity': 'HEATING', + 'remainingSeconds': 1790.846, }), 'climateTimers': list([ dict({ @@ -4189,9 +7860,9 @@ 'electricChargingState': dict({ 'chargingConnectionType': 'UNKNOWN', 'chargingLevelPercent': 80, - 'chargingStatus': 'CHARGING', + 'chargingStatus': 'INVALID', 'chargingTarget': 80, - 'isChargerConnected': True, + 'isChargerConnected': False, 'range': 472, 'remainingChargingMinutes': 10, }), @@ -4341,7 +8012,7 @@ }), }), }), - 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBA0FINGERPRINT01.json', + 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBA0FINGERPRINT02.json', }), dict({ 'content': dict({ @@ -4444,7 +8115,294 @@ }), 'servicePack': 'WAVE_01', }), - 'filename': 'bmw-eadrax-crccs_v2_vehicles_WBA0FINGERPRINT01.json', + 'filename': 'bmw-eadrax-crccs_v2_vehicles_WBA0FINGERPRINT02.json', + }), + dict({ + 'content': dict({ + 'capabilities': dict({ + 'a4aType': 'NOT_SUPPORTED', + 'checkSustainabilityDPP': False, + 'climateFunction': 'VENTILATION', + 'climateNow': True, + 'climateTimerTrigger': 'DEPARTURE_TIMER', + 'digitalKey': dict({ + 'bookedServicePackage': 'SMACC_1_5', + 'readerGraphics': 'readerGraphics', + 'state': 'ACTIVATED', + }), + 'horn': True, + 'isBmwChargingSupported': False, + 'isCarSharingSupported': False, + 'isChargeNowForBusinessSupported': False, + 'isChargingHistorySupported': False, + 'isChargingHospitalityEnabled': False, + 'isChargingLoudnessEnabled': False, + 'isChargingPlanSupported': False, + 'isChargingPowerLimitEnabled': False, + 'isChargingSettingsEnabled': False, + 'isChargingTargetSocEnabled': False, + 'isClimateTimerSupported': True, + 'isClimateTimerWeeklyActive': False, + 'isCustomerEsimSupported': False, + 'isDCSContractManagementSupported': False, + 'isDataPrivacyEnabled': False, + 'isEasyChargeEnabled': False, + 'isEvGoChargingSupported': False, + 'isMiniChargingSupported': False, + 'isNonLscFeatureEnabled': False, + 'isPersonalPictureUploadSupported': False, + 'isRemoteEngineStartSupported': False, + 'isRemoteHistoryDeletionSupported': False, + 'isRemoteHistorySupported': True, + 'isRemoteParkingSupported': False, + 'isRemoteServicesActivationRequired': False, + 'isRemoteServicesBookingRequired': False, + 'isScanAndChargeSupported': False, + 'isSustainabilityAccumulatedViewEnabled': False, + 'isSustainabilitySupported': False, + 'isWifiHotspotServiceSupported': True, + 'lastStateCallState': 'ACTIVATED', + 'lights': True, + 'lock': True, + 'remote360': True, + 'remoteChargingCommands': dict({ + }), + 'remoteSoftwareUpgrade': True, + 'sendPoi': True, + 'specialThemeSupport': list([ + ]), + 'speechThirdPartyAlexa': False, + 'speechThirdPartyAlexaSDK': False, + 'unlock': True, + 'vehicleFinder': True, + 'vehicleStateSource': 'LAST_STATE_CALL', + }), + 'state': dict({ + 'chargingProfile': dict({ + 'chargingMode': 'IMMEDIATE_CHARGING', + 'chargingPreference': 'NO_PRESELECTION', + 'chargingSettings': dict({ + 'hospitality': 'NO_ACTION', + 'idcc': 'NO_ACTION', + 'targetSoc': 0, + }), + 'departureTimes': list([ + ]), + }), + 'checkControlMessages': list([ + dict({ + 'severity': 'LOW', + 'type': 'TIRE_PRESSURE', + }), + dict({ + 'severity': 'LOW', + 'type': 'ENGINE_OIL', + }), + ]), + 'climateControlState': dict({ + 'activity': 'INACTIVE', + }), + 'climateTimers': list([ + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': False, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': True, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + dict({ + 'departureTime': dict({ + 'hour': 0, + 'minute': 0, + }), + 'isWeeklyTimer': True, + 'timerAction': 'DEACTIVATE', + 'timerWeekDays': list([ + ]), + }), + ]), + 'combustionFuelLevel': dict({ + 'range': 629, + 'remainingFuelLiters': 40, + 'remainingFuelPercent': 80, + }), + 'currentMileage': 1121, + 'doorsState': dict({ + 'combinedSecurityState': 'LOCKED', + 'combinedState': 'CLOSED', + 'hood': 'CLOSED', + 'leftFront': 'CLOSED', + 'leftRear': 'CLOSED', + 'rightFront': 'CLOSED', + 'rightRear': 'CLOSED', + 'trunk': 'CLOSED', + }), + 'driverPreferences': dict({ + 'lscPrivacyMode': 'OFF', + }), + 'isLeftSteering': True, + 'isLscSupported': True, + 'lastFetched': '2023-01-04T14:57:06.336Z', + 'lastUpdatedAt': '2023-01-04T14:57:06.348Z', + 'location': dict({ + 'address': dict({ + 'formatted': '**REDACTED**', + }), + 'coordinates': dict({ + 'latitude': '**REDACTED**', + 'longitude': '**REDACTED**', + }), + 'heading': '**REDACTED**', + }), + 'range': 629, + 'requiredServices': list([ + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'OIL', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'BRAKE_FLUID', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'VEHICLE_TUV', + }), + dict({ + 'dateTime': '2024-12-01T00:00:00.000Z', + 'description': '', + 'mileage': 50000, + 'status': 'OK', + 'type': 'VEHICLE_CHECK', + }), + dict({ + 'status': 'OK', + 'type': 'TIRE_WEAR_REAR', + }), + dict({ + 'status': 'OK', + 'type': 'TIRE_WEAR_FRONT', + }), + ]), + 'tireState': dict({ + 'frontLeft': dict({ + 'details': dict({ + 'dimension': '225/35 R20 90Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 4021, + 'mountingDate': '2022-03-07T00:00:00.000Z', + 'partNumber': '2461756', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 241, + 'pressureStatus': 0, + 'wearStatus': 0, + }), + }), + 'frontRight': dict({ + 'details': dict({ + 'dimension': '225/35 R20 90Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 2419, + 'mountingDate': '2022-03-07T00:00:00.000Z', + 'partNumber': '2461756', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 255, + 'pressureStatus': 0, + 'wearStatus': 0, + }), + }), + 'rearLeft': dict({ + 'details': dict({ + 'dimension': '255/30 R20 92Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 1219, + 'mountingDate': '2022-03-07T00:00:00.000Z', + 'partNumber': '2461757', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 324, + 'pressureStatus': 0, + 'wearStatus': 0, + }), + }), + 'rearRight': dict({ + 'details': dict({ + 'dimension': '255/30 R20 92Y XL', + 'isOptimizedForOemBmw': True, + 'manufacturer': 'Pirelli', + 'manufacturingWeek': 1219, + 'mountingDate': '2022-03-07T00:00:00.000Z', + 'partNumber': '2461757', + 'season': 2, + 'speedClassification': dict({ + 'atLeast': False, + 'speedRating': 300, + }), + 'treadDesign': 'P-ZERO', + }), + 'status': dict({ + 'currentPressure': 331, + 'pressureStatus': 0, + 'wearStatus': 0, + }), + }), + }), + 'windowsState': dict({ + 'combinedState': 'CLOSED', + 'leftFront': 'CLOSED', + 'leftRear': 'CLOSED', + 'rear': 'CLOSED', + 'rightFront': 'CLOSED', + 'rightRear': 'CLOSED', + }), + }), + }), + 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBA0FINGERPRINT03.json', }), dict({ 'content': dict({ @@ -4605,7 +8563,6 @@ 'combustionFuelLevel': dict({ 'range': 105, 'remainingFuelLiters': 6, - 'remainingFuelPercent': 65, }), 'currentMileage': 137009, 'doorsState': dict({ @@ -4665,7 +8622,7 @@ }), }), }), - 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBY0FINGERPRINT02.json', + 'filename': 'bmw-eadrax-vcs_v4_vehicles_state_WBY0FINGERPRINT04.json', }), dict({ 'content': dict({ @@ -4730,7 +8687,7 @@ }), 'servicePack': 'TCB1', }), - 'filename': 'bmw-eadrax-crccs_v2_vehicles_WBY0FINGERPRINT02.json', + 'filename': 'bmw-eadrax-crccs_v2_vehicles_WBY0FINGERPRINT04.json', }), ]), 'info': dict({ diff --git a/tests/components/bmw_connected_drive/snapshots/test_number.ambr b/tests/components/bmw_connected_drive/snapshots/test_number.ambr index a99d8bb3e0f..ab3668664f4 100644 --- a/tests/components/bmw_connected_drive/snapshots/test_number.ambr +++ b/tests/components/bmw_connected_drive/snapshots/test_number.ambr @@ -1,6 +1,23 @@ # serializer version: 1 # name: test_entity_state_attrs list([ + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'device_class': 'battery', + 'friendly_name': 'iX xDrive50 Target SoC', + 'icon': 'mdi:battery-charging-medium', + 'max': 100.0, + 'min': 20.0, + 'mode': , + 'step': 5.0, + }), + 'context': , + 'entity_id': 'number.ix_xdrive50_target_soc', + 'last_changed': , + 'last_updated': , + 'state': '80', + }), StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by MyBMW', diff --git a/tests/components/bmw_connected_drive/snapshots/test_select.ambr b/tests/components/bmw_connected_drive/snapshots/test_select.ambr index 522e74c61e2..cac71c3049d 100644 --- a/tests/components/bmw_connected_drive/snapshots/test_select.ambr +++ b/tests/components/bmw_connected_drive/snapshots/test_select.ambr @@ -1,6 +1,50 @@ # serializer version: 1 # name: test_entity_state_attrs list([ + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'iX xDrive50 AC Charging Limit', + 'icon': 'mdi:current-ac', + 'options': list([ + '6', + '7', + '8', + '9', + '10', + '11', + '12', + '13', + '14', + '15', + '16', + '20', + '32', + ]), + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'select.ix_xdrive50_ac_charging_limit', + 'last_changed': , + 'last_updated': , + 'state': '16', + }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'iX xDrive50 Charging Mode', + 'icon': 'mdi:vector-point-select', + 'options': list([ + 'IMMEDIATE_CHARGING', + 'DELAYED_CHARGING', + ]), + }), + 'context': , + 'entity_id': 'select.ix_xdrive50_charging_mode', + 'last_changed': , + 'last_updated': , + 'state': 'IMMEDIATE_CHARGING', + }), StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by MyBMW', diff --git a/tests/components/bmw_connected_drive/snapshots/test_switch.ambr b/tests/components/bmw_connected_drive/snapshots/test_switch.ambr index de5a44637c3..974f3d785ff 100644 --- a/tests/components/bmw_connected_drive/snapshots/test_switch.ambr +++ b/tests/components/bmw_connected_drive/snapshots/test_switch.ambr @@ -1,6 +1,30 @@ # serializer version: 1 # name: test_entity_state_attrs list([ + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'iX xDrive50 Climate', + 'icon': 'mdi:fan', + }), + 'context': , + 'entity_id': 'switch.ix_xdrive50_climate', + 'last_changed': , + 'last_updated': , + 'state': 'off', + }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'iX xDrive50 Charging', + 'icon': 'mdi:ev-station', + }), + 'context': , + 'entity_id': 'switch.ix_xdrive50_charging', + 'last_changed': , + 'last_updated': , + 'state': 'on', + }), StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by MyBMW', @@ -11,19 +35,19 @@ 'entity_id': 'switch.i4_edrive40_climate', 'last_changed': , 'last_updated': , - 'state': 'off', + 'state': 'on', }), StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by MyBMW', - 'friendly_name': 'i4 eDrive40 Charging', - 'icon': 'mdi:ev-station', + 'friendly_name': 'M340i xDrive Climate', + 'icon': 'mdi:fan', }), 'context': , - 'entity_id': 'switch.i4_edrive40_charging', + 'entity_id': 'switch.m340i_xdrive_climate', 'last_changed': , 'last_updated': , - 'state': 'on', + 'state': 'off', }), ]) # --- diff --git a/tests/components/bmw_connected_drive/test_button.py b/tests/components/bmw_connected_drive/test_button.py index 16803756702..9cea5f2fd91 100644 --- a/tests/components/bmw_connected_drive/test_button.py +++ b/tests/components/bmw_connected_drive/test_button.py @@ -7,13 +7,10 @@ import pytest import respx from syrupy.assertion import SnapshotAssertion -from homeassistant.components.bmw_connected_drive.coordinator import ( - BMWDataUpdateCoordinator, -) from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError -from . import setup_mocked_integration +from . import check_remote_service_call, setup_mocked_integration async def test_entity_state_attrs( @@ -31,25 +28,22 @@ async def test_entity_state_attrs( @pytest.mark.parametrize( - ("entity_id"), + ("entity_id", "remote_service"), [ - ("button.i4_edrive40_flash_lights"), - ("button.i4_edrive40_sound_horn"), - ("button.i4_edrive40_activate_air_conditioning"), - ("button.i4_edrive40_deactivate_air_conditioning"), - ("button.i4_edrive40_find_vehicle"), + ("button.i4_edrive40_flash_lights", "light-flash"), + ("button.i4_edrive40_sound_horn", "horn-blow"), ], ) -async def test_update_triggers_success( +async def test_service_call_success( hass: HomeAssistant, entity_id: str, + remote_service: str, bmw_fixture: respx.Router, ) -> None: - """Test button press.""" + """Test successful button press.""" # Setup component assert await setup_mocked_integration(hass) - BMWDataUpdateCoordinator.async_update_listeners.reset_mock() # Test await hass.services.async_call( @@ -58,20 +52,20 @@ async def test_update_triggers_success( blocking=True, target={"entity_id": entity_id}, ) - assert RemoteServices.trigger_remote_service.call_count == 1 - assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 1 + check_remote_service_call(bmw_fixture, remote_service) -async def test_update_failed( +async def test_service_call_fail( hass: HomeAssistant, bmw_fixture: respx.Router, monkeypatch: pytest.MonkeyPatch, ) -> None: - """Test button press.""" + """Test failed button press.""" # Setup component assert await setup_mocked_integration(hass) - BMWDataUpdateCoordinator.async_update_listeners.reset_mock() + entity_id = "switch.i4_edrive40_climate" + old_value = hass.states.get(entity_id).state # Setup exception monkeypatch.setattr( @@ -86,7 +80,115 @@ async def test_update_failed( "button", "press", blocking=True, - target={"entity_id": "button.i4_edrive40_flash_lights"}, + target={"entity_id": "button.i4_edrive40_activate_air_conditioning"}, ) - assert RemoteServices.trigger_remote_service.call_count == 1 - assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 0 + assert hass.states.get(entity_id).state == old_value + + +@pytest.mark.parametrize( + ( + "entity_id", + "state_entity_id", + "new_value", + "old_value", + "remote_service", + "remote_service_params", + ), + [ + ( + "button.i4_edrive40_activate_air_conditioning", + "switch.i4_edrive40_climate", + "on", + "off", + "climate-now", + {"action": "START"}, + ), + ( + "button.i4_edrive40_deactivate_air_conditioning", + "switch.i4_edrive40_climate", + "off", + "on", + "climate-now", + {"action": "STOP"}, + ), + ( + "button.i4_edrive40_find_vehicle", + "device_tracker.i4_edrive40", + "not_home", + "home", + "vehicle-finder", + {}, + ), + ], +) +async def test_service_call_success_state_change( + hass: HomeAssistant, + entity_id: str, + state_entity_id: str, + new_value: str, + old_value: str, + remote_service: str, + remote_service_params: dict, + bmw_fixture: respx.Router, +) -> None: + """Test successful button press with state change.""" + + # Setup component + assert await setup_mocked_integration(hass) + hass.states.async_set(state_entity_id, old_value) + assert hass.states.get(state_entity_id).state == old_value + + # Test + await hass.services.async_call( + "button", + "press", + blocking=True, + target={"entity_id": entity_id}, + ) + check_remote_service_call(bmw_fixture, remote_service, remote_service_params) + assert hass.states.get(state_entity_id).state == new_value + + +@pytest.mark.parametrize( + ("entity_id", "state_entity_id", "new_attrs", "old_attrs"), + [ + ( + "button.i4_edrive40_find_vehicle", + "device_tracker.i4_edrive40", + {"latitude": 123.456, "longitude": 34.5678, "direction": 121}, + {"latitude": 48.177334, "longitude": 11.556274, "direction": 180}, + ), + ], +) +async def test_service_call_success_attr_change( + hass: HomeAssistant, + entity_id: str, + state_entity_id: str, + new_attrs: dict, + old_attrs: dict, + bmw_fixture: respx.Router, +) -> None: + """Test successful button press with attribute change.""" + + # Setup component + assert await setup_mocked_integration(hass) + + assert { + k: v + for k, v in hass.states.get(state_entity_id).attributes.items() + if k in old_attrs + } == old_attrs + + # Test + await hass.services.async_call( + "button", + "press", + blocking=True, + target={"entity_id": entity_id}, + ) + check_remote_service_call(bmw_fixture) + assert { + k: v + for k, v in hass.states.get(state_entity_id).attributes.items() + if k in new_attrs + } == new_attrs diff --git a/tests/components/bmw_connected_drive/test_number.py b/tests/components/bmw_connected_drive/test_number.py index d8cd5d47867..bcd880fa0a6 100644 --- a/tests/components/bmw_connected_drive/test_number.py +++ b/tests/components/bmw_connected_drive/test_number.py @@ -7,13 +7,10 @@ import pytest import respx from syrupy.assertion import SnapshotAssertion -from homeassistant.components.bmw_connected_drive.coordinator import ( - BMWDataUpdateCoordinator, -) from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError -from . import setup_mocked_integration +from . import check_remote_service_call, setup_mocked_integration async def test_entity_state_attrs( @@ -31,33 +28,36 @@ async def test_entity_state_attrs( @pytest.mark.parametrize( - ("entity_id", "value"), + ("entity_id", "new_value", "old_value", "remote_service"), [ - ("number.i4_edrive40_target_soc", "80"), + ("number.i4_edrive40_target_soc", "80", "100", "charging-settings"), ], ) -async def test_update_triggers_success( +async def test_service_call_success( hass: HomeAssistant, entity_id: str, - value: str, + new_value: str, + old_value: str, + remote_service: str, bmw_fixture: respx.Router, ) -> None: - """Test allowed values for number inputs.""" + """Test successful number change.""" # Setup component assert await setup_mocked_integration(hass) - BMWDataUpdateCoordinator.async_update_listeners.reset_mock() + hass.states.async_set(entity_id, old_value) + assert hass.states.get(entity_id).state == old_value # Test await hass.services.async_call( "number", "set_value", - service_data={"value": value}, + service_data={"value": new_value}, blocking=True, target={"entity_id": entity_id}, ) - assert RemoteServices.trigger_remote_service.call_count == 1 - assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 1 + check_remote_service_call(bmw_fixture, remote_service) + assert hass.states.get(entity_id).state == new_value @pytest.mark.parametrize( @@ -66,7 +66,7 @@ async def test_update_triggers_success( ("number.i4_edrive40_target_soc", "81"), ], ) -async def test_update_triggers_fail( +async def test_service_call_invalid_input( hass: HomeAssistant, entity_id: str, value: str, @@ -76,7 +76,7 @@ async def test_update_triggers_fail( # Setup component assert await setup_mocked_integration(hass) - BMWDataUpdateCoordinator.async_update_listeners.reset_mock() + old_value = hass.states.get(entity_id).state # Test with pytest.raises(ValueError): @@ -87,8 +87,7 @@ async def test_update_triggers_fail( blocking=True, target={"entity_id": entity_id}, ) - assert RemoteServices.trigger_remote_service.call_count == 0 - assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 0 + assert hass.states.get(entity_id).state == old_value @pytest.mark.parametrize( @@ -99,18 +98,19 @@ async def test_update_triggers_fail( (ValueError, ValueError), ], ) -async def test_update_triggers_exceptions( +async def test_service_call_fail( hass: HomeAssistant, raised: Exception, expected: Exception, bmw_fixture: respx.Router, monkeypatch: pytest.MonkeyPatch, ) -> None: - """Test not allowed values for number inputs.""" + """Test exception handling.""" # Setup component assert await setup_mocked_integration(hass) - BMWDataUpdateCoordinator.async_update_listeners.reset_mock() + entity_id = "number.i4_edrive40_target_soc" + old_value = hass.states.get(entity_id).state # Setup exception monkeypatch.setattr( @@ -126,7 +126,6 @@ async def test_update_triggers_exceptions( "set_value", service_data={"value": "80"}, blocking=True, - target={"entity_id": "number.i4_edrive40_target_soc"}, + target={"entity_id": entity_id}, ) - assert RemoteServices.trigger_remote_service.call_count == 1 - assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 0 + assert hass.states.get(entity_id).state == old_value diff --git a/tests/components/bmw_connected_drive/test_select.py b/tests/components/bmw_connected_drive/test_select.py index 97da6f81d6e..2dbe66139b2 100644 --- a/tests/components/bmw_connected_drive/test_select.py +++ b/tests/components/bmw_connected_drive/test_select.py @@ -7,13 +7,10 @@ import pytest import respx from syrupy.assertion import SnapshotAssertion -from homeassistant.components.bmw_connected_drive.coordinator import ( - BMWDataUpdateCoordinator, -) from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError -from . import setup_mocked_integration +from . import check_remote_service_call, setup_mocked_integration async def test_entity_state_attrs( @@ -31,44 +28,58 @@ async def test_entity_state_attrs( @pytest.mark.parametrize( - ("entity_id", "value"), + ("entity_id", "new_value", "old_value", "remote_service"), [ - ("select.i3_rex_charging_mode", "IMMEDIATE_CHARGING"), - ("select.i4_edrive40_ac_charging_limit", "16"), - ("select.i4_edrive40_charging_mode", "DELAYED_CHARGING"), + ( + "select.i3_rex_charging_mode", + "IMMEDIATE_CHARGING", + "DELAYED_CHARGING", + "charging-profile", + ), + ("select.i4_edrive40_ac_charging_limit", "12", "16", "charging-settings"), + ( + "select.i4_edrive40_charging_mode", + "DELAYED_CHARGING", + "IMMEDIATE_CHARGING", + "charging-profile", + ), ], ) -async def test_update_triggers_success( +async def test_service_call_success( hass: HomeAssistant, entity_id: str, - value: str, + new_value: str, + old_value: str, + remote_service: str, bmw_fixture: respx.Router, ) -> None: - """Test allowed values for select inputs.""" + """Test successful input change.""" # Setup component assert await setup_mocked_integration(hass) - BMWDataUpdateCoordinator.async_update_listeners.reset_mock() + hass.states.async_set(entity_id, old_value) + assert hass.states.get(entity_id).state == old_value # Test await hass.services.async_call( "select", "select_option", - service_data={"option": value}, + service_data={"option": new_value}, blocking=True, target={"entity_id": entity_id}, ) - assert RemoteServices.trigger_remote_service.call_count == 1 - assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 1 + check_remote_service_call(bmw_fixture, remote_service) + assert hass.states.get(entity_id).state == new_value @pytest.mark.parametrize( ("entity_id", "value"), [ ("select.i4_edrive40_ac_charging_limit", "17"), + ("select.i4_edrive40_charging_mode", "BONKERS_MODE"), ], ) -async def test_update_triggers_fail( +async def test_service_call_invalid_input( hass: HomeAssistant, entity_id: str, value: str, @@ -78,7 +89,7 @@ async def test_update_triggers_fail( # Setup component assert await setup_mocked_integration(hass) - BMWDataUpdateCoordinator.async_update_listeners.reset_mock() + old_value = hass.states.get(entity_id).state # Test with pytest.raises(ValueError): @@ -89,8 +100,7 @@ async def test_update_triggers_fail( blocking=True, target={"entity_id": entity_id}, ) - assert RemoteServices.trigger_remote_service.call_count == 0 - assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 0 + assert hass.states.get(entity_id).state == old_value @pytest.mark.parametrize( @@ -101,17 +111,19 @@ async def test_update_triggers_fail( (ValueError, ValueError), ], ) -async def test_remote_service_exceptions( +async def test_service_call_fail( hass: HomeAssistant, raised: Exception, expected: Exception, bmw_fixture: respx.Router, monkeypatch: pytest.MonkeyPatch, ) -> None: - """Test exception handling for remote services.""" + """Test exception handling.""" # Setup component assert await setup_mocked_integration(hass) + entity_id = "select.i4_edrive40_ac_charging_limit" + old_value = hass.states.get(entity_id).state # Setup exception monkeypatch.setattr( @@ -127,6 +139,6 @@ async def test_remote_service_exceptions( "select_option", service_data={"option": "16"}, blocking=True, - target={"entity_id": "select.i4_edrive40_ac_charging_limit"}, + target={"entity_id": entity_id}, ) - assert RemoteServices.trigger_remote_service.call_count == 1 + assert hass.states.get(entity_id).state == old_value diff --git a/tests/components/bmw_connected_drive/test_sensor.py b/tests/components/bmw_connected_drive/test_sensor.py index 03f836529be..95b1145d9d6 100644 --- a/tests/components/bmw_connected_drive/test_sensor.py +++ b/tests/components/bmw_connected_drive/test_sensor.py @@ -26,8 +26,8 @@ from . import setup_mocked_integration ("sensor.i3_rex_remaining_fuel", IMPERIAL, "1.59", "gal"), ("sensor.i3_rex_remaining_range_fuel", METRIC, "105", "km"), ("sensor.i3_rex_remaining_range_fuel", IMPERIAL, "65.24", "mi"), - ("sensor.i3_rex_remaining_fuel_percent", METRIC, "65", "%"), - ("sensor.i3_rex_remaining_fuel_percent", IMPERIAL, "65", "%"), + ("sensor.m340i_xdrive_remaining_fuel_percent", METRIC, "80", "%"), + ("sensor.m340i_xdrive_remaining_fuel_percent", IMPERIAL, "80", "%"), ], ) async def test_unit_conversion( diff --git a/tests/components/bmw_connected_drive/test_switch.py b/tests/components/bmw_connected_drive/test_switch.py index 26de4d3b6e8..c050f4b6cc2 100644 --- a/tests/components/bmw_connected_drive/test_switch.py +++ b/tests/components/bmw_connected_drive/test_switch.py @@ -7,13 +7,10 @@ import pytest import respx from syrupy.assertion import SnapshotAssertion -from homeassistant.components.bmw_connected_drive.coordinator import ( - BMWDataUpdateCoordinator, -) from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError -from . import setup_mocked_integration +from . import check_remote_service_call, setup_mocked_integration async def test_entity_state_attrs( @@ -25,42 +22,45 @@ async def test_entity_state_attrs( # Setup component assert await setup_mocked_integration(hass) - BMWDataUpdateCoordinator.async_update_listeners.reset_mock() # Get all switch entities assert hass.states.async_all("switch") == snapshot @pytest.mark.parametrize( - ("entity_id", "value"), + ("entity_id", "new_value", "old_value", "remote_service", "remote_service_params"), [ - ("switch.i4_edrive40_climate", "ON"), - ("switch.i4_edrive40_climate", "OFF"), - ("switch.i4_edrive40_charging", "ON"), - ("switch.i4_edrive40_charging", "OFF"), + ("switch.i4_edrive40_climate", "on", "off", "climate-now", {"action": "START"}), + ("switch.i4_edrive40_climate", "off", "on", "climate-now", {"action": "STOP"}), + ("switch.iX_xdrive50_charging", "on", "off", "start-charging", {}), + ("switch.iX_xdrive50_charging", "off", "on", "stop-charging", {}), ], ) -async def test_update_triggers_success( +async def test_service_call_success( hass: HomeAssistant, entity_id: str, - value: str, + new_value: str, + old_value: str, + remote_service: str, + remote_service_params: dict, bmw_fixture: respx.Router, ) -> None: - """Test allowed values for switch inputs.""" + """Test successful switch change.""" # Setup component assert await setup_mocked_integration(hass) - BMWDataUpdateCoordinator.async_update_listeners.reset_mock() + hass.states.async_set(entity_id, old_value) + assert hass.states.get(entity_id).state == old_value # Test await hass.services.async_call( "switch", - f"turn_{value.lower()}", + f"turn_{new_value}", blocking=True, target={"entity_id": entity_id}, ) - assert RemoteServices.trigger_remote_service.call_count == 1 - assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 1 + check_remote_service_call(bmw_fixture, remote_service, remote_service_params) + assert hass.states.get(entity_id).state == new_value @pytest.mark.parametrize( @@ -71,18 +71,18 @@ async def test_update_triggers_success( (ValueError, ValueError), ], ) -async def test_update_triggers_exceptions( +async def test_service_call_fail( hass: HomeAssistant, raised: Exception, expected: Exception, bmw_fixture: respx.Router, monkeypatch: pytest.MonkeyPatch, ) -> None: - """Test not allowed values for switch inputs.""" + """Test exception handling.""" # Setup component assert await setup_mocked_integration(hass) - BMWDataUpdateCoordinator.async_update_listeners.reset_mock() + entity_id = "switch.i4_edrive40_climate" # Setup exception monkeypatch.setattr( @@ -91,20 +91,32 @@ async def test_update_triggers_exceptions( AsyncMock(side_effect=raised), ) + # Turning switch to ON + old_value = "off" + hass.states.async_set(entity_id, old_value) + assert hass.states.get(entity_id).state == old_value + # Test with pytest.raises(expected): await hass.services.async_call( "switch", "turn_on", blocking=True, - target={"entity_id": "switch.i4_edrive40_climate"}, + target={"entity_id": entity_id}, ) + assert hass.states.get(entity_id).state == old_value + + # Turning switch to OFF + old_value = "on" + hass.states.async_set(entity_id, old_value) + assert hass.states.get(entity_id).state == old_value + + # Test with pytest.raises(expected): await hass.services.async_call( "switch", "turn_off", blocking=True, - target={"entity_id": "switch.i4_edrive40_climate"}, + target={"entity_id": entity_id}, ) - assert RemoteServices.trigger_remote_service.call_count == 2 - assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 0 + assert hass.states.get(entity_id).state == old_value