From 72202dc1b91f490f09700f302f0eaf884dfdd5d6 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Wed, 9 Sep 2026 15:01:55 +0200 Subject: [PATCH] Adjust renault to not access DeviceEntry.config_entries (#181727) --- homeassistant/components/renault/services.py | 30 +++++++------------ homeassistant/components/renault/strings.json | 3 -- tests/components/renault/test_services.py | 23 ++++++++++++-- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/homeassistant/components/renault/services.py b/homeassistant/components/renault/services.py index 0a219b8accb3..14c11a7250bb 100644 --- a/homeassistant/components/renault/services.py +++ b/homeassistant/components/renault/services.py @@ -9,7 +9,8 @@ import voluptuous as vol from homeassistant.core import HomeAssistant, ServiceCall, callback from homeassistant.exceptions import ServiceValidationError -from homeassistant.helpers import config_validation as cv, device_registry as dr +from homeassistant.helpers import config_validation as cv +from homeassistant.helpers.service import async_get_device_and_config_entry from .const import DOMAIN from .renault_vehicle import RenaultVehicleProxy @@ -177,25 +178,14 @@ async def ac_set_schedules(service_call: ServiceCall) -> None: def get_vehicle_proxy(service_call: ServiceCall) -> RenaultVehicleProxy: """Get vehicle from service_call data.""" - device_registry = dr.async_get(service_call.hass) - device_id = service_call.data[RenaultServiceArgument.VEHICLE] - device_entry = device_registry.async_get(device_id) - if device_entry is None: - raise ServiceValidationError( - translation_domain=DOMAIN, - translation_key="invalid_device_id", - translation_placeholders={"device_id": device_id}, - ) - - loaded_entries: list[RenaultConfigEntry] = [ - entry - for entry in service_call.hass.config_entries.async_loaded_entries(DOMAIN) - if entry.entry_id in device_entry.config_entries - ] - for entry in loaded_entries: - for vin, vehicle in entry.runtime_data.vehicles.items(): - if (DOMAIN, vin) in device_entry.identifiers: - return vehicle + device_id: str = service_call.data[RenaultServiceArgument.VEHICLE] + entry: RenaultConfigEntry + device_entry, entry = async_get_device_and_config_entry( + service_call.hass, DOMAIN, device_id + ) + for vin, vehicle in entry.runtime_data.vehicles.items(): + if (DOMAIN, vin) in device_entry.identifiers: + return vehicle raise ServiceValidationError( translation_domain=DOMAIN, translation_key="no_config_entry_for_device", diff --git a/homeassistant/components/renault/strings.json b/homeassistant/components/renault/strings.json index 3f22f671d35f..a44daa145880 100644 --- a/homeassistant/components/renault/strings.json +++ b/homeassistant/components/renault/strings.json @@ -213,9 +213,6 @@ "battery_soc_unavailable": { "message": "Battery state of charge data is currently unavailable" }, - "invalid_device_id": { - "message": "No device with ID {device_id} was found" - }, "no_config_entry_for_device": { "message": "No loaded config entry was found for device with ID {device_id}" }, diff --git a/tests/components/renault/test_services.py b/tests/components/renault/test_services.py index d64ab07e29bf..255d941c40db 100644 --- a/tests/components/renault/test_services.py +++ b/tests/components/renault/test_services.py @@ -14,7 +14,7 @@ from syrupy.assertion import SnapshotAssertion from homeassistant.components.renault.const import DOMAIN from homeassistant.components.renault.services import RenaultServiceArgument from homeassistant.config_entries import ConfigEntry -from homeassistant.core import HomeAssistant +from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant from homeassistant.exceptions import HomeAssistantError, ServiceValidationError from homeassistant.helpers import device_registry as dr @@ -412,7 +412,8 @@ async def test_service_invalid_device_id( await hass.services.async_call( DOMAIN, RenaultService.AC_CANCEL, service_data=data, blocking=True ) - assert err.value.translation_key == "invalid_device_id" + assert err.value.translation_domain == HOMEASSISTANT_DOMAIN + assert err.value.translation_key == "service_device_not_found" assert err.value.translation_placeholders == {"device_id": "some_random_id"} @@ -444,6 +445,24 @@ async def test_service_invalid_device_id2( assert err.value.translation_placeholders == {"device_id": "REG-NUMBER"} +async def test_service_unloaded_config_entry( + hass: HomeAssistant, config_entry: ConfigEntry +) -> None: + """Test that service fails if the config entry is not loaded.""" + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + data = {RenaultServiceArgument.VEHICLE: get_device_id(hass)} + assert await hass.config_entries.async_unload(config_entry.entry_id) + + with pytest.raises(ServiceValidationError) as err: + await hass.services.async_call( + DOMAIN, RenaultService.AC_CANCEL, service_data=data, blocking=True + ) + assert err.value.translation_domain == HOMEASSISTANT_DOMAIN + assert err.value.translation_key == "service_config_entry_not_loaded" + + async def test_service_exception( hass: HomeAssistant, config_entry: ConfigEntry ) -> None: