mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 05:37:44 +00:00
Add flash light device actions (#33689)
* Add flash light device actions * Single action with extra fields * Change extra_fields to dictionary
This commit is contained in:
parent
2239f2f732
commit
7bd6f5413d
@ -87,6 +87,7 @@ VALID_BRIGHTNESS = vol.All(vol.Coerce(int), vol.Clamp(min=0, max=255))
|
||||
VALID_BRIGHTNESS_PCT = vol.All(vol.Coerce(float), vol.Range(min=0, max=100))
|
||||
VALID_BRIGHTNESS_STEP = vol.All(vol.Coerce(int), vol.Clamp(min=-255, max=255))
|
||||
VALID_BRIGHTNESS_STEP_PCT = vol.All(vol.Coerce(float), vol.Clamp(min=-100, max=100))
|
||||
VALID_FLASH = vol.In([FLASH_SHORT, FLASH_LONG])
|
||||
|
||||
LIGHT_TURN_ON_SCHEMA = {
|
||||
vol.Exclusive(ATTR_PROFILE, COLOR_GROUP): cv.string,
|
||||
@ -116,7 +117,7 @@ LIGHT_TURN_ON_SCHEMA = {
|
||||
),
|
||||
vol.Exclusive(ATTR_KELVIN, COLOR_GROUP): vol.All(vol.Coerce(int), vol.Range(min=0)),
|
||||
ATTR_WHITE_VALUE: vol.All(vol.Coerce(int), vol.Range(min=0, max=255)),
|
||||
ATTR_FLASH: vol.In([FLASH_SHORT, FLASH_LONG]),
|
||||
ATTR_FLASH: VALID_FLASH,
|
||||
ATTR_EFFECT: cv.string,
|
||||
}
|
||||
|
||||
@ -252,10 +253,7 @@ async def async_setup(hass, config):
|
||||
|
||||
component.async_register_entity_service(
|
||||
SERVICE_TURN_OFF,
|
||||
{
|
||||
ATTR_TRANSITION: VALID_TRANSITION,
|
||||
ATTR_FLASH: vol.In([FLASH_SHORT, FLASH_LONG]),
|
||||
},
|
||||
{ATTR_TRANSITION: VALID_TRANSITION, ATTR_FLASH: VALID_FLASH},
|
||||
"async_turn_off",
|
||||
)
|
||||
|
||||
|
@ -4,6 +4,13 @@ from typing import List
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.device_automation import toggle_entity
|
||||
from homeassistant.components.light import (
|
||||
ATTR_FLASH,
|
||||
FLASH_SHORT,
|
||||
SUPPORT_FLASH,
|
||||
VALID_BRIGHTNESS_PCT,
|
||||
VALID_FLASH,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_SUPPORTED_FEATURES,
|
||||
@ -19,6 +26,7 @@ from . import ATTR_BRIGHTNESS_PCT, ATTR_BRIGHTNESS_STEP_PCT, DOMAIN, SUPPORT_BRI
|
||||
|
||||
TYPE_BRIGHTNESS_INCREASE = "brightness_increase"
|
||||
TYPE_BRIGHTNESS_DECREASE = "brightness_decrease"
|
||||
TYPE_FLASH = "flash"
|
||||
|
||||
ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend(
|
||||
{
|
||||
@ -26,11 +34,10 @@ ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend(
|
||||
vol.Required(CONF_DOMAIN): DOMAIN,
|
||||
vol.Required(CONF_TYPE): vol.In(
|
||||
toggle_entity.DEVICE_ACTION_TYPES
|
||||
+ [TYPE_BRIGHTNESS_INCREASE, TYPE_BRIGHTNESS_DECREASE]
|
||||
),
|
||||
vol.Optional(ATTR_BRIGHTNESS_PCT): vol.All(
|
||||
vol.Coerce(int), vol.Range(min=0, max=100)
|
||||
+ [TYPE_BRIGHTNESS_INCREASE, TYPE_BRIGHTNESS_DECREASE, TYPE_FLASH]
|
||||
),
|
||||
vol.Optional(ATTR_BRIGHTNESS_PCT): VALID_BRIGHTNESS_PCT,
|
||||
vol.Optional(ATTR_FLASH): VALID_FLASH,
|
||||
}
|
||||
)
|
||||
|
||||
@ -60,6 +67,12 @@ async def async_call_action_from_config(
|
||||
elif ATTR_BRIGHTNESS_PCT in config:
|
||||
data[ATTR_BRIGHTNESS_PCT] = config[ATTR_BRIGHTNESS_PCT]
|
||||
|
||||
if config[CONF_TYPE] == TYPE_FLASH:
|
||||
if ATTR_FLASH in config:
|
||||
data[ATTR_FLASH] = config[ATTR_FLASH]
|
||||
else:
|
||||
data[ATTR_FLASH] = FLASH_SHORT
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN, SERVICE_TURN_ON, data, blocking=True, context=context
|
||||
)
|
||||
@ -100,6 +113,18 @@ async def async_get_actions(hass: HomeAssistant, device_id: str) -> List[dict]:
|
||||
)
|
||||
)
|
||||
|
||||
if supported_features & SUPPORT_FLASH:
|
||||
actions.extend(
|
||||
(
|
||||
{
|
||||
CONF_TYPE: TYPE_FLASH,
|
||||
"device_id": device_id,
|
||||
"entity_id": entry.entity_id,
|
||||
"domain": DOMAIN,
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
return actions
|
||||
|
||||
|
||||
@ -119,15 +144,12 @@ async def async_get_action_capabilities(hass: HomeAssistant, config: dict) -> di
|
||||
elif entry:
|
||||
supported_features = entry.supported_features
|
||||
|
||||
if not supported_features & SUPPORT_BRIGHTNESS:
|
||||
return {}
|
||||
extra_fields = {}
|
||||
|
||||
return {
|
||||
"extra_fields": vol.Schema(
|
||||
{
|
||||
vol.Optional(ATTR_BRIGHTNESS_PCT): vol.All(
|
||||
vol.Coerce(int), vol.Range(min=0, max=100)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
if supported_features & SUPPORT_BRIGHTNESS:
|
||||
extra_fields[vol.Optional(ATTR_BRIGHTNESS_PCT)] = VALID_BRIGHTNESS_PCT
|
||||
|
||||
if supported_features & SUPPORT_FLASH:
|
||||
extra_fields[vol.Optional(ATTR_FLASH)] = VALID_FLASH
|
||||
|
||||
return {"extra_fields": vol.Schema(extra_fields)} if extra_fields else {}
|
||||
|
@ -5,7 +5,8 @@
|
||||
"brightness_increase": "Increase {entity_name} brightness",
|
||||
"toggle": "Toggle {entity_name}",
|
||||
"turn_on": "Turn on {entity_name}",
|
||||
"turn_off": "Turn off {entity_name}"
|
||||
"turn_off": "Turn off {entity_name}",
|
||||
"flash": "Flash {entity_name}"
|
||||
},
|
||||
"condition_type": {
|
||||
"is_on": "{entity_name} is on",
|
||||
|
@ -2,7 +2,13 @@
|
||||
import pytest
|
||||
|
||||
import homeassistant.components.automation as automation
|
||||
from homeassistant.components.light import DOMAIN, SUPPORT_BRIGHTNESS
|
||||
from homeassistant.components.light import (
|
||||
DOMAIN,
|
||||
FLASH_LONG,
|
||||
FLASH_SHORT,
|
||||
SUPPORT_BRIGHTNESS,
|
||||
SUPPORT_FLASH,
|
||||
)
|
||||
from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON
|
||||
from homeassistant.helpers import device_registry
|
||||
from homeassistant.setup import async_setup_component
|
||||
@ -48,7 +54,7 @@ async def test_get_actions(hass, device_reg, entity_reg):
|
||||
"test",
|
||||
"5678",
|
||||
device_id=device_entry.id,
|
||||
supported_features=SUPPORT_BRIGHTNESS,
|
||||
supported_features=SUPPORT_BRIGHTNESS | SUPPORT_FLASH,
|
||||
)
|
||||
expected_actions = [
|
||||
{
|
||||
@ -81,6 +87,12 @@ async def test_get_actions(hass, device_reg, entity_reg):
|
||||
"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",
|
||||
},
|
||||
]
|
||||
actions = await async_get_device_automations(hass, "action", device_entry.id)
|
||||
assert actions == expected_actions
|
||||
@ -128,7 +140,7 @@ async def test_get_action_capabilities_brightness(hass, device_reg, entity_reg):
|
||||
{
|
||||
"name": "brightness_pct",
|
||||
"optional": True,
|
||||
"type": "integer",
|
||||
"type": "float",
|
||||
"valueMax": 100,
|
||||
"valueMin": 0,
|
||||
}
|
||||
@ -146,6 +158,45 @@ async def test_get_action_capabilities_brightness(hass, device_reg, entity_reg):
|
||||
assert capabilities == {"extra_fields": []}
|
||||
|
||||
|
||||
async def test_get_action_capabilities_flash(hass, device_reg, entity_reg):
|
||||
"""Test we get the expected capabilities from a light action."""
|
||||
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,
|
||||
supported_features=SUPPORT_FLASH,
|
||||
)
|
||||
|
||||
expected_capabilities = {
|
||||
"extra_fields": [
|
||||
{
|
||||
"name": "flash",
|
||||
"optional": True,
|
||||
"type": "select",
|
||||
"options": [("short", "short"), ("long", "long")],
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
actions = await async_get_device_automations(hass, "action", device_entry.id)
|
||||
assert len(actions) == 4
|
||||
for action in actions:
|
||||
capabilities = await async_get_device_automation_capabilities(
|
||||
hass, "action", action
|
||||
)
|
||||
if action["type"] == "turn_on":
|
||||
assert capabilities == expected_capabilities
|
||||
else:
|
||||
assert capabilities == {"extra_fields": []}
|
||||
|
||||
|
||||
async def test_action(hass, calls):
|
||||
"""Test for turn_on and turn_off actions."""
|
||||
platform = getattr(hass.components, f"test.{DOMAIN}")
|
||||
@ -187,6 +238,25 @@ async def test_action(hass, calls):
|
||||
"type": "toggle",
|
||||
},
|
||||
},
|
||||
{
|
||||
"trigger": {"platform": "event", "event_type": "test_flash_short"},
|
||||
"action": {
|
||||
"domain": DOMAIN,
|
||||
"device_id": "",
|
||||
"entity_id": ent1.entity_id,
|
||||
"type": "flash",
|
||||
},
|
||||
},
|
||||
{
|
||||
"trigger": {"platform": "event", "event_type": "test_flash_long"},
|
||||
"action": {
|
||||
"domain": DOMAIN,
|
||||
"device_id": "",
|
||||
"entity_id": ent1.entity_id,
|
||||
"type": "flash",
|
||||
"flash": "long",
|
||||
},
|
||||
},
|
||||
{
|
||||
"trigger": {
|
||||
"platform": "event",
|
||||
@ -252,6 +322,22 @@ async def test_action(hass, calls):
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(ent1.entity_id).state == STATE_ON
|
||||
|
||||
hass.bus.async_fire("test_toggle")
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(ent1.entity_id).state == STATE_OFF
|
||||
|
||||
hass.bus.async_fire("test_flash_short")
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(ent1.entity_id).state == STATE_ON
|
||||
|
||||
hass.bus.async_fire("test_toggle")
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(ent1.entity_id).state == STATE_OFF
|
||||
|
||||
hass.bus.async_fire("test_flash_long")
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(ent1.entity_id).state == STATE_ON
|
||||
|
||||
turn_on_calls = async_mock_service(hass, DOMAIN, "turn_on")
|
||||
|
||||
hass.bus.async_fire("test_brightness_increase")
|
||||
@ -281,3 +367,17 @@ async def test_action(hass, calls):
|
||||
assert len(turn_on_calls) == 4
|
||||
assert turn_on_calls[3].data["entity_id"] == ent1.entity_id
|
||||
assert "brightness_pct" not in turn_on_calls[3].data
|
||||
|
||||
hass.bus.async_fire("test_flash_short")
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(turn_on_calls) == 5
|
||||
assert turn_on_calls[4].data["entity_id"] == ent1.entity_id
|
||||
assert turn_on_calls[4].data["flash"] == FLASH_SHORT
|
||||
|
||||
hass.bus.async_fire("test_flash_long")
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(turn_on_calls) == 6
|
||||
assert turn_on_calls[5].data["entity_id"] == ent1.entity_id
|
||||
assert turn_on_calls[5].data["flash"] == FLASH_LONG
|
||||
|
Loading…
x
Reference in New Issue
Block a user