Template for testing to see if a json key exists in MQTT topic

I have a Tasmotized iFan02 controller that I’m trying to figure out a state template for.

the state topic for the fan is sent for both a change to the state of the light and the fan but contain different payloads.

The topic is: “stat/sonoff_MBR_fan/RESULT”

When the light is turned on the MQTT message is “{ “POWER1” : “ON” }”

When the fan speed is changed, to low for example, the MQTT message on the same topic is: “{ “FanSpeed” : 1 }”

the state template for the fan looks for the FanSpeed payload information but if I switch the light that info doesn’t exist in the message and I get an error.

Here is something similar to what I’m trying to accomplish but I just can’t find the right syntax to use to test the MQTT message data for the existence of “FanSpeed”:

state_value_template: >
  {% if value_json.FanSpeed is defined %}
    "{% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}"
  {% endif %}

Here is my complete fan & light code:

- platform: mqtt  
  name: "Master Bedroom Fan"
  command_topic: "cmnd/sonoff_MBR_fan/FanSpeed"
  speed_command_topic: "cmnd/sonoff_MBR_fan/FanSpeed"    
  state_topic: "stat/sonoff_MBR_fan/RESULT"
  speed_state_topic: "stat/sonoff_MBR_fan/RESULT"
  state_value_template: "{% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}"
  #state_value_template: >
  #  {% if value_json.FanSpeed %}
  #    "{% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}"
  #  {% endif %}
  speed_value_template: "{{ value_json.FanSpeed }}"
  availability_topic: tele/sonoff_MBR_fan/LWT
  payload_off: "0"
  payload_on: "4"
  payload_low_speed: "1"
  payload_medium_speed: "2"
  payload_high_speed: "3"
  payload_available: Online
  payload_not_available: Offline
  speeds:
    - off
    - low
    - medium
    - high

- platform: mqtt
  name: "Master Bedroom Light"
  command_topic: "cmnd/sonoff_MBR_fan/power1"
  state_topic: "stat/sonoff_MBR_fan/POWER1"
  qos: 1
  payload_on: "ON"
  payload_off: "OFF"
  retain: false

the non-commented code works but the commented code doesn’t

Basically what I want to have happen is that if the status MQTT message doesn’t contain the “FanSpeed” information I want the “state_value_template” to remain unchanged from the existing value.

Is that type of test possible?

I think you need an else statement for the check that retrieves the existing state of the entity. Something like

{% if value_json.FanSpeed %}
# work out value from FanSpeed
{% else %}
  # Get existing state of sensor
  {{ states('fan.master_bedroom_fan') }}
{% endif %}

I’ve also tried:

{% if value_json.FanSpeed %}
  "{% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}"
{% else %}
  {{ states('fan.master_bedroom_fan') }}
{% endif %}

and:

{% if value_json.FanSpeed %}
  "{% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}"
{% else %}
  {% states('fan.master_bedroom_fan') == 'off' -%}0{%- elif states('fan.master_bedroom_fan') == 'on' -%}4{%- endif %}
{% endif %}

But the state never changes from ‘off’.

I don’t think the “{% if value_json.FanSpeed %}” part is being evaluated correctly.

That’s the part I wasn’t sure on how to format correctly.

I put the following into the template editor:

{% set value_json={"FanSpeed": 0} %}
{% if value_json.FanSpeed %}
  "{% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}"
{% else %}
  "5"
{% endif %}

If I play with the value of the FanSpeed I get unexpected results.

If it is anything other than 0 the result is 4

if I change it to 0 then it returns a 5.

So it is evaluating something in there but it’s not what I expected. It seems like it’s evaluating as either true if >0 or false if =0.

Sorry, I am awake now. The correct syntax is

{% if value_json.FanSpeed is defined %}
...
1 Like

Sorry for the late response. My connection to the forum was veryy spotty yesterday. Anyway…

I already had tried that in my many other failed attempts so I thought that it was incorrect. However, I tried it again in the template editor and everything seemed to work.

HOWEVER, when i copied over to the yaml and restart it doesn’t work.

Here is the template:

{% set value_json={"FanSpeed":1} %}
{% if value_json.FanSpeed is defined %}
  "5"
{% else %}
  "{% if states.fan.master_bedroom_fan.state == 'off' -%}0{%- elif states.fan.master_bedroom_fan.state == 'on' -%}4{%- endif %}"
{% endif %}

If I put a value of 0 then I get a response of “5”. If I change the key to “Fanpeed” (no S) then I get “0”. If I switch around the “on” & “off” in the second line I get “4”. So that all seems to work perfectly.

Here is the yaml:

state_value_template: >
  {% if value_json.FanSpeed is defined %}
    "{% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}"
  {% else %}
    "{% if states.fan.master_bedroom_fan.state == 'off' -%}0{%- elif states.fan.master_bedroom_fan.state == 'on' -%}4{%- endif %}"
  {% endif %}

No matter what the value of the “FanSpeed” that gets returned from the MQTT then the test always returns a “0”.

It still looks like the “… is defined” statement is always being evaluated to ‘false’ so it always looks at the “else” but since that is already ‘off’ then the template just always returns ‘off’.

Here is the MQTT message:

ex

I didn’t believe this so I had to do some testing. I set up a fan like this

fan:
  - platform: mqtt  
    name: "Master Bedroom Fan"
    command_topic: "cmnd/sonoff_MBR_fan/FanSpeed"
    speed_command_topic: "cmnd/sonoff_MBR_fan/FanSpeed"    
    state_topic: "stat/sonoff_MBR_fan/RESULT"
    speed_state_topic: "stat/sonoff_MBR_fan/RESULT"
    state_value_template: >
      {% if value_json.FanSpeed is defined %}
        4
      {% else %}
        0
      {% endif %}
    speed_value_template: "{{ value_json.FanSpeed }}"
    payload_off: "0"
    payload_on: "4"
    payload_low_speed: "1"
    payload_medium_speed: "2"
    payload_high_speed: "3"
    speeds:
      - off
      - low
      - medium
      - high

and sent a message like this

$ mosquitto_pub -t stat/sonoff_MBR_fan/RESULT -m '{"FanSpeed":4}'

which turned the fan on

and then this

$ mosquitto_pub -t stat/sonoff_MBR_fan/RESULT -m '{"FanxSpeed":4}'

which turns the fan off.

So the check for the presence of FanSpeed is correct.

There are a couple things in the rest of your template that don’t look correct to me

  • The quotes " do not look correct. I don’t think they should be there
  • The close brackets construct doesn’t look correct -%}. I don’t think the - is necessary, but I don’t know if it causes a problem

But I am not a jinja expert - I try and avoid it as far as possible.

I’ll do some more testing but I think the "'s are there to turn the result into a string as required by the component for the state. It turns the returned data from 4 to “4”. I’ll try it without them when I get a chance and see what happens.

I think the -% character just forces a elimination of whitespace between the values. I don’t know if it’s necessary but I don’t think it will hurt anything.

On your testing did your state of the entity show that it was “off” or “on” reflecting the actual state of the fan?

My fan actually turned on to the correct speed correctly and if you look at the attributes the speed is updating correctly but the state always shows “off” even though the fan is actually running in, for example, medium speed.

no matter what I do using the “if…” statements the state always shows as “off” no matter what the actual real world state is. If I just use the plain template without the “if…” part both the state and speed both work correctly.

In that case, I think you need to surround the values returned with quotes, rather than the whole line. I suspect, from experience with other languages, that surrounding the whole line with quotes will cause the interpreter to treat the whole line as a string, rather than a command. I didn’t use any quotes in my testing.

I don’t have a fan. I just sent an mqtt message that turned the state of the entity from on to off and back again.

As a follow up and a thank you -

For some reason taking out the " from inside the first “if” ended up causing it to finally work.

But I don’t get why…

This worked to give the correct state (but gave a json error):

state_value_template: "{% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}"

This wouldn’t work:

state_value_template: >
  {% if value_json.FanSpeed is defined %}
    "{% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}"
  {% else %}
    "{% if states.fan.master_bedroom_fan.state == 'off' -%}0{%- elif states.fan.master_bedroom_fan.state == 'on' -%}4{%- endif %}"
  {% endif %}

But this did work (and got rid of the json error):

state_value_template: >
  {% if value_json.FanSpeed is defined %}
    {% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}
  {% else %}
    {% if states.fan.master_bedroom_fan.state == 'off' -%}0{%- elif states.fan.master_bedroom_fan.state == 'on' -%}4{%- endif %}
  {% endif %}

It must be some quirky thing with jinja that processes the " inside the ‘if’ statement differently than outside it.

Thanks again! :grinning:

And I think I stumbled upon my answer:

“3. You must surround single-line templates with double quotes ( " ) or single quotes ( ' ).”

Since the quotes are required for single line templates if the same line is put in a multi-line template and surrounded by quotes it apparently acts completely differently.

For what its worth, this is my explanation.

When the interpreter encounters the quote mark in the single line context, it is still interpreting yaml syntax, and the quotes are needed to surround all the jinja syntax.

However, in the longer case, it is already interpreting jinja syntax, so the quotes are interpreted as surrounding a jinja text string, rather than jinja commands.

Such complications are a major reason why I use appdaemon rather than HA automations.