Evaluation of data_template for MQTT.publish topic is incorrect

Hi *,

I have the following config of an input selector, a mqtt position sensor and a mqtt switch. It a controller for my rollershutters - 100% are closed and 0% are opened:

input_select:
  rollershutter_badog:
    name: Rollershutter BadOG
    options:
      - 100
      - 86
      - 38
      - 0
    initial: 0

switch:    
  - platform: mqtt
    name: "rollershutter_1_bathroom_up"
    command_topic: "house/bathroom/rollershutter/1/drive/up"
    payload_on: "0"
    payload_off: "-1"

  - platform: mqtt
    name: "rollershutter_1_bathroom_down"
    command_topic: "house/bathroom/rollershutter/1/drive/down"
    payload_on: "100"
    payload_off: "-1"

sensor:
  - platform: mqtt
    device_class: "battery"
    name: "rollershutter_1_bathroom_position"
    state_topic: "house/bathroom/rollershutter/1/position"
    unit_of_measurement: "%"    
    
  - platform: mqtt
    name: "rollershutter_1_bathroom_stop"
    state_topic: "house/bathroom/rollershutter/1/drive/stop"
    

The following automation shall drive the motor the the preset position:

- alias: "Badezimmer Rollershutter Preset"
  trigger:
    platform: state
    entity_id: input_select.rollershutter_badog
  action:    
    - service: mqtt.publish
      data_template:
        topic: >-
          {% if (( states('sensor.rollershutter_1_bathroom_position') | int ) == 100 ) and (( states('input_select.rollershutter_badog.state') | int ) < 100 ) %}
            "1house/bathroom/rollershutter/1/drive/up"
          {%-elif (( states('sensor.rollershutter_1_bathroom_position') | int ) == 0 ) and (( states('input_select.rollershutter_badog.state') | int ) > 0 ) %}
            "2house/bathroom/rollershutter/1/drive/down"
          {%-elif ( states('sensor.rollershutter_1_bathroom_position') | int ) < ( states('input_select.rollershutter_badog.state') | int ) %}
            "3house/bathroom/rollershutter/1/drive/up"
          {%-elif ( states('sensor.rollershutter_1_bathroom_position') | int ) > ( states('input_select.rollershutter_badog.state') | int ) %}
            "4house/bathroom/rollershutter/1/drive/down"
          {% else %}
            "error"
          {% endif %}
        payload_template: "{{ states.input_select.rollershutter_badog.state }}"

I tried the template debugging to see if the topic is evaluated correctly.
It is not.

Only conditions 1 and 4 are evaluated correctly.
Conditions 2 and 3 never check out:

  • 2 returns nothing at all
  • 3 returns “4house/bathroom/rollershutter/1/drive/down”

Does anyone have an idea, what I might be doing wrong?

Best,
Ck

and anything similar should be

states('input_select.rollershutter_badog')

i.e no .state.

Also, be consistent and use states('xxx') instead of states.xxx.
And use variables instead of getting the same state again and again.

So it can be

- service: mqtt.publish
  data_template:
    topic: >-
      {%- set pos = states('sensor.rollershutter_1_bathroom_position') | int %}
      {%- set badog = states('input_select.rollershutter_badog') | int %}
      {%- if pos == 100 and badog < 100 ) %}
        "1house/bathroom/rollershutter/1/drive/up"
      {%-elif pos == 0 and badog > 0 ) %}
        "2house/bathroom/rollershutter/1/drive/down"
      {%-elif pos < badog %}
        "3house/bathroom/rollershutter/1/drive/up"
      {%-elif pos > badog %}
        "4house/bathroom/rollershutter/1/drive/down"
      {% else %}
        error
      {% endif %}
    payload_template: "{{ states('input_select.rollershutter_badog' }}"

Not sure if your logic covers all options though. What if pos == badog? :wink:

1 Like

Ok, thanks. That works in the evaluator.
Non the less, the automation is never executed.
Any ideas?

But for my understanding, when I try this with .state in the template evaluator, the part of the condition evaluates correctly. How is that?

it’s called Jinja :wink:
try this

{{ states('input_select.rollershutter_badog.state') }}

and you’ll get unknown because there is no such entity.
then add int filter

{{ states('input_select.rollershutter_badog.state') | int }}

and you’ll get 0 because it’s a default when conversion fails.
so you and up with 0 < 100, which is always True so your A and 0<100 always depends on A only.

But

{{ states('input_select.rollershutter_badog.state') | int }}

evaluates correctly, otherwise I would not have asked…

However,

any idea why the automation is still not triggered?

what is “correctly” in your meaning?

This automation system should trigger whenever the input_select changes state. Are you saying it fails to do that?

Sorry, @AhmadK I was wrong. It is exactly as you said.
I have confused one of the many variations I have tried.

@123 The automation fails to execute. No logbook entry and no message while listening on the MQTT topic.

Which version are you testing? Your original one or the one AhmadK suggested?

I suggest you use AhmadK’s version and, as a test, manually trigger it. Go to Developer Tools > Services and complete the form like in the image below then click Call Service.

It should publish something.

I am using the solution of @AhmadK.

When I call the service, an entry in the logbook is created.
But I see no mqtt messages on the topics.
How can I provide a preset value when I call the service?

AhmadK’s example will, at minimum, publish to the topic name error.

If you are not seeing anything published, even to error, then I have to question whether your Home Assistant has a functional connection to your MQTT Broker.

Go to Developer Tools > MQTT, fill in the form with the data shown in the image, then click Publish.

Screenshot from 2020-03-24 11-50-17

You should see that hello was published to test.

Also, what are you using to confirm payloads have been published to topics? Are you using a tool like MQTT Explorer?

My MQTT broker is working fine, dedicated RPi with mosquitto installation.
I am monitoring the MQTT topic in Developer->MQTT and on my ESP32 that I am programming.

I don’t see any message, even not error.

Are you saying that you carried out the test I asked you to do and it failed to publish hello to the topic called test?

But I wouldn’t see error in any of the topics. I have to monitor the topic error and no message eather…

No I did not try hello and test. I can confirm that this way of debugging is working in principle, because I use it regularly.

It is just this automation, that I cannot get to work.

If you’re not interested in performing the test I suggested then my involvement ends now. You say it is “working in principle” but I need confirmation it is “working in fact”.

Good luck solving the problem.

Sorry, I did not want to offend you!
But I was bit short on time answering, because kid came in the way.
I will try it tomorrow.

I was not offended but I also have limited time to troubleshoot your problem. Someone else, with more available time, can assist you.

I figured the last bit out myself. The problem was not with the automation or the triggering event, but with the template expansion. The topics inside the conditional scope need to go into double curly brackets:

topic: >-
      {%- set pos = states('sensor.rollershutter_1_bathroom_position') | int %}
      {%- set badog = states('input_select.rollershutter_badog') | int %}
      {%- if pos == 100 and badog < 100 ) %}
        {{"1house/bathroom/rollershutter/1/drive/up"}}
      {%-elif pos == 0 and badog > 0 ) %}
        {{"2house/bathroom/rollershutter/1/drive/down"}}
      {%-elif pos < badog %}
        {{"3house/bathroom/rollershutter/1/drive/up"}}
      {%-elif pos > badog %}
        {{"4house/bathroom/rollershutter/1/drive/down"}}
      {% else %}
        {{"error"}}
      {% endif %}

mate, you haven’t fixed it then as your code is not valid (at least what you posted above), extra right brackets at if and the first elif :wink:
and you spotted the last bit right but there is something fundamentally wrong with your approach, let me explain why.

Generally everything outside {{}} (templates) is passed as-is. That means if we look at the original code,

 {%- if pos == 100 and badog < 100 ) %}
        "1house/bathroom/rollershutter/1/drive/up"

will return

“1house/bathroom/rollershutter/1/drive/up”

and it won’t work as expected at MQTT level because your MQTT topic is 1house/bathroom/rollershutter/1/drive/up, a different one (not sure if you’re allowed to have quotes in topics, wouldn’t recommend that).
The easiest way to correct that is to remove quotes.

There are several alternatives: you can return something from a template. As you figured out, {{ "blah-blah"}} does the trick.
A very useful alternative is using format if you want to return dynamic strings, from simple

{{ "{}".format("error") }}

to things like

{# all these variables can (and should be) be dynamic #}
{% set house = '1house' %}
{% set room = 'bathroom' %}
{% set direction = 'up' %}
{{ "{}/{}/rollershutter/1/drive/{}".format(house, room, direction) }}

and you’ll get the same result.

The bottom line the working code is

topic: >-
  {% set pos = states('sensor.rollershutter_1_bathroom_position') | int %}
  {% set badog = states('input_select.rollershutter_badog') | int %}
  {% if pos == 100 and badog < 100 %}
    1house/bathroom/rollershutter/1/drive/up
  {%elif pos == 0 and badog > 0 %}
    2house/bathroom/rollershutter/1/drive/down
  {%elif pos < badog %}
    3house/bathroom/rollershutter/1/drive/up
  {%elif pos > badog %}
    4house/bathroom/rollershutter/1/drive/down
  {% else %}
    error
  {% endif %}

so fix your config :wink: