diff --git a/homeassistant/components/dynalite/__init__.py b/homeassistant/components/dynalite/__init__.py index 78281f56f0f..f04869d7160 100644 --- a/homeassistant/components/dynalite/__init__.py +++ b/homeassistant/components/dynalite/__init__.py @@ -1,7 +1,7 @@ """Support for the Dynalite networks.""" import asyncio -from typing import Any, Dict, Union +from typing import Any, Dict, List, Union import voluptuous as vol @@ -9,7 +9,7 @@ from homeassistant import config_entries from homeassistant.components.cover import DEVICE_CLASSES_SCHEMA from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT, CONF_TYPE -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import config_validation as cv @@ -19,6 +19,9 @@ from .const import ( ACTIVE_INIT, ACTIVE_OFF, ACTIVE_ON, + ATTR_AREA, + ATTR_CHANNEL, + ATTR_HOST, CONF_ACTIVE, CONF_AREA, CONF_AUTO_DISCOVER, @@ -198,6 +201,36 @@ async def async_setup(hass: HomeAssistant, config: Dict[str, Any]) -> bool: ) ) + def get_bridges(host: str) -> List[DynaliteBridge]: + result = [] + for entry_id in hass.data[DOMAIN]: + cur_bridge = hass.data[DOMAIN][entry_id] + if not host or cur_bridge.host == host: + result.append(cur_bridge) + return result + + async def request_area_preset_service(service_call: ServiceCall): + host = service_call.data.get(ATTR_HOST, "") + bridges = get_bridges(host) + LOGGER.debug("Selected bridged for service call: %s", bridges) + area = service_call.data[ATTR_AREA] + channel = service_call.data.get(ATTR_CHANNEL) + for bridge in bridges: + bridge.dynalite_devices.request_area_preset(area, channel) + + hass.services.async_register( + DOMAIN, + "request_area_preset", + request_area_preset_service, + vol.Schema( + { + vol.Optional(ATTR_HOST): cv.string, + vol.Required(ATTR_AREA): int, + vol.Optional(ATTR_CHANNEL): int, + } + ), + ) + return True diff --git a/homeassistant/components/dynalite/const.py b/homeassistant/components/dynalite/const.py index 373e64a1b76..be8d94b6e46 100644 --- a/homeassistant/components/dynalite/const.py +++ b/homeassistant/components/dynalite/const.py @@ -51,6 +51,7 @@ DEFAULT_TEMPLATES = { } ATTR_AREA = "area" +ATTR_CHANNEL = "channel" ATTR_HOST = "host" ATTR_PACKET = "packet" ATTR_PRESET = "preset" diff --git a/homeassistant/components/dynalite/manifest.json b/homeassistant/components/dynalite/manifest.json index a8277eea85c..9c733ccc7a2 100644 --- a/homeassistant/components/dynalite/manifest.json +++ b/homeassistant/components/dynalite/manifest.json @@ -4,5 +4,5 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/dynalite", "codeowners": ["@ziv1234"], - "requirements": ["dynalite_devices==0.1.44"] + "requirements": ["dynalite_devices==0.1.45"] } diff --git a/homeassistant/components/dynalite/services.yaml b/homeassistant/components/dynalite/services.yaml new file mode 100644 index 00000000000..ccaa06ed19a --- /dev/null +++ b/homeassistant/components/dynalite/services.yaml @@ -0,0 +1,13 @@ +request_area_preset: + description: "Requests Dynalite to report the preset for an area." + fields: + host: + description: "Host gateway IP to send to or all configured gateways if not specified." + example: "192.168.0.101" + area: + description: "Area to request the preset reported" + example: 2 + channel: + description: "Channel to request the preset to be reported from. Default is channel 1" + example: 1 + diff --git a/requirements_all.txt b/requirements_all.txt index 6378ae5418e..c6fc71ff78e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -509,7 +509,7 @@ dsmr_parser==0.18 dweepy==0.3.0 # homeassistant.components.dynalite -dynalite_devices==0.1.44 +dynalite_devices==0.1.45 # homeassistant.components.rainforest_eagle eagle200_reader==0.2.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 4793e48d391..68bf6eb0bee 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -264,7 +264,7 @@ doorbirdpy==2.1.0 dsmr_parser==0.18 # homeassistant.components.dynalite -dynalite_devices==0.1.44 +dynalite_devices==0.1.45 # homeassistant.components.ee_brightbox eebrightbox==0.0.4 diff --git a/tests/components/dynalite/test_init.py b/tests/components/dynalite/test_init.py index be646a1854d..6d2fd66f1a2 100644 --- a/tests/components/dynalite/test_init.py +++ b/tests/components/dynalite/test_init.py @@ -79,6 +79,71 @@ async def test_async_setup(hass): assert len(hass.config_entries.async_entries(dynalite.DOMAIN)) == 1 +async def test_service_request_area_preset(hass): + """Test requesting and area preset via service call.""" + with patch( + "homeassistant.components.dynalite.bridge.DynaliteDevices.async_setup", + return_value=True, + ), patch( + "dynalite_devices_lib.dynalite.Dynalite.request_area_preset", return_value=True, + ) as mock_req_area_pres: + assert await async_setup_component( + hass, + dynalite.DOMAIN, + { + dynalite.DOMAIN: { + dynalite.CONF_BRIDGES: [ + { + CONF_HOST: "1.2.3.4", + CONF_PORT: 1234, + dynalite.CONF_AREA: {"7": {CONF_NAME: "test"}}, + }, + {CONF_HOST: "5.6.7.8", CONF_PORT: 5678}, + ] + } + }, + ) + await hass.async_block_till_done() + assert len(hass.config_entries.async_entries(dynalite.DOMAIN)) == 2 + await hass.services.async_call( + dynalite.DOMAIN, "request_area_preset", {"host": "1.2.3.4", "area": 2}, + ) + await hass.async_block_till_done() + mock_req_area_pres.assert_called_once_with(2, 1) + mock_req_area_pres.reset_mock() + await hass.services.async_call( + dynalite.DOMAIN, "request_area_preset", {"area": 3}, + ) + await hass.async_block_till_done() + assert mock_req_area_pres.mock_calls == [call(3, 1), call(3, 1)] + mock_req_area_pres.reset_mock() + await hass.services.async_call( + dynalite.DOMAIN, "request_area_preset", {"host": "5.6.7.8", "area": 4}, + ) + await hass.async_block_till_done() + mock_req_area_pres.assert_called_once_with(4, 1) + mock_req_area_pres.reset_mock() + await hass.services.async_call( + dynalite.DOMAIN, "request_area_preset", {"host": "6.5.4.3", "area": 5}, + ) + await hass.async_block_till_done() + mock_req_area_pres.assert_not_called() + mock_req_area_pres.reset_mock() + await hass.services.async_call( + dynalite.DOMAIN, + "request_area_preset", + {"host": "1.2.3.4", "area": 6, "channel": 9}, + ) + await hass.async_block_till_done() + mock_req_area_pres.assert_called_once_with(6, 9) + mock_req_area_pres.reset_mock() + await hass.services.async_call( + dynalite.DOMAIN, "request_area_preset", {"host": "1.2.3.4", "area": 7}, + ) + await hass.async_block_till_done() + mock_req_area_pres.assert_called_once_with(7, 1) + + async def test_async_setup_bad_config1(hass): """Test a successful with bad config on templates.""" with patch(