From d10866a2ae12b49189c43bf0e5322da2b6ad50b5 Mon Sep 17 00:00:00 2001 From: "A. Gideonse" Date: Sun, 10 May 2026 21:33:35 +0000 Subject: [PATCH 1/7] Complete exception translations for Indevolt --- homeassistant/components/indevolt/number.py | 10 +++++++++- homeassistant/components/indevolt/quality_scale.yaml | 2 +- homeassistant/components/indevolt/select.py | 7 ++++++- homeassistant/components/indevolt/strings.json | 3 +++ homeassistant/components/indevolt/switch.py | 10 +++++++++- tests/components/indevolt/test_number.py | 6 ++---- tests/components/indevolt/test_select.py | 6 ++---- tests/components/indevolt/test_switch.py | 6 ++---- 8 files changed, 34 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/indevolt/number.py b/homeassistant/components/indevolt/number.py index 5458245f6d9b7b..fa89a943bbf3a8 100644 --- a/homeassistant/components/indevolt/number.py +++ b/homeassistant/components/indevolt/number.py @@ -17,6 +17,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from . import IndevoltConfigEntry +from .const import DOMAIN from .coordinator import IndevoltCoordinator from .entity import IndevoltEntity @@ -138,4 +139,11 @@ async def async_set_native_value(self, value: float) -> None: await self.coordinator.async_request_refresh() else: - raise HomeAssistantError(f"Failed to set value {int_value} for {self.name}") + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="write_error", + translation_placeholders={ + "name": str(self.name), + "value": str(int_value), + }, + ) diff --git a/homeassistant/components/indevolt/quality_scale.yaml b/homeassistant/components/indevolt/quality_scale.yaml index 713f32f91f63df..16bc99af5593df 100644 --- a/homeassistant/components/indevolt/quality_scale.yaml +++ b/homeassistant/components/indevolt/quality_scale.yaml @@ -60,7 +60,7 @@ rules: entity-device-class: done entity-disabled-by-default: done entity-translations: done - exception-translations: todo + exception-translations: done icon-translations: todo reconfiguration-flow: done repair-issues: diff --git a/homeassistant/components/indevolt/select.py b/homeassistant/components/indevolt/select.py index 31b6f09b9d3771..aade638833e7ae 100644 --- a/homeassistant/components/indevolt/select.py +++ b/homeassistant/components/indevolt/select.py @@ -11,6 +11,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from . import IndevoltConfigEntry +from .const import DOMAIN from .coordinator import IndevoltCoordinator from .entity import IndevoltEntity @@ -108,4 +109,8 @@ async def async_select_option(self, option: str) -> None: await self.coordinator.async_request_refresh() else: - raise HomeAssistantError(f"Failed to set option {option} for {self.name}") + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="write_error", + translation_placeholders={"name": str(self.name), "value": option}, + ) diff --git a/homeassistant/components/indevolt/strings.json b/homeassistant/components/indevolt/strings.json index 83bba1627af132..e2f9854942e2e9 100644 --- a/homeassistant/components/indevolt/strings.json +++ b/homeassistant/components/indevolt/strings.json @@ -354,6 +354,9 @@ }, "soc_below_minimum": { "message": "Target SOC ({target}%) is below the device minimum ({minimum_soc}%)" + }, + "write_error": { + "message": "Cannot update {name} to {value}" } }, "services": { diff --git a/homeassistant/components/indevolt/switch.py b/homeassistant/components/indevolt/switch.py index 203f8ba419552d..91aca0bf130ded 100644 --- a/homeassistant/components/indevolt/switch.py +++ b/homeassistant/components/indevolt/switch.py @@ -15,6 +15,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from . import IndevoltConfigEntry +from .const import DOMAIN from .coordinator import IndevoltCoordinator from .entity import IndevoltEntity @@ -128,4 +129,11 @@ async def _async_toggle(self, value: int) -> None: await self.coordinator.async_request_refresh() else: - raise HomeAssistantError(f"Failed to set value {value} for {self.name}") + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="write_error", + translation_placeholders={ + "name": str(self.name), + "value": "on" if value else "off", + }, + ) diff --git a/tests/components/indevolt/test_number.py b/tests/components/indevolt/test_number.py index abfa5c8f7f22c1..4b41b729b44cf9 100644 --- a/tests/components/indevolt/test_number.py +++ b/tests/components/indevolt/test_number.py @@ -111,10 +111,8 @@ async def test_number_set_value_error( with patch("homeassistant.components.indevolt.PLATFORMS", [Platform.NUMBER]): await setup_integration(hass, mock_config_entry) - # Mock set_data to raise an error - mock_indevolt.set_data.side_effect = HomeAssistantError( - "Device communication failed" - ) + # Mock set_data to return failure + mock_indevolt.set_data.return_value = False # Attempt to set value with pytest.raises(HomeAssistantError): diff --git a/tests/components/indevolt/test_select.py b/tests/components/indevolt/test_select.py index cf875bd73ddffe..0d3c96a73b14af 100644 --- a/tests/components/indevolt/test_select.py +++ b/tests/components/indevolt/test_select.py @@ -92,10 +92,8 @@ async def test_select_set_option_error( with patch("homeassistant.components.indevolt.PLATFORMS", [Platform.SELECT]): await setup_integration(hass, mock_config_entry) - # Mock set_data to raise an error - mock_indevolt.set_data.side_effect = HomeAssistantError( - "Device communication failed" - ) + # Mock set_data to return failure + mock_indevolt.set_data.return_value = False # Attempt to change option with pytest.raises(HomeAssistantError): diff --git a/tests/components/indevolt/test_switch.py b/tests/components/indevolt/test_switch.py index 577d897ae5c64b..16b1ded3f26a17 100644 --- a/tests/components/indevolt/test_switch.py +++ b/tests/components/indevolt/test_switch.py @@ -167,10 +167,8 @@ async def test_switch_set_value_error( with patch("homeassistant.components.indevolt.PLATFORMS", [Platform.SWITCH]): await setup_integration(hass, mock_config_entry) - # Mock set_data to raise an error - mock_indevolt.set_data.side_effect = HomeAssistantError( - "Device communication failed" - ) + # Mock set_data to return failure + mock_indevolt.set_data.return_value = False # Attempt to switch on with pytest.raises(HomeAssistantError): From 6cf6e8fbd0d85fc94cdb7af107c7c27fb5835311 Mon Sep 17 00:00:00 2001 From: "A. Gideonse" Date: Sun, 10 May 2026 21:56:57 +0000 Subject: [PATCH 2/7] Improved coordinator exception handling --- .../components/indevolt/coordinator.py | 27 +++++-------------- tests/components/indevolt/test_number.py | 1 - tests/components/indevolt/test_select.py | 1 - tests/components/indevolt/test_switch.py | 1 - 4 files changed, 6 insertions(+), 24 deletions(-) diff --git a/homeassistant/components/indevolt/coordinator.py b/homeassistant/components/indevolt/coordinator.py index 12381aa519afbf..8973d3d8c12a13 100644 --- a/homeassistant/components/indevolt/coordinator.py +++ b/homeassistant/components/indevolt/coordinator.py @@ -33,14 +33,6 @@ type IndevoltConfigEntry = ConfigEntry[IndevoltCoordinator] -class DeviceTimeoutError(HomeAssistantError): - """Raised when device push times out.""" - - -class DeviceConnectionError(HomeAssistantError): - """Raised when device push fails due to connection issues.""" - - class IndevoltCoordinator(DataUpdateCoordinator[dict[str, Any]]): """Coordinator for fetching and pushing data to indevolt devices.""" @@ -98,10 +90,9 @@ async def async_push_data(self, sensor_key: str, value: Any) -> bool: """Push/write data values to given key on the device.""" try: return await self.api.set_data(sensor_key, value) - except TimeoutError as err: - raise DeviceTimeoutError(f"Device push timed out: {err}") from err - except (ClientError, OSError) as err: - raise DeviceConnectionError(f"Device push failed: {err}") from err + except (TimeoutError, ClientError, OSError) as err: + _LOGGER.debug("Device push failed for %s: %s", sensor_key, err) + return False async def async_switch_energy_mode( self, target_mode: IndevoltEnergyMode, refresh: bool = True @@ -125,15 +116,9 @@ async def async_switch_energy_mode( # Switch energy mode if required if current_mode != target_mode: - try: - success = await self.async_push_data( - IndevoltConfig.WRITE_ENERGY_MODE, target_mode - ) - except (DeviceTimeoutError, DeviceConnectionError) as err: - raise HomeAssistantError( - translation_domain=DOMAIN, - translation_key="failed_to_switch_energy_mode", - ) from err + success = await self.async_push_data( + IndevoltConfig.WRITE_ENERGY_MODE, target_mode + ) if not success: raise HomeAssistantError( diff --git a/tests/components/indevolt/test_number.py b/tests/components/indevolt/test_number.py index 4b41b729b44cf9..15d3971b2770f2 100644 --- a/tests/components/indevolt/test_number.py +++ b/tests/components/indevolt/test_number.py @@ -111,7 +111,6 @@ async def test_number_set_value_error( with patch("homeassistant.components.indevolt.PLATFORMS", [Platform.NUMBER]): await setup_integration(hass, mock_config_entry) - # Mock set_data to return failure mock_indevolt.set_data.return_value = False # Attempt to set value diff --git a/tests/components/indevolt/test_select.py b/tests/components/indevolt/test_select.py index 0d3c96a73b14af..2360990ed8dcf2 100644 --- a/tests/components/indevolt/test_select.py +++ b/tests/components/indevolt/test_select.py @@ -92,7 +92,6 @@ async def test_select_set_option_error( with patch("homeassistant.components.indevolt.PLATFORMS", [Platform.SELECT]): await setup_integration(hass, mock_config_entry) - # Mock set_data to return failure mock_indevolt.set_data.return_value = False # Attempt to change option diff --git a/tests/components/indevolt/test_switch.py b/tests/components/indevolt/test_switch.py index 16b1ded3f26a17..1184a03ce7a072 100644 --- a/tests/components/indevolt/test_switch.py +++ b/tests/components/indevolt/test_switch.py @@ -167,7 +167,6 @@ async def test_switch_set_value_error( with patch("homeassistant.components.indevolt.PLATFORMS", [Platform.SWITCH]): await setup_integration(hass, mock_config_entry) - # Mock set_data to return failure mock_indevolt.set_data.return_value = False # Attempt to switch on From 86045b799d801a7c040848696e42a48ea5ddafa7 Mon Sep 17 00:00:00 2001 From: "A. Gideonse" Date: Mon, 11 May 2026 00:03:04 +0200 Subject: [PATCH 3/7] Add exception context as suggested by Copilot Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- homeassistant/components/indevolt/coordinator.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/indevolt/coordinator.py b/homeassistant/components/indevolt/coordinator.py index 8973d3d8c12a13..52bed3a9813210 100644 --- a/homeassistant/components/indevolt/coordinator.py +++ b/homeassistant/components/indevolt/coordinator.py @@ -91,7 +91,9 @@ async def async_push_data(self, sensor_key: str, value: Any) -> bool: try: return await self.api.set_data(sensor_key, value) except (TimeoutError, ClientError, OSError) as err: - _LOGGER.debug("Device push failed for %s: %s", sensor_key, err) + _LOGGER.debug( + "Device push failed for %s: %s", sensor_key, err, exc_info=err + ) return False async def async_switch_energy_mode( From c41594d5b56634c8cca66da359f8d2b1fffd0911 Mon Sep 17 00:00:00 2001 From: "A. Gideonse" Date: Sun, 10 May 2026 22:12:19 +0000 Subject: [PATCH 4/7] Simplify translation logic for updates --- homeassistant/components/indevolt/number.py | 5 +---- homeassistant/components/indevolt/select.py | 2 +- homeassistant/components/indevolt/strings.json | 2 +- homeassistant/components/indevolt/switch.py | 5 +---- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/indevolt/number.py b/homeassistant/components/indevolt/number.py index fa89a943bbf3a8..bd4ef3ba12f874 100644 --- a/homeassistant/components/indevolt/number.py +++ b/homeassistant/components/indevolt/number.py @@ -142,8 +142,5 @@ async def async_set_native_value(self, value: float) -> None: raise HomeAssistantError( translation_domain=DOMAIN, translation_key="write_error", - translation_placeholders={ - "name": str(self.name), - "value": str(int_value), - }, + translation_placeholders={"name": str(self.name)}, ) diff --git a/homeassistant/components/indevolt/select.py b/homeassistant/components/indevolt/select.py index aade638833e7ae..2d4b0fab634b4e 100644 --- a/homeassistant/components/indevolt/select.py +++ b/homeassistant/components/indevolt/select.py @@ -112,5 +112,5 @@ async def async_select_option(self, option: str) -> None: raise HomeAssistantError( translation_domain=DOMAIN, translation_key="write_error", - translation_placeholders={"name": str(self.name), "value": option}, + translation_placeholders={"name": str(self.name)}, ) diff --git a/homeassistant/components/indevolt/strings.json b/homeassistant/components/indevolt/strings.json index e2f9854942e2e9..8788333d938d05 100644 --- a/homeassistant/components/indevolt/strings.json +++ b/homeassistant/components/indevolt/strings.json @@ -356,7 +356,7 @@ "message": "Target SOC ({target}%) is below the device minimum ({minimum_soc}%)" }, "write_error": { - "message": "Cannot update {name} to {value}" + "message": "Cannot update value for {name}" } }, "services": { diff --git a/homeassistant/components/indevolt/switch.py b/homeassistant/components/indevolt/switch.py index 91aca0bf130ded..e08f22f3609b38 100644 --- a/homeassistant/components/indevolt/switch.py +++ b/homeassistant/components/indevolt/switch.py @@ -132,8 +132,5 @@ async def _async_toggle(self, value: int) -> None: raise HomeAssistantError( translation_domain=DOMAIN, translation_key="write_error", - translation_placeholders={ - "name": str(self.name), - "value": "on" if value else "off", - }, + translation_placeholders={"name": str(self.name)}, ) From 0ffe2b4b0a9caa8efb2ff86e1f5eca90feaf0478 Mon Sep 17 00:00:00 2001 From: "A. Gideonse" Date: Mon, 11 May 2026 08:48:34 +0200 Subject: [PATCH 5/7] Remove redundant white space --- homeassistant/components/indevolt/quality_scale.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/indevolt/quality_scale.yaml b/homeassistant/components/indevolt/quality_scale.yaml index 9845917b9a7fc9..f93e6679f3cd14 100644 --- a/homeassistant/components/indevolt/quality_scale.yaml +++ b/homeassistant/components/indevolt/quality_scale.yaml @@ -69,7 +69,7 @@ rules: stale-devices: status: exempt comment: Integration represents a single device, not a hub with multiple devices - + # Platinum async-dependency: done inject-websession: done From 6dfccea11e9e4d0885a3d7c8dc346efaf4973328 Mon Sep 17 00:00:00 2001 From: "A. Gideonse" Date: Mon, 11 May 2026 08:42:37 +0000 Subject: [PATCH 6/7] Simplify exception handling using updated library --- homeassistant/components/indevolt/coordinator.py | 8 +------- tests/components/indevolt/test_services.py | 4 ++-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/indevolt/coordinator.py b/homeassistant/components/indevolt/coordinator.py index 52bed3a9813210..f6f2a18cb4a7a1 100644 --- a/homeassistant/components/indevolt/coordinator.py +++ b/homeassistant/components/indevolt/coordinator.py @@ -88,13 +88,7 @@ async def _async_update_data(self) -> dict[str, Any]: async def async_push_data(self, sensor_key: str, value: Any) -> bool: """Push/write data values to given key on the device.""" - try: - return await self.api.set_data(sensor_key, value) - except (TimeoutError, ClientError, OSError) as err: - _LOGGER.debug( - "Device push failed for %s: %s", sensor_key, err, exc_info=err - ) - return False + return await self.api.set_data(sensor_key, value) async def async_switch_energy_mode( self, target_mode: IndevoltEnergyMode, refresh: bool = True diff --git a/tests/components/indevolt/test_services.py b/tests/components/indevolt/test_services.py index d943fabc838041..6a6f2409ee2544 100644 --- a/tests/components/indevolt/test_services.py +++ b/tests/components/indevolt/test_services.py @@ -375,7 +375,7 @@ async def test_single_device_execution_failure( await setup_integration(hass, mock_config_entry) # Simulate an API push failure - mock_indevolt.set_data.side_effect = OSError("Device push failed") + mock_indevolt.set_data.return_value = False # Mock call to start charging with pytest.raises(HomeAssistantError) as exc_info: @@ -409,7 +409,7 @@ async def test_multi_device_execution_failure( await setup_integration(hass, alt_mock_config_entry) # Simulate an API push failure (triggers for both coordinators) - mock_indevolt.set_data.side_effect = OSError("Device push failed") + mock_indevolt.set_data.return_value = False # Mock call to start charging both devices with pytest.raises(HomeAssistantError) as exc_info: From 9819dba31df2ae6224a4eafbcbd884a1bd012932 Mon Sep 17 00:00:00 2001 From: "A. Gideonse" Date: Mon, 11 May 2026 08:46:12 +0000 Subject: [PATCH 7/7] Bump indevolt-api to 1.7.2 --- homeassistant/components/indevolt/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/indevolt/manifest.json b/homeassistant/components/indevolt/manifest.json index 442a641dfeb18f..e9ec848e999313 100644 --- a/homeassistant/components/indevolt/manifest.json +++ b/homeassistant/components/indevolt/manifest.json @@ -7,5 +7,5 @@ "integration_type": "device", "iot_class": "local_polling", "quality_scale": "silver", - "requirements": ["indevolt-api==1.7.1"] + "requirements": ["indevolt-api==1.7.2"] } diff --git a/requirements_all.txt b/requirements_all.txt index eb4c09bc9ddb29..94924123078e03 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1338,7 +1338,7 @@ imgw_pib==2.1.2 incomfort-client==0.7.0 # homeassistant.components.indevolt -indevolt-api==1.7.1 +indevolt-api==1.7.2 # homeassistant.components.influxdb influxdb-client==1.50.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 72ddc371d6a1e7..5e4bd22b239132 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1190,7 +1190,7 @@ imgw_pib==2.1.2 incomfort-client==0.7.0 # homeassistant.components.indevolt -indevolt-api==1.7.1 +indevolt-api==1.7.2 # homeassistant.components.influxdb influxdb-client==1.50.0