Skip to content

Commit

Permalink
fix incorrect handling of fast state transitioning
Browse files Browse the repository at this point in the history
nielsfaber committed May 27, 2024
1 parent 77a294e commit dd1adc7
Showing 1 changed file with 42 additions and 27 deletions.
69 changes: 42 additions & 27 deletions custom_components/alarmo/alarm_control_panel.py
Original file line number Diff line number Diff line change
@@ -424,7 +424,7 @@ def async_handle_arm_request(self, arm_mode, **kwargs):
_LOGGER.warning("Wrong code provided.")
if self.open_sensors:
self.open_sensors = None
self.async_write_ha_state()
self.schedule_update_ha_state()
return False
elif info and info[const.ATTR_IS_OVERRIDE_CODE]:
bypass_open_sensors = True
@@ -547,7 +547,7 @@ def async_update_config(area_id: str = None):
coordinator = self.hass.data[const.DOMAIN]["coordinator"]
self._config = coordinator.store.async_get_config()
self._config.update(coordinator.store.async_get_area(self.area_id))
self.async_write_ha_state()
self.schedule_update_ha_state()

self.async_on_remove(
async_dispatcher_connect(self.hass, "alarmo_config_updated", async_update_config)
@@ -583,8 +583,9 @@ def async_update_state(self, state: str = None):

_LOGGER.debug("entity {} was updated from {} to {}".format(self.entity_id, old_state, state))

if self._timer:
self._timer()
if state in const.ARM_MODES + [STATE_ALARM_DISARMED]:
# cancel a running timer that possibly running when transitioning from states arming, pending, triggered
self.async_clear_timer()

if self.state not in [STATE_ALARM_ARMING, STATE_ALARM_PENDING]:
self.delay = None
@@ -597,7 +598,7 @@ def async_update_state(self, state: str = None):

dispatcher_send(self.hass, "alarmo_state_updated", self.area_id, old_state, state)

self.async_write_ha_state()
self.schedule_update_ha_state()

def async_arm_failure(self, open_sensors: dict, context_id=None):
"""handle arm failure."""
@@ -611,7 +612,7 @@ def async_arm_failure(self, open_sensors: dict, context_id=None):
if self._revert_state in const.ARM_MODES:
self._arm_mode = self._revert_state

self.async_write_ha_state()
self.schedule_update_ha_state()

dispatcher_send(
self.hass,
@@ -692,6 +693,21 @@ def async_arm(self, arm_mode, **kwargs):
else:
# proceed the arm
_LOGGER.info("Alarm is now arming. Waiting for {} seconds.".format(exit_delay))

@callback
def async_leave_timer_finished(now):
"""Update state at a scheduled point in time."""
_LOGGER.debug("async_leave_timer_finished")
self.async_clear_timer()
self.async_arm(
self.arm_mode,
bypass_open_sensors=bypass_open_sensors,
skip_delay=True
)
self.async_set_timer(exit_delay, async_leave_timer_finished)
self.delay = exit_delay
self.open_sensors = None

dispatcher_send(
self.hass,
"alarmo_event",
@@ -703,21 +719,8 @@ def async_arm(self, arm_mode, **kwargs):
const.ATTR_CONTEXT_ID: context_id
}
)
self.delay = exit_delay
self.open_sensors = None
self.async_update_state(STATE_ALARM_ARMING)

@callback
def async_leave_timer_finished(now):
"""Update state at a scheduled point in time."""
_LOGGER.debug("async_leave_timer_finished")
self.async_arm(
self.arm_mode,
bypass_open_sensors=bypass_open_sensors,
skip_delay=True
)

self.async_set_timer(exit_delay, async_leave_timer_finished)
return True

@callback
@@ -751,16 +754,17 @@ def async_trigger(self, skip_delay: bool = False, open_sensors: dict = None):

if not entry_delay:
# countdown finished or immediate trigger event
self.async_update_state(STATE_ALARM_TRIGGERED)

if trigger_time:
# there is a max. trigger time configured

@callback
def async_trigger_timer_finished(now):
"""Update state at a scheduled point in time."""

_LOGGER.debug("async_trigger_timer_finished")
self._changed_by = None
self.async_clear_timer()
if self._config[const.ATTR_DISARM_AFTER_TRIGGER] or not self.arm_mode:
self.bypassed_sensors = None
self.async_update_state(STATE_ALARM_DISARMED)
@@ -777,26 +781,37 @@ def async_trigger_timer_finished(now):
)

self.async_set_timer(trigger_time, async_trigger_timer_finished)
else:
# clear previous timer when transitioning from pending state
self.async_clear_timer()

_LOGGER.info("Alarm is triggered!")
self.async_update_state(STATE_ALARM_TRIGGERED)

else: # to pending state
self.delay = entry_delay

self.async_update_state(STATE_ALARM_PENDING)

@callback
def async_entry_timer_finished(now):
"""Update state at a scheduled point in time."""
self.async_clear_timer()

_LOGGER.debug("async_entry_timer_finished")
self.async_trigger()

self.async_set_timer(entry_delay, async_entry_timer_finished)
self.delay = entry_delay
_LOGGER.info("Alarm will be triggered after {} seconds.".format(entry_delay))

def async_set_timer(self, delay, cb_func):
self.async_update_state(STATE_ALARM_PENDING)

def async_clear_timer(self):
"""clear a running timer."""
if self._timer:
self._timer()
self._timer = None

def async_set_timer(self, delay, cb_func):
self.async_clear_timer()
now = dt_util.utcnow()

if not isinstance(delay, datetime.timedelta):
@@ -852,7 +867,7 @@ def async_update_config(area_id=None):
self._config = coordinator.store.async_get_config()

self.async_update_state()
self.async_write_ha_state()
self.schedule_update_ha_state()

self.async_on_remove(
async_dispatcher_connect(self.hass, "alarmo_config_updated", async_update_config)
@@ -998,7 +1013,7 @@ def async_update_state(self, state: str = None):

self.update_ready_to_arm_modes()

self.async_write_ha_state()
self.schedule_update_ha_state()

@callback
def async_alarm_disarm(self, **kwargs):
@@ -1080,7 +1095,7 @@ def async_arm_failure(self, open_sensors: dict, context_id=None):
const.ATTR_CONTEXT_ID: context_id
}
)
self.async_write_ha_state()
self.schedule_update_ha_state()

@callback
def async_trigger(self, skip_delay: bool = False, _open_sensors: dict = None):

0 comments on commit dd1adc7

Please sign in to comment.