mirror of
https://github.com/home-assistant/core.git
synced 2026-05-08 17:49:37 +01:00
Add diagnostics to Volvo integration (#153997)
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
"""Volvo diagnostics."""
|
||||
|
||||
from dataclasses import asdict
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_API_KEY
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.redact import async_redact_data
|
||||
|
||||
from .const import CONF_VIN
|
||||
from .coordinator import VolvoConfigEntry
|
||||
|
||||
_TO_REDACT_ENTRY = [
|
||||
CONF_ACCESS_TOKEN,
|
||||
CONF_API_KEY,
|
||||
CONF_VIN,
|
||||
"id_token",
|
||||
"refresh_token",
|
||||
]
|
||||
|
||||
_TO_REDACT_DATA = [
|
||||
"coordinates",
|
||||
"heading",
|
||||
"vin",
|
||||
]
|
||||
|
||||
|
||||
async def async_get_config_entry_diagnostics(
|
||||
hass: HomeAssistant, entry: VolvoConfigEntry
|
||||
) -> dict[str, Any]:
|
||||
"""Return diagnostics for a config entry."""
|
||||
context = entry.runtime_data.interval_coordinators[0].context
|
||||
data: dict[str, dict] = {}
|
||||
|
||||
for coordinator in entry.runtime_data.interval_coordinators:
|
||||
data[coordinator.name] = {
|
||||
key: async_redact_data(asdict(value), _TO_REDACT_DATA) if value else None
|
||||
for key, value in coordinator.data.items()
|
||||
}
|
||||
|
||||
return {
|
||||
"entry_data": async_redact_data(entry.data, _TO_REDACT_ENTRY),
|
||||
"vehicle": async_redact_data(asdict(context.vehicle), _TO_REDACT_DATA),
|
||||
**data,
|
||||
}
|
||||
@@ -0,0 +1,535 @@
|
||||
# serializer version: 1
|
||||
# name: test_entry_diagnostics[xc40_electric_2024]
|
||||
dict({
|
||||
'Volvo fast interval coordinator': dict({
|
||||
'centralLock': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:20:20.570000+00:00',
|
||||
'unit': None,
|
||||
'value': 'LOCKED',
|
||||
}),
|
||||
'frontLeftDoor': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:20:20.570000+00:00',
|
||||
'unit': None,
|
||||
'value': 'CLOSED',
|
||||
}),
|
||||
'frontLeftWindow': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:28:12.202000+00:00',
|
||||
'unit': None,
|
||||
'value': 'CLOSED',
|
||||
}),
|
||||
'frontRightDoor': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:20:20.570000+00:00',
|
||||
'unit': None,
|
||||
'value': 'CLOSED',
|
||||
}),
|
||||
'frontRightWindow': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:28:12.202000+00:00',
|
||||
'unit': None,
|
||||
'value': 'CLOSED',
|
||||
}),
|
||||
'hood': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:20:20.570000+00:00',
|
||||
'unit': None,
|
||||
'value': 'CLOSED',
|
||||
}),
|
||||
'rearLeftDoor': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:20:20.570000+00:00',
|
||||
'unit': None,
|
||||
'value': 'CLOSED',
|
||||
}),
|
||||
'rearLeftWindow': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:28:12.202000+00:00',
|
||||
'unit': None,
|
||||
'value': 'CLOSED',
|
||||
}),
|
||||
'rearRightDoor': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:20:20.570000+00:00',
|
||||
'unit': None,
|
||||
'value': 'CLOSED',
|
||||
}),
|
||||
'rearRightWindow': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:28:12.202000+00:00',
|
||||
'unit': None,
|
||||
'value': 'CLOSED',
|
||||
}),
|
||||
'sunroof': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:28:12.202000+00:00',
|
||||
'unit': None,
|
||||
'value': 'UNSPECIFIED',
|
||||
}),
|
||||
'tailgate': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:20:20.570000+00:00',
|
||||
'unit': None,
|
||||
'value': 'CLOSED',
|
||||
}),
|
||||
'tankLid': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:20:20.570000+00:00',
|
||||
'unit': None,
|
||||
'value': 'CLOSED',
|
||||
}),
|
||||
}),
|
||||
'Volvo medium interval coordinator': dict({
|
||||
'batteryChargeLevel': dict({
|
||||
'extra_data': dict({
|
||||
'updated_at': '2025-07-02T08:51:23Z',
|
||||
}),
|
||||
'status': 'OK',
|
||||
'timestamp': None,
|
||||
'unit': 'percentage',
|
||||
'value': 53,
|
||||
}),
|
||||
'chargerConnectionStatus': dict({
|
||||
'extra_data': dict({
|
||||
'updated_at': '2025-07-02T08:51:23Z',
|
||||
}),
|
||||
'status': 'OK',
|
||||
'timestamp': None,
|
||||
'unit': None,
|
||||
'value': 'CONNECTED',
|
||||
}),
|
||||
'chargerPowerStatus': dict({
|
||||
'extra_data': dict({
|
||||
'updated_at': '2025-07-02T08:51:23Z',
|
||||
}),
|
||||
'status': 'OK',
|
||||
'timestamp': None,
|
||||
'unit': None,
|
||||
'value': 'PROVIDING_POWER',
|
||||
}),
|
||||
'chargingCurrentLimit': dict({
|
||||
'extra_data': dict({
|
||||
'updated_at': '2024-03-05T08:38:44Z',
|
||||
}),
|
||||
'status': 'OK',
|
||||
'timestamp': None,
|
||||
'unit': 'ampere',
|
||||
'value': 32,
|
||||
}),
|
||||
'chargingPower': dict({
|
||||
'extra_data': dict({
|
||||
'updated_at': '2025-07-02T08:51:23Z',
|
||||
}),
|
||||
'status': 'OK',
|
||||
'timestamp': None,
|
||||
'unit': 'watts',
|
||||
'value': 1386,
|
||||
}),
|
||||
'chargingStatus': dict({
|
||||
'extra_data': dict({
|
||||
'updated_at': '2025-07-02T08:51:23Z',
|
||||
}),
|
||||
'status': 'OK',
|
||||
'timestamp': None,
|
||||
'unit': None,
|
||||
'value': 'CHARGING',
|
||||
}),
|
||||
'chargingType': dict({
|
||||
'extra_data': dict({
|
||||
'updated_at': '2025-07-02T08:51:23Z',
|
||||
}),
|
||||
'status': 'OK',
|
||||
'timestamp': None,
|
||||
'unit': None,
|
||||
'value': 'AC',
|
||||
}),
|
||||
'electricRange': dict({
|
||||
'extra_data': dict({
|
||||
'updated_at': '2025-07-02T08:51:23Z',
|
||||
}),
|
||||
'status': 'OK',
|
||||
'timestamp': None,
|
||||
'unit': 'mi',
|
||||
'value': 150,
|
||||
}),
|
||||
'estimatedChargingTimeToTargetBatteryChargeLevel': dict({
|
||||
'extra_data': dict({
|
||||
'updated_at': '2025-07-02T08:51:23Z',
|
||||
}),
|
||||
'status': 'OK',
|
||||
'timestamp': None,
|
||||
'unit': 'minutes',
|
||||
'value': 1440,
|
||||
}),
|
||||
'targetBatteryChargeLevel': dict({
|
||||
'extra_data': dict({
|
||||
'updated_at': '2024-09-22T09:40:12Z',
|
||||
}),
|
||||
'status': 'OK',
|
||||
'timestamp': None,
|
||||
'unit': 'percentage',
|
||||
'value': 90,
|
||||
}),
|
||||
}),
|
||||
'Volvo slow interval coordinator': dict({
|
||||
'availabilityStatus': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:32:26.169000+00:00',
|
||||
'unit': None,
|
||||
'value': 'AVAILABLE',
|
||||
}),
|
||||
}),
|
||||
'Volvo very slow interval coordinator': dict({
|
||||
'averageEnergyConsumption': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:53:44.785000+00:00',
|
||||
'unit': 'kWh/100km',
|
||||
'value': 22.6,
|
||||
}),
|
||||
'averageSpeed': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': 'km/h',
|
||||
'value': 53,
|
||||
}),
|
||||
'averageSpeedAutomatic': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': 'km/h',
|
||||
'value': 26,
|
||||
}),
|
||||
'battery_capacity_kwh': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'value': 81.608,
|
||||
}),
|
||||
'brakeFluidLevelWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'brakeLightCenterWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'brakeLightLeftWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'brakeLightRightWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'daytimeRunningLightLeftWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'daytimeRunningLightRightWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'distanceToEmptyBattery': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:30:08.338000+00:00',
|
||||
'unit': 'km',
|
||||
'value': 250,
|
||||
}),
|
||||
'distanceToService': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': 'km',
|
||||
'value': 29000,
|
||||
}),
|
||||
'engineCoolantLevelWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'engineHoursToService': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': 'h',
|
||||
'value': 1266,
|
||||
}),
|
||||
'fogLightFrontWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'fogLightRearWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'frontLeft': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'UNSPECIFIED',
|
||||
}),
|
||||
'frontRight': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'UNSPECIFIED',
|
||||
}),
|
||||
'hazardLightsWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'UNSPECIFIED',
|
||||
}),
|
||||
'highBeamLeftWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'highBeamRightWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'lowBeamLeftWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'lowBeamRightWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'odometer': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': 'km',
|
||||
'value': 30000,
|
||||
}),
|
||||
'oilLevelWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'positionLightFrontLeftWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'positionLightFrontRightWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'positionLightRearLeftWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'positionLightRearRightWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'rearLeft': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'UNSPECIFIED',
|
||||
}),
|
||||
'rearRight': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'UNSPECIFIED',
|
||||
}),
|
||||
'registrationPlateLightWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'reverseLightsWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'UNSPECIFIED',
|
||||
}),
|
||||
'serviceWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'sideMarkLightsWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'timeToService': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': 'months',
|
||||
'value': 23,
|
||||
}),
|
||||
'tripMeterAutomatic': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': 'km',
|
||||
'value': 18.2,
|
||||
}),
|
||||
'tripMeterManual': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': 'km',
|
||||
'value': 3822.9,
|
||||
}),
|
||||
'turnIndicationFrontLeftWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'turnIndicationFrontRightWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'turnIndicationRearLeftWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'turnIndicationRearRightWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
'washerFluidLevelWarning': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'timestamp': '2024-12-30T14:18:56.849000+00:00',
|
||||
'unit': None,
|
||||
'value': 'NO_WARNING',
|
||||
}),
|
||||
}),
|
||||
'entry_data': dict({
|
||||
'api_key': '**REDACTED**',
|
||||
'auth_implementation': 'volvo',
|
||||
'token': dict({
|
||||
'access_token': '**REDACTED**',
|
||||
'expires_at': 1759919745.7328658,
|
||||
'expires_in': 60,
|
||||
'refresh_token': '**REDACTED**',
|
||||
'token_type': 'Bearer',
|
||||
}),
|
||||
'vin': '**REDACTED**',
|
||||
}),
|
||||
'vehicle': dict({
|
||||
'battery_capacity_kwh': 81.608,
|
||||
'description': dict({
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'model': 'XC40',
|
||||
'steering': 'LEFT',
|
||||
'upholstery': 'null',
|
||||
}),
|
||||
'external_colour': 'Silver Dawn',
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'fuel_type': 'ELECTRIC',
|
||||
'gearbox': 'AUTOMATIC',
|
||||
'images': dict({
|
||||
'exterior_image_url': 'https://cas.volvocars.com/image/dynamic/MY24_0000/123/exterior-v4/_/default.png?market=se&client=public-api-engineering&angle=1&bg=00000000&w=1920',
|
||||
'extra_data': dict({
|
||||
}),
|
||||
'internal_image_url': 'https://cas.volvocars.com/image/dynamic/MY24_0000/123/interior-v4/_/default.jpg?market=se&client=public-api-engineering&angle=0&w=1920',
|
||||
}),
|
||||
'model_year': 2024,
|
||||
'vin': '**REDACTED**',
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
@@ -0,0 +1,35 @@
|
||||
"""Test Volvo diagnostics."""
|
||||
|
||||
from collections.abc import Awaitable, Callable
|
||||
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.const import CONF_TOKEN
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.diagnostics import get_diagnostics_for_config_entry
|
||||
from tests.typing import ClientSessionGenerator
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_api")
|
||||
async def test_entry_diagnostics(
|
||||
hass: HomeAssistant,
|
||||
setup_integration: Callable[[], Awaitable[bool]],
|
||||
hass_client: ClientSessionGenerator,
|
||||
snapshot: SnapshotAssertion,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test config entry diagnostics."""
|
||||
|
||||
assert await setup_integration()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Give it a fixed timestamp so it won't change with every test run
|
||||
mock_config_entry.data[CONF_TOKEN]["expires_at"] = 1759919745.7328658
|
||||
|
||||
assert (
|
||||
await get_diagnostics_for_config_entry(hass, hass_client, mock_config_entry)
|
||||
== snapshot
|
||||
)
|
||||
Reference in New Issue
Block a user