### Initialize and Start CardataCoordinator Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Set up the CardataCoordinator for state management and message dispatch. Start the watchdog to monitor connection and data updates. ```python from custom_components.cardata.coordinator import CardataCoordinator from custom_components.cardata.descriptor_state import DescriptorState coordinator = CardataCoordinator(hass=hass, entry_id="ENTRY_ID") await coordinator.async_start_watchdog() ``` -------------------------------- ### Iterate All Descriptors for Platform Setup Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Iterate through all registered descriptors for a given VIN to set up entity platforms. Supports filtering for binary sensors. ```python # Iterate all registered descriptors for entity platform setup for vin, descriptor in coordinator.iter_descriptors(binary=False): print(f"Sensor: {vin} → {descriptor}") for vin, descriptor in coordinator.iter_descriptors(binary=True): print(f"Binary sensor: {vin} → {descriptor}") ``` -------------------------------- ### Container Management - Get All Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/cardata_api_documentation.md Retrieves all information about your created containers. ```APIDOC ## GET /customers/containers/ ### Description Retrieves all information about your created containers. A container can either have the state ACTIVE or INACTIVE. Data retrieval is only achievable for containers with the state ACTIVE. ### Method GET ### Endpoint /customers/containers/ ``` -------------------------------- ### External Power Meter Injection Automation Example Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/README.md Example Home Assistant automation to call the `cardata.update_charging_power` service when the external power meter's sensor state changes and the car is home. ```APIDOC ## Automation Example ### Description This automation triggers when the power meter sensor changes and the car is detected as home, then calls the `cardata.update_charging_power` service. ### Trigger - Platform: state Entity ID: sensor.my_ev_meter_power ### Condition - Condition: state Entity ID: device_tracker.my_bmw State: home ### Action - Service: cardata.update_charging_power Data: vin: "WBY31AW090FP15359" power_kw: "{{ states('sensor.my_ev_meter_power') | float / 1000 }}" ``` -------------------------------- ### GET Vehicle Image API Call Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Retrieves the image of a vehicle. Requires an access token, specifies the API version, and sets the Accept header. ```bash curl -X GET "https://api-cardata.bmwgroup.com/customer/vehicles/WBY31AW090FP15359/image" \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "x-version: v1" \ -H "Accept: */*" ``` -------------------------------- ### Manage BMW CarData Stream Connection Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Set up message and status callbacks, start the connection, update credentials, and gracefully shut down the stream. Handles global locks and transparent reconnections. ```python stream.set_message_callback(coordinator.async_handle_message) stream.set_status_callback(coordinator.async_handle_connection_event) # Start connection (uses global lock, blocks bootstrap until metadata is ready) await stream.async_start() # Update credentials after token refresh (reconnects transparently) await stream.async_update_credentials( gcid="NEW_GCID", id_token="NEW_ID_TOKEN", ) # Graceful shutdown await stream.async_stop() ``` -------------------------------- ### Example API Response with Timestamp Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/cardata_api_documentation.md This JSON structure represents a typical response from the BMW CarData API, including a data point's name, its timestamp, and unit of measurement. ```json { "name: "vehicle.cabin.infotainment.navigation.currentLocation.longitude", "timestamp": ""2025-07-28T05:16:53.000Z", "unit": “degrees”, } ``` -------------------------------- ### Full BMW CarData Vehicle Card YAML Configuration Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/README.md This comprehensive example includes all available options for the BMW CarData vehicle card. Customize 'license_plate' and other boolean flags to tailor the card's appearance and functionality. ```yaml type: custom:bmw-cardata-vehicle-card device_id: abcdef1234567890abcdef1234567890 license_plate: AB 123 CD soc_source: predicted show_indicators: true show_range: true show_image: true show_map: true show_buttons: true ``` -------------------------------- ### OAuth 2.0 Device Code Flow - Poll for Tokens (curl) Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Example using curl to poll for access and refresh tokens after a user has approved the device authorization request. ```bash # Step 2 – Poll for tokens (repeat until approved or expired) curl --request POST \ --url https://customer.bmwgroup.com/gcdm/oauth/token \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data 'client_id=31C3B263-A9B7-4C8E-B123-456789ABCDEF' \ --data 'device_code=DEVICE_CODE_FROM_STEP1' \ --data 'grant_type=urn:ietf:params:oauth:grant-type:device_code' \ --data 'code_verifier=YOUR_86_CHAR_RANDOM_VERIFIER' # Response: access_token, refresh_token, id_token, gcid, expires_in, scope ``` -------------------------------- ### BMW CarData API: Get Static Vehicle Metadata Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Fetch basic metadata for a specific vehicle, such as model, brand, and series, using its VIN. Requires Bearer token authentication and specific headers. ```bash # GET static vehicle metadata (model, brand, series, etc.) curl -X GET "https://api-cardata.bmwgroup.com/customers/vehicles/WBY31AW090FP15359/basicData" \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "x-version: v1" ``` -------------------------------- ### OAuth 2.0 Device Code Flow - Refresh Tokens (curl) Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Example using curl to refresh access and ID tokens before they expire, using the provided refresh token. ```bash # Step 3 – Refresh tokens before expiry (access/id tokens valid 1 hour) curl --request POST \ --url https://customer.bmwgroup.com/gcdm/oauth/token \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data 'grant_type=refresh_token' \ --data 'refresh_token=YOUR_REFRESH_TOKEN' \ --data 'client_id=31C3B263-A9B7-4C8E-B123-456789ABCDEF' ``` -------------------------------- ### Get Magic SOC (Driving Prediction) from CardataCoordinator Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Retrieve the 'Magic SOC' which represents driving predictions. This feature must be enabled and active to return a value. ```python # Get Magic SOC (driving prediction) magic_soc = coordinator.get_magic_soc("WBY31AW090FP15359") # Returns float or None if not enabled/active ``` -------------------------------- ### BMW CarData REST API Endpoints Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Details on how to interact with the BMW CarData REST API, including required headers, rate limits, and example requests. ```APIDOC ## BMW CarData REST API Endpoints ### Base URL `https://api-cardata.bmwgroup.com` (v1) ### Authentication Bearer token authentication. ### Rate Limiting 50 calls/day (HTTP 429 / CU-429). ### Required Headers - `Authorization: Bearer ACCESS_TOKEN` - `x-version: v1` - `Accept: application/json` ### Endpoints #### GET vehicle mappings Retrieves primary and secondary ownership information per VIN. ```bash curl -X GET "https://api-cardata.bmwgroup.com/customers/vehicles/mappings" \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "x-version: v1" \ -H "Accept: application/json" ``` *Response Example*: `list of {vin, mappingType: "PRIMARY"|"SECONDARY", ...}` #### GET static vehicle metadata Retrieves basic metadata for a vehicle. ```bash curl -X GET "https://api-cardata.bmwgroup.com/customers/vehicles/WBY31AW090FP15359/basicData" \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "x-version: v1" ``` #### GET telematics data Retrieves telematics data for a specific container ID. ```bash curl -X GET "https://api-cardata.bmwgroup.com/customers/vehicles/WBY31AW090FP15359/telematicData?containerId=CONTAINER_ID" \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "x-version: v1" ``` *Response Example*: `{ "name": "vehicle.cabin.infotainment.navigation.currentLocation.longitude", "timestamp": "2025-05-17T12:00:00.000Z", ... }` ``` -------------------------------- ### OAuth 2.0 Device Code Flow - Request Device Code (curl) Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Example using curl to initiate the OAuth 2.0 Device Authorization Grant flow by requesting a device code from the BMW CarData API. ```bash # Equivalent manual curl flow for Step 1 – Request device code # POST https://customer.bmwgroup.com/gcdm/oauth/device/code curl --request POST \ --url https://customer.bmwgroup.com/gcdm/oauth/device/code \ --header 'Accept: application/json' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data 'client_id=31C3B263-A9B7-4C8E-B123-456789ABCDEF' \ --data 'response_type=device_code' \ --data 'scope=authenticate_user openid cardata:api:read cardata:streaming:read' \ --data 'code_challenge=BASE64URL_SHA256_OF_VERIFIER' \ --data 'code_challenge_method=S256' # Response includes: device_code, user_code, verification_uri_complete, interval, expires_in ``` -------------------------------- ### BMW CarData API: Get Vehicle Mappings Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Retrieve a list of vehicles associated with the account, including VIN and ownership type (PRIMARY/SECONDARY). Requires Bearer token authentication. ```bash # Required headers for all API requests: # Authorization: Bearer ACCESS_TOKEN # x-version: v1 # Accept: application/json # GET vehicle mappings (PRIMARY/SECONDARY ownership per VIN) curl -X GET "https://api-cardata.bmwgroup.com/customers/vehicles/mappings" \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "x-version: v1" \ -H "Accept: application/json" # Response: list of {vin, mappingType: "PRIMARY"|"SECONDARY", ...} ``` -------------------------------- ### GET Tyre Diagnosis API Call Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Retrieves smart maintenance tyre diagnosis data for a vehicle. Requires an access token and specifies the API version. ```bash curl -X GET "https://api-cardata.bmwgroup.com/customer/vehicles/WBY31AW090FP15359/smartMaintenanceTyreDiagnosis" \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "x-version: v1" ``` -------------------------------- ### Get Predicted SOC from CardataCoordinator Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Retrieve the predicted State of Charge (SOC) for a given VIN. This can be either a charging prediction or a direct passthrough from BMW. ```python # Get predicted SOC (charging prediction or BMW passthrough) predicted_soc = coordinator.get_predicted_soc("WBY31AW090FP15359") # Returns float (e.g. 83.5) or None ``` -------------------------------- ### GET Charging History API Call Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Retrieves the charging history for a vehicle for the last 30 days. Requires an access token and specifies the API version. ```bash curl -X GET "https://api-cardata.bmwgroup.com/customers/vehicles/WBY31AW090FP15359/chargingHistory" \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "x-version: v1" ``` -------------------------------- ### Home Assistant: Fetch Basic Vehicle Data Service Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Calls the GET /customers/vehicles/{vin}/basicData API endpoint and updates the device registry with manufacturer, model, serial number, etc. This service is part of the 'cardata' domain. ```yaml service: cardata.fetch_basic_data data: vin: "WBY31AW090FP15359" ``` -------------------------------- ### Instantiate CardataStreamManager for Direct Mode Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Python code to instantiate the CardataStreamManager for connecting to BMW's direct MQTT stream. Requires Home Assistant instance, client ID, GCID, ID token, and host details. ```python from custom_components.cardata.stream import CardataStreamManager # Instantiate for BMW direct mode stream = CardataStreamManager( hass=hass, client_id="31C3B263-A9B7-4C8E-B123-456789ABCDEF", gcid="GCID_FROM_TOKEN_RESPONSE", id_token="ID_TOKEN_FROM_TOKEN_RESPONSE", host="customer.streaming-cardata.bmwgroup.com", port=9000, keepalive=30, error_callback=my_error_handler, entry_id="CONFIG_ENTRY_ID", ) ``` -------------------------------- ### Configure Options Flow Menu Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt This YAML snippet outlines the available options in the Home Assistant integration's configuration menu. These options can be changed without restarting the code. ```yaml # Available Configure menu options and their effect: # ┌─────────────────────────────────────────────────────────────────────┐ # │ Refresh tokens → Force token refresh + MQTT credential swap│ # │ Start device auth again → Trigger full Device Code Flow reauth │ # │ Initiate vehicles (API) → Call GET /mappings to discover VINs │ # │ Get basic vehicle info → Call GET /basicData for all VINs │ # │ Get telematics data → Call GET /telematicData for active VINs │ # │ Reset telemetry container → Delete + recreate BMW container │ # │ Clean up orphaned entities → Remove stale entities from registry │ # │ MQTT Broker → Switch to custom MQTT broker │ ``` -------------------------------- ### CardataStreamManager Usage Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Demonstrates how to initialize and use the CardataStreamManager for connecting and managing data streams, including updating credentials and graceful shutdown. ```APIDOC ## CardataStreamManager ### Description Manages the connection and message callbacks for the BMW CarData stream. ### Methods - `set_message_callback(callback)`: Sets the callback for incoming messages. - `set_status_callback(callback)`: Sets the callback for connection status events. - `async_start()`: Starts the connection. Blocks until metadata is ready. - `async_update_credentials(gcid, id_token)`: Updates credentials and reconnects transparently. - `async_stop()`: Gracefully shuts down the connection. ### Initialization with Custom Broker ```python stream_custom = CardataStreamManager( hass=hass, client_id="...", gcid="...", id_token="...", host="192.168.1.100", port=1883, keepalive=30, custom_broker=True, custom_mqtt_username="user", custom_mqtt_password="pass", custom_mqtt_tls="off", # "off" | "tls" | "tls_insecure" custom_mqtt_topic_prefix="bmw/", ) ``` ### Debugging `stream.debug_info`: Inspects the connection state. ``` -------------------------------- ### Request Device Codes via POST /gcdm/oauth/device/code Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/cardata_api_documentation.md Use this cURL command to initiate the authorization process for a specific device. Ensure you replace placeholders with your generated client ID and code challenge. The response provides user and device codes for subsequent steps. ```bash curl --request POST \ --url https://customer.bmwgroup.com/gcdm/oauth/device/code \ --header 'Accept: application/json' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data client_id=cj5b3499-4918-40x6-a232-f4112f837d72 \ --data response_type=device_code \ --data 'scope=authenticate_user openid cardata:streaming:read cardata:api:read' \ --data code_challenge=yourCodeChallenge \ --data code_challenge_method=S256 \ ``` -------------------------------- ### Configure Custom BMW CarData Broker Mode Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Initialize CardataStreamManager for custom broker mode, specifying connection details and authentication for a local MQTT bridge. Supports TLS and topic prefix configuration. ```python stream_custom = CardataStreamManager( hass=hass, client_id="...", gcid="...", id_token="...", host="192.168.1.100", port=1883, keepalive=30, custom_broker=True, custom_mqtt_username="user", custom_mqtt_password="pass", custom_mqtt_tls="off", # "off" | "tls" | "tls_insecure" custom_mqtt_topic_prefix="bmw/", ) ``` -------------------------------- ### Retrieve Descriptor State from CardataCoordinator Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Get the state of a specific vehicle descriptor using the VIN and descriptor name. Returns the value, unit, and timestamp if available. ```python state: DescriptorState | None = coordinator.get_state( "WBY31AW090FP15359", "vehicle.drivetrain.batteryManagement.header" ) # state.value = 78, state.unit = "%", state.timestamp = "2025-05-17T12:00:00.000Z" ``` -------------------------------- ### Display Default Consumption and Capacity by Model Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt This Python snippet demonstrates how to access and print the default battery consumption and capacity data by model, which are used as fallbacks by the integration. ```python from custom_components.cardata.const import ( DEFAULT_CONSUMPTION_BY_MODEL, DEFAULT_CAPACITY_BY_MODEL, ) # Lookup is by prefix-match against modelName/series (longest match first) # Example entries: print(DEFAULT_CONSUMPTION_BY_MODEL) # { # "i4 eDrive40": 0.18, # kWh/km # "i4 M50": 0.21, # "iX xDrive50": 0.22, # "iX M60": 0.24, # "i7 xDrive60": 0.21, # "iX3 50 xDrive": 0.19, # ... # } print(DEFAULT_CAPACITY_BY_MODEL) # { # "i4 eDrive40": 80.7, # usable kWh # "i4 eDrive35": 59.4, # "iX xDrive40": 71.0, # "iX M60": 105.2, # "i7 M70": 101.7, # ... # } ``` -------------------------------- ### Configure BMW CarData Integration Settings Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt These settings control optional features and MQTT broker configuration for the BMW CarData integration. Ensure correct values are set for your desired functionality. ```yaml enable_magic_soc: false # Driving SOC prediction (BEV only) enable_charging_history: false # Daily charging session history fetch enable_tyre_diagnosis: false # Daily tyre health data fetch enable_trip_end_polling: true # Immediate API poll when trip ends trip_poll_cooldown_minutes: 10 # Minimum gap between trip-end polls enable_external_power_injection: false # Accept smart meter power via service custom_mqtt_enabled: false custom_mqtt_host: "192.168.1.100" custom_mqtt_port: 1883 custom_mqtt_username: "" # empty for anonymous custom_mqtt_password: "" custom_mqtt_tls: "off" # "off" | "tls" | "tls_insecure" custom_mqtt_topic_prefix: "bmw/" # messages expected at {prefix}{VIN} ``` -------------------------------- ### Home Assistant: Fetch Vehicle Mappings Service Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Calls the GET /customers/vehicles/mappings API endpoint and logs PRIMARY/SECONDARY mapping information. This service is part of the 'cardata' domain. ```yaml service: cardata.fetch_vehicle_mappings data: entry_id: "01K65NKFESKBQZ78PBW6V9BCCX" ``` -------------------------------- ### Container Management - Create Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/cardata_api_documentation.md Creates a new container for managing telematics data. ```APIDOC ## POST /customers/containers/ ### Description Creates one or more containers for managing telematics data. Use the telematics data catalogue for the correct syntax concerning the technicalDescriptor for a telematic data key. ### Method POST ### Endpoint /customers/containers/ ### Parameters #### Request Body - **technicalDescriptor** (string) - Required - The descriptor for the telematic data key. ``` -------------------------------- ### SOC Predictor for Charging Sessions (Python) Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Manage and predict State of Charge during AC or DC charging sessions. Anchor sessions with initial parameters, update power readings, and end sessions to trigger efficiency learning. ```python from custom_components.cardata.soc_prediction import SOCPredictor predictor = SOCPredictor() # Anchor a charging session (called when charging.status becomes CHARGINGACTIVE) predictor.anchor_session( vin="WBY31AW090FP15359", anchor_soc=55.0, # BMW-reported SOC at charge start (%) capacity_kwh=80.7, # battery capacity (from maxEnergy or model default) target_soc=80.0, # charging target (from charging.level) timestamp="2025-05-17T10:00:00.000Z", is_phev=False, charging_method="AC", # "AC" or "DC" phases=3, voltage=230, current=16, ) # Update power reading (called on each charging.power descriptor update) predictor.update_power_reading( vin="WBY31AW090FP15359", power_kw=11.0, aux_power_kw=0.0, from_local=False, # True when injected via update_charging_power service ) # Get current predicted SOC soc = predictor.get_predicted_soc("WBY31AW090FP15359") # Returns float (e.g. 63.5) or None if no active session # Check charging state print(predictor.is_charging("WBY31AW090FP15359")) # True # End session and trigger efficiency learning predictor.end_session( vin="WBY31AW090FP15359", final_bmw_soc=80.0, timestamp="2025-05-17T12:30:00.000Z", ) # Efficiency constants and learning bounds # SOCPredictor.AC_EFFICIENCY = 0.90 (default, before learning) # SOCPredictor.DC_EFFICIENCY = 0.93 (default, before learning) # MIN_VALID_EFFICIENCY = 0.40, MAX_VALID_EFFICIENCY = 0.98 # MIN_LEARNING_SOC_GAIN = 5.0 (% minimum SOC gain to learn from session) ``` -------------------------------- ### Request Access Tokens using Device Code Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/cardata_api_documentation.md Use this cURL command to request access tokens after completing the device authentication flow. Ensure you replace placeholders with your actual client ID, device code, and code verifier. ```bash curl --request POST \ --url https://customer.bmwgroup.com/gcdm/oauth/token \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data client_id=cj5b3499-4918-40x6-a232-f4112f837d72 \ --data device_code=yourDeviceCode \ --data grant_type=urn:ietf:params:oauth:grant-type:device_code \ --data code_verifier=yourCodeVerifier ``` -------------------------------- ### Magic SOC Predictor for Driving Consumption (Python) Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Estimate battery drain during driving using odometer and learned consumption rates. Anchor driving sessions with initial parameters, update odometer and GPS, and end sessions to learn from trip data. ```python from custom_components.cardata.magic_soc import MagicSOCPredictor, LearnedConsumption predictor = MagicSOCPredictor() # Anchor a driving session (called when isMoving transitions True) predictor.anchor_driving_session( vin="WBY31AW090FP15359", anchor_soc=78.0, # BMW SOC at trip start odometer_km=15234.5, # trip-start odometer capacity_kwh=80.7, timestamp=time.time(), model_name="i4 eDrive40", # for per-model consumption defaults ) # Update odometer during trip (called on travelledDistance descriptor) predictor.update_odometer( vin="WBY31AW090FP15359", odometer_km=15267.3, timestamp=time.time(), ) # Update GPS position (triggers Haversine distance calculation as fallback) predictor.update_driving_gps( vin="WBY31AW090FP15359", lat=48.1351, lon=11.5820, ) # Get current driving SOC estimate soc = predictor.get_magic_soc("WBY31AW090FP15359") # Returns float (e.g. 73.2) or None # End driving session and learn from trip data predictor.end_driving_session( vin="WBY31AW090FP15359", final_bmw_soc=72.0, # BMW-confirmed SOC at trip end odometer_km=15267.3, timestamp=time.time(), ) ``` -------------------------------- ### BMW CarData API: Get Telematics Data Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Retrieve telematics data for a specific vehicle container using its VIN and container ID. Requires Bearer token authentication and specific headers. ```bash # GET telematics data for a container curl -X GET "https://api-cardata.bmwgroup.com/customers/vehicles/WBY31AW090FP15359/telematicData?containerId=CONTAINER_ID" \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "x-version: v1" # Response example: # { # "name": "vehicle.cabin.infotainment.navigation.currentLocation.longitude", # "timestamp": "2025-05-17T12:00:00.000Z", ``` -------------------------------- ### Import Telemetry Descriptor Constants Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Imports various descriptor constants from the custom_components.cardata.const module. These constants represent BMW telemetry paths and virtual sensor keys. ```python from custom_components.cardata.const import ( # SOC / battery descriptors DESC_SOC_HEADER, DESC_SOC_DISPLAYED, DESC_MAX_ENERGY, DESC_BATTERY_SIZE_MAX, DESC_CHARGING_STATUS, DESC_CHARGING_POWER, DESC_CHARGING_LEVEL, DESC_CHARGING_AC_VOLTAGE, DESC_CHARGING_AC_AMPERE, DESC_CHARGING_PHASES, # Trip / fuel descriptors DESC_TRAVELLED_DISTANCE, DESC_TRIP_HVSOC, DESC_REMAINING_FUEL, DESC_FUEL_LEVEL, # Location descriptors LOCATION_LATITUDE_DESCRIPTOR, LOCATION_LONGITUDE_DESCRIPTOR, # Virtual sensor keys (not from BMW, computed locally) PREDICTED_SOC_DESCRIPTOR, MAGIC_SOC_DESCRIPTOR, # API and MQTT endpoint constants API_BASE_URL, API_VERSION, DEFAULT_STREAM_HOST, DEFAULT_STREAM_PORT, DEVICE_CODE_URL, TOKEN_URL, DEFAULT_SCOPE, # Quota and timing TARGET_DAILY_POLLS, DEFAULT_REFRESH_INTERVAL, DEFAULT_TRIP_POLL_COOLDOWN_MINUTES, LOCAL_POWER_TTL_SECONDS, HTTP_TIMEOUT, MQTT_KEEPALIVE, # Container defaults HV_BATTERY_CONTAINER_NAME, HV_BATTERY_CONTAINER_PURPOSE, HV_BATTERY_DESCRIPTORS, ) ``` ```python from custom_components.cardata.const import ( OPTION_ENABLE_MAGIC_SOC, OPTION_ENABLE_CHARGING_HISTORY, OPTION_ENABLE_TYRE_DIAGNOSIS, OPTION_ENABLE_TRIP_POLL, OPTION_TRIP_POLL_COOLDOWN, OPTION_ENABLE_EXTERNAL_POWER, OPTION_CUSTOM_MQTT_ENABLED, OPTION_CUSTOM_MQTT_HOST, OPTION_CUSTOM_MQTT_PORT, OPTION_CUSTOM_MQTT_TLS, OPTION_CUSTOM_MQTT_TOPIC_PREFIX, ) ``` -------------------------------- ### Request Device Codes Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/cardata_api_documentation.md Initiates the authorization process for a specific device by requesting user and device codes. This is the first step in the Device Code Flow. ```APIDOC ## POST /gcdm/oauth/device/code ### Description Requests authorization codes (user_code and device_code) necessary for device authentication and subsequent token retrieval. ### Method POST ### Endpoint /gcdm/oauth/device/code ### Parameters #### Request Body - **client_id** (string) - Required - The client ID generated from the customer portal. - **response_type** (string) - Required - Must be 'device_code'. - **code_challenge** (string) - Required - A transformation of the code_verifier using the specified method. - **code_challenge_method** (string) - Required - Must be 'S256'. - **scope** (string) - Required - Space-separated list of requested scopes (e.g., 'authenticate_user openid cardata:streaming:read cardata:api:read'). ### Request Example ```curl curl --request POST \ --url https://customer.bmwgroup.com/gcdm/oauth/device/code \ --header 'Accept: application/json' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data client_id=cj5b3499-4918-40x6-a232-f4112f837d72 \ --data response_type=device_code \ --data 'scope=authenticate_user openid cardata:streaming:read cardata:api:read' \ --data code_challenge=yourCodeChallenge \ --data code_challenge_method=S256 ``` ### Response #### Success Response (200) - **user_code** (string) - The code displayed to the user for verification. - **device_code** (string) - The code used by the device to poll for tokens. - **interval** (integer) - Minimum seconds to wait between polling requests. - **expires_in** (integer) - Lifetime in seconds for device_code and user_code. - **verification_uri** (string) - The URI where the user authorizes the login. ``` -------------------------------- ### Enable Debug Logging in Custom Component Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/info.md Modify the `DEBUG_LOG` constant in the `custom_components/cardata/const.py` file to enable detailed logging for MQTT and authentication. Set to `False` to reduce log verbosity. ```python DEBUG_LOG = True ``` -------------------------------- ### Access Learned Consumption Data Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Retrieve and print learned consumption data for a specific VIN. This requires a pre-existing learned consumption model. ```python consumption: LearnedConsumption = predictor._learned.get("WBY31AW090FP15359") print(consumption.kwh_per_km) # e.g. 0.183 after learning print(consumption.trip_count) # number of completed learning trips ``` -------------------------------- ### Automate Descriptor Selection in Browser Console Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/README.md Use this JavaScript snippet in your browser's developer console to automatically select all available data descriptors on the BMW CarData portal. This can save time when configuring which data points to stream. ```javascript document.querySelectorAll('label.chakra-checkbox:not([data-checked])').forEach(l => l.click()); ``` -------------------------------- ### Automate Checkbox Selection in Browser Console Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/info.md Use this JavaScript snippet in your browser's developer console to automatically select all desired data descriptors on the BMW CarData portal. Ensure all necessary descriptors for features like 'Extrapolated SOC' are included. ```javascript (() => { const labels = document.querySelectorAll('.css-k008qs label.chakra-checkbox'); let changed = 0; labels.forEach(label => { const input = label.querySelector('input.chakra-checkbox__input[type="checkbox"]'); if (!input || input.disabled || input.checked) return; label.click(); if (!input.checked) { const ctrl = label.querySelector('.chakra-checkbox__control'); if (ctrl) ctrl.click(); } if (!input.checked) { input.checked = true; ['click', 'input', 'change'].forEach(type => input.dispatchEvent(new Event(type, { bubbles: true })) ); } if (input.checked) changed++; }); console.log(`Checked ${changed} of ${labels.length} checkboxes.`); })(); ``` -------------------------------- ### Home Assistant: Migrate Entity IDs Service Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt A developer tool to migrate entity IDs to include a model prefix. Supports dry run and force options. This service is part of the 'cardata' domain. ```yaml service: cardata.migrate_entity_ids data: dry_run: true # preview changes without applying force: false # force even if already migrated ``` -------------------------------- ### POST Create Telematic Container API Call Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Creates a new telematic container for a vehicle. Requires an access token, specifies the API version, and includes a JSON payload with container details. ```bash curl -X POST "https://api-cardata.bmwgroup.com/customers/containers" \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "x-version: v1" \ -H "Content-Type: application/json" \ -d '{ "name": "BMW CarData HV Battery", "purpose": "High voltage battery telemetry", "descriptors": [ "vehicle.drivetrain.batteryManagement.header", "vehicle.powertrain.electric.battery.charging.power", "vehicle.drivetrain.electricEngine.charging.status" ] }' ``` -------------------------------- ### Basic Vehicle Data Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/cardata_api_documentation.md Retrieves static vehicle metadata such as brand and model. ```APIDOC ## GET /customers/vehicles/{vin}/basicData ### Description Retrieves static vehicle metadata (brand, model, etc.). ### Method GET ### Endpoint /customers/vehicles/{vin}/basicData ### Parameters #### Path Parameters - **vin** (string) - Required - The Vehicle Identification Number. ``` -------------------------------- ### Lovelace Vehicle Card Configuration Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Configure the custom BMW Cardata vehicle card for your Home Assistant dashboard. Minimal configuration requires only the `type` and `device_id`. ```yaml # Minimal card configuration (YAML dashboard) type: custom:bmw-cardata-vehicle-card device_id: abcdef1234567890abcdef1234567890 ``` ```yaml # Full configuration with all options type: custom:bmw-cardata-vehicle-card device_id: abcdef1234567890abcdef1234567890 license_plate: "AB 123 CD" soc_source: predicted # "soc" (BMW last known) | "predicted" (charging) | "magic" (driving) show_indicators: true # locks, doors, windows, alarm status row show_range: true # battery/fuel bar with range show_image: true # vehicle image show_map: true # inline GPS map show_buttons: true # quick-info tiles (location, mileage, service) ``` -------------------------------- ### Home Assistant: Fetch Tyre Diagnosis Service Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Fetches per-wheel tyre health and wear data using one API call per VIN. This service is part of the 'cardata' domain. ```yaml service: cardata.fetch_tyre_diagnosis data: vin: "WBY31AW090FP15359" ``` -------------------------------- ### Home Assistant: Fetch Vehicle Images Service Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Manually fetches and caches vehicle images for all configured VINs. This service is part of the 'cardata' domain. ```yaml service: cardata.fetch_vehicle_images ``` -------------------------------- ### Retrieve Location-Based Charging Settings Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/cardata_api_documentation.md Retrieves location-based charging settings for an electric vehicle. ```APIDOC ## GET /customers/vehicles/locationBasedChargingSettings ### Description Retrieves location-based charging settings for an electric vehicle. Units are in KM. ### Method GET ### Endpoint /customers/vehicles/locationBasedChargingSettings ``` -------------------------------- ### Home Assistant: Fetch Charging History Service Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Fetches the last 30 days of charging sessions using one API call per VIN. This service is part of the 'cardata' domain. ```yaml service: cardata.fetch_charging_history data: vin: "WBY31AW090FP15359" ``` -------------------------------- ### Inspect BMW CarData Stream Connection State Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Print debug information about the current CarData stream connection, including broker mode, client ID, host, port, and protocol. ```python print(stream.debug_info) ``` -------------------------------- ### Retrieve Charging History Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/cardata_api_documentation.md Retrieves the charging history sessions for an electric vehicle. ```APIDOC ## GET /customer/vehicles/{vin}/chargingHistory ### Description Retrieves the charging history sessions for an electric vehicle. ### Method GET ### Endpoint /customer/vehicles/{vin}/chargingHistory ### Parameters #### Path Parameters - **vin** (string) - Required - The Vehicle Identification Number. ``` -------------------------------- ### Set Manual Battery Capacity Override Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Manually set the battery capacity in kWh for a specific VIN. This overrides any automatically detected capacity. ```python # Set manual battery capacity override (kWh) coordinator.set_manual_battery_capacity("WBY31AW090FP15359", 80.7) ``` -------------------------------- ### Home Assistant: Fetch Telematic Data Service Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Fetches current container data for a VIN via the API and logs the response. This service is part of the 'cardata' domain. ```yaml service: cardata.fetch_telematic_data data: entry_id: "01K65NKFESKBQZ78PBW6V9BCCX" # optional if only one entry vin: "WBY31AW090FP15359" # optional, defaults to first seen VIN ``` -------------------------------- ### BMW CarData Vehicle Card YAML Configuration to Hide Map and Buttons Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/README.md Configure the BMW CarData vehicle card to hide the map and quick-info buttons by setting 'show_map' and 'show_buttons' to false. This simplifies the card's display. ```yaml type: custom:bmw-cardata-vehicle-card device_id: abcdef1234567890abcdef1234567890 show_map: false show_buttons: false ``` -------------------------------- ### Home Assistant Automation for Charging Power Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Automate pushing charging power data to the BMW SOC predictor. This requires the `cardata.update_charging_power` service to be available. ```yaml automation: - alias: "Push smart meter power to BMW SOC predictor" trigger: - platform: state entity_id: sensor.wallbox_charging_power_w condition: - condition: state entity_id: device_tracker.my_bmw_i4 state: home action: - service: cardata.update_charging_power data: vin: "WBY31AW090FP15359" power_kw: > {{ (states('sensor.wallbox_charging_power_w') | float) / 1000 }} aux_power_kw: 0.0 ``` -------------------------------- ### Refresh Access Tokens using Refresh Token Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/cardata_api_documentation.md This cURL command demonstrates how to refresh your access and ID tokens using a valid refresh token. This is essential for maintaining authenticated access to CarData APIs. ```bash curl --request POST \ --url https://customer.bmwgroup.com/gcdm/oauth/token \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data grant_type=refresh_token \ --data refresh_token=yourRefreshToken \ --data client_id=cj5b3499-4918-40x6-a232-f4112f837d72 ``` -------------------------------- ### Handle Incoming BMW CarData Messages Source: https://context7.com/kvanbiesen/bmw-cardata-ha/llms.txt Process incoming MQTT or API messages using the CardataCoordinator. This involves parsing VIN and data payloads to update vehicle state. ```python payload = { "vin": "WBY31AW090FP15359", "data": { "vehicle.drivetrain.batteryManagement.header": { "value": 78, "unit": "%", "timestamp": "2025-05-17T12:00:00.000Z" }, "vehicle.drivetrain.electricEngine.charging.status": { "value": "CHARGINGACTIVE", "unit": None, "timestamp": "2025-05-17T12:00:00.000Z" }, } } await coordinator.async_handle_message(payload) ``` -------------------------------- ### Request Tokens Source: https://github.com/kvanbiesen/bmw-cardata-ha/blob/main/cardata_api_documentation.md After authenticating your device, you can request access tokens using the device code. This endpoint is used for both initial token requests and refreshing existing tokens. ```APIDOC ## POST /gcdm/oauth/token ### Description Requests access tokens, refresh tokens, and ID tokens. This endpoint is used for both the initial device authorization flow and for refreshing expired tokens. ### Method POST ### Endpoint https://customer.bmwgroup.com/gcdm/oauth/token ### Parameters #### Request Body - **Content-Type** (string) - Required - Use the fixed value as stated in the Swagger (application/x-www-form-urlencoded). - **client_id** (string) - Required - The generated client ID from the customer portal. - **device_code** (string) - Required (for initial token request) - Part of the response of POST /gcdm/oauth/device/code. - **grant_type** (string) - Required - Use the fixed value as stated in the Swagger. For initial token request, use `urn:ietf:params:oauth:grant-type:device_code`. For refreshing tokens, use `refresh_token`. - **code_verifier** (string) - Required (for initial token request) - See explanation from the code verifier chapter. - **refresh_token** (string) - Required (for token refresh) - The token used to refresh access and ID tokens. ### Request Example (Initial Token Request) ```curl curl --request POST \ --url https://customer.bmwgroup.com/gcdm/oauth/token \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data client_id=cj5b3499-4918-40x6-a232-f4112f837d72 \ --data device_code=yourDeviceCode \ --data grant_type=urn:ietf:params:oauth:grant-type:device_code \ --data code_verifier=yourCodeVerifier ``` ### Request Example (Token Refresh) ```curl curl --request POST \ --url https://customer.bmwgroup.com/gcdm/oauth/token \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data grant_type=refresh_token \ --data refresh_token=yourRefreshToken \ --data client_id=cj5b3499-4918-40x6-a232-f4112f837d72 ``` ### Response #### Success Response (200) - **access_token** (string) - Your token to access the CarData APIs. - **token_type** (string) - The type of the token (e.g., Bearer). - **expires_in** (integer) - The duration in seconds until the access token expires. - **refresh_token** (string) - The token to refresh your access token. - **scope** (string) - The given scope(s) of your token(s). - **id_token** (string) - Your token to access the CarData data stream. - **gcid** (string) - Your unique identifier of your portal user account. ```