Using MQTT messages as triggers

Ok, I think I got the idea of blueprints.

I have several automations that are almost identical that link a Aqara Zigbee button to a group of lights. When I do a single click on it, the light toggles state, like this:

- id: '1607725222698'
  alias: Quarto do Murilo -- mudar o estado do lustre
  description: ''
  trigger:
  - platform: mqtt
    topic: zigbee2mqtt/BTQuartoMurilo/action
    payload: single
  action:
  - service: light.toggle
    entity_id: light.lustre_do_quarto_do_murilo
  mode: single

I believe that the input elements will be the MQTT topic and the light entity, right?

How can I do a bluprint for this? I think in something like this:

blueprint:
  name: Muda estado de luzes com botao Aqara
  domain: automation
  input:
    botao:
    lustre:
  
trigger:
  platform: mqtt
  topic: zigbee2mqtt/{{!input botao}}/action
  payload: single

action:
  service: light.toggle
  entity_id: !input lustre

What is the right way of using a MQTT topic as a trigger for a blueprint?

Thanks!

Why several automations and not just one that toggles the appropriate light based on the received payload?

1 Like

The payload is the same (single). What varies is the mqtt topic

    topic: zigbee2mqtt/+/action

For more information, see Wildcards.

The action can determine which topic was responsible for the trigger by parsing trigger.topic.


EDIT

Let me know if you want help creating the all-in-one automation.

2 Likes

Thanks! I did not think about using wildcards. I will rewrite the automations to use wildcard. :slight_smile:

But my doubt remains: how can I use a Mqtt topic as input for a blueprint?

If you create the all-in-one automation I am proposing, you donā€™t need a blueprint.


EDIT

For what I have in mind, I would need more examples of the association between the topic and the entity. For example, if the topic contains BTQuartoMurilo it is associated with the light called lustre_do_quarto_do_murilo. I need more associations like that to create the automation.

I would have thought that with Z2M exposing native entities in homeassistant it would be more logical to use a state trigger for your blueprint.

Users can then feed the entity_ids of their buttons into the automations that use your blueprint.

Regardless of whether you SHOULD do this, the reason itā€™s not working is several things.

  1. I donā€™t believe mqtt triggers support templates in the topic
  2. if it does allow templates in the topic, youā€™d need quotes around it
  3. templates donā€™t support inputs, so you need to convert it to a variable.

So, you can entire the FULL topic as the input and use topic: !input botao in your MQTT trigger. Orā€¦ you can use conditions and variables, like this:

blueprint:
  name: MQTT Test
  description: MQTT Test
  domain: automation
  input:
    topic_piece:

mode: restart
max_exceeded: silent

variables:
  topic_piece: !input topic_piece

trigger:
  platform: mqtt
  topic: "test/+"


action:
  - condition: template
    value_template: "{{ trigger.topic == 'test/' + topic_piece }}"

  - service: input_text.set_value
    data:
      entity_id: input_text.test_1
      value: "{{ trigger.payload }}"
1 Like

Got it. Thanks!

If I have a MQTT topic structure like

RFBridge/remote1/key1
ā€¦
RFBridge/remote1/key8

which I want to control several devices (which arenā€™t named the same as the latter part of the trigger topic, just to be awkward!), how would I do it. I have this so far, and itā€™s showing the correct device name when I press the corresponding button on the RF remote (which triggers the MQTT message sent) ā€¦ I just canā€™t seem to work out how to make the leap to toggling the device stateā€¦

alias: Downstairs Lights - Toggle
description: ''
trigger:
  - platform: mqtt
    topic: 'RFBridge/remote1/#'
    payload: 'ON'
condition: []
action:
  - service: system_log.write
    data:
      message: >-
        {% set key_pressed = trigger.topic.split("/")[-1] %} {% if key_pressed
        ==  "key1" %} switch.downstairs_lights {% elif key_pressed == "key2" %}
        light.light4 {% elif key_pressed == "key3" %} light.light1 {% elif
        key_pressed == "key4" %} light.light5 {% elif key_pressed == "key5"
        %}light.light2 {% elif key_pressed == "key7" %} light.light3 {%  endif
        %}
      level: warning
mode: single

Any suggestions or subtle whacks on the side of the head for not doing the bleeding obvious would be appreciated. Thereā€™s a coffee in your future if you can make sense of my ramblings and point me in the right direction :wink:

I would do it like this:

alias: Downstairs Lights - Toggle
description: ''
trigger:
  - platform: mqtt
    topic: 'RFBridge/remote1/#'
    payload: 'ON'
condition: []
action:
  - service: homeassistant.toggle
    data:
      entity_id: >-
        {% set i = trigger.topic[-1] | int %}
        {% set lights = { 1: 'switch.downstairs_lights', 2: 'light.light4',
                          3: 'light.light1', 4: 'light.light5',
                          5: 'light.light2', 6: 'light.light0',
                          7: 'light.light3', 8: 'light.light0' } %}
        {{ lights[i] if i in lights.keys() else 'none' }}
mode: single

In your example, it doesnā€™t specify a light if the topic contains key6 or key8. In my example, I set those two to light.light0. You will need to change that to the actual lights controlled by key6 and key8.

The template works like this:

  • It sets a variable named i to the last character in the topic and converts it to an integer value.
  • It creates a dictionary that lists keys, from 1 to 8, and their corresponding values representing the light (or switch) to be controlled.
  • The final line checks if i exists in the dictionary. If it exists, it reports its corresponding value (retrieved by lights[i]). If it does not exist, then it reports none which means nothing will be toggled.
1 Like

Coffee sent :wink:

Thank you very much, especially for the explanation of how the code worksā€¦ that makes perfect sense. Now, if you would like cake with that coffee ā€¦ :laughing:

My intention for those remaining two buttons was for them to control brightness. i.e. key6 would be increasing brightness, and key8 would be decreasing. Lets say for light.light_0, as I have yet to incorporate the global brightness for this rig into HA. Is it practical to including this in the same automation, or just do another one. And itā€™s if not practical, whatā€™s the best way of ignoring those two buttons here, if only so it doesnā€™t spew log warnings? As it probably comes to no surprise to you, neither ā€˜noneā€™ or ā€˜nullā€™ gave me any satisfactionā€¦

Downstairs Lights - Toggle Lights: Error executing script. Invalid data for call_service at pos 1: Entity ID is an invalid entity id for dictionary value @ data['entity_id'] 

Edit: Am I trying to be too clever here, using the wildcard? Perhaps better to use trigger for each key to eliminate the two not interested in?

I had to change the name for the entity ids name slightly (my mistake) and it seemed to be looking for light, not lights. But this is now working, except for the log warnings on the remaining two keys. Iā€™m not set on the button order, I can re-map that in node-red if changing the sequence makes anything easier.

alias: Downstairs Lights - Toggle Lights
description: ''
trigger:
  - platform: mqtt
    topic: 'RFBridge/remote1/#'
    payload: 'ON'
condition: []
action:
  - service: homeassistant.toggle
    data:
      entity_id: >-
        {% set i = trigger.topic[-1] | int %} 
        {% set lights = { 1: 'switch.downstairs_lights', 2: 'light.light_4',
                          3: 'light.light_1', 4: 'light.light_5',
                          5: 'light.light_2', 6: 'none',
                          7: 'light.light_3', 8: 'none' } %}
        {{ lights[i] if i in lights.keys() else 'none' }}
mode: single
1 Like

Actually, on second thoughtā€¦ Iā€™ll keep hammering away at it, as I now have the remote automation doing what I want, up to the point that I need to implement the global brightness stuff on the light controller, before I can do the last bit for brightnessā€¦

Iā€™ve ended up with three automationā€¦ one for the individual lights, one for the master on/off, and a third will be for the brightness. Iā€™ll do a separate post a little later to explain it all, and edit this one to cross-link to it. Plus Iā€™ll ask any further questions there as to not take this one off tangent. Thanks again!

Thanks for the coffee!

Iā€™ll look into the issue concerning the warning message.

It appears that homeassistant.toggle does not accept none for entity_id.

That seems like an oversight to me because light.toggle and switch.toggle accept none without complaint (as they also do for turn_on and turn_off services). The value none was adopted several versions ago as a way of instructing the service to ā€œdo nothing quietlyā€.

Iā€™ve modified the automation so that it doesnā€™t rely on the use of none and only accepts buttons 1, 2, 3, 4, 5, and 7.

alias: Downstairs Lights - Toggle Lights
description: ''
trigger:
  - platform: mqtt
    topic: 'RFBridge/remote1/#'
    payload: 'ON'
condition: []
action:
  - variables:
      i: '{{ trigger.topic[-1] | int }}'
  - condition: template
    value_template: "{{ i in [1, 2, 3, 4, 5, 7] }}"
  - service: homeassistant.toggle
    data:
      entity_id: >-
        {{ { 1: 'switch.downstairs_lights', 2: 'light.light_4',
             3: 'light.light_1', 4: 'light.light_5',
             5: 'light.light_2', 7: 'light.light_3' }[i] }}
mode: single

EDIT

If you want the ability to increase one or more predefined lightā€™s brightness with key6 and decrease it with key8 hereā€™s a way to do it:

alias: Downstairs Lights - Toggle Lights
description: ''
trigger:
  - platform: mqtt
    topic: 'RFBridge/remote1/#'
    payload: 'ON'
condition: []
action:
  - variables:
      i: '{{ trigger.topic[-1] | int }}'
  - choose:
    - conditions: '{{ i in [1, 2, 3, 4, 5, 7] }}'
      sequence:
      - service: homeassistant.toggle
        data:
          entity_id: >-
            {{ { 1: 'switch.downstairs_lights', 2: 'light.light_4',
                 3: 'light.light_1', 4: 'light.light_5',
                 5: 'light.light_2', 7: 'light.light_3' }[i] }}
    - conditions: '{{ i in [6, 8] }}'
      sequence:
      - service: light.turn_on
        data:
          entity_id:
          - light.light_1
          - light.light_2
          brightness_step_pct: '{{ 10 if i == 6 else -10 }}'
mode: queued
1 Like

Oh myā€¦ that is nice! :slight_smile: Makes my current solution look like what it isā€¦ crude (but effective?) :laughing: And I still havenā€™t done that post, have Iā€¦ Iā€™ll do that right now to put this into context, and link back to this thread. Think I owe you another coffee now too! :wink:

EDIT: Start of waffle on what this was all about

Yeah, since light.toggle and switch.toggle both accept none, youā€™d expect homeassistant.toggle to also accept it, wouldnā€™t youā€¦ Suppose should ask it be added via feature requests?

Automation Kludge
alias: Downstairs Lights - Toggle Lights
description: ''
trigger:
  - platform: mqtt
    topic: RFBridge/remote1/key2
    payload: 'ON'
  - platform: mqtt
    topic: RFBridge/remote1/key3
    payload: 'ON'
  - platform: mqtt
    topic: RFBridge/remote1/key4
    payload: 'ON'
  - platform: mqtt
    topic: RFBridge/remote1/key5
    payload: 'ON'
  - platform: mqtt
    topic: RFBridge/remote1/key7
    payload: 'ON'
condition: []
action:
  - service: light.toggle
    data:
      entity_id: >-
        {% set key_pressed = trigger.topic.split("/")[-1] %} {% if key_pressed
        == "key3" %} light.light_1 {% elif key_pressed == "key5" %}
        light.light_2 {% elif key_pressed == "key7" %} light.light_3 {% elif
        key_pressed == "key2" %} light.light_4 {% elif key_pressed == "key4" %}
        light.light_5 {% endif %}
mode: single
alias: Downstairs Lights - Brightness
description: ''
trigger:
  - platform: mqtt
    topic: RFBridge/remote1/key6
    payload: 'ON'
  - platform: mqtt
    topic: RFBridge/remote1/key8
    payload: 'ON'
condition: []
action:
  - service: light.turn_on
    data_template:
      entity_id: light.light_master
      brightness: >-
        {% if trigger.topic.split("/")[-1] == "key6" %} {{
        states.light.light_master.attributes.brightness | int + 50 }} {% else %}
        {{ states.light.light_master.attributes.brightness | int - 50 }} {%
        endif %}  
mode: single