Reflect Verisure lock, alarm control panel and switch state immediately without cloud pull (#149479)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
This commit is contained in:
Tor André Roland
2025-09-13 16:41:51 +02:00
committed by GitHub
parent 97077898bb
commit 24c04cceee
3 changed files with 47 additions and 35 deletions

View File

@@ -67,8 +67,13 @@ class VerisureAlarm(
)
LOGGER.debug("Verisure set arm state %s", state)
result = None
attempts = 0
while result is None:
await asyncio.sleep(0.5)
if attempts == 30:
break
if attempts > 1:
await asyncio.sleep(0.5)
attempts += 1
transaction = await self.hass.async_add_executor_job(
self.coordinator.verisure.request,
self.coordinator.verisure.poll_arm_state(
@@ -81,8 +86,10 @@ class VerisureAlarm(
.get("armStateChangePollResult", {})
.get("result")
)
await self.coordinator.async_refresh()
LOGGER.debug("Result is %s", result)
if result == "OK":
self._attr_alarm_state = ALARM_STATE_TO_HA.get(state)
self.async_write_ha_state()
async def async_alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
@@ -108,16 +115,20 @@ class VerisureAlarm(
"ARMED_AWAY", self.coordinator.verisure.arm_away(code)
)
@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
def _update_alarm_attributes(self) -> None:
"""Update alarm state and changed by from coordinator data."""
self._attr_alarm_state = ALARM_STATE_TO_HA.get(
self.coordinator.data["alarm"]["statusType"]
)
self._attr_changed_by = self.coordinator.data["alarm"].get("name")
@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self._update_alarm_attributes()
super()._handle_coordinator_update()
async def async_added_to_hass(self) -> None:
"""When entity is added to hass."""
await super().async_added_to_hass()
self._handle_coordinator_update()
self._update_alarm_attributes()

View File

@@ -10,7 +10,7 @@ from verisure import Error as VerisureError
from homeassistant.components.lock import LockEntity, LockState
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_CODE
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import (
AddConfigEntryEntitiesCallback,
@@ -70,7 +70,9 @@ class VerisureDoorlock(CoordinatorEntity[VerisureDataUpdateCoordinator], LockEnt
self._attr_unique_id = serial_number
self.serial_number = serial_number
self._state: str | None = None
self._attr_is_locked = None
self._attr_changed_by = None
self._changed_method: str | None = None
@property
def device_info(self) -> DeviceInfo:
@@ -92,20 +94,6 @@ class VerisureDoorlock(CoordinatorEntity[VerisureDataUpdateCoordinator], LockEnt
super().available and self.serial_number in self.coordinator.data["locks"]
)
@property
def changed_by(self) -> str | None:
"""Last change triggered by."""
return (
self.coordinator.data["locks"][self.serial_number]
.get("user", {})
.get("name")
)
@property
def changed_method(self) -> str:
"""Last change method."""
return self.coordinator.data["locks"][self.serial_number]["lockMethod"]
@property
def code_format(self) -> str:
"""Return the configured code format."""
@@ -115,16 +103,9 @@ class VerisureDoorlock(CoordinatorEntity[VerisureDataUpdateCoordinator], LockEnt
return f"^\\d{{{digits}}}$"
@property
def is_locked(self) -> bool:
"""Return true if lock is locked."""
return (
self.coordinator.data["locks"][self.serial_number]["lockStatus"] == "LOCKED"
)
@property
def extra_state_attributes(self) -> dict[str, str]:
def extra_state_attributes(self) -> dict[str, str | None]:
"""Return the state attributes."""
return {"method": self.changed_method}
return {"method": self._changed_method}
async def async_unlock(self, **kwargs: Any) -> None:
"""Send unlock command."""
@@ -154,7 +135,7 @@ class VerisureDoorlock(CoordinatorEntity[VerisureDataUpdateCoordinator], LockEnt
target_state = "LOCKED" if state == LockState.LOCKED else "UNLOCKED"
lock_status = None
attempts = 0
while lock_status != "OK":
while lock_status is None:
if attempts == 30:
break
if attempts > 1:
@@ -172,8 +153,10 @@ class VerisureDoorlock(CoordinatorEntity[VerisureDataUpdateCoordinator], LockEnt
.get("doorLockStateChangePollResult", {})
.get("result")
)
LOGGER.debug("Lock status is %s", lock_status)
if lock_status == "OK":
self._state = state
self._attr_is_locked = state == LockState.LOCKED
self.async_write_ha_state()
def disable_autolock(self) -> None:
"""Disable autolock on a doorlock."""
@@ -196,3 +179,21 @@ class VerisureDoorlock(CoordinatorEntity[VerisureDataUpdateCoordinator], LockEnt
LOGGER.debug("Enabling autolock on %s", self.serial_number)
except VerisureError as ex:
LOGGER.error("Could not enable autolock, %s", ex)
def _update_lock_attributes(self) -> None:
"""Update lock state, changed by, and method from coordinator data."""
lock_data = self.coordinator.data["locks"][self.serial_number]
self._attr_is_locked = lock_data["lockStatus"] == "LOCKED"
self._attr_changed_by = lock_data.get("user", {}).get("name")
self._changed_method = lock_data["lockMethod"]
@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self._update_lock_attributes()
super()._handle_coordinator_update()
async def async_added_to_hass(self) -> None:
"""When entity is added to hass."""
await super().async_added_to_hass()
self._update_lock_attributes()

View File

@@ -99,4 +99,4 @@ class VerisureSmartplug(CoordinatorEntity[VerisureDataUpdateCoordinator], Switch
)
self._state = state
self._change_timestamp = monotonic()
await self.coordinator.async_request_refresh()
self.async_write_ha_state()