Implement new state property for alarm_control_panel which is using an enum (#126283)

* Alarm state from enum

* Fixes

* Set final

* Fix rebase

* Test const

* Fix breaking version

* Fix other for alarm_control_panel

* Fix integrations

* More

* More

* More

* More

* Fix zha

* Replace _attr_state

* Fix alarm_control_panel

* Fix tests

* Fixes

* Mods

* Change some

* More

* More

* More

* Tests

* Last tests

* Return enum

* Fix zha

* Remove not needed check

* Fix wording

* Fix homekit

* Mod prometheus

* Fix mypy

* Fix homekit

* Fix ifttt
pull/128945/head
G Johansson 2024-10-21 22:54:27 +02:00 committed by GitHub
parent 59ad69b637
commit cdfec7ebb4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
90 changed files with 2010 additions and 1810 deletions

View File

@ -7,13 +7,9 @@ from jaraco.abode.devices.alarm import Alarm
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -44,14 +40,14 @@ class AbodeAlarm(AbodeDevice, AlarmControlPanelEntity):
_device: Alarm
@property
def state(self) -> str | None:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the device."""
if self._device.is_standby:
return STATE_ALARM_DISARMED
return AlarmControlPanelState.DISARMED
if self._device.is_away:
return STATE_ALARM_ARMED_AWAY
return AlarmControlPanelState.ARMED_AWAY
if self._device.is_home:
return STATE_ALARM_ARMED_HOME
return AlarmControlPanelState.ARMED_HOME
return None
def alarm_disarm(self, code: str | None = None) -> None:

View File

@ -5,12 +5,7 @@ from __future__ import annotations
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
)
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED,
AlarmControlPanelState,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
@ -65,37 +60,37 @@ class AgentBaseStation(AlarmControlPanelEntity):
self._attr_available = self._client.is_available
armed = self._client.is_armed
if armed is None:
self._attr_state = None
self._attr_alarm_state = None
return
if armed:
prof = (await self._client.get_active_profile()).lower()
self._attr_state = STATE_ALARM_ARMED_AWAY
self._attr_alarm_state = AlarmControlPanelState.ARMED_AWAY
if prof == CONF_HOME_MODE_NAME:
self._attr_state = STATE_ALARM_ARMED_HOME
self._attr_alarm_state = AlarmControlPanelState.ARMED_HOME
elif prof == CONF_NIGHT_MODE_NAME:
self._attr_state = STATE_ALARM_ARMED_NIGHT
self._attr_alarm_state = AlarmControlPanelState.ARMED_NIGHT
else:
self._attr_state = STATE_ALARM_DISARMED
self._attr_alarm_state = AlarmControlPanelState.DISARMED
async def async_alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
await self._client.disarm()
self._attr_state = STATE_ALARM_DISARMED
self._attr_alarm_state = AlarmControlPanelState.DISARMED
async def async_alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command. Uses custom mode."""
await self._client.arm()
await self._client.set_active_profile(CONF_AWAY_MODE_NAME)
self._attr_state = STATE_ALARM_ARMED_AWAY
self._attr_alarm_state = AlarmControlPanelState.ARMED_AWAY
async def async_alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command. Uses custom mode."""
await self._client.arm()
await self._client.set_active_profile(CONF_HOME_MODE_NAME)
self._attr_state = STATE_ALARM_ARMED_HOME
self._attr_alarm_state = AlarmControlPanelState.ARMED_HOME
async def async_alarm_arm_night(self, code: str | None = None) -> None:
"""Send arm night command. Uses custom mode."""
await self._client.arm()
await self._client.set_active_profile(CONF_NIGHT_MODE_NAME)
self._attr_state = STATE_ALARM_ARMED_NIGHT
self._attr_alarm_state = AlarmControlPanelState.ARMED_NIGHT

View File

@ -2,6 +2,7 @@
from __future__ import annotations
import asyncio
from datetime import timedelta
from functools import partial
import logging
@ -33,6 +34,7 @@ from homeassistant.helpers.deprecation import (
)
from homeassistant.helpers.entity import Entity, EntityDescription
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.entity_platform import EntityPlatform
from homeassistant.helpers.typing import ConfigType
from homeassistant.util.hass_dict import HassKey
@ -49,6 +51,7 @@ from .const import ( # noqa: F401
ATTR_CODE_ARM_REQUIRED,
DOMAIN,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
@ -142,6 +145,7 @@ CACHED_PROPERTIES_WITH_ATTR_ = {
"changed_by",
"code_arm_required",
"supported_features",
"alarm_state",
}
@ -149,6 +153,7 @@ class AlarmControlPanelEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_A
"""An abstract class for alarm control entities."""
entity_description: AlarmControlPanelEntityDescription
_attr_alarm_state: AlarmControlPanelState | None = None
_attr_changed_by: str | None = None
_attr_code_arm_required: bool = True
_attr_code_format: CodeFormat | None = None
@ -157,6 +162,78 @@ class AlarmControlPanelEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_A
)
_alarm_control_panel_option_default_code: str | None = None
__alarm_legacy_state: bool = False
__alarm_legacy_state_reported: bool = False
def __init_subclass__(cls, **kwargs: Any) -> None:
"""Post initialisation processing."""
super().__init_subclass__(**kwargs)
if any(method in cls.__dict__ for method in ("_attr_state", "state")):
# Integrations should use the 'alarm_state' property instead of
# setting the state directly.
cls.__alarm_legacy_state = True
def __setattr__(self, __name: str, __value: Any) -> None:
"""Set attribute.
Deprecation warning if setting '_attr_state' directly
unless already reported.
"""
if __name == "_attr_state":
if self.__alarm_legacy_state_reported is not True:
self._report_deprecated_alarm_state_handling()
self.__alarm_legacy_state_reported = True
return super().__setattr__(__name, __value)
@callback
def add_to_platform_start(
self,
hass: HomeAssistant,
platform: EntityPlatform,
parallel_updates: asyncio.Semaphore | None,
) -> None:
"""Start adding an entity to a platform."""
super().add_to_platform_start(hass, platform, parallel_updates)
if self.__alarm_legacy_state and not self.__alarm_legacy_state_reported:
self._report_deprecated_alarm_state_handling()
@callback
def _report_deprecated_alarm_state_handling(self) -> None:
"""Report on deprecated handling of alarm state.
Integrations should implement alarm_state instead of using state directly.
"""
self.__alarm_legacy_state_reported = True
if "custom_components" in type(self).__module__:
# Do not report on core integrations as they have been fixed.
report_issue = "report it to the custom integration author."
_LOGGER.warning(
"Entity %s (%s) is setting state directly"
" which will stop working in HA Core 2025.11."
" Entities should implement the 'alarm_state' property and"
" return its state using the AlarmControlPanelState enum, please %s",
self.entity_id,
type(self),
report_issue,
)
@final
@property
def state(self) -> str | None:
"""Return the current state."""
if (alarm_state := self.alarm_state) is None:
return None
return alarm_state
@cached_property
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the current alarm control panel entity state.
Integrations should overwrite this or use the '_attr_alarm_state'
attribute to set the alarm status using the 'AlarmControlPanelState' enum.
"""
return self._attr_alarm_state
@final
@callback
def code_or_default_code(self, code: str | None) -> str | None:

View File

@ -17,6 +17,21 @@ ATTR_CHANGED_BY: Final = "changed_by"
ATTR_CODE_ARM_REQUIRED: Final = "code_arm_required"
class AlarmControlPanelState(StrEnum):
"""Alarm control panel entity states."""
DISARMED = "disarmed"
ARMED_HOME = "armed_home"
ARMED_AWAY = "armed_away"
ARMED_NIGHT = "armed_night"
ARMED_VACATION = "armed_vacation"
ARMED_CUSTOM_BYPASS = "armed_custom_bypass"
PENDING = "pending"
ARMING = "arming"
DISARMING = "disarming"
TRIGGERED = "triggered"
class CodeFormat(StrEnum):
"""Code formats for the Alarm Control Panel."""

View File

@ -13,13 +13,6 @@ from homeassistant.const import (
CONF_DOMAIN,
CONF_ENTITY_ID,
CONF_TYPE,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import (
@ -31,7 +24,7 @@ from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
from homeassistant.helpers.entity import get_supported_features
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
from . import DOMAIN
from . import DOMAIN, AlarmControlPanelState
from .const import (
CONDITION_ARMED_AWAY,
CONDITION_ARMED_CUSTOM_BYPASS,
@ -109,19 +102,19 @@ def async_condition_from_config(
) -> condition.ConditionCheckerType:
"""Create a function to test a device condition."""
if config[CONF_TYPE] == CONDITION_TRIGGERED:
state = STATE_ALARM_TRIGGERED
state = AlarmControlPanelState.TRIGGERED
elif config[CONF_TYPE] == CONDITION_DISARMED:
state = STATE_ALARM_DISARMED
state = AlarmControlPanelState.DISARMED
elif config[CONF_TYPE] == CONDITION_ARMED_HOME:
state = STATE_ALARM_ARMED_HOME
state = AlarmControlPanelState.ARMED_HOME
elif config[CONF_TYPE] == CONDITION_ARMED_AWAY:
state = STATE_ALARM_ARMED_AWAY
state = AlarmControlPanelState.ARMED_AWAY
elif config[CONF_TYPE] == CONDITION_ARMED_NIGHT:
state = STATE_ALARM_ARMED_NIGHT
state = AlarmControlPanelState.ARMED_NIGHT
elif config[CONF_TYPE] == CONDITION_ARMED_VACATION:
state = STATE_ALARM_ARMED_VACATION
state = AlarmControlPanelState.ARMED_VACATION
elif config[CONF_TYPE] == CONDITION_ARMED_CUSTOM_BYPASS:
state = STATE_ALARM_ARMED_CUSTOM_BYPASS
state = AlarmControlPanelState.ARMED_CUSTOM_BYPASS
registry = er.async_get(hass)
entity_id = er.async_resolve_entity_id(registry, config[ATTR_ENTITY_ID])

View File

@ -15,13 +15,6 @@ from homeassistant.const import (
CONF_FOR,
CONF_PLATFORM,
CONF_TYPE,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
from homeassistant.helpers import config_validation as cv, entity_registry as er
@ -29,7 +22,7 @@ from homeassistant.helpers.entity import get_supported_features
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
from homeassistant.helpers.typing import ConfigType
from . import DOMAIN
from . import DOMAIN, AlarmControlPanelState
from .const import AlarmControlPanelEntityFeature
BASIC_TRIGGER_TYPES: Final[set[str]] = {"triggered", "disarmed", "arming"}
@ -129,19 +122,19 @@ async def async_attach_trigger(
) -> CALLBACK_TYPE:
"""Attach a trigger."""
if config[CONF_TYPE] == "triggered":
to_state = STATE_ALARM_TRIGGERED
to_state = AlarmControlPanelState.TRIGGERED
elif config[CONF_TYPE] == "disarmed":
to_state = STATE_ALARM_DISARMED
to_state = AlarmControlPanelState.DISARMED
elif config[CONF_TYPE] == "arming":
to_state = STATE_ALARM_ARMING
to_state = AlarmControlPanelState.ARMING
elif config[CONF_TYPE] == "armed_home":
to_state = STATE_ALARM_ARMED_HOME
to_state = AlarmControlPanelState.ARMED_HOME
elif config[CONF_TYPE] == "armed_away":
to_state = STATE_ALARM_ARMED_AWAY
to_state = AlarmControlPanelState.ARMED_AWAY
elif config[CONF_TYPE] == "armed_night":
to_state = STATE_ALARM_ARMED_NIGHT
to_state = AlarmControlPanelState.ARMED_NIGHT
elif config[CONF_TYPE] == "armed_vacation":
to_state = STATE_ALARM_ARMED_VACATION
to_state = AlarmControlPanelState.ARMED_VACATION
state_config = {
state_trigger.CONF_PLATFORM: "state",

View File

@ -16,28 +16,21 @@ from homeassistant.const import (
SERVICE_ALARM_ARM_VACATION,
SERVICE_ALARM_DISARM,
SERVICE_ALARM_TRIGGER,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import Context, HomeAssistant, State
from . import DOMAIN
from . import DOMAIN, AlarmControlPanelState
_LOGGER: Final = logging.getLogger(__name__)
VALID_STATES: Final[set[str]] = {
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
AlarmControlPanelState.ARMED_AWAY,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_HOME,
AlarmControlPanelState.ARMED_NIGHT,
AlarmControlPanelState.ARMED_VACATION,
AlarmControlPanelState.DISARMED,
AlarmControlPanelState.TRIGGERED,
}
@ -65,19 +58,19 @@ async def _async_reproduce_state(
service_data = {ATTR_ENTITY_ID: state.entity_id}
if state.state == STATE_ALARM_ARMED_AWAY:
if state.state == AlarmControlPanelState.ARMED_AWAY:
service = SERVICE_ALARM_ARM_AWAY
elif state.state == STATE_ALARM_ARMED_CUSTOM_BYPASS:
elif state.state == AlarmControlPanelState.ARMED_CUSTOM_BYPASS:
service = SERVICE_ALARM_ARM_CUSTOM_BYPASS
elif state.state == STATE_ALARM_ARMED_HOME:
elif state.state == AlarmControlPanelState.ARMED_HOME:
service = SERVICE_ALARM_ARM_HOME
elif state.state == STATE_ALARM_ARMED_NIGHT:
elif state.state == AlarmControlPanelState.ARMED_NIGHT:
service = SERVICE_ALARM_ARM_NIGHT
elif state.state == STATE_ALARM_ARMED_VACATION:
elif state.state == AlarmControlPanelState.ARMED_VACATION:
service = SERVICE_ALARM_ARM_VACATION
elif state.state == STATE_ALARM_DISARMED:
elif state.state == AlarmControlPanelState.DISARMED:
service = SERVICE_ALARM_DISARM
elif state.state == STATE_ALARM_TRIGGERED:
elif state.state == AlarmControlPanelState.TRIGGERED:
service = SERVICE_ALARM_TRIGGER
await hass.services.async_call(

View File

@ -7,16 +7,10 @@ import voluptuous as vol
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.const import (
ATTR_CODE,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.const import ATTR_CODE
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_platform
import homeassistant.helpers.config_validation as cv
@ -106,15 +100,15 @@ class AlarmDecoderAlarmPanel(AlarmDecoderEntity, AlarmControlPanelEntity):
def _message_callback(self, message):
"""Handle received messages."""
if message.alarm_sounding or message.fire_alarm:
self._attr_state = STATE_ALARM_TRIGGERED
self._attr_alarm_state = AlarmControlPanelState.TRIGGERED
elif message.armed_away:
self._attr_state = STATE_ALARM_ARMED_AWAY
self._attr_alarm_state = AlarmControlPanelState.ARMED_AWAY
elif message.armed_home and (message.entry_delay_off or message.perimeter_only):
self._attr_state = STATE_ALARM_ARMED_NIGHT
self._attr_alarm_state = AlarmControlPanelState.ARMED_NIGHT
elif message.armed_home:
self._attr_state = STATE_ALARM_ARMED_HOME
self._attr_alarm_state = AlarmControlPanelState.ARMED_HOME
else:
self._attr_state = STATE_ALARM_DISARMED
self._attr_alarm_state = AlarmControlPanelState.DISARMED
self._attr_extra_state_attributes = {
"ac_power": message.ac_power,

View File

@ -26,6 +26,7 @@ from homeassistant.components import (
)
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.components.climate import HVACMode
@ -36,10 +37,6 @@ from homeassistant.const import (
ATTR_TEMPERATURE,
ATTR_UNIT_OF_MEASUREMENT,
PERCENTAGE,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_IDLE,
STATE_OFF,
STATE_ON,
@ -1317,13 +1314,13 @@ class AlexaSecurityPanelController(AlexaCapability):
raise UnsupportedProperty(name)
arm_state = self.entity.state
if arm_state == STATE_ALARM_ARMED_HOME:
if arm_state == AlarmControlPanelState.ARMED_HOME:
return "ARMED_STAY"
if arm_state == STATE_ALARM_ARMED_AWAY:
if arm_state == AlarmControlPanelState.ARMED_AWAY:
return "ARMED_AWAY"
if arm_state == STATE_ALARM_ARMED_NIGHT:
if arm_state == AlarmControlPanelState.ARMED_NIGHT:
return "ARMED_NIGHT"
if arm_state == STATE_ALARM_ARMED_CUSTOM_BYPASS:
if arm_state == AlarmControlPanelState.ARMED_CUSTOM_BYPASS:
return "ARMED_STAY"
return "DISARMED"

View File

@ -9,6 +9,7 @@ from typing import Any
from homeassistant import core as ha
from homeassistant.components import (
alarm_control_panel,
button,
camera,
climate,
@ -51,7 +52,6 @@ from homeassistant.const import (
SERVICE_VOLUME_MUTE,
SERVICE_VOLUME_SET,
SERVICE_VOLUME_UP,
STATE_ALARM_DISARMED,
UnitOfTemperature,
)
from homeassistant.helpers import network
@ -1083,7 +1083,7 @@ async def async_api_arm(
arm_state = directive.payload["armState"]
data: dict[str, Any] = {ATTR_ENTITY_ID: entity.entity_id}
if entity.state != STATE_ALARM_DISARMED:
if entity.state != alarm_control_panel.AlarmControlPanelState.DISARMED:
msg = "You must disarm the system before you can set the requested arm state."
raise AlexaSecurityPanelAuthorizationRequired(msg)
@ -1133,7 +1133,7 @@ async def async_api_disarm(
# Per Alexa Documentation: If you receive a Disarm directive, and the
# system is already disarmed, respond with a success response,
# not an error response.
if entity.state == STATE_ALARM_DISARMED:
if entity.state == alarm_control_panel.AlarmControlPanelState.DISARMED:
return response
payload = directive.payload

View File

@ -9,13 +9,10 @@ from blinkpy.blinkpy import Blink, BlinkSyncModule
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_ATTRIBUTION,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_DISARMED,
)
from homeassistant.const import ATTR_ATTRIBUTION
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.device_registry import DeviceInfo
@ -80,8 +77,10 @@ class BlinkSyncModuleHA(
self.sync.attributes["associated_cameras"] = list(self.sync.cameras)
self.sync.attributes[ATTR_ATTRIBUTION] = DEFAULT_ATTRIBUTION
self._attr_extra_state_attributes = self.sync.attributes
self._attr_state = (
STATE_ALARM_ARMED_AWAY if self.sync.arm else STATE_ALARM_DISARMED
self._attr_alarm_state = (
AlarmControlPanelState.ARMED_AWAY
if self.sync.arm
else AlarmControlPanelState.DISARMED
)
async def async_alarm_disarm(self, code: str | None = None) -> None:

View File

@ -10,14 +10,9 @@ from canary.model import Location
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
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,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
@ -70,18 +65,18 @@ class CanaryAlarm(
return self.coordinator.data["locations"][self._location_id]
@property
def state(self) -> str | None:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the device."""
if self.location.is_private:
return STATE_ALARM_DISARMED
return AlarmControlPanelState.DISARMED
mode = self.location.mode
if mode.name == LOCATION_MODE_AWAY:
return STATE_ALARM_ARMED_AWAY
return AlarmControlPanelState.ARMED_AWAY
if mode.name == LOCATION_MODE_HOME:
return STATE_ALARM_ARMED_HOME
return AlarmControlPanelState.ARMED_HOME
if mode.name == LOCATION_MODE_NIGHT:
return STATE_ALARM_ARMED_NIGHT
return AlarmControlPanelState.ARMED_NIGHT
return None

View File

@ -10,21 +10,12 @@ from aiocomelit.const import ALARM_AREAS, AlarmAreaState
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_DISARMING,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
@ -112,7 +103,7 @@ class ComelitAlarmEntity(CoordinatorEntity[ComelitVedoSystem], AlarmControlPanel
return super().available
@property
def state(self) -> StateType:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the alarm."""
_LOGGER.debug(
@ -123,16 +114,16 @@ class ComelitAlarmEntity(CoordinatorEntity[ComelitVedoSystem], AlarmControlPanel
)
if self._area.human_status == AlarmAreaState.ARMED:
if self._area.armed == ALARM_AREA_ARMED_STATUS[AWAY]:
return STATE_ALARM_ARMED_AWAY
return AlarmControlPanelState.ARMED_AWAY
if self._area.armed == ALARM_AREA_ARMED_STATUS[NIGHT]:
return STATE_ALARM_ARMED_NIGHT
return STATE_ALARM_ARMED_HOME
return AlarmControlPanelState.ARMED_NIGHT
return AlarmControlPanelState.ARMED_HOME
return {
AlarmAreaState.DISARMED: STATE_ALARM_DISARMED,
AlarmAreaState.ENTRY_DELAY: STATE_ALARM_DISARMING,
AlarmAreaState.EXIT_DELAY: STATE_ALARM_ARMING,
AlarmAreaState.TRIGGERED: STATE_ALARM_TRIGGERED,
AlarmAreaState.DISARMED: AlarmControlPanelState.DISARMED,
AlarmAreaState.ENTRY_DELAY: AlarmControlPanelState.DISARMING,
AlarmAreaState.EXIT_DELAY: AlarmControlPanelState.ARMING,
AlarmAreaState.TRIGGERED: AlarmControlPanelState.TRIGGERED,
}.get(self._area.human_status)
async def async_alarm_disarm(self, code: str | None = None) -> None:

View File

@ -13,18 +13,10 @@ from homeassistant.components.alarm_control_panel import (
PLATFORM_SCHEMA as ALARM_CONTROL_PANEL_PLATFORM_SCHEMA,
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.const import (
CONF_CODE,
CONF_HOST,
CONF_MODE,
CONF_NAME,
CONF_PORT,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
)
from homeassistant.const import CONF_CODE, CONF_HOST, CONF_MODE, CONF_NAME, CONF_PORT
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -75,7 +67,6 @@ class Concord232Alarm(AlarmControlPanelEntity):
"""Representation of the Concord232-based alarm panel."""
_attr_code_format = CodeFormat.NUMBER
_attr_state: str | None
_attr_supported_features = (
AlarmControlPanelEntityFeature.ARM_HOME
| AlarmControlPanelEntityFeature.ARM_AWAY
@ -107,21 +98,21 @@ class Concord232Alarm(AlarmControlPanelEntity):
return
if part["arming_level"] == "Off":
self._attr_state = STATE_ALARM_DISARMED
self._attr_alarm_state = AlarmControlPanelState.DISARMED
elif "Home" in part["arming_level"]:
self._attr_state = STATE_ALARM_ARMED_HOME
self._attr_alarm_state = AlarmControlPanelState.ARMED_HOME
else:
self._attr_state = STATE_ALARM_ARMED_AWAY
self._attr_alarm_state = AlarmControlPanelState.ARMED_AWAY
def alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
if not self._validate_code(code, STATE_ALARM_DISARMED):
if not self._validate_code(code, AlarmControlPanelState.DISARMED):
return
self._alarm.disarm(code)
def alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command."""
if not self._validate_code(code, STATE_ALARM_ARMED_HOME):
if not self._validate_code(code, AlarmControlPanelState.ARMED_HOME):
return
if self._mode == "silent":
self._alarm.arm("stay", "silent")
@ -130,7 +121,7 @@ class Concord232Alarm(AlarmControlPanelEntity):
def alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command."""
if not self._validate_code(code, STATE_ALARM_ARMED_AWAY):
if not self._validate_code(code, AlarmControlPanelState.ARMED_AWAY):
return
self._alarm.arm("away")

View File

@ -13,18 +13,10 @@ from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_CONTROl_PANEL_DOMAIN,
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -32,16 +24,16 @@ from .entity import DeconzDevice
from .hub import DeconzHub
DECONZ_TO_ALARM_STATE = {
AncillaryControlPanel.ARMED_AWAY: STATE_ALARM_ARMED_AWAY,
AncillaryControlPanel.ARMED_NIGHT: STATE_ALARM_ARMED_NIGHT,
AncillaryControlPanel.ARMED_STAY: STATE_ALARM_ARMED_HOME,
AncillaryControlPanel.ARMING_AWAY: STATE_ALARM_ARMING,
AncillaryControlPanel.ARMING_NIGHT: STATE_ALARM_ARMING,
AncillaryControlPanel.ARMING_STAY: STATE_ALARM_ARMING,
AncillaryControlPanel.DISARMED: STATE_ALARM_DISARMED,
AncillaryControlPanel.ENTRY_DELAY: STATE_ALARM_PENDING,
AncillaryControlPanel.EXIT_DELAY: STATE_ALARM_PENDING,
AncillaryControlPanel.IN_ALARM: STATE_ALARM_TRIGGERED,
AncillaryControlPanel.ARMED_AWAY: AlarmControlPanelState.ARMED_AWAY,
AncillaryControlPanel.ARMED_NIGHT: AlarmControlPanelState.ARMED_NIGHT,
AncillaryControlPanel.ARMED_STAY: AlarmControlPanelState.ARMED_HOME,
AncillaryControlPanel.ARMING_AWAY: AlarmControlPanelState.ARMING,
AncillaryControlPanel.ARMING_NIGHT: AlarmControlPanelState.ARMING,
AncillaryControlPanel.ARMING_STAY: AlarmControlPanelState.ARMING,
AncillaryControlPanel.DISARMED: AlarmControlPanelState.DISARMED,
AncillaryControlPanel.ENTRY_DELAY: AlarmControlPanelState.PENDING,
AncillaryControlPanel.EXIT_DELAY: AlarmControlPanelState.PENDING,
AncillaryControlPanel.IN_ALARM: AlarmControlPanelState.TRIGGERED,
}
@ -105,7 +97,7 @@ class DeconzAlarmControlPanel(DeconzDevice[AncillaryControl], AlarmControlPanelE
super().async_update_callback()
@property
def state(self) -> str | None:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the control panel."""
if self._device.panel in DECONZ_TO_ALARM_STATE:
return DECONZ_TO_ALARM_STATE[self._device.panel]

View File

@ -4,20 +4,10 @@ from __future__ import annotations
import datetime
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
from homeassistant.components.manual.alarm_control_panel import ManualAlarm
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_ARMING_TIME,
CONF_DELAY_TIME,
CONF_TRIGGER_TIME,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.const import CONF_ARMING_TIME, CONF_DELAY_TIME, CONF_TRIGGER_TIME
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -39,36 +29,36 @@ async def async_setup_entry(
True,
False,
{
STATE_ALARM_ARMED_AWAY: {
AlarmControlPanelState.ARMED_AWAY: {
CONF_ARMING_TIME: datetime.timedelta(seconds=5),
CONF_DELAY_TIME: datetime.timedelta(seconds=0),
CONF_TRIGGER_TIME: datetime.timedelta(seconds=10),
},
STATE_ALARM_ARMED_HOME: {
AlarmControlPanelState.ARMED_HOME: {
CONF_ARMING_TIME: datetime.timedelta(seconds=5),
CONF_DELAY_TIME: datetime.timedelta(seconds=0),
CONF_TRIGGER_TIME: datetime.timedelta(seconds=10),
},
STATE_ALARM_ARMED_NIGHT: {
AlarmControlPanelState.ARMED_NIGHT: {
CONF_ARMING_TIME: datetime.timedelta(seconds=5),
CONF_DELAY_TIME: datetime.timedelta(seconds=0),
CONF_TRIGGER_TIME: datetime.timedelta(seconds=10),
},
STATE_ALARM_ARMED_VACATION: {
AlarmControlPanelState.ARMED_VACATION: {
CONF_ARMING_TIME: datetime.timedelta(seconds=5),
CONF_DELAY_TIME: datetime.timedelta(seconds=0),
CONF_TRIGGER_TIME: datetime.timedelta(seconds=10),
},
STATE_ALARM_DISARMED: {
AlarmControlPanelState.DISARMED: {
CONF_DELAY_TIME: datetime.timedelta(seconds=0),
CONF_TRIGGER_TIME: datetime.timedelta(seconds=10),
},
STATE_ALARM_ARMED_CUSTOM_BYPASS: {
AlarmControlPanelState.ARMED_CUSTOM_BYPASS: {
CONF_ARMING_TIME: datetime.timedelta(seconds=5),
CONF_DELAY_TIME: datetime.timedelta(seconds=0),
CONF_TRIGGER_TIME: datetime.timedelta(seconds=10),
},
STATE_ALARM_TRIGGERED: {
AlarmControlPanelState.TRIGGERED: {
CONF_ARMING_TIME: datetime.timedelta(seconds=5)
},
},

View File

@ -9,13 +9,7 @@ import requests
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
)
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
AlarmControlPanelState,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -33,13 +27,13 @@ from . import (
_LOGGER = logging.getLogger(__name__)
STATES = {
"ARM": STATE_ALARM_ARMED_AWAY,
"DAY HOME": STATE_ALARM_ARMED_HOME,
"DISARM": STATE_ALARM_DISARMED,
"ARMHOME": STATE_ALARM_ARMED_HOME,
"HOME": STATE_ALARM_ARMED_HOME,
"NIGHT HOME": STATE_ALARM_ARMED_NIGHT,
"TRIGGERED": STATE_ALARM_TRIGGERED,
"ARM": AlarmControlPanelState.ARMED_AWAY,
"DAY HOME": AlarmControlPanelState.ARMED_HOME,
"DISARM": AlarmControlPanelState.DISARMED,
"ARMHOME": AlarmControlPanelState.ARMED_HOME,
"HOME": AlarmControlPanelState.ARMED_HOME,
"NIGHT HOME": AlarmControlPanelState.ARMED_NIGHT,
"TRIGGERED": AlarmControlPanelState.TRIGGERED,
}
@ -66,7 +60,6 @@ def setup_platform(
class EgardiaAlarm(AlarmControlPanelEntity):
"""Representation of a Egardia alarm."""
_attr_state: str | None
_attr_code_arm_required = False
_attr_supported_features = (
AlarmControlPanelEntityFeature.ARM_HOME
@ -123,7 +116,7 @@ class EgardiaAlarm(AlarmControlPanelEntity):
_LOGGER.debug("Not ignoring status %s", status)
newstatus = STATES.get(status.upper())
_LOGGER.debug("newstatus %s", newstatus)
self._attr_state = newstatus
self._attr_alarm_state = newstatus
else:
_LOGGER.error("Ignoring status")

View File

@ -15,17 +15,9 @@ from homeassistant.components.alarm_control_panel import (
ATTR_CHANGED_BY,
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_platform
import homeassistant.helpers.config_validation as cv
@ -125,7 +117,7 @@ class ElkArea(ElkAttachedEntity, AlarmControlPanelEntity, RestoreEntity):
self._changed_by_time: str | None = None
self._changed_by_id: int | None = None
self._changed_by: str | None = None
self._state: str | None = None
self._state: AlarmControlPanelState | None = None
async def async_added_to_hass(self) -> None:
"""Register callback for ElkM1 changes."""
@ -177,7 +169,7 @@ class ElkArea(ElkAttachedEntity, AlarmControlPanelEntity, RestoreEntity):
return CodeFormat.NUMBER
@property
def state(self) -> str | None:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the element."""
return self._state
@ -207,23 +199,25 @@ class ElkArea(ElkAttachedEntity, AlarmControlPanelEntity, RestoreEntity):
def _element_changed(self, element: Element, changeset: dict[str, Any]) -> None:
elk_state_to_hass_state = {
ArmedStatus.DISARMED: STATE_ALARM_DISARMED,
ArmedStatus.ARMED_AWAY: STATE_ALARM_ARMED_AWAY,
ArmedStatus.ARMED_STAY: STATE_ALARM_ARMED_HOME,
ArmedStatus.ARMED_STAY_INSTANT: STATE_ALARM_ARMED_HOME,
ArmedStatus.ARMED_TO_NIGHT: STATE_ALARM_ARMED_NIGHT,
ArmedStatus.ARMED_TO_NIGHT_INSTANT: STATE_ALARM_ARMED_NIGHT,
ArmedStatus.ARMED_TO_VACATION: STATE_ALARM_ARMED_AWAY,
ArmedStatus.DISARMED: AlarmControlPanelState.DISARMED,
ArmedStatus.ARMED_AWAY: AlarmControlPanelState.ARMED_AWAY,
ArmedStatus.ARMED_STAY: AlarmControlPanelState.ARMED_HOME,
ArmedStatus.ARMED_STAY_INSTANT: AlarmControlPanelState.ARMED_HOME,
ArmedStatus.ARMED_TO_NIGHT: AlarmControlPanelState.ARMED_NIGHT,
ArmedStatus.ARMED_TO_NIGHT_INSTANT: AlarmControlPanelState.ARMED_NIGHT,
ArmedStatus.ARMED_TO_VACATION: AlarmControlPanelState.ARMED_AWAY,
}
if self._element.alarm_state is None:
self._state = None
elif self._element.in_alarm_state():
# Area is in alarm state
self._state = STATE_ALARM_TRIGGERED
self._state = AlarmControlPanelState.TRIGGERED
elif self._entry_exit_timer_is_running():
self._state = (
STATE_ALARM_ARMING if self._element.is_exit else STATE_ALARM_PENDING
AlarmControlPanelState.ARMING
if self._element.is_exit
else AlarmControlPanelState.PENDING
)
elif self._element.armed_status is not None:
self._state = elk_state_to_hass_state[self._element.armed_status]

View File

@ -10,20 +10,13 @@ from elmax_api.model.panel import PanelStatus
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_DISARMING,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError, InvalidStateError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from .const import DOMAIN
from .coordinator import ElmaxCoordinator
@ -74,16 +67,16 @@ class ElmaxArea(ElmaxEntity, AlarmControlPanelEntity):
_attr_code_arm_required = False
_attr_has_entity_name = True
_attr_supported_features = AlarmControlPanelEntityFeature.ARM_AWAY
_pending_state: str | None = None
_pending_state: AlarmControlPanelState | None = None
async def async_alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command."""
if self._attr_state == AlarmStatus.NOT_ARMED_NOT_ARMABLE:
if self._attr_alarm_state == AlarmStatus.NOT_ARMED_NOT_ARMABLE:
raise InvalidStateError(
f"Cannot arm {self.name}: please check for open windows/doors first"
)
self._pending_state = STATE_ALARM_ARMING
self._pending_state = AlarmControlPanelState.ARMING
self.async_write_ha_state()
try:
@ -107,7 +100,7 @@ class ElmaxArea(ElmaxEntity, AlarmControlPanelEntity):
if code is None or code == "":
raise ValueError("Please input the disarm code.")
self._pending_state = STATE_ALARM_DISARMING
self._pending_state = AlarmControlPanelState.DISARMING
self.async_write_ha_state()
try:
@ -130,7 +123,7 @@ class ElmaxArea(ElmaxEntity, AlarmControlPanelEntity):
await self.coordinator.async_refresh()
@property
def state(self) -> StateType:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the entity."""
if self._pending_state is not None:
return self._pending_state
@ -151,10 +144,10 @@ class ElmaxArea(ElmaxEntity, AlarmControlPanelEntity):
ALARM_STATE_TO_HA = {
AlarmArmStatus.ARMED_TOTALLY: STATE_ALARM_ARMED_AWAY,
AlarmArmStatus.ARMED_P1_P2: STATE_ALARM_ARMED_AWAY,
AlarmArmStatus.ARMED_P2: STATE_ALARM_ARMED_AWAY,
AlarmArmStatus.ARMED_P1: STATE_ALARM_ARMED_AWAY,
AlarmArmStatus.NOT_ARMED: STATE_ALARM_DISARMED,
AlarmStatus.TRIGGERED: STATE_ALARM_TRIGGERED,
AlarmArmStatus.ARMED_TOTALLY: AlarmControlPanelState.ARMED_AWAY,
AlarmArmStatus.ARMED_P1_P2: AlarmControlPanelState.ARMED_AWAY,
AlarmArmStatus.ARMED_P2: AlarmControlPanelState.ARMED_AWAY,
AlarmArmStatus.ARMED_P1: AlarmControlPanelState.ARMED_AWAY,
AlarmArmStatus.NOT_ARMED: AlarmControlPanelState.DISARMED,
AlarmStatus.TRIGGERED: AlarmControlPanelState.TRIGGERED,
}

View File

@ -9,20 +9,10 @@ import voluptuous as vol
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
CONF_CODE,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
STATE_UNKNOWN,
)
from homeassistant.const import ATTR_ENTITY_ID, CONF_CODE
from homeassistant.core import HomeAssistant, ServiceCall, callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_connect
@ -144,24 +134,24 @@ class EnvisalinkAlarm(EnvisalinkEntity, AlarmControlPanelEntity):
self.async_write_ha_state()
@property
def state(self) -> str:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the device."""
state = STATE_UNKNOWN
state = None
if self._info["status"]["alarm"]:
state = STATE_ALARM_TRIGGERED
state = AlarmControlPanelState.TRIGGERED
elif self._info["status"]["armed_zero_entry_delay"]:
state = STATE_ALARM_ARMED_NIGHT
state = AlarmControlPanelState.ARMED_NIGHT
elif self._info["status"]["armed_away"]:
state = STATE_ALARM_ARMED_AWAY
state = AlarmControlPanelState.ARMED_AWAY
elif self._info["status"]["armed_stay"]:
state = STATE_ALARM_ARMED_HOME
state = AlarmControlPanelState.ARMED_HOME
elif self._info["status"]["exit_delay"]:
state = STATE_ALARM_ARMING
state = AlarmControlPanelState.ARMING
elif self._info["status"]["entry_delay"]:
state = STATE_ALARM_PENDING
state = AlarmControlPanelState.PENDING
elif self._info["status"]["alpha"]:
state = STATE_ALARM_DISARMED
state = AlarmControlPanelState.DISARMED
return state
async def async_alarm_disarm(self, code: str | None = None) -> None:

View File

@ -6,9 +6,9 @@ from functools import partial
from aioesphomeapi import (
AlarmControlPanelCommand,
AlarmControlPanelEntityState,
AlarmControlPanelEntityState as ESPHomeAlarmControlPanelEntityState,
AlarmControlPanelInfo,
AlarmControlPanelState,
AlarmControlPanelState as ESPHomeAlarmControlPanelState,
APIIntEnum,
EntityInfo,
)
@ -16,20 +16,9 @@ from aioesphomeapi import (
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_DISARMING,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import callback
from .entity import (
@ -40,21 +29,21 @@ from .entity import (
)
from .enum_mapper import EsphomeEnumMapper
_ESPHOME_ACP_STATE_TO_HASS_STATE: EsphomeEnumMapper[AlarmControlPanelState, str] = (
EsphomeEnumMapper(
{
AlarmControlPanelState.DISARMED: STATE_ALARM_DISARMED,
AlarmControlPanelState.ARMED_HOME: STATE_ALARM_ARMED_HOME,
AlarmControlPanelState.ARMED_AWAY: STATE_ALARM_ARMED_AWAY,
AlarmControlPanelState.ARMED_NIGHT: STATE_ALARM_ARMED_NIGHT,
AlarmControlPanelState.ARMED_VACATION: STATE_ALARM_ARMED_VACATION,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS: STATE_ALARM_ARMED_CUSTOM_BYPASS,
AlarmControlPanelState.PENDING: STATE_ALARM_PENDING,
AlarmControlPanelState.ARMING: STATE_ALARM_ARMING,
AlarmControlPanelState.DISARMING: STATE_ALARM_DISARMING,
AlarmControlPanelState.TRIGGERED: STATE_ALARM_TRIGGERED,
}
)
_ESPHOME_ACP_STATE_TO_HASS_STATE: EsphomeEnumMapper[
ESPHomeAlarmControlPanelState, AlarmControlPanelState
] = EsphomeEnumMapper(
{
ESPHomeAlarmControlPanelState.DISARMED: AlarmControlPanelState.DISARMED,
ESPHomeAlarmControlPanelState.ARMED_HOME: AlarmControlPanelState.ARMED_HOME,
ESPHomeAlarmControlPanelState.ARMED_AWAY: AlarmControlPanelState.ARMED_AWAY,
ESPHomeAlarmControlPanelState.ARMED_NIGHT: AlarmControlPanelState.ARMED_NIGHT,
ESPHomeAlarmControlPanelState.ARMED_VACATION: AlarmControlPanelState.ARMED_VACATION,
ESPHomeAlarmControlPanelState.ARMED_CUSTOM_BYPASS: AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
ESPHomeAlarmControlPanelState.PENDING: AlarmControlPanelState.PENDING,
ESPHomeAlarmControlPanelState.ARMING: AlarmControlPanelState.ARMING,
ESPHomeAlarmControlPanelState.DISARMING: AlarmControlPanelState.DISARMING,
ESPHomeAlarmControlPanelState.TRIGGERED: AlarmControlPanelState.TRIGGERED,
}
)
@ -70,7 +59,7 @@ class EspHomeACPFeatures(APIIntEnum):
class EsphomeAlarmControlPanel(
EsphomeEntity[AlarmControlPanelInfo, AlarmControlPanelEntityState],
EsphomeEntity[AlarmControlPanelInfo, ESPHomeAlarmControlPanelEntityState],
AlarmControlPanelEntity,
):
"""An Alarm Control Panel implementation for ESPHome."""
@ -101,7 +90,7 @@ class EsphomeAlarmControlPanel(
@property
@esphome_state_property
def state(self) -> str | None:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the device."""
return _ESPHOME_ACP_STATE_TO_HASS_STATE.from_esphome(self._state.state)
@ -159,5 +148,5 @@ async_setup_entry = partial(
platform_async_setup_entry,
info_type=AlarmControlPanelInfo,
entity_type=EsphomeAlarmControlPanel,
state_type=AlarmControlPanelEntityState,
state_type=ESPHomeAlarmControlPanelEntityState,
)

View File

@ -13,13 +13,9 @@ from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityDescription,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.device_registry import DeviceInfo
@ -45,9 +41,9 @@ ALARM_TYPE = EzvizAlarmControlPanelEntityDescription(
key="ezviz_alarm",
ezviz_alarm_states=[
None,
STATE_ALARM_DISARMED,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
AlarmControlPanelState.DISARMED,
AlarmControlPanelState.ARMED_AWAY,
AlarmControlPanelState.ARMED_HOME,
],
)
@ -96,7 +92,7 @@ class EzvizAlarm(AlarmControlPanelEntity):
self._attr_device_info = device_info
self.entity_description = entity_description
self.coordinator = coordinator
self._attr_state = None
self._attr_alarm_state = None
async def async_added_to_hass(self) -> None:
"""Entity added to hass."""
@ -108,7 +104,7 @@ class EzvizAlarm(AlarmControlPanelEntity):
if self.coordinator.ezviz_client.api_set_defence_mode(
DefenseModeType.HOME_MODE.value
):
self._attr_state = STATE_ALARM_DISARMED
self._attr_alarm_state = AlarmControlPanelState.DISARMED
except PyEzvizError as err:
raise HomeAssistantError("Cannot disarm EZVIZ alarm") from err
@ -119,7 +115,7 @@ class EzvizAlarm(AlarmControlPanelEntity):
if self.coordinator.ezviz_client.api_set_defence_mode(
DefenseModeType.AWAY_MODE.value
):
self._attr_state = STATE_ALARM_ARMED_AWAY
self._attr_alarm_state = AlarmControlPanelState.ARMED_AWAY
except PyEzvizError as err:
raise HomeAssistantError("Cannot arm EZVIZ alarm") from err
@ -130,7 +126,7 @@ class EzvizAlarm(AlarmControlPanelEntity):
if self.coordinator.ezviz_client.api_set_defence_mode(
DefenseModeType.SLEEP_MODE.value
):
self._attr_state = STATE_ALARM_ARMED_HOME
self._attr_alarm_state = AlarmControlPanelState.ARMED_HOME
except PyEzvizError as err:
raise HomeAssistantError("Cannot arm EZVIZ alarm") from err
@ -145,7 +141,7 @@ class EzvizAlarm(AlarmControlPanelEntity):
_LOGGER.debug(
"Updating EZVIZ alarm with response %s", ezviz_alarm_state_number
)
self._attr_state = self.entity_description.ezviz_alarm_states[
self._attr_alarm_state = self.entity_description.ezviz_alarm_states[
int(ezviz_alarm_state_number)
]

View File

@ -5,15 +5,9 @@ from typing import Any
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -22,14 +16,14 @@ from .entity import FreeboxHomeEntity
from .router import FreeboxRouter
FREEBOX_TO_STATUS = {
"alarm1_arming": STATE_ALARM_ARMING,
"alarm2_arming": STATE_ALARM_ARMING,
"alarm1_armed": STATE_ALARM_ARMED_AWAY,
"alarm2_armed": STATE_ALARM_ARMED_HOME,
"alarm1_alert_timer": STATE_ALARM_TRIGGERED,
"alarm2_alert_timer": STATE_ALARM_TRIGGERED,
"alert": STATE_ALARM_TRIGGERED,
"idle": STATE_ALARM_DISARMED,
"alarm1_arming": AlarmControlPanelState.ARMING,
"alarm2_arming": AlarmControlPanelState.ARMING,
"alarm1_armed": AlarmControlPanelState.ARMED_AWAY,
"alarm2_armed": AlarmControlPanelState.ARMED_HOME,
"alarm1_alert_timer": AlarmControlPanelState.TRIGGERED,
"alarm2_alert_timer": AlarmControlPanelState.TRIGGERED,
"alert": AlarmControlPanelState.TRIGGERED,
"idle": AlarmControlPanelState.DISARMED,
}
@ -103,6 +97,6 @@ class FreeboxAlarm(FreeboxHomeEntity, AlarmControlPanelEntity):
"""Update state."""
state: str | None = await self.get_home_endpoint_value(self._command_state)
if state:
self._attr_state = FREEBOX_TO_STATUS.get(state)
self._attr_alarm_state = FREEBOX_TO_STATUS.get(state)
else:
self._attr_state = None
self._attr_alarm_state = None

View File

@ -33,7 +33,10 @@ from homeassistant.components import (
valve,
water_heater,
)
from homeassistant.components.alarm_control_panel import AlarmControlPanelEntityFeature
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.components.camera import CameraEntityFeature
from homeassistant.components.climate import ClimateEntityFeature
from homeassistant.components.cover import CoverEntityFeature
@ -63,13 +66,6 @@ from homeassistant.const import (
SERVICE_ALARM_TRIGGER,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
STATE_IDLE,
STATE_OFF,
STATE_ON,
@ -1557,19 +1553,19 @@ class ArmDisArmTrait(_Trait):
commands = [COMMAND_ARM_DISARM]
state_to_service = {
STATE_ALARM_ARMED_HOME: SERVICE_ALARM_ARM_HOME,
STATE_ALARM_ARMED_NIGHT: SERVICE_ALARM_ARM_NIGHT,
STATE_ALARM_ARMED_AWAY: SERVICE_ALARM_ARM_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS: SERVICE_ALARM_ARM_CUSTOM_BYPASS,
STATE_ALARM_TRIGGERED: SERVICE_ALARM_TRIGGER,
AlarmControlPanelState.ARMED_HOME: SERVICE_ALARM_ARM_HOME,
AlarmControlPanelState.ARMED_NIGHT: SERVICE_ALARM_ARM_NIGHT,
AlarmControlPanelState.ARMED_AWAY: SERVICE_ALARM_ARM_AWAY,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS: SERVICE_ALARM_ARM_CUSTOM_BYPASS,
AlarmControlPanelState.TRIGGERED: SERVICE_ALARM_TRIGGER,
}
state_to_support = {
STATE_ALARM_ARMED_HOME: AlarmControlPanelEntityFeature.ARM_HOME,
STATE_ALARM_ARMED_NIGHT: AlarmControlPanelEntityFeature.ARM_NIGHT,
STATE_ALARM_ARMED_AWAY: AlarmControlPanelEntityFeature.ARM_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS: AlarmControlPanelEntityFeature.ARM_CUSTOM_BYPASS,
STATE_ALARM_TRIGGERED: AlarmControlPanelEntityFeature.TRIGGER,
AlarmControlPanelState.ARMED_HOME: AlarmControlPanelEntityFeature.ARM_HOME,
AlarmControlPanelState.ARMED_NIGHT: AlarmControlPanelEntityFeature.ARM_NIGHT,
AlarmControlPanelState.ARMED_AWAY: AlarmControlPanelEntityFeature.ARM_AWAY,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS: AlarmControlPanelEntityFeature.ARM_CUSTOM_BYPASS,
AlarmControlPanelState.TRIGGERED: AlarmControlPanelEntityFeature.TRIGGER,
}
"""The list of states to support in increasing security state."""
@ -1595,8 +1591,8 @@ class ArmDisArmTrait(_Trait):
def _default_arm_state(self):
states = self._supported_states()
if STATE_ALARM_TRIGGERED in states:
states.remove(STATE_ALARM_TRIGGERED)
if AlarmControlPanelState.TRIGGERED in states:
states.remove(AlarmControlPanelState.TRIGGERED)
if not states:
raise SmartHomeError(ERR_NOT_SUPPORTED, "ArmLevel missing")
@ -1611,7 +1607,7 @@ class ArmDisArmTrait(_Trait):
# level synonyms are generated from state names
# 'armed_away' becomes 'armed away' or 'away'
level_synonym = [state.replace("_", " ")]
if state != STATE_ALARM_TRIGGERED:
if state != AlarmControlPanelState.TRIGGERED:
level_synonym.append(state.split("_")[1])
level = {
@ -1652,11 +1648,11 @@ class ArmDisArmTrait(_Trait):
elif (
params["arm"]
and params.get("cancel")
and self.state.state == STATE_ALARM_PENDING
and self.state.state == AlarmControlPanelState.PENDING
):
service = SERVICE_ALARM_DISARM
else:
if self.state.state == STATE_ALARM_DISARMED:
if self.state.state == AlarmControlPanelState.DISARMED:
raise SmartHomeError(ERR_ALREADY_DISARMED, "System is already disarmed")
_verify_pin_challenge(data, self.state, challenge)
service = SERVICE_ALARM_DISARM

View File

@ -8,6 +8,7 @@ from __future__ import annotations
from dataclasses import dataclass
from typing import Protocol
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
from homeassistant.components.climate import HVACMode
from homeassistant.components.lock import LockState
from homeassistant.components.vacuum import STATE_CLEANING, STATE_ERROR, STATE_RETURNING
@ -20,12 +21,6 @@ from homeassistant.components.water_heater import (
STATE_PERFORMANCE,
)
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_TRIGGERED,
STATE_CLOSED,
STATE_HOME,
STATE_IDLE,
@ -60,12 +55,12 @@ ON_OFF_STATES: dict[Platform | str, tuple[set[str], str, str]] = {
Platform.ALARM_CONTROL_PANEL: (
{
STATE_ON,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_TRIGGERED,
AlarmControlPanelState.ARMED_AWAY,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_HOME,
AlarmControlPanelState.ARMED_NIGHT,
AlarmControlPanelState.ARMED_VACATION,
AlarmControlPanelState.TRIGGERED,
},
STATE_ON,
STATE_OFF,

View File

@ -7,14 +7,9 @@ from datetime import timedelta
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -24,10 +19,10 @@ from .entity import HiveEntity
PARALLEL_UPDATES = 0
SCAN_INTERVAL = timedelta(seconds=15)
HIVETOHA = {
"home": STATE_ALARM_DISARMED,
"asleep": STATE_ALARM_ARMED_NIGHT,
"away": STATE_ALARM_ARMED_AWAY,
"sos": STATE_ALARM_TRIGGERED,
"home": AlarmControlPanelState.DISARMED,
"asleep": AlarmControlPanelState.ARMED_NIGHT,
"away": AlarmControlPanelState.ARMED_AWAY,
"sos": AlarmControlPanelState.TRIGGERED,
}
@ -76,6 +71,6 @@ class HiveAlarmControlPanelEntity(HiveEntity, AlarmControlPanelEntity):
self._attr_available = self.device["deviceData"].get("online")
if self._attr_available:
if self.device["status"]["state"]:
self._attr_state = STATE_ALARM_TRIGGERED
self._attr_alarm_state = AlarmControlPanelState.TRIGGERED
else:
self._attr_state = HIVETOHA[self.device["status"]["mode"]]
self._attr_alarm_state = HIVETOHA[self.device["status"]["mode"]]

View File

@ -8,6 +8,7 @@ from pyhap.const import CATEGORY_ALARM_SYSTEM
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_CONTROL_PANEL_DOMAIN,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.const import (
ATTR_CODE,
@ -17,13 +18,6 @@ from homeassistant.const import (
SERVICE_ALARM_ARM_HOME,
SERVICE_ALARM_ARM_NIGHT,
SERVICE_ALARM_DISARM,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import State, callback
@ -43,22 +37,22 @@ HK_ALARM_DISARMED = 3
HK_ALARM_TRIGGERED = 4
HASS_TO_HOMEKIT_CURRENT = {
STATE_ALARM_ARMED_HOME: HK_ALARM_STAY_ARMED,
STATE_ALARM_ARMED_VACATION: HK_ALARM_AWAY_ARMED,
STATE_ALARM_ARMED_AWAY: HK_ALARM_AWAY_ARMED,
STATE_ALARM_ARMED_NIGHT: HK_ALARM_NIGHT_ARMED,
STATE_ALARM_ARMING: HK_ALARM_DISARMED,
STATE_ALARM_DISARMED: HK_ALARM_DISARMED,
STATE_ALARM_TRIGGERED: HK_ALARM_TRIGGERED,
AlarmControlPanelState.ARMED_HOME: HK_ALARM_STAY_ARMED,
AlarmControlPanelState.ARMED_VACATION: HK_ALARM_AWAY_ARMED,
AlarmControlPanelState.ARMED_AWAY: HK_ALARM_AWAY_ARMED,
AlarmControlPanelState.ARMED_NIGHT: HK_ALARM_NIGHT_ARMED,
AlarmControlPanelState.ARMING: HK_ALARM_DISARMED,
AlarmControlPanelState.DISARMED: HK_ALARM_DISARMED,
AlarmControlPanelState.TRIGGERED: HK_ALARM_TRIGGERED,
}
HASS_TO_HOMEKIT_TARGET = {
STATE_ALARM_ARMED_HOME: HK_ALARM_STAY_ARMED,
STATE_ALARM_ARMED_VACATION: HK_ALARM_AWAY_ARMED,
STATE_ALARM_ARMED_AWAY: HK_ALARM_AWAY_ARMED,
STATE_ALARM_ARMED_NIGHT: HK_ALARM_NIGHT_ARMED,
STATE_ALARM_ARMING: HK_ALARM_AWAY_ARMED,
STATE_ALARM_DISARMED: HK_ALARM_DISARMED,
AlarmControlPanelState.ARMED_HOME: HK_ALARM_STAY_ARMED,
AlarmControlPanelState.ARMED_VACATION: HK_ALARM_AWAY_ARMED,
AlarmControlPanelState.ARMED_AWAY: HK_ALARM_AWAY_ARMED,
AlarmControlPanelState.ARMED_NIGHT: HK_ALARM_NIGHT_ARMED,
AlarmControlPanelState.ARMING: HK_ALARM_AWAY_ARMED,
AlarmControlPanelState.DISARMED: HK_ALARM_DISARMED,
}
HASS_TO_HOMEKIT_SERVICES = {
@ -124,7 +118,7 @@ class SecuritySystem(HomeAccessory):
self.char_current_state = serv_alarm.configure_char(
CHAR_CURRENT_SECURITY_STATE,
value=HASS_TO_HOMEKIT_CURRENT[STATE_ALARM_DISARMED],
value=HASS_TO_HOMEKIT_CURRENT[AlarmControlPanelState.DISARMED],
valid_values={
key: val
for key, val in default_current_states.items()
@ -158,8 +152,16 @@ class SecuritySystem(HomeAccessory):
@callback
def async_update_state(self, new_state: State) -> None:
"""Update security state after state changed."""
hass_state = new_state.state
if (current_state := HASS_TO_HOMEKIT_CURRENT.get(hass_state)) is not None:
hass_state = None
if new_state and new_state.state == "None":
# Bail out early for no state
return
if new_state and new_state.state is not None:
hass_state = AlarmControlPanelState(new_state.state)
if (
hass_state
and (current_state := HASS_TO_HOMEKIT_CURRENT.get(hass_state)) is not None
):
self.char_current_state.set_value(current_state)
_LOGGER.debug(
"%s: Updated current state to %s (%d)",
@ -167,5 +169,8 @@ class SecuritySystem(HomeAccessory):
hass_state,
current_state,
)
if (target_state := HASS_TO_HOMEKIT_TARGET.get(hass_state)) is not None:
if (
hass_state
and (target_state := HASS_TO_HOMEKIT_TARGET.get(hass_state)) is not None
):
self.char_target_state.set_value(target_state)

View File

@ -10,17 +10,10 @@ from aiohomekit.model.services import Service, ServicesTypes
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_BATTERY_LEVEL,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
Platform,
)
from homeassistant.const import ATTR_BATTERY_LEVEL, Platform
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -29,18 +22,18 @@ from .connection import HKDevice
from .entity import HomeKitEntity
CURRENT_STATE_MAP = {
0: STATE_ALARM_ARMED_HOME,
1: STATE_ALARM_ARMED_AWAY,
2: STATE_ALARM_ARMED_NIGHT,
3: STATE_ALARM_DISARMED,
4: STATE_ALARM_TRIGGERED,
0: AlarmControlPanelState.ARMED_HOME,
1: AlarmControlPanelState.ARMED_AWAY,
2: AlarmControlPanelState.ARMED_NIGHT,
3: AlarmControlPanelState.DISARMED,
4: AlarmControlPanelState.TRIGGERED,
}
TARGET_STATE_MAP = {
STATE_ALARM_ARMED_HOME: 0,
STATE_ALARM_ARMED_AWAY: 1,
STATE_ALARM_ARMED_NIGHT: 2,
STATE_ALARM_DISARMED: 3,
AlarmControlPanelState.ARMED_HOME: 0,
AlarmControlPanelState.ARMED_AWAY: 1,
AlarmControlPanelState.ARMED_NIGHT: 2,
AlarmControlPanelState.DISARMED: 3,
}
@ -86,7 +79,7 @@ class HomeKitAlarmControlPanelEntity(HomeKitEntity, AlarmControlPanelEntity):
]
@property
def state(self) -> str:
def alarm_state(self) -> AlarmControlPanelState:
"""Return the state of the device."""
return CURRENT_STATE_MAP[
self.service.value(CharacteristicsTypes.SECURITY_SYSTEM_STATE_CURRENT)
@ -94,21 +87,23 @@ class HomeKitAlarmControlPanelEntity(HomeKitEntity, AlarmControlPanelEntity):
async def async_alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
await self.set_alarm_state(STATE_ALARM_DISARMED, code)
await self.set_alarm_state(AlarmControlPanelState.DISARMED, code)
async def async_alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm command."""
await self.set_alarm_state(STATE_ALARM_ARMED_AWAY, code)
await self.set_alarm_state(AlarmControlPanelState.ARMED_AWAY, code)
async def async_alarm_arm_home(self, code: str | None = None) -> None:
"""Send stay command."""
await self.set_alarm_state(STATE_ALARM_ARMED_HOME, code)
await self.set_alarm_state(AlarmControlPanelState.ARMED_HOME, code)
async def async_alarm_arm_night(self, code: str | None = None) -> None:
"""Send night command."""
await self.set_alarm_state(STATE_ALARM_ARMED_NIGHT, code)
await self.set_alarm_state(AlarmControlPanelState.ARMED_NIGHT, code)
async def set_alarm_state(self, state: str, code: str | None = None) -> None:
async def set_alarm_state(
self, state: AlarmControlPanelState, code: str | None = None
) -> None:
"""Send state command."""
await self.async_put_characteristics(
{CharacteristicsTypes.SECURITY_SYSTEM_STATE_TARGET: TARGET_STATE_MAP[state]}

View File

@ -9,14 +9,9 @@ from homematicip.functionalHomes import SecurityAndAlarmHome
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -65,21 +60,21 @@ class HomematicipAlarmControlPanelEntity(AlarmControlPanelEntity):
)
@property
def state(self) -> str:
def alarm_state(self) -> AlarmControlPanelState:
"""Return the state of the alarm control panel."""
# check for triggered alarm
if self._security_and_alarm.alarmActive:
return STATE_ALARM_TRIGGERED
return AlarmControlPanelState.TRIGGERED
activation_state = self._home.get_security_zones_activation()
# check arm_away
if activation_state == (True, True):
return STATE_ALARM_ARMED_AWAY
return AlarmControlPanelState.ARMED_AWAY
# check arm_home
if activation_state == (False, True):
return STATE_ALARM_ARMED_HOME
return AlarmControlPanelState.ARMED_HOME
return STATE_ALARM_DISARMED
return AlarmControlPanelState.DISARMED
@property
def _security_and_alarm(self) -> SecurityAndAlarmHome:

View File

@ -5,6 +5,7 @@ from __future__ import annotations
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
@ -50,7 +51,7 @@ class IAlarmPanel(
self._attr_unique_id = coordinator.mac
@property
def state(self) -> str | None:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the device."""
return self.coordinator.state

View File

@ -2,12 +2,7 @@
from pyialarm import IAlarm
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
DATA_COORDINATOR = "ialarm"
@ -16,8 +11,8 @@ DEFAULT_PORT = 18034
DOMAIN = "ialarm"
IALARM_TO_HASS = {
IAlarm.ARMED_AWAY: STATE_ALARM_ARMED_AWAY,
IAlarm.ARMED_STAY: STATE_ALARM_ARMED_HOME,
IAlarm.DISARMED: STATE_ALARM_DISARMED,
IAlarm.TRIGGERED: STATE_ALARM_TRIGGERED,
IAlarm.ARMED_AWAY: AlarmControlPanelState.ARMED_AWAY,
IAlarm.ARMED_STAY: AlarmControlPanelState.ARMED_HOME,
IAlarm.DISARMED: AlarmControlPanelState.DISARMED,
IAlarm.TRIGGERED: AlarmControlPanelState.TRIGGERED,
}

View File

@ -7,7 +7,10 @@ import logging
from pyialarm import IAlarm
from homeassistant.components.alarm_control_panel import SCAN_INTERVAL
from homeassistant.components.alarm_control_panel import (
SCAN_INTERVAL,
AlarmControlPanelState,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
@ -22,7 +25,7 @@ class IAlarmDataUpdateCoordinator(DataUpdateCoordinator[None]):
def __init__(self, hass: HomeAssistant, ialarm: IAlarm, mac: str) -> None:
"""Initialize global iAlarm data updater."""
self.ialarm = ialarm
self.state: str | None = None
self.state: AlarmControlPanelState | None = None
self.host: str = ialarm.host
self.mac = mac

View File

@ -10,6 +10,7 @@ from homeassistant.components.alarm_control_panel import (
PLATFORM_SCHEMA as ALARM_CONTROL_PANEL_PLATFORM_SCHEMA,
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.const import (
@ -18,10 +19,6 @@ from homeassistant.const import (
CONF_CODE,
CONF_NAME,
CONF_OPTIMISTIC,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED,
)
from homeassistant.core import HomeAssistant, ServiceCall
import homeassistant.helpers.config_validation as cv
@ -33,10 +30,10 @@ from . import ATTR_EVENT, DOMAIN, SERVICE_PUSH_ALARM_STATE, SERVICE_TRIGGER
_LOGGER = logging.getLogger(__name__)
ALLOWED_STATES = [
STATE_ALARM_DISARMED,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
AlarmControlPanelState.DISARMED,
AlarmControlPanelState.ARMED_NIGHT,
AlarmControlPanelState.ARMED_AWAY,
AlarmControlPanelState.ARMED_HOME,
]
DATA_IFTTT_ALARM = "ifttt_alarm"
@ -168,40 +165,41 @@ class IFTTTAlarmPanel(AlarmControlPanelEntity):
"""Send disarm command."""
if not self._check_code(code):
return
self.set_alarm_state(self._event_disarm, STATE_ALARM_DISARMED)
self.set_alarm_state(self._event_disarm, AlarmControlPanelState.DISARMED)
def alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command."""
if self._code_arm_required and not self._check_code(code):
return
self.set_alarm_state(self._event_away, STATE_ALARM_ARMED_AWAY)
self.set_alarm_state(self._event_away, AlarmControlPanelState.ARMED_AWAY)
def alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command."""
if self._code_arm_required and not self._check_code(code):
return
self.set_alarm_state(self._event_home, STATE_ALARM_ARMED_HOME)
self.set_alarm_state(self._event_home, AlarmControlPanelState.ARMED_HOME)
def alarm_arm_night(self, code: str | None = None) -> None:
"""Send arm night command."""
if self._code_arm_required and not self._check_code(code):
return
self.set_alarm_state(self._event_night, STATE_ALARM_ARMED_NIGHT)
self.set_alarm_state(self._event_night, AlarmControlPanelState.ARMED_NIGHT)
def set_alarm_state(self, event: str, state: str) -> None:
def set_alarm_state(self, event: str, state: AlarmControlPanelState) -> None:
"""Call the IFTTT trigger service to change the alarm state."""
data = {ATTR_EVENT: event}
self.hass.services.call(DOMAIN, SERVICE_TRIGGER, data)
_LOGGER.debug("Called IFTTT integration to trigger event %s", event)
if self._optimistic:
self._attr_state = state
self._attr_alarm_state = state
def push_alarm_state(self, value: str) -> None:
"""Push the alarm state to the given value."""
value = AlarmControlPanelState(value)
if value in ALLOWED_STATES:
_LOGGER.debug("Pushed the alarm state to %s", value)
self._attr_state = value
self._attr_alarm_state = value
def _check_code(self, code: str | None) -> bool:
return self._code is None or self._code == code

View File

@ -9,14 +9,9 @@ import lupupy
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -64,16 +59,16 @@ class LupusecAlarm(LupusecDevice, AlarmControlPanelEntity):
)
@property
def state(self) -> str | None:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the device."""
if self._device.is_standby:
state = STATE_ALARM_DISARMED
state = AlarmControlPanelState.DISARMED
elif self._device.is_away:
state = STATE_ALARM_ARMED_AWAY
state = AlarmControlPanelState.ARMED_AWAY
elif self._device.is_home:
state = STATE_ALARM_ARMED_HOME
state = AlarmControlPanelState.ARMED_HOME
elif self._device.is_alarm_triggered:
state = STATE_ALARM_TRIGGERED
state = AlarmControlPanelState.TRIGGERED
else:
state = None
return state

View File

@ -11,6 +11,7 @@ from homeassistant.components.alarm_control_panel import (
PLATFORM_SCHEMA as ALARM_CONTROL_PANEL_PLATFORM_SCHEMA,
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.const import (
@ -21,15 +22,6 @@ from homeassistant.const import (
CONF_NAME,
CONF_TRIGGER_TIME,
CONF_UNIQUE_ID,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import ServiceValidationError
@ -47,6 +39,16 @@ CONF_ARMING_STATES = "arming_states"
CONF_CODE_TEMPLATE = "code_template"
CONF_CODE_ARM_REQUIRED = "code_arm_required"
CONF_ALARM_ARMED_AWAY = "armed_away"
CONF_ALARM_ARMED_CUSTOM_BYPASS = "armed_custom_bypass"
CONF_ALARM_ARMED_HOME = "armed_home"
CONF_ALARM_ARMED_NIGHT = "armed_night"
CONF_ALARM_ARMED_VACATION = "armed_vacation"
CONF_ALARM_ARMING = "arming"
CONF_ALARM_DISARMED = "disarmed"
CONF_ALARM_PENDING = "pending"
CONF_ALARM_TRIGGERED = "triggered"
DEFAULT_ALARM_NAME = "HA Alarm"
DEFAULT_DELAY_TIME = datetime.timedelta(seconds=60)
DEFAULT_ARMING_TIME = datetime.timedelta(seconds=60)
@ -54,39 +56,46 @@ DEFAULT_TRIGGER_TIME = datetime.timedelta(seconds=120)
DEFAULT_DISARM_AFTER_TRIGGER = False
SUPPORTED_STATES = [
STATE_ALARM_DISARMED,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_TRIGGERED,
AlarmControlPanelState.DISARMED,
AlarmControlPanelState.ARMED_AWAY,
AlarmControlPanelState.ARMED_HOME,
AlarmControlPanelState.ARMED_NIGHT,
AlarmControlPanelState.ARMED_VACATION,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
AlarmControlPanelState.TRIGGERED,
]
SUPPORTED_PRETRIGGER_STATES = [
state for state in SUPPORTED_STATES if state != STATE_ALARM_TRIGGERED
state for state in SUPPORTED_STATES if state != AlarmControlPanelState.TRIGGERED
]
SUPPORTED_ARMING_STATES = [
state
for state in SUPPORTED_STATES
if state not in (STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED)
if state
not in (
AlarmControlPanelState.DISARMED,
AlarmControlPanelState.TRIGGERED,
)
]
SUPPORTED_ARMING_STATE_TO_FEATURE = {
STATE_ALARM_ARMED_AWAY: AlarmControlPanelEntityFeature.ARM_AWAY,
STATE_ALARM_ARMED_HOME: AlarmControlPanelEntityFeature.ARM_HOME,
STATE_ALARM_ARMED_NIGHT: AlarmControlPanelEntityFeature.ARM_NIGHT,
STATE_ALARM_ARMED_VACATION: AlarmControlPanelEntityFeature.ARM_VACATION,
STATE_ALARM_ARMED_CUSTOM_BYPASS: AlarmControlPanelEntityFeature.ARM_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_AWAY: AlarmControlPanelEntityFeature.ARM_AWAY,
AlarmControlPanelState.ARMED_HOME: AlarmControlPanelEntityFeature.ARM_HOME,
AlarmControlPanelState.ARMED_NIGHT: AlarmControlPanelEntityFeature.ARM_NIGHT,
AlarmControlPanelState.ARMED_VACATION: AlarmControlPanelEntityFeature.ARM_VACATION,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS: AlarmControlPanelEntityFeature.ARM_CUSTOM_BYPASS,
}
ATTR_PREVIOUS_STATE = "previous_state"
ATTR_NEXT_STATE = "next_state"
def _state_validator(config: dict[str, Any]) -> dict[str, Any]:
def _state_validator(
config: dict[AlarmControlPanelState | str, Any],
) -> dict[str, Any]:
"""Validate the state."""
state: AlarmControlPanelState
for state in SUPPORTED_PRETRIGGER_STATES:
if CONF_DELAY_TIME not in config[state]:
config[state] = config[state] | {CONF_DELAY_TIME: config[CONF_DELAY_TIME]}
@ -142,26 +151,26 @@ PLATFORM_SCHEMA = vol.Schema(
vol.Optional(
CONF_ARMING_STATES, default=SUPPORTED_ARMING_STATES
): vol.All(cv.ensure_list, [vol.In(SUPPORTED_ARMING_STATES)]),
vol.Optional(STATE_ALARM_ARMED_AWAY, default={}): _state_schema(
STATE_ALARM_ARMED_AWAY
vol.Optional(CONF_ALARM_ARMED_AWAY, default={}): _state_schema(
AlarmControlPanelState.ARMED_AWAY
),
vol.Optional(STATE_ALARM_ARMED_HOME, default={}): _state_schema(
STATE_ALARM_ARMED_HOME
vol.Optional(CONF_ALARM_ARMED_HOME, default={}): _state_schema(
AlarmControlPanelState.ARMED_HOME
),
vol.Optional(STATE_ALARM_ARMED_NIGHT, default={}): _state_schema(
STATE_ALARM_ARMED_NIGHT
vol.Optional(CONF_ALARM_ARMED_NIGHT, default={}): _state_schema(
AlarmControlPanelState.ARMED_NIGHT
),
vol.Optional(STATE_ALARM_ARMED_VACATION, default={}): _state_schema(
STATE_ALARM_ARMED_VACATION
vol.Optional(CONF_ALARM_ARMED_VACATION, default={}): _state_schema(
AlarmControlPanelState.ARMED_VACATION
),
vol.Optional(
STATE_ALARM_ARMED_CUSTOM_BYPASS, default={}
): _state_schema(STATE_ALARM_ARMED_CUSTOM_BYPASS),
vol.Optional(STATE_ALARM_DISARMED, default={}): _state_schema(
STATE_ALARM_DISARMED
vol.Optional(CONF_ALARM_ARMED_CUSTOM_BYPASS, default={}): _state_schema(
AlarmControlPanelState.ARMED_CUSTOM_BYPASS
),
vol.Optional(STATE_ALARM_TRIGGERED, default={}): _state_schema(
STATE_ALARM_TRIGGERED
vol.Optional(CONF_ALARM_DISARMED, default={}): _state_schema(
AlarmControlPanelState.DISARMED
),
vol.Optional(CONF_ALARM_TRIGGERED, default={}): _state_schema(
AlarmControlPanelState.TRIGGERED
),
},
),
@ -217,25 +226,25 @@ class ManualAlarm(AlarmControlPanelEntity, RestoreEntity):
config: dict[str, Any],
) -> None:
"""Init the manual alarm panel."""
self._state = STATE_ALARM_DISARMED
self._state: AlarmControlPanelState = AlarmControlPanelState.DISARMED
self._hass = hass
self._attr_name = name
self._attr_unique_id = unique_id
self._code = code_template or code or None
self._attr_code_arm_required = code_arm_required
self._disarm_after_trigger = disarm_after_trigger
self._previous_state = self._state
self._previous_state: AlarmControlPanelState = self._state
self._state_ts: datetime.datetime = dt_util.utcnow()
self._delay_time_by_state = {
self._delay_time_by_state: dict[AlarmControlPanelState, Any] = {
state: config[state][CONF_DELAY_TIME]
for state in SUPPORTED_PRETRIGGER_STATES
}
self._trigger_time_by_state = {
self._trigger_time_by_state: dict[AlarmControlPanelState, Any] = {
state: config[state][CONF_TRIGGER_TIME]
for state in SUPPORTED_PRETRIGGER_STATES
}
self._arming_time_by_state = {
self._arming_time_by_state: dict[AlarmControlPanelState, Any] = {
state: config[state][CONF_ARMING_TIME] for state in SUPPORTED_ARMING_STATES
}
@ -246,11 +255,11 @@ class ManualAlarm(AlarmControlPanelEntity, RestoreEntity):
]
@property
def state(self) -> str:
def alarm_state(self) -> AlarmControlPanelState:
"""Return the state of the device."""
if self._state == STATE_ALARM_TRIGGERED:
if self._state == AlarmControlPanelState.TRIGGERED:
if self._within_pending_time(self._state):
return STATE_ALARM_PENDING
return AlarmControlPanelState.PENDING
trigger_time: datetime.timedelta = self._trigger_time_by_state[
self._previous_state
]
@ -258,39 +267,42 @@ class ManualAlarm(AlarmControlPanelEntity, RestoreEntity):
self._state_ts + self._pending_time(self._state) + trigger_time
) < dt_util.utcnow():
if self._disarm_after_trigger:
return STATE_ALARM_DISARMED
return AlarmControlPanelState.DISARMED
self._state = self._previous_state
return self._state
if self._state in SUPPORTED_ARMING_STATES and self._within_arming_time(
self._state
):
return STATE_ALARM_ARMING
return AlarmControlPanelState.ARMING
return self._state
@property
def _active_state(self) -> str:
def _active_state(self) -> AlarmControlPanelState:
"""Get the current state."""
if self.state in (STATE_ALARM_PENDING, STATE_ALARM_ARMING):
if self.state in (
AlarmControlPanelState.PENDING,
AlarmControlPanelState.ARMING,
):
return self._previous_state
return self._state
def _arming_time(self, state: str) -> datetime.timedelta:
def _arming_time(self, state: AlarmControlPanelState) -> datetime.timedelta:
"""Get the arming time."""
arming_time: datetime.timedelta = self._arming_time_by_state[state]
return arming_time
def _pending_time(self, state: str) -> datetime.timedelta:
def _pending_time(self, state: AlarmControlPanelState) -> datetime.timedelta:
"""Get the pending time."""
delay_time: datetime.timedelta = self._delay_time_by_state[self._previous_state]
return delay_time
def _within_arming_time(self, state: str) -> bool:
def _within_arming_time(self, state: AlarmControlPanelState) -> bool:
"""Get if the action is in the arming time window."""
return self._state_ts + self._arming_time(state) > dt_util.utcnow()
def _within_pending_time(self, state: str) -> bool:
def _within_pending_time(self, state: AlarmControlPanelState) -> bool:
"""Get if the action is in the pending time window."""
return self._state_ts + self._pending_time(state) > dt_util.utcnow()
@ -305,35 +317,35 @@ class ManualAlarm(AlarmControlPanelEntity, RestoreEntity):
async def async_alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
self._async_validate_code(code, STATE_ALARM_DISARMED)
self._state = STATE_ALARM_DISARMED
self._async_validate_code(code, AlarmControlPanelState.DISARMED)
self._state = AlarmControlPanelState.DISARMED
self._state_ts = dt_util.utcnow()
self.async_write_ha_state()
async def async_alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command."""
self._async_validate_code(code, STATE_ALARM_ARMED_HOME)
self._async_update_state(STATE_ALARM_ARMED_HOME)
self._async_validate_code(code, AlarmControlPanelState.ARMED_HOME)
self._async_update_state(AlarmControlPanelState.ARMED_HOME)
async def async_alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command."""
self._async_validate_code(code, STATE_ALARM_ARMED_AWAY)
self._async_update_state(STATE_ALARM_ARMED_AWAY)
self._async_validate_code(code, AlarmControlPanelState.ARMED_AWAY)
self._async_update_state(AlarmControlPanelState.ARMED_AWAY)
async def async_alarm_arm_night(self, code: str | None = None) -> None:
"""Send arm night command."""
self._async_validate_code(code, STATE_ALARM_ARMED_NIGHT)
self._async_update_state(STATE_ALARM_ARMED_NIGHT)
self._async_validate_code(code, AlarmControlPanelState.ARMED_NIGHT)
self._async_update_state(AlarmControlPanelState.ARMED_NIGHT)
async def async_alarm_arm_vacation(self, code: str | None = None) -> None:
"""Send arm vacation command."""
self._async_validate_code(code, STATE_ALARM_ARMED_VACATION)
self._async_update_state(STATE_ALARM_ARMED_VACATION)
self._async_validate_code(code, AlarmControlPanelState.ARMED_VACATION)
self._async_update_state(AlarmControlPanelState.ARMED_VACATION)
async def async_alarm_arm_custom_bypass(self, code: str | None = None) -> None:
"""Send arm custom bypass command."""
self._async_validate_code(code, STATE_ALARM_ARMED_CUSTOM_BYPASS)
self._async_update_state(STATE_ALARM_ARMED_CUSTOM_BYPASS)
self._async_validate_code(code, AlarmControlPanelState.ARMED_CUSTOM_BYPASS)
self._async_update_state(AlarmControlPanelState.ARMED_CUSTOM_BYPASS)
async def async_alarm_trigger(self, code: str | None = None) -> None:
"""Send alarm trigger command.
@ -343,9 +355,9 @@ class ManualAlarm(AlarmControlPanelEntity, RestoreEntity):
"""
if not self._trigger_time_by_state[self._active_state]:
return
self._async_update_state(STATE_ALARM_TRIGGERED)
self._async_update_state(AlarmControlPanelState.TRIGGERED)
def _async_update_state(self, state: str) -> None:
def _async_update_state(self, state: AlarmControlPanelState) -> None:
"""Update the state."""
if self._state == state:
return
@ -358,7 +370,7 @@ class ManualAlarm(AlarmControlPanelEntity, RestoreEntity):
def _async_set_state_update_events(self) -> None:
state = self._state
if state == STATE_ALARM_TRIGGERED:
if state == AlarmControlPanelState.TRIGGERED:
pending_time = self._pending_time(state)
async_track_point_in_time(
self._hass, self.async_scheduled_update, self._state_ts + pending_time
@ -382,7 +394,7 @@ class ManualAlarm(AlarmControlPanelEntity, RestoreEntity):
def _async_validate_code(self, code: str | None, state: str) -> None:
"""Validate given code."""
if (
state != STATE_ALARM_DISARMED and not self.code_arm_required
state != AlarmControlPanelState.DISARMED and not self.code_arm_required
) or self._code is None:
return
@ -405,10 +417,13 @@ class ManualAlarm(AlarmControlPanelEntity, RestoreEntity):
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes."""
if self.state in (STATE_ALARM_PENDING, STATE_ALARM_ARMING):
if self.state in (
AlarmControlPanelState.PENDING,
AlarmControlPanelState.ARMING,
):
prev_state: str | None = self._previous_state
state: str | None = self._state
elif self.state == STATE_ALARM_TRIGGERED:
elif self.state == AlarmControlPanelState.TRIGGERED:
prev_state = self._previous_state
state = None
else:
@ -429,9 +444,9 @@ class ManualAlarm(AlarmControlPanelEntity, RestoreEntity):
if next_state := state.attributes.get(ATTR_NEXT_STATE):
# If in arming or pending state we record the transition,
# not the current state
self._state = next_state
self._state = AlarmControlPanelState(next_state)
else:
self._state = state.state
self._state = AlarmControlPanelState(state.state)
if prev_state := state.attributes.get(ATTR_PREVIOUS_STATE):
self._previous_state = prev_state

View File

@ -12,6 +12,7 @@ from homeassistant.components import mqtt
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.const import (
@ -22,14 +23,6 @@ from homeassistant.const import (
CONF_PENDING_TIME,
CONF_PLATFORM,
CONF_TRIGGER_TIME,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import Event, EventStateChangedData, HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
@ -54,6 +47,15 @@ CONF_PAYLOAD_ARM_NIGHT = "payload_arm_night"
CONF_PAYLOAD_ARM_VACATION = "payload_arm_vacation"
CONF_PAYLOAD_ARM_CUSTOM_BYPASS = "payload_arm_custom_bypass"
CONF_ALARM_ARMED_AWAY = "armed_away"
CONF_ALARM_ARMED_CUSTOM_BYPASS = "armed_custom_bypass"
CONF_ALARM_ARMED_HOME = "armed_home"
CONF_ALARM_ARMED_NIGHT = "armed_night"
CONF_ALARM_ARMED_VACATION = "armed_vacation"
CONF_ALARM_DISARMED = "disarmed"
CONF_ALARM_PENDING = "pending"
CONF_ALARM_TRIGGERED = "triggered"
DEFAULT_ALARM_NAME = "HA Alarm"
DEFAULT_DELAY_TIME = datetime.timedelta(seconds=0)
DEFAULT_PENDING_TIME = datetime.timedelta(seconds=60)
@ -67,21 +69,21 @@ DEFAULT_ARM_CUSTOM_BYPASS = "ARM_CUSTOM_BYPASS"
DEFAULT_DISARM = "DISARM"
SUPPORTED_STATES = [
STATE_ALARM_DISARMED,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_TRIGGERED,
AlarmControlPanelState.DISARMED,
AlarmControlPanelState.ARMED_AWAY,
AlarmControlPanelState.ARMED_HOME,
AlarmControlPanelState.ARMED_NIGHT,
AlarmControlPanelState.ARMED_VACATION,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
AlarmControlPanelState.TRIGGERED,
]
SUPPORTED_PRETRIGGER_STATES = [
state for state in SUPPORTED_STATES if state != STATE_ALARM_TRIGGERED
state for state in SUPPORTED_STATES if state != AlarmControlPanelState.TRIGGERED
]
SUPPORTED_PENDING_STATES = [
state for state in SUPPORTED_STATES if state != STATE_ALARM_DISARMED
state for state in SUPPORTED_STATES if state != AlarmControlPanelState.DISARMED
]
ATTR_PRE_PENDING_STATE = "pre_pending_state"
@ -143,26 +145,26 @@ PLATFORM_SCHEMA = vol.Schema(
vol.Optional(
CONF_DISARM_AFTER_TRIGGER, default=DEFAULT_DISARM_AFTER_TRIGGER
): cv.boolean,
vol.Optional(STATE_ALARM_ARMED_AWAY, default={}): _state_schema(
STATE_ALARM_ARMED_AWAY
vol.Optional(CONF_ALARM_ARMED_AWAY, default={}): _state_schema(
AlarmControlPanelState.ARMED_AWAY
),
vol.Optional(STATE_ALARM_ARMED_HOME, default={}): _state_schema(
STATE_ALARM_ARMED_HOME
vol.Optional(CONF_ALARM_ARMED_HOME, default={}): _state_schema(
AlarmControlPanelState.ARMED_HOME
),
vol.Optional(STATE_ALARM_ARMED_NIGHT, default={}): _state_schema(
STATE_ALARM_ARMED_NIGHT
vol.Optional(CONF_ALARM_ARMED_NIGHT, default={}): _state_schema(
AlarmControlPanelState.ARMED_NIGHT
),
vol.Optional(STATE_ALARM_ARMED_VACATION, default={}): _state_schema(
STATE_ALARM_ARMED_VACATION
vol.Optional(CONF_ALARM_ARMED_VACATION, default={}): _state_schema(
AlarmControlPanelState.ARMED_VACATION
),
vol.Optional(
STATE_ALARM_ARMED_CUSTOM_BYPASS, default={}
): _state_schema(STATE_ALARM_ARMED_CUSTOM_BYPASS),
vol.Optional(STATE_ALARM_DISARMED, default={}): _state_schema(
STATE_ALARM_DISARMED
vol.Optional(CONF_ALARM_ARMED_CUSTOM_BYPASS, default={}): _state_schema(
AlarmControlPanelState.ARMED_CUSTOM_BYPASS
),
vol.Optional(STATE_ALARM_TRIGGERED, default={}): _state_schema(
STATE_ALARM_TRIGGERED
vol.Optional(CONF_ALARM_DISARMED, default={}): _state_schema(
AlarmControlPanelState.DISARMED
),
vol.Optional(CONF_ALARM_TRIGGERED, default={}): _state_schema(
AlarmControlPanelState.TRIGGERED
),
vol.Required(mqtt.CONF_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Required(mqtt.CONF_STATE_TOPIC): mqtt.valid_subscribe_topic,
@ -268,7 +270,7 @@ class ManualMQTTAlarm(AlarmControlPanelEntity):
config,
):
"""Init the manual MQTT alarm panel."""
self._state = STATE_ALARM_DISARMED
self._state = AlarmControlPanelState.DISARMED
self._hass = hass
self._attr_name = name
if code_template:
@ -304,38 +306,38 @@ class ManualMQTTAlarm(AlarmControlPanelEntity):
self._payload_arm_custom_bypass = payload_arm_custom_bypass
@property
def state(self) -> str:
def alarm_state(self) -> AlarmControlPanelState:
"""Return the state of the device."""
if self._state == STATE_ALARM_TRIGGERED:
if self._state == AlarmControlPanelState.TRIGGERED:
if self._within_pending_time(self._state):
return STATE_ALARM_PENDING
return AlarmControlPanelState.PENDING
trigger_time = self._trigger_time_by_state[self._previous_state]
if (
self._state_ts + self._pending_time(self._state) + trigger_time
) < dt_util.utcnow():
if self._disarm_after_trigger:
return STATE_ALARM_DISARMED
return AlarmControlPanelState.DISARMED
self._state = self._previous_state
return self._state
if self._state in SUPPORTED_PENDING_STATES and self._within_pending_time(
self._state
):
return STATE_ALARM_PENDING
return AlarmControlPanelState.PENDING
return self._state
@property
def _active_state(self):
"""Get the current state."""
if self.state == STATE_ALARM_PENDING:
if self.state == AlarmControlPanelState.PENDING:
return self._previous_state
return self._state
def _pending_time(self, state):
"""Get the pending time."""
pending_time = self._pending_time_by_state[state]
if state == STATE_ALARM_TRIGGERED:
if state == AlarmControlPanelState.TRIGGERED:
pending_time += self._delay_time_by_state[self._previous_state]
return pending_time
@ -354,35 +356,35 @@ class ManualMQTTAlarm(AlarmControlPanelEntity):
async def async_alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
self._async_validate_code(code, STATE_ALARM_DISARMED)
self._state = STATE_ALARM_DISARMED
self._async_validate_code(code, AlarmControlPanelState.DISARMED)
self._state = AlarmControlPanelState.DISARMED
self._state_ts = dt_util.utcnow()
self.async_write_ha_state()
async def async_alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command."""
self._async_validate_code(code, STATE_ALARM_ARMED_HOME)
self._async_update_state(STATE_ALARM_ARMED_HOME)
self._async_validate_code(code, AlarmControlPanelState.ARMED_HOME)
self._async_update_state(AlarmControlPanelState.ARMED_HOME)
async def async_alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command."""
self._async_validate_code(code, STATE_ALARM_ARMED_AWAY)
self._async_update_state(STATE_ALARM_ARMED_AWAY)
self._async_validate_code(code, AlarmControlPanelState.ARMED_AWAY)
self._async_update_state(AlarmControlPanelState.ARMED_AWAY)
async def async_alarm_arm_night(self, code: str | None = None) -> None:
"""Send arm night command."""
self._async_validate_code(code, STATE_ALARM_ARMED_NIGHT)
self._async_update_state(STATE_ALARM_ARMED_NIGHT)
self._async_validate_code(code, AlarmControlPanelState.ARMED_NIGHT)
self._async_update_state(AlarmControlPanelState.ARMED_NIGHT)
async def async_alarm_arm_vacation(self, code: str | None = None) -> None:
"""Send arm vacation command."""
self._async_validate_code(code, STATE_ALARM_ARMED_VACATION)
self._async_update_state(STATE_ALARM_ARMED_VACATION)
self._async_validate_code(code, AlarmControlPanelState.ARMED_VACATION)
self._async_update_state(AlarmControlPanelState.ARMED_VACATION)
async def async_alarm_arm_custom_bypass(self, code: str | None = None) -> None:
"""Send arm custom bypass command."""
self._async_validate_code(code, STATE_ALARM_ARMED_CUSTOM_BYPASS)
self._async_update_state(STATE_ALARM_ARMED_CUSTOM_BYPASS)
self._async_validate_code(code, AlarmControlPanelState.ARMED_CUSTOM_BYPASS)
self._async_update_state(AlarmControlPanelState.ARMED_CUSTOM_BYPASS)
async def async_alarm_trigger(self, code: str | None = None) -> None:
"""Send alarm trigger command.
@ -392,7 +394,7 @@ class ManualMQTTAlarm(AlarmControlPanelEntity):
"""
if not self._trigger_time_by_state[self._active_state]:
return
self._async_update_state(STATE_ALARM_TRIGGERED)
self._async_update_state(AlarmControlPanelState.TRIGGERED)
def _async_update_state(self, state: str) -> None:
"""Update the state."""
@ -405,7 +407,7 @@ class ManualMQTTAlarm(AlarmControlPanelEntity):
self.async_write_ha_state()
pending_time = self._pending_time(state)
if state == STATE_ALARM_TRIGGERED:
if state == AlarmControlPanelState.TRIGGERED:
async_track_point_in_time(
self._hass, self.async_scheduled_update, self._state_ts + pending_time
)
@ -424,7 +426,7 @@ class ManualMQTTAlarm(AlarmControlPanelEntity):
def _async_validate_code(self, code, state):
"""Validate given code."""
if (
state != STATE_ALARM_DISARMED and not self.code_arm_required
state != AlarmControlPanelState.DISARMED and not self.code_arm_required
) or self._code is None:
return
@ -443,7 +445,7 @@ class ManualMQTTAlarm(AlarmControlPanelEntity):
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes."""
if self.state != STATE_ALARM_PENDING:
if self.state != AlarmControlPanelState.PENDING:
return {}
return {
ATTR_PRE_PENDING_STATE: self._previous_state,

View File

@ -7,23 +7,12 @@ import logging
import voluptuous as vol
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.components.alarm_control_panel import AlarmControlPanelEntityFeature
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_CODE,
CONF_NAME,
CONF_VALUE_TEMPLATE,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_DISARMING,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_CODE, CONF_NAME, CONF_VALUE_TEMPLATE
from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -182,29 +171,30 @@ class MqttAlarm(MqttEntity, alarm.AlarmControlPanelEntity):
)
return
if payload == PAYLOAD_NONE:
self._attr_state = None
self._attr_alarm_state = None
return
if payload not in (
STATE_ALARM_DISARMED,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_PENDING,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMING,
STATE_ALARM_TRIGGERED,
AlarmControlPanelState.DISARMED,
AlarmControlPanelState.ARMED_HOME,
AlarmControlPanelState.ARMED_AWAY,
AlarmControlPanelState.ARMED_NIGHT,
AlarmControlPanelState.ARMED_VACATION,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
AlarmControlPanelState.PENDING,
AlarmControlPanelState.ARMING,
AlarmControlPanelState.DISARMING,
AlarmControlPanelState.TRIGGERED,
):
_LOGGER.warning("Received unexpected payload: %s", msg.payload)
return
self._attr_state = str(payload)
assert isinstance(payload, str)
self._attr_alarm_state = AlarmControlPanelState(payload)
@callback
def _prepare_subscribe_topics(self) -> None:
"""(Re)Subscribe to topics."""
self.add_subscription(
CONF_STATE_TOPIC, self._state_message_received, {"_attr_state"}
CONF_STATE_TOPIC, self._state_message_received, {"_attr_alarm_state"}
)
async def _subscribe_topics(self) -> None:

View File

@ -9,18 +9,9 @@ from nessclient import ArmingMode, ArmingState, Client
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -31,12 +22,12 @@ from . import DATA_NESS, SIGNAL_ARMING_STATE_CHANGED
_LOGGER = logging.getLogger(__name__)
ARMING_MODE_TO_STATE = {
ArmingMode.ARMED_AWAY: STATE_ALARM_ARMED_AWAY,
ArmingMode.ARMED_HOME: STATE_ALARM_ARMED_HOME,
ArmingMode.ARMED_DAY: STATE_ALARM_ARMED_AWAY, # no applicable state, fallback to away
ArmingMode.ARMED_NIGHT: STATE_ALARM_ARMED_NIGHT,
ArmingMode.ARMED_VACATION: STATE_ALARM_ARMED_VACATION,
ArmingMode.ARMED_HIGHEST: STATE_ALARM_ARMED_AWAY, # no applicable state, fallback to away
ArmingMode.ARMED_AWAY: AlarmControlPanelState.ARMED_AWAY,
ArmingMode.ARMED_HOME: AlarmControlPanelState.ARMED_HOME,
ArmingMode.ARMED_DAY: AlarmControlPanelState.ARMED_AWAY, # no applicable state, fallback to away
ArmingMode.ARMED_NIGHT: AlarmControlPanelState.ARMED_NIGHT,
ArmingMode.ARMED_VACATION: AlarmControlPanelState.ARMED_VACATION,
ArmingMode.ARMED_HIGHEST: AlarmControlPanelState.ARMED_AWAY, # no applicable state, fallback to away
}
@ -101,19 +92,19 @@ class NessAlarmPanel(AlarmControlPanelEntity):
"""Handle arming state update."""
if arming_state == ArmingState.UNKNOWN:
self._attr_state = None
self._attr_alarm_state = None
elif arming_state == ArmingState.DISARMED:
self._attr_state = STATE_ALARM_DISARMED
self._attr_alarm_state = AlarmControlPanelState.DISARMED
elif arming_state in (ArmingState.ARMING, ArmingState.EXIT_DELAY):
self._attr_state = STATE_ALARM_ARMING
self._attr_alarm_state = AlarmControlPanelState.ARMING
elif arming_state == ArmingState.ARMED:
self._attr_state = ARMING_MODE_TO_STATE.get(
arming_mode, STATE_ALARM_ARMED_AWAY
self._attr_alarm_state = ARMING_MODE_TO_STATE.get(
arming_mode, AlarmControlPanelState.ARMED_AWAY
)
elif arming_state == ArmingState.ENTRY_DELAY:
self._attr_state = STATE_ALARM_PENDING
self._attr_alarm_state = AlarmControlPanelState.PENDING
elif arming_state == ArmingState.TRIGGERED:
self._attr_state = STATE_ALARM_TRIGGERED
self._attr_alarm_state = AlarmControlPanelState.TRIGGERED
else:
_LOGGER.warning("Unhandled arming state: %s", arming_state)

View File

@ -13,17 +13,10 @@ from homeassistant.components.alarm_control_panel import (
PLATFORM_SCHEMA as ALARM_CONTROL_PANEL_PLATFORM_SCHEMA,
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.const import (
CONF_HOST,
CONF_NAME,
CONF_PORT,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import PlatformNotReady
from homeassistant.helpers import config_validation as cv, entity_platform
@ -95,7 +88,6 @@ class NX584Alarm(AlarmControlPanelEntity):
"""Representation of a NX584-based alarm panel."""
_attr_code_format = CodeFormat.NUMBER
_attr_state: str | None
_attr_supported_features = (
AlarmControlPanelEntityFeature.ARM_HOME
| AlarmControlPanelEntityFeature.ARM_AWAY
@ -118,11 +110,11 @@ class NX584Alarm(AlarmControlPanelEntity):
"Unable to connect to %(host)s: %(reason)s",
{"host": self._url, "reason": ex},
)
self._attr_state = None
self._attr_alarm_state = None
zones = []
except IndexError:
_LOGGER.error("NX584 reports no partitions")
self._attr_state = None
self._attr_alarm_state = None
zones = []
bypassed = False
@ -136,15 +128,15 @@ class NX584Alarm(AlarmControlPanelEntity):
break
if not part["armed"]:
self._attr_state = STATE_ALARM_DISARMED
self._attr_alarm_state = AlarmControlPanelState.DISARMED
elif bypassed:
self._attr_state = STATE_ALARM_ARMED_HOME
self._attr_alarm_state = AlarmControlPanelState.ARMED_HOME
else:
self._attr_state = STATE_ALARM_ARMED_AWAY
self._attr_alarm_state = AlarmControlPanelState.ARMED_AWAY
for flag in part["condition_flags"]:
if flag == "Siren on":
self._attr_state = STATE_ALARM_TRIGGERED
self._attr_alarm_state = AlarmControlPanelState.TRIGGERED
def alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""

View File

@ -14,18 +14,10 @@ from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityDescription,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
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 import EntityDescription
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -41,7 +33,7 @@ class OverkizAlarmDescription(AlarmControlPanelEntityDescription):
"""Class to describe an Overkiz alarm control panel."""
supported_features: AlarmControlPanelEntityFeature
fn_state: Callable[[Callable[[str], OverkizStateType]], str]
fn_state: Callable[[Callable[[str], OverkizStateType]], AlarmControlPanelState]
alarm_disarm: str | None = None
alarm_disarm_args: OverkizStateType | list[OverkizStateType] = None
@ -55,42 +47,44 @@ class OverkizAlarmDescription(AlarmControlPanelEntityDescription):
alarm_trigger_args: OverkizStateType | list[OverkizStateType] = None
MAP_INTERNAL_STATUS_STATE: dict[str, str] = {
OverkizCommandParam.OFF: STATE_ALARM_DISARMED,
OverkizCommandParam.ZONE_1: STATE_ALARM_ARMED_HOME,
OverkizCommandParam.ZONE_2: STATE_ALARM_ARMED_NIGHT,
OverkizCommandParam.TOTAL: STATE_ALARM_ARMED_AWAY,
MAP_INTERNAL_STATUS_STATE: dict[str, AlarmControlPanelState] = {
OverkizCommandParam.OFF: AlarmControlPanelState.DISARMED,
OverkizCommandParam.ZONE_1: AlarmControlPanelState.ARMED_HOME,
OverkizCommandParam.ZONE_2: AlarmControlPanelState.ARMED_NIGHT,
OverkizCommandParam.TOTAL: AlarmControlPanelState.ARMED_AWAY,
}
def _state_tsk_alarm_controller(select_state: Callable[[str], OverkizStateType]) -> str:
def _state_tsk_alarm_controller(
select_state: Callable[[str], OverkizStateType],
) -> AlarmControlPanelState:
"""Return the state of the device."""
if (
cast(str, select_state(OverkizState.INTERNAL_INTRUSION_DETECTED))
== OverkizCommandParam.DETECTED
):
return STATE_ALARM_TRIGGERED
return AlarmControlPanelState.TRIGGERED
if cast(str, select_state(OverkizState.INTERNAL_CURRENT_ALARM_MODE)) != cast(
str, select_state(OverkizState.INTERNAL_TARGET_ALARM_MODE)
):
return STATE_ALARM_PENDING
return AlarmControlPanelState.PENDING
return MAP_INTERNAL_STATUS_STATE[
cast(str, select_state(OverkizState.INTERNAL_TARGET_ALARM_MODE))
]
MAP_CORE_ACTIVE_ZONES: dict[str, str] = {
OverkizCommandParam.A: STATE_ALARM_ARMED_HOME,
f"{OverkizCommandParam.A},{OverkizCommandParam.B}": STATE_ALARM_ARMED_NIGHT,
f"{OverkizCommandParam.A},{OverkizCommandParam.B},{OverkizCommandParam.C}": STATE_ALARM_ARMED_AWAY,
MAP_CORE_ACTIVE_ZONES: dict[str, AlarmControlPanelState] = {
OverkizCommandParam.A: AlarmControlPanelState.ARMED_HOME,
f"{OverkizCommandParam.A},{OverkizCommandParam.B}": AlarmControlPanelState.ARMED_NIGHT,
f"{OverkizCommandParam.A},{OverkizCommandParam.B},{OverkizCommandParam.C}": AlarmControlPanelState.ARMED_AWAY,
}
def _state_stateful_alarm_controller(
select_state: Callable[[str], OverkizStateType],
) -> str:
) -> AlarmControlPanelState:
"""Return the state of the device."""
if state := cast(str, select_state(OverkizState.CORE_ACTIVE_ZONES)):
# The Stateful Alarm Controller has 3 zones with the following options:
@ -99,44 +93,44 @@ def _state_stateful_alarm_controller(
if state in MAP_CORE_ACTIVE_ZONES:
return MAP_CORE_ACTIVE_ZONES[state]
return STATE_ALARM_ARMED_CUSTOM_BYPASS
return AlarmControlPanelState.ARMED_CUSTOM_BYPASS
return STATE_ALARM_DISARMED
return AlarmControlPanelState.DISARMED
MAP_MYFOX_STATUS_STATE: dict[str, str] = {
OverkizCommandParam.ARMED: STATE_ALARM_ARMED_AWAY,
OverkizCommandParam.DISARMED: STATE_ALARM_DISARMED,
OverkizCommandParam.PARTIAL: STATE_ALARM_ARMED_NIGHT,
MAP_MYFOX_STATUS_STATE: dict[str, AlarmControlPanelState] = {
OverkizCommandParam.ARMED: AlarmControlPanelState.ARMED_AWAY,
OverkizCommandParam.DISARMED: AlarmControlPanelState.DISARMED,
OverkizCommandParam.PARTIAL: AlarmControlPanelState.ARMED_NIGHT,
}
def _state_myfox_alarm_controller(
select_state: Callable[[str], OverkizStateType],
) -> str:
) -> AlarmControlPanelState:
"""Return the state of the device."""
if (
cast(str, select_state(OverkizState.CORE_INTRUSION))
== OverkizCommandParam.DETECTED
):
return STATE_ALARM_TRIGGERED
return AlarmControlPanelState.TRIGGERED
return MAP_MYFOX_STATUS_STATE[
cast(str, select_state(OverkizState.MYFOX_ALARM_STATUS))
]
MAP_ARM_TYPE: dict[str, str] = {
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,
MAP_ARM_TYPE: dict[str, AlarmControlPanelState] = {
OverkizCommandParam.DISARMED: AlarmControlPanelState.DISARMED,
OverkizCommandParam.ARMED_DAY: AlarmControlPanelState.ARMED_HOME,
OverkizCommandParam.ARMED_NIGHT: AlarmControlPanelState.ARMED_NIGHT,
OverkizCommandParam.ARMED: AlarmControlPanelState.ARMED_AWAY,
}
def _state_alarm_panel_controller(
select_state: Callable[[str], OverkizStateType],
) -> str:
) -> AlarmControlPanelState:
"""Return the state of the device."""
return MAP_ARM_TYPE[
cast(str, select_state(OverkizState.VERISURE_ALARM_PANEL_MAIN_ARM_TYPE))
@ -254,7 +248,7 @@ class OverkizAlarmControlPanel(OverkizDescriptiveEntity, AlarmControlPanelEntity
self._attr_supported_features = self.entity_description.supported_features
@property
def state(self) -> str:
def alarm_state(self) -> AlarmControlPanelState:
"""Return the state of the device."""
return self.entity_description.fn_state(self.executor.select_state)

View File

@ -9,13 +9,9 @@ from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_CONTROL_PANEL_DOMAIN,
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.dispatcher import async_dispatcher_connect
@ -28,9 +24,9 @@ _LOGGER = logging.getLogger(__name__)
EVENT_MAP = {
"off": STATE_ALARM_DISARMED,
"alarm_silenced": STATE_ALARM_DISARMED,
"alarm_grace_period_expired": STATE_ALARM_TRIGGERED,
"off": AlarmControlPanelState.DISARMED,
"alarm_silenced": AlarmControlPanelState.DISARMED,
"alarm_grace_period_expired": AlarmControlPanelState.TRIGGERED,
}
@ -103,9 +99,11 @@ class MinutPointAlarmControl(AlarmControlPanelEntity):
self.async_write_ha_state()
@property
def state(self) -> str:
def alarm_state(self) -> AlarmControlPanelState:
"""Return state of the device."""
return EVENT_MAP.get(self._home["alarm_status"], STATE_ALARM_ARMED_AWAY)
return EVENT_MAP.get(
self._home["alarm_status"], AlarmControlPanelState.ARMED_AWAY
)
async def async_alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""

View File

@ -14,6 +14,7 @@ from prometheus_client.metrics import MetricWrapperBase
import voluptuous as vol
from homeassistant import core as hacore
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
from homeassistant.components.climate import (
ATTR_CURRENT_TEMPERATURE,
ATTR_FAN_MODE,
@ -51,16 +52,6 @@ from homeassistant.const import (
CONTENT_TYPE_TEXT_PLAIN,
EVENT_STATE_CHANGED,
PERCENTAGE,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_DISARMING,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
STATE_CLOSED,
STATE_CLOSING,
STATE_ON,
@ -828,22 +819,9 @@ class PrometheusMetrics:
["state"],
)
alarm_states = [
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
STATE_ALARM_PENDING,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMING,
]
for alarm_state in alarm_states:
metric.labels(**dict(self._labels(state), state=alarm_state)).set(
float(alarm_state == current_state)
for alarm_state in AlarmControlPanelState:
metric.labels(**dict(self._labels(state), state=alarm_state.value)).set(
float(alarm_state.value == current_state)
)

View File

@ -10,13 +10,9 @@ from pyprosegur.installation import Installation, Status
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -26,10 +22,10 @@ from . import DOMAIN
_LOGGER = logging.getLogger(__name__)
STATE_MAPPING = {
Status.DISARMED: STATE_ALARM_DISARMED,
Status.ARMED: STATE_ALARM_ARMED_AWAY,
Status.PARTIALLY: STATE_ALARM_ARMED_HOME,
Status.ERROR_PARTIALLY: STATE_ALARM_ARMED_HOME,
Status.DISARMED: AlarmControlPanelState.DISARMED,
Status.ARMED: AlarmControlPanelState.ARMED_AWAY,
Status.PARTIALLY: AlarmControlPanelState.ARMED_HOME,
Status.ERROR_PARTIALLY: AlarmControlPanelState.ARMED_HOME,
}
@ -82,7 +78,7 @@ class ProsegurAlarm(AlarmControlPanelEntity):
self._attr_available = False
return
self._attr_state = STATE_MAPPING.get(self._installation.status)
self._attr_alarm_state = STATE_MAPPING.get(self._installation.status)
self._attr_available = True
async def async_alarm_disarm(self, code: str | None = None) -> None:

View File

@ -12,19 +12,11 @@ from pyrisco.local.partition import Partition as LocalPartition
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_PIN,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.const import CONF_PIN
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -48,10 +40,10 @@ from .entity import RiscoCloudEntity
_LOGGER = logging.getLogger(__name__)
STATES_TO_SUPPORTED_FEATURES = {
STATE_ALARM_ARMED_AWAY: AlarmControlPanelEntityFeature.ARM_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS: AlarmControlPanelEntityFeature.ARM_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME: AlarmControlPanelEntityFeature.ARM_HOME,
STATE_ALARM_ARMED_NIGHT: AlarmControlPanelEntityFeature.ARM_NIGHT,
AlarmControlPanelState.ARMED_AWAY: AlarmControlPanelEntityFeature.ARM_AWAY,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS: AlarmControlPanelEntityFeature.ARM_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_HOME: AlarmControlPanelEntityFeature.ARM_HOME,
AlarmControlPanelState.ARMED_NIGHT: AlarmControlPanelEntityFeature.ARM_NIGHT,
}
@ -116,14 +108,14 @@ class RiscoAlarm(AlarmControlPanelEntity):
self._attr_supported_features |= STATES_TO_SUPPORTED_FEATURES[state]
@property
def state(self) -> str | None:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the device."""
if self._partition.triggered:
return STATE_ALARM_TRIGGERED
return AlarmControlPanelState.TRIGGERED
if self._partition.arming:
return STATE_ALARM_ARMING
return AlarmControlPanelState.ARMING
if self._partition.disarmed:
return STATE_ALARM_DISARMED
return AlarmControlPanelState.DISARMED
if self._partition.armed:
return self._risco_to_ha[RISCO_ARM]
if self._partition.partially_armed:
@ -148,21 +140,21 @@ class RiscoAlarm(AlarmControlPanelEntity):
async def async_alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command."""
await self._arm(STATE_ALARM_ARMED_HOME, code)
await self._arm(AlarmControlPanelState.ARMED_HOME, code)
async def async_alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command."""
await self._arm(STATE_ALARM_ARMED_AWAY, code)
await self._arm(AlarmControlPanelState.ARMED_AWAY, code)
async def async_alarm_arm_night(self, code: str | None = None) -> None:
"""Send arm night command."""
await self._arm(STATE_ALARM_ARMED_NIGHT, code)
await self._arm(AlarmControlPanelState.ARMED_NIGHT, code)
async def async_alarm_arm_custom_bypass(self, code: str | None = None) -> None:
"""Send arm custom bypass command."""
await self._arm(STATE_ALARM_ARMED_CUSTOM_BYPASS, code)
await self._arm(AlarmControlPanelState.ARMED_CUSTOM_BYPASS, code)
async def _arm(self, mode: str, code: str | None) -> None:
async def _arm(self, mode: AlarmControlPanelState, code: str | None) -> None:
if self.code_arm_required and not self._validate_code(code):
_LOGGER.warning("Wrong code entered for %s", mode)
return

View File

@ -9,6 +9,7 @@ from typing import Any
from pyrisco import CannotConnectError, RiscoCloud, RiscoLocal, UnauthorizedError
import voluptuous as vol
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
from homeassistant.config_entries import (
ConfigEntry,
ConfigFlow,
@ -23,10 +24,6 @@ from homeassistant.const import (
CONF_SCAN_INTERVAL,
CONF_TYPE,
CONF_USERNAME,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.aiohttp_client import async_get_clientsession
@ -64,10 +61,10 @@ LOCAL_SCHEMA = vol.Schema(
}
)
HA_STATES = [
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_AWAY.value,
AlarmControlPanelState.ARMED_HOME.value,
AlarmControlPanelState.ARMED_NIGHT.value,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS.value,
]

View File

@ -1,10 +1,7 @@
"""Constants for the Risco integration."""
from homeassistant.const import (
CONF_SCAN_INTERVAL,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
)
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
from homeassistant.const import CONF_SCAN_INTERVAL
DOMAIN = "risco"
@ -33,16 +30,18 @@ RISCO_ARM = "arm"
RISCO_PARTIAL_ARM = "partial_arm"
RISCO_STATES = [RISCO_ARM, RISCO_PARTIAL_ARM, *RISCO_GROUPS]
DEFAULT_RISCO_GROUPS_TO_HA = {group: STATE_ALARM_ARMED_HOME for group in RISCO_GROUPS}
DEFAULT_RISCO_GROUPS_TO_HA = {
group: AlarmControlPanelState.ARMED_HOME for group in RISCO_GROUPS
}
DEFAULT_RISCO_STATES_TO_HA = {
RISCO_ARM: STATE_ALARM_ARMED_AWAY,
RISCO_PARTIAL_ARM: STATE_ALARM_ARMED_HOME,
RISCO_ARM: AlarmControlPanelState.ARMED_AWAY,
RISCO_PARTIAL_ARM: AlarmControlPanelState.ARMED_HOME,
**DEFAULT_RISCO_GROUPS_TO_HA,
}
DEFAULT_HA_STATES_TO_RISCO = {
STATE_ALARM_ARMED_AWAY: RISCO_ARM,
STATE_ALARM_ARMED_HOME: RISCO_PARTIAL_ARM,
AlarmControlPanelState.ARMED_AWAY: RISCO_ARM,
AlarmControlPanelState.ARMED_HOME: RISCO_PARTIAL_ARM,
}
DEFAULT_OPTIONS = {

View File

@ -11,15 +11,9 @@ from satel_integra.satel_integra import AlarmState
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -67,7 +61,6 @@ class SatelIntegraAlarmPanel(AlarmControlPanelEntity):
_attr_code_format = CodeFormat.NUMBER
_attr_should_poll = False
_attr_state: str | None
_attr_supported_features = (
AlarmControlPanelEntityFeature.ARM_HOME
| AlarmControlPanelEntityFeature.ARM_AWAY
@ -95,8 +88,8 @@ class SatelIntegraAlarmPanel(AlarmControlPanelEntity):
"""Handle alarm status update."""
state = self._read_alarm_state()
_LOGGER.debug("Got status update, current status: %s", state)
if state != self._attr_state:
self._attr_state = state
if state != self._attr_alarm_state:
self._attr_alarm_state = state
self.async_write_ha_state()
else:
_LOGGER.debug("Ignoring alarm status message, same state")
@ -105,22 +98,28 @@ class SatelIntegraAlarmPanel(AlarmControlPanelEntity):
"""Read current status of the alarm and translate it into HA status."""
# Default - disarmed:
hass_alarm_status = STATE_ALARM_DISARMED
hass_alarm_status = AlarmControlPanelState.DISARMED
if not self._satel.connected:
return None
state_map = OrderedDict(
[
(AlarmState.TRIGGERED, STATE_ALARM_TRIGGERED),
(AlarmState.TRIGGERED_FIRE, STATE_ALARM_TRIGGERED),
(AlarmState.ENTRY_TIME, STATE_ALARM_PENDING),
(AlarmState.ARMED_MODE3, STATE_ALARM_ARMED_HOME),
(AlarmState.ARMED_MODE2, STATE_ALARM_ARMED_HOME),
(AlarmState.ARMED_MODE1, STATE_ALARM_ARMED_HOME),
(AlarmState.ARMED_MODE0, STATE_ALARM_ARMED_AWAY),
(AlarmState.EXIT_COUNTDOWN_OVER_10, STATE_ALARM_PENDING),
(AlarmState.EXIT_COUNTDOWN_UNDER_10, STATE_ALARM_PENDING),
(AlarmState.TRIGGERED, AlarmControlPanelState.TRIGGERED),
(AlarmState.TRIGGERED_FIRE, AlarmControlPanelState.TRIGGERED),
(AlarmState.ENTRY_TIME, AlarmControlPanelState.PENDING),
(AlarmState.ARMED_MODE3, AlarmControlPanelState.ARMED_HOME),
(AlarmState.ARMED_MODE2, AlarmControlPanelState.ARMED_HOME),
(AlarmState.ARMED_MODE1, AlarmControlPanelState.ARMED_HOME),
(AlarmState.ARMED_MODE0, AlarmControlPanelState.ARMED_AWAY),
(
AlarmState.EXIT_COUNTDOWN_OVER_10,
AlarmControlPanelState.PENDING,
),
(
AlarmState.EXIT_COUNTDOWN_UNDER_10,
AlarmControlPanelState.PENDING,
),
]
)
_LOGGER.debug("State map of Satel: %s", self._satel.partition_states)
@ -141,9 +140,11 @@ class SatelIntegraAlarmPanel(AlarmControlPanelEntity):
_LOGGER.debug("Code was empty or None")
return
clear_alarm_necessary = self._attr_state == STATE_ALARM_TRIGGERED
clear_alarm_necessary = (
self._attr_alarm_state == AlarmControlPanelState.TRIGGERED
)
_LOGGER.debug("Disarming, self._attr_state: %s", self._attr_state)
_LOGGER.debug("Disarming, self._attr_alarm_state: %s", self._attr_alarm_state)
await self._satel.disarm(code, [self._partition_id])

View File

@ -4,25 +4,19 @@ from __future__ import annotations
from dataclasses import dataclass
import logging
from typing import TYPE_CHECKING
from pysiaalarm import SIAEvent
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityDescription,
AlarmControlPanelState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
STATE_UNAVAILABLE,
)
from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN
from homeassistant.core import HomeAssistant, State
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from .const import CONF_ACCOUNT, CONF_ACCOUNTS, CONF_ZONES, KEY_ALARM, PREVIOUS_STATE
from .entity import SIABaseEntity, SIAEntityDescription
@ -41,32 +35,32 @@ class SIAAlarmControlPanelEntityDescription(
ENTITY_DESCRIPTION_ALARM = SIAAlarmControlPanelEntityDescription(
key=KEY_ALARM,
code_consequences={
"PA": STATE_ALARM_TRIGGERED,
"JA": STATE_ALARM_TRIGGERED,
"TA": STATE_ALARM_TRIGGERED,
"BA": STATE_ALARM_TRIGGERED,
"HA": STATE_ALARM_TRIGGERED,
"CA": STATE_ALARM_ARMED_AWAY,
"CB": STATE_ALARM_ARMED_AWAY,
"CG": STATE_ALARM_ARMED_AWAY,
"CL": STATE_ALARM_ARMED_AWAY,
"CP": STATE_ALARM_ARMED_AWAY,
"CQ": STATE_ALARM_ARMED_AWAY,
"CS": STATE_ALARM_ARMED_AWAY,
"CF": STATE_ALARM_ARMED_CUSTOM_BYPASS,
"NP": STATE_ALARM_DISARMED,
"NO": STATE_ALARM_DISARMED,
"OA": STATE_ALARM_DISARMED,
"OB": STATE_ALARM_DISARMED,
"OG": STATE_ALARM_DISARMED,
"OP": STATE_ALARM_DISARMED,
"OQ": STATE_ALARM_DISARMED,
"OR": STATE_ALARM_DISARMED,
"OS": STATE_ALARM_DISARMED,
"NC": STATE_ALARM_ARMED_NIGHT,
"NL": STATE_ALARM_ARMED_NIGHT,
"NE": STATE_ALARM_ARMED_NIGHT,
"NF": STATE_ALARM_ARMED_NIGHT,
"PA": AlarmControlPanelState.TRIGGERED,
"JA": AlarmControlPanelState.TRIGGERED,
"TA": AlarmControlPanelState.TRIGGERED,
"BA": AlarmControlPanelState.TRIGGERED,
"HA": AlarmControlPanelState.TRIGGERED,
"CA": AlarmControlPanelState.ARMED_AWAY,
"CB": AlarmControlPanelState.ARMED_AWAY,
"CG": AlarmControlPanelState.ARMED_AWAY,
"CL": AlarmControlPanelState.ARMED_AWAY,
"CP": AlarmControlPanelState.ARMED_AWAY,
"CQ": AlarmControlPanelState.ARMED_AWAY,
"CS": AlarmControlPanelState.ARMED_AWAY,
"CF": AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
"NP": AlarmControlPanelState.DISARMED,
"NO": AlarmControlPanelState.DISARMED,
"OA": AlarmControlPanelState.DISARMED,
"OB": AlarmControlPanelState.DISARMED,
"OG": AlarmControlPanelState.DISARMED,
"OP": AlarmControlPanelState.DISARMED,
"OQ": AlarmControlPanelState.DISARMED,
"OR": AlarmControlPanelState.DISARMED,
"OS": AlarmControlPanelState.DISARMED,
"NC": AlarmControlPanelState.ARMED_NIGHT,
"NL": AlarmControlPanelState.ARMED_NIGHT,
"NE": AlarmControlPanelState.ARMED_NIGHT,
"NF": AlarmControlPanelState.ARMED_NIGHT,
"BR": PREVIOUS_STATE,
},
)
@ -110,13 +104,17 @@ class SIAAlarmControlPanel(SIABaseEntity, AlarmControlPanelEntity):
entity_description,
)
self._attr_state: StateType = None
self._old_state: StateType = None
self._attr_alarm_state: AlarmControlPanelState | None = None
self._old_state: AlarmControlPanelState | None = None
def handle_last_state(self, last_state: State | None) -> None:
"""Handle the last state."""
if last_state is not None:
self._attr_state = last_state.state
self._attr_alarm_state = None
if last_state is not None and last_state.state not in (
STATE_UNAVAILABLE,
STATE_UNKNOWN,
):
self._attr_alarm_state = AlarmControlPanelState(last_state.state)
if self.state == STATE_UNAVAILABLE:
self._attr_available = False
@ -133,5 +131,7 @@ class SIAAlarmControlPanel(SIABaseEntity, AlarmControlPanelEntity):
_LOGGER.debug("New state will be %s", new_state)
if new_state == PREVIOUS_STATE:
new_state = self._old_state
self._attr_state, self._old_state = new_state, self._attr_state
if TYPE_CHECKING:
assert isinstance(new_state, AlarmControlPanelState)
self._attr_alarm_state, self._old_state = new_state, self._attr_alarm_state
return True

View File

@ -8,6 +8,7 @@ import logging
from pysiaalarm import SIAEvent
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PORT
from homeassistant.core import CALLBACK_TYPE, State, callback
@ -40,7 +41,7 @@ _LOGGER = logging.getLogger(__name__)
class SIARequiredKeysMixin:
"""Required keys for SIA entities."""
code_consequences: dict[str, StateType | bool]
code_consequences: dict[str, StateType | bool | AlarmControlPanelState]
@dataclass(frozen=True)

View File

@ -26,16 +26,9 @@ from simplipy.websocket import (
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -65,33 +58,33 @@ ATTR_WALL_POWER_LEVEL = "wall_power_level"
ATTR_WIFI_STRENGTH = "wifi_strength"
STATE_MAP_FROM_REST_API = {
SystemStates.ALARM: STATE_ALARM_TRIGGERED,
SystemStates.ALARM_COUNT: STATE_ALARM_PENDING,
SystemStates.AWAY: STATE_ALARM_ARMED_AWAY,
SystemStates.AWAY_COUNT: STATE_ALARM_ARMING,
SystemStates.ENTRY_DELAY: STATE_ALARM_PENDING,
SystemStates.EXIT_DELAY: STATE_ALARM_ARMING,
SystemStates.HOME: STATE_ALARM_ARMED_HOME,
SystemStates.HOME_COUNT: STATE_ALARM_ARMING,
SystemStates.OFF: STATE_ALARM_DISARMED,
SystemStates.TEST: STATE_ALARM_DISARMED,
SystemStates.ALARM: AlarmControlPanelState.TRIGGERED,
SystemStates.ALARM_COUNT: AlarmControlPanelState.PENDING,
SystemStates.AWAY: AlarmControlPanelState.ARMED_AWAY,
SystemStates.AWAY_COUNT: AlarmControlPanelState.ARMING,
SystemStates.ENTRY_DELAY: AlarmControlPanelState.PENDING,
SystemStates.EXIT_DELAY: AlarmControlPanelState.ARMING,
SystemStates.HOME: AlarmControlPanelState.ARMED_HOME,
SystemStates.HOME_COUNT: AlarmControlPanelState.ARMING,
SystemStates.OFF: AlarmControlPanelState.DISARMED,
SystemStates.TEST: AlarmControlPanelState.DISARMED,
}
STATE_MAP_FROM_WEBSOCKET_EVENT = {
EVENT_ALARM_CANCELED: STATE_ALARM_DISARMED,
EVENT_ALARM_TRIGGERED: STATE_ALARM_TRIGGERED,
EVENT_ARMED_AWAY: STATE_ALARM_ARMED_AWAY,
EVENT_ARMED_AWAY_BY_KEYPAD: STATE_ALARM_ARMED_AWAY,
EVENT_ARMED_AWAY_BY_REMOTE: STATE_ALARM_ARMED_AWAY,
EVENT_ARMED_HOME: STATE_ALARM_ARMED_HOME,
EVENT_AWAY_EXIT_DELAY_BY_KEYPAD: STATE_ALARM_ARMING,
EVENT_AWAY_EXIT_DELAY_BY_REMOTE: STATE_ALARM_ARMING,
EVENT_DISARMED_BY_KEYPAD: STATE_ALARM_DISARMED,
EVENT_DISARMED_BY_REMOTE: STATE_ALARM_DISARMED,
EVENT_ENTRY_DELAY: STATE_ALARM_PENDING,
EVENT_HOME_EXIT_DELAY: STATE_ALARM_ARMING,
EVENT_SECRET_ALERT_TRIGGERED: STATE_ALARM_TRIGGERED,
EVENT_USER_INITIATED_TEST: STATE_ALARM_DISARMED,
EVENT_ALARM_CANCELED: AlarmControlPanelState.DISARMED,
EVENT_ALARM_TRIGGERED: AlarmControlPanelState.TRIGGERED,
EVENT_ARMED_AWAY: AlarmControlPanelState.ARMED_AWAY,
EVENT_ARMED_AWAY_BY_KEYPAD: AlarmControlPanelState.ARMED_AWAY,
EVENT_ARMED_AWAY_BY_REMOTE: AlarmControlPanelState.ARMED_AWAY,
EVENT_ARMED_HOME: AlarmControlPanelState.ARMED_HOME,
EVENT_AWAY_EXIT_DELAY_BY_KEYPAD: AlarmControlPanelState.ARMING,
EVENT_AWAY_EXIT_DELAY_BY_REMOTE: AlarmControlPanelState.ARMING,
EVENT_DISARMED_BY_KEYPAD: AlarmControlPanelState.DISARMED,
EVENT_DISARMED_BY_REMOTE: AlarmControlPanelState.DISARMED,
EVENT_ENTRY_DELAY: AlarmControlPanelState.PENDING,
EVENT_HOME_EXIT_DELAY: AlarmControlPanelState.ARMING,
EVENT_SECRET_ALERT_TRIGGERED: AlarmControlPanelState.TRIGGERED,
EVENT_USER_INITIATED_TEST: AlarmControlPanelState.DISARMED,
}
WEBSOCKET_EVENTS_TO_LISTEN_FOR = (
@ -145,9 +138,9 @@ class SimpliSafeAlarm(SimpliSafeEntity, AlarmControlPanelEntity):
def _set_state_from_system_data(self) -> None:
"""Set the state based on the latest REST API data."""
if self._system.alarm_going_off:
self._attr_state = STATE_ALARM_TRIGGERED
self._attr_alarm_state = AlarmControlPanelState.TRIGGERED
elif state := STATE_MAP_FROM_REST_API.get(self._system.state):
self._attr_state = state
self._attr_alarm_state = state
self.async_reset_error_count()
else:
LOGGER.warning("Unexpected system state (REST API): %s", self._system.state)
@ -162,7 +155,7 @@ class SimpliSafeAlarm(SimpliSafeEntity, AlarmControlPanelEntity):
f'Error while disarming "{self._system.system_id}": {err}'
) from err
self._attr_state = STATE_ALARM_DISARMED
self._attr_alarm_state = AlarmControlPanelState.DISARMED
self.async_write_ha_state()
async def async_alarm_arm_home(self, code: str | None = None) -> None:
@ -174,7 +167,7 @@ class SimpliSafeAlarm(SimpliSafeEntity, AlarmControlPanelEntity):
f'Error while arming (home) "{self._system.system_id}": {err}'
) from err
self._attr_state = STATE_ALARM_ARMED_HOME
self._attr_alarm_state = AlarmControlPanelState.ARMED_HOME
self.async_write_ha_state()
async def async_alarm_arm_away(self, code: str | None = None) -> None:
@ -186,7 +179,7 @@ class SimpliSafeAlarm(SimpliSafeEntity, AlarmControlPanelEntity):
f'Error while arming (away) "{self._system.system_id}": {err}'
) from err
self._attr_state = STATE_ALARM_ARMING
self._attr_alarm_state = AlarmControlPanelState.ARMING
self.async_write_ha_state()
@callback
@ -230,7 +223,7 @@ class SimpliSafeAlarm(SimpliSafeEntity, AlarmControlPanelEntity):
assert event.event_type
if state := STATE_MAP_FROM_WEBSOCKET_EVENT.get(event.event_type):
self._attr_state = state
self._attr_alarm_state = state
self.async_reset_error_count()
else:
LOGGER.error("Unknown alarm websocket event: %s", event.event_type)

View File

@ -9,13 +9,7 @@ from pyspcwebgw.const import AreaMode
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
)
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
AlarmControlPanelState,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
@ -25,17 +19,17 @@ from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import DATA_API, SIGNAL_UPDATE_ALARM
def _get_alarm_state(area: Area) -> str | None:
def _get_alarm_state(area: Area) -> AlarmControlPanelState | None:
"""Get the alarm state."""
if area.verified_alarm:
return STATE_ALARM_TRIGGERED
return AlarmControlPanelState.TRIGGERED
mode_to_state = {
AreaMode.UNSET: STATE_ALARM_DISARMED,
AreaMode.PART_SET_A: STATE_ALARM_ARMED_HOME,
AreaMode.PART_SET_B: STATE_ALARM_ARMED_NIGHT,
AreaMode.FULL_SET: STATE_ALARM_ARMED_AWAY,
AreaMode.UNSET: AlarmControlPanelState.DISARMED,
AreaMode.PART_SET_A: AlarmControlPanelState.ARMED_HOME,
AreaMode.PART_SET_B: AlarmControlPanelState.ARMED_NIGHT,
AreaMode.FULL_SET: AlarmControlPanelState.ARMED_AWAY,
}
return mode_to_state.get(area.mode)
@ -91,7 +85,7 @@ class SpcAlarm(AlarmControlPanelEntity):
return self._area.last_changed_by
@property
def state(self) -> str | None:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the device."""
return _get_alarm_state(self._area)

View File

@ -13,6 +13,7 @@ from homeassistant.components.alarm_control_panel import (
PLATFORM_SCHEMA as ALARM_CONTROL_PANEL_PLATFORM_SCHEMA,
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.config_entries import ConfigEntry
@ -22,15 +23,6 @@ from homeassistant.const import (
CONF_NAME,
CONF_UNIQUE_ID,
CONF_VALUE_TEMPLATE,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
)
@ -51,15 +43,15 @@ from .template_entity import TemplateEntity, rewrite_common_legacy_to_modern_con
_LOGGER = logging.getLogger(__name__)
_VALID_STATES = [
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
AlarmControlPanelState.ARMED_AWAY,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_HOME,
AlarmControlPanelState.ARMED_NIGHT,
AlarmControlPanelState.ARMED_VACATION,
AlarmControlPanelState.ARMING,
AlarmControlPanelState.DISARMED,
AlarmControlPanelState.PENDING,
AlarmControlPanelState.TRIGGERED,
STATE_UNAVAILABLE,
]
@ -233,7 +225,7 @@ class AlarmControlPanelTemplate(TemplateEntity, AlarmControlPanelEntity, Restore
if (trigger_action := config.get(CONF_TRIGGER_ACTION)) is not None:
self._trigger_script = Script(hass, trigger_action, name, DOMAIN)
self._state: str | None = None
self._state: AlarmControlPanelState | None = None
self._attr_device_info = async_device_info_to_link_from_device_id(
hass,
config.get(CONF_DEVICE_ID),
@ -281,10 +273,10 @@ class AlarmControlPanelTemplate(TemplateEntity, AlarmControlPanelEntity, Restore
# then we should not restore state
and self._state is None
):
self._state = last_state.state
self._state = AlarmControlPanelState(last_state.state)
@property
def state(self) -> str | None:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the device."""
return self._state
@ -335,31 +327,39 @@ class AlarmControlPanelTemplate(TemplateEntity, AlarmControlPanelEntity, Restore
async def async_alarm_arm_away(self, code: str | None = None) -> None:
"""Arm the panel to Away."""
await self._async_alarm_arm(
STATE_ALARM_ARMED_AWAY, script=self._arm_away_script, code=code
AlarmControlPanelState.ARMED_AWAY,
script=self._arm_away_script,
code=code,
)
async def async_alarm_arm_home(self, code: str | None = None) -> None:
"""Arm the panel to Home."""
await self._async_alarm_arm(
STATE_ALARM_ARMED_HOME, script=self._arm_home_script, code=code
AlarmControlPanelState.ARMED_HOME,
script=self._arm_home_script,
code=code,
)
async def async_alarm_arm_night(self, code: str | None = None) -> None:
"""Arm the panel to Night."""
await self._async_alarm_arm(
STATE_ALARM_ARMED_NIGHT, script=self._arm_night_script, code=code
AlarmControlPanelState.ARMED_NIGHT,
script=self._arm_night_script,
code=code,
)
async def async_alarm_arm_vacation(self, code: str | None = None) -> None:
"""Arm the panel to Vacation."""
await self._async_alarm_arm(
STATE_ALARM_ARMED_VACATION, script=self._arm_vacation_script, code=code
AlarmControlPanelState.ARMED_VACATION,
script=self._arm_vacation_script,
code=code,
)
async def async_alarm_arm_custom_bypass(self, code: str | None = None) -> None:
"""Arm the panel to Custom Bypass."""
await self._async_alarm_arm(
STATE_ALARM_ARMED_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
script=self._arm_custom_bypass_script,
code=code,
)
@ -367,11 +367,13 @@ class AlarmControlPanelTemplate(TemplateEntity, AlarmControlPanelEntity, Restore
async def async_alarm_disarm(self, code: str | None = None) -> None:
"""Disarm the panel."""
await self._async_alarm_arm(
STATE_ALARM_DISARMED, script=self._disarm_script, code=code
AlarmControlPanelState.DISARMED, script=self._disarm_script, code=code
)
async def async_alarm_trigger(self, code: str | None = None) -> None:
"""Trigger the panel."""
await self._async_alarm_arm(
STATE_ALARM_TRIGGERED, script=self._trigger_script, code=code
AlarmControlPanelState.TRIGGERED,
script=self._trigger_script,
code=code,
)

View File

@ -9,19 +9,10 @@ from total_connect_client.location import TotalConnectLocation
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_DISARMING,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.helpers import entity_platform
@ -103,7 +94,7 @@ class TotalConnectAlarm(TotalConnectLocationEntity, AlarmControlPanelEntity):
self._attr_code_format = CodeFormat.NUMBER
@property
def state(self) -> str | None:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the device."""
# State attributes can be removed in 2025.3
attr = {
@ -121,29 +112,29 @@ class TotalConnectAlarm(TotalConnectLocationEntity, AlarmControlPanelEntity):
else:
attr["location_name"] = f"{self.device.name} partition {self._partition_id}"
state: str | None = None
state: AlarmControlPanelState | None = None
if self._partition.arming_state.is_disarmed():
state = STATE_ALARM_DISARMED
state = AlarmControlPanelState.DISARMED
elif self._partition.arming_state.is_armed_night():
state = STATE_ALARM_ARMED_NIGHT
state = AlarmControlPanelState.ARMED_NIGHT
elif self._partition.arming_state.is_armed_home():
state = STATE_ALARM_ARMED_HOME
state = AlarmControlPanelState.ARMED_HOME
elif self._partition.arming_state.is_armed_away():
state = STATE_ALARM_ARMED_AWAY
state = AlarmControlPanelState.ARMED_AWAY
elif self._partition.arming_state.is_armed_custom_bypass():
state = STATE_ALARM_ARMED_CUSTOM_BYPASS
state = AlarmControlPanelState.ARMED_CUSTOM_BYPASS
elif self._partition.arming_state.is_arming():
state = STATE_ALARM_ARMING
state = AlarmControlPanelState.ARMING
elif self._partition.arming_state.is_disarming():
state = STATE_ALARM_DISARMING
state = AlarmControlPanelState.DISARMING
elif self._partition.arming_state.is_triggered_police():
state = STATE_ALARM_TRIGGERED
state = AlarmControlPanelState.TRIGGERED
attr["triggered_source"] = "Police/Medical"
elif self._partition.arming_state.is_triggered_fire():
state = STATE_ALARM_TRIGGERED
state = AlarmControlPanelState.TRIGGERED
attr["triggered_source"] = "Fire/Smoke"
elif self._partition.arming_state.is_triggered_gas():
state = STATE_ALARM_TRIGGERED
state = AlarmControlPanelState.TRIGGERED
attr["triggered_source"] = "Carbon Monoxide"
self._attr_extra_state_attributes = attr

View File

@ -10,12 +10,7 @@ from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityDescription,
AlarmControlPanelEntityFeature,
)
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
AlarmControlPanelState,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
@ -35,11 +30,11 @@ class Mode(StrEnum):
SOS = "sos"
STATE_MAPPING: dict[str, str] = {
Mode.DISARMED: STATE_ALARM_DISARMED,
Mode.ARM: STATE_ALARM_ARMED_AWAY,
Mode.HOME: STATE_ALARM_ARMED_HOME,
Mode.SOS: STATE_ALARM_TRIGGERED,
STATE_MAPPING: dict[str, AlarmControlPanelState] = {
Mode.DISARMED: AlarmControlPanelState.DISARMED,
Mode.ARM: AlarmControlPanelState.ARMED_AWAY,
Mode.HOME: AlarmControlPanelState.ARMED_HOME,
Mode.SOS: AlarmControlPanelState.TRIGGERED,
}
@ -115,7 +110,7 @@ class TuyaAlarmEntity(TuyaEntity, AlarmControlPanelEntity):
self._attr_supported_features |= AlarmControlPanelEntityFeature.TRIGGER
@property
def state(self) -> str | None:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the device."""
if not (status := self.device.status.get(self.entity_description.key)):
return None

View File

@ -7,10 +7,10 @@ import asyncio
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import STATE_ALARM_ARMING, STATE_ALARM_DISARMING
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -86,7 +86,7 @@ class VerisureAlarm(
async def async_alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
self._attr_state = STATE_ALARM_DISARMING
self._attr_alarm_state = AlarmControlPanelState.DISARMING
self.async_write_ha_state()
await self._async_set_arm_state(
"DISARMED", self.coordinator.verisure.disarm(code)
@ -94,7 +94,7 @@ class VerisureAlarm(
async def async_alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command."""
self._attr_state = STATE_ALARM_ARMING
self._attr_alarm_state = AlarmControlPanelState.ARMING
self.async_write_ha_state()
await self._async_set_arm_state(
"ARMED_HOME", self.coordinator.verisure.arm_home(code)
@ -102,7 +102,7 @@ class VerisureAlarm(
async def async_alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command."""
self._attr_state = STATE_ALARM_ARMING
self._attr_alarm_state = AlarmControlPanelState.ARMING
self.async_write_ha_state()
await self._async_set_arm_state(
"ARMED_AWAY", self.coordinator.verisure.arm_away(code)
@ -111,7 +111,7 @@ class VerisureAlarm(
@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self._attr_state = ALARM_STATE_TO_HA.get(
self._attr_alarm_state = ALARM_STATE_TO_HA.get(
self.coordinator.data["alarm"]["statusType"]
)
self._attr_changed_by = self.coordinator.data["alarm"].get("name")

View File

@ -3,12 +3,7 @@
from datetime import timedelta
import logging
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
)
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
DOMAIN = "verisure"
@ -43,8 +38,8 @@ DEVICE_TYPE_NAME = {
}
ALARM_STATE_TO_HA = {
"DISARMED": STATE_ALARM_DISARMED,
"ARMED_HOME": STATE_ALARM_ARMED_HOME,
"ARMED_AWAY": STATE_ALARM_ARMED_AWAY,
"PENDING": STATE_ALARM_PENDING,
"DISARMED": AlarmControlPanelState.DISARMED,
"ARMED_HOME": AlarmControlPanelState.ARMED_HOME,
"ARMED_AWAY": AlarmControlPanelState.ARMED_AWAY,
"PENDING": AlarmControlPanelState.PENDING,
}

View File

@ -10,13 +10,9 @@ from miio import DeviceException
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -106,11 +102,11 @@ class XiaomiGatewayAlarm(AlarmControlPanelEntity):
self._attr_available = True
if state == XIAOMI_STATE_ARMED_VALUE:
self._attr_state = STATE_ALARM_ARMED_AWAY
self._attr_alarm_state = AlarmControlPanelState.ARMED_AWAY
elif state == XIAOMI_STATE_DISARMED_VALUE:
self._attr_state = STATE_ALARM_DISARMED
self._attr_alarm_state = AlarmControlPanelState.DISARMED
elif state == XIAOMI_STATE_ARMING_VALUE:
self._attr_state = STATE_ALARM_ARMING
self._attr_alarm_state = AlarmControlPanelState.ARMING
else:
_LOGGER.warning(
"New state (%s) doesn't match expected values: %s/%s/%s",
@ -119,6 +115,6 @@ class XiaomiGatewayAlarm(AlarmControlPanelEntity):
XIAOMI_STATE_DISARMED_VALUE,
XIAOMI_STATE_ARMING_VALUE,
)
self._attr_state = None
self._attr_alarm_state = None
_LOGGER.debug("State value: %s", self._attr_state)
_LOGGER.debug("State value: %s", self._attr_alarm_state)

View File

@ -13,12 +13,12 @@ from yalesmartalarmclient.const import (
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.const import CONF_NAME
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from . import YaleConfigEntry
from .const import DOMAIN, STATE_MAP, YALE_ALL_ERRORS
@ -106,6 +106,6 @@ class YaleAlarmDevice(YaleAlarmEntity, AlarmControlPanelEntity):
return super().available
@property
def state(self) -> StateType:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the alarm."""
return STATE_MAP.get(self.coordinator.data["alarm"])

View File

@ -9,12 +9,8 @@ from yalesmartalarmclient.client import (
)
from yalesmartalarmclient.exceptions import AuthenticationError, UnknownError
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
Platform,
)
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
from homeassistant.const import Platform
CONF_AREA_ID = "area_id"
CONF_LOCK_CODE_DIGITS = "lock_code_digits"
@ -45,9 +41,9 @@ PLATFORMS = [
]
STATE_MAP = {
YALE_STATE_DISARM: STATE_ALARM_DISARMED,
YALE_STATE_ARM_PARTIAL: STATE_ALARM_ARMED_HOME,
YALE_STATE_ARM_FULL: STATE_ALARM_ARMED_AWAY,
YALE_STATE_DISARM: AlarmControlPanelState.DISARMED,
YALE_STATE_ARM_PARTIAL: AlarmControlPanelState.ARMED_HOME,
YALE_STATE_ARM_FULL: AlarmControlPanelState.ARMED_AWAY,
}
YALE_BASE_ERRORS = (

View File

@ -4,9 +4,14 @@ from __future__ import annotations
import functools
from zha.application.platforms.alarm_control_panel.const import (
AlarmState as ZHAAlarmState,
)
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
CodeFormat,
)
from homeassistant.config_entries import ConfigEntry
@ -23,6 +28,20 @@ from .helpers import (
get_zha_data,
)
ZHA_STATE_TO_ALARM_STATE_MAP = {
ZHAAlarmState.DISARMED.value: AlarmControlPanelState.DISARMED,
ZHAAlarmState.ARMED_HOME.value: AlarmControlPanelState.ARMED_HOME,
ZHAAlarmState.ARMED_AWAY.value: AlarmControlPanelState.ARMED_AWAY,
ZHAAlarmState.ARMED_NIGHT.value: AlarmControlPanelState.ARMED_NIGHT,
ZHAAlarmState.ARMED_VACATION.value: AlarmControlPanelState.ARMED_VACATION,
ZHAAlarmState.ARMED_CUSTOM_BYPASS.value: AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
ZHAAlarmState.PENDING.value: AlarmControlPanelState.PENDING,
ZHAAlarmState.ARMING.value: AlarmControlPanelState.ARMING,
ZHAAlarmState.DISARMING.value: AlarmControlPanelState.DISARMING,
ZHAAlarmState.TRIGGERED.value: AlarmControlPanelState.TRIGGERED,
ZHAAlarmState.UNKNOWN.value: None,
}
async def async_setup_entry(
hass: HomeAssistant,
@ -94,6 +113,6 @@ class ZHAAlarmControlPanel(ZHAEntity, AlarmControlPanelEntity):
self.async_write_ha_state()
@property
def state(self) -> str | None:
def alarm_state(self) -> AlarmControlPanelState | None:
"""Return the state of the entity."""
return self.entity_data.entity.state["state"]
return ZHA_STATE_TO_ALARM_STATE_MAP.get(self.entity_data.entity.state["state"])

View File

@ -479,16 +479,6 @@ STATE_PLAYING: Final = "playing"
STATE_PAUSED: Final = "paused"
STATE_IDLE: Final = "idle"
STATE_STANDBY: Final = "standby"
STATE_ALARM_DISARMED: Final = "disarmed"
STATE_ALARM_ARMED_HOME: Final = "armed_home"
STATE_ALARM_ARMED_AWAY: Final = "armed_away"
STATE_ALARM_ARMED_NIGHT: Final = "armed_night"
STATE_ALARM_ARMED_VACATION: Final = "armed_vacation"
STATE_ALARM_ARMED_CUSTOM_BYPASS: Final = "armed_custom_bypass"
STATE_ALARM_PENDING: Final = "pending"
STATE_ALARM_ARMING: Final = "arming"
STATE_ALARM_DISARMING: Final = "disarming"
STATE_ALARM_TRIGGERED: Final = "triggered"
STATE_UNAVAILABLE: Final = "unavailable"
STATE_OK: Final = "ok"
STATE_PROBLEM: Final = "problem"
@ -522,6 +512,60 @@ _DEPRECATED_STATE_JAMMED: Final = DeprecatedConstant(
"2025.10",
)
# #### ALARM CONTROL PANEL STATES ####
# STATE_ALARM_* below are deprecated as of 2024.11
# use the AlarmControlPanelState enum instead.
_DEPRECATED_STATE_ALARM_DISARMED: Final = DeprecatedConstant(
"disarmed",
"AlarmControlPanelState.DISARMED",
"2025.11",
)
_DEPRECATED_STATE_ALARM_ARMED_HOME: Final = DeprecatedConstant(
"armed_home",
"AlarmControlPanelState.ARMED_HOME",
"2025.11",
)
_DEPRECATED_STATE_ALARM_ARMED_AWAY: Final = DeprecatedConstant(
"armed_away",
"AlarmControlPanelState.ARMED_AWAY",
"2025.11",
)
_DEPRECATED_STATE_ALARM_ARMED_NIGHT: Final = DeprecatedConstant(
"armed_night",
"AlarmControlPanelState.ARMED_NIGHT",
"2025.11",
)
_DEPRECATED_STATE_ALARM_ARMED_VACATION: Final = DeprecatedConstant(
"armed_vacation",
"AlarmControlPanelState.ARMED_VACATION",
"2025.11",
)
_DEPRECATED_STATE_ALARM_ARMED_CUSTOM_BYPASS: Final = DeprecatedConstant(
"armed_custom_bypass",
"AlarmControlPanelState.ARMED_CUSTOM_BYPASS",
"2025.11",
)
_DEPRECATED_STATE_ALARM_PENDING: Final = DeprecatedConstant(
"pending",
"AlarmControlPanelState.PENDING",
"2025.11",
)
_DEPRECATED_STATE_ALARM_ARMING: Final = DeprecatedConstant(
"arming",
"AlarmControlPanelState.ARMING",
"2025.11",
)
_DEPRECATED_STATE_ALARM_DISARMING: Final = DeprecatedConstant(
"disarming",
"AlarmControlPanelState.DISARMING",
"2025.11",
)
_DEPRECATED_STATE_ALARM_TRIGGERED: Final = DeprecatedConstant(
"triggered",
"AlarmControlPanelState.TRIGGERED",
"2025.11",
)
# #### STATE AND EVENT ATTRIBUTES ####
# Attribution
ATTR_ATTRIBUTION: Final = "attribution"

View File

@ -3,7 +3,10 @@
from unittest.mock import PropertyMock, patch
from homeassistant.components.abode import ATTR_DEVICE_ID
from homeassistant.components.alarm_control_panel import DOMAIN as ALARM_DOMAIN
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_DOMAIN,
AlarmControlPanelState,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_FRIENDLY_NAME,
@ -11,9 +14,6 @@ from homeassistant.const import (
SERVICE_ALARM_ARM_AWAY,
SERVICE_ALARM_ARM_HOME,
SERVICE_ALARM_DISARM,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
@ -39,7 +39,7 @@ async def test_attributes(hass: HomeAssistant) -> None:
await setup_platform(hass, ALARM_DOMAIN)
state = hass.states.get(DEVICE_ID)
assert state.state == STATE_ALARM_DISARMED
assert state.state == AlarmControlPanelState.DISARMED
assert state.attributes.get(ATTR_DEVICE_ID) == "area_1"
assert not state.attributes.get("battery_backup")
assert not state.attributes.get("cellular_backup")
@ -75,7 +75,7 @@ async def test_set_alarm_away(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
state = hass.states.get(DEVICE_ID)
assert state.state == STATE_ALARM_ARMED_AWAY
assert state.state == AlarmControlPanelState.ARMED_AWAY
async def test_set_alarm_home(hass: HomeAssistant) -> None:
@ -105,7 +105,7 @@ async def test_set_alarm_home(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
state = hass.states.get(DEVICE_ID)
assert state.state == STATE_ALARM_ARMED_HOME
assert state.state == AlarmControlPanelState.ARMED_HOME
async def test_set_alarm_standby(hass: HomeAssistant) -> None:
@ -134,7 +134,7 @@ async def test_set_alarm_standby(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
state = hass.states.get(DEVICE_ID)
assert state.state == STATE_ALARM_DISARMED
assert state.state == AlarmControlPanelState.DISARMED
async def test_state_unknown(hass: HomeAssistant) -> None:

View File

@ -8,6 +8,7 @@ from homeassistant.components.alarm_control_panel import (
DOMAIN,
AlarmControlPanelEntity,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.const import (
ATTR_CODE,
@ -20,12 +21,6 @@ from homeassistant.const import (
SERVICE_ALARM_ARM_VACATION,
SERVICE_ALARM_DISARM,
SERVICE_ALARM_TRIGGER,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant
@ -145,31 +140,31 @@ class MockAlarm(MockEntity, AlarmControlPanelEntity):
def alarm_arm_away(self, code=None):
"""Send arm away command."""
self._attr_state = STATE_ALARM_ARMED_AWAY
self._attr_alarm_state = AlarmControlPanelState.ARMED_AWAY
self.schedule_update_ha_state()
def alarm_arm_home(self, code=None):
"""Send arm home command."""
self._attr_state = STATE_ALARM_ARMED_HOME
self._attr_alarm_state = AlarmControlPanelState.ARMED_HOME
self.schedule_update_ha_state()
def alarm_arm_night(self, code=None):
"""Send arm night command."""
self._attr_state = STATE_ALARM_ARMED_NIGHT
self._attr_alarm_state = AlarmControlPanelState.ARMED_NIGHT
self.schedule_update_ha_state()
def alarm_arm_vacation(self, code=None):
"""Send arm night command."""
self._attr_state = STATE_ALARM_ARMED_VACATION
self._attr_alarm_state = AlarmControlPanelState.ARMED_VACATION
self.schedule_update_ha_state()
def alarm_disarm(self, code=None):
"""Send disarm command."""
if code == "1234":
self._attr_state = STATE_ALARM_DISARMED
self._attr_alarm_state = AlarmControlPanelState.DISARMED
self.schedule_update_ha_state()
def alarm_trigger(self, code=None):
"""Send alarm trigger command."""
self._attr_state = STATE_ALARM_TRIGGERED
self._attr_alarm_state = AlarmControlPanelState.TRIGGERED
self.schedule_update_ha_state()

View File

@ -7,19 +7,10 @@ from homeassistant.components import automation
from homeassistant.components.alarm_control_panel import (
DOMAIN,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.components.device_automation import DeviceAutomationType
from homeassistant.const import (
CONF_PLATFORM,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
STATE_UNKNOWN,
EntityCategory,
)
from homeassistant.const import CONF_PLATFORM, STATE_UNKNOWN, EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.setup import async_setup_component
@ -541,27 +532,44 @@ async def test_action(
hass.bus.async_fire("test_event_arm_away")
await hass.async_block_till_done()
assert hass.states.get(entity_entry.entity_id).state == STATE_ALARM_ARMED_AWAY
assert (
hass.states.get(entity_entry.entity_id).state
== AlarmControlPanelState.ARMED_AWAY
)
hass.bus.async_fire("test_event_arm_home")
await hass.async_block_till_done()
assert hass.states.get(entity_entry.entity_id).state == STATE_ALARM_ARMED_HOME
assert (
hass.states.get(entity_entry.entity_id).state
== AlarmControlPanelState.ARMED_HOME
)
hass.bus.async_fire("test_event_arm_vacation")
await hass.async_block_till_done()
assert hass.states.get(entity_entry.entity_id).state == STATE_ALARM_ARMED_VACATION
assert (
hass.states.get(entity_entry.entity_id).state
== AlarmControlPanelState.ARMED_VACATION
)
hass.bus.async_fire("test_event_arm_night")
await hass.async_block_till_done()
assert hass.states.get(entity_entry.entity_id).state == STATE_ALARM_ARMED_NIGHT
assert (
hass.states.get(entity_entry.entity_id).state
== AlarmControlPanelState.ARMED_NIGHT
)
hass.bus.async_fire("test_event_disarm")
await hass.async_block_till_done()
assert hass.states.get(entity_entry.entity_id).state == STATE_ALARM_DISARMED
assert (
hass.states.get(entity_entry.entity_id).state == AlarmControlPanelState.DISARMED
)
hass.bus.async_fire("test_event_trigger")
await hass.async_block_till_done()
assert hass.states.get(entity_entry.entity_id).state == STATE_ALARM_TRIGGERED
assert (
hass.states.get(entity_entry.entity_id).state
== AlarmControlPanelState.TRIGGERED
)
async def test_action_legacy(
@ -615,4 +623,7 @@ async def test_action_legacy(
hass.bus.async_fire("test_event_arm_away")
await hass.async_block_till_done()
assert hass.states.get(entity_entry.entity_id).state == STATE_ALARM_ARMED_AWAY
assert (
hass.states.get(entity_entry.entity_id).state
== AlarmControlPanelState.ARMED_AWAY
)

View File

@ -7,18 +7,10 @@ from homeassistant.components import automation
from homeassistant.components.alarm_control_panel import (
DOMAIN,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.components.device_automation import DeviceAutomationType
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
EntityCategory,
)
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.setup import async_setup_component
@ -354,7 +346,7 @@ async def test_if_state(
]
},
)
hass.states.async_set(entry.entity_id, STATE_ALARM_TRIGGERED)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.TRIGGERED)
hass.bus.async_fire("test_event1")
hass.bus.async_fire("test_event2")
hass.bus.async_fire("test_event3")
@ -366,7 +358,7 @@ async def test_if_state(
assert len(service_calls) == 1
assert service_calls[0].data["some"] == "is_triggered - event - test_event1"
hass.states.async_set(entry.entity_id, STATE_ALARM_DISARMED)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.DISARMED)
hass.bus.async_fire("test_event1")
hass.bus.async_fire("test_event2")
hass.bus.async_fire("test_event3")
@ -378,7 +370,7 @@ async def test_if_state(
assert len(service_calls) == 2
assert service_calls[1].data["some"] == "is_disarmed - event - test_event2"
hass.states.async_set(entry.entity_id, STATE_ALARM_ARMED_HOME)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.ARMED_HOME)
hass.bus.async_fire("test_event1")
hass.bus.async_fire("test_event2")
hass.bus.async_fire("test_event3")
@ -390,7 +382,7 @@ async def test_if_state(
assert len(service_calls) == 3
assert service_calls[2].data["some"] == "is_armed_home - event - test_event3"
hass.states.async_set(entry.entity_id, STATE_ALARM_ARMED_AWAY)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.ARMED_AWAY)
hass.bus.async_fire("test_event1")
hass.bus.async_fire("test_event2")
hass.bus.async_fire("test_event3")
@ -402,7 +394,7 @@ async def test_if_state(
assert len(service_calls) == 4
assert service_calls[3].data["some"] == "is_armed_away - event - test_event4"
hass.states.async_set(entry.entity_id, STATE_ALARM_ARMED_NIGHT)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.ARMED_NIGHT)
hass.bus.async_fire("test_event1")
hass.bus.async_fire("test_event2")
hass.bus.async_fire("test_event3")
@ -414,7 +406,7 @@ async def test_if_state(
assert len(service_calls) == 5
assert service_calls[4].data["some"] == "is_armed_night - event - test_event5"
hass.states.async_set(entry.entity_id, STATE_ALARM_ARMED_VACATION)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.ARMED_VACATION)
hass.bus.async_fire("test_event1")
hass.bus.async_fire("test_event2")
hass.bus.async_fire("test_event3")
@ -426,7 +418,7 @@ async def test_if_state(
assert len(service_calls) == 6
assert service_calls[5].data["some"] == "is_armed_vacation - event - test_event6"
hass.states.async_set(entry.entity_id, STATE_ALARM_ARMED_CUSTOM_BYPASS)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.ARMED_CUSTOM_BYPASS)
hass.bus.async_fire("test_event1")
hass.bus.async_fire("test_event2")
hass.bus.async_fire("test_event3")
@ -488,7 +480,7 @@ async def test_if_state_legacy(
]
},
)
hass.states.async_set(entry.entity_id, STATE_ALARM_TRIGGERED)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.TRIGGERED)
hass.bus.async_fire("test_event1")
await hass.async_block_till_done()
assert len(service_calls) == 1

View File

@ -9,18 +9,10 @@ from homeassistant.components import automation
from homeassistant.components.alarm_control_panel import (
DOMAIN,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.components.device_automation import DeviceAutomationType
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
EntityCategory,
)
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.setup import async_setup_component
@ -256,7 +248,7 @@ async def test_if_fires_on_state_change(
DOMAIN, "test", "5678", device_id=device_entry.id
)
hass.states.async_set(entry.entity_id, STATE_ALARM_PENDING)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.PENDING)
assert await async_setup_component(
hass,
@ -400,7 +392,7 @@ async def test_if_fires_on_state_change(
)
# Fake that the entity is triggered.
hass.states.async_set(entry.entity_id, STATE_ALARM_TRIGGERED)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.TRIGGERED)
await hass.async_block_till_done()
assert len(service_calls) == 1
assert (
@ -409,7 +401,7 @@ async def test_if_fires_on_state_change(
)
# Fake that the entity is disarmed.
hass.states.async_set(entry.entity_id, STATE_ALARM_DISARMED)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.DISARMED)
await hass.async_block_till_done()
assert len(service_calls) == 2
assert (
@ -418,7 +410,7 @@ async def test_if_fires_on_state_change(
)
# Fake that the entity is armed home.
hass.states.async_set(entry.entity_id, STATE_ALARM_ARMED_HOME)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.ARMED_HOME)
await hass.async_block_till_done()
assert len(service_calls) == 3
assert (
@ -427,7 +419,7 @@ async def test_if_fires_on_state_change(
)
# Fake that the entity is armed away.
hass.states.async_set(entry.entity_id, STATE_ALARM_ARMED_AWAY)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.ARMED_AWAY)
await hass.async_block_till_done()
assert len(service_calls) == 4
assert (
@ -436,7 +428,7 @@ async def test_if_fires_on_state_change(
)
# Fake that the entity is armed night.
hass.states.async_set(entry.entity_id, STATE_ALARM_ARMED_NIGHT)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.ARMED_NIGHT)
await hass.async_block_till_done()
assert len(service_calls) == 5
assert (
@ -445,7 +437,7 @@ async def test_if_fires_on_state_change(
)
# Fake that the entity is armed vacation.
hass.states.async_set(entry.entity_id, STATE_ALARM_ARMED_VACATION)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.ARMED_VACATION)
await hass.async_block_till_done()
assert len(service_calls) == 6
assert (
@ -471,7 +463,7 @@ async def test_if_fires_on_state_change_with_for(
DOMAIN, "test", "5678", device_id=device_entry.id
)
hass.states.async_set(entry.entity_id, STATE_ALARM_DISARMED)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.DISARMED)
assert await async_setup_component(
hass,
@ -506,7 +498,7 @@ async def test_if_fires_on_state_change_with_for(
await hass.async_block_till_done()
assert len(service_calls) == 0
hass.states.async_set(entry.entity_id, STATE_ALARM_TRIGGERED)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.TRIGGERED)
await hass.async_block_till_done()
assert len(service_calls) == 0
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10))
@ -536,7 +528,7 @@ async def test_if_fires_on_state_change_legacy(
DOMAIN, "test", "5678", device_id=device_entry.id
)
hass.states.async_set(entry.entity_id, STATE_ALARM_DISARMED)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.DISARMED)
assert await async_setup_component(
hass,
@ -570,7 +562,7 @@ async def test_if_fires_on_state_change_legacy(
await hass.async_block_till_done()
assert len(service_calls) == 0
hass.states.async_set(entry.entity_id, STATE_ALARM_TRIGGERED)
hass.states.async_set(entry.entity_id, AlarmControlPanelState.TRIGGERED)
await hass.async_block_till_done()
assert len(service_calls) == 1
assert (

View File

@ -2,14 +2,17 @@
from types import ModuleType
from typing import Any
from unittest.mock import patch
import pytest
from homeassistant.components import alarm_control_panel
from homeassistant.components.alarm_control_panel.const import (
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_CONTROL_PANEL_DOMAIN,
AlarmControlPanelEntityFeature,
CodeFormat,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_CODE,
SERVICE_ALARM_ARM_AWAY,
@ -23,11 +26,20 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import UNDEFINED, UndefinedType
from .conftest import MockAlarmControlPanel
from .conftest import TEST_DOMAIN, MockAlarmControlPanel
from tests.common import help_test_all, import_and_test_deprecated_constant_enum
from tests.common import (
MockConfigEntry,
MockModule,
MockPlatform,
help_test_all,
import_and_test_deprecated_constant_enum,
mock_integration,
mock_platform,
)
async def help_test_async_alarm_control_panel_service(
@ -283,3 +295,197 @@ async def test_alarm_control_panel_with_default_code(
hass, mock_alarm_control_panel_entity.entity_id, SERVICE_ALARM_DISARM
)
mock_alarm_control_panel_entity.calls_disarm.assert_called_with("1234")
async def test_alarm_control_panel_not_log_deprecated_state_warning(
hass: HomeAssistant,
mock_alarm_control_panel_entity: MockAlarmControlPanel,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test correctly using alarm_state doesn't log issue or raise repair."""
state = hass.states.get(mock_alarm_control_panel_entity.entity_id)
assert state is not None
assert "Entities should implement the 'alarm_state' property and" not in caplog.text
async def test_alarm_control_panel_log_deprecated_state_warning_using_state_prop(
hass: HomeAssistant,
code_format: CodeFormat | None,
supported_features: AlarmControlPanelEntityFeature,
code_arm_required: bool,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test incorrectly using state property does log issue and raise repair."""
async def async_setup_entry_init(
hass: HomeAssistant, config_entry: ConfigEntry
) -> bool:
"""Set up test config entry."""
await hass.config_entries.async_forward_entry_setups(
config_entry, [ALARM_CONTROL_PANEL_DOMAIN]
)
return True
mock_integration(
hass,
MockModule(
TEST_DOMAIN,
async_setup_entry=async_setup_entry_init,
),
)
class MockLegacyAlarmControlPanel(MockAlarmControlPanel):
"""Mocked alarm control entity."""
def __init__(
self,
supported_features: AlarmControlPanelEntityFeature = AlarmControlPanelEntityFeature(
0
),
code_format: CodeFormat | None = None,
code_arm_required: bool = True,
) -> None:
"""Initialize the alarm control."""
super().__init__(supported_features, code_format, code_arm_required)
@property
def state(self) -> str:
"""Return the state of the entity."""
return "disarmed"
entity = MockLegacyAlarmControlPanel(
supported_features=supported_features,
code_format=code_format,
code_arm_required=code_arm_required,
)
async def async_setup_entry_platform(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up test alarm control panel platform via config entry."""
async_add_entities([entity])
mock_platform(
hass,
f"{TEST_DOMAIN}.{ALARM_CONTROL_PANEL_DOMAIN}",
MockPlatform(async_setup_entry=async_setup_entry_platform),
)
with patch.object(
MockLegacyAlarmControlPanel,
"__module__",
"tests.custom_components.test.alarm_control_panel",
):
config_entry = MockConfigEntry(domain=TEST_DOMAIN)
config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
state = hass.states.get(entity.entity_id)
assert state is not None
assert "Entities should implement the 'alarm_state' property and" in caplog.text
async def test_alarm_control_panel_log_deprecated_state_warning_using_attr_state_attr(
hass: HomeAssistant,
code_format: CodeFormat | None,
supported_features: AlarmControlPanelEntityFeature,
code_arm_required: bool,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test incorrectly using _attr_state attribute does log issue and raise repair."""
async def async_setup_entry_init(
hass: HomeAssistant, config_entry: ConfigEntry
) -> bool:
"""Set up test config entry."""
await hass.config_entries.async_forward_entry_setups(
config_entry, [ALARM_CONTROL_PANEL_DOMAIN]
)
return True
mock_integration(
hass,
MockModule(
TEST_DOMAIN,
async_setup_entry=async_setup_entry_init,
),
)
class MockLegacyAlarmControlPanel(MockAlarmControlPanel):
"""Mocked alarm control entity."""
def __init__(
self,
supported_features: AlarmControlPanelEntityFeature = AlarmControlPanelEntityFeature(
0
),
code_format: CodeFormat | None = None,
code_arm_required: bool = True,
) -> None:
"""Initialize the alarm control."""
super().__init__(supported_features, code_format, code_arm_required)
def alarm_disarm(self, code: str | None = None) -> None:
"""Mock alarm disarm calls."""
self._attr_state = "disarmed"
entity = MockLegacyAlarmControlPanel(
supported_features=supported_features,
code_format=code_format,
code_arm_required=code_arm_required,
)
async def async_setup_entry_platform(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up test alarm control panel platform via config entry."""
async_add_entities([entity])
mock_platform(
hass,
f"{TEST_DOMAIN}.{ALARM_CONTROL_PANEL_DOMAIN}",
MockPlatform(async_setup_entry=async_setup_entry_platform),
)
with patch.object(
MockLegacyAlarmControlPanel,
"__module__",
"tests.custom_components.test.alarm_control_panel",
):
config_entry = MockConfigEntry(domain=TEST_DOMAIN)
config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
state = hass.states.get(entity.entity_id)
assert state is not None
assert "Entities should implement the 'alarm_state' property and" not in caplog.text
with patch.object(
MockLegacyAlarmControlPanel,
"__module__",
"tests.custom_components.test.alarm_control_panel",
):
await help_test_async_alarm_control_panel_service(
hass, entity.entity_id, SERVICE_ALARM_DISARM
)
assert "Entities should implement the 'alarm_state' property and" in caplog.text
caplog.clear()
with patch.object(
MockLegacyAlarmControlPanel,
"__module__",
"tests.custom_components.test.alarm_control_panel",
):
await help_test_async_alarm_control_panel_service(
hass, entity.entity_id, SERVICE_ALARM_DISARM
)
# Test we only log once
assert "Entities should implement the 'alarm_state' property and" not in caplog.text

View File

@ -2,6 +2,7 @@
import pytest
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
from homeassistant.const import (
SERVICE_ALARM_ARM_AWAY,
SERVICE_ALARM_ARM_CUSTOM_BYPASS,
@ -10,13 +11,6 @@ from homeassistant.const import (
SERVICE_ALARM_ARM_VACATION,
SERVICE_ALARM_DISARM,
SERVICE_ALARM_TRIGGER,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant, State
from homeassistant.helpers.state import async_reproduce_state
@ -29,27 +23,37 @@ async def test_reproducing_states(
) -> None:
"""Test reproducing Alarm control panel states."""
hass.states.async_set(
"alarm_control_panel.entity_armed_away", STATE_ALARM_ARMED_AWAY, {}
)
hass.states.async_set(
"alarm_control_panel.entity_armed_custom_bypass",
STATE_ALARM_ARMED_CUSTOM_BYPASS,
"alarm_control_panel.entity_armed_away",
AlarmControlPanelState.ARMED_AWAY,
{},
)
hass.states.async_set(
"alarm_control_panel.entity_armed_home", STATE_ALARM_ARMED_HOME, {}
"alarm_control_panel.entity_armed_custom_bypass",
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
{},
)
hass.states.async_set(
"alarm_control_panel.entity_armed_night", STATE_ALARM_ARMED_NIGHT, {}
"alarm_control_panel.entity_armed_home",
AlarmControlPanelState.ARMED_HOME,
{},
)
hass.states.async_set(
"alarm_control_panel.entity_armed_vacation", STATE_ALARM_ARMED_VACATION, {}
"alarm_control_panel.entity_armed_night",
AlarmControlPanelState.ARMED_NIGHT,
{},
)
hass.states.async_set(
"alarm_control_panel.entity_disarmed", STATE_ALARM_DISARMED, {}
"alarm_control_panel.entity_armed_vacation",
AlarmControlPanelState.ARMED_VACATION,
{},
)
hass.states.async_set(
"alarm_control_panel.entity_triggered", STATE_ALARM_TRIGGERED, {}
"alarm_control_panel.entity_disarmed", AlarmControlPanelState.DISARMED, {}
)
hass.states.async_set(
"alarm_control_panel.entity_triggered",
AlarmControlPanelState.TRIGGERED,
{},
)
arm_away_calls = async_mock_service(
@ -76,18 +80,34 @@ async def test_reproducing_states(
await async_reproduce_state(
hass,
[
State("alarm_control_panel.entity_armed_away", STATE_ALARM_ARMED_AWAY),
State(
"alarm_control_panel.entity_armed_away",
AlarmControlPanelState.ARMED_AWAY,
),
State(
"alarm_control_panel.entity_armed_custom_bypass",
STATE_ALARM_ARMED_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
),
State("alarm_control_panel.entity_armed_home", STATE_ALARM_ARMED_HOME),
State("alarm_control_panel.entity_armed_night", STATE_ALARM_ARMED_NIGHT),
State(
"alarm_control_panel.entity_armed_vacation", STATE_ALARM_ARMED_VACATION
"alarm_control_panel.entity_armed_home",
AlarmControlPanelState.ARMED_HOME,
),
State(
"alarm_control_panel.entity_armed_night",
AlarmControlPanelState.ARMED_NIGHT,
),
State(
"alarm_control_panel.entity_armed_vacation",
AlarmControlPanelState.ARMED_VACATION,
),
State(
"alarm_control_panel.entity_disarmed",
AlarmControlPanelState.DISARMED,
),
State(
"alarm_control_panel.entity_triggered",
AlarmControlPanelState.TRIGGERED,
),
State("alarm_control_panel.entity_disarmed", STATE_ALARM_DISARMED),
State("alarm_control_panel.entity_triggered", STATE_ALARM_TRIGGERED),
],
)
@ -117,17 +137,34 @@ async def test_reproducing_states(
await async_reproduce_state(
hass,
[
State("alarm_control_panel.entity_armed_away", STATE_ALARM_TRIGGERED),
State(
"alarm_control_panel.entity_armed_custom_bypass", STATE_ALARM_ARMED_AWAY
"alarm_control_panel.entity_armed_away",
AlarmControlPanelState.TRIGGERED,
),
State(
"alarm_control_panel.entity_armed_home", STATE_ALARM_ARMED_CUSTOM_BYPASS
"alarm_control_panel.entity_armed_custom_bypass",
AlarmControlPanelState.ARMED_AWAY,
),
State(
"alarm_control_panel.entity_armed_home",
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
),
State(
"alarm_control_panel.entity_armed_night",
AlarmControlPanelState.ARMED_HOME,
),
State(
"alarm_control_panel.entity_armed_vacation",
AlarmControlPanelState.ARMED_NIGHT,
),
State(
"alarm_control_panel.entity_disarmed",
AlarmControlPanelState.ARMED_VACATION,
),
State(
"alarm_control_panel.entity_triggered",
AlarmControlPanelState.DISARMED,
),
State("alarm_control_panel.entity_armed_night", STATE_ALARM_ARMED_HOME),
State("alarm_control_panel.entity_armed_vacation", STATE_ALARM_ARMED_NIGHT),
State("alarm_control_panel.entity_disarmed", STATE_ALARM_ARMED_VACATION),
State("alarm_control_panel.entity_triggered", STATE_ALARM_DISARMED),
# Should not raise
State("alarm_control_panel.non_existing", "on"),
],

View File

@ -5,6 +5,7 @@ from unittest.mock import patch
import pytest
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
from homeassistant.components.alexa import smart_home
from homeassistant.components.climate import (
ATTR_CURRENT_TEMPERATURE,
@ -23,11 +24,6 @@ from homeassistant.components.water_heater import (
)
from homeassistant.const import (
ATTR_UNIT_OF_MEASUREMENT,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED,
STATE_OFF,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
@ -1351,15 +1347,23 @@ async def test_temperature_sensor_water_heater(hass: HomeAssistant) -> None:
async def test_report_alarm_control_panel_state(hass: HomeAssistant) -> None:
"""Test SecurityPanelController implements armState property."""
hass.states.async_set("alarm_control_panel.armed_away", STATE_ALARM_ARMED_AWAY, {})
hass.states.async_set(
"alarm_control_panel.armed_custom_bypass", STATE_ALARM_ARMED_CUSTOM_BYPASS, {}
"alarm_control_panel.armed_away", AlarmControlPanelState.ARMED_AWAY, {}
)
hass.states.async_set("alarm_control_panel.armed_home", STATE_ALARM_ARMED_HOME, {})
hass.states.async_set(
"alarm_control_panel.armed_night", STATE_ALARM_ARMED_NIGHT, {}
"alarm_control_panel.armed_custom_bypass",
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
{},
)
hass.states.async_set(
"alarm_control_panel.armed_home", AlarmControlPanelState.ARMED_HOME, {}
)
hass.states.async_set(
"alarm_control_panel.armed_night", AlarmControlPanelState.ARMED_NIGHT, {}
)
hass.states.async_set(
"alarm_control_panel.disarmed", AlarmControlPanelState.DISARMED, {}
)
hass.states.async_set("alarm_control_panel.disarmed", STATE_ALARM_DISARMED, {})
properties = await reported_properties(hass, "alarm_control_panel.armed_away")
properties.assert_equal("Alexa.SecurityPanelController", "armState", "ARMED_AWAY")

View File

@ -4,17 +4,16 @@ from unittest.mock import PropertyMock, patch
from canary.const import LOCATION_MODE_AWAY, LOCATION_MODE_HOME, LOCATION_MODE_NIGHT
from homeassistant.components.alarm_control_panel import DOMAIN as ALARM_DOMAIN
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_DOMAIN,
AlarmControlPanelState,
)
from homeassistant.components.canary import DOMAIN
from homeassistant.const import (
SERVICE_ALARM_ARM_AWAY,
SERVICE_ALARM_ARM_HOME,
SERVICE_ALARM_ARM_NIGHT,
SERVICE_ALARM_DISARM,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED,
STATE_UNKNOWN,
)
from homeassistant.core import HomeAssistant
@ -67,7 +66,7 @@ async def test_alarm_control_panel(
state = hass.states.get(entity_id)
assert state
assert state.state == STATE_ALARM_DISARMED
assert state.state == AlarmControlPanelState.DISARMED
assert state.attributes["private"]
type(mocked_location).is_private = PropertyMock(return_value=False)
@ -82,7 +81,7 @@ async def test_alarm_control_panel(
state = hass.states.get(entity_id)
assert state
assert state.state == STATE_ALARM_ARMED_HOME
assert state.state == AlarmControlPanelState.ARMED_HOME
# test armed away
type(mocked_location).mode = PropertyMock(
@ -94,7 +93,7 @@ async def test_alarm_control_panel(
state = hass.states.get(entity_id)
assert state
assert state.state == STATE_ALARM_ARMED_AWAY
assert state.state == AlarmControlPanelState.ARMED_AWAY
# test armed night
type(mocked_location).mode = PropertyMock(
@ -106,7 +105,7 @@ async def test_alarm_control_panel(
state = hass.states.get(entity_id)
assert state
assert state.state == STATE_ALARM_ARMED_NIGHT
assert state.state == AlarmControlPanelState.ARMED_NIGHT
async def test_alarm_control_panel_services(hass: HomeAssistant, canary) -> None:

View File

@ -9,6 +9,7 @@ from syrupy import SnapshotAssertion
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_CONTROL_PANEL_DOMAIN,
AlarmControlPanelState,
)
from homeassistant.const import (
ATTR_CODE,
@ -17,13 +18,6 @@ from homeassistant.const import (
SERVICE_ALARM_ARM_HOME,
SERVICE_ALARM_ARM_NIGHT,
SERVICE_ALARM_DISARM,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
Platform,
)
from homeassistant.core import HomeAssistant
@ -117,21 +111,21 @@ async def test_alarm_control_panel(
for action, state in (
# Event signals alarm control panel armed state
(AncillaryControlPanel.ARMED_AWAY, STATE_ALARM_ARMED_AWAY),
(AncillaryControlPanel.ARMED_NIGHT, STATE_ALARM_ARMED_NIGHT),
(AncillaryControlPanel.ARMED_STAY, STATE_ALARM_ARMED_HOME),
(AncillaryControlPanel.DISARMED, STATE_ALARM_DISARMED),
(AncillaryControlPanel.ARMED_AWAY, AlarmControlPanelState.ARMED_AWAY),
(AncillaryControlPanel.ARMED_NIGHT, AlarmControlPanelState.ARMED_NIGHT),
(AncillaryControlPanel.ARMED_STAY, AlarmControlPanelState.ARMED_HOME),
(AncillaryControlPanel.DISARMED, AlarmControlPanelState.DISARMED),
# Event signals alarm control panel arming state
(AncillaryControlPanel.ARMING_AWAY, STATE_ALARM_ARMING),
(AncillaryControlPanel.ARMING_NIGHT, STATE_ALARM_ARMING),
(AncillaryControlPanel.ARMING_STAY, STATE_ALARM_ARMING),
(AncillaryControlPanel.ARMING_AWAY, AlarmControlPanelState.ARMING),
(AncillaryControlPanel.ARMING_NIGHT, AlarmControlPanelState.ARMING),
(AncillaryControlPanel.ARMING_STAY, AlarmControlPanelState.ARMING),
# Event signals alarm control panel pending state
(AncillaryControlPanel.ENTRY_DELAY, STATE_ALARM_PENDING),
(AncillaryControlPanel.EXIT_DELAY, STATE_ALARM_PENDING),
(AncillaryControlPanel.ENTRY_DELAY, AlarmControlPanelState.PENDING),
(AncillaryControlPanel.EXIT_DELAY, AlarmControlPanelState.PENDING),
# Event signals alarm control panel triggered state
(AncillaryControlPanel.IN_ALARM, STATE_ALARM_TRIGGERED),
(AncillaryControlPanel.IN_ALARM, AlarmControlPanelState.TRIGGERED),
# Event signals alarm control panel unknown state keeps previous state
(AncillaryControlPanel.NOT_READY, STATE_ALARM_TRIGGERED),
(AncillaryControlPanel.NOT_READY, AlarmControlPanelState.TRIGGERED),
):
await sensor_ws_data({"state": {"panel": action}})
assert hass.states.get("alarm_control_panel.keypad").state == state

View File

@ -16,7 +16,6 @@ from homeassistant.const import (
CONF_EVENT,
CONF_ID,
CONF_UNIQUE_ID,
STATE_ALARM_ARMED_AWAY,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
@ -83,7 +82,7 @@ async def test_humanifying_deconz_alarm_event(
{
CONF_CODE: 1234,
CONF_DEVICE_ID: keypad_entry.id,
CONF_EVENT: STATE_ALARM_ARMED_AWAY,
CONF_EVENT: "armed_away",
CONF_ID: keypad_event_id,
CONF_UNIQUE_ID: keypad_serial,
},
@ -94,7 +93,7 @@ async def test_humanifying_deconz_alarm_event(
{
CONF_CODE: 1234,
CONF_DEVICE_ID: "ff99ff99ff99ff99ff99ff99ff99ff99",
CONF_EVENT: STATE_ALARM_ARMED_AWAY,
CONF_EVENT: "armed_away",
CONF_ID: removed_device_event_id,
CONF_UNIQUE_ID: removed_device_serial,
},

View File

@ -4,9 +4,9 @@ from unittest.mock import call
from aioesphomeapi import (
AlarmControlPanelCommand,
AlarmControlPanelEntityState,
AlarmControlPanelEntityState as ESPHomeAlarmEntityState,
AlarmControlPanelInfo,
AlarmControlPanelState,
AlarmControlPanelState as ESPHomeAlarmState,
APIClient,
)
@ -20,9 +20,10 @@ from homeassistant.components.alarm_control_panel import (
SERVICE_ALARM_ARM_VACATION,
SERVICE_ALARM_DISARM,
SERVICE_ALARM_TRIGGER,
AlarmControlPanelState,
)
from homeassistant.components.esphome.alarm_control_panel import EspHomeACPFeatures
from homeassistant.const import ATTR_ENTITY_ID, STATE_ALARM_ARMED_AWAY, STATE_UNKNOWN
from homeassistant.const import ATTR_ENTITY_ID, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
@ -48,9 +49,7 @@ async def test_generic_alarm_control_panel_requires_code(
requires_code_to_arm=True,
)
]
states = [
AlarmControlPanelEntityState(key=1, state=AlarmControlPanelState.ARMED_AWAY)
]
states = [ESPHomeAlarmEntityState(key=1, state=ESPHomeAlarmState.ARMED_AWAY)]
user_service = []
await mock_generic_device_entry(
mock_client=mock_client,
@ -60,7 +59,7 @@ async def test_generic_alarm_control_panel_requires_code(
)
state = hass.states.get("alarm_control_panel.test_myalarm_control_panel")
assert state is not None
assert state.state == STATE_ALARM_ARMED_AWAY
assert state.state == AlarmControlPanelState.ARMED_AWAY
await hass.services.async_call(
ALARM_CONTROL_PANEL_DOMAIN,
@ -183,9 +182,7 @@ async def test_generic_alarm_control_panel_no_code(
requires_code_to_arm=False,
)
]
states = [
AlarmControlPanelEntityState(key=1, state=AlarmControlPanelState.ARMED_AWAY)
]
states = [ESPHomeAlarmEntityState(key=1, state=ESPHomeAlarmState.ARMED_AWAY)]
user_service = []
await mock_generic_device_entry(
mock_client=mock_client,
@ -195,7 +192,7 @@ async def test_generic_alarm_control_panel_no_code(
)
state = hass.states.get("alarm_control_panel.test_myalarm_control_panel")
assert state is not None
assert state.state == STATE_ALARM_ARMED_AWAY
assert state.state == AlarmControlPanelState.ARMED_AWAY
await hass.services.async_call(
ALARM_CONTROL_PANEL_DOMAIN,

View File

@ -8,6 +8,7 @@ from freezegun.api import FrozenDateTimeFactory
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_CONTROL_PANEL_DOMAIN,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.components.freebox import SCAN_INTERVAL
from homeassistant.const import (
@ -16,11 +17,6 @@ from homeassistant.const import (
SERVICE_ALARM_ARM_HOME,
SERVICE_ALARM_DISARM,
SERVICE_ALARM_TRIGGER,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
STATE_UNKNOWN,
)
from homeassistant.core import HomeAssistant
@ -59,7 +55,7 @@ async def test_alarm_changed_from_external(
# Initial state
assert (
hass.states.get("alarm_control_panel.systeme_d_alarme").state
== STATE_ALARM_ARMING
== AlarmControlPanelState.ARMING
)
# Now simulate a changed status
@ -73,7 +69,7 @@ async def test_alarm_changed_from_external(
assert (
hass.states.get("alarm_control_panel.systeme_d_alarme").state
== STATE_ALARM_ARMED_AWAY
== AlarmControlPanelState.ARMED_AWAY
)
@ -98,7 +94,7 @@ async def test_alarm_changed_from_hass(hass: HomeAssistant, router: Mock) -> Non
# Initial state: arm_away
assert (
hass.states.get("alarm_control_panel.systeme_d_alarme").state
== STATE_ALARM_ARMED_AWAY
== AlarmControlPanelState.ARMED_AWAY
)
# Now call for a change -> disarmed
@ -113,7 +109,7 @@ async def test_alarm_changed_from_hass(hass: HomeAssistant, router: Mock) -> Non
assert (
hass.states.get("alarm_control_panel.systeme_d_alarme").state
== STATE_ALARM_DISARMED
== AlarmControlPanelState.DISARMED
)
# Now call for a change -> arm_away
@ -128,7 +124,7 @@ async def test_alarm_changed_from_hass(hass: HomeAssistant, router: Mock) -> Non
assert (
hass.states.get("alarm_control_panel.systeme_d_alarme").state
== STATE_ALARM_ARMING
== AlarmControlPanelState.ARMING
)
# Now call for a change -> arm_home
@ -144,7 +140,7 @@ async def test_alarm_changed_from_hass(hass: HomeAssistant, router: Mock) -> Non
assert (
hass.states.get("alarm_control_panel.systeme_d_alarme").state
== STATE_ALARM_ARMED_HOME
== AlarmControlPanelState.ARMED_HOME
)
# Now call for a change -> trigger
@ -159,7 +155,7 @@ async def test_alarm_changed_from_hass(hass: HomeAssistant, router: Mock) -> Non
assert (
hass.states.get("alarm_control_panel.systeme_d_alarme").state
== STATE_ALARM_TRIGGERED
== AlarmControlPanelState.TRIGGERED
)

View File

@ -33,7 +33,10 @@ from homeassistant.components import (
valve,
water_heater,
)
from homeassistant.components.alarm_control_panel import AlarmControlPanelEntityFeature
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.components.camera import CameraEntityFeature
from homeassistant.components.climate import ClimateEntityFeature
from homeassistant.components.cover import CoverEntityFeature
@ -63,9 +66,6 @@ from homeassistant.const import (
EVENT_CALL_SERVICE,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_IDLE,
STATE_OFF,
STATE_ON,
@ -1734,7 +1734,7 @@ async def test_arm_disarm_arm_away(hass: HomeAssistant) -> None:
hass,
State(
"alarm_control_panel.alarm",
STATE_ALARM_ARMED_AWAY,
AlarmControlPanelState.ARMED_AWAY,
{
alarm_control_panel.ATTR_CODE_ARM_REQUIRED: True,
ATTR_SUPPORTED_FEATURES: AlarmControlPanelEntityFeature.ARM_HOME
@ -1765,11 +1765,12 @@ async def test_arm_disarm_arm_away(hass: HomeAssistant) -> None:
assert trt.query_attributes() == {
"isArmed": True,
"currentArmLevel": STATE_ALARM_ARMED_AWAY,
"currentArmLevel": AlarmControlPanelState.ARMED_AWAY,
}
assert trt.can_execute(
trait.COMMAND_ARM_DISARM, {"arm": True, "armLevel": STATE_ALARM_ARMED_AWAY}
trait.COMMAND_ARM_DISARM,
{"arm": True, "armLevel": AlarmControlPanelState.ARMED_AWAY},
)
calls = async_mock_service(
@ -1782,7 +1783,7 @@ async def test_arm_disarm_arm_away(hass: HomeAssistant) -> None:
hass,
State(
"alarm_control_panel.alarm",
STATE_ALARM_DISARMED,
AlarmControlPanelState.DISARMED,
{alarm_control_panel.ATTR_CODE_ARM_REQUIRED: True},
),
BASIC_CONFIG,
@ -1791,7 +1792,7 @@ async def test_arm_disarm_arm_away(hass: HomeAssistant) -> None:
await trt.execute(
trait.COMMAND_ARM_DISARM,
BASIC_DATA,
{"arm": True, "armLevel": STATE_ALARM_ARMED_AWAY},
{"arm": True, "armLevel": AlarmControlPanelState.ARMED_AWAY},
{},
)
assert len(calls) == 0
@ -1801,7 +1802,7 @@ async def test_arm_disarm_arm_away(hass: HomeAssistant) -> None:
hass,
State(
"alarm_control_panel.alarm",
STATE_ALARM_DISARMED,
AlarmControlPanelState.DISARMED,
{alarm_control_panel.ATTR_CODE_ARM_REQUIRED: True},
),
PIN_CONFIG,
@ -1811,7 +1812,7 @@ async def test_arm_disarm_arm_away(hass: HomeAssistant) -> None:
await trt.execute(
trait.COMMAND_ARM_DISARM,
PIN_DATA,
{"arm": True, "armLevel": STATE_ALARM_ARMED_AWAY},
{"arm": True, "armLevel": AlarmControlPanelState.ARMED_AWAY},
{},
)
assert len(calls) == 0
@ -1823,7 +1824,7 @@ async def test_arm_disarm_arm_away(hass: HomeAssistant) -> None:
await trt.execute(
trait.COMMAND_ARM_DISARM,
PIN_DATA,
{"arm": True, "armLevel": STATE_ALARM_ARMED_AWAY},
{"arm": True, "armLevel": AlarmControlPanelState.ARMED_AWAY},
{"pin": 9999},
)
assert len(calls) == 0
@ -1834,7 +1835,7 @@ async def test_arm_disarm_arm_away(hass: HomeAssistant) -> None:
await trt.execute(
trait.COMMAND_ARM_DISARM,
PIN_DATA,
{"arm": True, "armLevel": STATE_ALARM_ARMED_AWAY},
{"arm": True, "armLevel": AlarmControlPanelState.ARMED_AWAY},
{"pin": "1234"},
)
@ -1845,7 +1846,7 @@ async def test_arm_disarm_arm_away(hass: HomeAssistant) -> None:
hass,
State(
"alarm_control_panel.alarm",
STATE_ALARM_ARMED_AWAY,
AlarmControlPanelState.ARMED_AWAY,
{alarm_control_panel.ATTR_CODE_ARM_REQUIRED: True},
),
PIN_CONFIG,
@ -1854,7 +1855,7 @@ async def test_arm_disarm_arm_away(hass: HomeAssistant) -> None:
await trt.execute(
trait.COMMAND_ARM_DISARM,
PIN_DATA,
{"arm": True, "armLevel": STATE_ALARM_ARMED_AWAY},
{"arm": True, "armLevel": AlarmControlPanelState.ARMED_AWAY},
{},
)
assert len(calls) == 1
@ -1865,7 +1866,7 @@ async def test_arm_disarm_arm_away(hass: HomeAssistant) -> None:
hass,
State(
"alarm_control_panel.alarm",
STATE_ALARM_DISARMED,
AlarmControlPanelState.DISARMED,
{alarm_control_panel.ATTR_CODE_ARM_REQUIRED: False},
),
PIN_CONFIG,
@ -1873,7 +1874,7 @@ async def test_arm_disarm_arm_away(hass: HomeAssistant) -> None:
await trt.execute(
trait.COMMAND_ARM_DISARM,
PIN_DATA,
{"arm": True, "armLevel": STATE_ALARM_ARMED_AWAY},
{"arm": True, "armLevel": AlarmControlPanelState.ARMED_AWAY},
{},
)
assert len(calls) == 2
@ -1897,7 +1898,7 @@ async def test_arm_disarm_disarm(hass: HomeAssistant) -> None:
hass,
State(
"alarm_control_panel.alarm",
STATE_ALARM_DISARMED,
AlarmControlPanelState.DISARMED,
{
alarm_control_panel.ATTR_CODE_ARM_REQUIRED: True,
ATTR_SUPPORTED_FEATURES: AlarmControlPanelEntityFeature.TRIGGER
@ -1953,7 +1954,7 @@ async def test_arm_disarm_disarm(hass: HomeAssistant) -> None:
hass,
State(
"alarm_control_panel.alarm",
STATE_ALARM_ARMED_AWAY,
AlarmControlPanelState.ARMED_AWAY,
{alarm_control_panel.ATTR_CODE_ARM_REQUIRED: True},
),
BASIC_CONFIG,
@ -1968,7 +1969,7 @@ async def test_arm_disarm_disarm(hass: HomeAssistant) -> None:
hass,
State(
"alarm_control_panel.alarm",
STATE_ALARM_ARMED_AWAY,
AlarmControlPanelState.ARMED_AWAY,
{alarm_control_panel.ATTR_CODE_ARM_REQUIRED: True},
),
PIN_CONFIG,
@ -2002,7 +2003,7 @@ async def test_arm_disarm_disarm(hass: HomeAssistant) -> None:
hass,
State(
"alarm_control_panel.alarm",
STATE_ALARM_DISARMED,
AlarmControlPanelState.DISARMED,
{alarm_control_panel.ATTR_CODE_ARM_REQUIRED: True},
),
PIN_CONFIG,
@ -2016,7 +2017,7 @@ async def test_arm_disarm_disarm(hass: HomeAssistant) -> None:
hass,
State(
"alarm_control_panel.alarm",
STATE_ALARM_ARMED_AWAY,
AlarmControlPanelState.ARMED_AWAY,
{alarm_control_panel.ATTR_CODE_ARM_REQUIRED: False},
),
PIN_CONFIG,
@ -2036,7 +2037,7 @@ async def test_arm_disarm_disarm(hass: HomeAssistant) -> None:
hass,
State(
"alarm_control_panel.alarm",
STATE_ALARM_PENDING,
AlarmControlPanelState.PENDING,
{alarm_control_panel.ATTR_CODE_ARM_REQUIRED: False},
),
PIN_CONFIG,

View File

@ -6,21 +6,11 @@ import pytest
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_CONTROL_PANEL_DOMAIN,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.components.homekit.const import ATTR_VALUE
from homeassistant.components.homekit.type_security_systems import SecuritySystem
from homeassistant.const import (
ATTR_CODE,
ATTR_ENTITY_ID,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
STATE_UNKNOWN,
)
from homeassistant.const import ATTR_CODE, ATTR_ENTITY_ID, STATE_UNKNOWN
from homeassistant.core import Event, HomeAssistant
from tests.common import async_mock_service
@ -46,27 +36,27 @@ async def test_switch_set_state(
assert acc.char_current_state.value == 3
assert acc.char_target_state.value == 3
hass.states.async_set(entity_id, STATE_ALARM_ARMED_AWAY)
hass.states.async_set(entity_id, AlarmControlPanelState.ARMED_AWAY)
await hass.async_block_till_done()
assert acc.char_target_state.value == 1
assert acc.char_current_state.value == 1
hass.states.async_set(entity_id, STATE_ALARM_ARMED_HOME)
hass.states.async_set(entity_id, AlarmControlPanelState.ARMED_HOME)
await hass.async_block_till_done()
assert acc.char_target_state.value == 0
assert acc.char_current_state.value == 0
hass.states.async_set(entity_id, STATE_ALARM_ARMED_NIGHT)
hass.states.async_set(entity_id, AlarmControlPanelState.ARMED_NIGHT)
await hass.async_block_till_done()
assert acc.char_target_state.value == 2
assert acc.char_current_state.value == 2
hass.states.async_set(entity_id, STATE_ALARM_DISARMED)
hass.states.async_set(entity_id, AlarmControlPanelState.DISARMED)
await hass.async_block_till_done()
assert acc.char_target_state.value == 3
assert acc.char_current_state.value == 3
hass.states.async_set(entity_id, STATE_ALARM_TRIGGERED)
hass.states.async_set(entity_id, AlarmControlPanelState.TRIGGERED)
await hass.async_block_till_done()
assert acc.char_target_state.value == 3
assert acc.char_current_state.value == 4
@ -161,42 +151,42 @@ async def test_arming(hass: HomeAssistant, hk_driver) -> None:
acc.run()
await hass.async_block_till_done()
hass.states.async_set(entity_id, STATE_ALARM_ARMED_AWAY)
hass.states.async_set(entity_id, AlarmControlPanelState.ARMED_AWAY)
await hass.async_block_till_done()
assert acc.char_target_state.value == 1
assert acc.char_current_state.value == 1
hass.states.async_set(entity_id, STATE_ALARM_ARMED_HOME)
hass.states.async_set(entity_id, AlarmControlPanelState.ARMED_HOME)
await hass.async_block_till_done()
assert acc.char_target_state.value == 0
assert acc.char_current_state.value == 0
hass.states.async_set(entity_id, STATE_ALARM_ARMED_VACATION)
hass.states.async_set(entity_id, AlarmControlPanelState.ARMED_VACATION)
await hass.async_block_till_done()
assert acc.char_target_state.value == 1
assert acc.char_current_state.value == 1
hass.states.async_set(entity_id, STATE_ALARM_ARMED_NIGHT)
hass.states.async_set(entity_id, AlarmControlPanelState.ARMED_NIGHT)
await hass.async_block_till_done()
assert acc.char_target_state.value == 2
assert acc.char_current_state.value == 2
hass.states.async_set(entity_id, STATE_ALARM_ARMING)
hass.states.async_set(entity_id, AlarmControlPanelState.ARMING)
await hass.async_block_till_done()
assert acc.char_target_state.value == 1
assert acc.char_current_state.value == 3
hass.states.async_set(entity_id, STATE_ALARM_DISARMED)
hass.states.async_set(entity_id, AlarmControlPanelState.DISARMED)
await hass.async_block_till_done()
assert acc.char_target_state.value == 3
assert acc.char_current_state.value == 3
hass.states.async_set(entity_id, STATE_ALARM_ARMED_AWAY)
hass.states.async_set(entity_id, AlarmControlPanelState.ARMED_AWAY)
await hass.async_block_till_done()
assert acc.char_target_state.value == 1
assert acc.char_current_state.value == 1
hass.states.async_set(entity_id, STATE_ALARM_TRIGGERED)
hass.states.async_set(entity_id, AlarmControlPanelState.TRIGGERED)
await hass.async_block_till_done()
assert acc.char_target_state.value == 1
assert acc.char_current_state.value == 4

View File

@ -4,14 +4,9 @@ from homematicip.aio.home import AsyncHome
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_CONTROL_PANEL_DOMAIN,
AlarmControlPanelState,
)
from homeassistant.components.homematicip_cloud import DOMAIN as HMIPC_DOMAIN
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
@ -83,7 +78,7 @@ async def test_hmip_alarm_control_panel(
await _async_manipulate_security_zones(
hass, home, internal_active=True, external_active=True
)
assert hass.states.get(entity_id).state is STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await hass.services.async_call(
"alarm_control_panel", "alarm_arm_home", {"entity_id": entity_id}, blocking=True
@ -91,7 +86,7 @@ async def test_hmip_alarm_control_panel(
assert home.mock_calls[-1][0] == "set_security_zones_activation"
assert home.mock_calls[-1][1] == (False, True)
await _async_manipulate_security_zones(hass, home, external_active=True)
assert hass.states.get(entity_id).state is STATE_ALARM_ARMED_HOME
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_HOME
await hass.services.async_call(
"alarm_control_panel", "alarm_disarm", {"entity_id": entity_id}, blocking=True
@ -99,7 +94,7 @@ async def test_hmip_alarm_control_panel(
assert home.mock_calls[-1][0] == "set_security_zones_activation"
assert home.mock_calls[-1][1] == (False, False)
await _async_manipulate_security_zones(hass, home)
assert hass.states.get(entity_id).state is STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await hass.services.async_call(
"alarm_control_panel", "alarm_arm_away", {"entity_id": entity_id}, blocking=True
@ -109,7 +104,7 @@ async def test_hmip_alarm_control_panel(
await _async_manipulate_security_zones(
hass, home, internal_active=True, external_active=True, alarm_triggered=True
)
assert hass.states.get(entity_id).state is STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
await hass.services.async_call(
"alarm_control_panel", "alarm_arm_home", {"entity_id": entity_id}, blocking=True
@ -119,4 +114,4 @@ async def test_hmip_alarm_control_panel(
await _async_manipulate_security_zones(
hass, home, external_active=True, alarm_triggered=True
)
assert hass.states.get(entity_id).state is STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED

View File

@ -7,7 +7,10 @@ from freezegun import freeze_time
import pytest
from homeassistant.components import alarm_control_panel
from homeassistant.components.alarm_control_panel import AlarmControlPanelEntityFeature
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.components.demo import alarm_control_panel as demo
from homeassistant.components.manual.alarm_control_panel import (
ATTR_NEXT_STATE,
@ -21,15 +24,6 @@ from homeassistant.const import (
SERVICE_ALARM_ARM_HOME,
SERVICE_ALARM_ARM_NIGHT,
SERVICE_ALARM_ARM_VACATION,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import CoreState, HomeAssistant, State
from homeassistant.exceptions import ServiceValidationError
@ -53,11 +47,14 @@ async def test_setup_demo_platform(hass: HomeAssistant) -> None:
@pytest.mark.parametrize(
("service", "expected_state"),
[
(SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY),
(SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS),
(SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION),
(SERVICE_ALARM_ARM_AWAY, AlarmControlPanelState.ARMED_AWAY),
(
SERVICE_ALARM_ARM_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
),
(SERVICE_ALARM_ARM_HOME, AlarmControlPanelState.ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, AlarmControlPanelState.ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, AlarmControlPanelState.ARMED_VACATION),
],
)
async def test_no_pending(hass: HomeAssistant, service, expected_state) -> None:
@ -79,7 +76,7 @@ async def test_no_pending(hass: HomeAssistant, service, expected_state) -> None:
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await hass.services.async_call(
alarm_control_panel.DOMAIN,
@ -94,11 +91,14 @@ async def test_no_pending(hass: HomeAssistant, service, expected_state) -> None:
@pytest.mark.parametrize(
("service", "expected_state"),
[
(SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY),
(SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS),
(SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION),
(SERVICE_ALARM_ARM_AWAY, AlarmControlPanelState.ARMED_AWAY),
(
SERVICE_ALARM_ARM_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
),
(SERVICE_ALARM_ARM_HOME, AlarmControlPanelState.ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, AlarmControlPanelState.ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, AlarmControlPanelState.ARMED_VACATION),
],
)
async def test_no_pending_when_code_not_req(
@ -123,7 +123,7 @@ async def test_no_pending_when_code_not_req(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await hass.services.async_call(
alarm_control_panel.DOMAIN,
@ -138,11 +138,14 @@ async def test_no_pending_when_code_not_req(
@pytest.mark.parametrize(
("service", "expected_state"),
[
(SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY),
(SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS),
(SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION),
(SERVICE_ALARM_ARM_AWAY, AlarmControlPanelState.ARMED_AWAY),
(
SERVICE_ALARM_ARM_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
),
(SERVICE_ALARM_ARM_HOME, AlarmControlPanelState.ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, AlarmControlPanelState.ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, AlarmControlPanelState.ARMED_VACATION),
],
)
async def test_with_pending(hass: HomeAssistant, service, expected_state) -> None:
@ -164,7 +167,7 @@ async def test_with_pending(hass: HomeAssistant, service, expected_state) -> Non
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await hass.services.async_call(
alarm_control_panel.DOMAIN,
@ -173,7 +176,7 @@ async def test_with_pending(hass: HomeAssistant, service, expected_state) -> Non
blocking=True,
)
assert hass.states.get(entity_id).state == STATE_ALARM_ARMING
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMING
state = hass.states.get(entity_id)
assert state.attributes["next_state"] == expected_state
@ -203,11 +206,14 @@ async def test_with_pending(hass: HomeAssistant, service, expected_state) -> Non
@pytest.mark.parametrize(
("service", "expected_state"),
[
(SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY),
(SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS),
(SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION),
(SERVICE_ALARM_ARM_AWAY, AlarmControlPanelState.ARMED_AWAY),
(
SERVICE_ALARM_ARM_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
),
(SERVICE_ALARM_ARM_HOME, AlarmControlPanelState.ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, AlarmControlPanelState.ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, AlarmControlPanelState.ARMED_VACATION),
],
)
async def test_with_invalid_code(hass: HomeAssistant, service, expected_state) -> None:
@ -229,7 +235,7 @@ async def test_with_invalid_code(hass: HomeAssistant, service, expected_state) -
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
with pytest.raises(ServiceValidationError, match=r"^Invalid alarm code provided$"):
await hass.services.async_call(
@ -242,17 +248,20 @@ async def test_with_invalid_code(hass: HomeAssistant, service, expected_state) -
blocking=True,
)
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
@pytest.mark.parametrize(
("service", "expected_state"),
[
(SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY),
(SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS),
(SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION),
(SERVICE_ALARM_ARM_AWAY, AlarmControlPanelState.ARMED_AWAY),
(
SERVICE_ALARM_ARM_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
),
(SERVICE_ALARM_ARM_HOME, AlarmControlPanelState.ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, AlarmControlPanelState.ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, AlarmControlPanelState.ARMED_VACATION),
],
)
async def test_with_template_code(hass: HomeAssistant, service, expected_state) -> None:
@ -274,7 +283,7 @@ async def test_with_template_code(hass: HomeAssistant, service, expected_state)
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await hass.services.async_call(
alarm_control_panel.DOMAIN,
@ -290,11 +299,14 @@ async def test_with_template_code(hass: HomeAssistant, service, expected_state)
@pytest.mark.parametrize(
("service", "expected_state"),
[
(SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY),
(SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS),
(SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION),
(SERVICE_ALARM_ARM_AWAY, AlarmControlPanelState.ARMED_AWAY),
(
SERVICE_ALARM_ARM_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
),
(SERVICE_ALARM_ARM_HOME, AlarmControlPanelState.ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, AlarmControlPanelState.ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, AlarmControlPanelState.ARMED_VACATION),
],
)
async def test_with_specific_pending(
@ -324,7 +336,7 @@ async def test_with_specific_pending(
blocking=True,
)
assert hass.states.get(entity_id).state == STATE_ALARM_ARMING
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMING
future = dt_util.utcnow() + timedelta(seconds=2)
with patch(
@ -355,11 +367,11 @@ async def test_trigger_no_pending(hass: HomeAssistant) -> None:
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass, entity_id=entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
assert hass.states.get(entity_id).state == AlarmControlPanelState.PENDING
future = dt_util.utcnow() + timedelta(seconds=60)
with patch(
@ -370,8 +382,8 @@ async def test_trigger_no_pending(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.attributes["previous_state"] == STATE_ALARM_DISARMED
assert state.state == STATE_ALARM_TRIGGERED
assert state.attributes["previous_state"] == AlarmControlPanelState.DISARMED
assert state.state == AlarmControlPanelState.TRIGGERED
async def test_trigger_with_delay(hass: HomeAssistant) -> None:
@ -394,17 +406,17 @@ async def test_trigger_with_delay(hass: HomeAssistant) -> None:
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_away(hass, CODE)
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["next_state"] == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["next_state"] == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=1)
with patch(
@ -415,8 +427,8 @@ async def test_trigger_with_delay(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.attributes["previous_state"] == STATE_ALARM_ARMED_AWAY
assert state.state == STATE_ALARM_TRIGGERED
assert state.attributes["previous_state"] == AlarmControlPanelState.ARMED_AWAY
assert state.state == AlarmControlPanelState.TRIGGERED
async def test_trigger_zero_trigger_time(hass: HomeAssistant) -> None:
@ -438,11 +450,11 @@ async def test_trigger_zero_trigger_time(hass: HomeAssistant) -> None:
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass)
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_trigger_zero_trigger_time_with_pending(hass: HomeAssistant) -> None:
@ -464,11 +476,11 @@ async def test_trigger_zero_trigger_time_with_pending(hass: HomeAssistant) -> No
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass)
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_trigger_with_pending(hass: HomeAssistant) -> None:
@ -490,14 +502,14 @@ async def test_trigger_with_pending(hass: HomeAssistant) -> None:
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass)
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
assert hass.states.get(entity_id).state == AlarmControlPanelState.PENDING
state = hass.states.get(entity_id)
assert state.attributes["next_state"] == STATE_ALARM_TRIGGERED
assert state.attributes["next_state"] == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=2)
with patch(
@ -508,8 +520,8 @@ async def test_trigger_with_pending(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.attributes["previous_state"] == STATE_ALARM_DISARMED
assert state.state == STATE_ALARM_TRIGGERED
assert state.attributes["previous_state"] == AlarmControlPanelState.DISARMED
assert state.state == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -520,7 +532,7 @@ async def test_trigger_with_pending(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_DISARMED
assert state.state == AlarmControlPanelState.DISARMED
async def test_trigger_with_unused_specific_delay(hass: HomeAssistant) -> None:
@ -544,17 +556,17 @@ async def test_trigger_with_unused_specific_delay(hass: HomeAssistant) -> None:
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_away(hass, CODE)
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["next_state"] == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["next_state"] == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -565,8 +577,8 @@ async def test_trigger_with_unused_specific_delay(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.attributes["previous_state"] == STATE_ALARM_ARMED_AWAY
assert state.state == STATE_ALARM_TRIGGERED
assert state.attributes["previous_state"] == AlarmControlPanelState.ARMED_AWAY
assert state.state == AlarmControlPanelState.TRIGGERED
async def test_trigger_with_specific_delay(hass: HomeAssistant) -> None:
@ -590,17 +602,17 @@ async def test_trigger_with_specific_delay(hass: HomeAssistant) -> None:
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_away(hass, CODE)
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["next_state"] == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["next_state"] == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=1)
with patch(
@ -611,8 +623,8 @@ async def test_trigger_with_specific_delay(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.attributes["previous_state"] == STATE_ALARM_ARMED_AWAY
assert state.state == STATE_ALARM_TRIGGERED
assert state.attributes["previous_state"] == AlarmControlPanelState.ARMED_AWAY
assert state.state == AlarmControlPanelState.TRIGGERED
async def test_trigger_with_pending_and_delay(hass: HomeAssistant) -> None:
@ -635,17 +647,17 @@ async def test_trigger_with_pending_and_delay(hass: HomeAssistant) -> None:
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_away(hass, CODE)
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["next_state"] == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["next_state"] == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=1)
with patch(
@ -656,8 +668,8 @@ async def test_trigger_with_pending_and_delay(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["next_state"] == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["next_state"] == AlarmControlPanelState.TRIGGERED
future += timedelta(seconds=1)
with patch(
@ -668,8 +680,8 @@ async def test_trigger_with_pending_and_delay(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.attributes["previous_state"] == STATE_ALARM_ARMED_AWAY
assert state.state == STATE_ALARM_TRIGGERED
assert state.attributes["previous_state"] == AlarmControlPanelState.ARMED_AWAY
assert state.state == AlarmControlPanelState.TRIGGERED
async def test_trigger_with_pending_and_specific_delay(hass: HomeAssistant) -> None:
@ -693,17 +705,17 @@ async def test_trigger_with_pending_and_specific_delay(hass: HomeAssistant) -> N
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_away(hass, CODE)
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["next_state"] == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["next_state"] == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=1)
with patch(
@ -714,8 +726,8 @@ async def test_trigger_with_pending_and_specific_delay(hass: HomeAssistant) -> N
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["next_state"] == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["next_state"] == AlarmControlPanelState.TRIGGERED
future += timedelta(seconds=1)
with patch(
@ -726,8 +738,8 @@ async def test_trigger_with_pending_and_specific_delay(hass: HomeAssistant) -> N
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.attributes["previous_state"] == STATE_ALARM_ARMED_AWAY
assert state.state == STATE_ALARM_TRIGGERED
assert state.attributes["previous_state"] == AlarmControlPanelState.ARMED_AWAY
assert state.state == AlarmControlPanelState.TRIGGERED
async def test_trigger_with_specific_pending(hass: HomeAssistant) -> None:
@ -752,7 +764,7 @@ async def test_trigger_with_specific_pending(hass: HomeAssistant) -> None:
await common.async_alarm_trigger(hass)
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
assert hass.states.get(entity_id).state == AlarmControlPanelState.PENDING
future = dt_util.utcnow() + timedelta(seconds=2)
with patch(
@ -763,8 +775,8 @@ async def test_trigger_with_specific_pending(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.attributes["previous_state"] == STATE_ALARM_DISARMED
assert state.state == STATE_ALARM_TRIGGERED
assert state.attributes["previous_state"] == AlarmControlPanelState.DISARMED
assert state.state == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -774,7 +786,7 @@ async def test_trigger_with_specific_pending(hass: HomeAssistant) -> None:
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_trigger_with_disarm_after_trigger(hass: HomeAssistant) -> None:
@ -796,13 +808,13 @@ async def test_trigger_with_disarm_after_trigger(hass: HomeAssistant) -> None:
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.attributes["previous_state"] == STATE_ALARM_DISARMED
assert state.state == STATE_ALARM_TRIGGERED
assert state.attributes["previous_state"] == AlarmControlPanelState.DISARMED
assert state.state == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -812,7 +824,7 @@ async def test_trigger_with_disarm_after_trigger(hass: HomeAssistant) -> None:
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_trigger_with_zero_specific_trigger_time(hass: HomeAssistant) -> None:
@ -835,11 +847,11 @@ async def test_trigger_with_zero_specific_trigger_time(hass: HomeAssistant) -> N
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass, entity_id=entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_trigger_with_unused_zero_specific_trigger_time(
@ -864,13 +876,13 @@ async def test_trigger_with_unused_zero_specific_trigger_time(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.attributes["previous_state"] == STATE_ALARM_DISARMED
assert state.state == STATE_ALARM_TRIGGERED
assert state.attributes["previous_state"] == AlarmControlPanelState.DISARMED
assert state.state == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -880,7 +892,7 @@ async def test_trigger_with_unused_zero_specific_trigger_time(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_trigger_with_specific_trigger_time(hass: HomeAssistant) -> None:
@ -902,13 +914,13 @@ async def test_trigger_with_specific_trigger_time(hass: HomeAssistant) -> None:
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.attributes["previous_state"] == STATE_ALARM_DISARMED
assert state.state == STATE_ALARM_TRIGGERED
assert state.attributes["previous_state"] == AlarmControlPanelState.DISARMED
assert state.state == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -918,7 +930,7 @@ async def test_trigger_with_specific_trigger_time(hass: HomeAssistant) -> None:
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_trigger_with_no_disarm_after_trigger(hass: HomeAssistant) -> None:
@ -941,17 +953,17 @@ async def test_trigger_with_no_disarm_after_trigger(hass: HomeAssistant) -> None
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_away(hass, CODE, entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.attributes["previous_state"] == STATE_ALARM_ARMED_AWAY
assert state.state == STATE_ALARM_TRIGGERED
assert state.attributes["previous_state"] == AlarmControlPanelState.ARMED_AWAY
assert state.state == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -961,7 +973,7 @@ async def test_trigger_with_no_disarm_after_trigger(hass: HomeAssistant) -> None
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
async def test_back_to_back_trigger_with_no_disarm_after_trigger(
@ -986,17 +998,17 @@ async def test_back_to_back_trigger_with_no_disarm_after_trigger(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_away(hass, CODE, entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.attributes["previous_state"] == STATE_ALARM_ARMED_AWAY
assert state.state == STATE_ALARM_TRIGGERED
assert state.attributes["previous_state"] == AlarmControlPanelState.ARMED_AWAY
assert state.state == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -1006,13 +1018,13 @@ async def test_back_to_back_trigger_with_no_disarm_after_trigger(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.attributes["previous_state"] == STATE_ALARM_ARMED_AWAY
assert state.state == STATE_ALARM_TRIGGERED
assert state.attributes["previous_state"] == AlarmControlPanelState.ARMED_AWAY
assert state.state == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -1022,7 +1034,7 @@ async def test_back_to_back_trigger_with_no_disarm_after_trigger(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
async def test_disarm_while_pending_trigger(hass: HomeAssistant) -> None:
@ -1043,15 +1055,15 @@ async def test_disarm_while_pending_trigger(hass: HomeAssistant) -> None:
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass)
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
assert hass.states.get(entity_id).state == AlarmControlPanelState.PENDING
await common.async_alarm_disarm(hass, entity_id=entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -1061,7 +1073,7 @@ async def test_disarm_while_pending_trigger(hass: HomeAssistant) -> None:
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_disarm_during_trigger_with_invalid_code(hass: HomeAssistant) -> None:
@ -1083,7 +1095,7 @@ async def test_disarm_during_trigger_with_invalid_code(hass: HomeAssistant) -> N
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
assert (
hass.states.get(entity_id).attributes[alarm_control_panel.ATTR_CODE_FORMAT]
== alarm_control_panel.CodeFormat.NUMBER
@ -1091,12 +1103,12 @@ async def test_disarm_during_trigger_with_invalid_code(hass: HomeAssistant) -> N
await common.async_alarm_trigger(hass)
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
assert hass.states.get(entity_id).state == AlarmControlPanelState.PENDING
with pytest.raises(ServiceValidationError, match=r"^Invalid alarm code provided$"):
await common.async_alarm_disarm(hass, entity_id=entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
assert hass.states.get(entity_id).state == AlarmControlPanelState.PENDING
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -1107,8 +1119,8 @@ async def test_disarm_during_trigger_with_invalid_code(hass: HomeAssistant) -> N
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.attributes["previous_state"] == STATE_ALARM_DISARMED
assert state.state == STATE_ALARM_TRIGGERED
assert state.attributes["previous_state"] == AlarmControlPanelState.DISARMED
assert state.state == AlarmControlPanelState.TRIGGERED
async def test_disarm_with_template_code(hass: HomeAssistant) -> None:
@ -1130,23 +1142,23 @@ async def test_disarm_with_template_code(hass: HomeAssistant) -> None:
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_home(hass, "def")
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_ARMED_HOME
assert state.state == AlarmControlPanelState.ARMED_HOME
with pytest.raises(ServiceValidationError, match=r"^Invalid alarm code provided$"):
await common.async_alarm_disarm(hass, "def")
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_ARMED_HOME
assert state.state == AlarmControlPanelState.ARMED_HOME
await common.async_alarm_disarm(hass, "abc")
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_DISARMED
assert state.state == AlarmControlPanelState.DISARMED
async def test_arm_away_after_disabled_disarmed(hass: HomeAssistant) -> None:
@ -1171,21 +1183,21 @@ async def test_arm_away_after_disabled_disarmed(hass: HomeAssistant) -> None:
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_away(hass, CODE)
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_ARMING
assert state.attributes["previous_state"] == STATE_ALARM_DISARMED
assert state.attributes["next_state"] == STATE_ALARM_ARMED_AWAY
assert state.state == AlarmControlPanelState.ARMING
assert state.attributes["previous_state"] == AlarmControlPanelState.DISARMED
assert state.attributes["next_state"] == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_ARMING
assert state.attributes["previous_state"] == STATE_ALARM_DISARMED
assert state.attributes["next_state"] == STATE_ALARM_ARMED_AWAY
assert state.state == AlarmControlPanelState.ARMING
assert state.attributes["previous_state"] == AlarmControlPanelState.DISARMED
assert state.attributes["next_state"] == AlarmControlPanelState.ARMED_AWAY
future = dt_util.utcnow() + timedelta(seconds=1)
with freeze_time(future):
@ -1193,14 +1205,14 @@ async def test_arm_away_after_disabled_disarmed(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_ARMED_AWAY
assert state.state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["previous_state"] == STATE_ALARM_ARMED_AWAY
assert state.attributes["next_state"] == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["previous_state"] == AlarmControlPanelState.ARMED_AWAY
assert state.attributes["next_state"] == AlarmControlPanelState.TRIGGERED
future += timedelta(seconds=1)
with freeze_time(future):
@ -1208,19 +1220,19 @@ async def test_arm_away_after_disabled_disarmed(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.attributes["previous_state"] == STATE_ALARM_ARMED_AWAY
assert state.state == STATE_ALARM_TRIGGERED
assert state.attributes["previous_state"] == AlarmControlPanelState.ARMED_AWAY
assert state.state == AlarmControlPanelState.TRIGGERED
@pytest.mark.parametrize(
"expected_state",
[
(STATE_ALARM_ARMED_AWAY),
(STATE_ALARM_ARMED_CUSTOM_BYPASS),
(STATE_ALARM_ARMED_HOME),
(STATE_ALARM_ARMED_NIGHT),
(STATE_ALARM_ARMED_VACATION),
(STATE_ALARM_DISARMED),
(AlarmControlPanelState.ARMED_AWAY),
(AlarmControlPanelState.ARMED_CUSTOM_BYPASS),
(AlarmControlPanelState.ARMED_HOME),
(AlarmControlPanelState.ARMED_NIGHT),
(AlarmControlPanelState.ARMED_VACATION),
(AlarmControlPanelState.DISARMED),
],
)
async def test_restore_state(hass: HomeAssistant, expected_state) -> None:
@ -1253,11 +1265,11 @@ async def test_restore_state(hass: HomeAssistant, expected_state) -> None:
@pytest.mark.parametrize(
"expected_state",
[
(STATE_ALARM_ARMED_AWAY),
(STATE_ALARM_ARMED_CUSTOM_BYPASS),
(STATE_ALARM_ARMED_HOME),
(STATE_ALARM_ARMED_NIGHT),
(STATE_ALARM_ARMED_VACATION),
(AlarmControlPanelState.ARMED_AWAY),
(AlarmControlPanelState.ARMED_CUSTOM_BYPASS),
(AlarmControlPanelState.ARMED_HOME),
(AlarmControlPanelState.ARMED_NIGHT),
(AlarmControlPanelState.ARMED_VACATION),
],
)
async def test_restore_state_arming(hass: HomeAssistant, expected_state) -> None:
@ -1265,7 +1277,7 @@ async def test_restore_state_arming(hass: HomeAssistant, expected_state) -> None
time = dt_util.utcnow() - timedelta(seconds=15)
entity_id = "alarm_control_panel.test"
attributes = {
"previous_state": STATE_ALARM_DISARMED,
"previous_state": AlarmControlPanelState.DISARMED,
"next_state": expected_state,
}
mock_restore_cache(
@ -1292,9 +1304,9 @@ async def test_restore_state_arming(hass: HomeAssistant, expected_state) -> None
state = hass.states.get(entity_id)
assert state
assert state.attributes["previous_state"] == STATE_ALARM_DISARMED
assert state.attributes["previous_state"] == AlarmControlPanelState.DISARMED
assert state.attributes["next_state"] == expected_state
assert state.state == STATE_ALARM_ARMING
assert state.state == AlarmControlPanelState.ARMING
future = time + timedelta(seconds=61)
with freeze_time(future):
@ -1308,12 +1320,12 @@ async def test_restore_state_arming(hass: HomeAssistant, expected_state) -> None
@pytest.mark.parametrize(
"previous_state",
[
(STATE_ALARM_ARMED_AWAY),
(STATE_ALARM_ARMED_CUSTOM_BYPASS),
(STATE_ALARM_ARMED_HOME),
(STATE_ALARM_ARMED_NIGHT),
(STATE_ALARM_ARMED_VACATION),
(STATE_ALARM_DISARMED),
(AlarmControlPanelState.ARMED_AWAY),
(AlarmControlPanelState.ARMED_CUSTOM_BYPASS),
(AlarmControlPanelState.ARMED_HOME),
(AlarmControlPanelState.ARMED_NIGHT),
(AlarmControlPanelState.ARMED_VACATION),
(AlarmControlPanelState.DISARMED),
],
)
async def test_restore_state_pending(hass: HomeAssistant, previous_state) -> None:
@ -1322,11 +1334,18 @@ async def test_restore_state_pending(hass: HomeAssistant, previous_state) -> Non
entity_id = "alarm_control_panel.test"
attributes = {
"previous_state": previous_state,
"next_state": STATE_ALARM_TRIGGERED,
"next_state": AlarmControlPanelState.TRIGGERED,
}
mock_restore_cache(
hass,
(State(entity_id, STATE_ALARM_TRIGGERED, attributes, last_updated=time),),
(
State(
entity_id,
AlarmControlPanelState.TRIGGERED,
attributes,
last_updated=time,
),
),
)
hass.set_state(CoreState.starting)
@ -1351,8 +1370,8 @@ async def test_restore_state_pending(hass: HomeAssistant, previous_state) -> Non
state = hass.states.get(entity_id)
assert state
assert state.attributes["previous_state"] == previous_state
assert state.attributes["next_state"] == STATE_ALARM_TRIGGERED
assert state.state == STATE_ALARM_PENDING
assert state.attributes["next_state"] == AlarmControlPanelState.TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
future = time + timedelta(seconds=61)
with freeze_time(future):
@ -1360,7 +1379,7 @@ async def test_restore_state_pending(hass: HomeAssistant, previous_state) -> Non
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.TRIGGERED
future = time + timedelta(seconds=121)
with freeze_time(future):
@ -1374,12 +1393,12 @@ async def test_restore_state_pending(hass: HomeAssistant, previous_state) -> Non
@pytest.mark.parametrize(
"previous_state",
[
(STATE_ALARM_ARMED_AWAY),
(STATE_ALARM_ARMED_CUSTOM_BYPASS),
(STATE_ALARM_ARMED_HOME),
(STATE_ALARM_ARMED_NIGHT),
(STATE_ALARM_ARMED_VACATION),
(STATE_ALARM_DISARMED),
(AlarmControlPanelState.ARMED_AWAY),
(AlarmControlPanelState.ARMED_CUSTOM_BYPASS),
(AlarmControlPanelState.ARMED_HOME),
(AlarmControlPanelState.ARMED_NIGHT),
(AlarmControlPanelState.ARMED_VACATION),
(AlarmControlPanelState.DISARMED),
],
)
async def test_restore_state_triggered(hass: HomeAssistant, previous_state) -> None:
@ -1391,7 +1410,14 @@ async def test_restore_state_triggered(hass: HomeAssistant, previous_state) -> N
}
mock_restore_cache(
hass,
(State(entity_id, STATE_ALARM_TRIGGERED, attributes, last_updated=time),),
(
State(
entity_id,
AlarmControlPanelState.TRIGGERED,
attributes,
last_updated=time,
),
),
)
hass.set_state(CoreState.starting)
@ -1417,7 +1443,7 @@ async def test_restore_state_triggered(hass: HomeAssistant, previous_state) -> N
assert state
assert state.attributes[ATTR_PREVIOUS_STATE] == previous_state
assert state.attributes[ATTR_NEXT_STATE] is None
assert state.state == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.TRIGGERED
future = time + timedelta(seconds=121)
with freeze_time(future):
@ -1433,11 +1459,18 @@ async def test_restore_state_triggered_long_ago(hass: HomeAssistant) -> None:
time = dt_util.utcnow() - timedelta(seconds=125)
entity_id = "alarm_control_panel.test"
attributes = {
"previous_state": STATE_ALARM_ARMED_AWAY,
"previous_state": AlarmControlPanelState.ARMED_AWAY,
}
mock_restore_cache(
hass,
(State(entity_id, STATE_ALARM_TRIGGERED, attributes, last_updated=time),),
(
State(
entity_id,
AlarmControlPanelState.TRIGGERED,
attributes,
last_updated=time,
),
),
)
hass.set_state(CoreState.starting)
@ -1460,7 +1493,7 @@ async def test_restore_state_triggered_long_ago(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_DISARMED
assert state.state == AlarmControlPanelState.DISARMED
async def test_default_arming_states(hass: HomeAssistant) -> None:

View File

@ -7,6 +7,7 @@ from freezegun import freeze_time
import pytest
from homeassistant.components import alarm_control_panel
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
from homeassistant.const import (
ATTR_CODE,
ATTR_ENTITY_ID,
@ -15,14 +16,6 @@ from homeassistant.const import (
SERVICE_ALARM_ARM_HOME,
SERVICE_ALARM_ARM_NIGHT,
SERVICE_ALARM_ARM_VACATION,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
@ -78,11 +71,14 @@ async def test_fail_setup_without_command_topic(
@pytest.mark.parametrize(
("service", "expected_state"),
[
(SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY),
(SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS),
(SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION),
(SERVICE_ALARM_ARM_AWAY, AlarmControlPanelState.ARMED_AWAY),
(
SERVICE_ALARM_ARM_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
),
(SERVICE_ALARM_ARM_HOME, AlarmControlPanelState.ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, AlarmControlPanelState.ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, AlarmControlPanelState.ARMED_VACATION),
],
)
async def test_no_pending(
@ -111,7 +107,7 @@ async def test_no_pending(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await hass.services.async_call(
alarm_control_panel.DOMAIN,
@ -126,11 +122,14 @@ async def test_no_pending(
@pytest.mark.parametrize(
("service", "expected_state"),
[
(SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY),
(SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS),
(SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION),
(SERVICE_ALARM_ARM_AWAY, AlarmControlPanelState.ARMED_AWAY),
(
SERVICE_ALARM_ARM_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
),
(SERVICE_ALARM_ARM_HOME, AlarmControlPanelState.ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, AlarmControlPanelState.ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, AlarmControlPanelState.ARMED_VACATION),
],
)
async def test_no_pending_when_code_not_req(
@ -160,7 +159,7 @@ async def test_no_pending_when_code_not_req(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await hass.services.async_call(
alarm_control_panel.DOMAIN,
@ -175,11 +174,14 @@ async def test_no_pending_when_code_not_req(
@pytest.mark.parametrize(
("service", "expected_state"),
[
(SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY),
(SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS),
(SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION),
(SERVICE_ALARM_ARM_AWAY, AlarmControlPanelState.ARMED_AWAY),
(
SERVICE_ALARM_ARM_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
),
(SERVICE_ALARM_ARM_HOME, AlarmControlPanelState.ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, AlarmControlPanelState.ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, AlarmControlPanelState.ARMED_VACATION),
],
)
async def test_with_pending(
@ -208,7 +210,7 @@ async def test_with_pending(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await hass.services.async_call(
alarm_control_panel.DOMAIN,
@ -217,7 +219,7 @@ async def test_with_pending(
blocking=True,
)
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
assert hass.states.get(entity_id).state == AlarmControlPanelState.PENDING
state = hass.states.get(entity_id)
assert state.attributes["post_pending_state"] == expected_state
@ -247,11 +249,14 @@ async def test_with_pending(
@pytest.mark.parametrize(
("service", "expected_state"),
[
(SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY),
(SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS),
(SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION),
(SERVICE_ALARM_ARM_AWAY, AlarmControlPanelState.ARMED_AWAY),
(
SERVICE_ALARM_ARM_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
),
(SERVICE_ALARM_ARM_HOME, AlarmControlPanelState.ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, AlarmControlPanelState.ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, AlarmControlPanelState.ARMED_VACATION),
],
)
async def test_with_invalid_code(
@ -280,7 +285,7 @@ async def test_with_invalid_code(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
with pytest.raises(HomeAssistantError, match=r"^Invalid alarm code provided$"):
await hass.services.async_call(
@ -290,17 +295,20 @@ async def test_with_invalid_code(
blocking=True,
)
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
@pytest.mark.parametrize(
("service", "expected_state"),
[
(SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY),
(SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS),
(SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION),
(SERVICE_ALARM_ARM_AWAY, AlarmControlPanelState.ARMED_AWAY),
(
SERVICE_ALARM_ARM_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
),
(SERVICE_ALARM_ARM_HOME, AlarmControlPanelState.ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, AlarmControlPanelState.ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, AlarmControlPanelState.ARMED_VACATION),
],
)
async def test_with_template_code(
@ -329,7 +337,7 @@ async def test_with_template_code(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await hass.services.async_call(
alarm_control_panel.DOMAIN,
@ -345,11 +353,14 @@ async def test_with_template_code(
@pytest.mark.parametrize(
("service", "expected_state"),
[
(SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY),
(SERVICE_ALARM_ARM_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS),
(SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, STATE_ALARM_ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, STATE_ALARM_ARMED_VACATION),
(SERVICE_ALARM_ARM_AWAY, AlarmControlPanelState.ARMED_AWAY),
(
SERVICE_ALARM_ARM_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
),
(SERVICE_ALARM_ARM_HOME, AlarmControlPanelState.ARMED_HOME),
(SERVICE_ALARM_ARM_NIGHT, AlarmControlPanelState.ARMED_NIGHT),
(SERVICE_ALARM_ARM_VACATION, AlarmControlPanelState.ARMED_VACATION),
],
)
async def test_with_specific_pending(
@ -384,7 +395,7 @@ async def test_with_specific_pending(
blocking=True,
)
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
assert hass.states.get(entity_id).state == AlarmControlPanelState.PENDING
future = dt_util.utcnow() + timedelta(seconds=2)
with patch(
@ -419,12 +430,12 @@ async def test_trigger_no_pending(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass, entity_id=entity_id)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
assert hass.states.get(entity_id).state == AlarmControlPanelState.PENDING
future = dt_util.utcnow() + timedelta(seconds=60)
with patch(
@ -434,7 +445,7 @@ async def test_trigger_no_pending(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
async def test_trigger_with_delay(
@ -461,17 +472,17 @@ async def test_trigger_with_delay(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_away(hass, CODE)
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["post_pending_state"] == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["post_pending_state"] == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=1)
with patch(
@ -482,7 +493,7 @@ async def test_trigger_with_delay(
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.TRIGGERED
async def test_trigger_zero_trigger_time(
@ -508,11 +519,11 @@ async def test_trigger_zero_trigger_time(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass)
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_trigger_zero_trigger_time_with_pending(
@ -538,11 +549,11 @@ async def test_trigger_zero_trigger_time_with_pending(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass)
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_trigger_with_pending(
@ -568,14 +579,14 @@ async def test_trigger_with_pending(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass)
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
assert hass.states.get(entity_id).state == AlarmControlPanelState.PENDING
state = hass.states.get(entity_id)
assert state.attributes["post_pending_state"] == STATE_ALARM_TRIGGERED
assert state.attributes["post_pending_state"] == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=2)
with patch(
@ -585,7 +596,7 @@ async def test_trigger_with_pending(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -595,7 +606,7 @@ async def test_trigger_with_pending(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_trigger_with_disarm_after_trigger(
@ -621,11 +632,11 @@ async def test_trigger_with_disarm_after_trigger(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass, entity_id=entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -635,7 +646,7 @@ async def test_trigger_with_disarm_after_trigger(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_trigger_with_zero_specific_trigger_time(
@ -662,11 +673,11 @@ async def test_trigger_with_zero_specific_trigger_time(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass, entity_id=entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_trigger_with_unused_zero_specific_trigger_time(
@ -693,11 +704,11 @@ async def test_trigger_with_unused_zero_specific_trigger_time(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass, entity_id=entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -707,7 +718,7 @@ async def test_trigger_with_unused_zero_specific_trigger_time(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_trigger_with_specific_trigger_time(
@ -733,11 +744,11 @@ async def test_trigger_with_specific_trigger_time(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass, entity_id=entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -747,7 +758,7 @@ async def test_trigger_with_specific_trigger_time(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_back_to_back_trigger_with_no_disarm_after_trigger(
@ -773,15 +784,15 @@ async def test_back_to_back_trigger_with_no_disarm_after_trigger(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_away(hass, CODE, entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -791,11 +802,11 @@ async def test_back_to_back_trigger_with_no_disarm_after_trigger(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -805,7 +816,7 @@ async def test_back_to_back_trigger_with_no_disarm_after_trigger(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
async def test_disarm_while_pending_trigger(
@ -830,15 +841,15 @@ async def test_disarm_while_pending_trigger(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass)
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
assert hass.states.get(entity_id).state == AlarmControlPanelState.PENDING
await common.async_alarm_disarm(hass, entity_id=entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -848,7 +859,7 @@ async def test_disarm_while_pending_trigger(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_disarm_during_trigger_with_invalid_code(
@ -874,7 +885,7 @@ async def test_disarm_during_trigger_with_invalid_code(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
assert (
hass.states.get(entity_id).attributes[alarm_control_panel.ATTR_CODE_FORMAT]
== alarm_control_panel.CodeFormat.NUMBER
@ -882,12 +893,12 @@ async def test_disarm_during_trigger_with_invalid_code(
await common.async_alarm_trigger(hass)
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
assert hass.states.get(entity_id).state == AlarmControlPanelState.PENDING
with pytest.raises(HomeAssistantError, match=r"Invalid alarm code provided$"):
await common.async_alarm_disarm(hass, entity_id=entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
assert hass.states.get(entity_id).state == AlarmControlPanelState.PENDING
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -897,7 +908,7 @@ async def test_disarm_during_trigger_with_invalid_code(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
async def test_trigger_with_unused_specific_delay(
@ -925,17 +936,17 @@ async def test_trigger_with_unused_specific_delay(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_away(hass, CODE)
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["post_pending_state"] == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["post_pending_state"] == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -946,7 +957,7 @@ async def test_trigger_with_unused_specific_delay(
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.TRIGGERED
async def test_trigger_with_specific_delay(
@ -974,17 +985,17 @@ async def test_trigger_with_specific_delay(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_away(hass, CODE)
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["post_pending_state"] == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["post_pending_state"] == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=1)
with patch(
@ -995,7 +1006,7 @@ async def test_trigger_with_specific_delay(
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.TRIGGERED
async def test_trigger_with_pending_and_delay(
@ -1023,17 +1034,17 @@ async def test_trigger_with_pending_and_delay(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_away(hass, CODE)
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["post_pending_state"] == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["post_pending_state"] == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=1)
with patch(
@ -1044,8 +1055,8 @@ async def test_trigger_with_pending_and_delay(
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["post_pending_state"] == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["post_pending_state"] == AlarmControlPanelState.TRIGGERED
future += timedelta(seconds=1)
with patch(
@ -1056,7 +1067,7 @@ async def test_trigger_with_pending_and_delay(
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.TRIGGERED
async def test_trigger_with_pending_and_specific_delay(
@ -1085,17 +1096,17 @@ async def test_trigger_with_pending_and_specific_delay(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_away(hass, CODE)
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["post_pending_state"] == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["post_pending_state"] == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=1)
with patch(
@ -1106,8 +1117,8 @@ async def test_trigger_with_pending_and_specific_delay(
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["post_pending_state"] == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["post_pending_state"] == AlarmControlPanelState.TRIGGERED
future += timedelta(seconds=1)
with patch(
@ -1118,7 +1129,7 @@ async def test_trigger_with_pending_and_specific_delay(
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.TRIGGERED
async def test_trigger_with_specific_pending(
@ -1147,7 +1158,7 @@ async def test_trigger_with_specific_pending(
await common.async_alarm_trigger(hass)
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
assert hass.states.get(entity_id).state == AlarmControlPanelState.PENDING
future = dt_util.utcnow() + timedelta(seconds=2)
with patch(
@ -1157,7 +1168,7 @@ async def test_trigger_with_specific_pending(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -1167,7 +1178,7 @@ async def test_trigger_with_specific_pending(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_trigger_with_no_disarm_after_trigger(
@ -1194,15 +1205,15 @@ async def test_trigger_with_no_disarm_after_trigger(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_away(hass, CODE, entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
future = dt_util.utcnow() + timedelta(seconds=5)
with patch(
@ -1212,7 +1223,7 @@ async def test_trigger_with_no_disarm_after_trigger(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
async def test_arm_away_after_disabled_disarmed(
@ -1241,21 +1252,21 @@ async def test_arm_away_after_disabled_disarmed(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_away(hass, CODE)
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["pre_pending_state"] == STATE_ALARM_DISARMED
assert state.attributes["post_pending_state"] == STATE_ALARM_ARMED_AWAY
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["pre_pending_state"] == AlarmControlPanelState.DISARMED
assert state.attributes["post_pending_state"] == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["pre_pending_state"] == STATE_ALARM_DISARMED
assert state.attributes["post_pending_state"] == STATE_ALARM_ARMED_AWAY
assert state.state == AlarmControlPanelState.PENDING
assert state.attributes["pre_pending_state"] == AlarmControlPanelState.DISARMED
assert state.attributes["post_pending_state"] == AlarmControlPanelState.ARMED_AWAY
future = dt_util.utcnow() + timedelta(seconds=1)
with freeze_time(future):
@ -1263,14 +1274,18 @@ async def test_arm_away_after_disabled_disarmed(
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_ARMED_AWAY
assert state.state == AlarmControlPanelState.ARMED_AWAY
await common.async_alarm_trigger(hass, entity_id=entity_id)
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_PENDING
assert state.attributes["pre_pending_state"] == STATE_ALARM_ARMED_AWAY
assert state.attributes["post_pending_state"] == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.PENDING
assert (
state.attributes["pre_pending_state"] == AlarmControlPanelState.ARMED_AWAY
)
assert (
state.attributes["post_pending_state"] == AlarmControlPanelState.TRIGGERED
)
future += timedelta(seconds=1)
with freeze_time(future):
@ -1278,7 +1293,7 @@ async def test_arm_away_after_disabled_disarmed(
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.TRIGGERED
async def test_disarm_with_template_code(
@ -1304,33 +1319,33 @@ async def test_disarm_with_template_code(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_arm_home(hass, "def")
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_ARMED_HOME
assert state.state == AlarmControlPanelState.ARMED_HOME
with pytest.raises(HomeAssistantError, match=r"Invalid alarm code provided$"):
await common.async_alarm_disarm(hass, "def")
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_ARMED_HOME
assert state.state == AlarmControlPanelState.ARMED_HOME
await common.async_alarm_disarm(hass, "abc")
state = hass.states.get(entity_id)
assert state.state == STATE_ALARM_DISARMED
assert state.state == AlarmControlPanelState.DISARMED
@pytest.mark.parametrize(
("config", "expected_state"),
[
("payload_arm_away", STATE_ALARM_ARMED_AWAY),
("payload_arm_custom_bypass", STATE_ALARM_ARMED_CUSTOM_BYPASS),
("payload_arm_home", STATE_ALARM_ARMED_HOME),
("payload_arm_night", STATE_ALARM_ARMED_NIGHT),
("payload_arm_vacation", STATE_ALARM_ARMED_VACATION),
("payload_arm_away", AlarmControlPanelState.ARMED_AWAY),
("payload_arm_custom_bypass", AlarmControlPanelState.ARMED_CUSTOM_BYPASS),
("payload_arm_home", AlarmControlPanelState.ARMED_HOME),
("payload_arm_night", AlarmControlPanelState.ARMED_NIGHT),
("payload_arm_vacation", AlarmControlPanelState.ARMED_VACATION),
],
)
async def test_arm_via_command_topic(
@ -1359,12 +1374,12 @@ async def test_arm_via_command_topic(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
# Fire the arm command via MQTT; ensure state changes to arming
async_fire_mqtt_message(hass, "alarm/command", command)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
assert hass.states.get(entity_id).state == AlarmControlPanelState.PENDING
# Fast-forward a little bit
future = dt_util.utcnow() + timedelta(seconds=1)
@ -1400,18 +1415,18 @@ async def test_disarm_pending_via_command_topic(
entity_id = "alarm_control_panel.test"
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
await common.async_alarm_trigger(hass)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_PENDING
assert hass.states.get(entity_id).state == AlarmControlPanelState.PENDING
# Now that we're pending, receive a command to disarm
async_fire_mqtt_message(hass, "alarm/command", "DISARM")
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
async def test_state_changes_are_published_to_mqtt(
@ -1437,7 +1452,7 @@ async def test_state_changes_are_published_to_mqtt(
# Component should send disarmed alarm state on startup
await hass.async_block_till_done()
mqtt_mock.async_publish.assert_called_once_with(
"alarm/state", STATE_ALARM_DISARMED, 0, True
"alarm/state", AlarmControlPanelState.DISARMED, 0, True
)
mqtt_mock.async_publish.reset_mock()
@ -1445,7 +1460,7 @@ async def test_state_changes_are_published_to_mqtt(
await common.async_alarm_arm_home(hass, "1234")
await hass.async_block_till_done()
mqtt_mock.async_publish.assert_called_once_with(
"alarm/state", STATE_ALARM_PENDING, 0, True
"alarm/state", AlarmControlPanelState.PENDING, 0, True
)
mqtt_mock.async_publish.reset_mock()
# Fast-forward a little bit
@ -1457,7 +1472,7 @@ async def test_state_changes_are_published_to_mqtt(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
mqtt_mock.async_publish.assert_called_once_with(
"alarm/state", STATE_ALARM_ARMED_HOME, 0, True
"alarm/state", AlarmControlPanelState.ARMED_HOME, 0, True
)
mqtt_mock.async_publish.reset_mock()
@ -1465,7 +1480,7 @@ async def test_state_changes_are_published_to_mqtt(
await common.async_alarm_arm_away(hass, "1234")
await hass.async_block_till_done()
mqtt_mock.async_publish.assert_called_once_with(
"alarm/state", STATE_ALARM_PENDING, 0, True
"alarm/state", AlarmControlPanelState.PENDING, 0, True
)
mqtt_mock.async_publish.reset_mock()
# Fast-forward a little bit
@ -1477,7 +1492,7 @@ async def test_state_changes_are_published_to_mqtt(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
mqtt_mock.async_publish.assert_called_once_with(
"alarm/state", STATE_ALARM_ARMED_AWAY, 0, True
"alarm/state", AlarmControlPanelState.ARMED_AWAY, 0, True
)
mqtt_mock.async_publish.reset_mock()
@ -1485,7 +1500,7 @@ async def test_state_changes_are_published_to_mqtt(
await common.async_alarm_arm_night(hass, "1234")
await hass.async_block_till_done()
mqtt_mock.async_publish.assert_called_once_with(
"alarm/state", STATE_ALARM_PENDING, 0, True
"alarm/state", AlarmControlPanelState.PENDING, 0, True
)
mqtt_mock.async_publish.reset_mock()
# Fast-forward a little bit
@ -1497,7 +1512,7 @@ async def test_state_changes_are_published_to_mqtt(
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
mqtt_mock.async_publish.assert_called_once_with(
"alarm/state", STATE_ALARM_ARMED_NIGHT, 0, True
"alarm/state", AlarmControlPanelState.ARMED_NIGHT, 0, True
)
mqtt_mock.async_publish.reset_mock()
@ -1505,7 +1520,7 @@ async def test_state_changes_are_published_to_mqtt(
await common.async_alarm_disarm(hass)
await hass.async_block_till_done()
mqtt_mock.async_publish.assert_called_once_with(
"alarm/state", STATE_ALARM_DISARMED, 0, True
"alarm/state", AlarmControlPanelState.DISARMED, 0, True
)

View File

@ -9,7 +9,10 @@ from unittest.mock import patch
import pytest
from homeassistant.components import alarm_control_panel, mqtt
from homeassistant.components.alarm_control_panel import AlarmControlPanelEntityFeature
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.components.mqtt.alarm_control_panel import (
MQTT_ALARM_ATTRIBUTES_BLOCKED,
)
@ -25,16 +28,6 @@ from homeassistant.const import (
SERVICE_ALARM_DISARM,
SERVICE_ALARM_TRIGGER,
SERVICE_RELOAD,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_DISARMING,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
STATE_UNKNOWN,
)
from homeassistant.core import HomeAssistant
@ -213,23 +206,23 @@ async def test_update_state_via_state_topic(
assert hass.states.get(entity_id).state == STATE_UNKNOWN
for state in (
STATE_ALARM_DISARMED,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_PENDING,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMING,
STATE_ALARM_TRIGGERED,
AlarmControlPanelState.DISARMED,
AlarmControlPanelState.ARMED_HOME,
AlarmControlPanelState.ARMED_AWAY,
AlarmControlPanelState.ARMED_NIGHT,
AlarmControlPanelState.ARMED_VACATION,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
AlarmControlPanelState.PENDING,
AlarmControlPanelState.ARMING,
AlarmControlPanelState.DISARMING,
AlarmControlPanelState.TRIGGERED,
):
async_fire_mqtt_message(hass, "alarm/state", state)
assert hass.states.get(entity_id).state == state
# Ignore empty payload (last state is STATE_ALARM_TRIGGERED)
# Ignore empty payload (last state is AlarmControlPanelState.TRIGGERED)
async_fire_mqtt_message(hass, "alarm/state", "")
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
# Reset state on `None` payload
async_fire_mqtt_message(hass, "alarm/state", "None")
@ -769,7 +762,7 @@ async def test_update_state_via_state_topic_template(
async_fire_mqtt_message(hass, "test-topic", "100")
state = hass.states.get("alarm_control_panel.test")
assert state.state == STATE_ALARM_ARMED_AWAY
assert state.state == AlarmControlPanelState.ARMED_AWAY
@pytest.mark.parametrize(
@ -1306,7 +1299,11 @@ async def test_entity_name(
@pytest.mark.parametrize(
("topic", "payload1", "payload2"),
[
("test-topic", STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME),
(
"test-topic",
AlarmControlPanelState.DISARMED,
AlarmControlPanelState.ARMED_HOME,
),
("availability-topic", "online", "offline"),
("json-attributes-topic", '{"attr1": "val1"}', '{"attr1": "val2"}'),
],

View File

@ -6,6 +6,7 @@ from nessclient import ArmingMode, ArmingState
import pytest
from homeassistant.components import alarm_control_panel
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
from homeassistant.components.ness_alarm import (
ATTR_CODE,
ATTR_OUTPUT_ID,
@ -24,13 +25,6 @@ from homeassistant.const import (
SERVICE_ALARM_ARM_HOME,
SERVICE_ALARM_DISARM,
SERVICE_ALARM_TRIGGER,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
STATE_UNKNOWN,
)
from homeassistant.core import HomeAssistant
@ -90,7 +84,9 @@ async def test_dispatch_state_change(hass: HomeAssistant, mock_nessclient) -> No
on_state_change(ArmingState.ARMING, None)
await hass.async_block_till_done()
assert hass.states.is_state("alarm_control_panel.alarm_panel", STATE_ALARM_ARMING)
assert hass.states.is_state(
"alarm_control_panel.alarm_panel", AlarmControlPanelState.ARMING
)
async def test_alarm_disarm(hass: HomeAssistant, mock_nessclient) -> None:
@ -178,15 +174,27 @@ async def test_arming_state_change(hass: HomeAssistant, mock_nessclient) -> None
"""Test arming state change handing."""
states = [
(ArmingState.UNKNOWN, None, STATE_UNKNOWN),
(ArmingState.DISARMED, None, STATE_ALARM_DISARMED),
(ArmingState.ARMING, None, STATE_ALARM_ARMING),
(ArmingState.EXIT_DELAY, None, STATE_ALARM_ARMING),
(ArmingState.ARMED, None, STATE_ALARM_ARMED_AWAY),
(ArmingState.ARMED, ArmingMode.ARMED_AWAY, STATE_ALARM_ARMED_AWAY),
(ArmingState.ARMED, ArmingMode.ARMED_HOME, STATE_ALARM_ARMED_HOME),
(ArmingState.ARMED, ArmingMode.ARMED_NIGHT, STATE_ALARM_ARMED_NIGHT),
(ArmingState.ENTRY_DELAY, None, STATE_ALARM_PENDING),
(ArmingState.TRIGGERED, None, STATE_ALARM_TRIGGERED),
(ArmingState.DISARMED, None, AlarmControlPanelState.DISARMED),
(ArmingState.ARMING, None, AlarmControlPanelState.ARMING),
(ArmingState.EXIT_DELAY, None, AlarmControlPanelState.ARMING),
(ArmingState.ARMED, None, AlarmControlPanelState.ARMED_AWAY),
(
ArmingState.ARMED,
ArmingMode.ARMED_AWAY,
AlarmControlPanelState.ARMED_AWAY,
),
(
ArmingState.ARMED,
ArmingMode.ARMED_HOME,
AlarmControlPanelState.ARMED_HOME,
),
(
ArmingState.ARMED,
ArmingMode.ARMED_NIGHT,
AlarmControlPanelState.ARMED_NIGHT,
),
(ArmingState.ENTRY_DELAY, None, AlarmControlPanelState.PENDING),
(ArmingState.TRIGGERED, None, AlarmControlPanelState.TRIGGERED),
]
await async_setup_component(hass, DOMAIN, VALID_CONFIG)

View File

@ -31,6 +31,7 @@ from homeassistant.components import (
switch,
update,
)
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
from homeassistant.components.climate import (
ATTR_CURRENT_TEMPERATURE,
ATTR_FAN_MODE,
@ -64,8 +65,6 @@ from homeassistant.const import (
CONTENT_TYPE_TEXT_PLAIN,
DEGREE,
PERCENTAGE,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_CLOSED,
STATE_CLOSING,
STATE_HOME,
@ -2466,7 +2465,7 @@ async def alarm_control_panel_fixture(
suggested_object_id="alarm_control_panel_1",
original_name="Alarm Control Panel 1",
)
set_state_with_entry(hass, alarm_control_panel_1, STATE_ALARM_ARMED_AWAY)
set_state_with_entry(hass, alarm_control_panel_1, AlarmControlPanelState.ARMED_AWAY)
data["alarm_control_panel_1"] = alarm_control_panel_1
alarm_control_panel_2 = entity_registry.async_get_or_create(
@ -2476,7 +2475,7 @@ async def alarm_control_panel_fixture(
suggested_object_id="alarm_control_panel_2",
original_name="Alarm Control Panel 2",
)
set_state_with_entry(hass, alarm_control_panel_2, STATE_ALARM_ARMED_HOME)
set_state_with_entry(hass, alarm_control_panel_2, AlarmControlPanelState.ARMED_HOME)
data["alarm_control_panel_2"] = alarm_control_panel_2
await hass.async_block_till_done()

View File

@ -6,7 +6,10 @@ from unittest.mock import AsyncMock, patch
from pyprosegur.installation import Status
import pytest
from homeassistant.components.alarm_control_panel import DOMAIN as ALARM_DOMAIN
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_DOMAIN,
AlarmControlPanelState,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_FRIENDLY_NAME,
@ -14,9 +17,6 @@ from homeassistant.const import (
SERVICE_ALARM_ARM_AWAY,
SERVICE_ALARM_ARM_HOME,
SERVICE_ALARM_DISARM,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
STATE_UNAVAILABLE,
)
from homeassistant.core import HomeAssistant
@ -93,9 +93,13 @@ async def test_connection_error(
@pytest.mark.parametrize(
("code", "alarm_service", "alarm_state"),
[
(Status.ARMED, SERVICE_ALARM_ARM_AWAY, STATE_ALARM_ARMED_AWAY),
(Status.PARTIALLY, SERVICE_ALARM_ARM_HOME, STATE_ALARM_ARMED_HOME),
(Status.DISARMED, SERVICE_ALARM_DISARM, STATE_ALARM_DISARMED),
(Status.ARMED, SERVICE_ALARM_ARM_AWAY, AlarmControlPanelState.ARMED_AWAY),
(
Status.PARTIALLY,
SERVICE_ALARM_ARM_HOME,
AlarmControlPanelState.ARMED_HOME,
),
(Status.DISARMED, SERVICE_ALARM_DISARM, AlarmControlPanelState.DISARMED),
],
)
async def test_arm(

View File

@ -9,6 +9,7 @@ import pytest
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_DOMAIN,
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
)
from homeassistant.components.risco import CannotConnectError, UnauthorizedError
from homeassistant.components.risco.const import DOMAIN
@ -18,13 +19,6 @@ from homeassistant.const import (
SERVICE_ALARM_ARM_HOME,
SERVICE_ALARM_ARM_NIGHT,
SERVICE_ALARM_DISARM,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
STATE_UNKNOWN,
)
from homeassistant.core import HomeAssistant
@ -42,25 +36,25 @@ SECOND_LOCAL_ENTITY_ID = "alarm_control_panel.name_1"
CODES_REQUIRED_OPTIONS = {"code_arm_required": True, "code_disarm_required": True}
TEST_RISCO_TO_HA = {
"arm": STATE_ALARM_ARMED_AWAY,
"partial_arm": STATE_ALARM_ARMED_HOME,
"A": STATE_ALARM_ARMED_HOME,
"B": STATE_ALARM_ARMED_HOME,
"C": STATE_ALARM_ARMED_NIGHT,
"D": STATE_ALARM_ARMED_NIGHT,
"arm": AlarmControlPanelState.ARMED_AWAY,
"partial_arm": AlarmControlPanelState.ARMED_HOME,
"A": AlarmControlPanelState.ARMED_HOME,
"B": AlarmControlPanelState.ARMED_HOME,
"C": AlarmControlPanelState.ARMED_NIGHT,
"D": AlarmControlPanelState.ARMED_NIGHT,
}
TEST_FULL_RISCO_TO_HA = {
**TEST_RISCO_TO_HA,
"D": STATE_ALARM_ARMED_CUSTOM_BYPASS,
"D": AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
}
TEST_HA_TO_RISCO = {
STATE_ALARM_ARMED_AWAY: "arm",
STATE_ALARM_ARMED_HOME: "partial_arm",
STATE_ALARM_ARMED_NIGHT: "C",
AlarmControlPanelState.ARMED_AWAY: "arm",
AlarmControlPanelState.ARMED_HOME: "partial_arm",
AlarmControlPanelState.ARMED_NIGHT: "C",
}
TEST_FULL_HA_TO_RISCO = {
**TEST_HA_TO_RISCO,
STATE_ALARM_ARMED_CUSTOM_BYPASS: "D",
AlarmControlPanelState.ARMED_CUSTOM_BYPASS: "D",
}
CUSTOM_MAPPING_OPTIONS = {
"risco_states_to_ha": TEST_RISCO_TO_HA,
@ -210,7 +204,7 @@ async def test_cloud_states(
hass,
two_part_cloud_alarm,
"triggered",
STATE_ALARM_TRIGGERED,
AlarmControlPanelState.TRIGGERED,
entity_id,
partition_id,
)
@ -218,7 +212,7 @@ async def test_cloud_states(
hass,
two_part_cloud_alarm,
"arming",
STATE_ALARM_ARMING,
AlarmControlPanelState.ARMING,
entity_id,
partition_id,
)
@ -226,7 +220,7 @@ async def test_cloud_states(
hass,
two_part_cloud_alarm,
"armed",
STATE_ALARM_ARMED_AWAY,
AlarmControlPanelState.ARMED_AWAY,
entity_id,
partition_id,
)
@ -234,7 +228,7 @@ async def test_cloud_states(
hass,
two_part_cloud_alarm,
"partially_armed",
STATE_ALARM_ARMED_HOME,
AlarmControlPanelState.ARMED_HOME,
entity_id,
partition_id,
)
@ -242,7 +236,7 @@ async def test_cloud_states(
hass,
two_part_cloud_alarm,
"disarmed",
STATE_ALARM_DISARMED,
AlarmControlPanelState.DISARMED,
entity_id,
partition_id,
)
@ -257,7 +251,7 @@ async def test_cloud_states(
hass,
two_part_cloud_alarm,
"partially_armed",
STATE_ALARM_ARMED_NIGHT,
AlarmControlPanelState.ARMED_NIGHT,
entity_id,
partition_id,
)
@ -595,7 +589,7 @@ async def test_local_states(
hass,
two_part_local_alarm,
"triggered",
STATE_ALARM_TRIGGERED,
AlarmControlPanelState.TRIGGERED,
entity_id,
partition_id,
callback,
@ -604,7 +598,7 @@ async def test_local_states(
hass,
two_part_local_alarm,
"arming",
STATE_ALARM_ARMING,
AlarmControlPanelState.ARMING,
entity_id,
partition_id,
callback,
@ -613,7 +607,7 @@ async def test_local_states(
hass,
two_part_local_alarm,
"armed",
STATE_ALARM_ARMED_AWAY,
AlarmControlPanelState.ARMED_AWAY,
entity_id,
partition_id,
callback,
@ -622,7 +616,7 @@ async def test_local_states(
hass,
two_part_local_alarm,
"partially_armed",
STATE_ALARM_ARMED_HOME,
AlarmControlPanelState.ARMED_HOME,
entity_id,
partition_id,
callback,
@ -631,7 +625,7 @@ async def test_local_states(
hass,
two_part_local_alarm,
"disarmed",
STATE_ALARM_DISARMED,
AlarmControlPanelState.DISARMED,
entity_id,
partition_id,
callback,
@ -647,7 +641,7 @@ async def test_local_states(
hass,
two_part_local_alarm,
"partially_armed",
STATE_ALARM_ARMED_NIGHT,
AlarmControlPanelState.ARMED_NIGHT,
entity_id,
partition_id,
callback,

View File

@ -4,7 +4,7 @@ from unittest.mock import AsyncMock
from pyspcwebgw.const import AreaMode
from homeassistant.const import STATE_ALARM_ARMED_AWAY, STATE_ALARM_DISARMED
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
@ -19,7 +19,7 @@ async def test_update_alarm_device(hass: HomeAssistant, mock_client: AsyncMock)
entity_id = "alarm_control_panel.house"
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
assert hass.states.get(entity_id).attributes["changed_by"] == "Sven"
mock_area = mock_client.return_value.areas["1"]
@ -30,5 +30,5 @@ async def test_update_alarm_device(hass: HomeAssistant, mock_client: AsyncMock)
await mock_client.call_args_list[0][1]["async_callback"](mock_area)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
assert hass.states.get(entity_id).attributes["changed_by"] == "Anna"

View File

@ -4,21 +4,15 @@ import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components import template
from homeassistant.components.alarm_control_panel import DOMAIN as ALARM_DOMAIN
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_DOMAIN,
AlarmControlPanelState,
)
from homeassistant.const import (
ATTR_DOMAIN,
ATTR_ENTITY_ID,
ATTR_SERVICE_DATA,
EVENT_CALL_SERVICE,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
)
@ -113,15 +107,15 @@ async def test_template_state_text(hass: HomeAssistant) -> None:
"""Test the state text of a template."""
for set_state in (
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMED_VACATION,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED,
AlarmControlPanelState.ARMED_HOME,
AlarmControlPanelState.ARMED_AWAY,
AlarmControlPanelState.ARMED_NIGHT,
AlarmControlPanelState.ARMED_VACATION,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
AlarmControlPanelState.ARMING,
AlarmControlPanelState.DISARMED,
AlarmControlPanelState.PENDING,
AlarmControlPanelState.TRIGGERED,
):
hass.states.async_set(PANEL_NAME, set_state)
await hass.async_block_till_done()
@ -166,7 +160,7 @@ async def test_setup_config_entry(
hass.states.async_set("alarm_control_panel.one", "disarmed", {})
await hass.async_block_till_done()
state = hass.states.get("alarm_control_panel.my_template")
assert state.state == STATE_ALARM_DISARMED
assert state.state == AlarmControlPanelState.DISARMED
@pytest.mark.parametrize(("count", "domain"), [(1, "alarm_control_panel")])
@ -190,13 +184,13 @@ async def test_optimistic_states(hass: HomeAssistant) -> None:
assert state.state == "unknown"
for service, set_state in (
("alarm_arm_away", STATE_ALARM_ARMED_AWAY),
("alarm_arm_home", STATE_ALARM_ARMED_HOME),
("alarm_arm_night", STATE_ALARM_ARMED_NIGHT),
("alarm_arm_vacation", STATE_ALARM_ARMED_VACATION),
("alarm_arm_custom_bypass", STATE_ALARM_ARMED_CUSTOM_BYPASS),
("alarm_disarm", STATE_ALARM_DISARMED),
("alarm_trigger", STATE_ALARM_TRIGGERED),
("alarm_arm_away", AlarmControlPanelState.ARMED_AWAY),
("alarm_arm_home", AlarmControlPanelState.ARMED_HOME),
("alarm_arm_night", AlarmControlPanelState.ARMED_NIGHT),
("alarm_arm_vacation", AlarmControlPanelState.ARMED_VACATION),
("alarm_arm_custom_bypass", AlarmControlPanelState.ARMED_CUSTOM_BYPASS),
("alarm_disarm", AlarmControlPanelState.DISARMED),
("alarm_trigger", AlarmControlPanelState.TRIGGERED),
):
await hass.services.async_call(
ALARM_DOMAIN,
@ -465,15 +459,33 @@ async def test_code_config(hass: HomeAssistant, code_format, code_arm_required)
@pytest.mark.parametrize(
("restored_state", "initial_state"),
[
(STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_AWAY),
(STATE_ALARM_ARMED_CUSTOM_BYPASS, STATE_ALARM_ARMED_CUSTOM_BYPASS),
(STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_HOME),
(STATE_ALARM_ARMED_NIGHT, STATE_ALARM_ARMED_NIGHT),
(STATE_ALARM_ARMED_VACATION, STATE_ALARM_ARMED_VACATION),
(STATE_ALARM_ARMING, STATE_ALARM_ARMING),
(STATE_ALARM_DISARMED, STATE_ALARM_DISARMED),
(STATE_ALARM_PENDING, STATE_ALARM_PENDING),
(STATE_ALARM_TRIGGERED, STATE_ALARM_TRIGGERED),
(
AlarmControlPanelState.ARMED_AWAY,
AlarmControlPanelState.ARMED_AWAY,
),
(
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
AlarmControlPanelState.ARMED_CUSTOM_BYPASS,
),
(
AlarmControlPanelState.ARMED_HOME,
AlarmControlPanelState.ARMED_HOME,
),
(
AlarmControlPanelState.ARMED_NIGHT,
AlarmControlPanelState.ARMED_NIGHT,
),
(
AlarmControlPanelState.ARMED_VACATION,
AlarmControlPanelState.ARMED_VACATION,
),
(AlarmControlPanelState.ARMING, AlarmControlPanelState.ARMING),
(AlarmControlPanelState.DISARMED, AlarmControlPanelState.DISARMED),
(AlarmControlPanelState.PENDING, AlarmControlPanelState.PENDING),
(
AlarmControlPanelState.TRIGGERED,
AlarmControlPanelState.TRIGGERED,
),
(STATE_UNAVAILABLE, STATE_UNKNOWN),
(STATE_UNKNOWN, STATE_UNKNOWN),
("faulty_state", STATE_UNKNOWN),

View File

@ -12,7 +12,10 @@ from total_connect_client.exceptions import (
TotalConnectError,
)
from homeassistant.components.alarm_control_panel import DOMAIN as ALARM_DOMAIN
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_DOMAIN,
AlarmControlPanelState,
)
from homeassistant.components.totalconnect.alarm_control_panel import (
SERVICE_ALARM_ARM_AWAY_INSTANT,
SERVICE_ALARM_ARM_HOME_INSTANT,
@ -26,14 +29,6 @@ from homeassistant.const import (
SERVICE_ALARM_ARM_HOME,
SERVICE_ALARM_ARM_NIGHT,
SERVICE_ALARM_DISARM,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_ARMING,
STATE_ALARM_DISARMED,
STATE_ALARM_DISARMING,
STATE_ALARM_TRIGGERED,
STATE_UNAVAILABLE,
)
from homeassistant.core import HomeAssistant
@ -100,8 +95,8 @@ async def test_arm_home_success(
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID_2).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert hass.states.get(ENTITY_ID_2).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 1
await hass.services.async_call(
@ -113,9 +108,9 @@ async def test_arm_home_success(
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert mock_request.call_count == 3
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_HOME
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.ARMED_HOME
# second partition should not be armed
assert hass.states.get(ENTITY_ID_2).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID_2).state == AlarmControlPanelState.DISARMED
async def test_arm_home_failure(hass: HomeAssistant) -> None:
@ -125,7 +120,7 @@ async def test_arm_home_failure(hass: HomeAssistant) -> None:
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 1
with pytest.raises(HomeAssistantError) as err:
@ -134,7 +129,7 @@ async def test_arm_home_failure(hass: HomeAssistant) -> None:
)
await hass.async_block_till_done()
assert f"{err.value}" == "Failed to arm home test"
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 2
# config entry usercode is invalid
@ -144,7 +139,7 @@ async def test_arm_home_failure(hass: HomeAssistant) -> None:
)
await hass.async_block_till_done()
assert f"{err.value}" == "Usercode is invalid, did not arm home"
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
# should have started a re-auth flow
assert len(hass.config_entries.flow.async_progress_by_handler(DOMAIN)) == 1
assert mock_request.call_count == 3
@ -159,8 +154,8 @@ async def test_arm_home_instant_success(
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID_2).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert hass.states.get(ENTITY_ID_2).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 1
await hass.services.async_call(
@ -172,7 +167,7 @@ async def test_arm_home_instant_success(
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert mock_request.call_count == 3
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_HOME
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.ARMED_HOME
async def test_arm_home_instant_failure(hass: HomeAssistant) -> None:
@ -182,7 +177,7 @@ async def test_arm_home_instant_failure(hass: HomeAssistant) -> None:
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 1
with pytest.raises(HomeAssistantError) as err:
@ -191,7 +186,7 @@ async def test_arm_home_instant_failure(hass: HomeAssistant) -> None:
)
await hass.async_block_till_done()
assert f"{err.value}" == "Failed to arm home instant test"
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 2
# usercode is invalid
@ -201,7 +196,7 @@ async def test_arm_home_instant_failure(hass: HomeAssistant) -> None:
)
await hass.async_block_till_done()
assert f"{err.value}" == "Usercode is invalid, did not arm home instant"
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
# should have started a re-auth flow
assert len(hass.config_entries.flow.async_progress_by_handler(DOMAIN)) == 1
assert mock_request.call_count == 3
@ -216,8 +211,8 @@ async def test_arm_away_instant_success(
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID_2).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert hass.states.get(ENTITY_ID_2).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 1
await hass.services.async_call(
@ -229,7 +224,7 @@ async def test_arm_away_instant_success(
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert mock_request.call_count == 3
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.ARMED_AWAY
async def test_arm_away_instant_failure(hass: HomeAssistant) -> None:
@ -239,7 +234,7 @@ async def test_arm_away_instant_failure(hass: HomeAssistant) -> None:
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 1
with pytest.raises(HomeAssistantError) as err:
@ -248,7 +243,7 @@ async def test_arm_away_instant_failure(hass: HomeAssistant) -> None:
)
await hass.async_block_till_done()
assert f"{err.value}" == "Failed to arm away instant test"
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 2
# usercode is invalid
@ -258,7 +253,7 @@ async def test_arm_away_instant_failure(hass: HomeAssistant) -> None:
)
await hass.async_block_till_done()
assert f"{err.value}" == "Usercode is invalid, did not arm away instant"
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
# should have started a re-auth flow
assert len(hass.config_entries.flow.async_progress_by_handler(DOMAIN)) == 1
assert mock_request.call_count == 3
@ -273,7 +268,7 @@ async def test_arm_away_success(
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 1
await hass.services.async_call(
@ -285,7 +280,7 @@ async def test_arm_away_success(
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert mock_request.call_count == 3
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.ARMED_AWAY
async def test_arm_away_failure(hass: HomeAssistant) -> None:
@ -295,7 +290,7 @@ async def test_arm_away_failure(hass: HomeAssistant) -> None:
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 1
with pytest.raises(HomeAssistantError) as err:
@ -304,7 +299,7 @@ async def test_arm_away_failure(hass: HomeAssistant) -> None:
)
await hass.async_block_till_done()
assert f"{err.value}" == "Failed to arm away test"
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 2
# usercode is invalid
@ -314,7 +309,7 @@ async def test_arm_away_failure(hass: HomeAssistant) -> None:
)
await hass.async_block_till_done()
assert f"{err.value}" == "Usercode is invalid, did not arm away"
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
# should have started a re-auth flow
assert len(hass.config_entries.flow.async_progress_by_handler(DOMAIN)) == 1
assert mock_request.call_count == 3
@ -329,7 +324,7 @@ async def test_disarm_success(
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.ARMED_AWAY
assert mock_request.call_count == 1
await hass.services.async_call(
@ -341,7 +336,7 @@ async def test_disarm_success(
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert mock_request.call_count == 3
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
async def test_disarm_failure(hass: HomeAssistant) -> None:
@ -355,7 +350,7 @@ async def test_disarm_failure(hass: HomeAssistant) -> None:
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.ARMED_AWAY
assert mock_request.call_count == 1
with pytest.raises(HomeAssistantError) as err:
@ -364,7 +359,7 @@ async def test_disarm_failure(hass: HomeAssistant) -> None:
)
await hass.async_block_till_done()
assert f"{err.value}" == "Failed to disarm test"
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.ARMED_AWAY
assert mock_request.call_count == 2
# usercode is invalid
@ -374,7 +369,7 @@ async def test_disarm_failure(hass: HomeAssistant) -> None:
)
await hass.async_block_till_done()
assert f"{err.value}" == "Usercode is invalid, did not disarm"
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.ARMED_AWAY
# should have started a re-auth flow
assert len(hass.config_entries.flow.async_progress_by_handler(DOMAIN)) == 1
assert mock_request.call_count == 3
@ -389,7 +384,7 @@ async def test_disarm_code_required(
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.ARMED_AWAY
assert mock_request.call_count == 1
# runtime user entered code is bad
@ -399,7 +394,7 @@ async def test_disarm_code_required(
await hass.services.async_call(
ALARM_DOMAIN, SERVICE_ALARM_DISARM, DATA_WITH_CODE, blocking=True
)
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.ARMED_AWAY
# code check means the call to total_connect never happens
assert mock_request.call_count == 1
@ -415,7 +410,7 @@ async def test_disarm_code_required(
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert mock_request.call_count == 3
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
async def test_arm_night_success(
@ -427,7 +422,7 @@ async def test_arm_night_success(
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 1
await hass.services.async_call(
@ -439,7 +434,7 @@ async def test_arm_night_success(
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert mock_request.call_count == 3
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_NIGHT
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.ARMED_NIGHT
async def test_arm_night_failure(hass: HomeAssistant) -> None:
@ -449,7 +444,7 @@ async def test_arm_night_failure(hass: HomeAssistant) -> None:
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 1
with pytest.raises(HomeAssistantError) as err:
@ -458,7 +453,7 @@ async def test_arm_night_failure(hass: HomeAssistant) -> None:
)
await hass.async_block_till_done()
assert f"{err.value}" == "Failed to arm night test"
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 2
# usercode is invalid
@ -468,7 +463,7 @@ async def test_arm_night_failure(hass: HomeAssistant) -> None:
)
await hass.async_block_till_done()
assert f"{err.value}" == "Usercode is invalid, did not arm night"
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
# should have started a re-auth flow
assert len(hass.config_entries.flow.async_progress_by_handler(DOMAIN)) == 1
assert mock_request.call_count == 3
@ -481,7 +476,7 @@ async def test_arming(hass: HomeAssistant, freezer: FrozenDateTimeFactory) -> No
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 1
await hass.services.async_call(
@ -493,7 +488,7 @@ async def test_arming(hass: HomeAssistant, freezer: FrozenDateTimeFactory) -> No
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert mock_request.call_count == 3
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMING
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.ARMING
async def test_disarming(hass: HomeAssistant, freezer: FrozenDateTimeFactory) -> None:
@ -503,7 +498,7 @@ async def test_disarming(hass: HomeAssistant, freezer: FrozenDateTimeFactory) ->
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.ARMED_AWAY
assert mock_request.call_count == 1
await hass.services.async_call(
@ -515,7 +510,7 @@ async def test_disarming(hass: HomeAssistant, freezer: FrozenDateTimeFactory) ->
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert mock_request.call_count == 3
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMING
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMING
async def test_triggered_fire(hass: HomeAssistant) -> None:
@ -526,7 +521,7 @@ async def test_triggered_fire(hass: HomeAssistant) -> None:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
state = hass.states.get(ENTITY_ID)
assert state.state == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.TRIGGERED
assert state.attributes.get("triggered_source") == "Fire/Smoke"
assert mock_request.call_count == 1
@ -539,7 +534,7 @@ async def test_triggered_police(hass: HomeAssistant) -> None:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
state = hass.states.get(ENTITY_ID)
assert state.state == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.TRIGGERED
assert state.attributes.get("triggered_source") == "Police/Medical"
assert mock_request.call_count == 1
@ -552,7 +547,7 @@ async def test_triggered_carbon_monoxide(hass: HomeAssistant) -> None:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
state = hass.states.get(ENTITY_ID)
assert state.state == STATE_ALARM_TRIGGERED
assert state.state == AlarmControlPanelState.TRIGGERED
assert state.attributes.get("triggered_source") == "Carbon Monoxide"
assert mock_request.call_count == 1
@ -564,7 +559,10 @@ async def test_armed_custom(hass: HomeAssistant) -> None:
with patch(TOTALCONNECT_REQUEST, side_effect=responses) as mock_request:
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_CUSTOM_BYPASS
assert (
hass.states.get(ENTITY_ID).state
== AlarmControlPanelState.ARMED_CUSTOM_BYPASS
)
assert mock_request.call_count == 1
@ -596,7 +594,7 @@ async def test_other_update_failures(
# first things work as planned
await async_update_entity(hass, ENTITY_ID)
await hass.async_block_till_done()
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 1
# then an error: ServiceUnavailable --> UpdateFailed
@ -610,7 +608,7 @@ async def test_other_update_failures(
freezer.tick(SCAN_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 3
# then an error: TotalConnectError --> UpdateFailed
@ -624,7 +622,7 @@ async def test_other_update_failures(
freezer.tick(SCAN_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert hass.states.get(ENTITY_ID).state == AlarmControlPanelState.DISARMED
assert mock_request.call_count == 5
# unknown TotalConnect status via ValueError

View File

@ -13,9 +13,10 @@ from yalesmartalarmclient import (
YaleSmartAlarmData,
)
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
from homeassistant.components.yale_smart_alarm.const import DOMAIN
from homeassistant.config_entries import SOURCE_USER
from homeassistant.const import STATE_ALARM_ARMED_AWAY, STATE_UNAVAILABLE
from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant
from homeassistant.util import dt as dt_util
@ -74,7 +75,7 @@ async def test_coordinator_setup_and_update_errors(
client = load_config_entry[1]
state = hass.states.get("alarm_control_panel.yale_smart_alarm")
assert state.state == STATE_ALARM_ARMED_AWAY
assert state.state == AlarmControlPanelState.ARMED_AWAY
client.reset_mock()
client.get_information.side_effect = ConnectionError("Could not connect")
@ -116,7 +117,7 @@ async def test_coordinator_setup_and_update_errors(
await hass.async_block_till_done(wait_background_tasks=True)
client.get_information.assert_called_once()
state = hass.states.get("alarm_control_panel.yale_smart_alarm")
assert state.state == STATE_ALARM_ARMED_AWAY
assert state.state == AlarmControlPanelState.ARMED_AWAY
client.reset_mock()
client.get_information.side_effect = AuthenticationError("Can not authenticate")

View File

@ -8,22 +8,17 @@ from zigpy.zcl import Cluster
from zigpy.zcl.clusters import security
import zigpy.zcl.foundation as zcl_f
from homeassistant.components.alarm_control_panel import DOMAIN as ALARM_DOMAIN
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_DOMAIN,
AlarmControlPanelState,
)
from homeassistant.components.zha.helpers import (
ZHADeviceProxy,
ZHAGatewayProxy,
get_zha_gateway,
get_zha_gateway_proxy,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT,
STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED,
Platform,
)
from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
from .common import find_entity_id
@ -79,7 +74,7 @@ async def test_alarm_control_panel(
cluster = zigpy_device.endpoints[1].ias_ace
assert entity_id is not None
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
# arm_away from HA
cluster.client_command.reset_mock()
@ -90,7 +85,7 @@ async def test_alarm_control_panel(
blocking=True,
)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
assert cluster.client_command.call_count == 2
assert cluster.client_command.await_count == 2
assert cluster.client_command.call_args == call(
@ -113,7 +108,7 @@ async def test_alarm_control_panel(
blocking=True,
)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
cluster.client_command.reset_mock()
await hass.services.async_call(
ALARM_DOMAIN,
@ -128,7 +123,7 @@ async def test_alarm_control_panel(
blocking=True,
)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
assert cluster.client_command.call_count == 4
assert cluster.client_command.await_count == 4
assert cluster.client_command.call_args == call(
@ -151,7 +146,7 @@ async def test_alarm_control_panel(
blocking=True,
)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_HOME
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_HOME
assert cluster.client_command.call_count == 2
assert cluster.client_command.await_count == 2
assert cluster.client_command.call_args == call(
@ -171,7 +166,7 @@ async def test_alarm_control_panel(
blocking=True,
)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_NIGHT
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_NIGHT
assert cluster.client_command.call_count == 2
assert cluster.client_command.await_count == 2
assert cluster.client_command.call_args == call(
@ -190,7 +185,7 @@ async def test_alarm_control_panel(
"cluster_command", 1, 0, [security.IasAce.ArmMode.Arm_All_Zones, "", 0]
)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY
# reset the panel
await reset_alarm_panel(hass, cluster, entity_id)
@ -200,7 +195,7 @@ async def test_alarm_control_panel(
"cluster_command", 1, 0, [security.IasAce.ArmMode.Arm_Day_Home_Only, "", 0]
)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_HOME
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_HOME
# reset the panel
await reset_alarm_panel(hass, cluster, entity_id)
@ -210,33 +205,33 @@ async def test_alarm_control_panel(
"cluster_command", 1, 0, [security.IasAce.ArmMode.Arm_Night_Sleep_Only, "", 0]
)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_NIGHT
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_NIGHT
# disarm from panel with bad code
cluster.listener_event(
"cluster_command", 1, 0, [security.IasAce.ArmMode.Disarm, "", 0]
)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_NIGHT
assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_NIGHT
# disarm from panel with bad code for 2nd time trips alarm
cluster.listener_event(
"cluster_command", 1, 0, [security.IasAce.ArmMode.Disarm, "", 0]
)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
# disarm from panel with good code
cluster.listener_event(
"cluster_command", 1, 0, [security.IasAce.ArmMode.Disarm, "4321", 0]
)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
# panic from panel
cluster.listener_event("cluster_command", 1, 4, [])
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
# reset the panel
await reset_alarm_panel(hass, cluster, entity_id)
@ -244,7 +239,7 @@ async def test_alarm_control_panel(
# fire from panel
cluster.listener_event("cluster_command", 1, 3, [])
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
# reset the panel
await reset_alarm_panel(hass, cluster, entity_id)
@ -252,7 +247,7 @@ async def test_alarm_control_panel(
# emergency from panel
cluster.listener_event("cluster_command", 1, 2, [])
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
# reset the panel
await reset_alarm_panel(hass, cluster, entity_id)
@ -264,7 +259,7 @@ async def test_alarm_control_panel(
blocking=True,
)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
assert hass.states.get(entity_id).state == AlarmControlPanelState.TRIGGERED
assert cluster.client_command.call_count == 1
assert cluster.client_command.await_count == 1
assert cluster.client_command.call_args == call(
@ -290,7 +285,7 @@ async def reset_alarm_panel(hass: HomeAssistant, cluster: Cluster, entity_id: st
blocking=True,
)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert hass.states.get(entity_id).state == AlarmControlPanelState.DISARMED
assert cluster.client_command.call_count == 2
assert cluster.client_command.await_count == 2
assert cluster.client_command.call_args == call(

View File

@ -8,7 +8,7 @@ from unittest.mock import Mock, patch
import pytest
from homeassistant import const
from homeassistant.components import lock, sensor
from homeassistant.components import alarm_control_panel, lock, sensor
from .common import (
extract_stack_to_frame,
@ -218,6 +218,38 @@ def test_deprecated_constants_lock(
)
def _create_tuples_alarm_states(
enum: type[Enum], constant_prefix: str, remove_in_version: str
) -> list[tuple[Enum, str]]:
return [
(enum_field, constant_prefix, remove_in_version)
for enum_field in enum
if enum_field
not in [
lock.LockState.OPEN,
lock.LockState.OPENING,
]
]
@pytest.mark.parametrize(
("enum", "constant_prefix", "remove_in_version"),
_create_tuples_lock_states(
alarm_control_panel.AlarmControlPanelState, "STATE_ALARM_", "2025.11"
),
)
def test_deprecated_constants_alarm(
caplog: pytest.LogCaptureFixture,
enum: Enum,
constant_prefix: str,
remove_in_version: str,
) -> None:
"""Test deprecated constants."""
import_and_test_deprecated_constant_enum(
caplog, const, enum, constant_prefix, remove_in_version
)
def test_deprecated_unit_of_conductivity_alias() -> None:
"""Test UnitOfConductivity deprecation."""