diff --git a/.coveragerc b/.coveragerc index 0078882e167..86b129f636c 100644 --- a/.coveragerc +++ b/.coveragerc @@ -866,6 +866,7 @@ omit = homeassistant/components/screenlogic/binary_sensor.py homeassistant/components/screenlogic/climate.py homeassistant/components/screenlogic/sensor.py + homeassistant/components/screenlogic/services.py homeassistant/components/screenlogic/switch.py homeassistant/components/scsgate/* homeassistant/components/scsgate/cover.py diff --git a/homeassistant/components/screenlogic/__init__.py b/homeassistant/components/screenlogic/__init__.py index c5c082cd509..cb747b3ed84 100644 --- a/homeassistant/components/screenlogic/__init__.py +++ b/homeassistant/components/screenlogic/__init__.py @@ -25,6 +25,7 @@ from homeassistant.helpers.update_coordinator import ( from .config_flow import async_discover_gateways_by_unique_id, name_for_mac from .const import DEFAULT_SCAN_INTERVAL, DISCOVERED_GATEWAYS, DOMAIN +from .services import async_load_screenlogic_services, async_unload_screenlogic_services _LOGGER = logging.getLogger(__name__) @@ -68,10 +69,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): hass, config_entry=entry, gateway=gateway, api_lock=api_lock ) - device_data = defaultdict(list) + async_load_screenlogic_services(hass) await coordinator.async_config_entry_first_refresh() + device_data = defaultdict(list) + for circuit in coordinator.data["circuits"]: device_data["switch"].append(circuit) @@ -120,6 +123,8 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): if unload_ok: hass.data[DOMAIN].pop(entry.entry_id) + async_unload_screenlogic_services(hass) + return unload_ok @@ -137,6 +142,7 @@ class ScreenlogicDataUpdateCoordinator(DataUpdateCoordinator): self.gateway = gateway self.api_lock = api_lock self.screenlogic_data = {} + interval = timedelta( seconds=config_entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL) ) diff --git a/homeassistant/components/screenlogic/const.py b/homeassistant/components/screenlogic/const.py index d777dc6ddc5..49a57b8d46e 100644 --- a/homeassistant/components/screenlogic/const.py +++ b/homeassistant/components/screenlogic/const.py @@ -1,7 +1,16 @@ """Constants for the ScreenLogic integration.""" +from screenlogicpy.const import COLOR_MODE + +from homeassistant.util import slugify DOMAIN = "screenlogic" DEFAULT_SCAN_INTERVAL = 30 MIN_SCAN_INTERVAL = 10 +SERVICE_SET_COLOR_MODE = "set_color_mode" +ATTR_COLOR_MODE = "color_mode" +SUPPORTED_COLOR_MODES = { + slugify(name): num for num, name in COLOR_MODE.NAME_FOR_NUM.items() +} + DISCOVERED_GATEWAYS = "_discovered_gateways" diff --git a/homeassistant/components/screenlogic/manifest.json b/homeassistant/components/screenlogic/manifest.json index e62c5ba1f8a..e4d1be9bfb4 100644 --- a/homeassistant/components/screenlogic/manifest.json +++ b/homeassistant/components/screenlogic/manifest.json @@ -3,7 +3,7 @@ "name": "Pentair ScreenLogic", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/screenlogic", - "requirements": ["screenlogicpy==0.2.1"], + "requirements": ["screenlogicpy==0.3.0"], "codeowners": ["@dieselrabbit"], "dhcp": [ { diff --git a/homeassistant/components/screenlogic/services.py b/homeassistant/components/screenlogic/services.py new file mode 100644 index 00000000000..7ca2bb69129 --- /dev/null +++ b/homeassistant/components/screenlogic/services.py @@ -0,0 +1,89 @@ +"""Services for ScreenLogic integration.""" + +import logging + +from screenlogicpy import ScreenLogicError +import voluptuous as vol + +from homeassistant.core import ServiceCall, callback +from homeassistant.exceptions import HomeAssistantError +import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.service import async_extract_config_entry_ids +from homeassistant.helpers.typing import HomeAssistantType + +from .const import ( + ATTR_COLOR_MODE, + DOMAIN, + SERVICE_SET_COLOR_MODE, + SUPPORTED_COLOR_MODES, +) + +_LOGGER = logging.getLogger(__name__) + +SET_COLOR_MODE_SCHEMA = cv.make_entity_service_schema( + { + vol.Required(ATTR_COLOR_MODE): vol.In(SUPPORTED_COLOR_MODES), + }, +) + + +@callback +def async_load_screenlogic_services(hass: HomeAssistantType): + """Set up services for the ScreenLogic integration.""" + if hass.services.has_service(DOMAIN, SERVICE_SET_COLOR_MODE): + # Integration-level services have already been added. Return. + return + + async def extract_screenlogic_config_entry_ids(service_call: ServiceCall): + return [ + entry_id + for entry_id in await async_extract_config_entry_ids(hass, service_call) + if hass.config_entries.async_get_entry(entry_id).domain == DOMAIN + ] + + async def async_set_color_mode(service_call: ServiceCall): + if not ( + screenlogic_entry_ids := await extract_screenlogic_config_entry_ids( + service_call + ) + ): + raise HomeAssistantError( + f"Failed to call service '{SERVICE_SET_COLOR_MODE}'. Config entry for target not found" + ) + color_num = SUPPORTED_COLOR_MODES[service_call.data[ATTR_COLOR_MODE]] + for entry_id in screenlogic_entry_ids: + coordinator = hass.data[DOMAIN][entry_id]["coordinator"] + _LOGGER.debug( + "Service %s called on %s with mode %s", + SERVICE_SET_COLOR_MODE, + coordinator.gateway.name, + color_num, + ) + try: + async with coordinator.api_lock: + if not await hass.async_add_executor_job( + coordinator.gateway.set_color_lights, color_num + ): + raise HomeAssistantError( + f"Failed to call service '{SERVICE_SET_COLOR_MODE}'" + ) + except ScreenLogicError as error: + raise HomeAssistantError(error) from error + + hass.services.async_register( + DOMAIN, SERVICE_SET_COLOR_MODE, async_set_color_mode, SET_COLOR_MODE_SCHEMA + ) + + +@callback +def async_unload_screenlogic_services(hass: HomeAssistantType): + """Unload services for the ScreenLogic integration.""" + if hass.data[DOMAIN]: + # There is still another config entry for this domain, don't remove services. + return + + if not hass.services.has_service(DOMAIN, SERVICE_SET_COLOR_MODE): + return + + _LOGGER.info("Unloading ScreenLogic Services") + hass.services.async_remove(domain=DOMAIN, service=SERVICE_SET_COLOR_MODE) diff --git a/homeassistant/components/screenlogic/services.yaml b/homeassistant/components/screenlogic/services.yaml new file mode 100644 index 00000000000..7b54b9541d2 --- /dev/null +++ b/homeassistant/components/screenlogic/services.yaml @@ -0,0 +1,38 @@ +# ScreenLogic Services +set_color_mode: + name: Set Color Mode + description: Sets the color mode for all color-capable lights attached to this ScreenLogic gateway. + target: + device: + integration: screenlogic + fields: + color_mode: + name: Color Mode + description: The ScreenLogic color mode to set + required: true + example: "romance" + selector: + select: + options: + - all_off + - all_on + - color_set + - color_sync + - color_swim + - party + - romance + - caribbean + - american + - sunset + - royal + - save + - recall + - blue + - green + - red + - white + - magenta + - thumper + - next_mode + - reset + - hold diff --git a/requirements_all.txt b/requirements_all.txt index 644682ad29e..b52b8415755 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2024,7 +2024,7 @@ scapy==2.4.4 schiene==0.23 # homeassistant.components.screenlogic -screenlogicpy==0.2.1 +screenlogicpy==0.3.0 # homeassistant.components.scsgate scsgate==0.1.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index f90dcf3ff69..b0b64af7159 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1073,7 +1073,7 @@ samsungtvws==1.6.0 scapy==2.4.4 # homeassistant.components.screenlogic -screenlogicpy==0.2.1 +screenlogicpy==0.3.0 # homeassistant.components.emulated_kasa # homeassistant.components.sense