diff --git a/homeassistant/components/mazda/diagnostics.py b/homeassistant/components/mazda/diagnostics.py new file mode 100644 index 00000000000..421410f4a34 --- /dev/null +++ b/homeassistant/components/mazda/diagnostics.py @@ -0,0 +1,57 @@ +"""Diagnostics support for the Mazda integration.""" +from __future__ import annotations + +from typing import Any + +from homeassistant.components.diagnostics.util import async_redact_data +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_EMAIL, CONF_PASSWORD +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers.device_registry import DeviceEntry + +from .const import DATA_COORDINATOR, DOMAIN + +TO_REDACT_INFO = [CONF_EMAIL, CONF_PASSWORD] +TO_REDACT_DATA = ["vin", "id", "latitude", "longitude"] + + +async def async_get_config_entry_diagnostics( + hass: HomeAssistant, config_entry: ConfigEntry +) -> dict[str, Any]: + """Return diagnostics for a config entry.""" + coordinator = hass.data[DOMAIN][config_entry.entry_id][DATA_COORDINATOR] + + diagnostics_data = { + "info": async_redact_data(config_entry.data, TO_REDACT_INFO), + "data": [ + async_redact_data(vehicle, TO_REDACT_DATA) for vehicle in coordinator.data + ], + } + + return diagnostics_data + + +async def async_get_device_diagnostics( + hass: HomeAssistant, config_entry: ConfigEntry, device: DeviceEntry +) -> dict[str, Any]: + """Return diagnostics for a device.""" + coordinator = hass.data[DOMAIN][config_entry.entry_id][DATA_COORDINATOR] + + vin = next(iter(device.identifiers))[1] + + target_vehicle = None + for vehicle in coordinator.data: + if vehicle["vin"] == vin: + target_vehicle = vehicle + break + + if target_vehicle is None: + raise HomeAssistantError("Vehicle not found") + + diagnostics_data = { + "info": async_redact_data(config_entry.data, TO_REDACT_INFO), + "data": async_redact_data(target_vehicle, TO_REDACT_DATA), + } + + return diagnostics_data diff --git a/tests/components/mazda/fixtures/diagnostics_config_entry.json b/tests/components/mazda/fixtures/diagnostics_config_entry.json new file mode 100644 index 00000000000..445ae141cb2 --- /dev/null +++ b/tests/components/mazda/fixtures/diagnostics_config_entry.json @@ -0,0 +1,62 @@ +{ + "info": { + "email": "**REDACTED**", + "password": "**REDACTED**", + "region": "MNAO" + }, + "data": [ + { + "vin": "**REDACTED**", + "id": "**REDACTED**", + "nickname": "My Mazda3", + "carlineCode": "M3S", + "carlineName": "MAZDA3 2.5 S SE AWD", + "modelYear": "2021", + "modelCode": "M3S SE XA", + "modelName": "W/ SELECT PKG AWD SDN", + "automaticTransmission": true, + "interiorColorCode": "BY3", + "interiorColorName": "BLACK", + "exteriorColorCode": "42M", + "exteriorColorName": "DEEP CRYSTAL BLUE MICA", + "isElectric": false, + "status": { + "lastUpdatedTimestamp": "20210123143809", + "latitude": "**REDACTED**", + "longitude": "**REDACTED**", + "positionTimestamp": "20210123143808", + "fuelRemainingPercent": 87.0, + "fuelDistanceRemainingKm": 380.8, + "odometerKm": 2795.8, + "doors": { + "driverDoorOpen": false, + "passengerDoorOpen": false, + "rearLeftDoorOpen": false, + "rearRightDoorOpen": false, + "trunkOpen": false, + "hoodOpen": false, + "fuelLidOpen": false + }, + "doorLocks": { + "driverDoorUnlocked": false, + "passengerDoorUnlocked": false, + "rearLeftDoorUnlocked": false, + "rearRightDoorUnlocked": false + }, + "windows": { + "driverWindowOpen": false, + "passengerWindowOpen": false, + "rearLeftWindowOpen": false, + "rearRightWindowOpen": false + }, + "hazardLightsOn": false, + "tirePressure": { + "frontLeftTirePressurePsi": 35.0, + "frontRightTirePressurePsi": 35.0, + "rearLeftTirePressurePsi": 33.0, + "rearRightTirePressurePsi": 33.0 + } + } + } + ] +} diff --git a/tests/components/mazda/fixtures/diagnostics_device.json b/tests/components/mazda/fixtures/diagnostics_device.json new file mode 100644 index 00000000000..0b2fa8550ac --- /dev/null +++ b/tests/components/mazda/fixtures/diagnostics_device.json @@ -0,0 +1,60 @@ +{ + "info": { + "email": "**REDACTED**", + "password": "**REDACTED**", + "region": "MNAO" + }, + "data": { + "vin": "**REDACTED**", + "id": "**REDACTED**", + "nickname": "My Mazda3", + "carlineCode": "M3S", + "carlineName": "MAZDA3 2.5 S SE AWD", + "modelYear": "2021", + "modelCode": "M3S SE XA", + "modelName": "W/ SELECT PKG AWD SDN", + "automaticTransmission": true, + "interiorColorCode": "BY3", + "interiorColorName": "BLACK", + "exteriorColorCode": "42M", + "exteriorColorName": "DEEP CRYSTAL BLUE MICA", + "isElectric": false, + "status": { + "lastUpdatedTimestamp": "20210123143809", + "latitude": "**REDACTED**", + "longitude": "**REDACTED**", + "positionTimestamp": "20210123143808", + "fuelRemainingPercent": 87.0, + "fuelDistanceRemainingKm": 380.8, + "odometerKm": 2795.8, + "doors": { + "driverDoorOpen": false, + "passengerDoorOpen": false, + "rearLeftDoorOpen": false, + "rearRightDoorOpen": false, + "trunkOpen": false, + "hoodOpen": false, + "fuelLidOpen": false + }, + "doorLocks": { + "driverDoorUnlocked": false, + "passengerDoorUnlocked": false, + "rearLeftDoorUnlocked": false, + "rearRightDoorUnlocked": false + }, + "windows": { + "driverWindowOpen": false, + "passengerWindowOpen": false, + "rearLeftWindowOpen": false, + "rearRightWindowOpen": false + }, + "hazardLightsOn": false, + "tirePressure": { + "frontLeftTirePressurePsi": 35.0, + "frontRightTirePressurePsi": 35.0, + "rearLeftTirePressurePsi": 33.0, + "rearRightTirePressurePsi": 33.0 + } + } + } +} diff --git a/tests/components/mazda/test_diagnostics.py b/tests/components/mazda/test_diagnostics.py new file mode 100644 index 00000000000..a75601cdea2 --- /dev/null +++ b/tests/components/mazda/test_diagnostics.py @@ -0,0 +1,75 @@ +"""Test Mazda diagnostics.""" + +import json + +import pytest + +from homeassistant.components.mazda.const import DATA_COORDINATOR, DOMAIN +from homeassistant.core import HomeAssistant +from homeassistant.helpers import device_registry as dr + +from . import init_integration + +from tests.common import load_fixture +from tests.components.diagnostics import ( + get_diagnostics_for_config_entry, + get_diagnostics_for_device, +) + + +async def test_config_entry_diagnostics(hass: HomeAssistant, hass_client): + """Test config entry diagnostics.""" + await init_integration(hass) + assert hass.data[DOMAIN] + + config_entry = hass.config_entries.async_entries(DOMAIN)[0] + + diagnostics_fixture = json.loads( + load_fixture("mazda/diagnostics_config_entry.json") + ) + + assert ( + await get_diagnostics_for_config_entry(hass, hass_client, config_entry) + == diagnostics_fixture + ) + + +async def test_device_diagnostics(hass: HomeAssistant, hass_client): + """Test device diagnostics.""" + await init_integration(hass) + assert hass.data[DOMAIN] + + config_entry = hass.config_entries.async_entries(DOMAIN)[0] + + device_registry = dr.async_get(hass) + reg_device = device_registry.async_get_device( + identifiers={(DOMAIN, "JM000000000000000")}, + ) + assert reg_device is not None + + diagnostics_fixture = json.loads(load_fixture("mazda/diagnostics_device.json")) + + assert ( + await get_diagnostics_for_device(hass, hass_client, config_entry, reg_device) + == diagnostics_fixture + ) + + +async def test_device_diagnostics_vehicle_not_found(hass: HomeAssistant, hass_client): + """Test device diagnostics when the vehicle cannot be found.""" + await init_integration(hass) + assert hass.data[DOMAIN] + + config_entry = hass.config_entries.async_entries(DOMAIN)[0] + + device_registry = dr.async_get(hass) + reg_device = device_registry.async_get_device( + identifiers={(DOMAIN, "JM000000000000000")}, + ) + assert reg_device is not None + + # Remove vehicle info from hass.data so that vehicle will not be found + hass.data[DOMAIN][config_entry.entry_id][DATA_COORDINATOR].data = [] + + with pytest.raises(AssertionError): + await get_diagnostics_for_device(hass, hass_client, config_entry, reg_device)