From ed6aef2fd7b613b01351a7f639213ffff6bcf636 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 8 Jan 2020 21:22:56 +0100 Subject: [PATCH] Implement capability attributes (#30545) * Implement capability attributes * Fix HeOS update order * Fix test --- homeassistant/components/fan/__init__.py | 6 ++++- homeassistant/components/heos/media_player.py | 4 ++- .../components/media_player/__init__.py | 20 ++++++++++++-- homeassistant/components/vacuum/__init__.py | 13 ++++++++- .../components/water_heater/__init__.py | 27 +++++++++++++------ tests/components/fan/test_init.py | 2 +- 6 files changed, 58 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/fan/__init__.py b/homeassistant/components/fan/__init__.py index fe6843ed6b9..44b33af0c6e 100644 --- a/homeassistant/components/fan/__init__.py +++ b/homeassistant/components/fan/__init__.py @@ -47,7 +47,6 @@ ATTR_DIRECTION = "direction" PROP_TO_ATTR = { "speed": ATTR_SPEED, - "speed_list": ATTR_SPEED_LIST, "oscillating": ATTR_OSCILLATING, "current_direction": ATTR_DIRECTION, } @@ -178,6 +177,11 @@ class FanEntity(ToggleEntity): """Return the current direction of the fan.""" return None + @property + def capability_attributes(self): + """Return capabilitiy attributes.""" + return {ATTR_SPEED_LIST: self.speed_list} + @property def state_attributes(self) -> dict: """Return optional state attributes.""" diff --git a/homeassistant/components/heos/media_player.py b/homeassistant/components/heos/media_player.py index 10ea28ca16c..9016a8b3cea 100644 --- a/homeassistant/components/heos/media_player.py +++ b/homeassistant/components/heos/media_player.py @@ -115,7 +115,6 @@ class HeosMediaPlayer(MediaPlayerDevice): async def async_added_to_hass(self): """Device added to hass.""" - self._source_manager = self.hass.data[HEOS_DOMAIN][DATA_SOURCE_MANAGER] # Update state when attributes of the player change self._signals.append( self._player.heos.dispatcher.connect( @@ -242,6 +241,9 @@ class HeosMediaPlayer(MediaPlayerDevice): current_support = [CONTROL_TO_SUPPORT[control] for control in controls] self._supported_features = reduce(ior, current_support, BASE_SUPPORTED_FEATURES) + if self._source_manager is None: + self._source_manager = self.hass.data[HEOS_DOMAIN][DATA_SOURCE_MANAGER] + async def async_will_remove_from_hass(self): """Disconnect the device when removed.""" for signal_remove in self._signals: diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index 1375a0ed429..83c117d6c05 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -149,9 +149,7 @@ ATTR_TO_PROPERTY = [ ATTR_APP_ID, ATTR_APP_NAME, ATTR_INPUT_SOURCE, - ATTR_INPUT_SOURCE_LIST, ATTR_SOUND_MODE, - ATTR_SOUND_MODE_LIST, ATTR_MEDIA_SHUFFLE, ] @@ -784,6 +782,24 @@ class MediaPlayerDevice(Entity): return ENTITY_IMAGE_URL.format(self.entity_id, self.access_token, image_hash) + @property + def capability_attributes(self): + """Return capabilitiy attributes.""" + supported_features = self.supported_features + data = {} + + if supported_features & SUPPORT_SELECT_SOURCE: + source_list = self.source_list + if source_list: + data[ATTR_INPUT_SOURCE_LIST] = source_list + + if supported_features & SUPPORT_SELECT_SOUND_MODE: + sound_mode_list = self.sound_mode_list + if sound_mode_list: + data[ATTR_SOUND_MODE_LIST] = sound_mode_list + + return data + @property def state_attributes(self): """Return the state attributes.""" diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index 5dd4682e7cc..225a6ed72bc 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -246,6 +246,12 @@ class VacuumDevice(_BaseVacuum, ToggleEntity): battery_level=self.battery_level, charging=charging ) + @property + def capability_attributes(self): + """Return capabilitiy attributes.""" + if self.fan_speed is not None: + return {ATTR_FAN_SPEED_LIST: self.fan_speed_list} + @property def state_attributes(self): """Return the state attributes of the vacuum cleaner.""" @@ -260,7 +266,6 @@ class VacuumDevice(_BaseVacuum, ToggleEntity): if self.fan_speed is not None: data[ATTR_FAN_SPEED] = self.fan_speed - data[ATTR_FAN_SPEED_LIST] = self.fan_speed_list return data @@ -323,6 +328,12 @@ class StateVacuumDevice(_BaseVacuum): battery_level=self.battery_level, charging=charging ) + @property + def capability_attributes(self): + """Return capabilitiy attributes.""" + if self.fan_speed is not None: + return {ATTR_FAN_SPEED_LIST: self.fan_speed_list} + @property def state_attributes(self): """Return the state attributes of the vacuum cleaner.""" diff --git a/homeassistant/components/water_heater/__init__.py b/homeassistant/components/water_heater/__init__.py index c5ba009717c..8da94ff1098 100644 --- a/homeassistant/components/water_heater/__init__.py +++ b/homeassistant/components/water_heater/__init__.py @@ -143,6 +143,25 @@ class WaterHeaterDevice(Entity): return PRECISION_TENTHS return PRECISION_WHOLE + @property + def capability_attributes(self): + """Return capabilitiy attributes.""" + supported_features = self.supported_features + + data = { + ATTR_MIN_TEMP: show_temp( + self.hass, self.min_temp, self.temperature_unit, self.precision + ), + ATTR_MAX_TEMP: show_temp( + self.hass, self.max_temp, self.temperature_unit, self.precision + ), + } + + if supported_features & SUPPORT_OPERATION_MODE: + data[ATTR_OPERATION_LIST] = self.operation_list + + return data + @property def state_attributes(self): """Return the optional state attributes.""" @@ -153,12 +172,6 @@ class WaterHeaterDevice(Entity): self.temperature_unit, self.precision, ), - ATTR_MIN_TEMP: show_temp( - self.hass, self.min_temp, self.temperature_unit, self.precision - ), - ATTR_MAX_TEMP: show_temp( - self.hass, self.max_temp, self.temperature_unit, self.precision - ), ATTR_TEMPERATURE: show_temp( self.hass, self.target_temperature, @@ -183,8 +196,6 @@ class WaterHeaterDevice(Entity): if supported_features & SUPPORT_OPERATION_MODE: data[ATTR_OPERATION_MODE] = self.current_operation - if self.operation_list: - data[ATTR_OPERATION_LIST] = self.operation_list if supported_features & SUPPORT_AWAY_MODE: is_away = self.is_away_mode_on diff --git a/tests/components/fan/test_init.py b/tests/components/fan/test_init.py index 316504381ec..5d66edea9c7 100644 --- a/tests/components/fan/test_init.py +++ b/tests/components/fan/test_init.py @@ -31,7 +31,7 @@ class TestFanEntity(unittest.TestCase): assert "off" == self.fan.state assert 0 == len(self.fan.speed_list) assert 0 == self.fan.supported_features - assert {"speed_list": []} == self.fan.state_attributes + assert {"speed_list": []} == self.fan.capability_attributes # Test set_speed not required self.fan.oscillate(True) with pytest.raises(NotImplementedError):