Mark device actions from hidden or auxiliary entities as secondary (#70278)

This commit is contained in:
Erik Montnemery 2022-04-20 19:48:46 +02:00 committed by GitHub
parent 2a99084911
commit 64381acbaf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 875 additions and 164 deletions

View file

@ -67,7 +67,7 @@ async def async_get_actions(
supported_features = get_supported_features(hass, entry.entity_id)
base_action = {
base_action: dict = {
CONF_DEVICE_ID: device_id,
CONF_DOMAIN: DOMAIN,
CONF_ENTITY_ID: entry.entity_id,

View file

@ -13,8 +13,13 @@ import voluptuous as vol
import voluptuous_serialize
from homeassistant.components import websocket_api
from homeassistant.const import CONF_DEVICE_ID, CONF_DOMAIN, CONF_PLATFORM
from homeassistant.core import HomeAssistant
from homeassistant.const import (
ATTR_ENTITY_ID,
CONF_DEVICE_ID,
CONF_DOMAIN,
CONF_PLATFORM,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import (
config_validation as cv,
device_registry as dr,
@ -166,6 +171,24 @@ async def async_get_device_automation_platform(
return platform
@callback
def _async_set_entity_device_automation_metadata(
hass: HomeAssistant, automation: dict[str, Any]
) -> None:
"""Set device automation metadata based on entity registry entry data."""
if "metadata" not in automation:
automation["metadata"] = {}
if ATTR_ENTITY_ID not in automation or "secondary" in automation["metadata"]:
return
entity_registry = er.async_get(hass)
# Guard against the entry being removed before this is called
if not (entry := entity_registry.async_get(automation[ATTR_ENTITY_ID])):
return
automation["metadata"]["secondary"] = bool(entry.entity_category or entry.hidden_by)
async def _async_get_device_automations_from_domain(
hass, domain, automation_type, device_ids, return_exceptions
):
@ -242,6 +265,8 @@ async def async_get_device_automations(
)
continue
for automation in device_results:
if automation_type == DeviceAutomationType.ACTION:
_async_set_entity_device_automation_metadata(hass, automation)
combined_results[automation["device_id"]].append(automation)
return combined_results

View file

@ -1465,6 +1465,7 @@ DEVICE_ACTION_BASE_SCHEMA = vol.Schema(
**SCRIPT_ACTION_BASE_SCHEMA,
vol.Required(CONF_DEVICE_ID): string,
vol.Required(CONF_DOMAIN): str,
vol.Remove("metadata"): dict,
}
)

View file

@ -6,6 +6,7 @@ from homeassistant.components.NEW_DOMAIN import DOMAIN
from homeassistant.components.device_automation import DeviceAutomationType
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry, entity_registry
from homeassistant.helpers.entity import EntityCategory
from homeassistant.setup import async_setup_component
from tests.common import (
@ -46,16 +47,58 @@ async def test_get_actions(
expected_actions = [
{
"domain": DOMAIN,
"type": "turn_on",
"type": action,
"device_id": device_entry.id,
"entity_id": "NEW_DOMAIN.test_5678",
},
"entity_id": f"{DOMAIN}.test_5678",
}
for action in ["turn_off", "turn_on"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert_lists_same(actions, expected_actions)
@pytest.mark.parametrize(
"hidden_by,entity_category",
(
(entity_registry.RegistryEntryHider.INTEGRATION, None),
(entity_registry.RegistryEntryHider.USER, None),
(None, EntityCategory.CONFIG),
(None, EntityCategory.DIAGNOSTIC),
),
)
async def test_get_actions_hidden_auxiliary(
hass,
device_reg,
entity_reg,
hidden_by,
entity_category,
):
"""Test we get the expected actions from a hidden or auxiliary entity."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(
DOMAIN,
"test",
"5678",
device_id=device_entry.id,
entity_category=entity_category,
hidden_by=hidden_by,
)
expected_actions = [
{
"domain": DOMAIN,
"type": "turn_off",
"type": action,
"device_id": device_entry.id,
"entity_id": "NEW_DOMAIN.test_5678",
},
"entity_id": f"{DOMAIN}.test_5678",
"metadata": {"secondary": True},
}
for action in ["turn_off", "turn_on", "toggle"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id

View file

@ -2,7 +2,6 @@
from __future__ import annotations
import asyncio
import collections
from collections import OrderedDict
from collections.abc import Awaitable, Collection
from contextlib import contextmanager
@ -1226,72 +1225,17 @@ def async_mock_signal(hass, signal):
return calls
class hashdict(dict):
"""
hashable dict implementation, suitable for use as a key into other dicts.
>>> h1 = hashdict({"apples": 1, "bananas":2})
>>> h2 = hashdict({"bananas": 3, "mangoes": 5})
>>> h1+h2
hashdict(apples=1, bananas=3, mangoes=5)
>>> d1 = {}
>>> d1[h1] = "salad"
>>> d1[h1]
'salad'
>>> d1[h2]
Traceback (most recent call last):
...
KeyError: hashdict(bananas=3, mangoes=5)
based on answers from
http://stackoverflow.com/questions/1151658/python-hashable-dicts
"""
def __key(self):
return tuple(sorted(self.items()))
def __repr__(self): # noqa: D105 no docstring
return ", ".join(f"{i[0]!s}={i[1]!r}" for i in self.__key())
def __hash__(self): # noqa: D105 no docstring
return hash(self.__key())
def __setitem__(self, key, value): # noqa: D105 no docstring
raise TypeError(f"{self.__class__.__name__} does not support item assignment")
def __delitem__(self, key): # noqa: D105 no docstring
raise TypeError(f"{self.__class__.__name__} does not support item assignment")
def clear(self): # noqa: D102 no docstring
raise TypeError(f"{self.__class__.__name__} does not support item assignment")
def pop(self, *args, **kwargs): # noqa: D102 no docstring
raise TypeError(f"{self.__class__.__name__} does not support item assignment")
def popitem(self, *args, **kwargs): # noqa: D102 no docstring
raise TypeError(f"{self.__class__.__name__} does not support item assignment")
def setdefault(self, *args, **kwargs): # noqa: D102 no docstring
raise TypeError(f"{self.__class__.__name__} does not support item assignment")
def update(self, *args, **kwargs): # noqa: D102 no docstring
raise TypeError(f"{self.__class__.__name__} does not support item assignment")
# update is not ok because it mutates the object
# __add__ is ok because it creates a new object
# while the new object is under construction, it's ok to mutate it
def __add__(self, right): # noqa: D105 no docstring
result = hashdict(self)
dict.update(result, right)
return result
def assert_lists_same(a, b):
"""Compare two lists, ignoring order."""
assert collections.Counter([hashdict(i) for i in a]) == collections.Counter(
[hashdict(i) for i in b]
)
"""Compare two lists, ignoring order.
Check both that all items in a are in b and that all items in b are in a,
otherwise assert_lists_same(["1", "1"], ["1", "2"]) could be True.
"""
assert len(a) == len(b)
for i in a:
assert i in b
for i in b:
assert i in a
def raise_contains_mocks(val):

View file

@ -15,6 +15,8 @@ from homeassistant.const import (
STATE_UNKNOWN,
)
from homeassistant.helpers import device_registry
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_registry import RegistryEntryHider
from homeassistant.setup import async_setup_component
from tests.common import (
@ -125,6 +127,7 @@ async def test_get_actions(
"type": action,
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
"metadata": {"secondary": False},
}
for action in expected_action_types
]
@ -134,6 +137,55 @@ async def test_get_actions(
assert_lists_same(actions, expected_actions)
@pytest.mark.parametrize(
"hidden_by,entity_category",
(
(RegistryEntryHider.INTEGRATION, None),
(RegistryEntryHider.USER, None),
(None, EntityCategory.CONFIG),
(None, EntityCategory.DIAGNOSTIC),
),
)
async def test_get_actions_hidden_auxiliary(
hass,
device_reg,
entity_reg,
hidden_by,
entity_category,
):
"""Test we get the expected actions from a hidden or auxiliary entity."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(
DOMAIN,
"test",
"5678",
device_id=device_entry.id,
entity_category=entity_category,
hidden_by=hidden_by,
supported_features=const.AlarmControlPanelEntityFeature.ARM_AWAY,
)
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 ["disarm", "arm_away"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert_lists_same(actions, expected_actions)
async def test_get_actions_arm_night_only(hass, device_reg, entity_reg):
"""Test we get the expected actions from a alarm_control_panel."""
config_entry = MockConfigEntry(domain="test", data={})
@ -152,12 +204,14 @@ async def test_get_actions_arm_night_only(hass, device_reg, entity_reg):
"type": "arm_night",
"device_id": device_entry.id,
"entity_id": "alarm_control_panel.test_5678",
"metadata": {"secondary": False},
},
{
"domain": DOMAIN,
"type": "disarm",
"device_id": device_entry.id,
"entity_id": "alarm_control_panel.test_5678",
"metadata": {"secondary": False},
},
]
actions = await async_get_device_automations(

View file

@ -6,6 +6,7 @@ from homeassistant.components.button import DOMAIN
from homeassistant.components.device_automation import DeviceAutomationType
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry, entity_registry
from homeassistant.helpers.entity import EntityCategory
from homeassistant.setup import async_setup_component
from tests.common import (
@ -49,6 +50,7 @@ async def test_get_actions(
"type": "press",
"device_id": device_entry.id,
"entity_id": "button.test_5678",
"metadata": {"secondary": False},
}
]
actions = await async_get_device_automations(
@ -57,6 +59,54 @@ async def test_get_actions(
assert_lists_same(actions, expected_actions)
@pytest.mark.parametrize(
"hidden_by,entity_category",
(
(entity_registry.RegistryEntryHider.INTEGRATION, None),
(entity_registry.RegistryEntryHider.USER, None),
(None, EntityCategory.CONFIG),
(None, EntityCategory.DIAGNOSTIC),
),
)
async def test_get_actions_hidden_auxiliary(
hass,
device_reg,
entity_reg,
hidden_by,
entity_category,
):
"""Test we get the expected actions from a hidden or auxiliary entity."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(
DOMAIN,
"test",
"5678",
device_id=device_entry.id,
entity_category=entity_category,
hidden_by=hidden_by,
)
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 ["press"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert_lists_same(actions, expected_actions)
async def test_action(hass: HomeAssistant) -> None:
"""Test for press action."""
assert await async_setup_component(

View file

@ -6,6 +6,8 @@ import homeassistant.components.automation as automation
from homeassistant.components.climate import DOMAIN, const, device_action
from homeassistant.components.device_automation import DeviceAutomationType
from homeassistant.helpers import config_validation as cv, device_registry
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_registry import RegistryEntryHider
from homeassistant.setup import async_setup_component
from tests.common import (
@ -86,6 +88,7 @@ async def test_get_actions(
"type": action,
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
"metadata": {"secondary": False},
}
for action in expected_action_types
]
@ -96,6 +99,55 @@ async def test_get_actions(
assert_lists_same(actions, expected_actions)
@pytest.mark.parametrize(
"hidden_by,entity_category",
(
(RegistryEntryHider.INTEGRATION, None),
(RegistryEntryHider.USER, None),
(None, EntityCategory.CONFIG),
(None, EntityCategory.DIAGNOSTIC),
),
)
async def test_get_actions_hidden_auxiliary(
hass,
device_reg,
entity_reg,
hidden_by,
entity_category,
):
"""Test we get the expected actions from a hidden or auxiliary entity."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(
DOMAIN,
"test",
"5678",
device_id=device_entry.id,
entity_category=entity_category,
hidden_by=hidden_by,
supported_features=0,
)
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 ["set_hvac_mode"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert_lists_same(actions, expected_actions)
async def test_action(hass):
"""Test for actions."""
hass.states.async_set(

View file

@ -16,6 +16,8 @@ from homeassistant.components.cover import (
from homeassistant.components.device_automation import DeviceAutomationType
from homeassistant.const import CONF_PLATFORM
from homeassistant.helpers import device_registry
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_registry import RegistryEntryHider
from homeassistant.setup import async_setup_component
from tests.common import (
@ -99,6 +101,7 @@ async def test_get_actions(
"type": action,
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
"metadata": {"secondary": False},
}
for action in expected_action_types
]
@ -108,6 +111,55 @@ async def test_get_actions(
assert_lists_same(actions, expected_actions)
@pytest.mark.parametrize(
"hidden_by,entity_category",
(
(RegistryEntryHider.INTEGRATION, None),
(RegistryEntryHider.USER, None),
(None, EntityCategory.CONFIG),
(None, EntityCategory.DIAGNOSTIC),
),
)
async def test_get_actions_hidden_auxiliary(
hass,
device_reg,
entity_reg,
hidden_by,
entity_category,
):
"""Test we get the expected actions from a hidden or auxiliary entity."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(
DOMAIN,
"test",
"5678",
device_id=device_entry.id,
entity_category=entity_category,
hidden_by=hidden_by,
supported_features=SUPPORT_CLOSE,
)
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 ["close"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert_lists_same(actions, expected_actions)
async def test_get_action_capabilities(
hass, device_reg, entity_reg, enable_custom_integrations
):

View file

@ -57,18 +57,21 @@ async def test_websocket_get_actions(hass, hass_ws_client, device_reg, entity_re
"type": "turn_off",
"device_id": device_entry.id,
"entity_id": "light.test_5678",
"metadata": {"secondary": False},
},
{
"domain": "light",
"type": "turn_on",
"device_id": device_entry.id,
"entity_id": "light.test_5678",
"metadata": {"secondary": False},
},
{
"domain": "light",
"type": "toggle",
"device_id": device_entry.id,
"entity_id": "light.test_5678",
"metadata": {"secondary": False},
},
]

View file

@ -5,6 +5,8 @@ import homeassistant.components.automation as automation
from homeassistant.components.device_automation import DeviceAutomationType
from homeassistant.components.fan import DOMAIN
from homeassistant.helpers import device_registry
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_registry import RegistryEntryHider
from homeassistant.setup import async_setup_component
from tests.common import (
@ -39,19 +41,64 @@ async def test_get_actions(hass, device_reg, entity_reg):
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id)
expected_actions = [
expected_actions = []
expected_actions += [
{
"domain": DOMAIN,
"type": "turn_on",
"type": action,
"device_id": device_entry.id,
"entity_id": "fan.test_5678",
},
"entity_id": f"{DOMAIN}.test_5678",
"metadata": {"secondary": False},
}
for action in ["turn_on", "turn_off"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert_lists_same(actions, expected_actions)
@pytest.mark.parametrize(
"hidden_by,entity_category",
(
(RegistryEntryHider.INTEGRATION, None),
(RegistryEntryHider.USER, None),
(None, EntityCategory.CONFIG),
(None, EntityCategory.DIAGNOSTIC),
),
)
async def test_get_actions_hidden_auxiliary(
hass,
device_reg,
entity_reg,
hidden_by,
entity_category,
):
"""Test we get the expected actions from a hidden or auxiliary entity."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(
DOMAIN,
"test",
"5678",
device_id=device_entry.id,
entity_category=entity_category,
hidden_by=hidden_by,
)
expected_actions = []
expected_actions += [
{
"domain": DOMAIN,
"type": "turn_off",
"type": action,
"device_id": device_entry.id,
"entity_id": "fan.test_5678",
},
"entity_id": f"{DOMAIN}.test_5678",
"metadata": {"secondary": True},
}
for action in ["turn_on", "turn_off"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id

View file

@ -7,6 +7,8 @@ from homeassistant.components.device_automation import DeviceAutomationType
from homeassistant.components.humidifier import DOMAIN, const, device_action
from homeassistant.const import STATE_ON
from homeassistant.helpers import config_validation as cv, device_registry
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_registry import RegistryEntryHider
from homeassistant.setup import async_setup_component
from tests.common import (
@ -76,6 +78,7 @@ async def test_get_actions(
"type": action,
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
"metadata": {"secondary": False},
}
for action in basic_action_types
]
@ -85,6 +88,7 @@ async def test_get_actions(
"type": action,
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
"metadata": {"secondary": False},
}
for action in expected_action_types
]
@ -94,6 +98,55 @@ async def test_get_actions(
assert_lists_same(actions, expected_actions)
@pytest.mark.parametrize(
"hidden_by,entity_category",
(
(RegistryEntryHider.INTEGRATION, None),
(RegistryEntryHider.USER, None),
(None, EntityCategory.CONFIG),
(None, EntityCategory.DIAGNOSTIC),
),
)
async def test_get_actions_hidden_auxiliary(
hass,
device_reg,
entity_reg,
hidden_by,
entity_category,
):
"""Test we get the expected actions from a hidden or auxiliary entity."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(
DOMAIN,
"test",
"5678",
device_id=device_entry.id,
entity_category=entity_category,
hidden_by=hidden_by,
supported_features=0,
)
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 ["turn_on", "turn_off", "toggle", "set_humidity"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert_lists_same(actions, expected_actions)
async def test_action(hass):
"""Test for actions."""
hass.states.async_set(

View file

@ -13,10 +13,13 @@ from homeassistant.components.light import (
)
from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON
from homeassistant.helpers import device_registry
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_registry import RegistryEntryHider
from homeassistant.setup import async_setup_component
from tests.common import (
MockConfigEntry,
assert_lists_same,
async_get_device_automation_capabilities,
async_get_device_automations,
async_mock_service,
@ -60,48 +63,78 @@ async def test_get_actions(hass, device_reg, entity_reg):
supported_features=LightEntityFeature.FLASH,
capabilities={"supported_color_modes": ["brightness"]},
)
expected_actions = [
expected_actions = []
expected_actions += [
{
"domain": DOMAIN,
"type": "turn_off",
"type": action,
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
},
{
"domain": DOMAIN,
"type": "turn_on",
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
},
{
"domain": DOMAIN,
"type": "toggle",
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
},
{
"domain": DOMAIN,
"type": "brightness_increase",
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
},
{
"domain": DOMAIN,
"type": "brightness_decrease",
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
},
{
"domain": DOMAIN,
"type": "flash",
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
},
"metadata": {"secondary": False},
}
for action in [
"turn_off",
"turn_on",
"toggle",
"brightness_decrease",
"brightness_increase",
"flash",
]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert actions == expected_actions
assert_lists_same(actions, expected_actions)
@pytest.mark.parametrize(
"hidden_by,entity_category",
(
(RegistryEntryHider.INTEGRATION, None),
(RegistryEntryHider.USER, None),
(None, EntityCategory.CONFIG),
(None, EntityCategory.DIAGNOSTIC),
),
)
async def test_get_actions_hidden_auxiliary(
hass,
device_reg,
entity_reg,
hidden_by,
entity_category,
):
"""Test we get the expected actions from a hidden or auxiliary entity."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(
DOMAIN,
"test",
"5678",
device_id=device_entry.id,
entity_category=entity_category,
hidden_by=hidden_by,
supported_features=0,
capabilities={"supported_color_modes": ["onoff"]},
)
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 ["turn_on", "turn_off", "toggle"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert_lists_same(actions, expected_actions)
async def test_get_action_capabilities(hass, device_reg, entity_reg):

View file

@ -5,6 +5,8 @@ import homeassistant.components.automation as automation
from homeassistant.components.device_automation import DeviceAutomationType
from homeassistant.components.lock import DOMAIN, LockEntityFeature
from homeassistant.helpers import device_registry
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_registry import RegistryEntryHider
from homeassistant.setup import async_setup_component
from tests.common import (
@ -74,6 +76,7 @@ async def test_get_actions(
"type": action,
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
"metadata": {"secondary": False},
}
for action in basic_action_types
]
@ -83,6 +86,7 @@ async def test_get_actions(
"type": action,
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
"metadata": {"secondary": False},
}
for action in expected_action_types
]
@ -92,6 +96,55 @@ async def test_get_actions(
assert_lists_same(actions, expected_actions)
@pytest.mark.parametrize(
"hidden_by,entity_category",
(
(RegistryEntryHider.INTEGRATION, None),
(RegistryEntryHider.USER, None),
(None, EntityCategory.CONFIG),
(None, EntityCategory.DIAGNOSTIC),
),
)
async def test_get_actions_hidden_auxiliary(
hass,
device_reg,
entity_reg,
hidden_by,
entity_category,
):
"""Test we get the expected actions from a hidden or auxiliary entity."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(
DOMAIN,
"test",
"5678",
device_id=device_entry.id,
entity_category=entity_category,
hidden_by=hidden_by,
supported_features=0,
)
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 ["lock", "unlock"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert_lists_same(actions, expected_actions)
async def test_action(hass):
"""Test for lock actions."""
assert await async_setup_component(

View file

@ -13,7 +13,7 @@ async def test_get_actions(hass, push_registration):
assert await async_get_device_automations(
hass, device_automation.DeviceAutomationType.ACTION, device_id
) == [{"domain": DOMAIN, "device_id": device_id, "type": "notify"}]
) == [{"domain": DOMAIN, "device_id": device_id, "metadata": {}, "type": "notify"}]
capabilitites = await device_automation._async_get_device_automation_capabilities(
hass,

View file

@ -6,6 +6,8 @@ import homeassistant.components.automation as automation
from homeassistant.components.device_automation import DeviceAutomationType
from homeassistant.components.number import DOMAIN, device_action
from homeassistant.helpers import config_validation as cv, device_registry
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_registry import RegistryEntryHider
from homeassistant.setup import async_setup_component
from tests.common import (
@ -47,6 +49,7 @@ async def test_get_actions(hass, device_reg, entity_reg):
"type": "set_value",
"device_id": device_entry.id,
"entity_id": "number.test_5678",
"metadata": {"secondary": False},
},
]
actions = await async_get_device_automations(
@ -55,6 +58,54 @@ async def test_get_actions(hass, device_reg, entity_reg):
assert_lists_same(actions, expected_actions)
@pytest.mark.parametrize(
"hidden_by,entity_category",
(
(RegistryEntryHider.INTEGRATION, None),
(RegistryEntryHider.USER, None),
(None, EntityCategory.CONFIG),
(None, EntityCategory.DIAGNOSTIC),
),
)
async def test_get_actions_hidden_auxiliary(
hass,
device_reg,
entity_reg,
hidden_by,
entity_category,
):
"""Test we get the expected actions from a hidden or auxiliary entity."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(
DOMAIN,
"test",
"5678",
device_id=device_entry.id,
entity_category=entity_category,
hidden_by=hidden_by,
)
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 ["set_value"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert_lists_same(actions, expected_actions)
async def test_get_action_no_state(hass, device_reg, entity_reg):
"""Test we get the expected actions for an entity."""
config_entry = MockConfigEntry(domain="test", data={})
@ -70,6 +121,7 @@ async def test_get_action_no_state(hass, device_reg, entity_reg):
"type": "set_value",
"device_id": device_entry.id,
"entity_id": "number.test_5678",
"metadata": {"secondary": False},
},
]
actions = await async_get_device_automations(

View file

@ -6,10 +6,13 @@ from homeassistant.components.device_automation import DeviceAutomationType
from homeassistant.components.remote import DOMAIN
from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON
from homeassistant.helpers import device_registry
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_registry import RegistryEntryHider
from homeassistant.setup import async_setup_component
from tests.common import (
MockConfigEntry,
assert_lists_same,
async_get_device_automations,
async_mock_service,
mock_device_registry,
@ -48,27 +51,65 @@ async def test_get_actions(hass, device_reg, entity_reg):
expected_actions = [
{
"domain": DOMAIN,
"type": "turn_off",
"type": action,
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
},
{
"domain": DOMAIN,
"type": "turn_on",
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
},
{
"domain": DOMAIN,
"type": "toggle",
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
},
"metadata": {"secondary": False},
}
for action in ["turn_off", "turn_on", "toggle"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert actions == expected_actions
assert_lists_same(actions, expected_actions)
@pytest.mark.parametrize(
"hidden_by,entity_category",
(
(RegistryEntryHider.INTEGRATION, None),
(RegistryEntryHider.USER, None),
(None, EntityCategory.CONFIG),
(None, EntityCategory.DIAGNOSTIC),
),
)
async def test_get_actions_hidden_auxiliary(
hass,
device_reg,
entity_reg,
hidden_by,
entity_category,
):
"""Test we get the expected actions from a hidden or auxiliary entity."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(
DOMAIN,
"test",
"5678",
device_id=device_entry.id,
entity_category=entity_category,
hidden_by=hidden_by,
)
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 ["turn_off", "turn_on", "toggle"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert_lists_same(actions, expected_actions)
async def test_action(hass, calls, enable_custom_integrations):

View file

@ -105,7 +105,7 @@ async def test_get_actions(hass, device_reg: DeviceRegistry, device, expected):
actions = [action for action in actions if action["domain"] == DOMAIN]
expected_actions = [
{"domain": DOMAIN, "device_id": device_entry.id, **action_type}
{"domain": DOMAIN, "device_id": device_entry.id, "metadata": {}, **action_type}
for action_type in expected
]

View file

@ -12,6 +12,7 @@ from homeassistant.helpers import (
device_registry,
entity_registry,
)
from homeassistant.helpers.entity import EntityCategory
from homeassistant.setup import async_setup_component
from tests.common import (
@ -55,6 +56,7 @@ async def test_get_actions(
"type": "select_option",
"device_id": device_entry.id,
"entity_id": "select.test_5678",
"metadata": {"secondary": False},
}
]
actions = await async_get_device_automations(
@ -63,6 +65,54 @@ async def test_get_actions(
assert_lists_same(actions, expected_actions)
@pytest.mark.parametrize(
"hidden_by,entity_category",
(
(entity_registry.RegistryEntryHider.INTEGRATION, None),
(entity_registry.RegistryEntryHider.USER, None),
(None, EntityCategory.CONFIG),
(None, EntityCategory.DIAGNOSTIC),
),
)
async def test_get_actions_hidden_auxiliary(
hass,
device_reg,
entity_reg,
hidden_by,
entity_category,
):
"""Test we get the expected actions from a hidden or auxiliary entity."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(
DOMAIN,
"test",
"5678",
device_id=device_entry.id,
entity_category=entity_category,
hidden_by=hidden_by,
)
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 ["select_option"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert_lists_same(actions, expected_actions)
async def test_action(hass: HomeAssistant) -> None:
"""Test for select_option action."""
assert await async_setup_component(

View file

@ -6,10 +6,13 @@ from homeassistant.components.device_automation import DeviceAutomationType
from homeassistant.components.switch import DOMAIN
from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON
from homeassistant.helpers import device_registry
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_registry import RegistryEntryHider
from homeassistant.setup import async_setup_component
from tests.common import (
MockConfigEntry,
assert_lists_same,
async_get_device_automations,
async_mock_service,
mock_device_registry,
@ -45,30 +48,69 @@ async def test_get_actions(hass, device_reg, entity_reg):
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id)
expected_actions = [
expected_actions = []
expected_actions += [
{
"domain": DOMAIN,
"type": "turn_off",
"type": action,
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
},
{
"domain": DOMAIN,
"type": "turn_on",
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
},
{
"domain": DOMAIN,
"type": "toggle",
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
},
"metadata": {"secondary": False},
}
for action in ["turn_off", "turn_on", "toggle"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert actions == expected_actions
assert_lists_same(actions, expected_actions)
@pytest.mark.parametrize(
"hidden_by,entity_category",
(
(RegistryEntryHider.INTEGRATION, None),
(RegistryEntryHider.USER, None),
(None, EntityCategory.CONFIG),
(None, EntityCategory.DIAGNOSTIC),
),
)
async def test_get_actions_hidden_auxiliary(
hass,
device_reg,
entity_reg,
hidden_by,
entity_category,
):
"""Test we get the expected actions from a hidden or auxiliary entity."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(
DOMAIN,
"test",
"5678",
device_id=device_entry.id,
entity_category=entity_category,
hidden_by=hidden_by,
)
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 ["turn_off", "turn_on", "toggle"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert_lists_same(actions, expected_actions)
async def test_action(hass, calls, enable_custom_integrations):

View file

@ -5,6 +5,8 @@ import homeassistant.components.automation as automation
from homeassistant.components.device_automation import DeviceAutomationType
from homeassistant.components.vacuum import DOMAIN
from homeassistant.helpers import device_registry
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_registry import RegistryEntryHider
from homeassistant.setup import async_setup_component
from tests.common import (
@ -39,19 +41,64 @@ async def test_get_actions(hass, device_reg, entity_reg):
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id)
expected_actions = [
expected_actions = []
expected_actions += [
{
"domain": DOMAIN,
"type": "clean",
"type": action,
"device_id": device_entry.id,
"entity_id": "vacuum.test_5678",
},
"metadata": {"secondary": False},
}
for action in ["clean", "dock"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert_lists_same(actions, expected_actions)
@pytest.mark.parametrize(
"hidden_by,entity_category",
(
(RegistryEntryHider.INTEGRATION, None),
(RegistryEntryHider.USER, None),
(None, EntityCategory.CONFIG),
(None, EntityCategory.DIAGNOSTIC),
),
)
async def test_get_actions_hidden_auxiliary(
hass,
device_reg,
entity_reg,
hidden_by,
entity_category,
):
"""Test we get the expected actions from a hidden or auxiliary entity."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(
DOMAIN,
"test",
"5678",
device_id=device_entry.id,
entity_category=entity_category,
hidden_by=hidden_by,
)
expected_actions = []
expected_actions += [
{
"domain": DOMAIN,
"type": "dock",
"type": action,
"device_id": device_entry.id,
"entity_id": "vacuum.test_5678",
},
"entity_id": f"{DOMAIN}.test_5678",
"metadata": {"secondary": True},
}
for action in ["clean", "dock"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id

View file

@ -5,6 +5,8 @@ import homeassistant.components.automation as automation
from homeassistant.components.device_automation import DeviceAutomationType
from homeassistant.components.water_heater import DOMAIN
from homeassistant.helpers import device_registry
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_registry import RegistryEntryHider
from homeassistant.setup import async_setup_component
from tests.common import (
@ -39,19 +41,64 @@ async def test_get_actions(hass, device_reg, entity_reg):
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id)
expected_actions = [
expected_actions = []
expected_actions += [
{
"domain": DOMAIN,
"type": "turn_on",
"type": action,
"device_id": device_entry.id,
"entity_id": "water_heater.test_5678",
},
"entity_id": f"{DOMAIN}.test_5678",
"metadata": {"secondary": False},
}
for action in ["turn_on", "turn_off"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id
)
assert_lists_same(actions, expected_actions)
@pytest.mark.parametrize(
"hidden_by,entity_category",
(
(RegistryEntryHider.INTEGRATION, None),
(RegistryEntryHider.USER, None),
(None, EntityCategory.CONFIG),
(None, EntityCategory.DIAGNOSTIC),
),
)
async def test_get_actions_hidden_auxiliary(
hass,
device_reg,
entity_reg,
hidden_by,
entity_category,
):
"""Test we get the expected actions from a hidden or auxiliary entity."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
entity_reg.async_get_or_create(
DOMAIN,
"test",
"5678",
device_id=device_entry.id,
entity_category=entity_category,
hidden_by=hidden_by,
)
expected_actions = []
expected_actions += [
{
"domain": DOMAIN,
"type": "turn_off",
"type": action,
"device_id": device_entry.id,
"entity_id": "water_heater.test_5678",
},
"entity_id": f"{DOMAIN}.test_5678",
"metadata": {"secondary": True},
}
for action in ["turn_on", "turn_off"]
]
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device_entry.id

View file

@ -58,31 +58,40 @@ async def test_get_actions(hass, device_ias):
)
expected_actions = [
{"domain": DOMAIN, "type": "squawk", "device_id": reg_device.id},
{"domain": DOMAIN, "type": "warn", "device_id": reg_device.id},
{
"domain": DOMAIN,
"type": "squawk",
"device_id": reg_device.id,
"metadata": {},
},
{"domain": DOMAIN, "type": "warn", "device_id": reg_device.id, "metadata": {}},
{
"domain": Platform.SELECT,
"type": "select_option",
"device_id": reg_device.id,
"entity_id": "select.fakemanufacturer_fakemodel_e769900a_ias_wd_warningmode",
"metadata": {"secondary": True},
},
{
"domain": Platform.SELECT,
"type": "select_option",
"device_id": reg_device.id,
"entity_id": "select.fakemanufacturer_fakemodel_e769900a_ias_wd_sirenlevel",
"metadata": {"secondary": True},
},
{
"domain": Platform.SELECT,
"type": "select_option",
"device_id": reg_device.id,
"entity_id": "select.fakemanufacturer_fakemodel_e769900a_ias_wd_strobelevel",
"metadata": {"secondary": True},
},
{
"domain": Platform.SELECT,
"type": "select_option",
"device_id": reg_device.id,
"entity_id": "select.fakemanufacturer_fakemodel_e769900a_ias_wd_strobe",
"metadata": {"secondary": True},
},
]

View file

@ -38,28 +38,40 @@ async def test_get_actions(
"type": "clear_lock_usercode",
"device_id": device.id,
"entity_id": "lock.touchscreen_deadbolt",
"metadata": {"secondary": False},
},
{
"domain": DOMAIN,
"type": "set_lock_usercode",
"device_id": device.id,
"entity_id": "lock.touchscreen_deadbolt",
"metadata": {"secondary": False},
},
{
"domain": DOMAIN,
"type": "refresh_value",
"device_id": device.id,
"entity_id": "binary_sensor.touchscreen_deadbolt_low_battery_level",
"metadata": {"secondary": True},
},
{
"domain": DOMAIN,
"type": "refresh_value",
"device_id": device.id,
"entity_id": "lock.touchscreen_deadbolt",
"metadata": {"secondary": False},
},
{
"domain": DOMAIN,
"type": "set_value",
"device_id": device.id,
"metadata": {},
},
{
"domain": DOMAIN,
"type": "ping",
"device_id": device.id,
"metadata": {},
},
{
"domain": DOMAIN,
@ -68,6 +80,7 @@ async def test_get_actions(
"parameter": 3,
"bitmask": None,
"subtype": "3 (Beeper)",
"metadata": {},
},
]
actions = await async_get_device_automations(