First Off, what I have works, it just looks like a dogs’ breakfast : - ((((
I’ve tried inumerable ways to get the final data_template onto multiple lines : -
if True
– Do This
elif True
– Do That
else
– Do Other stuff
endif
But no joy.
So I’m posting this here so that someone can point out where I’m being stupid AND so that others can at least take what I have and adapt it to their onw transient states.
The code ‘should’ be self explanatory with input_number’s and input_datetime used so that you can configure stuff from the frontend.
Anyway, its taken from a package (which I could post the 3 packages involved if needed) : -
script:
#script to set 'between' statuses, e.g. darkslot, timeofday for lighting etc.
sc_ha_gen_reboot:
alias: Re-Boot Check
sequence:
- service_template: >
{% if (states.sun.sun.attributes.elevation <= states('input_number.in_light_flood_on_elev_offset') | float and not states.sun.sun.attributes.rising or states.sun.sun.attributes.elevation <= states('input_number.in_light_flood_off_elev_offset') | float and states.sun.sun.attributes.rising) %}
input_boolean.turn_on
{% else %}
input_boolean.turn_off
{% endif %}
#data_template:
entity_id: input_boolean.ib_global_darkslot
- service: input_select.select_option
data_template:
entity_id: input_select.is_aalight_segment
option: "{% if ((states.sun.sun.attributes.elevation > states('input_number.in_aalight_day') | float) and (states.sun.sun.attributes.rising)) or ((states.sun.sun.attributes.elevation > states('input_number.in_aalight_evening') | float) and not (states.sun.sun.attributes.rising)) %}Day{% elif ((states.sun.sun.attributes.elevation < states('input_number.in_aalight_evening') | float) and not (states.sun.sun.attributes.rising)) and (states('sensor.time') < states('input_datetime.id_aalight_night')) %}Evening{% else %}Night{% endif %}"
Another thing I’ve noticed is that without the spurious ‘comment’ in the first service, the entity_id seems to become part of the template when using notepad+
No big rush, as it does work : - ))) and it’s more for my curiosity and leaning
Cheers
Taras,
Thanks for your reply, I read it in the coffee shop, was sure I had tried that … but as inaccuracy often offends (especially me !) I decided to wait till I got back home to check.
It Passes the configuration check without any quibble, but it does not set the input_select.
So nope, I noticed that the Template editor returns Day rather than ‘Day’ or “Day” so I fiddled with it to get those outputs … still no joy. It won’t set the input_select. : - (((((
Thanks anyway (proves I’m not a TOTAL moron (though my wife has doubts)
Your original goal was to get the template on ‘multiple lines’ and, given that it passes the config check, it has been achieved. The fact it doesn’t set the input_select is an entirely separate challenge.
Firstly, the general structure of what I suggested is valid. It most certainly can set an input_select. Here’s a simple example (if somewhat contrived) of setting an input_select. I’ve tested it and it works.
Try this automation. You’ll need to either create input_boolean.toggler or use some other one you already have. Toggling the inpout_boolean will toggle the input_select between Day and Night.
- alias: 'input_select test'
trigger:
platform: state
entity_id: input_boolean.toggler
action:
service: input_select.select_option
data_template:
entity_id: input_select.is_aalight_segment
option: >
{% if trigger.to_state.state == 'on' %}
Day
{% else %}
Night
{% endif %}
Sorry Tara’s, what am I testing ?
I currently have 3 segments of the day and 4 groups of lights, all with their own light levels depending on segment.
When the segment changes, the level for that group changes and each light (if on) sets to the new level. Any new light switched on comes on at the current group level.
Why would I swap that for just two levels ?
I admit that your code looks clean and probably works (I can test in the morning) but I’m not clear on the why.
Do you think if we can get it working bi-state, we can then move on to Tri-state ?
Regards
Mutt
You’re carrying out an experiment. The goal is to confirm that this simple automation, containing a template for option, can successfully set the input_select.
If it succeeds, we can circle back to your original automation and try to determine why it failed to set the input_select.
Okay,
Some interesting results …
First I used your example in an automation : -
- alias: 'input_select test'
trigger:
platform: state
entity_id: input_boolean.ib_global_test
action:
- service: input_select.select_option
data_template:
entity_id: input_select.is_aalight_segment
option: >
{% if trigger.to_state.state == 'on' %}
Day
{% else %}
Night
{% endif %}
And it works, set the select to ‘evening’ then hit the bit and depending on where you left the bit before setting evening it will toggle to Day or Night or just flip with the bit as expected.
So I move the code to a Script (same code, just triggered manually via exceute)
sc_ha_gen_test:
alias: Test Script
sequence:
- service: input_select.select_option
data_template:
entity_id: input_select.is_aalight_segment
option: >
{% if trigger.to_state.state == 'on' %}
Day
{% else %}
Night
{% endif %}
BOTH passed config check, but the script, with the exact same code does NOT work, execute all day long (no matter the position of the bit), the select will stay where it was, no matter where it starts.
So it seems to be down to the fact that it’s a script and ‘may’ have a different indenting requirement or something ???
At first glance, I don’t see anything wrong with the script … so I’ll have to experiment with it to learn if there’s some sort of limitation.
EDIT
On second glance, I do see something wrong with it. It contains a reference to the trigger object:
trigger.to_state.state
There’s no trigger in a script. The first test in the template always fails. That’s why when you manually executed the script it did not toggle the input_select’s state.
You’ve confirmed that it’s possible to set the input_select’s state. That means, in the original script, there must be something wrong with the template’s tests. Those long-winded ‘if this and that or the other thing’ may not be behaving the way you think.
I’ve re-written it using variables in order to make the tests more legible. Review it to ensure the logic is correct.
- service: input_select.select_option
data_template:
entity_id: input_select.is_aalight_segment
option: >
{% set elev = state_attr('sun.sun', 'elevation') | float %}
{% set rising = state_attr('sun.sun', 'rising') %}
{% set day = states('input_number.in_aalight_day') | float %}
{% set day = states('input_number.in_aalight_evening') | float %}
{% if (elev > day and rising) or (elev > evening and not rising) %}
Day
{% elif (elevation < evening and not rising) and (states('sensor.time') < states('input_datetime.id_aalight_night')) %}
Evening
{% else %}
Night
{% endif %}
Are you sure the test using sensor.time and input_datetime is correct? You’re not comparing two integers or floats but strings containing the time. In addition, both have hours and minutes but one also includes seconds.
As my ‘jinja’ skills improve, due mainly to the patience of 123, pnbruckner and petros.
I have managed to solve this issue.
Basically I have 3 ‘states’ that change during the day based on different conditions.
Lighting levels based on both elevation of the sun (different on ‘sunrise’ (…ish) to ‘sunset’ (…ish) and given time spots, all adjusted through the UI. (3 periods : - Day, Evening, Night
Bathroom/Ventilation Fan Slot (also used as sounder/notification permissive) just based on time. Again, all adjusted through the UI
Outside Light Enable (floods, porch and patio) this based soley on sun elevation (but again different on ‘sunrise’ (…ish) to ‘sunset’ (…ish)
This is fine and dandy if you never restart, but if you do … how do you know where you are ?
So, my Idea was to write a script that would be triggered on a restart and use the exact same criteria to set the status of these ‘segments’. The idea being to allow it to be extended (as required) for other items and allow it’s use by others with similar needs.
Here is the final script, please note that ‘some’ of the ‘#’ comments are REALLY close to the left margin, this was generally required to force the jinja interpretter to see them as comments and not just a mangling of the template.
script:
#script to set 'between' statuses, e.g. darkslot, timeofday for lighting etc.
sc_ha_gen_reboot:
alias: Re-Boot Check Status Script
sequence:
### set the 'on-slot' permissive for : - floodlights, patio & porch lights
- service_template: >
{% if (state_attr('sun.sun', 'elevation') <= states('input_number.in_light_flood_on_elev_offset') | float and not state_attr('sun.sun', 'rising')
or state_attr('sun.sun', 'elevation') <= states('input_number.in_light_flood_off_elev_offset') | float and state_attr('sun.sun', 'rising')) %}
input_boolean.turn_on
{% else %}
input_boolean.turn_off
{% endif %}
# end of template: but entitty_id follows
entity_id: input_boolean.ib_global_darkslot
### set the light level segment of the day
- service: input_select.select_option
data_template:
entity_id: input_select.is_aalight_segment
option: >
{% if (state_attr('sun.sun', 'elevation') > states('input_number.in_aalight_day') | float and state_attr('sun.sun', 'rising'))
or (state_attr('sun.sun', 'elevation') > states('input_number.in_aalight_evening') | float and not state_attr('sun.sun', 'rising')) %}
Day
{% elif (state_attr('sun.sun', 'elevation') > states('input_number.in_aalight_evening') | float and not state_attr('sun.sun', 'rising'))
and (states('sensor.time') < states('input_datetime.id_aalight_night') [0:5]) %}
Evening
{% else %}
Night
{% endif %}
### set the fan/noise permissive bit
- service_template: >
{% if (states('input_datetime.id_fans_allowed_on') [0:5] < states('sensor.time') < states('input_datetime.id_fans_forced_off') [0:5]) %}
input_boolean.turn_on
{% else %}
input_boolean.turn_off
{% endif %}
# end of template: but entitty_id follows (this is also used as a 'noise permissive' for sirens
entity_id: input_boolean.ib_fan_permissive
It’s pretty complete and extensively tested, but if anyone can break it or improve on it, I would be happy to help tweek it. And also help others adapt it to their needs.
Cheers
Mutt
Personally, I’d probably go a different route only because I don’t like giving people options to directly change states. Any kind of user input can be overridden by the user and I don’t like them mucking it up. So i’d create template binary sensors and sensors with that information. You don’t even need to update on startup because the sensors will update every minute.
I’d also take @123’s approach to make it easier to read.
binary_sensor:
- platform: template
sensors:
ib_global_darkslot:
entity_id: sensor.time
value_template: >
{% set elevation = state_attr('sun.sun', 'elevation') | float %}
{% set rising = state_attr('sun.sun', 'rising') %}
{% set flood = states('input_number.in_light_flood_on_elev_offset') | float %}
{{ (elevation <= flood and not rising) or (elevation <= flood and rising) }}
id_fans_allowed_on:
value_template: >
{% set fan_on = states('input_datetime.id_fans_allowed_on')[0:5] %}
{% set fan_off = states('input_datetime.id_fans_forced_off')[0:5] %}
{{ fan_on < states('sensor.time') < fan_off }}
sensor:
- platform: template
sensors:
is_aalight_segment:
value_template: >
{% set elevation = state_attr('sun.sun', 'elevation') | float %}
{% set day = states('input_number.in_aalight_day') | float %}
{% set rising = state_attr('sun.sun', 'rising') %}
{% set evening = states('input_number.in_aalight_evening') | float %}
{% set evening_time = states('input_datetime.id_aalight_night')[0:5] %}
{% set time = states('sensor.time') %}
{% if (elevation > day and rising) or (elevation > evening and not rising) %}
Day
{% elif (elevation > evening and not rising) and (time < evening_time) %}
Evening
{% else %}
Night
{% endif %}
EDIT: Then base your automations off the sensor, and binary sensors.
I’ve read a LOT of ‘template examples’ on the forum and the ones I’ve found most relevant/interesting to me (I’ve skipped others because their efforts were not linked to digging in the same holes as I have underway) were yourself Teras and Phil. So that’s where I gave the credit.
Next week somebody else will be my superhero ! ; - ))))))))))
I like the approach, and the explanation. I’ll look into this.
I was thinking about changing my uptime to minutes but was worried that I’d overrun the sensor, with changes to my config going on like this, I’ll NEVER get to 22 days, 18 hrs, 7 mins (or whatever the limit is).
It’s all ‘grist for the mill’ and once again, I thank you
Cheers
@123 , @petro ,
I’ve noticed that during building and testing, it’s very useful to be able to flip variables around ‘A LOT’ to see how this behaves when interacting with an array of ‘inputs’.
I’ve also noticed that as they become more stable, I (historically) have moved them into ‘sensors’.
This was not a concious process, just something that happened.
You have made the case and I’ve made the association.
It is a LOT easier to test an automation or script (just hit reload) rather that having to wait for a restart (especially if any of it is z-wave network dependant.
I think I’ll move them over, after a little more testing and a re-write. (more to make sure “I” understand whats going on).
Cheers