diff --git a/homeassistant/components/homewizard/__init__.py b/homeassistant/components/homewizard/__init__.py index 5c41e0e2925..c123c9d34e1 100644 --- a/homeassistant/components/homewizard/__init__.py +++ b/homeassistant/components/homewizard/__init__.py @@ -1,6 +1,4 @@ """The Homewizard integration.""" -import logging - from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntry from homeassistant.const import CONF_IP_ADDRESS from homeassistant.core import HomeAssistant @@ -9,8 +7,6 @@ from homeassistant.exceptions import ConfigEntryNotReady from .const import DOMAIN, PLATFORMS from .coordinator import HWEnergyDeviceUpdateCoordinator as Coordinator -_LOGGER = logging.getLogger(__name__) - async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up Homewizard from a config entry.""" @@ -19,22 +15,23 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: await coordinator.async_config_entry_first_refresh() except ConfigEntryNotReady: - await coordinator.api.close() + await coordinator.api.close() # type: ignore[no-untyped-call] if coordinator.api_disabled: entry.async_start_reauth(hass) raise + hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator + # Abort reauth config flow if active for progress_flow in hass.config_entries.flow.async_progress_by_handler(DOMAIN): - if progress_flow["context"].get("source") == SOURCE_REAUTH: + if ( + "context" in progress_flow + and progress_flow["context"].get("source") == SOURCE_REAUTH + ): hass.config_entries.flow.async_abort(progress_flow["flow_id"]) - # Setup entry - hass.data.setdefault(DOMAIN, {}) - hass.data[DOMAIN][entry.entry_id] = coordinator - # Finalize await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) @@ -43,12 +40,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload a config entry.""" - _LOGGER.debug("__init__ async_unload_entry") - - unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) - - if unload_ok: + if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): coordinator = hass.data[DOMAIN].pop(entry.entry_id) await coordinator.api.close() - return unload_ok diff --git a/homeassistant/components/homewizard/config_flow.py b/homeassistant/components/homewizard/config_flow.py index 3ae2d5fba17..1960b2e79a7 100644 --- a/homeassistant/components/homewizard/config_flow.py +++ b/homeassistant/components/homewizard/config_flow.py @@ -251,7 +251,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): raise AbortFlow("unknown_error") from ex finally: - await energy_api.close() + await energy_api.close() # type: ignore[no-untyped-call] async def _async_set_and_check_unique_id(self, entry_info: dict[str, Any]) -> None: """Validate if entry exists.""" diff --git a/homeassistant/components/homewizard/const.py b/homeassistant/components/homewizard/const.py index e5ceb5ab23d..7627d48accb 100644 --- a/homeassistant/components/homewizard/const.py +++ b/homeassistant/components/homewizard/const.py @@ -1,8 +1,8 @@ """Constants for the Homewizard integration.""" from __future__ import annotations +from dataclasses import dataclass from datetime import timedelta -from typing import TypedDict # Set up. from homewizard_energy.models import Data, Device, State, System @@ -24,10 +24,11 @@ CONF_SERIAL = "serial" UPDATE_INTERVAL = timedelta(seconds=5) -class DeviceResponseEntry(TypedDict): +@dataclass +class DeviceResponseEntry: """Dict describing a single response entry.""" device: Device data: Data - state: State - system: System + state: State | None + system: System | None = None diff --git a/homeassistant/components/homewizard/coordinator.py b/homeassistant/components/homewizard/coordinator.py index c97a1319407..f49f7f8ccdc 100644 --- a/homeassistant/components/homewizard/coordinator.py +++ b/homeassistant/components/homewizard/coordinator.py @@ -39,16 +39,15 @@ class HWEnergyDeviceUpdateCoordinator(DataUpdateCoordinator[DeviceResponseEntry] # Update all properties try: - data: DeviceResponseEntry = { - "device": await self.api.device(), - "data": await self.api.data(), - "state": await self.api.state(), - "system": None, - } + data = DeviceResponseEntry( + device=await self.api.device(), + data=await self.api.data(), + state=await self.api.state(), + ) features = await self.api.features() if features.has_system: - data["system"] = await self.api.system() + data.system = await self.api.system() except RequestError as ex: raise UpdateFailed(ex) from ex diff --git a/homeassistant/components/homewizard/diagnostics.py b/homeassistant/components/homewizard/diagnostics.py index a0c852cf4b6..814c3b78355 100644 --- a/homeassistant/components/homewizard/diagnostics.py +++ b/homeassistant/components/homewizard/diagnostics.py @@ -22,13 +22,13 @@ async def async_get_config_entry_diagnostics( coordinator: HWEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] meter_data = { - "device": asdict(coordinator.data["device"]), - "data": asdict(coordinator.data["data"]), - "state": asdict(coordinator.data["state"]) - if coordinator.data["state"] is not None + "device": asdict(coordinator.data.device), + "data": asdict(coordinator.data.data), + "state": asdict(coordinator.data.state) + if coordinator.data.state is not None else None, - "system": asdict(coordinator.data["system"]) - if coordinator.data["system"] is not None + "system": asdict(coordinator.data.system) + if coordinator.data.system is not None else None, } diff --git a/homeassistant/components/homewizard/entity.py b/homeassistant/components/homewizard/entity.py index 604759e1e91..2aa1b0369d9 100644 --- a/homeassistant/components/homewizard/entity.py +++ b/homeassistant/components/homewizard/entity.py @@ -1,6 +1,7 @@ """Base entity for the HomeWizard integration.""" from __future__ import annotations +from homeassistant.const import ATTR_IDENTIFIERS from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.update_coordinator import CoordinatorEntity @@ -19,7 +20,11 @@ class HomeWizardEntity(CoordinatorEntity[HWEnergyDeviceUpdateCoordinator]): self._attr_device_info = DeviceInfo( name=coordinator.entry.title, manufacturer="HomeWizard", - sw_version=coordinator.data["device"].firmware_version, - model=coordinator.data["device"].product_type, - identifiers={(DOMAIN, coordinator.data["device"].serial)}, + sw_version=coordinator.data.device.firmware_version, + model=coordinator.data.device.product_type, ) + + if coordinator.data.device.serial is not None: + self._attr_device_info[ATTR_IDENTIFIERS] = { + (DOMAIN, coordinator.data.device.serial) + } diff --git a/homeassistant/components/homewizard/helpers.py b/homeassistant/components/homewizard/helpers.py index 59aae7367ec..953bdd0c0a6 100644 --- a/homeassistant/components/homewizard/helpers.py +++ b/homeassistant/components/homewizard/helpers.py @@ -21,7 +21,8 @@ def homewizard_exception_handler( """Decorate HomeWizard Energy calls to handle HomeWizardEnergy exceptions. A decorator that wraps the passed in function, catches HomeWizardEnergy errors, - and reloads the integration when the API was disabled so the reauth flow is triggered. + and reloads the integration when the API was disabled so the reauth flow is + triggered. """ async def handler( @@ -29,7 +30,6 @@ def homewizard_exception_handler( ) -> None: try: await func(self, *args, **kwargs) - except RequestError as ex: raise HomeAssistantError from ex except DisabledError as ex: diff --git a/homeassistant/components/homewizard/manifest.json b/homeassistant/components/homewizard/manifest.json index 8af3ba4b297..9ad05ff89a0 100644 --- a/homeassistant/components/homewizard/manifest.json +++ b/homeassistant/components/homewizard/manifest.json @@ -4,7 +4,7 @@ "documentation": "https://www.home-assistant.io/integrations/homewizard", "codeowners": ["@DCSBL"], "dependencies": [], - "requirements": ["python-homewizard-energy==1.4.0"], + "requirements": ["python-homewizard-energy==1.5.0"], "zeroconf": ["_hwenergy._tcp.local."], "config_flow": true, "quality_scale": "platinum", diff --git a/homeassistant/components/homewizard/number.py b/homeassistant/components/homewizard/number.py index 82218a11d5a..605d0371386 100644 --- a/homeassistant/components/homewizard/number.py +++ b/homeassistant/components/homewizard/number.py @@ -1,8 +1,6 @@ """Creates HomeWizard Number entities.""" from __future__ import annotations -from typing import Optional, cast - from homeassistant.components.number import NumberEntity from homeassistant.config_entries import ConfigEntry from homeassistant.const import PERCENTAGE @@ -23,19 +21,17 @@ async def async_setup_entry( ) -> None: """Set up numbers for device.""" coordinator: HWEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] - - if coordinator.data["state"]: - async_add_entities( - [ - HWEnergyNumberEntity(coordinator, entry), - ] - ) + if coordinator.data.state: + async_add_entities([HWEnergyNumberEntity(coordinator, entry)]) class HWEnergyNumberEntity(HomeWizardEntity, NumberEntity): """Representation of status light number.""" _attr_entity_category = EntityCategory.CONFIG + _attr_icon = "mdi:lightbulb-on" + _attr_name = "Status light brightness" + _attr_native_unit_of_measurement = PERCENTAGE def __init__( self, @@ -45,20 +41,19 @@ class HWEnergyNumberEntity(HomeWizardEntity, NumberEntity): """Initialize the control number.""" super().__init__(coordinator) self._attr_unique_id = f"{entry.unique_id}_status_light_brightness" - self._attr_name = "Status light brightness" - self._attr_native_unit_of_measurement = PERCENTAGE - self._attr_icon = "mdi:lightbulb-on" @homewizard_exception_handler async def async_set_native_value(self, value: float) -> None: """Set a new value.""" - await self.coordinator.api.state_set(brightness=value * (255 / 100)) + await self.coordinator.api.state_set(brightness=int(value * (255 / 100))) await self.coordinator.async_refresh() @property def native_value(self) -> float | None: """Return the current value.""" - brightness = cast(Optional[float], self.coordinator.data["state"].brightness) - if brightness is None: + if ( + self.coordinator.data.state is None + or self.coordinator.data.state.brightness is None + ): return None - return round(brightness * (100 / 255)) + return round(self.coordinator.data.state.brightness * (100 / 255)) diff --git a/homeassistant/components/homewizard/sensor.py b/homeassistant/components/homewizard/sensor.py index 79fb2a72aef..0e7a494dcd8 100644 --- a/homeassistant/components/homewizard/sensor.py +++ b/homeassistant/components/homewizard/sensor.py @@ -137,11 +137,13 @@ async def async_setup_entry( """Initialize sensors.""" coordinator: HWEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] - entities = [] - if coordinator.data["data"] is not None: - for description in SENSORS: - if getattr(coordinator.data["data"], description.key) is not None: - entities.append(HWEnergySensor(coordinator, entry, description)) + entities: list[HWEnergySensor] = [] + if coordinator.data.data is not None: + entities.extend( + HWEnergySensor(coordinator, entry, description) + for description in SENSORS + if getattr(coordinator.data.data, description.key) is not None + ) async_add_entities(entities) @@ -166,12 +168,15 @@ class HWEnergySensor(HomeWizardEntity, SensorEntity): # Special case for export, not everyone has solarpanels # The chance that 'export' is non-zero when you have solar panels is nil - if self.data_type in [ - "total_power_export_t1_kwh", - "total_power_export_t2_kwh", - ]: - if self.native_value == 0: - self._attr_entity_registry_enabled_default = False + if ( + self.data_type + in [ + "total_power_export_t1_kwh", + "total_power_export_t2_kwh", + ] + and self.native_value == 0 + ): + self._attr_entity_registry_enabled_default = False @property def data(self) -> DeviceResponseEntry: @@ -181,7 +186,7 @@ class HWEnergySensor(HomeWizardEntity, SensorEntity): @property def native_value(self) -> StateType: """Return state of meter.""" - return cast(StateType, getattr(self.data["data"], self.data_type)) + return cast(StateType, getattr(self.data.data, self.data_type)) @property def available(self) -> bool: diff --git a/homeassistant/components/homewizard/switch.py b/homeassistant/components/homewizard/switch.py index fcc157734f4..1f76940fb1b 100644 --- a/homeassistant/components/homewizard/switch.py +++ b/homeassistant/components/homewizard/switch.py @@ -25,11 +25,11 @@ async def async_setup_entry( entities: list[SwitchEntity] = [] - if coordinator.data["state"]: + if coordinator.data.state: entities.append(HWEnergyMainSwitchEntity(coordinator, entry)) entities.append(HWEnergySwitchLockEntity(coordinator, entry)) - if coordinator.data["system"]: + if coordinator.data.system: entities.append(HWEnergyEnableCloudEntity(hass, coordinator, entry)) async_add_entities(entities) @@ -79,12 +79,18 @@ class HWEnergyMainSwitchEntity(HWEnergySwitchEntity): This switch becomes unavailable when switch_lock is enabled. """ - return super().available and not self.coordinator.data["state"].switch_lock + return ( + super().available + and self.coordinator.data.state is not None + and not self.coordinator.data.state.switch_lock + ) @property - def is_on(self) -> bool: + def is_on(self) -> bool | None: """Return true if switch is on.""" - return bool(self.coordinator.data["state"].power_on) + if self.coordinator.data.state is None: + return None + return self.coordinator.data.state.power_on class HWEnergySwitchLockEntity(HWEnergySwitchEntity): @@ -118,9 +124,11 @@ class HWEnergySwitchLockEntity(HWEnergySwitchEntity): await self.coordinator.async_refresh() @property - def is_on(self) -> bool: + def is_on(self) -> bool | None: """Return true if switch is on.""" - return bool(self.coordinator.data["state"].switch_lock) + if self.coordinator.data.state is None: + return None + return self.coordinator.data.state.switch_lock class HWEnergyEnableCloudEntity(HWEnergySwitchEntity): @@ -164,6 +172,8 @@ class HWEnergyEnableCloudEntity(HWEnergySwitchEntity): return "mdi:cloud" if self.is_on else "mdi:cloud-off-outline" @property - def is_on(self) -> bool: + def is_on(self) -> bool | None: """Return true if cloud connection is active.""" - return bool(self.coordinator.data["system"].cloud_enabled) + if self.coordinator.data.system is None: + return None + return self.coordinator.data.system.cloud_enabled diff --git a/requirements_all.txt b/requirements_all.txt index 5970eca0153..9a71bfe20f9 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2039,7 +2039,7 @@ python-gc100==1.0.3a0 python-gitlab==1.6.0 # homeassistant.components.homewizard -python-homewizard-energy==1.4.0 +python-homewizard-energy==1.5.0 # homeassistant.components.hp_ilo python-hpilo==4.3 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 8c0d61eb173..f1a7befbce8 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1444,7 +1444,7 @@ python-forecastio==1.4.0 python-fullykiosk==0.0.12 # homeassistant.components.homewizard -python-homewizard-energy==1.4.0 +python-homewizard-energy==1.5.0 # homeassistant.components.izone python-izone==1.2.9