Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions homeassistant/components/mqtt/trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import voluptuous as vol

from homeassistant.const import CONF_PAYLOAD, CONF_PLATFORM
from homeassistant.const import CONF_PAYLOAD, CONF_PLATFORM, CONF_VALUE_TEMPLATE
from homeassistant.core import HassJob, callback
from homeassistant.helpers import config_validation as cv, template

Expand All @@ -23,6 +23,7 @@
vol.Required(CONF_PLATFORM): mqtt.DOMAIN,
vol.Required(CONF_TOPIC): mqtt.util.valid_subscribe_topic_template,
vol.Optional(CONF_PAYLOAD): cv.template,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_ENCODING, default=DEFAULT_ENCODING): cv.string,
vol.Optional(CONF_QOS, default=DEFAULT_QOS): vol.All(
vol.Coerce(int), vol.In([0, 1, 2])
Expand All @@ -36,27 +37,38 @@
async def async_attach_trigger(hass, config, action, automation_info):
"""Listen for state changes based on configuration."""
topic = config[CONF_TOPIC]
payload = config.get(CONF_PAYLOAD)
wanted_payload = config.get(CONF_PAYLOAD)
value_template = config.get(CONF_VALUE_TEMPLATE)
encoding = config[CONF_ENCODING] or None
qos = config[CONF_QOS]
job = HassJob(action)
variables = None
if automation_info:
variables = automation_info.get("variables")

template.attach(hass, payload)
if payload:
payload = payload.async_render(variables, limited=True)
template.attach(hass, wanted_payload)
if wanted_payload:
wanted_payload = wanted_payload.async_render(variables, limited=True)

template.attach(hass, topic)
if isinstance(topic, template.Template):
topic = topic.async_render(variables, limited=True)
topic = mqtt.util.valid_subscribe_topic(topic)

template.attach(hass, value_template)

@callback
def mqtt_automation_listener(mqttmsg):
"""Listen for MQTT messages."""
if payload is None or payload == mqttmsg.payload:
payload = mqttmsg.payload

if value_template is not None:
payload = value_template.async_render_with_possible_json_value(
payload,
error_value=None,
)

if wanted_payload is None or wanted_payload == payload:
data = {
"platform": "mqtt",
"topic": mqttmsg.topic,
Expand All @@ -73,7 +85,7 @@ def mqtt_automation_listener(mqttmsg):
hass.async_run_hass_job(job, {"trigger": data})

_LOGGER.debug(
"Attaching MQTT trigger for topic: '%s', payload: '%s'", topic, payload
"Attaching MQTT trigger for topic: '%s', payload: '%s'", topic, wanted_payload
)

remove = await mqtt.async_subscribe(
Expand Down
31 changes: 31 additions & 0 deletions tests/components/mqtt/test_trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,37 @@ async def test_if_fires_on_templated_topic_and_payload_match(hass, calls):
assert len(calls) == 1


async def test_if_fires_on_payload_template(hass, calls):
"""Test if message is fired on templated topic and payload match."""
assert await async_setup_component(
hass,
automation.DOMAIN,
{
automation.DOMAIN: {
"trigger": {
"platform": "mqtt",
"topic": "test-topic",
"payload": "hello",
"value_template": "{{ value_json.wanted_key }}",
},
"action": {"service": "test.automation"},
}
},
)

async_fire_mqtt_message(hass, "test-topic", "hello")
await hass.async_block_till_done()
assert len(calls) == 0

async_fire_mqtt_message(hass, "test-topic", '{"unwanted_key":"hello"}')
await hass.async_block_till_done()
assert len(calls) == 0

async_fire_mqtt_message(hass, "test-topic", '{"wanted_key":"hello"}')
await hass.async_block_till_done()
assert len(calls) == 1


async def test_non_allowed_templates(hass, calls, caplog):
"""Test non allowed function in template."""
assert await async_setup_component(
Expand Down