mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Make manual and manual_mqtt fully asynchronous (#83436)
* manual: make it completely async Restoring the timers on startup cannot use track_point_in_time, because the restoring code runs from the async_added_to_hass method. Rewrite everything to run in the event loop instead of using threaded wrappers, this way the code can be reused in async_added_to_hass. * manual_mqtt: replace async function with @callback * manual_mqtt: make it completely async Restoring the timers on startup cannot use track_point_in_time, because the restoring code runs from the async_added_to_hass method. Rewrite everything to run in the event loop instead of using threaded wrappers, this way the code can be reused in async_added_to_hass when state restore is added. Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
This commit is contained in:
parent
5c272583e7
commit
02fa5656bb
@ -32,7 +32,7 @@ from homeassistant.const import (
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.event import track_point_in_time
|
||||
from homeassistant.helpers.event import async_track_point_in_time
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
import homeassistant.util.dt as dt_util
|
||||
@ -284,61 +284,61 @@ class ManualAlarm(alarm.AlarmControlPanelEntity, RestoreEntity):
|
||||
return alarm.CodeFormat.NUMBER
|
||||
return alarm.CodeFormat.TEXT
|
||||
|
||||
def alarm_disarm(self, code: str | None = None) -> None:
|
||||
async def async_alarm_disarm(self, code: str | None = None) -> None:
|
||||
"""Send disarm command."""
|
||||
if not self._validate_code(code, STATE_ALARM_DISARMED):
|
||||
if not self._async_validate_code(code, STATE_ALARM_DISARMED):
|
||||
return
|
||||
|
||||
self._state = STATE_ALARM_DISARMED
|
||||
self._state_ts = dt_util.utcnow()
|
||||
self.schedule_update_ha_state()
|
||||
self.async_schedule_update_ha_state()
|
||||
|
||||
def alarm_arm_home(self, code: str | None = None) -> None:
|
||||
async def async_alarm_arm_home(self, code: str | None = None) -> None:
|
||||
"""Send arm home command."""
|
||||
if self.code_arm_required and not self._validate_code(
|
||||
if self.code_arm_required and not self._async_validate_code(
|
||||
code, STATE_ALARM_ARMED_HOME
|
||||
):
|
||||
return
|
||||
|
||||
self._update_state(STATE_ALARM_ARMED_HOME)
|
||||
self._async_update_state(STATE_ALARM_ARMED_HOME)
|
||||
|
||||
def alarm_arm_away(self, code: str | None = None) -> None:
|
||||
async def async_alarm_arm_away(self, code: str | None = None) -> None:
|
||||
"""Send arm away command."""
|
||||
if self.code_arm_required and not self._validate_code(
|
||||
if self.code_arm_required and not self._async_validate_code(
|
||||
code, STATE_ALARM_ARMED_AWAY
|
||||
):
|
||||
return
|
||||
|
||||
self._update_state(STATE_ALARM_ARMED_AWAY)
|
||||
self._async_update_state(STATE_ALARM_ARMED_AWAY)
|
||||
|
||||
def alarm_arm_night(self, code: str | None = None) -> None:
|
||||
async def async_alarm_arm_night(self, code: str | None = None) -> None:
|
||||
"""Send arm night command."""
|
||||
if self.code_arm_required and not self._validate_code(
|
||||
if self.code_arm_required and not self._async_validate_code(
|
||||
code, STATE_ALARM_ARMED_NIGHT
|
||||
):
|
||||
return
|
||||
|
||||
self._update_state(STATE_ALARM_ARMED_NIGHT)
|
||||
self._async_update_state(STATE_ALARM_ARMED_NIGHT)
|
||||
|
||||
def alarm_arm_vacation(self, code: str | None = None) -> None:
|
||||
async def async_alarm_arm_vacation(self, code: str | None = None) -> None:
|
||||
"""Send arm vacation command."""
|
||||
if self.code_arm_required and not self._validate_code(
|
||||
if self.code_arm_required and not self._async_validate_code(
|
||||
code, STATE_ALARM_ARMED_VACATION
|
||||
):
|
||||
return
|
||||
|
||||
self._update_state(STATE_ALARM_ARMED_VACATION)
|
||||
self._async_update_state(STATE_ALARM_ARMED_VACATION)
|
||||
|
||||
def alarm_arm_custom_bypass(self, code: str | None = None) -> None:
|
||||
async def async_alarm_arm_custom_bypass(self, code: str | None = None) -> None:
|
||||
"""Send arm custom bypass command."""
|
||||
if self.code_arm_required and not self._validate_code(
|
||||
if self.code_arm_required and not self._async_validate_code(
|
||||
code, STATE_ALARM_ARMED_CUSTOM_BYPASS
|
||||
):
|
||||
return
|
||||
|
||||
self._update_state(STATE_ALARM_ARMED_CUSTOM_BYPASS)
|
||||
self._async_update_state(STATE_ALARM_ARMED_CUSTOM_BYPASS)
|
||||
|
||||
def alarm_trigger(self, code: str | None = None) -> None:
|
||||
async def async_alarm_trigger(self, code: str | None = None) -> None:
|
||||
"""
|
||||
Send alarm trigger command.
|
||||
|
||||
@ -347,9 +347,9 @@ class ManualAlarm(alarm.AlarmControlPanelEntity, RestoreEntity):
|
||||
"""
|
||||
if not self._trigger_time_by_state[self._active_state]:
|
||||
return
|
||||
self._update_state(STATE_ALARM_TRIGGERED)
|
||||
self._async_update_state(STATE_ALARM_TRIGGERED)
|
||||
|
||||
def _update_state(self, state: str) -> None:
|
||||
def _async_update_state(self, state: str) -> None:
|
||||
"""Update the state."""
|
||||
if self._state == state:
|
||||
return
|
||||
@ -357,16 +357,16 @@ class ManualAlarm(alarm.AlarmControlPanelEntity, RestoreEntity):
|
||||
self._previous_state = self._state
|
||||
self._state = state
|
||||
self._state_ts = dt_util.utcnow()
|
||||
self.schedule_update_ha_state()
|
||||
self.async_schedule_update_ha_state()
|
||||
|
||||
if state == STATE_ALARM_TRIGGERED:
|
||||
pending_time = self._pending_time(state)
|
||||
track_point_in_time(
|
||||
async_track_point_in_time(
|
||||
self._hass, self.async_scheduled_update, self._state_ts + pending_time
|
||||
)
|
||||
|
||||
trigger_time = self._trigger_time_by_state[self._previous_state]
|
||||
track_point_in_time(
|
||||
async_track_point_in_time(
|
||||
self._hass,
|
||||
self.async_scheduled_update,
|
||||
self._state_ts + pending_time + trigger_time,
|
||||
@ -374,20 +374,20 @@ class ManualAlarm(alarm.AlarmControlPanelEntity, RestoreEntity):
|
||||
elif state in SUPPORTED_ARMING_STATES:
|
||||
arming_time = self._arming_time(state)
|
||||
if arming_time:
|
||||
track_point_in_time(
|
||||
async_track_point_in_time(
|
||||
self._hass,
|
||||
self.async_scheduled_update,
|
||||
self._state_ts + arming_time,
|
||||
)
|
||||
|
||||
def _validate_code(self, code, state):
|
||||
def _async_validate_code(self, code, state):
|
||||
"""Validate given code."""
|
||||
if self._code is None:
|
||||
return True
|
||||
if isinstance(self._code, str):
|
||||
alarm_code = self._code
|
||||
else:
|
||||
alarm_code = self._code.render(
|
||||
alarm_code = self._code.async_render(
|
||||
parse_result=False, from_state=self._state, to_state=state
|
||||
)
|
||||
check = not alarm_code or code == alarm_code
|
||||
|
@ -27,12 +27,12 @@ from homeassistant.const import (
|
||||
STATE_ALARM_PENDING,
|
||||
STATE_ALARM_TRIGGERED,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.event import (
|
||||
async_track_point_in_time,
|
||||
async_track_state_change_event,
|
||||
track_point_in_time,
|
||||
)
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
import homeassistant.util.dt as dt_util
|
||||
@ -314,43 +314,43 @@ class ManualMQTTAlarm(alarm.AlarmControlPanelEntity):
|
||||
return alarm.CodeFormat.NUMBER
|
||||
return alarm.CodeFormat.TEXT
|
||||
|
||||
def alarm_disarm(self, code: str | None = None) -> None:
|
||||
async def async_alarm_disarm(self, code: str | None = None) -> None:
|
||||
"""Send disarm command."""
|
||||
if not self._validate_code(code, STATE_ALARM_DISARMED):
|
||||
if not self._async_validate_code(code, STATE_ALARM_DISARMED):
|
||||
return
|
||||
|
||||
self._state = STATE_ALARM_DISARMED
|
||||
self._state_ts = dt_util.utcnow()
|
||||
self.schedule_update_ha_state()
|
||||
self.async_schedule_update_ha_state()
|
||||
|
||||
def alarm_arm_home(self, code: str | None = None) -> None:
|
||||
async def async_alarm_arm_home(self, code: str | None = None) -> None:
|
||||
"""Send arm home command."""
|
||||
if self.code_arm_required and not self._validate_code(
|
||||
if self.code_arm_required and not self._async_validate_code(
|
||||
code, STATE_ALARM_ARMED_HOME
|
||||
):
|
||||
return
|
||||
|
||||
self._update_state(STATE_ALARM_ARMED_HOME)
|
||||
self._async_update_state(STATE_ALARM_ARMED_HOME)
|
||||
|
||||
def alarm_arm_away(self, code: str | None = None) -> None:
|
||||
async def async_alarm_arm_away(self, code: str | None = None) -> None:
|
||||
"""Send arm away command."""
|
||||
if self.code_arm_required and not self._validate_code(
|
||||
if self.code_arm_required and not self._async_validate_code(
|
||||
code, STATE_ALARM_ARMED_AWAY
|
||||
):
|
||||
return
|
||||
|
||||
self._update_state(STATE_ALARM_ARMED_AWAY)
|
||||
self._async_update_state(STATE_ALARM_ARMED_AWAY)
|
||||
|
||||
def alarm_arm_night(self, code: str | None = None) -> None:
|
||||
async def async_alarm_arm_night(self, code: str | None = None) -> None:
|
||||
"""Send arm night command."""
|
||||
if self.code_arm_required and not self._validate_code(
|
||||
if self.code_arm_required and not self._async_validate_code(
|
||||
code, STATE_ALARM_ARMED_NIGHT
|
||||
):
|
||||
return
|
||||
|
||||
self._update_state(STATE_ALARM_ARMED_NIGHT)
|
||||
self._async_update_state(STATE_ALARM_ARMED_NIGHT)
|
||||
|
||||
def alarm_trigger(self, code: str | None = None) -> None:
|
||||
async def async_alarm_trigger(self, code: str | None = None) -> None:
|
||||
"""
|
||||
Send alarm trigger command.
|
||||
|
||||
@ -359,9 +359,9 @@ class ManualMQTTAlarm(alarm.AlarmControlPanelEntity):
|
||||
"""
|
||||
if not self._trigger_time_by_state[self._active_state]:
|
||||
return
|
||||
self._update_state(STATE_ALARM_TRIGGERED)
|
||||
self._async_update_state(STATE_ALARM_TRIGGERED)
|
||||
|
||||
def _update_state(self, state):
|
||||
def _async_update_state(self, state: str) -> None:
|
||||
"""Update the state."""
|
||||
if self._state == state:
|
||||
return
|
||||
@ -369,33 +369,33 @@ class ManualMQTTAlarm(alarm.AlarmControlPanelEntity):
|
||||
self._previous_state = self._state
|
||||
self._state = state
|
||||
self._state_ts = dt_util.utcnow()
|
||||
self.schedule_update_ha_state()
|
||||
self.async_schedule_update_ha_state()
|
||||
|
||||
pending_time = self._pending_time(state)
|
||||
if state == STATE_ALARM_TRIGGERED:
|
||||
track_point_in_time(
|
||||
self._hass, self.async_update_ha_state, self._state_ts + pending_time
|
||||
async_track_point_in_time(
|
||||
self._hass, self.async_scheduled_update, self._state_ts + pending_time
|
||||
)
|
||||
|
||||
trigger_time = self._trigger_time_by_state[self._previous_state]
|
||||
track_point_in_time(
|
||||
async_track_point_in_time(
|
||||
self._hass,
|
||||
self.async_update_ha_state,
|
||||
self.async_scheduled_update,
|
||||
self._state_ts + pending_time + trigger_time,
|
||||
)
|
||||
elif state in SUPPORTED_PENDING_STATES and pending_time:
|
||||
track_point_in_time(
|
||||
self._hass, self.async_update_ha_state, self._state_ts + pending_time
|
||||
async_track_point_in_time(
|
||||
self._hass, self.async_scheduled_update, self._state_ts + pending_time
|
||||
)
|
||||
|
||||
def _validate_code(self, code, state):
|
||||
def _async_validate_code(self, code, state):
|
||||
"""Validate given code."""
|
||||
if self._code is None:
|
||||
return True
|
||||
if isinstance(self._code, str):
|
||||
alarm_code = self._code
|
||||
else:
|
||||
alarm_code = self._code.render(
|
||||
alarm_code = self._code.async_render(
|
||||
from_state=self._state, to_state=state, parse_result=False
|
||||
)
|
||||
check = not alarm_code or code == alarm_code
|
||||
@ -413,6 +413,11 @@ class ManualMQTTAlarm(alarm.AlarmControlPanelEntity):
|
||||
ATTR_POST_PENDING_STATE: self._state,
|
||||
}
|
||||
|
||||
@callback
|
||||
def async_scheduled_update(self, now):
|
||||
"""Update state at a scheduled point in time."""
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Subscribe to MQTT events."""
|
||||
async_track_state_change_event(
|
||||
|
Loading…
x
Reference in New Issue
Block a user