I’ve been struggling for some time with turning a light on and off, with the help of an automation. After a couple of days of reading the trigger has been solved, but I’m stuck at the action part. In short the automation is made for a light/switch that turns on a car heater a specific time before departure - after departure time I want the light/switch to be turned off.
The trigger part returns “True” as it should when the light/switch is to be turned on, and “False” when the light/switch is to be turned off. What I want is for the switch to actually be turned off when the trigger reports “False”.
Some people suggest adding an extra automation to turn the light off, but imagine there has to be a better way.
Anyone have any ideas of what I could do solve this in one automation?
alias: Motorvärmare (test)
description: ''
trigger:
- platform: template
value_template: >-
{% set dtime = now().strftime("%Y-%m-%d ") %}
{% set time = now().timestamp() %}
{% set dur = states('input_number.motorvarmare_minuter') | int*60 %}
{% set motorvarmare_on = strptime(dtime +
states('input_datetime.motorvarmare_start'), '%Y-%m-%d
%H:%M:%S').timestamp() - dur %}
{% set motorvarmare_off = strptime(dtime +
states('input_datetime.motorvarmare_start'), '%Y-%m-%d
%H:%M:%S').timestamp() %}
{{ motorvarmare_on <= time <= motorvarmare_off }}
condition: []
action:
- service: light.turn_on
data: {}
entity_id: light.brytare10210
mode: single
Can you give me an example of a typical state value for input_datetime.motorvarmare_start? Is it something like 2020-12-13 10:25:12? Or is it just a time like 10:25:12?
Also, do the on and off times remain within the same day or can they span more than a single day?
That seems like a reasonable option, instead of relying on the automation trigger itself. I’m new to Home Assistant so I don’t know all the ins and outs.
As soon as I’ve put the kids to bed I’ll see if i can make it work.
As far as I understand, the function is meant to add date (from now() ) to the variable from input_datetime, which is displayed as 10:25:12, which in turn is a timestamp from 00:00:00 current day whereas now() as a timestamp calculates from 1900-01-01.
This allows me to calculate switch on time, dependant on input_datetime, from the same baseline as now() uses.
Thank you all for pointing me in the right direction. I got it to work!
It was less of a hassle than I initially thought but I would have preferred to keep it in one automation rather than using a binary_sensor too. I’m sure there’s a reasonable explanation for not having that possibility.
All that needs to be done now are some finishing touches to entity names and such.
This is my binary_sensor:
- platform: template
sensors:
motorvarmare_binary_sensor:
friendly_name: "motorvarmare_binary_sensor"
value_template: >-
{% set dtime = now().strftime("%Y-%m-%d ") %}
{% set time = now().timestamp() %}
{% set dur = states('input_number.motorvarmare_minuter') | int*60 %}
{% set motorvarmare_on = strptime(dtime + states('input_datetime.motorvarmare_start'), '%Y-%m-%d %H:%M:%S').timestamp() - dur %}
{% set motorvarmare_off = strptime(dtime + states('input_datetime.motorvarmare_start'), '%Y-%m-%d %H:%M:%S').timestamp() %}
{{ motorvarmare_on <= time <= motorvarmare_off }}
What I was leading up to is that your template is employing far more time conversions, notably via strptime, than are needed for this application. In fact, there’s no need to use it at all.
{% set t = (now().time() | string)[:5] %}
{% set s = state_attr('input_datetime.motorvarmare_start', 'timestamp') %}
{% set d = states('input_number.motorvarmare_minuter') | int * 60 %}
{% set offset = (s - d) | timestamp_custom('%H:%M', false) %}
{{ offset <= t <= states('input_datetime.motorvarmare_start') }}
First line gets the current time (as a string).
Second line gets the timestamp (as an integer) directly from the input_datetime.
Third line calculates the duration (as an integer).
Fourth line computes the offset by subtracting the duration from the timestamp then converts it to a time string.
Last line performs a string comparison to determine if the current time string lies between the other two time strings.
I started with using sensor.time, instead of now(), partly because it seemed more similiar to input_datetime and partly because I couldn’t figure out how to reduce now() to a timestamp I could work with. So I took a bit of inspiration here and a bit of inspiration there.
What does the [:5] do specifically, in the first row?
This will only work if there are no other interactions with light.brytare10210. Otherwise it will simply toggle whichever state the light is in at the time (rather than specifically shutting it off or on.)
Indeed, I misread the ‘choose’ and thought it was saying if the light was on turn it off, rather than the binary sensor. Otherwise I would have suggested exactly that.
@qoheleth I’m not sure I follow. Do you mean that the automation won’t work/trigger if the light state has been manually altered?
Edit: Never mind, I see now that you were replying to another answer.
@123 Does this mean that it wont be possible to manually change the light state, when binary_sensor and light are in sync?
In this particular case the light is a 433Mhz RFLink entity, so I’m not receiving any acknowledgement anyway. But for the sake of learning…
That “light.turn_{{ trigger.to_state.state }}” construction was exactly what I was looking for for another application. (It saves splitting the action to turn_on and turn_off).
Thanks for that.