From 5092971452afc44b9a82431fa318a9c4625ad7f4 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 9 Feb 2020 19:47:59 -0800 Subject: [PATCH] Add brightness light device actions (#31567) --- .../device_automation/toggle_entity.py | 4 +- .../components/light/device_action.py | 77 +++++++++++++++++-- tests/components/light/test_device_action.py | 62 ++++++++++++++- 3 files changed, 134 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/device_automation/toggle_entity.py b/homeassistant/components/device_automation/toggle_entity.py index f6bb74edbec..a2dcd62db8c 100644 --- a/homeassistant/components/device_automation/toggle_entity.py +++ b/homeassistant/components/device_automation/toggle_entity.py @@ -74,10 +74,12 @@ ENTITY_TRIGGERS = [ }, ] +DEVICE_ACTION_TYPES = [CONF_TOGGLE, CONF_TURN_OFF, CONF_TURN_ON] + ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend( { vol.Required(CONF_ENTITY_ID): cv.entity_id, - vol.Required(CONF_TYPE): vol.In([CONF_TOGGLE, CONF_TURN_OFF, CONF_TURN_ON]), + vol.Required(CONF_TYPE): vol.In(DEVICE_ACTION_TYPES), } ) diff --git a/homeassistant/components/light/device_action.py b/homeassistant/components/light/device_action.py index c436ce7886a..99f5b6b12bc 100644 --- a/homeassistant/components/light/device_action.py +++ b/homeassistant/components/light/device_action.py @@ -4,13 +4,32 @@ from typing import List import voluptuous as vol from homeassistant.components.device_automation import toggle_entity -from homeassistant.const import CONF_DOMAIN +from homeassistant.const import ( + ATTR_ENTITY_ID, + ATTR_SUPPORTED_FEATURES, + CONF_DOMAIN, + CONF_TYPE, + SERVICE_TURN_ON, +) from homeassistant.core import Context, HomeAssistant +from homeassistant.helpers import config_validation as cv, entity_registry from homeassistant.helpers.typing import ConfigType, TemplateVarsType -from . import DOMAIN +from . import ATTR_BRIGHTNESS_STEP_PCT, DOMAIN, SUPPORT_BRIGHTNESS -ACTION_SCHEMA = toggle_entity.ACTION_SCHEMA.extend({vol.Required(CONF_DOMAIN): DOMAIN}) +TYPE_BRIGHTNESS_INCREASE = "brightness_increase" +TYPE_BRIGHTNESS_DECREASE = "brightness_decrease" + +ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend( + { + vol.Required(ATTR_ENTITY_ID): cv.entity_id, + vol.Required(CONF_DOMAIN): DOMAIN, + vol.Required(CONF_TYPE): vol.In( + toggle_entity.DEVICE_ACTION_TYPES + + [TYPE_BRIGHTNESS_INCREASE, TYPE_BRIGHTNESS_DECREASE] + ), + } +) async def async_call_action_from_config( @@ -20,11 +39,57 @@ async def async_call_action_from_config( context: Context, ) -> None: """Change state based on configuration.""" - await toggle_entity.async_call_action_from_config( - hass, config, variables, context, DOMAIN + if config[CONF_TYPE] in toggle_entity.DEVICE_ACTION_TYPES: + await toggle_entity.async_call_action_from_config( + hass, config, variables, context, DOMAIN + ) + return + + data = {ATTR_ENTITY_ID: config[ATTR_ENTITY_ID]} + + if config[CONF_TYPE] == TYPE_BRIGHTNESS_INCREASE: + data[ATTR_BRIGHTNESS_STEP_PCT] = 10 + else: + data[ATTR_BRIGHTNESS_STEP_PCT] = -10 + + await hass.services.async_call( + DOMAIN, SERVICE_TURN_ON, data, blocking=True, context=context ) async def async_get_actions(hass: HomeAssistant, device_id: str) -> List[dict]: """List device actions.""" - return await toggle_entity.async_get_actions(hass, device_id, DOMAIN) + actions = await toggle_entity.async_get_actions(hass, device_id, DOMAIN) + + registry = await entity_registry.async_get_registry(hass) + + for entry in entity_registry.async_entries_for_device(registry, device_id): + if entry.domain != DOMAIN: + continue + + state = hass.states.get(entry.entity_id) + + if state: + supported_features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0) + else: + supported_features = entry.supported_features + + if supported_features & SUPPORT_BRIGHTNESS: + actions.extend( + ( + { + CONF_TYPE: TYPE_BRIGHTNESS_INCREASE, + "device_id": device_id, + "entity_id": entry.entity_id, + "domain": DOMAIN, + }, + { + CONF_TYPE: TYPE_BRIGHTNESS_DECREASE, + "device_id": device_id, + "entity_id": entry.entity_id, + "domain": DOMAIN, + }, + ) + ) + + return actions diff --git a/tests/components/light/test_device_action.py b/tests/components/light/test_device_action.py index a737396cca8..3ac8171ce7d 100644 --- a/tests/components/light/test_device_action.py +++ b/tests/components/light/test_device_action.py @@ -2,7 +2,7 @@ import pytest import homeassistant.components.automation as automation -from homeassistant.components.light import DOMAIN +from homeassistant.components.light import DOMAIN, SUPPORT_BRIGHTNESS from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON from homeassistant.helpers import device_registry from homeassistant.setup import async_setup_component @@ -42,7 +42,13 @@ async def test_get_actions(hass, device_reg, entity_reg): 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_reg.async_get_or_create( + DOMAIN, + "test", + "5678", + device_id=device_entry.id, + supported_features=SUPPORT_BRIGHTNESS, + ) expected_actions = [ { "domain": DOMAIN, @@ -62,6 +68,18 @@ async def test_get_actions(hass, device_reg, entity_reg): "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", + }, ] actions = await async_get_device_automations(hass, "action", device_entry.id) assert actions == expected_actions @@ -108,6 +126,30 @@ async def test_action(hass, calls): "type": "toggle", }, }, + { + "trigger": { + "platform": "event", + "event_type": "test_brightness_increase", + }, + "action": { + "domain": DOMAIN, + "device_id": "", + "entity_id": ent1.entity_id, + "type": "brightness_increase", + }, + }, + { + "trigger": { + "platform": "event", + "event_type": "test_brightness_decrease", + }, + "action": { + "domain": DOMAIN, + "device_id": "", + "entity_id": ent1.entity_id, + "type": "brightness_decrease", + }, + }, ] }, ) @@ -138,3 +180,19 @@ async def test_action(hass, calls): hass.bus.async_fire("test_event3") 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") + await hass.async_block_till_done() + + assert len(turn_on_calls) == 1 + assert turn_on_calls[0].data["entity_id"] == ent1.entity_id + assert turn_on_calls[0].data["brightness_step_pct"] == 10 + + hass.bus.async_fire("test_brightness_decrease") + await hass.async_block_till_done() + + assert len(turn_on_calls) == 2 + assert turn_on_calls[1].data["entity_id"] == ent1.entity_id + assert turn_on_calls[1].data["brightness_step_pct"] == -10