Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Alarm Control Panel #777

Merged
merged 11 commits into from
Feb 22, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 8 additions & 181 deletions custom_components/tahoma/alarm_control_panel.py
Original file line number Diff line number Diff line change
@@ -1,201 +1,28 @@
"""Support for Overkiz alarm control panels."""
"""Support for Overkiz Alarms."""
from __future__ import annotations

from homeassistant.components.alarm_control_panel import AlarmControlPanelEntity
from homeassistant.components.alarm_control_panel.const import (
SUPPORT_ALARM_ARM_AWAY,
SUPPORT_ALARM_ARM_CUSTOM_BYPASS,
SUPPORT_ALARM_ARM_HOME,
SUPPORT_ALARM_ARM_NIGHT,
SUPPORT_ALARM_TRIGGER,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
Platform,
)
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from . import HomeAssistantOverkizData
from .alarm_entities import WIDGET_TO_ALARM_ENTITY
from .const import DOMAIN
from .entity import OverkizEntity

COMMAND_ALARM_OFF = "alarmOff"
COMMAND_ALARM_ON = "alarmOn"
COMMAND_ALARM_PARTIAL_1 = "alarmPartial1"
COMMAND_ALARM_PARTIAL_2 = "alarmPartial2"
COMMAND_ARM = "arm"
COMMAND_ARM_PARTIAL_DAY = "armPartialDay"
COMMAND_ARM_PARTIAL_NIGHT = "armPartialNight"
COMMAND_DISARM = "disarm"
COMMAND_PARTIAL = "partial"
COMMAND_SET_ALARM_STATUS = "setAlarmStatus"

CORE_INTRUSION_STATE = "core:IntrusionState"
INTERNAL_CURRENT_ALARM_MODE_STATE = "internal:CurrentAlarmModeState"
INTERNAL_TARGET_ALARM_MODE_STATE = "internal:TargetAlarmModeState"
INTERNAL_INTRUSION_DETECTED_STATE = "internal:IntrusionDetectedState"
MYFOX_ALARM_STATUS_STATE = "myfox:AlarmStatusState"
VERISURE_ALARM_PANEL_MAIN_ARM_TYPE_STATE = "verisure:AlarmPanelMainArmTypeState"

STATE_ARMED = "armed"
STATE_ARMED_DAY = "armedDay"
STATE_ARMED_NIGHT = "armedNight"
STATE_DETECTED = "detected"
STATE_DISARMED = "disarmed"
STATE_OFF = "off"
STATE_PARTIAL = "partial"
STATE_ZONE_1 = "zone1"
STATE_ZONE_2 = "zone2"
STATE_PENDING = "pending"
STATE_TOTAL = "total"
STATE_UNDETECTED = "undetected"

MAP_MYFOX_STATUS_STATE = {
STATE_ARMED: STATE_ALARM_ARMED_AWAY,
STATE_DISARMED: STATE_ALARM_DISARMED,
STATE_PARTIAL: STATE_ALARM_ARMED_NIGHT,
}

MAP_INTERNAL_STATUS_STATE = {
STATE_OFF: STATE_ALARM_DISARMED,
STATE_ZONE_1: STATE_ALARM_ARMED_HOME,
STATE_ZONE_2: STATE_ALARM_ARMED_NIGHT,
STATE_TOTAL: STATE_ALARM_ARMED_AWAY,
}

MAP_VERISURE_STATUS_STATE = {
STATE_ARMED: STATE_ALARM_ARMED_AWAY,
STATE_DISARMED: STATE_ALARM_DISARMED,
STATE_ARMED_DAY: STATE_ALARM_ARMED_HOME,
STATE_ARMED_NIGHT: STATE_ALARM_ARMED_NIGHT,
}


async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
):
"""Set up the Overkiz alarm control panels from a config entry."""
) -> None:
"""Set up the Overkiz alarm control panel from a config entry."""
data: HomeAssistantOverkizData = hass.data[DOMAIN][entry.entry_id]

entities = [
OverkizAlarmControlPanel(device.device_url, data.coordinator)
WIDGET_TO_ALARM_ENTITY[device.widget](device.device_url, data.coordinator)
for device in data.platforms[Platform.ALARM_CONTROL_PANEL]
if device.widget in WIDGET_TO_ALARM_ENTITY
]
async_add_entities(entities)


class OverkizAlarmControlPanel(OverkizEntity, AlarmControlPanelEntity):
"""Representation of a Overkiz Alarm Control Panel."""

@property
def state(self):
"""Return the state of the device."""
if self.executor.has_state(
CORE_INTRUSION_STATE, INTERNAL_INTRUSION_DETECTED_STATE
):
state = self.executor.select_state(
CORE_INTRUSION_STATE, INTERNAL_INTRUSION_DETECTED_STATE
)
if state == STATE_DETECTED:
return STATE_ALARM_TRIGGERED
elif state == STATE_PENDING:
return STATE_ALARM_PENDING

if (
self.executor.has_state(INTERNAL_CURRENT_ALARM_MODE_STATE)
and self.executor.has_state(INTERNAL_TARGET_ALARM_MODE_STATE)
and self.executor.select_state(INTERNAL_CURRENT_ALARM_MODE_STATE)
!= self.executor.select_state(INTERNAL_TARGET_ALARM_MODE_STATE)
):
return STATE_ALARM_PENDING

if self.executor.has_state(MYFOX_ALARM_STATUS_STATE):
return MAP_MYFOX_STATUS_STATE[
self.executor.select_state(MYFOX_ALARM_STATUS_STATE)
]

if self.executor.has_state(INTERNAL_CURRENT_ALARM_MODE_STATE):
return MAP_INTERNAL_STATUS_STATE[
self.executor.select_state(INTERNAL_CURRENT_ALARM_MODE_STATE)
]

if self.executor.has_state(VERISURE_ALARM_PANEL_MAIN_ARM_TYPE_STATE):
return MAP_VERISURE_STATUS_STATE[
self.executor.select_state(VERISURE_ALARM_PANEL_MAIN_ARM_TYPE_STATE)
]

return None

@property
def supported_features(self) -> int:
"""Return the list of supported features."""
supported_features = 0

if self.executor.has_command(COMMAND_ARM, COMMAND_ALARM_ON):
supported_features |= SUPPORT_ALARM_ARM_AWAY

if self.executor.has_command(COMMAND_ALARM_PARTIAL_1, COMMAND_ARM_PARTIAL_DAY):
supported_features |= SUPPORT_ALARM_ARM_HOME

if self.executor.has_command(
COMMAND_PARTIAL, COMMAND_ALARM_PARTIAL_2, COMMAND_ARM_PARTIAL_NIGHT
):
supported_features |= SUPPORT_ALARM_ARM_NIGHT

if self.executor.has_command(COMMAND_SET_ALARM_STATUS):
supported_features |= SUPPORT_ALARM_TRIGGER
supported_features |= SUPPORT_ALARM_ARM_CUSTOM_BYPASS

return supported_features

async def async_alarm_disarm(self, code=None):
"""Send disarm command."""
await self.executor.async_execute_command(
self.executor.select_command(COMMAND_DISARM, COMMAND_ALARM_OFF)
)

async def async_alarm_arm_home(self, code=None):
"""Send arm home command."""
await self.executor.async_execute_command(
COMMAND_ALARM_PARTIAL_1, COMMAND_ARM_PARTIAL_DAY
)

async def async_alarm_arm_night(self, code=None):
"""Send arm night command."""
await self.executor.async_execute_command(
self.executor.select_command(
COMMAND_PARTIAL, COMMAND_ALARM_PARTIAL_2, COMMAND_ARM_PARTIAL_NIGHT
)
)

async def async_alarm_arm_away(self, code=None):
"""Send arm away command."""
await self.executor.async_execute_command(
self.executor.select_command(COMMAND_ARM, COMMAND_ALARM_ON)
)

async def async_alarm_trigger(self, code=None) -> None:
"""Send alarm trigger command."""
await self.executor.async_execute_command(
self.executor.select_command(COMMAND_SET_ALARM_STATUS, STATE_DETECTED)
)

async def async_alarm_arm_custom_bypass(self, code=None) -> None:
"""Send arm custom bypass command."""
await self.executor.async_execute_command(
self.executor.select_command(COMMAND_SET_ALARM_STATUS, STATE_UNDETECTED)
)

@property
def entity_registry_enabled_default(self) -> bool:
"""Return if the entity should be enabled when first added to the entity registry."""
return self.device.widget != "TSKAlarmController"
async_add_entities(entities)
14 changes: 14 additions & 0 deletions custom_components/tahoma/alarm_entities/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""Alarm Control Panel entities."""
from pyoverkiz.enums.ui import UIWidget

from .alarm_panel_controller import AlarmPanelController
from .my_fox_alarm_controller import MyFoxAlarmController
from .stateful_alarm_controller import StatefulAlarmController
from .tsk_alarm_controller import TSKAlarmController

WIDGET_TO_ALARM_ENTITY = {
UIWidget.TSKALARM_CONTROLLER: TSKAlarmController,
UIWidget.STATEFUL_ALARM_CONTROLLER: StatefulAlarmController,
UIWidget.ALARM_PANEL_CONTROLLER: AlarmPanelController,
UIWidget.MY_FOX_ALARM_CONTROLLER: MyFoxAlarmController,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""Support for Overkiz AlarmPanelController."""
from __future__ import annotations

from pyoverkiz.enums import OverkizCommand, OverkizCommandParam, OverkizState

from homeassistant.components.alarm_control_panel import AlarmControlPanelEntity
from homeassistant.components.alarm_control_panel.const import (
SUPPORT_ALARM_ARM_AWAY,
SUPPORT_ALARM_ARM_HOME,
SUPPORT_ALARM_ARM_NIGHT,
)
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED,
)

from ..entity import OverkizEntity


class AlarmPanelController(OverkizEntity, AlarmControlPanelEntity):
"""Representation of a Overkiz Alarm Control Panel."""

_attr_supported_features = (
SUPPORT_ALARM_ARM_AWAY | SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_NIGHT
)

@property
def state(self):
"""Return the state of the device."""
MAP_ARM_TYPE = {
OverkizCommandParam.DISARMED: STATE_ALARM_DISARMED,
OverkizCommandParam.ARMED_DAY: STATE_ALARM_ARMED_HOME,
OverkizCommandParam.ARMED_NIGHT: STATE_ALARM_ARMED_NIGHT,
OverkizCommandParam.ARMED: STATE_ALARM_ARMED_AWAY,
}

return MAP_ARM_TYPE[
self.executor.select_state(OverkizState.VERISURE_ALARM_PANEL_MAIN_ARM_TYPE)
]

async def async_alarm_disarm(self, code=None):
"""Send disarm command."""
await self.executor.async_execute_command(OverkizCommand.DISARM)

async def async_alarm_arm_home(self, code=None):
"""Send arm home command."""
await self.executor.async_execute_command(OverkizCommand.ARM_PARTIAL_DAY)

async def async_alarm_arm_night(self, code=None):
"""Send arm night command."""
await self.executor.async_execute_command(OverkizCommand.ARM_PARTIAL_NIGHT)

async def async_alarm_arm_away(self, code=None):
"""Send arm away command."""
await self.executor.async_execute_command(OverkizCommand.ARM)
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""Support for Overkiz MyFoxAlarmController."""
from __future__ import annotations

from pyoverkiz.enums import OverkizCommand, OverkizCommandParam, OverkizState

from homeassistant.components.alarm_control_panel import AlarmControlPanelEntity
from homeassistant.components.alarm_control_panel.const import (
SUPPORT_ALARM_ARM_AWAY,
SUPPORT_ALARM_ARM_NIGHT,
)
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)

from ..entity import OverkizEntity


class MyFoxAlarmController(OverkizEntity, AlarmControlPanelEntity):
"""Representation of a Overkiz Alarm Control Panel."""

_attr_supported_features = SUPPORT_ALARM_ARM_AWAY | SUPPORT_ALARM_ARM_NIGHT

@property
def state(self):
"""Return the state of the device."""
if (
self.executor.select_state(OverkizState.CORE_INTRUSION)
== OverkizCommandParam.DETECTED
):
return STATE_ALARM_TRIGGERED

MAP_MYFOX_STATUS_STATE = {
OverkizCommandParam.ARMED: STATE_ALARM_ARMED_AWAY,
OverkizCommandParam.DISARMED: STATE_ALARM_DISARMED,
OverkizCommandParam.PARTIAL: STATE_ALARM_ARMED_NIGHT,
}

return MAP_MYFOX_STATUS_STATE[
self.executor.select_state(OverkizState.MYFOX_ALARM_STATUS)
]

async def async_alarm_disarm(self, code=None):
"""Send disarm command."""
await self.executor.async_execute_command(OverkizCommand.DISARM)

async def async_alarm_arm_night(self, code=None):
"""Send arm night command."""
await self.executor.async_execute_command(OverkizCommand.PARTIAL)

async def async_alarm_arm_away(self, code=None):
"""Send arm away command."""
await self.executor.async_execute_command(OverkizCommand.ARM)
Loading