Using one switch device to trigger another via MQTT revisited

Following this link, I created an automation in the automation.yaml file. It gave the below error on ‘check config’. So I wholesale copied the text from the thread, and got the same the error.

Error loading /config/configuration.yaml: while scanning for the next token
found character '%' that cannot start any token

Is there anywhere the explains the syntax of a yaml file specifically the following that are observed in the above thread’s code snippits that are reported to run successfully:

  • the greater than sign: >
  • the percent sign: %

here is the code I tried:

  alias: p1_control
  trigger:
    platform: state
    entity_id: switch.sonoff2
  action:
    - service_template: >
      {% if is_state('switch.sonoff2', 'on') %}
        switch.turn_on
      {% else is_state('switch.sonoff2', 'off') %}
        switch.turn_off
      {% endif %}
      entity_id: switch.sonoff

If found this link that has yaml information. It does not mention the % or >. And this link.

I tried the above with and without the dash “-”. I read that the dash followed by space denotes lists. I don’t know why the code has a dash in the action section.

The first example in the documentation suggests that the lines after the > need to be indented. See https://www.home-assistant.io/docs/configuration/templating/

PS, wouldn’t toggle be simpler?

the “>” denotes a multi-line template. If you only have one line of template then the template has to be enclosed by quotation marks.

So you could technically do this:

- service_template: "{% if is_state('switch.sonoff2', 'on') %}switch.turn_on{% else is_state('switch.sonoff2', 'off') %}switch.turn_off{% endif %}"

but that’s damn hard to read.

so if you split it up into multiple lines then you get rid of the outermost quotation marks, add the ‘>’ then jump to the next lines.

here is a reference:

https://yaml-multiline.info/

You won’t find the ‘%’ in yaml references because it’s a jinja templating character.

the {%…%} is a program statement. this is when you want the program to do something (compare, set, etc).

if you use {{…}} it is a program print (or output). it’s used when you want to return a value (get an actual result) out of a template.

here is a reference:

http://jinja.pocoo.org/docs/2.10/templates/

2 Likes

Thanks for the links and comments.
I corrected an indentation error (maybe). Config-check now reads as below.

It is expecting the block end directly after the ‘if’ word.

Reading the links, I don’t see the problem. is it the number of spaces - I ensured two for each sub-line, etc.

Should there be something that defines the ‘service_template’, located outside of the automation? If so, where (directory) should I provide that programming?

Invalid config for [automation]: invalid template (TemplateSyntaxError: expected token 'end of statement block', got 'is_state') for dictionary value @ data['action'][0]['service_template']. 
Got None. (See /config/configuration.yaml, line 18). 
Please check the docs at https://home-assistant.io/components/automation/

Sorry, just re-read the initial post.

Does anyone know where I can find definition of the above error?
I do not see the syntax error. I can copy out of a thread that reports the code is correct, and I still get this error.

Invalid template

You said you had fixed your indentation, but you have not posted your current code.

The code for the above error is

- alias: p1_control
  trigger:
    platform: state
    entity_id: switch.sonoff2
  action:
    service_template: >
      {% if is_state('switch.sonoff2', 'on') %}
        switch.turn_on
      {% else is_state('switch.sonoff2', 'off') %}
        switch.turn_off
      {% endif %}
      entity_id: switch.sonoff

I also tried this code

- alias: p1_control
  trigger:
    platform: mqtt
    entity_id: stat/DVES_5A97C3_fb/power2
  action:
    service_template: >
      {% if states('stat/DVES_5A97C3_fb/power2', 'on') %}
        switch.turn_on
      {% else states('stat/DVES_5A97C3_fb/power2', 'off') %}
        switch.turn_off
      {% endif %}
      entity_id: cmnd/DVES_5A97C3_fb/power1

and got this error, but am thinking the switch.turn_on/off should be an mqtt message of some sort.

Invalid config for [automation]: [entity_id] is an invalid option for [automation]. 
Check: automation->trigger->0->entity_id. (See /config/configuration.yaml, line 18). 
Please check the docs at https://home-assistant.io/components/automation/

My config yaml file is still the default that was created when installing hass.io, and is as follows:


# Configure a default setup of Home Assistant (frontend, api, etc)
default_config:

# Example configuration.yaml entry
#mqtt:
#  discovery: true
#  discovery_prefix: homeassistant

# Uncomment this if you are using SSL/TLS, running in Docker container, etc.
# http:
#   base_url: example.duckdns.org:8123

# Text to speech
tts:
  - platform: google_translate

group: !include groups.yaml
automation: !include automations.yaml
script: !include scripts.yaml

try this (notice the different indentation level of the last “entity_id” line):

- alias: p1_control
  trigger:
    platform: state
    entity_id: switch.sonoff2
  action:
    service_template: >
      {% if is_state('switch.sonoff2', 'on') %}
        switch.turn_on
      {% else is_state('switch.sonoff2', 'off') %}
        switch.turn_off
      {% endif %}
    entity_id: switch.sonoff

Normally, without a template and only one service in the action section you woud write the acrtion section like this:

action:
  service: some_service
  entity_id: some_entity

In that case the indentation level for the service and entity_id is the same.

If you have more than one service call in the action then you have to turn the services into a list:

action:
  - service: some_service
    entity_id: some_entity
  - service: some_other_service
    entity_id: some_othr_entity

Then in those cases the entity_id is indented one more level below the service call.

In your case the indentation level is like the first one above even tho your service call is on multiple lines.

If you try the code all the way above it should work (hopefully…).

One switch controlling the state of another switch:

- alias: p1_control
  trigger:
    platform: state
    entity_id: switch.sonoff2
  action:
    service_template: 'switch.turn_{{trigger.to_state.state}}'
    entity_id: switch.sonoff

finity:
Thanks. This did not work. It gave the same error. I would think a template has to be defined prior to use, but maybe for this, the word template is just telling hass.io that the codes lines following follow their own format?

So I was able to get the below to work.
I can toggle the sonoff2 from the sonoff’s control page, but the automation does not actuate. I assume this means the trigger is not working.
I can hit the trigger button on the hass.io UI and turn the switch on. However, it turns on no matter what the state of sonoff2. The code block below, I think, would only turn on sonoff if sonoff is on also. So something is wrong there.

- alias: p1_control
  trigger:
    platform: state
    entity_id: switch.sonoff2
  action:
    service_template: >
      {% if is_state('switch.sonoff2', 'on') %}
        switch.turn_on
      {% endif %}
      entity_id: switch.sonoff

If i put in the else statement, then I get the same error as before. I believe I have the indenting correct. I have tried indenting differently just to see any changes.

      {% else is_state('switch.sonoff2', 'off') %}
        switch.turn_off

123 Taras:
Similar to my posting for finity, your recommendation passed the config check.
However, sonoff does not turn on when sonoff2 is on. Nor turn off, etc.
I can click the trigger button on the hass.io UI and it will turn on the sonoff, regardless of the state of sonoff2.

OK I figured out the error. I completely overlooked it the first time. The “else” statement in the template shouldn’t be looking for a true/false. It’s already being called because the first “if” statement has already decided it’s false.

Try this:

- alias: p1_control
  trigger:
    platform: state
    entity_id: switch.sonoff2
  action:
    service_template: >
      {% if is_state('switch.sonoff2', 'on') %}
        switch.turn_on
      {% else %}
        switch.turn_off
      {% endif %}
    entity_id: switch.sonoff

Also, you’re thinking of the automation wrong.

You are using the automation to control the state of switch.sonoff based on the change in state of switch.sonoff2 not the other way around.

And sonoff doesn’t care what it’s state is if it’s operated independently of sonoff2. You can turn sonoff off & on all day and will happily switch states regardless of the state of sonoff2. However, if you switch sonoff2 then sonoff will follow it’s state because it triggers the automation.

Then, I’m sorry to say, either there was a mistake made in transcribing the automation to your system or the test was flawed. I’ve used it countless times successfully and I’ve suggested it to others who have used it successfully; it does work.

Its service_template dispenses with if-else and leverages the usefulness of the trigger object:

{{trigger.to_state.state}}
  • If switch.sonoff2 changes to state on, it triggers the automation and the service_template appends on to switch.turn_ to create switch.turn_on for the entity_id switch.sonoff.
  • When switch.sonoff2 changes to state off, it calls the service switch.turn_off for switch.sonoff. Easy-peasy.
- alias: p1_control
  trigger:
    platform: state
    entity_id: switch.sonoff2
  action:
    service_template: 'switch.turn_{{trigger.to_state.state}}'
    entity_id: switch.sonoff

FWIW, what won’t work is if you attempt to trigger this automation manually (such as using the service automation.trigger via the Service page). When done this way, the trigger object is undefined and the action will fail.

123 Taras
I was able to get it to work, and with the from_state, which is what I was really after.

Have you used this in non-UI automation? I assume the answer is yes, but want to confirm, and if the coding is the same. On some other threads I am getting warning about the UI and non-UI automation being significantly different, and might decide to ditch the UI path.

Thanks for the help.

finity:
fixing the else statement got it past config check and I was able to get this code to work also. I also confirmed that the line indentation of entity_id will kill it.
Thanks for the help!!

One more question - not related to my code issues, but again, why the word ‘template’? It seems to be a misnomer. It is essentially just code. There is no predetermined pattern (template) that has to be followed. Or am I missing something?

???

That would make the second switch’s state opposite of the first switch’s state.

SW1 changes from on to off
Template using from_state creates: switch.turn_on for SW2
SW2’s state (on) is now opposite of SW1’s state (off)

SW1 changes from off to on
Template using from_state creates: switch.turn_off for SW2
SW2’s state (off) is now opposite of SW1’s state (on)

If that’s what you were really after, it wasn’t mentioned earlier. :man_shrugging:

An automation is an automation. It may affect entities that are are exposed in the Lovelace UI or it may not. It depends on what’s in the automation.

What is this alleged “warning about the UI and non-UI automation being significantly different”?


EDIT
Clarified by nickrout. You were referring to using Home Assistant’s Automation Editor vs a text editor (like Visual Studio Code, or Atom, or Notepad++ or etc).

I think he means writing automations via the gui vs writing yaml.

1 Like

In that case there’s an important missing word:

Have you used this in non-UI automation editor?

The answer would be a resounding ‘YES’ because Home Assistant’s Automation Editor has limitations.