diff --git a/custom_components/econnect_metronet/__init__.py b/custom_components/econnect_metronet/__init__.py index 80d01f7..47371cf 100644 --- a/custom_components/econnect_metronet/__init__.py +++ b/custom_components/econnect_metronet/__init__.py @@ -130,6 +130,7 @@ async def async_setup_entry(hass: HomeAssistant, config: ConfigEntry) -> bool: # as we need both to access the integration configurations. hass.services.async_register(DOMAIN, "arm_sectors", partial(services.arm_sectors, hass, config.entry_id)) hass.services.async_register(DOMAIN, "disarm_sectors", partial(services.disarm_sectors, hass, config.entry_id)) + hass.services.async_register(DOMAIN, "update_state", partial(services.update_state, hass, config.entry_id)) for component in PLATFORMS: hass.async_create_task(hass.config_entries.async_forward_entry_setup(config, component)) diff --git a/custom_components/econnect_metronet/icons.json b/custom_components/econnect_metronet/icons.json index 9f1a113..070a948 100644 --- a/custom_components/econnect_metronet/icons.json +++ b/custom_components/econnect_metronet/icons.json @@ -1,6 +1,7 @@ { "services": { "arm_sectors": "mdi:shield-lock", - "disarm_sectors": "mdi:shield-off" + "disarm_sectors": "mdi:shield-off", + "update_state": "mdi:update" } } diff --git a/custom_components/econnect_metronet/services.py b/custom_components/econnect_metronet/services.py index 2c57f66..8d0d228 100644 --- a/custom_components/econnect_metronet/services.py +++ b/custom_components/econnect_metronet/services.py @@ -2,7 +2,7 @@ from homeassistant.core import HomeAssistant, ServiceCall -from .const import DOMAIN, KEY_DEVICE +from .const import DOMAIN, KEY_COORDINATOR, KEY_DEVICE from .decorators import retry_refresh_token_service _LOGGER = logging.getLogger(__name__) @@ -26,3 +26,11 @@ async def disarm_sectors(hass: HomeAssistant, config_id: str, call: ServiceCall) code = call.data.get("code") _LOGGER.debug(f"Service | Disarming sectors: {sectors}") await hass.async_add_executor_job(device.disarm, code, sectors) + + +@retry_refresh_token_service +async def update_state(hass: HomeAssistant, config_id: str, call: ServiceCall): + _LOGGER.debug(f"Service | Triggered action {call.service}") + coordinator = hass.data[DOMAIN][config_id][KEY_COORDINATOR] + _LOGGER.debug("Service | Updating alarm state...") + await coordinator.async_refresh() diff --git a/custom_components/econnect_metronet/services.yaml b/custom_components/econnect_metronet/services.yaml index 6527555..e2d1bb3 100644 --- a/custom_components/econnect_metronet/services.yaml +++ b/custom_components/econnect_metronet/services.yaml @@ -1,5 +1,9 @@ # Describes the format for available e-Connect services +update_state: + name: Update Alarm State + description: Force an update of the alarm areas and inputs. + arm_sectors: name: Arm Sectors description: Arm one or multiple sectors. diff --git a/tests/test_services.py b/tests/test_services.py index 4fa5981..d1bf5d4 100644 --- a/tests/test_services.py +++ b/tests/test_services.py @@ -57,3 +57,21 @@ async def test_service_disarm_sectors(hass, config_entry, alarm_device, coordina assert disarm.call_count == 1 assert disarm.call_args[0][0] == "1234" assert disarm.call_args[0][1] == [1, 3] + + +async def test_service_update_state(hass, config_entry, alarm_device, coordinator, mocker): + # Ensure `update_state` triggers a full refresh + update = mocker.patch.object(alarm_device, "update") + hass.data[DOMAIN][config_entry.entry_id] = { + "device": alarm_device, + "coordinator": coordinator, + } + call = ServiceCall( + domain=DOMAIN, + service="update_state", + data={}, + ) + # Test + await services.update_state(hass, config_entry.entry_id, call) + assert update.call_count == 1 + assert update.call_args == ()