diff --git a/__init__.py b/__init__.py index 98b32e0..c228946 100644 --- a/__init__.py +++ b/__init__.py @@ -171,7 +171,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: "Consider enabling elevated permissions to get more optimizer data", exc_info=exception, ) - optimizers_device_infos = None + optimizers_device_infos = {} except Exception as exc: # pylint: disable=broad-except _LOGGER.exception( "Cannot create optimizer sensor entities due to an unexpected error", @@ -319,7 +319,6 @@ async def _create_update_coordinator( device_infos: HuaweiInverterBridgeDeviceInfos, update_interval, ): - coordinator = HuaweiSolarUpdateCoordinator( hass, _LOGGER, @@ -377,7 +376,6 @@ async def _create_optimizer_update_coordinator( optimizer_device_infos: dict[int, DeviceInfo], update_interval, ): - coordinator = HuaweiSolarOptimizerUpdateCoordinator( hass, _LOGGER, @@ -434,7 +432,6 @@ async def _create_configuration_update_coordinator( device_infos: HuaweiInverterBridgeDeviceInfos, update_interval, ): - coordinator = HuaweiSolarConfigurationUpdateCoordinator( hass, _LOGGER, diff --git a/config_flow.py b/config_flow.py index 4fcb4d8..84f3b66 100644 --- a/config_flow.py +++ b/config_flow.py @@ -22,8 +22,8 @@ ConnectionException, HuaweiSolarBridge, HuaweiSolarException, + InvalidCredentials, ReadException, - InvalidCredentials ) from .const import ( @@ -226,7 +226,7 @@ async def async_step_user( async def async_step_setup_serial( self, user_input: dict[str, Any] | None = None ) -> FlowResult: - """Handles connection parameters when using ModbusRTU.""" + """Handle connection parameters when using ModbusRTU.""" # Parameter configuration is always possible over serial connection self._enable_parameter_configuration = True @@ -234,7 +234,6 @@ async def async_step_setup_serial( errors = {} if user_input is not None: - user_selection = user_input[CONF_PORT] if user_selection == CONF_MANUAL_PATH: self._slave_ids = user_input[CONF_SLAVE_IDS] @@ -251,7 +250,6 @@ async def async_step_setup_serial( except ValueError: errors["base"] = "invalid_slave_ids" else: - try: info = await validate_serial_setup(user_input) @@ -317,7 +315,6 @@ async def async_step_setup_serial_manual_path( errors = {} if user_input is not None: - try: user_input[CONF_SLAVE_IDS] = list( map(int, user_input[CONF_SLAVE_IDS].split(",")) @@ -369,7 +366,7 @@ async def async_step_setup_serial_manual_path( async def async_step_setup_network( self, user_input: dict[str, Any] | None = None ) -> FlowResult: - """Handles connection parameters when using ModbusTCP.""" + """Handle connection parameters when using ModbusTCP.""" errors = {} @@ -381,7 +378,6 @@ async def async_step_setup_network( except ValueError: errors["base"] = "invalid_slave_ids" else: - try: info = await validate_network_setup(user_input) diff --git a/diagnostics.py b/diagnostics.py index a9a4a69..de1fd8f 100644 --- a/diagnostics.py +++ b/diagnostics.py @@ -12,15 +12,15 @@ from huawei_solar import HuaweiSolarBridge from . import ( - HuaweiSolarUpdateCoordinator, HuaweiSolarConfigurationUpdateCoordinator, HuaweiSolarOptimizerUpdateCoordinator, + HuaweiSolarUpdateCoordinator, ) from .const import ( - DATA_UPDATE_COORDINATORS, - DOMAIN, DATA_CONFIGURATION_UPDATE_COORDINATORS, DATA_OPTIMIZER_UPDATE_COORDINATORS, + DATA_UPDATE_COORDINATORS, + DOMAIN, ) TO_REDACT = {CONF_PASSWORD} @@ -69,7 +69,6 @@ async def async_get_config_entry_diagnostics( async def _build_bridge_diagnostics_info(bridge: HuaweiSolarBridge) -> dict[str, Any]: - diagnostics_data = { "model_name": bridge.model_name, "pv_string_count": bridge.pv_string_count, diff --git a/hacs.json b/hacs.json index 49fc696..892acb1 100644 --- a/hacs.json +++ b/hacs.json @@ -1,6 +1,6 @@ { - "name": "Huawei Solar", - "content_in_root": true, - "render_readme": true, - "homeassistant": "2023.3.7" -} \ No newline at end of file + "name": "Huawei Solar", + "content_in_root": true, + "render_readme": true, + "homeassistant": "2023.3.7", +} diff --git a/manifest.json b/manifest.json index 8ce323d..25b0e4c 100644 --- a/manifest.json +++ b/manifest.json @@ -1,19 +1,12 @@ { - "domain": "huawei_solar", - "name": "Huawei Solar", - "config_flow": true, - "documentation": "https://www.home-assistant.io/integrations/huawei_solar", - "issue_tracker": "https://github.com/wlcrs/huawei_solar/issues", - "requirements": [ - "huawei-solar==2.2.8b2" - ], - "codeowners": [ - "@wlcrs" - ], - "iot_class": "local_polling", - "version": "1.2.6b8", - "loggers": [ - "huawei_solar", - "pymodbus" - ] -} \ No newline at end of file + "domain": "huawei_solar", + "name": "Huawei Solar", + "config_flow": true, + "documentation": "https://www.home-assistant.io/integrations/huawei_solar", + "issue_tracker": "https://github.com/wlcrs/huawei_solar/issues", + "requirements": ["huawei-solar==2.2.8b2"], + "codeowners": ["@wlcrs"], + "iot_class": "local_polling", + "version": "1.2.6b8", + "loggers": ["huawei_solar", "pymodbus"], +} diff --git a/number.py b/number.py index 2a2e6eb..fd4587b 100644 --- a/number.py +++ b/number.py @@ -1,4 +1,4 @@ -"""This component provides number entities for Huawei Solar.""" +"""Number entities for Huawei Solar.""" from __future__ import annotations import logging @@ -9,7 +9,7 @@ NumberEntityDescription, NumberMode, ) -from homeassistant.components.number.const import DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE +from homeassistant.components.number.const import DEFAULT_MAX_VALUE, DEFAULT_MIN_VALUE from homeassistant.config_entries import ConfigEntry from homeassistant.const import PERCENTAGE, POWER_WATT from homeassistant.core import HomeAssistant, callback @@ -21,11 +21,7 @@ from huawei_solar import register_names as rn from huawei_solar import register_values as rv -from . import ( - HuaweiSolarConfigurationUpdateCoordinator, - HuaweiSolarEntity, - HuaweiSolarUpdateCoordinator, -) +from . import HuaweiSolarConfigurationUpdateCoordinator, HuaweiSolarEntity from .const import ( CONF_ENABLE_PARAMETER_CONFIGURATION, DATA_CONFIGURATION_UPDATE_COORDINATORS, @@ -292,6 +288,7 @@ async def async_set_native_value(self, value: float) -> None: @property def native_max_value(self) -> float: + """Maximum value, possibly determined dynamically using _dynamic_max_value.""" native_max_value = self.entity_description.native_max_value if self._dynamic_max_value: @@ -305,6 +302,7 @@ def native_max_value(self) -> float: @property def native_min_value(self) -> float: + """Minimum value, possibly determined dynamically using _dynamic_min_value.""" native_min_value = self.entity_description.native_min_value if self._dynamic_min_value: diff --git a/select.py b/select.py index 878d1f0..b816232 100644 --- a/select.py +++ b/select.py @@ -1,11 +1,11 @@ -"""This component provides switch entities for Huawei Solar.""" +"""Switch entities for Huawei Solar.""" from __future__ import annotations import logging from collections.abc import Callable from dataclasses import dataclass from enum import IntEnum -from typing import Generic, TypeVar, Any +from typing import Any, Generic, TypeVar, TYPE_CHECKING from homeassistant.components.select import SelectEntity, SelectEntityDescription from homeassistant.config_entries import ConfigEntry @@ -19,11 +19,7 @@ from huawei_solar import register_values as rv from huawei_solar.registers import REGISTERS -from . import ( - HuaweiSolarConfigurationUpdateCoordinator, - HuaweiSolarEntity, - HuaweiSolarUpdateCoordinator, -) +from . import HuaweiSolarConfigurationUpdateCoordinator, HuaweiSolarEntity from .const import ( CONF_ENABLE_PARAMETER_CONFIGURATION, DATA_CONFIGURATION_UPDATE_COORDINATORS, @@ -31,6 +27,9 @@ DOMAIN, ) +if TYPE_CHECKING: + from . import HuaweiSolarUpdateCoordinator + _LOGGER = logging.getLogger(__name__) @@ -78,13 +77,13 @@ async def async_setup_entry( _LOGGER.info("Skipping select setup, as parameter configuration is not enabled") return - update_coordinators = hass.data[DOMAIN][entry.entry_id][ - DATA_UPDATE_COORDINATORS - ] # type: list[HuaweiSolarUpdateCoordinator] + update_coordinators: list[HuaweiSolarUpdateCoordinator] = hass.data[DOMAIN][ + entry.entry_id + ][DATA_UPDATE_COORDINATORS] - configuration_update_coordinators = hass.data[DOMAIN][entry.entry_id][ - DATA_CONFIGURATION_UPDATE_COORDINATORS - ] + configuration_update_coordinators: list[ + HuaweiSolarConfigurationUpdateCoordinator + ] = hass.data[DOMAIN][entry.entry_id][DATA_CONFIGURATION_UPDATE_COORDINATORS] # When more than one inverter is present, then we suffix all sensors with '#1', '#2', ... # The order for these suffixes is the order in which the user entered the slave-ids. @@ -94,7 +93,7 @@ async def async_setup_entry( for idx, (update_coordinator, configuration_update_coordinator) in enumerate( zip(update_coordinators, configuration_update_coordinators) ): - slave_entities: list[HuaweiSolarSelectEntity] = [] + slave_entities: list[HuaweiSolarSelectEntity | StorageModeSelectEntity] = [] bridge = update_coordinator.bridge device_infos = update_coordinator.device_infos @@ -210,8 +209,7 @@ async def async_select_option(self, option) -> None: @property def available(self) -> bool: - """Override available property (from CoordinatorEntity) to take into account - the custom check_is_available_func result""" + """Override available property (from CoordinatorEntity) to take into account the custom check_is_available_func result.""" available = super().available if self.entity_description.check_is_available_func and available: diff --git a/sensor.py b/sensor.py index 656254c..0f2f762 100644 --- a/sensor.py +++ b/sensor.py @@ -4,7 +4,7 @@ from collections.abc import Callable from dataclasses import dataclass from itertools import zip_longest -from typing import Any, Union +from typing import Any from homeassistant.components.sensor import ( SensorDeviceClass, @@ -28,7 +28,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import CoordinatorEntity -from huawei_solar import HuaweiSolarBridge +from huawei_solar import HuaweiSolarBridge, Result from huawei_solar import register_names as rn from huawei_solar import register_values as rv from huawei_solar.files import OptimizerRunningStatus @@ -704,7 +704,12 @@ async def async_setup_entry( for idx, (update_coordinator, configuration_update_coordinator) in enumerate( zip_longest(update_coordinators, configuration_update_coordinators) ): - slave_entities: list[HuaweiSolarSensorEntity] = [] + slave_entities: list[ + HuaweiSolarSensorEntity + | HuaweiSolarTOUPricePeriodsSensorEntity + | HuaweiSolarFixedChargingPeriodsSensorEntity + | HuaweiSolarCapacityControlPeriodsSensorEntity + ] = [] bridge = update_coordinator.bridge device_infos = update_coordinator.device_infos @@ -799,7 +804,7 @@ async def async_setup_entry( DATA_OPTIMIZER_UPDATE_COORDINATORS ] # type: list[HuaweiSolarOptimizerUpdateCoordinator] - for idx, update_coordinator in enumerate(optimizer_update_coordinators): + for update_coordinator in optimizer_update_coordinators: optimizer_entities: list[HuaweiSolarOptimizerSensorEntity] = [] bridge = update_coordinator.bridge @@ -865,8 +870,7 @@ def _handle_coordinator_update(self) -> None: class HuaweiSolarAlarmSensorEntity(HuaweiSolarSensorEntity): - """Huawei Solar Sensor for Alarm values, which are spread over three - registers that are received by the DataUpdateCoordinator""" + """Huawei Solar Sensor for Alarm values, which are spread over three registers that are received by the DataUpdateCoordinator.""" ALARM_REGISTERS = [rn.ALARM_1, rn.ALARM_2, rn.ALARM_3] @@ -904,7 +908,7 @@ def _handle_coordinator_update(self) -> None: self.async_write_ha_state() -def _days_effective_to_str(days: tuple(bool, bool, bool, bool, bool, bool, bool)): +def _days_effective_to_str(days: tuple[bool, bool, bool, bool, bool, bool, bool]): value = "" for i in range(0, 7): # Sunday is on index 0, but we want to name it day 7 if days[(i + 1) % 7]: @@ -923,7 +927,8 @@ class HuaweiSolarTOUPricePeriodsSensorEntity( """Huawei Solar Sensor for configured TOU periods. It shows the number of configured TOU periods, and has the - contents of them as extended attributes""" + contents of them as extended attributes + """ def __init__( self, @@ -963,17 +968,17 @@ def _huawei_luna2000_period_to_text(self, period: HUAWEI_LUNA2000_TimeOfUsePerio def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" - result: Union[ - list[LG_RESU_TimeOfUsePeriod], list[HUAWEI_LUNA2000_TimeOfUsePeriod] - ] = self.coordinator.data.get( + result: Result = self.coordinator.data.get( rn.STORAGE_TIME_OF_USE_CHARGING_AND_DISCHARGING_PERIODS ) - data = result.value if result else [] + data: list[LG_RESU_TimeOfUsePeriod] | list[HUAWEI_LUNA2000_TimeOfUsePeriod] = ( + result.value if result else [] + ) self._attr_native_value = len(data) if len(data) == 0: - self._attr_extra_state_attributes = {} + self._attr_extra_state_attributes.clear() else: if isinstance(data[0], LG_RESU_TimeOfUsePeriod): self._attr_extra_state_attributes = { @@ -994,7 +999,8 @@ class HuaweiSolarCapacityControlPeriodsSensorEntity( """Huawei Solar Sensor for configured Capacity Control periods. It shows the number of configured capacity control periods, and has the - contents of them as extended attributes""" + contents of them as extended attributes + """ def __init__( self, @@ -1042,7 +1048,7 @@ def _handle_coordinator_update(self) -> None: self._attr_available = True else: self._attr_native_value = None - self._attr_extra_state_attributes = None + self._attr_extra_state_attributes.clear() self._attr_available = False self.async_write_ha_state() @@ -1054,7 +1060,8 @@ class HuaweiSolarFixedChargingPeriodsSensorEntity( """Huawei Solar Sensor for configured Fixed Charging and Discharging periods. It shows the number of configured fixed charging and discharging periods, and has the - contents of them as extended attributes""" + contents of them as extended attributes + """ def __init__( self, @@ -1087,12 +1094,12 @@ def _period_to_text(self, cdp: ChargeDischargePeriod): @callback def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" - result: list[ChargeDischargePeriod] = self.coordinator.data.get( + result: Result = self.coordinator.data.get( rn.STORAGE_FIXED_CHARGING_AND_DISCHARGING_PERIODS ) if result: - data = result.value + data: list[ChargeDischargePeriod] = result.value self._attr_native_value = len(data) self._attr_extra_state_attributes = { f"Period {idx+1}": self._period_to_text(period) @@ -1101,7 +1108,7 @@ def _handle_coordinator_update(self) -> None: self._attr_available = True else: self._attr_native_value = None - self._attr_extra_state_attributes = None + self._attr_extra_state_attributes.clear() self._attr_available = False self.async_write_ha_state() diff --git a/services.py b/services.py index 50ac3d2..37c3662 100644 --- a/services.py +++ b/services.py @@ -9,7 +9,7 @@ import voluptuous as vol from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, ServiceCall -from homeassistant.helpers import device_registry +from homeassistant.helpers import device_registry as dr from huawei_solar import HuaweiSolarBridge from huawei_solar import register_names as rn @@ -30,13 +30,13 @@ SERVICE_FORCIBLE_DISCHARGE, SERVICE_FORCIBLE_DISCHARGE_SOC, SERVICE_RESET_MAXIMUM_FEED_GRID_POWER, - SERVICE_SET_DI_ACTIVE_POWER_SCHEDULING, - SERVICE_SET_ZERO_POWER_GRID_CONNECTION, SERVICE_SET_CAPACITY_CONTROL_PERIODS, + SERVICE_SET_DI_ACTIVE_POWER_SCHEDULING, SERVICE_SET_FIXED_CHARGE_PERIODS, SERVICE_SET_MAXIMUM_FEED_GRID_POWER, SERVICE_SET_MAXIMUM_FEED_GRID_POWER_PERCENT, SERVICE_SET_TOU_PERIODS, + SERVICE_SET_ZERO_POWER_GRID_CONNECTION, SERVICE_STOP_FORCIBLE_CHARGE, ) @@ -95,7 +95,7 @@ { vol.Required(DATA_PERIODS): vol.All( cv.string, - vol.Match((HUAWEI_LUNA2000_TOU_PATTERN + r"|" + LG_RESU_TOU_PATTERN)), + vol.Match(HUAWEI_LUNA2000_TOU_PATTERN + r"|" + LG_RESU_TOU_PATTERN), ) } ) @@ -149,7 +149,7 @@ def _parse_time(value: str): return minutes_since_midnight -async def async_setup_services( +async def async_setup_services( # noqa: C901 hass: HomeAssistant, entry: ConfigEntry, bridges_with_device_infos: list[ @@ -159,7 +159,7 @@ async def async_setup_services( """Huawei Solar Services Setup.""" def get_battery_bridge(service_call: ServiceCall): - dev_reg = device_registry.async_get(hass) + dev_reg = dr.async_get(hass) device_entry = dev_reg.async_get(service_call.data[DATA_DEVICE_ID]) if not device_entry: @@ -182,14 +182,13 @@ def get_battery_bridge(service_call: ServiceCall): ) def get_inverter_bridge(service_call: ServiceCall): - dev_reg = device_registry.async_get(hass) + dev_reg = dr.async_get(hass) device_entry = dev_reg.async_get(service_call.data[DATA_DEVICE_ID]) if not device_entry: raise HuaweiSolarServiceException("No such device found") for bridge, device_infos in bridges_with_device_infos: - for identifier in device_infos["inverter"]["identifiers"]: for device_identifier in device_entry.identifiers: if identifier == device_identifier: @@ -293,7 +292,7 @@ async def forcible_discharge_soc(service_call: ServiceCall) -> None: ) async def stop_forcible_charge(service_call: ServiceCall) -> None: - """Stops a forcible charge or discharge.""" + """Stop a forcible charge or discharge.""" bridge = get_battery_bridge(service_call) await bridge.set( @@ -308,7 +307,7 @@ async def stop_forcible_charge(service_call: ServiceCall) -> None: await bridge.set(rn.STORAGE_FORCIBLE_CHARGE_DISCHARGE_SETTING_MODE, 0) async def reset_maximum_feed_grid_power(service_call: ServiceCall) -> None: - """Sets Active Power Control to 'Unlimited'""" + """Set Active Power Control to 'Unlimited'.""" bridge = get_inverter_bridge(service_call) await bridge.set( @@ -322,7 +321,7 @@ async def reset_maximum_feed_grid_power(service_call: ServiceCall) -> None: ) async def set_di_active_power_scheduling(service_call: ServiceCall) -> None: - """Sets Active Power Control to 'DI active scheduling'""" + """Set Active Power Control to 'DI active scheduling'.""" bridge = get_inverter_bridge(service_call) await bridge.set( @@ -336,7 +335,7 @@ async def set_di_active_power_scheduling(service_call: ServiceCall) -> None: ) async def set_zero_power_grid_connection(service_call: ServiceCall) -> None: - """Sets Active Power Control to 'Zero-Power Grid Connection'""" + """Set Active Power Control to 'Zero-Power Grid Connection'.""" bridge = get_inverter_bridge(service_call) await bridge.set( @@ -349,9 +348,8 @@ async def set_zero_power_grid_connection(service_call: ServiceCall) -> None: 0, ) - async def set_maximum_feed_grid_power(service_call: ServiceCall) -> None: - """Sets Active Power Control to 'Power-limited grid connection' with the given wattage.""" + """Set Active Power Control to 'Power-limited grid connection' with the given wattage.""" bridge = get_inverter_bridge(service_call) power = await _validate_power_value( @@ -365,7 +363,7 @@ async def set_maximum_feed_grid_power(service_call: ServiceCall) -> None: ) async def set_maximum_feed_grid_power_percentage(service_call: ServiceCall) -> None: - """Sets Active Power Control to 'Power-limited grid connection' with the given percentage.""" + """Set Active Power Control to 'Power-limited grid connection' with the given percentage.""" bridge = get_inverter_bridge(service_call) power_percentage = service_call.data[DATA_POWER_PERCENTAGE] diff --git a/strings.json b/strings.json index f5836d6..161776d 100644 --- a/strings.json +++ b/strings.json @@ -1,51 +1,47 @@ { - "config": { - "step": { - "user": { - "data": { - "type": "Connection type" + "config": { + "step": { + "user": { + "data": {"type": "Connection type"}, + "title": "Select connection type", + }, + "setup_serial": { + "data": { + "port": "Select device", + "slave_ids": "Slave IDs (Comma separated)", + }, + "title": "Device", + }, + "setup_serial_manual_path": { + "data": {"port": "[%key:common::config_flow::data::usb_path%]"}, + "title": "Path", + }, + "setup_network": { + "data": { + "host": "[%key:common::config_flow::data::host%]", + "port": "[%key:common::config_flow::data::port%]", + "slave_ids": "Slave IDs (Comma separated)", + "enable_parameter_configuration": "Advanced: elevate permissions", + } + }, + "network_login": { + "description": "Please enter the Installer credentials", + "data": { + "username": "[%key:common::config_flow::data::username%]", + "password": "[%key:common::config_flow::data::password%]", + }, + }, }, - "title": "Select connection type" - }, - "setup_serial": { - "data": { - "port": "Select device", - "slave_ids": "Slave IDs (Comma separated)" + "error": { + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", + "slave_cannot_connect": "Failed to connect to additional slave", + "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]", + "unknown": "[%key:common::config_flow::error::unknown%]", + "read_error": "Reading from the inverter failed.", + "invalid_slave_ids": "Slave IDs must be comma-separated list of ints", }, - "title": "Device" - }, - "setup_serial_manual_path": { - "data": { - "port": "[%key:common::config_flow::data::usb_path%]" + "abort": { + "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" }, - "title": "Path" - }, - "setup_network": { - "data": { - "host": "[%key:common::config_flow::data::host%]", - "port": "[%key:common::config_flow::data::port%]", - "slave_ids": "Slave IDs (Comma separated)", - "enable_parameter_configuration": "Advanced: elevate permissions" - } - }, - "network_login": { - "description": "Please enter the Installer credentials", - "data": { - "username": "[%key:common::config_flow::data::username%]", - "password": "[%key:common::config_flow::data::password%]" - } - } - }, - "error": { - "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", - "slave_cannot_connect": "Failed to connect to additional slave", - "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]", - "unknown": "[%key:common::config_flow::error::unknown%]", - "read_error": "Reading from the inverter failed.", - "invalid_slave_ids": "Slave IDs must be comma-separated list of ints" - }, - "abort": { - "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" } - } } diff --git a/switch.py b/switch.py index 55c938c..a9adf8f 100644 --- a/switch.py +++ b/switch.py @@ -1,11 +1,11 @@ -"""This component provides switch entities for Huawei Solar.""" +"""Switch entities for Huawei Solar.""" from __future__ import annotations import asyncio import logging from collections.abc import Callable from dataclasses import dataclass -from typing import Generic, TypeVar, Any +from typing import Any, Generic, TypeVar from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription from homeassistant.config_entries import ConfigEntry @@ -85,7 +85,9 @@ async def async_setup_entry( for idx, (update_coordinator, configuration_update_coordinator) in enumerate( zip(update_coordinators, configuration_update_coordinators) ): - slave_entities: list[HuaweiSolarSwitchEntity] = [] + slave_entities: list[ + HuaweiSolarSwitchEntity | HuaweiSolarOnOffSwitchEntity + ] = [] bridge = update_coordinator.bridge device_infos = update_coordinator.device_infos @@ -186,8 +188,7 @@ async def async_turn_off(self, **kwargs) -> None: @property def available(self) -> bool: - """Override available property (from CoordinatorEntity) to take into account - the custom check_is_available_func result""" + """Override available property (from CoordinatorEntity) to take into account the custom check_is_available_func result.""" available = super().available if self.entity_description.check_is_available_func and available: @@ -199,8 +200,6 @@ def available(self) -> bool: class HuaweiSolarOnOffSwitchEntity(CoordinatorEntity, HuaweiSolarEntity, SwitchEntity): """Huawei Solar Switch Entity.""" - entity_description: HuaweiSolarSwitchEntityDescription - POLL_FREQUENCY_SECONDS = 15 MAX_STATUS_CHANGE_TIME_SECONDS = 3000 # Maximum status change time is 5 minutes @@ -250,15 +249,16 @@ def _handle_coordinator_update(self) -> None: async def async_turn_on(self, **kwargs) -> None: """Turn the setting on.""" async with self._change_lock: - await self.bridge.set(rn.STARTUP, 0) # Turning on can take up to 5 minutes... We'll poll every 15 seconds for _ in range( self.MAX_STATUS_CHANGE_TIME_SECONDS // self.POLL_FREQUENCY_SECONDS ): - asyncio.sleep(self.POLL_FREQUENCY_SECONDS) - device_status = (await self.bridge.client.get(rn.DEVICE_STATUS, bridge.slave_id)).value + await asyncio.sleep(self.POLL_FREQUENCY_SECONDS) + device_status = ( + await self.bridge.client.get(rn.DEVICE_STATUS, self.bridge.slave_id) + ).value if not self._is_off(device_status): self._attr_is_on = True break @@ -275,8 +275,10 @@ async def async_turn_off(self, **kwargs) -> None: for _ in range( self.MAX_STATUS_CHANGE_TIME_SECONDS // self.POLL_FREQUENCY_SECONDS ): - asyncio.sleep(self.POLL_FREQUENCY_SECONDS) - device_status = (await self.bridge.client.get(rn.DEVICE_STATUS, bridge.slave_id)).value + await asyncio.sleep(self.POLL_FREQUENCY_SECONDS) + device_status = ( + await self.bridge.client.get(rn.DEVICE_STATUS, self.bridge.slave_id) + ).value if self._is_off(device_status): self._attr_is_on = False break