How to make self adjusting schedule?

Hello everyone,
I’d like to make a self changing schedule. I have a bunch of terrariums. The animals living in them should wake up from hibernation slowly so I need to increase the on-hours incrementally.

I wrote down what I basically would like to do in bastardized bash script since that was the only way I could explain it:

on_time.file = 11 am
off_time.file = 1 pm

script:

if on_time.file >= 8 am and on_time.file = now and light = off; do
    light = on
    on_time.file = on_time.file-1
fi

if off_time.file <= 10 pm and off_time.file = now and light = on; do
    light = off
    off_time.file = off_time.file+1
fi

end script

Does someone have an idea or a script that does something like this? Please help and dont kill me for my bad script. :slight_smile: thanks

Create one Time Helper each for on and off times and set them for the next on/off times you want to use.

alias: 
trigger:
  - platform: time
    at: input_datetime.on_time
    id: 'on'
  - platform: time
    at: input_datetime.off_time
    id: 'off'
condition:
  - alias: Check that it has been at least 2 hours since this automation last executed 
    condition: template
    value_template: "{{ now() > this.attributes.last_triggered | default(as_datetime(0),1) + timedelta(hours = 2) }}"
action:
  - variables:
      current:  "{{ trigger.now.replace(second=0,microsecond=0) }}"
      target_time: |
        {% if trigger.id == 'off' %}
          {% set t_max = today_at('22:00') %} 
          {{ ([t_max, current + timedelta(hours=1)] | min).strftime('%H:%M:00') }}
        {% else %}
          {% set t_min = today_at('08:00') %} 
          {{ ([t_min, current - timedelta(hours=1)] | max).strftime('%H:%M:00') }}
        {% endif %}
  - service: light.turn_{{ trigger.id }}
    target:
      entity_id: light.terrarium_example
  - service: input_datetime.set_datetime
    data:
      time: "{{ target_time }}"
    target:
      entity_id: "{{ trigger.entity_id }}"          

EDIT: Corrected +/- issue mentioned below and added throttle condition

1 Like

Thank you very much! I managed to get the helpers set up and also put the script into place. Now I have two follow up questions:

  1. would “off” not have to be the one with a positive timedelta? Since “off” happens later (and slides forward in the day throughout this automation) while “on” slides backward towards 8 am?

  2. how do I make sure that off doesnt trigger every hour? (It happens the first time at 1 pm and slides forward to 10 pm so the helper gets set anew for 2pm which would be the same day, should that not be tomorrow then?)

I’m sorry I didnt think of this beforehand but its just occured to me. Could this be remedied by setting date&time and changing them by 23 and 25 hrs respectively for on and off?

Yes, I think that was a copy/paste error on my part :man_facepalming: … but while your at it you might want to think about how to determine the if it is time to do the transitions so the automation can be set up to handle the opposite behavior in the autumn.

You just need an appropriate condition.

  - alias: Check that it has been at least 2 hours since this automation last executed 
    condition: template
    value_template: "{{ now() > this.attributes.last_triggered | default(as_datetime(0),1) + timedelta(hours = 2) }}"

You would need to use Input datetime helpers with both date & time, and the template for target time would have to be changed a bit… but yes it is possible to do it that way.

1 Like

Thank you very much! This makes a lot of sense!

I’m not totally sure I know where to put this though. Does it go into the other script or is it an additional script and if so, which one should be activated and which one should not be?

I have added the condition into the automation post above so you can see where it goes.

FWIW, I think the following should cover both increasing light “on” time in spring and decreasing it in the autumn… obviously the dates and times are just placeholders.

Untested Terrarium Light Schedule Automation

I just made up dates and times, so change them to meet your needs.

alias:
variables:
  spring: "{{ today_at().replace(month=2, day=28) <= now() <= today_at().replace(month=3, day=10) }}"
  autumn: "{{ today_at().replace(month=8, day=30) <= now() <= today_at().replace(month=9, day=10) }}"
  mapper:
    on_spring: "08:00" 
    off_spring: "22:00"
    on_autumn: "12:00"
    off_autumn: "18:00"
trigger:
  - platform: time
    at: input_datetime.on_time
    id: 'on'
  - platform: time
    at: input_datetime.off_time
    id: 'off'
condition:
  - alias: Check that it has been at least 2 hours since this automation last executed 
    condition: template
    value_template: "{{ now() > this.attributes.last_triggered | default(as_datetime(0),1) + timedelta(hours = 2) }}"
action:
  - service: light.turn_{{ trigger.id }}
    target:
      entity_id: light.terrarium_EXAMPLE
  - alias: Check variables to see if it is in one of the date ranges to change the on/off times 
    condition: template
    value_template: "{{ spring or autumn }}"
  - variables:
      type_key: "{{trigger.id}}_{{'spring' if spring else 'autumn'}}"
      time_value: "{{ today_at(mapper.get(type_key)) }}"
      sign: "{{ 1 if type_key in ['off_spring', 'on_autumn'] else -1  }}"
      target_time: |
        {% set adjusted = trigger.now + timedelta(hours=(1 * sign)) %}
        {{ ([time_value, adjusted] | sort)[0 if sign < 0 else 1].strftime('%H:%M:00') }}
  - service: input_datetime.set_datetime
    data:
      time: "{{ target_time }}"
    target:
      entity_id: "{{ trigger.entity_id }}"
1 Like

This is so cool! Thank you for taking the time. In the meantime, I tested the older script. It did turn on my device but I think I might have messed something up since it didnt change the helpers. Here’s what I used:

alias: Terrarien_Winterruhe
description: Fährt die An/Aus-Zeiten der Terrarien hoch
trigger:
  - platform: time
    at: input_datetime.terrarien_an
    id: "on"
  - platform: time
    at: input_datetime.terrarien_aus
    id: "off"
condition: []
action:
  - variables:
      current: "{{ trigger.now }}"
      target_time: |
        {% if trigger.id == 'off' %}
          {% set t_max = today_at('22:00') %} 
          {{ ([t_max, current - timedelta(minutes=1)] | min).strftime('%H:%M:00') }}
        {% else %}
          {% set t_min = today_at('08:00') %} 
          {{ ([t_min, current + timedelta(minutes=1)] | max).strftime('%H:%M:00') }}
        {% endif %}
  - service: switch.turn_{{ trigger.id }}
    target:
      entity_id: switch.steckdose_kueche_switch_0
  - service: input_datetime.set_datetime
    data:
      time: "{{ target_time }}"
    target:
      entity_id: input_datetime.{{ trigger.id }}_time

It threw an error which it wont let me copy so I made a screenshot:
Screenshot_20240310_111859

What did I do wrong?

You aren’t the reason for the error… for some reason it doesn’t want to accept the current variable defined like that. It works fine if you use trigger.now in the template for target_time.

You also need to make a couple changes to the last line so your entity names get rendered correctly:

alias: Terrarien_Winterruhe
description: Fährt die An/Aus-Zeiten der Terrarien hoch
trigger:
  - platform: time
    at: input_datetime.terrarien_an
    id: "on"
  - platform: time
    at: input_datetime.terrarien_aus
    id: "off"
condition: 
  - alias: Check that it has been at least 2 hours since this automation last executed 
    condition: template
    value_template: "{{ now() > this.attributes.last_triggered | default(as_datetime(0),1) + timedelta(hours = 2) }}"
    enabled: false
action:
  - variables:
      target_time: |
        {% set current = trigger.now %}
        {% if trigger.id == 'off' %}
          {% set t_max = today_at('22:00') %} 
          {{ ([t_max, current - timedelta(minutes=1)] | min).strftime('%H:%M:00') }}
        {% else %}
          {% set t_min = today_at('08:00') %} 
          {{ ([t_min, current + timedelta(minutes=1)] | max).strftime('%H:%M:00') }}
        {% endif %}
  - service: switch.turn_{{ trigger.id }}
    target:
      entity_id: switch.steckdose_kueche_switch_0
  - service: input_datetime.set_datetime
    data:
      time: "{{ target_time }}"
    target:
      entity_id: "{{ trigger.entity_id }}"

PS Don’t forget to re-enable the throttle condition once you’ve finished testing and ironing out any issues.

1 Like

While experimenting with script variables, I discovered a script variable doesn’t preserve a datetime object’s type and is rendered as a string. That explains why the error indicates it can’t concatenate a string to a timedelta object.

2 Likes

Finally! It works! The testing equipment is switching every minute (after I changed the timedelta to +2 minutes on both and set the helpers to one minute apart).

Thank you very much for taking so much time and giving this so much effort! I’m baffled at the proficiency and dedication, especially asking my first question. :slight_smile:

Have a great day!