Implementation of new Vacation mode for MQTT-based alarm panels (#53561)

* Impelentation of new Vacation Mode for MQTT-based alarm panels

* Fixed typo

* another typo fix

* Split integrations: remove manual_mqtt

* added newline

* Impelentation of new Vacation Mode for MQTT-based alarm panels

* Fixed typo

* another typo fix

* Split integrations: remove manual_mqtt

* added newline

* missing abbreviation

* Fix tests

Co-authored-by: Erik Montnemery <erik@montnemery.com>
pull/55145/head
posixx 2021-08-24 13:22:49 +02:00 committed by GitHub
parent a5e498207d
commit 547ede1e91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 95 additions and 0 deletions

View File

@ -113,6 +113,7 @@ ABBREVIATIONS = {
"pl_arm_away": "payload_arm_away",
"pl_arm_home": "payload_arm_home",
"pl_arm_nite": "payload_arm_night",
"pl_arm_vacation": "payload_arm_vacation",
"pl_arm_custom_b": "payload_arm_custom_bypass",
"pl_avail": "payload_available",
"pl_cln_sp": "payload_clean_spot",

View File

@ -11,6 +11,7 @@ from homeassistant.components.alarm_control_panel.const import (
SUPPORT_ALARM_ARM_CUSTOM_BYPASS,
SUPPORT_ALARM_ARM_HOME,
SUPPORT_ALARM_ARM_NIGHT,
SUPPORT_ALARM_ARM_VACATION,
)
from homeassistant.const import (
CONF_CODE,
@ -20,6 +21,7 @@ from homeassistant.const import (
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,
@ -52,6 +54,7 @@ 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"
CONF_PAYLOAD_ARM_VACATION = "payload_arm_vacation"
CONF_PAYLOAD_ARM_CUSTOM_BYPASS = "payload_arm_custom_bypass"
CONF_COMMAND_TEMPLATE = "command_template"
@ -65,6 +68,7 @@ MQTT_ALARM_ATTRIBUTES_BLOCKED = frozenset(
DEFAULT_COMMAND_TEMPLATE = "{{action}}"
DEFAULT_ARM_NIGHT = "ARM_NIGHT"
DEFAULT_ARM_VACATION = "ARM_VACATION"
DEFAULT_ARM_AWAY = "ARM_AWAY"
DEFAULT_ARM_HOME = "ARM_HOME"
DEFAULT_ARM_CUSTOM_BYPASS = "ARM_CUSTOM_BYPASS"
@ -83,6 +87,9 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend(
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,
vol.Optional(
CONF_PAYLOAD_ARM_VACATION, default=DEFAULT_ARM_VACATION
): cv.string,
vol.Optional(
CONF_PAYLOAD_ARM_CUSTOM_BYPASS, default=DEFAULT_ARM_CUSTOM_BYPASS
): cv.string,
@ -158,6 +165,7 @@ class MqttAlarm(MqttEntity, alarm.AlarmControlPanelEntity):
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,
@ -193,6 +201,7 @@ class MqttAlarm(MqttEntity, alarm.AlarmControlPanelEntity):
SUPPORT_ALARM_ARM_HOME
| SUPPORT_ALARM_ARM_AWAY
| SUPPORT_ALARM_ARM_NIGHT
| SUPPORT_ALARM_ARM_VACATION
| SUPPORT_ALARM_ARM_CUSTOM_BYPASS
)
@ -256,6 +265,17 @@ class MqttAlarm(MqttEntity, alarm.AlarmControlPanelEntity):
action = self._config[CONF_PAYLOAD_ARM_NIGHT]
self._publish(code, action)
async def async_alarm_arm_vacation(self, code=None):
"""Send arm vacation command.
This method is a coroutine.
"""
code_required = self._config[CONF_CODE_ARM_REQUIRED]
if code_required and not self._validate_code(code, "arming vacation"):
return
action = self._config[CONF_PAYLOAD_ARM_VACATION]
self._publish(code, action)
async def async_alarm_arm_custom_bypass(self, code=None):
"""Send arm custom bypass command.

View File

@ -12,6 +12,7 @@ from homeassistant.const import (
SERVICE_ALARM_ARM_CUSTOM_BYPASS,
SERVICE_ALARM_ARM_HOME,
SERVICE_ALARM_ARM_NIGHT,
SERVICE_ALARM_ARM_VACATION,
SERVICE_ALARM_DISARM,
SERVICE_ALARM_TRIGGER,
)
@ -61,6 +62,19 @@ async def async_alarm_arm_night(hass, code=None, entity_id=ENTITY_MATCH_ALL):
await hass.services.async_call(DOMAIN, SERVICE_ALARM_ARM_NIGHT, data, blocking=True)
async def async_alarm_arm_vacation(hass, code=None, entity_id=ENTITY_MATCH_ALL):
"""Send the alarm the command for vacation mode."""
data = {}
if code:
data[ATTR_CODE] = code
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
await hass.services.async_call(
DOMAIN, SERVICE_ALARM_ARM_VACATION, data, blocking=True
)
async def async_alarm_trigger(hass, code=None, entity_id=ENTITY_MATCH_ALL):
"""Send the alarm the command for disarm."""
data = {}

View File

@ -14,6 +14,7 @@ from homeassistant.const import (
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,
@ -124,6 +125,7 @@ async def test_update_state_via_state_topic(hass, mqtt_mock):
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,
@ -176,6 +178,7 @@ async def test_arm_home_not_publishes_mqtt_with_invalid_code_when_req(hass, mqtt
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG_CODE,
)
await hass.async_block_till_done()
call_count = mqtt_mock.async_publish.call_count
await common.async_alarm_arm_home(hass, "abcd")
@ -227,6 +230,7 @@ async def test_arm_away_not_publishes_mqtt_with_invalid_code_when_req(hass, mqtt
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG_CODE,
)
await hass.async_block_till_done()
call_count = mqtt_mock.async_publish.call_count
await common.async_alarm_arm_away(hass, "abcd")
@ -278,6 +282,7 @@ async def test_arm_night_not_publishes_mqtt_with_invalid_code_when_req(hass, mqt
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG_CODE,
)
await hass.async_block_till_done()
call_count = mqtt_mock.async_publish.call_count
await common.async_alarm_arm_night(hass, "abcd")
@ -304,6 +309,60 @@ async def test_arm_night_publishes_mqtt_when_code_not_req(hass, mqtt_mock):
)
async def test_arm_vacation_publishes_mqtt(hass, mqtt_mock):
"""Test publishing of MQTT messages while armed."""
assert await async_setup_component(
hass,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG,
)
await hass.async_block_till_done()
await common.async_alarm_arm_vacation(hass)
mqtt_mock.async_publish.assert_called_once_with(
"alarm/command", "ARM_VACATION", 0, False
)
async def test_arm_vacation_not_publishes_mqtt_with_invalid_code_when_req(
hass, mqtt_mock
):
"""Test not publishing of MQTT messages with invalid code.
When code_arm_required = True
"""
assert await async_setup_component(
hass,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG_CODE,
)
await hass.async_block_till_done()
call_count = mqtt_mock.async_publish.call_count
await common.async_alarm_arm_vacation(hass, "abcd")
assert mqtt_mock.async_publish.call_count == call_count
async def test_arm_vacation_publishes_mqtt_when_code_not_req(hass, mqtt_mock):
"""Test publishing of MQTT messages.
When code_arm_required = False
"""
config = copy.deepcopy(DEFAULT_CONFIG_CODE)
config[alarm_control_panel.DOMAIN]["code_arm_required"] = False
assert await async_setup_component(
hass,
alarm_control_panel.DOMAIN,
config,
)
await hass.async_block_till_done()
await common.async_alarm_arm_vacation(hass)
mqtt_mock.async_publish.assert_called_once_with(
"alarm/command", "ARM_VACATION", 0, False
)
async def test_arm_custom_bypass_publishes_mqtt(hass, mqtt_mock):
"""Test publishing of MQTT messages while armed."""
assert await async_setup_component(
@ -446,6 +505,7 @@ async def test_disarm_not_publishes_mqtt_with_invalid_code_when_req(hass, mqtt_m
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG_CODE,
)
await hass.async_block_till_done()
call_count = mqtt_mock.async_publish.call_count
await common.async_alarm_disarm(hass, "abcd")