From b5ccdf8165f29f598d9ef4576dfbcb02d6c5d72e Mon Sep 17 00:00:00 2001 From: Duco Sebel <74970928+DCSBL@users.noreply.github.com> Date: Thu, 18 Dec 2025 14:01:37 +0100 Subject: [PATCH] Implement new battery charge modes in HomeWizard (#159107) --- .../components/homewizard/manifest.json | 2 +- homeassistant/components/homewizard/select.py | 71 ++++++++----------- .../components/homewizard/strings.json | 4 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- .../homewizard/fixtures/HWE-P1/batteries.json | 2 + .../snapshots/test_diagnostics.ambr | 5 ++ .../homewizard/snapshots/test_select.ambr | 12 ++-- 8 files changed, 47 insertions(+), 53 deletions(-) diff --git a/homeassistant/components/homewizard/manifest.json b/homeassistant/components/homewizard/manifest.json index a96eca28d8c..2ae50ffd0ca 100644 --- a/homeassistant/components/homewizard/manifest.json +++ b/homeassistant/components/homewizard/manifest.json @@ -13,6 +13,6 @@ "iot_class": "local_polling", "loggers": ["homewizard_energy"], "quality_scale": "platinum", - "requirements": ["python-homewizard-energy==9.3.0"], + "requirements": ["python-homewizard-energy==10.0.0"], "zeroconf": ["_hwenergy._tcp.local.", "_homewizard._tcp.local."] } diff --git a/homeassistant/components/homewizard/select.py b/homeassistant/components/homewizard/select.py index 2ae37883107..132eac87375 100644 --- a/homeassistant/components/homewizard/select.py +++ b/homeassistant/components/homewizard/select.py @@ -2,12 +2,7 @@ from __future__ import annotations -from collections.abc import Awaitable, Callable -from dataclasses import dataclass -from typing import Any - -from homewizard_energy import HomeWizardEnergy -from homewizard_energy.models import Batteries, CombinedModels as DeviceResponseEntry +from homewizard_energy.models import Batteries from homeassistant.components.select import SelectEntity, SelectEntityDescription from homeassistant.const import EntityCategory @@ -21,69 +16,59 @@ from .helpers import homewizard_exception_handler PARALLEL_UPDATES = 1 -@dataclass(frozen=True, kw_only=True) -class HomeWizardSelectEntityDescription(SelectEntityDescription): - """Class describing HomeWizard select entities.""" - - available_fn: Callable[[DeviceResponseEntry], bool] - create_fn: Callable[[DeviceResponseEntry], bool] - current_fn: Callable[[DeviceResponseEntry], str | None] - set_fn: Callable[[HomeWizardEnergy, str], Awaitable[Any]] - - -DESCRIPTIONS = [ - HomeWizardSelectEntityDescription( - key="battery_group_mode", - translation_key="battery_group_mode", - entity_category=EntityCategory.CONFIG, - entity_registry_enabled_default=False, - options=[Batteries.Mode.ZERO, Batteries.Mode.STANDBY, Batteries.Mode.TO_FULL], - available_fn=lambda x: x.batteries is not None, - create_fn=lambda x: x.batteries is not None, - current_fn=lambda x: x.batteries.mode if x.batteries else None, - set_fn=lambda api, mode: api.batteries(mode=Batteries.Mode(mode)), - ), -] - - async def async_setup_entry( hass: HomeAssistant, entry: HomeWizardConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Set up HomeWizard select based on a config entry.""" - async_add_entities( - HomeWizardSelectEntity( - coordinator=entry.runtime_data, - description=description, + if entry.runtime_data.data.device.supports_batteries(): + async_add_entities( + [ + HomeWizardBatteryModeSelectEntity( + coordinator=entry.runtime_data, + ) + ] ) - for description in DESCRIPTIONS - if description.create_fn(entry.runtime_data.data) - ) -class HomeWizardSelectEntity(HomeWizardEntity, SelectEntity): +class HomeWizardBatteryModeSelectEntity(HomeWizardEntity, SelectEntity): """Defines a HomeWizard select entity.""" - entity_description: HomeWizardSelectEntityDescription + entity_description: SelectEntityDescription def __init__( self, coordinator: HWEnergyDeviceUpdateCoordinator, - description: HomeWizardSelectEntityDescription, ) -> None: """Initialize the switch.""" super().__init__(coordinator) + + description = SelectEntityDescription( + key="battery_group_mode", + translation_key="battery_group_mode", + entity_category=EntityCategory.CONFIG, + entity_registry_enabled_default=False, + options=[ + str(mode) + for mode in (coordinator.data.device.supported_battery_modes() or []) + ], + ) + self.entity_description = description self._attr_unique_id = f"{coordinator.config_entry.unique_id}_{description.key}" @property def current_option(self) -> str | None: """Return the selected entity option to represent the entity state.""" - return self.entity_description.current_fn(self.coordinator.data) + return ( + self.coordinator.data.batteries.mode + if self.coordinator.data.batteries and self.coordinator.data.batteries.mode + else None + ) @homewizard_exception_handler async def async_select_option(self, option: str) -> None: """Change the selected option.""" - await self.entity_description.set_fn(self.coordinator.api, option) + await self.coordinator.api.batteries(Batteries.Mode(option)) await self.coordinator.async_request_refresh() diff --git a/homeassistant/components/homewizard/strings.json b/homeassistant/components/homewizard/strings.json index 714e99a7f65..e92d6d5d04c 100644 --- a/homeassistant/components/homewizard/strings.json +++ b/homeassistant/components/homewizard/strings.json @@ -65,7 +65,9 @@ "state": { "standby": "Standby", "to_full": "Manual charge mode", - "zero": "Zero mode" + "zero": "Zero mode", + "zero_charge_only": "Zero mode (charge only)", + "zero_discharge_only": "Zero mode (discharge only)" } } }, diff --git a/requirements_all.txt b/requirements_all.txt index 468f535e239..8972f127b75 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2511,7 +2511,7 @@ python-google-weather-api==0.0.4 python-homeassistant-analytics==0.9.0 # homeassistant.components.homewizard -python-homewizard-energy==9.3.0 +python-homewizard-energy==10.0.0 # homeassistant.components.hp_ilo python-hpilo==4.4.3 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index d47b3ed747b..6e2fa8f774e 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -2104,7 +2104,7 @@ python-google-weather-api==0.0.4 python-homeassistant-analytics==0.9.0 # homeassistant.components.homewizard -python-homewizard-energy==9.3.0 +python-homewizard-energy==10.0.0 # homeassistant.components.izone python-izone==1.2.9 diff --git a/tests/components/homewizard/fixtures/HWE-P1/batteries.json b/tests/components/homewizard/fixtures/HWE-P1/batteries.json index 279e49606b3..05560004fff 100644 --- a/tests/components/homewizard/fixtures/HWE-P1/batteries.json +++ b/tests/components/homewizard/fixtures/HWE-P1/batteries.json @@ -1,5 +1,7 @@ { "mode": "zero", + "permissions": ["charge_allowed", "discharge_allowed"], + "battery_count": 2, "power_w": -404, "target_power_w": -400, "max_consumption_w": 1600, diff --git a/tests/components/homewizard/snapshots/test_diagnostics.ambr b/tests/components/homewizard/snapshots/test_diagnostics.ambr index 449dfd0c02f..c465608be87 100644 --- a/tests/components/homewizard/snapshots/test_diagnostics.ambr +++ b/tests/components/homewizard/snapshots/test_diagnostics.ambr @@ -279,9 +279,14 @@ dict({ 'data': dict({ 'batteries': dict({ + 'battery_count': 2, 'max_consumption_w': 1600.0, 'max_production_w': 800.0, 'mode': 'zero', + 'permissions': list([ + 'charge_allowed', + 'discharge_allowed', + ]), 'power_w': -404.0, 'target_power_w': -400.0, }), diff --git a/tests/components/homewizard/snapshots/test_select.ambr b/tests/components/homewizard/snapshots/test_select.ambr index 0797256120c..10898ec527a 100644 --- a/tests/components/homewizard/snapshots/test_select.ambr +++ b/tests/components/homewizard/snapshots/test_select.ambr @@ -4,9 +4,9 @@ 'attributes': ReadOnlyDict({ 'friendly_name': 'Device Battery group mode', 'options': list([ - , - , - , + 'standby', + 'to_full', + 'zero', ]), }), 'context': , @@ -24,9 +24,9 @@ 'area_id': None, 'capabilities': dict({ 'options': list([ - , - , - , + 'standby', + 'to_full', + 'zero', ]), }), 'config_entry_id': ,