From c725238c209392fede2c65e67214e5b29637cb16 Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Tue, 23 Jan 2024 23:36:44 +0100 Subject: [PATCH] Fix alexa fails reporting the state in specific cases (#108743) * Fix alexa fails reporting the state in specific cases * More cases --- .../components/alexa/capabilities.py | 32 +++++++++++-------- homeassistant/components/alexa/entities.py | 5 +-- homeassistant/components/alexa/handlers.py | 8 ++--- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/alexa/capabilities.py b/homeassistant/components/alexa/capabilities.py index ab3bd8591fd..d30f3f7376d 100644 --- a/homeassistant/components/alexa/capabilities.py +++ b/homeassistant/components/alexa/capabilities.py @@ -860,8 +860,8 @@ class AlexaInputController(AlexaCapability): def inputs(self) -> list[dict[str, str]] | None: """Return the list of valid supported inputs.""" - source_list: list[Any] = self.entity.attributes.get( - media_player.ATTR_INPUT_SOURCE_LIST, [] + source_list: list[Any] = ( + self.entity.attributes.get(media_player.ATTR_INPUT_SOURCE_LIST) or [] ) return AlexaInputController.get_valid_inputs(source_list) @@ -1196,7 +1196,7 @@ class AlexaThermostatController(AlexaCapability): return None supported_modes: list[str] = [] - hvac_modes = self.entity.attributes.get(climate.ATTR_HVAC_MODES, []) + hvac_modes = self.entity.attributes.get(climate.ATTR_HVAC_MODES) or [] for mode in hvac_modes: if thermostat_mode := API_THERMOSTAT_MODES.get(mode): supported_modes.append(thermostat_mode) @@ -1422,18 +1422,22 @@ class AlexaModeController(AlexaCapability): # Humidifier mode if self.instance == f"{humidifier.DOMAIN}.{humidifier.ATTR_MODE}": - mode = self.entity.attributes.get(humidifier.ATTR_MODE, None) - if mode in self.entity.attributes.get(humidifier.ATTR_AVAILABLE_MODES, []): + mode = self.entity.attributes.get(humidifier.ATTR_MODE) + modes: list[str] = ( + self.entity.attributes.get(humidifier.ATTR_AVAILABLE_MODES) or [] + ) + if mode in modes: return f"{humidifier.ATTR_MODE}.{mode}" # Water heater operation mode if self.instance == f"{water_heater.DOMAIN}.{water_heater.ATTR_OPERATION_MODE}": operation_mode = self.entity.attributes.get( - water_heater.ATTR_OPERATION_MODE, None + water_heater.ATTR_OPERATION_MODE ) - if operation_mode in self.entity.attributes.get( - water_heater.ATTR_OPERATION_LIST, [] - ): + operation_modes: list[str] = ( + self.entity.attributes.get(water_heater.ATTR_OPERATION_LIST) or [] + ) + if operation_mode in operation_modes: return f"{water_heater.ATTR_OPERATION_MODE}.{operation_mode}" # Cover Position @@ -1492,7 +1496,7 @@ class AlexaModeController(AlexaCapability): self._resource = AlexaModeResource( [AlexaGlobalCatalog.SETTING_PRESET], False ) - preset_modes = self.entity.attributes.get(fan.ATTR_PRESET_MODES, []) + preset_modes = self.entity.attributes.get(fan.ATTR_PRESET_MODES) or [] for preset_mode in preset_modes: self._resource.add_mode( f"{fan.ATTR_PRESET_MODE}.{preset_mode}", [preset_mode] @@ -1508,7 +1512,7 @@ class AlexaModeController(AlexaCapability): # Humidifier modes if self.instance == f"{humidifier.DOMAIN}.{humidifier.ATTR_MODE}": self._resource = AlexaModeResource([AlexaGlobalCatalog.SETTING_MODE], False) - modes = self.entity.attributes.get(humidifier.ATTR_AVAILABLE_MODES, []) + modes = self.entity.attributes.get(humidifier.ATTR_AVAILABLE_MODES) or [] for mode in modes: self._resource.add_mode(f"{humidifier.ATTR_MODE}.{mode}", [mode]) # Humidifiers or Fans with a single mode completely break Alexa discovery, @@ -1522,8 +1526,8 @@ class AlexaModeController(AlexaCapability): # Water heater operation modes if self.instance == f"{water_heater.DOMAIN}.{water_heater.ATTR_OPERATION_MODE}": self._resource = AlexaModeResource([AlexaGlobalCatalog.SETTING_MODE], False) - operation_modes = self.entity.attributes.get( - water_heater.ATTR_OPERATION_LIST, [] + operation_modes = ( + self.entity.attributes.get(water_heater.ATTR_OPERATION_LIST) or [] ) for operation_mode in operation_modes: self._resource.add_mode( @@ -2368,7 +2372,7 @@ class AlexaEqualizerController(AlexaCapability): """Return the sound modes supported in the configurations object.""" configurations = None supported_sound_modes = self.get_valid_inputs( - self.entity.attributes.get(media_player.ATTR_SOUND_MODE_LIST, []) + self.entity.attributes.get(media_player.ATTR_SOUND_MODE_LIST) or [] ) if supported_sound_modes: configurations = {"modes": {"supported": supported_sound_modes}} diff --git a/homeassistant/components/alexa/entities.py b/homeassistant/components/alexa/entities.py index d0e265b8454..70679f8dafb 100644 --- a/homeassistant/components/alexa/entities.py +++ b/homeassistant/components/alexa/entities.py @@ -478,7 +478,7 @@ class ClimateCapabilities(AlexaEntity): if ( self.entity.domain == climate.DOMAIN and climate.HVACMode.OFF - in self.entity.attributes.get(climate.ATTR_HVAC_MODES, []) + in (self.entity.attributes.get(climate.ATTR_HVAC_MODES) or []) or self.entity.domain == water_heater.DOMAIN and (supported_features & water_heater.WaterHeaterEntityFeature.ON_OFF) ): @@ -742,7 +742,8 @@ class MediaPlayerCapabilities(AlexaEntity): and domain != "denonavr" ): inputs = AlexaEqualizerController.get_valid_inputs( - self.entity.attributes.get(media_player.const.ATTR_SOUND_MODE_LIST, []) + self.entity.attributes.get(media_player.const.ATTR_SOUND_MODE_LIST) + or [] ) if len(inputs) > 0: yield AlexaEqualizerController(self.entity) diff --git a/homeassistant/components/alexa/handlers.py b/homeassistant/components/alexa/handlers.py index 68702bc0533..463693f7da6 100644 --- a/homeassistant/components/alexa/handlers.py +++ b/homeassistant/components/alexa/handlers.py @@ -570,7 +570,7 @@ async def async_api_select_input( # Attempt to map the ALL UPPERCASE payload name to a source. # Strips trailing 1 to match single input devices. - source_list = entity.attributes.get(media_player.const.ATTR_INPUT_SOURCE_LIST, []) + source_list = entity.attributes.get(media_player.const.ATTR_INPUT_SOURCE_LIST) or [] for source in source_list: formatted_source = ( source.lower().replace("-", "").replace("_", "").replace(" ", "") @@ -987,7 +987,7 @@ async def async_api_set_thermostat_mode( ha_preset = next((k for k, v in API_THERMOSTAT_PRESETS.items() if v == mode), None) if ha_preset: - presets = entity.attributes.get(climate.ATTR_PRESET_MODES, []) + presets = entity.attributes.get(climate.ATTR_PRESET_MODES) or [] if ha_preset not in presets: msg = f"The requested thermostat mode {ha_preset} is not supported" @@ -997,7 +997,7 @@ async def async_api_set_thermostat_mode( data[climate.ATTR_PRESET_MODE] = ha_preset elif mode == "CUSTOM": - operation_list = entity.attributes.get(climate.ATTR_HVAC_MODES, []) + operation_list = entity.attributes.get(climate.ATTR_HVAC_MODES) or [] custom_mode = directive.payload["thermostatMode"]["customName"] custom_mode = next( (k for k, v in API_THERMOSTAT_MODES_CUSTOM.items() if v == custom_mode), @@ -1013,7 +1013,7 @@ async def async_api_set_thermostat_mode( data[climate.ATTR_HVAC_MODE] = custom_mode else: - operation_list = entity.attributes.get(climate.ATTR_HVAC_MODES, []) + operation_list = entity.attributes.get(climate.ATTR_HVAC_MODES) or [] ha_modes: dict[str, str] = { k: v for k, v in API_THERMOSTAT_MODES.items() if v == mode }