Dynamic Automation for multiple components?

@RobDYI you are right. It got messed up when I pasted. I edited it above

Thanks a lot, guys! In the meantime, I figured out a few things and found, that it was basically my condition-part, which was wrong. So the trigger actually works.
I am not at my PC atm, but I will try your suggestions soon and report back.

Thanks again!

Alright, here is what I’ve got, this automation is working, means:

  • trigger is working (explicit window gets opened)
  • condition is working (explicit cover/blind is lower than constant value threshold)
  • actions are working (store actual position in explicit input_number component and move explicit cover to a defined position

Looks like this:

- action:
  - data_template:
      entity_id: input_number.dinning_room
      value: "{{states.cover.dinning_room.attributes.current_position | float }}"
    service: input_number.set_value
  - data:
      entity_id: cover.dinning_room
      position: '40'
    service: cover.set_cover_position
  id: '834611532639'
  alias: "Open blinds when window gets opened"
  trigger:
  - entity_id: binary_sensor.dinning_room
    from: 'off'
    platform: state
    to: 'on'
  condition:
  - condition: numeric_state
    below: 40
    entity_id: cover.dinning_room
    value_template: "{{states.cover.dinning_room.attributes.current_position | float }}"

I am relatively sure, that I can manage to get it working so that the threshold/target position can be defined by another input_number slider component. Also the counter-automation to close blinds when window gets closed shouldn’t be a problem now.

But: I couldn’t get it working the “dynamic” way, where the corresponding blinds are moved depending on the window contact that triggered the automation. for first tests, I only modified the condition to be “dynamic”. Means THIS is NOT working:

- action:
  - data_template:
      entity_id: input_number.dinning_room
      value: "{{states.cover.dinning_room.attributes.current_position | float }}"
    service: input_number.set_value
  - data:
      entity_id: cover.dinning_room
      position: '40'
    service: cover.set_cover_position
  id: '834611532639'
  alias: "Open blinds when window gets opened"
  trigger:
  - entity_id: binary_sensor.dinning_room
    from: 'off'
    platform: state
    to: 'on'
  condition:
  - condition: numeric_state
    below: 40
    entity_id: cover.dinning_room
    value_template: "{{states.cover.{{trigger.entity_id.split('.')[1]}}.attributes.current_position | float }}"

The HA log say:

Invalid config for [automation]: invalid template (TemplateSyntaxError: expected name or number) for dictionary value @ data['condition'][0]['value_template']. Got none.

Where is the problem here (except that one that is sitting in front of my computer :wink: )?

Thanks and greetings

@Jojo-A Are you using the Automation Editor? For some reason, the sequence of events is messed up. The reason I ask is, ever since it was released, I’ve seen more mixed up code on the forum and wondering what’s the reason for the sudden change. I got used to writing it manually so never bothered with the editor. Anyways, try this…it should work with the Trigger>Condition>Action sequence with proper spacing as per the documentation. This should work for you…

  - id: '834611532639'
    alias: "Open blinds when window gets opened"
    trigger:
      - platform: state
        entity_id: binary_sensor.dinning_room
        from: 'off'
        to: 'on'
    condition:
      - condition: numeric_state
        entity_id: cover.dinning_room
        value_template: "{{states.cover.{{trigger.entity_id.split('.')[1]}}.attributes.current_position | float }}"
          below: 40
    action:
      - service: input_number.set_value
        entity_id: input_number.dinning_room
        data_template:
          value: "{{states.cover.dinning_room.attributes.current_position | float }}"
      - service: cover.set_cover_position
        entity_id: cover.dinning_room
        data:
          position: 40

@Jer78
Thank you, I’ll give it a try as soon as I am back home. But why do you think your code should fix my problem? The error above seems not to be caused be wrong code order. And in your code, the syntax of the faulty part is identical to mine :thinking: .
Anyway, I’ll give it a try.

Yes, am am using the Automation editor. You are right, this thing seems to smash the code around in random order. I think the “idea” of the editor is great, but atm, it lags of fundamental things. For example you can not define the logic combination of triggers/conditions (AND, OR). Maybe I switch over to the manual automation creation. I also like to have a “clean” code style…

Greetings

Actually you are right. Numeric state condition can’t take a template. So what you’d need to do is first make a template sensor with the value_template and then use that new sensor as the numeric state condition.

Could this be a good potential candidate for a python script? You could create a dictionary that has sensor names as keys, and the corresponding heater for each value. You could then have an automation that is triggered by a state change on the sensors, and calls the python script.

@Jer78
well, actually you are not right that I am right :face_with_raised_eyebrow: . According to this page:
https://home-assistant.io/docs/scripts/conditions/ numeric_state CAN have a value_template.
I am relatively sure, that I just have syntax errors with missing/wrong brackets, quotes, double-quotes, whatever.
Also it would be interesting to know, if the proposition of @brg468 (usage of {{trigger.entity_id.split(’.’)[1]}} ) would work at all. Until now I had no chance to verify that, because the second window is not ready yet. Maybe I try that by firing the other window events manually…

@Dolores
of course this might be another solution. But actually I am still too new in this HA stuff and have no experiences in Python at all. Please understand, when I don’t want to change the actual configuration, as I am happy, that it kind of “works” as it is atm :blush:

Greetings!

After a little testing on my end it seems that {{trigger.entity_id.split(’.’)[1]}} does work, but it doesn’t seem to work inside another template, like your looking for in your example above:
{{states.cover.{{trigger.entity_id.split('.'[1]}}.attributes.current_position | float }}

I was able to make it dynamically select the entity that triggered the automation, but when I tried nesting it I was never able to make it work…Maybe somebody has an idea to try, it seems like in theory it would work but I haven’t found a way yet.

EDIT: the code below does not throw any errors, when using the UI cofiguration validation. But HA will fail to start with that!!! See two posts below.

So basically, this code does NOT work! Don’t try this at home… assistant

- id: '834611532639'
  alias: "Open blinds when window gets opened"
  trigger:
    - platform: state
      entity_id: binary_sensor.dinning_room
      from: 'off'
      to: 'on'
    - platform: state
      entity_id: binary_sensor.living_room
      from: 'off'
      to: 'on'
    - platform: state
      entity_id: binary_sensor.kitchen
      from: 'off'
      to: 'on'
  condition:
    - condition: template
      value_template: '{{ states.cover.{{trigger.entity_id.split('.')[1]}}.attributes.current_position < (states.input_number.fresh_air.state | int) }}'
  action:
    - service: input_number.set_value
      entity_id: input_number.{{trigger.entity_id.split('.')[1]}}
      data_template:
        value: "{{states.cover.{{trigger.entity_id.split('.')[1]}}.attributes.current_position | float }}"
    - service: cover.set_cover_position
      entity_id: cover.{{trigger.entity_id.split('.')[1]}}
      data_template:
        position: '{{ states.input_number.fresh_air.state | int }}'
- id: '495011554639'
  alias: "Close blinds when window gets closed"
  trigger:
    - platform: state
      entity_id: binary_sensor.dinning_room
      from: 'on'
      to: 'off'
    - platform: state
      entity_id: binary_sensor.living_room
      from: 'on'
      to: 'off'
    - platform: state
      entity_id: binary_sensor.kitchen
      from: 'on'
      to: 'off'
  condition:
    - condition: template
      value_template: '{{ states.cover.{{trigger.entity_id.split('.')[1]}}.attributes.current_position > (states.input_number.{{trigger.entity_id.split('.')[1]}}.state | int) }}'
  action:
    - service: cover.set_cover_position
      entity_id: cover.{{trigger.entity_id.split('.')[1]}}
      data_template:
        position: '{{ states.input_number.{{trigger.entity_id.split('.')[1]}}.state | int }}'

I tested that by firing the state change events of the different binary sensors through the HA UI. Result: the corresponding automations got triggered every time, but only when the event of the window “dinning_room” arrived (which is the one that has a physical motor) it moved as it should :slight_smile: .
Come over here and grab a beer :beers: .

@brg468
this is strange. For me, it worked. Maybe you can compare your config to mine?
EDIT: you are right, it does not work… :frowning:

Greetings!

2 Likes

@Jojo-A AWESOME! Good job!!

Oh sorry guys, bad news:
it does still not work. I only thought it would work, because when I checked the code with the validating feature in the UI, it told me to be “Valid!”, but when I restart HA it fails :rage: . Dammit…
I’ll edit the post above accordingly.

So when I restart HA, it fails with the message:

ERROR (Thread-2) [homeassistant.util.yaml] while parsing a block mapping in "/home/homeassistant/.homeassistant/automations.yaml", line 89, column 7
expected <block end>, but found '<scalar>' in "/home/homeassistant/.homeassistant/automations.yaml", line 90, column 67

When I now replace all nested {{trigger.entity_id.split(’.’)[1]}} with just dinning_room, HA starts, but it throws a lot of errors regarding automation:

2017-12-14 14:04:01 ERROR (MainThread) [homeassistant.config] Invalid config for [automation]: Entity ID input_number.{{trigger.entity_id.split('.')[1]}} is an invalid entity id for dictionary value @ data['action'][0]['entity_id']. Got None
invalid template (TemplateSyntaxError: expected name or number) for dictionary value @ data['action'][0]['data_template']['value']. Got None. (See /home/homeassistant/.homeassistant/configuration.yaml, line 156). Please check the docs at https://home-assistant.io/components/automation/
2017-12-14 14:04:01 ERROR (MainThread) [homeassistant.config] Invalid config for [automation]: Entity ID cover.{{trigger.entity_id.split('.')[1]}} is an invalid entity id for dictionary value @ data['action'][0]['entity_id']. Got None. (See /home/homeassistant/.homeassistant/configuration.yaml, line 156). Please check the docs at https://home-assistant.io/components/automation/

This is actually bad, because it seems to me as if this nice idea does just not work in general :frowning: .

I also tried to use another component (input_text and template_sensor) as some kind of “buffer” for the trigger entity, that I don’t need to use nested templates. But this fails, too, with similar errors (“no valid entity_id” or so). If someone likes to investigate that with me, this would be welcome, of course.

I don’t know, if it is useful to let the idea of @brg468 marked as the solution. Sure, it extracts the name of the entity that triggerd the automation. But in the end, I was not able to use this for my problem. What do you think?

Until now I have tried A LOT of things, nothing worked as I hoped it would. So for now, I’ll give up and figure out another solution.

Thank you guys anyway. The beers are still here for you :wink: .

Greetings

Sorry it didn’t end up working. I hadn’t used anything quite like that before so it was kinda a shot in the dark that seemed to make sense. I tried to find another way to set it up that didn’t directly involve nesting the two templates, like using a variable to represent that part, but it always ended up with the same issue. I’m sure there’s a solution but it’s probably a bit more involved unfortunately.

@Jojo-A Don’t give up. There’s always other ways around this. Maybe move the entity_id underneath the data_template. Which line exactly is HA balking at? It says line 89, 90, can you paste which ones those are?

Worst case scenario you’ll have to make an automation per window. In my experience, everything eventually works, some just take a lot more effort and time than others.

No reason to be sorry, dude! I highly appreciate, that you shared your idea. And indeed, on the first glace it looked really charming and promising :slight_smile: . It’s not your fault that I couldn’t get it working. But I think I should remove the “Solution” mark, as it didn’t work in the end. Others should not take the same pain as me :wink: .

@Jer78
No, we never give up. Of course, there are other solutions, we just don’t know them, yet. I just give up this particular approach.
I think as a first step, I’ll have to create individual automations for each window. Worst case (which will be if I don’t learn/understand enough about templating) would be, that I have to create three automations per window, so 27 automations in total… Best case would be to have only one automation per window, if I am able to set up a proper template.

In pseudocode I like to do:

if(window got opened)
{
    set the heating to "lower"
    if(cover is below "threshold")
    {
        save actual cover position
        move cover up to "threshold"
    }
}
else    // if window got closed
{
    set the heating to "auto"
    if(cover is higher than previously saved position)
    {
        move cover back down to previously saved position
    }
}

So my main challenge will be to write a template with nested conditions. I don’t ask you to present me a solution for that, as I have not tried it by myself, yet. So I gonne try this by myself until I fail epically and then I came back to ask. But this will be topic for another thread :slight_smile: .

Greetings!

@Dolores
are you familar with python programming? I’ve thought much about your suggestion and I think I will give it a shot. I’d appreciate, if you coud take a look at my very first python script to see if it has a chance to work. Syntax errors are expected :wink:

The automation is now just:

- id: '303427509327'
  alias: "Call window automation script"
  trigger:
    - platform: state
      entity_id: binary_sensor.dinning_room
    - platform: state
      entity_id: binary_sensor.living_room
    - platform: state
      entity_id: binary_sensor.kitchen
    (... six more triggers here... )
  action:
    - service: python_script.window_automation
      data:
        entity_id: '{{ trigger.entity_id.split('.')[1] }}'
        sensor_state: '{{ trigger.to_state.state }}'

My window_automation.py contains:

sensor_state = data.get('sensor_state')
entity_id = data.get('entity_id')
current_position = hass.states.get(('cover.' + entity_id).attributes.current_position)
saved_position = (hass.states.get(('input_number.' + entity_id).state) | int)
fresh_air_position = (hass.states.get('input_number.fresh_air').state) | int)

# Window got opened, do the following
# - set heating to "lower"
# - save current cover position
# - open cover until "fresh air"-position is reached
if sensor_state == 'on':
	hass.services.call('climate', 'set_operation_mode', { 'entity_id': ('climate.' + entity_id), 'operation_mode': 'lowering'})
	if current_position < fresh_air_position:
		hass.services.call('input_number', 'set_value', { 'entity_id': ('input_number.' + entity_id), 'value': (current_position | float) })
		hass.services.call('cover', 'set_cover_position', {'entity_id': ('cover.' + entity_id), 'position': fresh_air_position })

# Window got closed, do the following
# - set heating to "auto"
# - move cover back to previous position
elif sensor_state == 'off':
	hass.services.call('climate', 'set_operation_mode', { 'entity_id': ('climate.' + entity_id), 'operation_mode': 'auto'})
	if current_position > saved_position:
		hass.services.call('cover', 'set_cover_position', {'entity_id': ('cover.' + entity_id), 'position': saved_position })

Thanks and greetings!

I must confess… to being a horrible person. :grin: I have very little python experience, having only created two apps, and never having created a python script!

You can shorten your trigger by just having one triggering, with a list of entity_id’s. Not that this will make much of a difference!

@Dolores
Oh, thats sad :frowning: . Anyway, I have posted this question into the “Scripts” section. Hopefully someone there knows better.
I already made first tests. But when the automation gets triggered, nothing happens. So I expect there are bugs in the script, but I don’t know how to debug that, because I don’t even see error messages.

From what I do know, instead of doing your fancy templating for service calls, I would define a python dictionary that converts from sensors to heaters.

https://www.python-course.eu/dictionaries.php

Ok guys,

I think I got it solved now. I followed the suggestion of @Dolores and wrote a short python script.

With this little piece of code, I only need one single automation, that will be triggered if any of my windows is opened OR closed. The rest is handled by the script.

This is the automation:

- id: '303427509327'
  alias: "Window contact covers/heating"
  trigger:
    - platform: state
      entity_id: binary_sensor.dinning_room
    - platform: state
      entity_id: binary_sensor.living_room
    - platform: state
      entity_id: binary_sensor.kitchen
    # ...many more triggers here...
  action:
    - service: python_script.window_automation
      data_template:
        entity_id: '{{ trigger.entity_id }}'
        sensor_state: '{{ trigger.to_state.state }}'

The script code:

sensor_state = data.get('sensor_state')
entity_id = data.get('entity_id')
entity_id = entity_id.split('.')[1]
current_position = hass.states.get('cover.' + entity_id).attributes['current_position']
saved_position = hass.states.get('input_number.' + entity_id).state
fresh_air_position = hass.states.get('input_number.fresh_air').state

# Window got opened, do the following
# - set heating to "lower"
# - save current cover position
# - open cover until "fresh air"-position is reached
if sensor_state == 'on':
	hass.services.call('climate', 'set_operation_mode', { 'entity_id': ('climate.' + entity_id), 'operation_mode': 'lowering'})
	if float(current_position) < float(fresh_air_position):
		hass.services.call('input_number', 'set_value', { 'entity_id': ('input_number.' + entity_id), 'value': float(current_position) })
		hass.services.call('cover', 'set_cover_position', {'entity_id': ('cover.' + entity_id), 'position': int(float(fresh_air_position)) })

# Window got closed, do the following
# - set heating to "auto"
# - move cover back to previous position
elif sensor_state == 'off':
	hass.services.call('climate', 'set_operation_mode', { 'entity_id': ('climate.' + entity_id), 'operation_mode': 'auto'})
	if float(current_position) > float(saved_position):
		hass.services.call('cover', 'set_cover_position', {'entity_id': ('cover.' + entity_id), 'position': int(float(saved_position)) })

This is my very first python script, so there is surely room for improvements :wink: .

During the debugging process of that script, I faced very similar errors as before when I tried to do that as templates in my automation directly. Most of these errors were just type conversion errors (especially this one “int(float(xyz))” drove my crazy…). So I THINK it should be possible to solve this inside a template with correct conversions as well. Maybe someone likes to give it another shot…

Thanks for your help!

Jojo

2 Likes