From b12c5a5ba2cb0a0b47bd00dc504984ca26f398be Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 26 Jun 2023 23:08:30 +0200 Subject: [PATCH] Use entity registry id in humidifier device actions (#95270) --- .../components/humidifier/device_action.py | 13 +- .../humidifier/test_device_action.py | 178 +++++++++++++++--- 2 files changed, 158 insertions(+), 33 deletions(-) diff --git a/homeassistant/components/humidifier/device_action.py b/homeassistant/components/humidifier/device_action.py index f0f2d415a6f..f1f25101e93 100644 --- a/homeassistant/components/humidifier/device_action.py +++ b/homeassistant/components/humidifier/device_action.py @@ -4,6 +4,7 @@ from __future__ import annotations import voluptuous as vol from homeassistant.components.device_automation import ( + async_get_entity_registry_entry_or_raise, async_validate_entity_schema, toggle_entity, ) @@ -29,7 +30,7 @@ from . import DOMAIN, const SET_HUMIDITY_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend( { vol.Required(CONF_TYPE): "set_humidity", - vol.Required(CONF_ENTITY_ID): cv.entity_domain(DOMAIN), + vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid, vol.Required(const.ATTR_HUMIDITY): vol.Coerce(int), } ) @@ -37,7 +38,7 @@ SET_HUMIDITY_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend( SET_MODE_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend( { vol.Required(CONF_TYPE): "set_mode", - vol.Required(CONF_ENTITY_ID): cv.entity_domain(DOMAIN), + vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid, vol.Required(ATTR_MODE): cv.string, } ) @@ -71,7 +72,7 @@ async def async_get_actions( base_action = { CONF_DEVICE_ID: device_id, CONF_DOMAIN: DOMAIN, - CONF_ENTITY_ID: entry.entity_id, + CONF_ENTITY_ID: entry.id, } actions.append({**base_action, CONF_TYPE: "set_humidity"}) @@ -118,9 +119,11 @@ async def async_get_action_capabilities( fields[vol.Required(const.ATTR_HUMIDITY)] = vol.Coerce(int) elif action_type == "set_mode": try: + entry = async_get_entity_registry_entry_or_raise( + hass, config[CONF_ENTITY_ID] + ) available_modes = ( - get_capability(hass, config[ATTR_ENTITY_ID], const.ATTR_AVAILABLE_MODES) - or [] + get_capability(hass, entry.entity_id, const.ATTR_AVAILABLE_MODES) or [] ) except HomeAssistantError: available_modes = [] diff --git a/tests/components/humidifier/test_device_action.py b/tests/components/humidifier/test_device_action.py index 4e20d16ea1d..600be154fc7 100644 --- a/tests/components/humidifier/test_device_action.py +++ b/tests/components/humidifier/test_device_action.py @@ -65,14 +65,13 @@ async def test_get_actions( f"{DOMAIN}.test_5678", "attributes", {"supported_features": features_state} ) expected_actions = [] - basic_action_types = ["set_humidity"] - toggle_action_types = ["turn_on", "turn_off", "toggle"] + basic_action_types = ["set_humidity", "turn_on", "turn_off", "toggle"] expected_actions += [ { "domain": DOMAIN, "type": action, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, } for action in basic_action_types @@ -85,16 +84,6 @@ async def test_get_actions( "entity_id": entity_entry.id, "metadata": {"secondary": False}, } - for action in toggle_action_types - ] - expected_actions += [ - { - "domain": DOMAIN, - "type": action, - "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", - "metadata": {"secondary": False}, - } for action in expected_action_types ] actions = await async_get_device_automations( @@ -135,19 +124,8 @@ async def test_get_actions_hidden_auxiliary( hidden_by=hidden_by, supported_features=0, ) - basic_action_types = ["set_humidity"] - toggle_action_types = ["turn_on", "turn_off", "toggle"] + basic_action_types = ["set_humidity", "turn_on", "turn_off", "toggle"] expected_actions = [] - expected_actions += [ - { - "domain": DOMAIN, - "type": action, - "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", - "metadata": {"secondary": True}, - } - for action in basic_action_types - ] expected_actions += [ { "domain": DOMAIN, @@ -156,7 +134,7 @@ async def test_get_actions_hidden_auxiliary( "entity_id": entity_entry.id, "metadata": {"secondary": True}, } - for action in toggle_action_types + for action in basic_action_types ] actions = await async_get_device_automations( hass, DeviceAutomationType.ACTION, device_entry.id @@ -220,7 +198,7 @@ async def test_action(hass: HomeAssistant, entity_registry: er.EntityRegistry) - "action": { "domain": DOMAIN, "device_id": "abcdefgh", - "entity_id": entry.entity_id, + "entity_id": entry.id, "type": "set_humidity", "humidity": 35, }, @@ -233,7 +211,7 @@ async def test_action(hass: HomeAssistant, entity_registry: er.EntityRegistry) - "action": { "domain": DOMAIN, "device_id": "abcdefgh", - "entity_id": entry.entity_id, + "entity_id": entry.id, "type": "set_mode", "mode": const.MODE_AWAY, }, @@ -480,6 +458,150 @@ async def test_capabilities( capabilities_state, ) + capabilities = await device_action.async_get_action_capabilities( + hass, + { + "domain": DOMAIN, + "device_id": "abcdefgh", + "entity_id": entity_entry.id, + "type": action, + }, + ) + + assert capabilities and "extra_fields" in capabilities + + assert ( + voluptuous_serialize.convert( + capabilities["extra_fields"], custom_serializer=cv.custom_serializer + ) + == expected_capabilities + ) + + +@pytest.mark.parametrize( + ( + "set_state", + "capabilities_reg", + "capabilities_state", + "action", + "expected_capabilities", + ), + [ + ( + False, + {}, + {}, + "set_humidity", + [ + { + "name": "humidity", + "required": True, + "type": "integer", + } + ], + ), + ( + False, + {}, + {}, + "set_mode", + [ + { + "name": "mode", + "options": [], + "required": True, + "type": "select", + } + ], + ), + ( + False, + {const.ATTR_AVAILABLE_MODES: [const.MODE_HOME, const.MODE_AWAY]}, + {}, + "set_mode", + [ + { + "name": "mode", + "options": [("home", "home"), ("away", "away")], + "required": True, + "type": "select", + } + ], + ), + ( + True, + {}, + {}, + "set_humidity", + [ + { + "name": "humidity", + "required": True, + "type": "integer", + } + ], + ), + ( + True, + {}, + {}, + "set_mode", + [ + { + "name": "mode", + "options": [], + "required": True, + "type": "select", + } + ], + ), + ( + True, + {}, + {const.ATTR_AVAILABLE_MODES: [const.MODE_HOME, const.MODE_AWAY]}, + "set_mode", + [ + { + "name": "mode", + "options": [("home", "home"), ("away", "away")], + "required": True, + "type": "select", + } + ], + ), + ], +) +async def test_capabilities_legacy( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + entity_registry: er.EntityRegistry, + set_state, + capabilities_reg, + capabilities_state, + action, + expected_capabilities, +) -> None: + """Test getting capabilities.""" + config_entry = MockConfigEntry(domain="test", data={}) + config_entry.add_to_hass(hass) + device_entry = device_registry.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + ) + entity_entry = entity_registry.async_get_or_create( + DOMAIN, + "test", + "5678", + device_id=device_entry.id, + capabilities=capabilities_reg, + ) + if set_state: + hass.states.async_set( + f"{DOMAIN}.test_5678", + STATE_ON, + capabilities_state, + ) + capabilities = await device_action.async_get_action_capabilities( hass, {