Files
rikku-home-assistant/custom_components/localtuya/alarm_control_panel.py
T
2025-04-21 21:03:30 -04:00

132 lines
4.1 KiB
Python

"""Platform to present any Tuya DP as a Alarm."""
from enum import StrEnum
import logging
from functools import partial
from .config_flow import col_to_select
import voluptuous as vol
from homeassistant.helpers.selector import ObjectSelector
from homeassistant.components.alarm_control_panel import (
DOMAIN,
AlarmControlPanelEntity,
CodeFormat,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from .entity import LocalTuyaEntity, async_setup_entry
from .const import CONF_ALARM_SUPPORTED_STATES, DictSelector
_LOGGER = logging.getLogger(__name__)
DEFAULT_PRECISION = 2
class TuyaMode(StrEnum):
DISARMED = "disarmed"
ARM = "arm"
HOME = "home"
SOS = "sos"
DEFAULT_SUPPORTED_MODES = {
AlarmControlPanelState.DISARMED: TuyaMode.DISARMED,
AlarmControlPanelState.ARMED_AWAY: TuyaMode.ARM,
AlarmControlPanelState.ARMED_HOME: TuyaMode.HOME,
AlarmControlPanelState.TRIGGERED: TuyaMode.SOS,
}
def flow_schema(dps):
"""Return schema used in config flow."""
return {
vol.Optional(
CONF_ALARM_SUPPORTED_STATES, default=DEFAULT_SUPPORTED_MODES
): ObjectSelector(),
}
class LocalTuyaAlarmControlPanel(LocalTuyaEntity, AlarmControlPanelEntity):
"""Representation of a Tuya Alarm."""
_supported_modes = {}
def __init__(
self,
device,
config_entry,
dpid,
**kwargs,
):
"""Initialize the Tuya Alarm."""
super().__init__(device, config_entry, dpid, _LOGGER, **kwargs)
self._state = None
self._changed_by = None
# supported modes
if supported_modes := self._config.get(CONF_ALARM_SUPPORTED_STATES, {}):
# Key is HA state and value is Tuya State.
if AlarmControlPanelState.ARMED_AWAY in supported_modes:
self._attr_supported_features |= AlarmControlPanelEntityFeature.ARM_HOME
if AlarmControlPanelState.ARMED_HOME in supported_modes:
self._attr_supported_features |= AlarmControlPanelEntityFeature.ARM_AWAY
if AlarmControlPanelState.TRIGGERED in supported_modes:
self._attr_supported_features |= AlarmControlPanelEntityFeature.TRIGGER
self._states = DictSelector(supported_modes, reverse=True)
@property
def state(self):
"""Return Alarm state."""
return self._states.to_ha(self._state, None)
@property
def code_format(self) -> CodeFormat | None:
"""Code format or None if no code is required."""
return None # self._attr_code_format
@property
def changed_by(self) -> str | None:
"""Last change triggered by."""
return None # self._attr_changed_by
@property
def code_arm_required(self) -> bool:
"""Whether the code is required for arm actions."""
return True # self._attr_code_arm_required
async def async_alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
state = self._states.to_tuya(AlarmControlPanelState.DISARMED)
await self._device.set_dp(state, self._dp_id)
async def async_alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command."""
state = self._states.to_tuya(AlarmControlPanelState.ARMED_HOME)
await self._device.set_dp(state, self._dp_id)
async def async_alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command."""
state = self._states.to_tuya(AlarmControlPanelState.ARMED_AWAY)
await self._device.set_dp(state, self._dp_id)
async def async_alarm_trigger(self, code: str | None = None) -> None:
"""Send alarm trigger command."""
state = self._states.to_tuya(AlarmControlPanelState.TRIGGERED)
await self._device.set_dp(state, self._dp_id)
def status_updated(self):
"""Device status was updated."""
super().status_updated()
# No need to restore state for a AlarmControlPanel
async def restore_state_when_connected(self):
"""Do nothing for a AlarmControlPanel."""
return
async_setup_entry = partial(
async_setup_entry, DOMAIN, LocalTuyaAlarmControlPanel, flow_schema
)