mirror of
https://github.com/home-assistant/core.git
synced 2025-07-28 15:47:12 +00:00
Fix - only enable AlexaModeController if at least one mode is offered (#148614)
This commit is contained in:
parent
334d5f09fb
commit
ad4e5459b1
@ -505,8 +505,13 @@ class ClimateCapabilities(AlexaEntity):
|
|||||||
):
|
):
|
||||||
yield AlexaThermostatController(self.hass, self.entity)
|
yield AlexaThermostatController(self.hass, self.entity)
|
||||||
yield AlexaTemperatureSensor(self.hass, self.entity)
|
yield AlexaTemperatureSensor(self.hass, self.entity)
|
||||||
if self.entity.domain == water_heater.DOMAIN and (
|
if (
|
||||||
supported_features & water_heater.WaterHeaterEntityFeature.OPERATION_MODE
|
self.entity.domain == water_heater.DOMAIN
|
||||||
|
and (
|
||||||
|
supported_features
|
||||||
|
& water_heater.WaterHeaterEntityFeature.OPERATION_MODE
|
||||||
|
)
|
||||||
|
and self.entity.attributes.get(water_heater.ATTR_OPERATION_LIST)
|
||||||
):
|
):
|
||||||
yield AlexaModeController(
|
yield AlexaModeController(
|
||||||
self.entity,
|
self.entity,
|
||||||
@ -634,7 +639,9 @@ class FanCapabilities(AlexaEntity):
|
|||||||
self.entity, instance=f"{fan.DOMAIN}.{fan.ATTR_OSCILLATING}"
|
self.entity, instance=f"{fan.DOMAIN}.{fan.ATTR_OSCILLATING}"
|
||||||
)
|
)
|
||||||
force_range_controller = False
|
force_range_controller = False
|
||||||
if supported & fan.FanEntityFeature.PRESET_MODE:
|
if supported & fan.FanEntityFeature.PRESET_MODE and self.entity.attributes.get(
|
||||||
|
fan.ATTR_PRESET_MODES
|
||||||
|
):
|
||||||
yield AlexaModeController(
|
yield AlexaModeController(
|
||||||
self.entity, instance=f"{fan.DOMAIN}.{fan.ATTR_PRESET_MODE}"
|
self.entity, instance=f"{fan.DOMAIN}.{fan.ATTR_PRESET_MODE}"
|
||||||
)
|
)
|
||||||
@ -672,7 +679,11 @@ class RemoteCapabilities(AlexaEntity):
|
|||||||
yield AlexaPowerController(self.entity)
|
yield AlexaPowerController(self.entity)
|
||||||
supported = self.entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
supported = self.entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
||||||
activities = self.entity.attributes.get(remote.ATTR_ACTIVITY_LIST) or []
|
activities = self.entity.attributes.get(remote.ATTR_ACTIVITY_LIST) or []
|
||||||
if activities and supported & remote.RemoteEntityFeature.ACTIVITY:
|
if (
|
||||||
|
activities
|
||||||
|
and (supported & remote.RemoteEntityFeature.ACTIVITY)
|
||||||
|
and self.entity.attributes.get(remote.ATTR_ACTIVITY_LIST)
|
||||||
|
):
|
||||||
yield AlexaModeController(
|
yield AlexaModeController(
|
||||||
self.entity, instance=f"{remote.DOMAIN}.{remote.ATTR_ACTIVITY}"
|
self.entity, instance=f"{remote.DOMAIN}.{remote.ATTR_ACTIVITY}"
|
||||||
)
|
)
|
||||||
@ -692,7 +703,9 @@ class HumidifierCapabilities(AlexaEntity):
|
|||||||
"""Yield the supported interfaces."""
|
"""Yield the supported interfaces."""
|
||||||
yield AlexaPowerController(self.entity)
|
yield AlexaPowerController(self.entity)
|
||||||
supported = self.entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
supported = self.entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
||||||
if supported & humidifier.HumidifierEntityFeature.MODES:
|
if (
|
||||||
|
supported & humidifier.HumidifierEntityFeature.MODES
|
||||||
|
) and self.entity.attributes.get(humidifier.ATTR_AVAILABLE_MODES):
|
||||||
yield AlexaModeController(
|
yield AlexaModeController(
|
||||||
self.entity, instance=f"{humidifier.DOMAIN}.{humidifier.ATTR_MODE}"
|
self.entity, instance=f"{humidifier.DOMAIN}.{humidifier.ATTR_MODE}"
|
||||||
)
|
)
|
||||||
|
@ -5,6 +5,7 @@ from unittest.mock import patch
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components import fan, humidifier, remote, water_heater
|
||||||
from homeassistant.components.alexa import smart_home
|
from homeassistant.components.alexa import smart_home
|
||||||
from homeassistant.const import EntityCategory, UnitOfTemperature, __version__
|
from homeassistant.const import EntityCategory, UnitOfTemperature, __version__
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
@ -200,3 +201,167 @@ async def test_serialize_discovery_recovers(
|
|||||||
"Error serializing Alexa.PowerController discovery"
|
"Error serializing Alexa.PowerController discovery"
|
||||||
f" for {hass.states.get('switch.bla')}"
|
f" for {hass.states.get('switch.bla')}"
|
||||||
) in caplog.text
|
) in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("domain", "state", "state_attributes", "mode_controller_exists"),
|
||||||
|
[
|
||||||
|
("switch", "on", {}, False),
|
||||||
|
(
|
||||||
|
"fan",
|
||||||
|
"on",
|
||||||
|
{
|
||||||
|
"preset_modes": ["eco", "auto"],
|
||||||
|
"preset_mode": "eco",
|
||||||
|
"supported_features": fan.FanEntityFeature.PRESET_MODE.value,
|
||||||
|
},
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"fan",
|
||||||
|
"on",
|
||||||
|
{
|
||||||
|
"preset_modes": ["eco", "auto"],
|
||||||
|
"preset_mode": None,
|
||||||
|
"supported_features": fan.FanEntityFeature.PRESET_MODE.value,
|
||||||
|
},
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"fan",
|
||||||
|
"on",
|
||||||
|
{
|
||||||
|
"preset_modes": ["eco"],
|
||||||
|
"preset_mode": None,
|
||||||
|
"supported_features": fan.FanEntityFeature.PRESET_MODE.value,
|
||||||
|
},
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"fan",
|
||||||
|
"on",
|
||||||
|
{
|
||||||
|
"preset_modes": [],
|
||||||
|
"preset_mode": None,
|
||||||
|
"supported_features": fan.FanEntityFeature.PRESET_MODE.value,
|
||||||
|
},
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"humidifier",
|
||||||
|
"on",
|
||||||
|
{
|
||||||
|
"available_modes": ["auto", "manual"],
|
||||||
|
"mode": "auto",
|
||||||
|
"supported_features": humidifier.HumidifierEntityFeature.MODES.value,
|
||||||
|
},
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"humidifier",
|
||||||
|
"on",
|
||||||
|
{
|
||||||
|
"available_modes": ["auto"],
|
||||||
|
"mode": None,
|
||||||
|
"supported_features": humidifier.HumidifierEntityFeature.MODES.value,
|
||||||
|
},
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"humidifier",
|
||||||
|
"on",
|
||||||
|
{
|
||||||
|
"available_modes": [],
|
||||||
|
"mode": None,
|
||||||
|
"supported_features": humidifier.HumidifierEntityFeature.MODES.value,
|
||||||
|
},
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"remote",
|
||||||
|
"on",
|
||||||
|
{
|
||||||
|
"activity_list": ["tv", "dvd"],
|
||||||
|
"current_activity": "tv",
|
||||||
|
"supported_features": remote.RemoteEntityFeature.ACTIVITY.value,
|
||||||
|
},
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"remote",
|
||||||
|
"on",
|
||||||
|
{
|
||||||
|
"activity_list": ["tv"],
|
||||||
|
"current_activity": None,
|
||||||
|
"supported_features": remote.RemoteEntityFeature.ACTIVITY.value,
|
||||||
|
},
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"remote",
|
||||||
|
"on",
|
||||||
|
{
|
||||||
|
"activity_list": [],
|
||||||
|
"current_activity": None,
|
||||||
|
"supported_features": remote.RemoteEntityFeature.ACTIVITY.value,
|
||||||
|
},
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"water_heater",
|
||||||
|
"on",
|
||||||
|
{
|
||||||
|
"operation_list": ["on", "auto"],
|
||||||
|
"operation_mode": "auto",
|
||||||
|
"supported_features": water_heater.WaterHeaterEntityFeature.OPERATION_MODE.value,
|
||||||
|
},
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"water_heater",
|
||||||
|
"on",
|
||||||
|
{
|
||||||
|
"operation_list": ["on"],
|
||||||
|
"operation_mode": None,
|
||||||
|
"supported_features": water_heater.WaterHeaterEntityFeature.OPERATION_MODE.value,
|
||||||
|
},
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"water_heater",
|
||||||
|
"on",
|
||||||
|
{
|
||||||
|
"operation_list": [],
|
||||||
|
"operation_mode": None,
|
||||||
|
"supported_features": water_heater.WaterHeaterEntityFeature.OPERATION_MODE.value,
|
||||||
|
},
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_mode_controller_is_omitted_if_no_modes_are_set(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
domain: str,
|
||||||
|
state: str,
|
||||||
|
state_attributes: dict[str, Any],
|
||||||
|
mode_controller_exists: bool,
|
||||||
|
) -> None:
|
||||||
|
"""Test we do not generate an invalid discovery with AlexaModeController during serialize discovery.
|
||||||
|
|
||||||
|
AlexModeControllers need at least 2 modes. If one mode is set, an extra mode will be added for compatibility.
|
||||||
|
If no modes are offered, the mode controller should be omitted to prevent schema validations.
|
||||||
|
"""
|
||||||
|
request = get_new_request("Alexa.Discovery", "Discover")
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
f"{domain}.bla", state, {"friendly_name": "Boop Woz"} | state_attributes
|
||||||
|
)
|
||||||
|
|
||||||
|
msg = await smart_home.async_handle_message(hass, get_default_config(hass), request)
|
||||||
|
msg = msg["event"]
|
||||||
|
|
||||||
|
interfaces = {
|
||||||
|
ifc["interface"] for ifc in msg["payload"]["endpoints"][0]["capabilities"]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert ("Alexa.ModeController" in interfaces) is mode_controller_exists
|
||||||
|
Loading…
x
Reference in New Issue
Block a user