Add diagnostics to Subaru integration (#81169)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
7f047cf95c
commit
494cbf0dbe
4 changed files with 296 additions and 0 deletions
56
homeassistant/components/subaru/diagnostics.py
Normal file
56
homeassistant/components/subaru/diagnostics.py
Normal file
|
@ -0,0 +1,56 @@
|
|||
"""Diagnostics for the Subaru integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from subarulink.const import LATITUDE, LONGITUDE, ODOMETER, VEHICLE_NAME
|
||||
|
||||
from homeassistant.components.diagnostics.util import async_redact_data
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_DEVICE_ID, CONF_PASSWORD, CONF_PIN, CONF_USERNAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.device_registry import DeviceEntry
|
||||
|
||||
from .const import DOMAIN, ENTRY_COORDINATOR, VEHICLE_VIN
|
||||
|
||||
CONFIG_FIELDS_TO_REDACT = [CONF_USERNAME, CONF_PASSWORD, CONF_PIN, CONF_DEVICE_ID]
|
||||
DATA_FIELDS_TO_REDACT = [VEHICLE_VIN, VEHICLE_NAME, LATITUDE, LONGITUDE, ODOMETER]
|
||||
|
||||
|
||||
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][ENTRY_COORDINATOR]
|
||||
|
||||
diagnostics_data = {
|
||||
"config_entry": async_redact_data(config_entry.data, CONFIG_FIELDS_TO_REDACT),
|
||||
"options": async_redact_data(config_entry.options, []),
|
||||
"data": [
|
||||
async_redact_data(info, DATA_FIELDS_TO_REDACT)
|
||||
for info in coordinator.data.values()
|
||||
],
|
||||
}
|
||||
|
||||
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][ENTRY_COORDINATOR]
|
||||
|
||||
vin = next(iter(device.identifiers))[1]
|
||||
|
||||
if info := coordinator.data.get(vin):
|
||||
return {
|
||||
"config_entry": async_redact_data(
|
||||
config_entry.data, CONFIG_FIELDS_TO_REDACT
|
||||
),
|
||||
"options": async_redact_data(config_entry.options, []),
|
||||
"data": async_redact_data(info, DATA_FIELDS_TO_REDACT),
|
||||
}
|
||||
|
||||
raise HomeAssistantError("Device not found")
|
|
@ -0,0 +1,82 @@
|
|||
{
|
||||
"config_entry": {
|
||||
"username": "**REDACTED**",
|
||||
"password": "**REDACTED**",
|
||||
"country": "USA",
|
||||
"pin": "**REDACTED**",
|
||||
"device_id": "**REDACTED**"
|
||||
},
|
||||
"options": { "update_enabled": true },
|
||||
"data": [
|
||||
{
|
||||
"status": {
|
||||
"AVG_FUEL_CONSUMPTION": 2.3,
|
||||
"BATTERY_VOLTAGE": 12.0,
|
||||
"DISTANCE_TO_EMPTY_FUEL": 707,
|
||||
"DOOR_BOOT_LOCK_STATUS": "UNKNOWN",
|
||||
"DOOR_BOOT_POSITION": "CLOSED",
|
||||
"DOOR_ENGINE_HOOD_LOCK_STATUS": "UNKNOWN",
|
||||
"DOOR_ENGINE_HOOD_POSITION": "CLOSED",
|
||||
"DOOR_FRONT_LEFT_LOCK_STATUS": "UNKNOWN",
|
||||
"DOOR_FRONT_LEFT_POSITION": "CLOSED",
|
||||
"DOOR_FRONT_RIGHT_LOCK_STATUS": "UNKNOWN",
|
||||
"DOOR_FRONT_RIGHT_POSITION": "CLOSED",
|
||||
"DOOR_REAR_LEFT_LOCK_STATUS": "UNKNOWN",
|
||||
"DOOR_REAR_LEFT_POSITION": "CLOSED",
|
||||
"DOOR_REAR_RIGHT_LOCK_STATUS": "UNKNOWN",
|
||||
"DOOR_REAR_RIGHT_POSITION": "CLOSED",
|
||||
"EV_CHARGER_STATE_TYPE": "CHARGING",
|
||||
"EV_CHARGE_SETTING_AMPERE_TYPE": "MAXIMUM",
|
||||
"EV_CHARGE_VOLT_TYPE": "CHARGE_LEVEL_1",
|
||||
"EV_DISTANCE_TO_EMPTY": 1,
|
||||
"EV_IS_PLUGGED_IN": "UNLOCKED_CONNECTED",
|
||||
"EV_STATE_OF_CHARGE_MODE": "EV_MODE",
|
||||
"EV_STATE_OF_CHARGE_PERCENT": 20,
|
||||
"EV_TIME_TO_FULLY_CHARGED_UTC": "2020-07-24T03:06:40+00:00",
|
||||
"EXT_EXTERNAL_TEMP": 21.5,
|
||||
"ODOMETER": "**REDACTED**",
|
||||
"POSITION_HEADING_DEGREE": 150,
|
||||
"POSITION_SPEED_KMPH": "0",
|
||||
"POSITION_TIMESTAMP": 1595560000.0,
|
||||
"SEAT_BELT_STATUS_FRONT_LEFT": "BELTED",
|
||||
"SEAT_BELT_STATUS_FRONT_MIDDLE": "NOT_EQUIPPED",
|
||||
"SEAT_BELT_STATUS_FRONT_RIGHT": "BELTED",
|
||||
"SEAT_BELT_STATUS_SECOND_LEFT": "UNKNOWN",
|
||||
"SEAT_BELT_STATUS_SECOND_MIDDLE": "UNKNOWN",
|
||||
"SEAT_BELT_STATUS_SECOND_RIGHT": "UNKNOWN",
|
||||
"SEAT_BELT_STATUS_THIRD_LEFT": "UNKNOWN",
|
||||
"SEAT_BELT_STATUS_THIRD_MIDDLE": "UNKNOWN",
|
||||
"SEAT_BELT_STATUS_THIRD_RIGHT": "UNKNOWN",
|
||||
"SEAT_OCCUPATION_STATUS_FRONT_LEFT": "UNKNOWN",
|
||||
"SEAT_OCCUPATION_STATUS_FRONT_MIDDLE": "NOT_EQUIPPED",
|
||||
"SEAT_OCCUPATION_STATUS_FRONT_RIGHT": "UNKNOWN",
|
||||
"SEAT_OCCUPATION_STATUS_SECOND_LEFT": "UNKNOWN",
|
||||
"SEAT_OCCUPATION_STATUS_SECOND_MIDDLE": "UNKNOWN",
|
||||
"SEAT_OCCUPATION_STATUS_SECOND_RIGHT": "UNKNOWN",
|
||||
"SEAT_OCCUPATION_STATUS_THIRD_LEFT": "UNKNOWN",
|
||||
"SEAT_OCCUPATION_STATUS_THIRD_MIDDLE": "UNKNOWN",
|
||||
"SEAT_OCCUPATION_STATUS_THIRD_RIGHT": "UNKNOWN",
|
||||
"TIMESTAMP": 1595560000.0,
|
||||
"TRANSMISSION_MODE": "UNKNOWN",
|
||||
"TYRE_PRESSURE_FRONT_LEFT": 0,
|
||||
"TYRE_PRESSURE_FRONT_RIGHT": 2550,
|
||||
"TYRE_PRESSURE_REAR_LEFT": 2450,
|
||||
"TYRE_PRESSURE_REAR_RIGHT": 2350,
|
||||
"TYRE_STATUS_FRONT_LEFT": "UNKNOWN",
|
||||
"TYRE_STATUS_FRONT_RIGHT": "UNKNOWN",
|
||||
"TYRE_STATUS_REAR_LEFT": "UNKNOWN",
|
||||
"TYRE_STATUS_REAR_RIGHT": "UNKNOWN",
|
||||
"VEHICLE_STATE_TYPE": "IGNITION_OFF",
|
||||
"WINDOW_BACK_STATUS": "UNKNOWN",
|
||||
"WINDOW_FRONT_LEFT_STATUS": "VENTED",
|
||||
"WINDOW_FRONT_RIGHT_STATUS": "VENTED",
|
||||
"WINDOW_REAR_LEFT_STATUS": "UNKNOWN",
|
||||
"WINDOW_REAR_RIGHT_STATUS": "UNKNOWN",
|
||||
"WINDOW_SUNROOF_STATUS": "UNKNOWN",
|
||||
"heading": 170,
|
||||
"latitude": "**REDACTED**",
|
||||
"longitude": "**REDACTED**"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
80
tests/components/subaru/fixtures/diagnostics_device.json
Normal file
80
tests/components/subaru/fixtures/diagnostics_device.json
Normal file
|
@ -0,0 +1,80 @@
|
|||
{
|
||||
"config_entry": {
|
||||
"username": "**REDACTED**",
|
||||
"password": "**REDACTED**",
|
||||
"country": "USA",
|
||||
"pin": "**REDACTED**",
|
||||
"device_id": "**REDACTED**"
|
||||
},
|
||||
"options": { "update_enabled": true },
|
||||
"data": {
|
||||
"status": {
|
||||
"AVG_FUEL_CONSUMPTION": 2.3,
|
||||
"BATTERY_VOLTAGE": 12.0,
|
||||
"DISTANCE_TO_EMPTY_FUEL": 707,
|
||||
"DOOR_BOOT_LOCK_STATUS": "UNKNOWN",
|
||||
"DOOR_BOOT_POSITION": "CLOSED",
|
||||
"DOOR_ENGINE_HOOD_LOCK_STATUS": "UNKNOWN",
|
||||
"DOOR_ENGINE_HOOD_POSITION": "CLOSED",
|
||||
"DOOR_FRONT_LEFT_LOCK_STATUS": "UNKNOWN",
|
||||
"DOOR_FRONT_LEFT_POSITION": "CLOSED",
|
||||
"DOOR_FRONT_RIGHT_LOCK_STATUS": "UNKNOWN",
|
||||
"DOOR_FRONT_RIGHT_POSITION": "CLOSED",
|
||||
"DOOR_REAR_LEFT_LOCK_STATUS": "UNKNOWN",
|
||||
"DOOR_REAR_LEFT_POSITION": "CLOSED",
|
||||
"DOOR_REAR_RIGHT_LOCK_STATUS": "UNKNOWN",
|
||||
"DOOR_REAR_RIGHT_POSITION": "CLOSED",
|
||||
"EV_CHARGER_STATE_TYPE": "CHARGING",
|
||||
"EV_CHARGE_SETTING_AMPERE_TYPE": "MAXIMUM",
|
||||
"EV_CHARGE_VOLT_TYPE": "CHARGE_LEVEL_1",
|
||||
"EV_DISTANCE_TO_EMPTY": 1,
|
||||
"EV_IS_PLUGGED_IN": "UNLOCKED_CONNECTED",
|
||||
"EV_STATE_OF_CHARGE_MODE": "EV_MODE",
|
||||
"EV_STATE_OF_CHARGE_PERCENT": 20,
|
||||
"EV_TIME_TO_FULLY_CHARGED_UTC": "2020-07-24T03:06:40+00:00",
|
||||
"EXT_EXTERNAL_TEMP": 21.5,
|
||||
"ODOMETER": "**REDACTED**",
|
||||
"POSITION_HEADING_DEGREE": 150,
|
||||
"POSITION_SPEED_KMPH": "0",
|
||||
"POSITION_TIMESTAMP": 1595560000.0,
|
||||
"SEAT_BELT_STATUS_FRONT_LEFT": "BELTED",
|
||||
"SEAT_BELT_STATUS_FRONT_MIDDLE": "NOT_EQUIPPED",
|
||||
"SEAT_BELT_STATUS_FRONT_RIGHT": "BELTED",
|
||||
"SEAT_BELT_STATUS_SECOND_LEFT": "UNKNOWN",
|
||||
"SEAT_BELT_STATUS_SECOND_MIDDLE": "UNKNOWN",
|
||||
"SEAT_BELT_STATUS_SECOND_RIGHT": "UNKNOWN",
|
||||
"SEAT_BELT_STATUS_THIRD_LEFT": "UNKNOWN",
|
||||
"SEAT_BELT_STATUS_THIRD_MIDDLE": "UNKNOWN",
|
||||
"SEAT_BELT_STATUS_THIRD_RIGHT": "UNKNOWN",
|
||||
"SEAT_OCCUPATION_STATUS_FRONT_LEFT": "UNKNOWN",
|
||||
"SEAT_OCCUPATION_STATUS_FRONT_MIDDLE": "NOT_EQUIPPED",
|
||||
"SEAT_OCCUPATION_STATUS_FRONT_RIGHT": "UNKNOWN",
|
||||
"SEAT_OCCUPATION_STATUS_SECOND_LEFT": "UNKNOWN",
|
||||
"SEAT_OCCUPATION_STATUS_SECOND_MIDDLE": "UNKNOWN",
|
||||
"SEAT_OCCUPATION_STATUS_SECOND_RIGHT": "UNKNOWN",
|
||||
"SEAT_OCCUPATION_STATUS_THIRD_LEFT": "UNKNOWN",
|
||||
"SEAT_OCCUPATION_STATUS_THIRD_MIDDLE": "UNKNOWN",
|
||||
"SEAT_OCCUPATION_STATUS_THIRD_RIGHT": "UNKNOWN",
|
||||
"TIMESTAMP": 1595560000.0,
|
||||
"TRANSMISSION_MODE": "UNKNOWN",
|
||||
"TYRE_PRESSURE_FRONT_LEFT": 0,
|
||||
"TYRE_PRESSURE_FRONT_RIGHT": 2550,
|
||||
"TYRE_PRESSURE_REAR_LEFT": 2450,
|
||||
"TYRE_PRESSURE_REAR_RIGHT": 2350,
|
||||
"TYRE_STATUS_FRONT_LEFT": "UNKNOWN",
|
||||
"TYRE_STATUS_FRONT_RIGHT": "UNKNOWN",
|
||||
"TYRE_STATUS_REAR_LEFT": "UNKNOWN",
|
||||
"TYRE_STATUS_REAR_RIGHT": "UNKNOWN",
|
||||
"VEHICLE_STATE_TYPE": "IGNITION_OFF",
|
||||
"WINDOW_BACK_STATUS": "UNKNOWN",
|
||||
"WINDOW_FRONT_LEFT_STATUS": "VENTED",
|
||||
"WINDOW_FRONT_RIGHT_STATUS": "VENTED",
|
||||
"WINDOW_REAR_LEFT_STATUS": "UNKNOWN",
|
||||
"WINDOW_REAR_RIGHT_STATUS": "UNKNOWN",
|
||||
"WINDOW_SUNROOF_STATUS": "UNKNOWN",
|
||||
"heading": 170,
|
||||
"latitude": "**REDACTED**",
|
||||
"longitude": "**REDACTED**"
|
||||
}
|
||||
}
|
||||
}
|
78
tests/components/subaru/test_diagnostics.py
Normal file
78
tests/components/subaru/test_diagnostics.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
"""Test Subaru diagnostics."""
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.subaru.const import DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
|
||||
from .api_responses import TEST_VIN_2_EV
|
||||
|
||||
from tests.common import load_fixture
|
||||
from tests.components.diagnostics import (
|
||||
get_diagnostics_for_config_entry,
|
||||
get_diagnostics_for_device,
|
||||
)
|
||||
from tests.components.subaru.conftest import (
|
||||
MOCK_API_FETCH,
|
||||
MOCK_API_GET_DATA,
|
||||
advance_time_to_next_fetch,
|
||||
)
|
||||
|
||||
|
||||
async def test_config_entry_diagnostics(hass: HomeAssistant, hass_client, ev_entry):
|
||||
"""Test config entry diagnostics."""
|
||||
|
||||
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
|
||||
|
||||
diagnostics_fixture = json.loads(
|
||||
load_fixture("subaru/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, ev_entry):
|
||||
"""Test device diagnostics."""
|
||||
|
||||
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
|
||||
|
||||
device_registry = dr.async_get(hass)
|
||||
reg_device = device_registry.async_get_device(
|
||||
identifiers={(DOMAIN, TEST_VIN_2_EV)},
|
||||
)
|
||||
assert reg_device is not None
|
||||
|
||||
diagnostics_fixture = json.loads(load_fixture("subaru/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, ev_entry
|
||||
):
|
||||
"""Test device diagnostics when the vehicle cannot be found."""
|
||||
|
||||
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
|
||||
|
||||
device_registry = dr.async_get(hass)
|
||||
reg_device = device_registry.async_get_device(
|
||||
identifiers={(DOMAIN, TEST_VIN_2_EV)},
|
||||
)
|
||||
assert reg_device is not None
|
||||
|
||||
# Simulate case where Subaru API does not return vehicle data
|
||||
with patch(MOCK_API_FETCH), patch(MOCK_API_GET_DATA, return_value=None):
|
||||
advance_time_to_next_fetch(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
with pytest.raises(AssertionError):
|
||||
await get_diagnostics_for_device(hass, hass_client, config_entry, reg_device)
|
Loading…
Add table
Reference in a new issue