2023-03-03 10:26:13 +00:00
|
|
|
"""Control a MQTT alarm."""
|
2022-01-03 07:53:52 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2021-01-09 13:37:33 +00:00
|
|
|
import functools
|
2015-09-18 15:30:34 +00:00
|
|
|
import logging
|
2018-05-29 05:50:27 +00:00
|
|
|
import re
|
2015-09-18 15:30:34 +00:00
|
|
|
|
2016-04-05 04:22:58 +00:00
|
|
|
import voluptuous as vol
|
|
|
|
|
2019-01-27 17:54:52 +00:00
|
|
|
import homeassistant.components.alarm_control_panel as alarm
|
2022-04-07 07:44:26 +00:00
|
|
|
from homeassistant.components.alarm_control_panel import AlarmControlPanelEntityFeature
|
2022-01-03 07:53:52 +00:00
|
|
|
from homeassistant.config_entries import ConfigEntry
|
2019-01-27 17:54:52 +00:00
|
|
|
from homeassistant.const import (
|
2019-07-31 19:25:30 +00:00
|
|
|
CONF_CODE,
|
|
|
|
CONF_NAME,
|
|
|
|
CONF_VALUE_TEMPLATE,
|
|
|
|
STATE_ALARM_ARMED_AWAY,
|
2020-04-06 09:45:37 +00:00
|
|
|
STATE_ALARM_ARMED_CUSTOM_BYPASS,
|
2019-07-31 19:25:30 +00:00
|
|
|
STATE_ALARM_ARMED_HOME,
|
|
|
|
STATE_ALARM_ARMED_NIGHT,
|
2021-08-24 11:22:49 +00:00
|
|
|
STATE_ALARM_ARMED_VACATION,
|
2020-04-06 09:45:37 +00:00
|
|
|
STATE_ALARM_ARMING,
|
2019-07-31 19:25:30 +00:00
|
|
|
STATE_ALARM_DISARMED,
|
2020-04-06 09:45:37 +00:00
|
|
|
STATE_ALARM_DISARMING,
|
2019-07-31 19:25:30 +00:00
|
|
|
STATE_ALARM_PENDING,
|
|
|
|
STATE_ALARM_TRIGGERED,
|
|
|
|
)
|
2021-04-22 21:53:37 +00:00
|
|
|
from homeassistant.core import HomeAssistant, callback
|
2016-04-05 04:22:58 +00:00
|
|
|
import homeassistant.helpers.config_validation as cv
|
2022-01-03 07:53:52 +00:00
|
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
|
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
2015-09-18 15:30:34 +00:00
|
|
|
|
2022-05-31 07:32:44 +00:00
|
|
|
from . import subscription
|
|
|
|
from .config import DEFAULT_RETAIN, MQTT_BASE_SCHEMA
|
2022-01-03 08:03:47 +00:00
|
|
|
from .const import (
|
2022-01-20 15:15:26 +00:00
|
|
|
CONF_COMMAND_TEMPLATE,
|
2022-01-03 08:03:47 +00:00
|
|
|
CONF_COMMAND_TOPIC,
|
|
|
|
CONF_ENCODING,
|
|
|
|
CONF_QOS,
|
|
|
|
CONF_RETAIN,
|
|
|
|
CONF_STATE_TOPIC,
|
Add option to disable MQTT Alarm Control Panel supported features (#98363)
* Make MQTT Alarm Control Panel features conditional
The MQTT Alarm Control Panel currently enables all features (arm home,
arm away, arm night, arm vacation, arm custom bypass) unconditionally.
This clutters the interface and can even be potentially dangerous, by
enabling modes that the remote alarm may not support.
Make all the features conditional, by adding a new "supported_features"
configuration option, comprising a list of the supported features as
options. Feature enablement seems inconsistent across the MQTT
component; this implementation is most alike to the Humidifier modes
option, but using a generic "supported_features" name that other
implementations may reuse in the future.
The default value of this new setting remains to be all features, which
while it may be overly expansive, is necessary to maintain backwards
compatibility.
* Apply suggestions from code review
* Use vol.Optional() instead of vol.Required() for "supported_features".
* Move the initialization of _attr_supported_features to _setup_from_config.
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
* Apply suggestions from emontnemery's code review
* Use vol.In() instead of cv.multi_seelct()
* Remove superfluous _attr_supported_features initializers, already
present in the base class.
Co-authored-by: Erik Montnemery <erik@montnemery.com>
* Add invalid config tests for the MQTT Alarm Control Panel
* Set expected_features to None in the invalid MQTT Alarm Control Panel tests
* Add another expected_features=None in the invalid tests
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
---------
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2023-08-18 06:23:48 +00:00
|
|
|
CONF_SUPPORTED_FEATURES,
|
2022-01-03 08:03:47 +00:00
|
|
|
)
|
2020-04-01 18:48:32 +00:00
|
|
|
from .debug_info import log_messages
|
2023-05-31 07:02:48 +00:00
|
|
|
from .mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, async_setup_entry_helper
|
2022-11-02 19:33:18 +00:00
|
|
|
from .models import MqttCommandTemplate, MqttValueTemplate, ReceiveMessage
|
2022-10-11 08:49:54 +00:00
|
|
|
from .util import get_mqtt_data, valid_publish_topic, valid_subscribe_topic
|
2019-03-21 05:56:46 +00:00
|
|
|
|
2015-09-18 15:30:34 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
Add option to disable MQTT Alarm Control Panel supported features (#98363)
* Make MQTT Alarm Control Panel features conditional
The MQTT Alarm Control Panel currently enables all features (arm home,
arm away, arm night, arm vacation, arm custom bypass) unconditionally.
This clutters the interface and can even be potentially dangerous, by
enabling modes that the remote alarm may not support.
Make all the features conditional, by adding a new "supported_features"
configuration option, comprising a list of the supported features as
options. Feature enablement seems inconsistent across the MQTT
component; this implementation is most alike to the Humidifier modes
option, but using a generic "supported_features" name that other
implementations may reuse in the future.
The default value of this new setting remains to be all features, which
while it may be overly expansive, is necessary to maintain backwards
compatibility.
* Apply suggestions from code review
* Use vol.Optional() instead of vol.Required() for "supported_features".
* Move the initialization of _attr_supported_features to _setup_from_config.
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
* Apply suggestions from emontnemery's code review
* Use vol.In() instead of cv.multi_seelct()
* Remove superfluous _attr_supported_features initializers, already
present in the base class.
Co-authored-by: Erik Montnemery <erik@montnemery.com>
* Add invalid config tests for the MQTT Alarm Control Panel
* Set expected_features to None in the invalid MQTT Alarm Control Panel tests
* Add another expected_features=None in the invalid tests
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
---------
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2023-08-18 06:23:48 +00:00
|
|
|
_SUPPORTED_FEATURES = {
|
|
|
|
"arm_home": AlarmControlPanelEntityFeature.ARM_HOME,
|
|
|
|
"arm_away": AlarmControlPanelEntityFeature.ARM_AWAY,
|
|
|
|
"arm_night": AlarmControlPanelEntityFeature.ARM_NIGHT,
|
|
|
|
"arm_vacation": AlarmControlPanelEntityFeature.ARM_VACATION,
|
|
|
|
"arm_custom_bypass": AlarmControlPanelEntityFeature.ARM_CUSTOM_BYPASS,
|
|
|
|
"trigger": AlarmControlPanelEntityFeature.TRIGGER,
|
|
|
|
}
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
CONF_CODE_ARM_REQUIRED = "code_arm_required"
|
|
|
|
CONF_CODE_DISARM_REQUIRED = "code_disarm_required"
|
2021-11-29 13:41:52 +00:00
|
|
|
CONF_CODE_TRIGGER_REQUIRED = "code_trigger_required"
|
2019-07-31 19:25:30 +00:00
|
|
|
CONF_PAYLOAD_DISARM = "payload_disarm"
|
|
|
|
CONF_PAYLOAD_ARM_HOME = "payload_arm_home"
|
|
|
|
CONF_PAYLOAD_ARM_AWAY = "payload_arm_away"
|
|
|
|
CONF_PAYLOAD_ARM_NIGHT = "payload_arm_night"
|
2021-08-24 11:22:49 +00:00
|
|
|
CONF_PAYLOAD_ARM_VACATION = "payload_arm_vacation"
|
2020-04-06 09:45:37 +00:00
|
|
|
CONF_PAYLOAD_ARM_CUSTOM_BYPASS = "payload_arm_custom_bypass"
|
2021-11-29 13:41:52 +00:00
|
|
|
CONF_PAYLOAD_TRIGGER = "payload_trigger"
|
2019-07-31 19:25:30 +00:00
|
|
|
|
2021-06-29 08:32:23 +00:00
|
|
|
MQTT_ALARM_ATTRIBUTES_BLOCKED = frozenset(
|
|
|
|
{
|
|
|
|
alarm.ATTR_CHANGED_BY,
|
|
|
|
alarm.ATTR_CODE_ARM_REQUIRED,
|
|
|
|
alarm.ATTR_CODE_FORMAT,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
DEFAULT_COMMAND_TEMPLATE = "{{action}}"
|
|
|
|
DEFAULT_ARM_NIGHT = "ARM_NIGHT"
|
2021-08-24 11:22:49 +00:00
|
|
|
DEFAULT_ARM_VACATION = "ARM_VACATION"
|
2019-07-31 19:25:30 +00:00
|
|
|
DEFAULT_ARM_AWAY = "ARM_AWAY"
|
|
|
|
DEFAULT_ARM_HOME = "ARM_HOME"
|
2020-04-06 09:45:37 +00:00
|
|
|
DEFAULT_ARM_CUSTOM_BYPASS = "ARM_CUSTOM_BYPASS"
|
2019-07-31 19:25:30 +00:00
|
|
|
DEFAULT_DISARM = "DISARM"
|
2021-11-29 13:41:52 +00:00
|
|
|
DEFAULT_TRIGGER = "TRIGGER"
|
2019-07-31 19:25:30 +00:00
|
|
|
DEFAULT_NAME = "MQTT Alarm"
|
2021-10-19 10:07:38 +00:00
|
|
|
|
|
|
|
REMOTE_CODE = "REMOTE_CODE"
|
|
|
|
REMOTE_CODE_TEXT = "REMOTE_CODE_TEXT"
|
|
|
|
|
2022-05-31 07:32:44 +00:00
|
|
|
PLATFORM_SCHEMA_MODERN = MQTT_BASE_SCHEMA.extend(
|
2021-03-11 12:42:13 +00:00
|
|
|
{
|
Add option to disable MQTT Alarm Control Panel supported features (#98363)
* Make MQTT Alarm Control Panel features conditional
The MQTT Alarm Control Panel currently enables all features (arm home,
arm away, arm night, arm vacation, arm custom bypass) unconditionally.
This clutters the interface and can even be potentially dangerous, by
enabling modes that the remote alarm may not support.
Make all the features conditional, by adding a new "supported_features"
configuration option, comprising a list of the supported features as
options. Feature enablement seems inconsistent across the MQTT
component; this implementation is most alike to the Humidifier modes
option, but using a generic "supported_features" name that other
implementations may reuse in the future.
The default value of this new setting remains to be all features, which
while it may be overly expansive, is necessary to maintain backwards
compatibility.
* Apply suggestions from code review
* Use vol.Optional() instead of vol.Required() for "supported_features".
* Move the initialization of _attr_supported_features to _setup_from_config.
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
* Apply suggestions from emontnemery's code review
* Use vol.In() instead of cv.multi_seelct()
* Remove superfluous _attr_supported_features initializers, already
present in the base class.
Co-authored-by: Erik Montnemery <erik@montnemery.com>
* Add invalid config tests for the MQTT Alarm Control Panel
* Set expected_features to None in the invalid MQTT Alarm Control Panel tests
* Add another expected_features=None in the invalid tests
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
---------
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2023-08-18 06:23:48 +00:00
|
|
|
vol.Optional(CONF_SUPPORTED_FEATURES, default=list(_SUPPORTED_FEATURES)): [
|
|
|
|
vol.In(_SUPPORTED_FEATURES)
|
|
|
|
],
|
2021-03-11 12:42:13 +00:00
|
|
|
vol.Optional(CONF_CODE): cv.string,
|
|
|
|
vol.Optional(CONF_CODE_ARM_REQUIRED, default=True): cv.boolean,
|
|
|
|
vol.Optional(CONF_CODE_DISARM_REQUIRED, default=True): cv.boolean,
|
2021-11-29 13:41:52 +00:00
|
|
|
vol.Optional(CONF_CODE_TRIGGER_REQUIRED, default=True): cv.boolean,
|
2021-03-11 12:42:13 +00:00
|
|
|
vol.Optional(
|
|
|
|
CONF_COMMAND_TEMPLATE, default=DEFAULT_COMMAND_TEMPLATE
|
|
|
|
): cv.template,
|
2022-05-31 07:32:44 +00:00
|
|
|
vol.Required(CONF_COMMAND_TOPIC): valid_publish_topic,
|
2023-07-21 10:52:10 +00:00
|
|
|
vol.Optional(CONF_NAME): vol.Any(cv.string, None),
|
2021-03-11 12:42:13 +00:00
|
|
|
vol.Optional(CONF_PAYLOAD_ARM_AWAY, default=DEFAULT_ARM_AWAY): cv.string,
|
|
|
|
vol.Optional(CONF_PAYLOAD_ARM_HOME, default=DEFAULT_ARM_HOME): cv.string,
|
|
|
|
vol.Optional(CONF_PAYLOAD_ARM_NIGHT, default=DEFAULT_ARM_NIGHT): cv.string,
|
2021-08-24 11:22:49 +00:00
|
|
|
vol.Optional(
|
|
|
|
CONF_PAYLOAD_ARM_VACATION, default=DEFAULT_ARM_VACATION
|
|
|
|
): cv.string,
|
2021-03-11 12:42:13 +00:00
|
|
|
vol.Optional(
|
|
|
|
CONF_PAYLOAD_ARM_CUSTOM_BYPASS, default=DEFAULT_ARM_CUSTOM_BYPASS
|
|
|
|
): cv.string,
|
|
|
|
vol.Optional(CONF_PAYLOAD_DISARM, default=DEFAULT_DISARM): cv.string,
|
2021-11-29 13:41:52 +00:00
|
|
|
vol.Optional(CONF_PAYLOAD_TRIGGER, default=DEFAULT_TRIGGER): cv.string,
|
2022-05-31 07:32:44 +00:00
|
|
|
vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
|
|
|
|
vol.Required(CONF_STATE_TOPIC): valid_subscribe_topic,
|
2021-03-11 12:42:13 +00:00
|
|
|
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
|
|
|
|
}
|
|
|
|
).extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
|
2019-07-31 19:25:30 +00:00
|
|
|
|
2022-05-20 06:37:53 +00:00
|
|
|
DISCOVERY_SCHEMA = PLATFORM_SCHEMA_MODERN.extend({}, extra=vol.REMOVE_EXTRA)
|
2021-10-25 11:47:06 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
|
2022-01-03 07:53:52 +00:00
|
|
|
async def async_setup_entry(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
config_entry: ConfigEntry,
|
|
|
|
async_add_entities: AddEntitiesCallback,
|
|
|
|
) -> None:
|
2023-01-08 21:07:10 +00:00
|
|
|
"""Set up MQTT alarm control panel through YAML and through MQTT discovery."""
|
2021-01-09 13:37:33 +00:00
|
|
|
setup = functools.partial(
|
|
|
|
_async_setup_entity, hass, async_add_entities, config_entry=config_entry
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2021-10-25 11:47:06 +00:00
|
|
|
await async_setup_entry_helper(hass, alarm.DOMAIN, setup, DISCOVERY_SCHEMA)
|
2018-09-25 06:44:14 +00:00
|
|
|
|
2018-09-28 14:57:17 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
async def _async_setup_entity(
|
2022-07-12 09:07:18 +00:00
|
|
|
hass: HomeAssistant,
|
|
|
|
async_add_entities: AddEntitiesCallback,
|
|
|
|
config: ConfigType,
|
2022-11-02 19:33:18 +00:00
|
|
|
config_entry: ConfigEntry,
|
|
|
|
discovery_data: DiscoveryInfoType | None = None,
|
2022-07-12 09:07:18 +00:00
|
|
|
) -> None:
|
2018-09-28 14:57:17 +00:00
|
|
|
"""Set up the MQTT Alarm Control Panel platform."""
|
2020-09-10 18:52:23 +00:00
|
|
|
async_add_entities([MqttAlarm(hass, config, config_entry, discovery_data)])
|
2015-09-18 15:30:34 +00:00
|
|
|
|
|
|
|
|
2021-01-09 16:46:53 +00:00
|
|
|
class MqttAlarm(MqttEntity, alarm.AlarmControlPanelEntity):
|
2016-09-09 00:32:32 +00:00
|
|
|
"""Representation of a MQTT alarm status."""
|
2016-03-07 19:21:43 +00:00
|
|
|
|
2023-07-21 10:52:10 +00:00
|
|
|
_default_name = DEFAULT_NAME
|
2021-11-08 13:02:18 +00:00
|
|
|
_entity_id_format = alarm.ENTITY_ID_FORMAT
|
2021-06-29 08:32:23 +00:00
|
|
|
_attributes_extra_blocked = MQTT_ALARM_ATTRIBUTES_BLOCKED
|
|
|
|
|
2022-11-02 19:33:18 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
hass: HomeAssistant,
|
|
|
|
config: ConfigType,
|
|
|
|
config_entry: ConfigEntry,
|
|
|
|
discovery_data: DiscoveryInfoType | None,
|
|
|
|
) -> None:
|
2017-04-30 05:04:49 +00:00
|
|
|
"""Init the MQTT Alarm Control Panel."""
|
2022-06-28 11:41:23 +00:00
|
|
|
self._state: str | None = None
|
2018-12-02 09:29:31 +00:00
|
|
|
|
2021-01-09 16:46:53 +00:00
|
|
|
MqttEntity.__init__(self, hass, config, config_entry, discovery_data)
|
2015-09-18 15:30:34 +00:00
|
|
|
|
2021-01-09 16:46:53 +00:00
|
|
|
@staticmethod
|
2022-11-02 19:33:18 +00:00
|
|
|
def config_schema() -> vol.Schema:
|
2021-01-09 16:46:53 +00:00
|
|
|
"""Return the config schema."""
|
2021-10-25 11:47:06 +00:00
|
|
|
return DISCOVERY_SCHEMA
|
2018-11-24 09:48:01 +00:00
|
|
|
|
2022-11-02 19:33:18 +00:00
|
|
|
def _setup_from_config(self, config: ConfigType) -> None:
|
|
|
|
"""(Re)Setup the entity."""
|
2022-01-03 15:07:40 +00:00
|
|
|
self._value_template = MqttValueTemplate(
|
2022-11-02 19:33:18 +00:00
|
|
|
config.get(CONF_VALUE_TEMPLATE),
|
2022-01-03 15:07:40 +00:00
|
|
|
entity=self,
|
|
|
|
).async_render_with_possible_json_value
|
2021-12-15 10:28:43 +00:00
|
|
|
self._command_template = MqttCommandTemplate(
|
2022-11-02 19:33:18 +00:00
|
|
|
config[CONF_COMMAND_TEMPLATE], entity=self
|
2021-12-15 10:28:43 +00:00
|
|
|
).async_render
|
2019-03-30 06:36:10 +00:00
|
|
|
|
Add option to disable MQTT Alarm Control Panel supported features (#98363)
* Make MQTT Alarm Control Panel features conditional
The MQTT Alarm Control Panel currently enables all features (arm home,
arm away, arm night, arm vacation, arm custom bypass) unconditionally.
This clutters the interface and can even be potentially dangerous, by
enabling modes that the remote alarm may not support.
Make all the features conditional, by adding a new "supported_features"
configuration option, comprising a list of the supported features as
options. Feature enablement seems inconsistent across the MQTT
component; this implementation is most alike to the Humidifier modes
option, but using a generic "supported_features" name that other
implementations may reuse in the future.
The default value of this new setting remains to be all features, which
while it may be overly expansive, is necessary to maintain backwards
compatibility.
* Apply suggestions from code review
* Use vol.Optional() instead of vol.Required() for "supported_features".
* Move the initialization of _attr_supported_features to _setup_from_config.
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
* Apply suggestions from emontnemery's code review
* Use vol.In() instead of cv.multi_seelct()
* Remove superfluous _attr_supported_features initializers, already
present in the base class.
Co-authored-by: Erik Montnemery <erik@montnemery.com>
* Add invalid config tests for the MQTT Alarm Control Panel
* Set expected_features to None in the invalid MQTT Alarm Control Panel tests
* Add another expected_features=None in the invalid tests
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
---------
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
Co-authored-by: Erik Montnemery <erik@montnemery.com>
2023-08-18 06:23:48 +00:00
|
|
|
for feature in self._config[CONF_SUPPORTED_FEATURES]:
|
|
|
|
self._attr_supported_features |= _SUPPORTED_FEATURES[feature]
|
|
|
|
|
2022-11-02 19:33:18 +00:00
|
|
|
def _prepare_subscribe_topics(self) -> None:
|
2020-09-10 18:52:23 +00:00
|
|
|
"""(Re)Subscribe to topics."""
|
|
|
|
|
2017-02-22 08:43:22 +00:00
|
|
|
@callback
|
2020-04-01 18:48:32 +00:00
|
|
|
@log_messages(self.hass, self.entity_id)
|
2022-11-02 19:33:18 +00:00
|
|
|
def message_received(msg: ReceiveMessage) -> None:
|
2017-04-30 05:04:49 +00:00
|
|
|
"""Run when new MQTT message has been received."""
|
2022-01-03 15:07:40 +00:00
|
|
|
payload = self._value_template(msg.payload)
|
2019-03-30 06:36:10 +00:00
|
|
|
if payload not in (
|
2019-07-31 19:25:30 +00:00
|
|
|
STATE_ALARM_DISARMED,
|
|
|
|
STATE_ALARM_ARMED_HOME,
|
|
|
|
STATE_ALARM_ARMED_AWAY,
|
|
|
|
STATE_ALARM_ARMED_NIGHT,
|
2021-08-24 11:22:49 +00:00
|
|
|
STATE_ALARM_ARMED_VACATION,
|
2020-04-06 09:45:37 +00:00
|
|
|
STATE_ALARM_ARMED_CUSTOM_BYPASS,
|
2019-07-31 19:25:30 +00:00
|
|
|
STATE_ALARM_PENDING,
|
2020-04-06 09:45:37 +00:00
|
|
|
STATE_ALARM_ARMING,
|
|
|
|
STATE_ALARM_DISARMING,
|
2019-07-31 19:25:30 +00:00
|
|
|
STATE_ALARM_TRIGGERED,
|
|
|
|
):
|
2019-03-13 19:58:20 +00:00
|
|
|
_LOGGER.warning("Received unexpected payload: %s", msg.payload)
|
2015-10-14 06:08:12 +00:00
|
|
|
return
|
2022-11-02 19:33:18 +00:00
|
|
|
self._state = str(payload)
|
2022-10-11 08:49:54 +00:00
|
|
|
get_mqtt_data(self.hass).state_write_requests.write_state_request(self)
|
2015-09-18 15:30:34 +00:00
|
|
|
|
2022-02-03 01:12:22 +00:00
|
|
|
self._sub_state = subscription.async_prepare_subscribe_topics(
|
2019-07-31 19:25:30 +00:00
|
|
|
self.hass,
|
|
|
|
self._sub_state,
|
|
|
|
{
|
|
|
|
"state_topic": {
|
|
|
|
"topic": self._config[CONF_STATE_TOPIC],
|
|
|
|
"msg_callback": message_received,
|
|
|
|
"qos": self._config[CONF_QOS],
|
2022-01-03 15:08:07 +00:00
|
|
|
"encoding": self._config[CONF_ENCODING] or None,
|
2019-07-31 19:25:30 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
)
|
2018-11-24 09:48:01 +00:00
|
|
|
|
2022-11-02 19:33:18 +00:00
|
|
|
async def _subscribe_topics(self) -> None:
|
2022-02-03 01:12:22 +00:00
|
|
|
"""(Re)Subscribe to topics."""
|
|
|
|
await subscription.async_subscribe_topics(self.hass, self._sub_state)
|
|
|
|
|
2015-09-18 15:30:34 +00:00
|
|
|
@property
|
2022-06-28 11:41:23 +00:00
|
|
|
def state(self) -> str | None:
|
2016-03-07 19:21:43 +00:00
|
|
|
"""Return the state of the device."""
|
2015-09-18 15:30:34 +00:00
|
|
|
return self._state
|
|
|
|
|
2015-09-19 22:22:37 +00:00
|
|
|
@property
|
2022-06-28 11:41:23 +00:00
|
|
|
def code_format(self) -> alarm.CodeFormat | None:
|
2018-05-29 05:50:27 +00:00
|
|
|
"""Return one or more digits/characters."""
|
2022-11-02 19:33:18 +00:00
|
|
|
code: str | None
|
2021-10-20 18:31:00 +00:00
|
|
|
if (code := self._config.get(CONF_CODE)) is None:
|
2018-05-29 05:50:27 +00:00
|
|
|
return None
|
2021-10-19 10:07:38 +00:00
|
|
|
if code == REMOTE_CODE or (isinstance(code, str) and re.search("^\\d+$", code)):
|
2022-04-18 17:37:32 +00:00
|
|
|
return alarm.CodeFormat.NUMBER
|
|
|
|
return alarm.CodeFormat.TEXT
|
2015-09-19 17:32:37 +00:00
|
|
|
|
2019-06-17 21:49:10 +00:00
|
|
|
@property
|
2022-06-28 11:41:23 +00:00
|
|
|
def code_arm_required(self) -> bool:
|
2019-06-17 21:49:10 +00:00
|
|
|
"""Whether the code is required for arm actions."""
|
2022-11-24 07:25:44 +00:00
|
|
|
return bool(self._config[CONF_CODE_ARM_REQUIRED])
|
2019-06-17 21:49:10 +00:00
|
|
|
|
2022-06-28 08:00:23 +00:00
|
|
|
async def async_alarm_disarm(self, code: str | None = None) -> None:
|
2017-02-22 08:43:22 +00:00
|
|
|
"""Send disarm command.
|
|
|
|
|
|
|
|
This method is a coroutine.
|
|
|
|
"""
|
2022-11-02 19:33:18 +00:00
|
|
|
code_required: bool = self._config[CONF_CODE_DISARM_REQUIRED]
|
2019-07-31 19:25:30 +00:00
|
|
|
if code_required and not self._validate_code(code, "disarming"):
|
2015-10-14 06:08:12 +00:00
|
|
|
return
|
2022-11-02 19:33:18 +00:00
|
|
|
payload: str = self._config[CONF_PAYLOAD_DISARM]
|
2021-10-28 06:13:32 +00:00
|
|
|
await self._publish(code, payload)
|
2015-09-18 15:30:34 +00:00
|
|
|
|
2022-06-28 08:00:23 +00:00
|
|
|
async def async_alarm_arm_home(self, code: str | None = None) -> None:
|
2017-02-22 08:43:22 +00:00
|
|
|
"""Send arm home command.
|
|
|
|
|
|
|
|
This method is a coroutine.
|
|
|
|
"""
|
2022-11-02 19:33:18 +00:00
|
|
|
code_required: bool = self._config[CONF_CODE_ARM_REQUIRED]
|
2019-07-31 19:25:30 +00:00
|
|
|
if code_required and not self._validate_code(code, "arming home"):
|
2015-10-14 06:08:12 +00:00
|
|
|
return
|
2022-11-02 19:33:18 +00:00
|
|
|
action: str = self._config[CONF_PAYLOAD_ARM_HOME]
|
2021-10-28 06:13:32 +00:00
|
|
|
await self._publish(code, action)
|
2017-02-22 08:43:22 +00:00
|
|
|
|
2022-06-28 08:00:23 +00:00
|
|
|
async def async_alarm_arm_away(self, code: str | None = None) -> None:
|
2017-02-22 08:43:22 +00:00
|
|
|
"""Send arm away command.
|
2015-09-18 15:30:34 +00:00
|
|
|
|
2017-02-22 08:43:22 +00:00
|
|
|
This method is a coroutine.
|
|
|
|
"""
|
2022-11-02 19:33:18 +00:00
|
|
|
code_required: bool = self._config[CONF_CODE_ARM_REQUIRED]
|
2019-07-31 19:25:30 +00:00
|
|
|
if code_required and not self._validate_code(code, "arming away"):
|
2015-10-14 06:08:12 +00:00
|
|
|
return
|
2022-11-02 19:33:18 +00:00
|
|
|
action: str = self._config[CONF_PAYLOAD_ARM_AWAY]
|
2021-10-28 06:13:32 +00:00
|
|
|
await self._publish(code, action)
|
2015-10-14 06:08:12 +00:00
|
|
|
|
2022-06-28 08:00:23 +00:00
|
|
|
async def async_alarm_arm_night(self, code: str | None = None) -> None:
|
2019-02-13 21:52:32 +00:00
|
|
|
"""Send arm night command.
|
|
|
|
|
|
|
|
This method is a coroutine.
|
|
|
|
"""
|
2022-11-02 19:33:18 +00:00
|
|
|
code_required: bool = self._config[CONF_CODE_ARM_REQUIRED]
|
2019-07-31 19:25:30 +00:00
|
|
|
if code_required and not self._validate_code(code, "arming night"):
|
2019-02-13 21:52:32 +00:00
|
|
|
return
|
2022-11-02 19:33:18 +00:00
|
|
|
action: str = self._config[CONF_PAYLOAD_ARM_NIGHT]
|
2021-10-28 06:13:32 +00:00
|
|
|
await self._publish(code, action)
|
2019-03-30 06:36:10 +00:00
|
|
|
|
2022-06-28 08:00:23 +00:00
|
|
|
async def async_alarm_arm_vacation(self, code: str | None = None) -> None:
|
2021-08-24 11:22:49 +00:00
|
|
|
"""Send arm vacation command.
|
|
|
|
|
|
|
|
This method is a coroutine.
|
|
|
|
"""
|
2022-11-02 19:33:18 +00:00
|
|
|
code_required: bool = self._config[CONF_CODE_ARM_REQUIRED]
|
2021-08-24 11:22:49 +00:00
|
|
|
if code_required and not self._validate_code(code, "arming vacation"):
|
|
|
|
return
|
2022-11-02 19:33:18 +00:00
|
|
|
action: str = self._config[CONF_PAYLOAD_ARM_VACATION]
|
2021-10-28 06:13:32 +00:00
|
|
|
await self._publish(code, action)
|
2021-08-24 11:22:49 +00:00
|
|
|
|
2022-06-28 08:00:23 +00:00
|
|
|
async def async_alarm_arm_custom_bypass(self, code: str | None = None) -> None:
|
2020-04-06 09:45:37 +00:00
|
|
|
"""Send arm custom bypass command.
|
|
|
|
|
|
|
|
This method is a coroutine.
|
|
|
|
"""
|
2022-11-02 19:33:18 +00:00
|
|
|
code_required: bool = self._config[CONF_CODE_ARM_REQUIRED]
|
2020-04-06 09:45:37 +00:00
|
|
|
if code_required and not self._validate_code(code, "arming custom bypass"):
|
|
|
|
return
|
2022-11-02 19:33:18 +00:00
|
|
|
action: str = self._config[CONF_PAYLOAD_ARM_CUSTOM_BYPASS]
|
2021-10-28 06:13:32 +00:00
|
|
|
await self._publish(code, action)
|
2020-04-06 09:45:37 +00:00
|
|
|
|
2022-06-28 08:00:23 +00:00
|
|
|
async def async_alarm_trigger(self, code: str | None = None) -> None:
|
2021-11-29 13:41:52 +00:00
|
|
|
"""Send trigger command.
|
|
|
|
|
|
|
|
This method is a coroutine.
|
|
|
|
"""
|
2022-11-02 19:33:18 +00:00
|
|
|
code_required: bool = self._config[CONF_CODE_TRIGGER_REQUIRED]
|
2021-11-29 13:41:52 +00:00
|
|
|
if code_required and not self._validate_code(code, "triggering"):
|
|
|
|
return
|
2022-11-02 19:33:18 +00:00
|
|
|
action: str = self._config[CONF_PAYLOAD_TRIGGER]
|
2021-11-29 13:41:52 +00:00
|
|
|
await self._publish(code, action)
|
|
|
|
|
2022-11-02 19:33:18 +00:00
|
|
|
async def _publish(self, code: str | None, action: str) -> None:
|
2019-03-30 06:36:10 +00:00
|
|
|
"""Publish via mqtt."""
|
2021-12-15 10:28:43 +00:00
|
|
|
variables = {"action": action, "code": code}
|
|
|
|
payload = self._command_template(None, variables=variables)
|
2022-02-04 16:35:32 +00:00
|
|
|
await self.async_publish(
|
2019-07-31 19:25:30 +00:00
|
|
|
self._config[CONF_COMMAND_TOPIC],
|
2019-03-30 06:36:10 +00:00
|
|
|
payload,
|
2019-04-07 14:08:04 +00:00
|
|
|
self._config[CONF_QOS],
|
2019-07-31 19:25:30 +00:00
|
|
|
self._config[CONF_RETAIN],
|
2022-01-03 08:03:47 +00:00
|
|
|
self._config[CONF_ENCODING],
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2019-02-13 21:52:32 +00:00
|
|
|
|
2022-11-02 19:33:18 +00:00
|
|
|
def _validate_code(self, code: str | None, state: str) -> bool:
|
2016-03-07 15:45:21 +00:00
|
|
|
"""Validate given code."""
|
2022-11-02 19:33:18 +00:00
|
|
|
conf_code: str | None = self._config.get(CONF_CODE)
|
|
|
|
check = bool(
|
2021-10-19 10:07:38 +00:00
|
|
|
conf_code is None
|
|
|
|
or code == conf_code
|
|
|
|
or (conf_code == REMOTE_CODE and code)
|
|
|
|
or (conf_code == REMOTE_CODE_TEXT and code)
|
|
|
|
)
|
2015-10-14 06:08:12 +00:00
|
|
|
if not check:
|
2019-07-31 19:25:30 +00:00
|
|
|
_LOGGER.warning("Wrong code entered for %s", state)
|
2015-10-14 06:08:12 +00:00
|
|
|
return check
|