Store runtime data in entry in renault (#116454)

This commit is contained in:
epenet 2024-04-30 17:39:03 +02:00 committed by GitHub
parent 0005f8400d
commit a440783208
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 40 additions and 52 deletions

View file

@ -15,6 +15,7 @@ from .renault_hub import RenaultHub
from .services import setup_services
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
RenaultConfigEntry = ConfigEntry[RenaultHub]
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
@ -23,7 +24,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
return True
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
async def async_setup_entry(
hass: HomeAssistant, config_entry: RenaultConfigEntry
) -> bool:
"""Load a config entry."""
renault_hub = RenaultHub(hass, config_entry.data[CONF_LOCALE])
try:
@ -36,19 +39,20 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
if not login_success:
raise ConfigEntryAuthFailed
hass.data.setdefault(DOMAIN, {})
try:
await renault_hub.async_initialise(config_entry)
except aiohttp.ClientError as exc:
raise ConfigEntryNotReady from exc
hass.data[DOMAIN][config_entry.entry_id] = renault_hub
config_entry.runtime_data = renault_hub
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
return True
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
async def async_unload_entry(
hass: HomeAssistant, config_entry: RenaultConfigEntry
) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(config_entry, PLATFORMS)

View file

@ -12,14 +12,12 @@ from homeassistant.components.binary_sensor import (
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from .const import DOMAIN
from . import RenaultConfigEntry
from .entity import RenaultDataEntity, RenaultDataEntityDescription
from .renault_hub import RenaultHub
@dataclass(frozen=True, kw_only=True)
@ -35,14 +33,13 @@ class RenaultBinarySensorEntityDescription(
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
config_entry: RenaultConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the Renault entities from config entry."""
proxy: RenaultHub = hass.data[DOMAIN][config_entry.entry_id]
entities: list[RenaultBinarySensor] = [
RenaultBinarySensor(vehicle, description)
for vehicle in proxy.vehicles.values()
for vehicle in config_entry.runtime_data.vehicles.values()
for description in BINARY_SENSOR_TYPES
if description.coordinator in vehicle.coordinators
]

View file

@ -7,13 +7,11 @@ from dataclasses import dataclass
from typing import Any
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN
from . import RenaultConfigEntry
from .entity import RenaultEntity
from .renault_hub import RenaultHub
@dataclass(frozen=True, kw_only=True)
@ -26,14 +24,13 @@ class RenaultButtonEntityDescription(ButtonEntityDescription):
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
config_entry: RenaultConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the Renault entities from config entry."""
proxy: RenaultHub = hass.data[DOMAIN][config_entry.entry_id]
entities: list[RenaultButtonEntity] = [
RenaultButtonEntity(vehicle, description)
for vehicle in proxy.vehicles.values()
for vehicle in config_entry.runtime_data.vehicles.values()
for description in BUTTON_TYPES
if not description.requires_electricity or vehicle.details.uses_electricity()
]

View file

@ -5,25 +5,22 @@ from __future__ import annotations
from renault_api.kamereon.models import KamereonVehicleLocationData
from homeassistant.components.device_tracker import SourceType, TrackerEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN
from . import RenaultConfigEntry
from .entity import RenaultDataEntity, RenaultDataEntityDescription
from .renault_hub import RenaultHub
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
config_entry: RenaultConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the Renault entities from config entry."""
proxy: RenaultHub = hass.data[DOMAIN][config_entry.entry_id]
entities: list[RenaultDeviceTracker] = [
RenaultDeviceTracker(vehicle, description)
for vehicle in proxy.vehicles.values()
for vehicle in config_entry.runtime_data.vehicles.values()
for description in DEVICE_TRACKER_TYPES
if description.coordinator in vehicle.coordinators
]

View file

@ -5,13 +5,12 @@ from __future__ import annotations
from typing import Any
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceEntry
from . import RenaultHub
from .const import CONF_KAMEREON_ACCOUNT_ID, DOMAIN
from . import RenaultConfigEntry
from .const import CONF_KAMEREON_ACCOUNT_ID
from .renault_vehicle import RenaultVehicleProxy
TO_REDACT = {
@ -27,11 +26,9 @@ TO_REDACT = {
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, entry: ConfigEntry
hass: HomeAssistant, entry: RenaultConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
renault_hub: RenaultHub = hass.data[DOMAIN][entry.entry_id]
return {
"entry": {
"title": entry.title,
@ -39,18 +36,17 @@ async def async_get_config_entry_diagnostics(
},
"vehicles": [
_get_vehicle_diagnostics(vehicle)
for vehicle in renault_hub.vehicles.values()
for vehicle in entry.runtime_data.vehicles.values()
],
}
async def async_get_device_diagnostics(
hass: HomeAssistant, entry: ConfigEntry, device: DeviceEntry
hass: HomeAssistant, entry: RenaultConfigEntry, device: DeviceEntry
) -> dict[str, Any]:
"""Return diagnostics for a device."""
renault_hub: RenaultHub = hass.data[DOMAIN][entry.entry_id]
vin = next(iter(device.identifiers))[1]
vehicle = renault_hub.vehicles[vin]
vehicle = entry.runtime_data.vehicles[vin]
return _get_vehicle_diagnostics(vehicle)

View file

@ -8,14 +8,12 @@ from typing import cast
from renault_api.kamereon.models import KamereonVehicleBatteryStatusData
from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from .const import DOMAIN
from . import RenaultConfigEntry
from .entity import RenaultDataEntity, RenaultDataEntityDescription
from .renault_hub import RenaultHub
@dataclass(frozen=True, kw_only=True)
@ -29,14 +27,13 @@ class RenaultSelectEntityDescription(
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
config_entry: RenaultConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the Renault entities from config entry."""
proxy: RenaultHub = hass.data[DOMAIN][config_entry.entry_id]
entities: list[RenaultSelectEntity] = [
RenaultSelectEntity(vehicle, description)
for vehicle in proxy.vehicles.values()
for vehicle in config_entry.runtime_data.vehicles.values()
for description in SENSOR_TYPES
if description.coordinator in vehicle.coordinators
]

View file

@ -21,7 +21,6 @@ from homeassistant.components.sensor import (
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
PERCENTAGE,
UnitOfEnergy,
@ -36,10 +35,9 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.util.dt import as_utc, parse_datetime
from .const import DOMAIN
from . import RenaultConfigEntry
from .coordinator import T
from .entity import RenaultDataEntity, RenaultDataEntityDescription
from .renault_hub import RenaultHub
from .renault_vehicle import RenaultVehicleProxy
@ -58,14 +56,13 @@ class RenaultSensorEntityDescription(
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
config_entry: RenaultConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the Renault entities from config entry."""
proxy: RenaultHub = hass.data[DOMAIN][config_entry.entry_id]
entities: list[RenaultSensor[Any]] = [
description.entity_class(vehicle, description)
for vehicle in proxy.vehicles.values()
for vehicle in config_entry.runtime_data.vehicles.values()
for description in SENSOR_TYPES
if description.coordinator in vehicle.coordinators
and (not description.requires_fuel or vehicle.details.uses_fuel())

View file

@ -9,13 +9,16 @@ from typing import TYPE_CHECKING, Any
import voluptuous as vol
from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.helpers import config_validation as cv, device_registry as dr
from .const import DOMAIN
from .renault_hub import RenaultHub
from .renault_vehicle import RenaultVehicleProxy
if TYPE_CHECKING:
from . import RenaultConfigEntry
LOGGER = logging.getLogger(__name__)
ATTR_SCHEDULES = "schedules"
@ -116,9 +119,13 @@ def setup_services(hass: HomeAssistant) -> None:
if device_entry is None:
raise ValueError(f"Unable to find device with id: {device_id}")
proxy: RenaultHub
for proxy in hass.data[DOMAIN].values():
for vin, vehicle in proxy.vehicles.items():
loaded_entries: list[RenaultConfigEntry] = [
entry
for entry in hass.config_entries.async_entries(DOMAIN)
if entry.state == ConfigEntryState.LOADED
]
for entry in loaded_entries:
for vin, vehicle in entry.runtime_data.vehicles.items():
if (DOMAIN, vin) in device_entry.identifiers:
return vehicle
raise ValueError(f"Unable to find vehicle with VIN: {device_entry.identifiers}")

View file

@ -57,7 +57,6 @@ async def test_setup_entry_bad_password(
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
assert config_entry.state is ConfigEntryState.SETUP_ERROR
assert not hass.data.get(DOMAIN)
@pytest.mark.parametrize("side_effect", [aiohttp.ClientConnectionError, GigyaException])
@ -76,7 +75,6 @@ async def test_setup_entry_exception(
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
assert config_entry.state is ConfigEntryState.SETUP_RETRY
assert not hass.data.get(DOMAIN)
@pytest.mark.usefixtures("patch_renault_account")
@ -95,7 +93,6 @@ async def test_setup_entry_kamereon_exception(
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
assert config_entry.state is ConfigEntryState.SETUP_RETRY
assert not hass.data.get(DOMAIN)
@pytest.mark.usefixtures("patch_renault_account", "patch_get_vehicles")
@ -111,4 +108,3 @@ async def test_setup_entry_missing_vehicle_details(
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
assert config_entry.state is ConfigEntryState.SETUP_RETRY
assert not hass.data.get(DOMAIN)