diff --git a/homeassistant/components/mqtt/abbreviations.py b/homeassistant/components/mqtt/abbreviations.py index 1daa6f837c7..9ad5ca4ce1c 100644 --- a/homeassistant/components/mqtt/abbreviations.py +++ b/homeassistant/components/mqtt/abbreviations.py @@ -39,6 +39,7 @@ ABBREVIATIONS = { "cmd_tpl": "command_template", "cod_arm_req": "code_arm_required", "cod_dis_req": "code_disarm_required", + "cod_trig_req": "code_trigger_required", "curr_temp_t": "current_temperature_topic", "curr_temp_tpl": "current_temperature_template", "dev": "device", @@ -147,6 +148,7 @@ ABBREVIATIONS = { "pl_ret": "payload_return_to_base", "pl_toff": "payload_turn_off", "pl_ton": "payload_turn_on", + "pl_trig": "payload_trigger", "pl_unlk": "payload_unlock", "pos_clsd": "position_closed", "pos_open": "position_open", diff --git a/homeassistant/components/mqtt/alarm_control_panel.py b/homeassistant/components/mqtt/alarm_control_panel.py index ffea92f14c3..3c324c0789b 100644 --- a/homeassistant/components/mqtt/alarm_control_panel.py +++ b/homeassistant/components/mqtt/alarm_control_panel.py @@ -12,6 +12,7 @@ from homeassistant.components.alarm_control_panel.const import ( SUPPORT_ALARM_ARM_HOME, SUPPORT_ALARM_ARM_NIGHT, SUPPORT_ALARM_ARM_VACATION, + SUPPORT_ALARM_TRIGGER, ) from homeassistant.const import ( CONF_CODE, @@ -43,12 +44,14 @@ _LOGGER = logging.getLogger(__name__) CONF_CODE_ARM_REQUIRED = "code_arm_required" CONF_CODE_DISARM_REQUIRED = "code_disarm_required" +CONF_CODE_TRIGGER_REQUIRED = "code_trigger_required" 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_PAYLOAD_TRIGGER = "payload_trigger" CONF_COMMAND_TEMPLATE = "command_template" MQTT_ALARM_ATTRIBUTES_BLOCKED = frozenset( @@ -66,6 +69,7 @@ DEFAULT_ARM_AWAY = "ARM_AWAY" DEFAULT_ARM_HOME = "ARM_HOME" DEFAULT_ARM_CUSTOM_BYPASS = "ARM_CUSTOM_BYPASS" DEFAULT_DISARM = "DISARM" +DEFAULT_TRIGGER = "TRIGGER" DEFAULT_NAME = "MQTT Alarm" REMOTE_CODE = "REMOTE_CODE" @@ -76,6 +80,7 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend( 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, + vol.Optional(CONF_CODE_TRIGGER_REQUIRED, default=True): cv.boolean, vol.Optional( CONF_COMMAND_TEMPLATE, default=DEFAULT_COMMAND_TEMPLATE ): cv.template, @@ -91,6 +96,7 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend( CONF_PAYLOAD_ARM_CUSTOM_BYPASS, default=DEFAULT_ARM_CUSTOM_BYPASS ): cv.string, vol.Optional(CONF_PAYLOAD_DISARM, default=DEFAULT_DISARM): cv.string, + vol.Optional(CONF_PAYLOAD_TRIGGER, default=DEFAULT_TRIGGER): cv.string, vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean, vol.Required(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic, vol.Optional(CONF_VALUE_TEMPLATE): cv.template, @@ -203,6 +209,7 @@ class MqttAlarm(MqttEntity, alarm.AlarmControlPanelEntity): | SUPPORT_ALARM_ARM_NIGHT | SUPPORT_ALARM_ARM_VACATION | SUPPORT_ALARM_ARM_CUSTOM_BYPASS + | SUPPORT_ALARM_TRIGGER ) @property @@ -286,6 +293,17 @@ class MqttAlarm(MqttEntity, alarm.AlarmControlPanelEntity): action = self._config[CONF_PAYLOAD_ARM_CUSTOM_BYPASS] await self._publish(code, action) + async def async_alarm_trigger(self, code=None): + """Send trigger command. + + This method is a coroutine. + """ + code_required = self._config[CONF_CODE_TRIGGER_REQUIRED] + if code_required and not self._validate_code(code, "triggering"): + return + action = self._config[CONF_PAYLOAD_TRIGGER] + await self._publish(code, action) + async def _publish(self, code, action): """Publish via mqtt.""" command_template = self._config[CONF_COMMAND_TEMPLATE] diff --git a/tests/components/mqtt/test_alarm_control_panel.py b/tests/components/mqtt/test_alarm_control_panel.py index 1351ae59496..2a74a75c241 100644 --- a/tests/components/mqtt/test_alarm_control_panel.py +++ b/tests/components/mqtt/test_alarm_control_panel.py @@ -18,6 +18,7 @@ from homeassistant.const import ( SERVICE_ALARM_ARM_NIGHT, SERVICE_ALARM_ARM_VACATION, SERVICE_ALARM_DISARM, + SERVICE_ALARM_TRIGGER, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_CUSTOM_BYPASS, STATE_ALARM_ARMED_HOME, @@ -192,6 +193,7 @@ async def test_ignore_update_state_if_unknown_via_state_topic(hass, mqtt_mock): (SERVICE_ALARM_ARM_VACATION, "ARM_VACATION"), (SERVICE_ALARM_ARM_CUSTOM_BYPASS, "ARM_CUSTOM_BYPASS"), (SERVICE_ALARM_DISARM, "DISARM"), + (SERVICE_ALARM_TRIGGER, "TRIGGER"), ], ) async def test_publish_mqtt_no_code(hass, mqtt_mock, service, payload): @@ -222,6 +224,7 @@ async def test_publish_mqtt_no_code(hass, mqtt_mock, service, payload): (SERVICE_ALARM_ARM_VACATION, "ARM_VACATION"), (SERVICE_ALARM_ARM_CUSTOM_BYPASS, "ARM_CUSTOM_BYPASS"), (SERVICE_ALARM_DISARM, "DISARM"), + (SERVICE_ALARM_TRIGGER, "TRIGGER"), ], ) async def test_publish_mqtt_with_code(hass, mqtt_mock, service, payload): @@ -271,6 +274,7 @@ async def test_publish_mqtt_with_code(hass, mqtt_mock, service, payload): (SERVICE_ALARM_ARM_VACATION, "ARM_VACATION"), (SERVICE_ALARM_ARM_CUSTOM_BYPASS, "ARM_CUSTOM_BYPASS"), (SERVICE_ALARM_DISARM, "DISARM"), + (SERVICE_ALARM_TRIGGER, "TRIGGER"), ], ) async def test_publish_mqtt_with_remote_code(hass, mqtt_mock, service, payload): @@ -311,6 +315,7 @@ async def test_publish_mqtt_with_remote_code(hass, mqtt_mock, service, payload): (SERVICE_ALARM_ARM_VACATION, "ARM_VACATION"), (SERVICE_ALARM_ARM_CUSTOM_BYPASS, "ARM_CUSTOM_BYPASS"), (SERVICE_ALARM_DISARM, "DISARM"), + (SERVICE_ALARM_TRIGGER, "TRIGGER"), ], ) async def test_publish_mqtt_with_remote_code_text(hass, mqtt_mock, service, payload): @@ -351,6 +356,7 @@ async def test_publish_mqtt_with_remote_code_text(hass, mqtt_mock, service, payl (SERVICE_ALARM_ARM_VACATION, "ARM_VACATION", "code_arm_required"), (SERVICE_ALARM_ARM_CUSTOM_BYPASS, "ARM_CUSTOM_BYPASS", "code_arm_required"), (SERVICE_ALARM_DISARM, "DISARM", "code_disarm_required"), + (SERVICE_ALARM_TRIGGER, "TRIGGER", "code_trigger_required"), ], ) async def test_publish_mqtt_with_code_required_false( @@ -358,7 +364,8 @@ async def test_publish_mqtt_with_code_required_false( ): """Test publishing of MQTT messages when code is configured. - code_arm_required = False / code_disarm_required = false + code_arm_required = False / code_disarm_required = False / + code_trigger_required = False """ config = copy.deepcopy(DEFAULT_CONFIG_CODE) config[alarm_control_panel.DOMAIN][disable_code] = False