Service template to turn lights on high or low depending on Sunrise/Sunset offset?

I’m trying to create a way when I come home and my “Away” mode is turned off that my lights will come on automatically, but to different scenes depending on the time of day.

Ideally I’d like to set it up so the lights will turn on a “High” scene if it’s 45 minutes after Sunrise or 45 minutes before Sunset. Otherwise, I want it to turn on my low, or “Main”, scene.

What I’ve got so far is this, which (I think) is saying turn on “high” if it’s 45 mins (or 2700 seconds) before sunset, but I’m stuck on how to add in the additional piece to say between xyz offset from sunrise and abc offset from sunset.

Any guidance?

  - alias: Lights On When Away Mode Turned Off
    trigger:
      platform: state
      entity_id: switch.mech_room_away
      to: 'off'
    action:
      - service_template: >-
          {{ as_timestamp(states.sun.sun.attributes.next_setting) - as_timestamp(now()) > 2700 }}
            scene.mech_room_phantom_keypad_1_high
          {% else %}
            scene.mech_room_phantom_keypad_1_main
          {% endif %}

@tom_l, I should give you credit for what I currently have because I took it from this thread. Any advice on how to modify it to meet the criteria above would be greatly appreciated!

try this:

{{ (as_timestamp(states.sun.sun.attributes.next_setting) - as_timestamp(now())) | int > 2700  and (as_timestamp(now()) -  as_timestamp(states.sensor.sunrise.state)) | int > 2700 }}

@finity thank you! I was just trying to test it out using a few test input booleans, but I’m new to service templates so I’m getting an error in my config. Here’s what I have (under automations)…is this the right gist or am I way off base here?

  - alias: Away Mode Off Test
    trigger:
      - platform: state
        entity_id: input_boolean.awaytestswitch
        to: 'off'
    action:
      - service_template: >-
          {{ (as_timestamp(states.sun.sun.attributes.next_setting) - as_timestamp(now())) | int > 2700  and (as_timestamp(now()) -  as_timestamp(states.sensor.sunrise.state)) | int > 2700 }}
            input_boolean.turn_on
            data:
              entity_id: input_boolean.awaytestdayon
          {% else %}
            input_boolean.turn_on
            data:
              entity_id: input_boolean.awaytestnighton
          {% endif %}
- alias: Away Mode Off Test
    trigger:
      - platform: state
        entity_id: input_boolean.awaytestswitch
        to: 'off'
    action:
      - service: input_boolean.turn_on
        data_template: >
          {{ (as_timestamp(states.sun.sun.attributes.next_setting) - as_timestamp(now())) | int > 2700  and (as_timestamp(now()) -  as_timestamp(states.sensor.sunrise.state)) | int > 2700 }}
            entity_id: input_boolean.awaytestdayon
          {% else %}
            entity_id: input_boolean.awaytestnighton
          {% endif %}

the thing you are templating is the entity_id of the input boolean you want to turn on. you aren’t templating which service call you want to use because in both instances you are turning on the boolean. the difference is which boolean gets turned on.

1 Like

Ok gotcha - unfortunately I’m still getting a config error:

Invalid config for [automation]: invalid template (TemplateSyntaxError: Encountered unknown tag ‘else’.) for dictionary value @ data[‘action’][0][‘data_template’][‘entity_id’]. Got None. (See /config/configuration.yaml, line 398). Please check the docs at https://home-assistant.io/components/automation/

I also tried this variation, but same error:

  - alias: Away Mode Off Test
    trigger:
      - platform: state
        entity_id: input_boolean.awaytestswitch
        to: 'off'
    action:
      - service: input_boolean.turn_on
        data_template:
          entity_id: >
            {{ (as_timestamp(states.sun.sun.attributes.next_setting) - as_timestamp(now())) | int > 2700  and (as_timestamp(now()) -  as_timestamp(states.sensor.sunrise.state)) | int > 2700 }}
              input_boolean.awaytestdayon
            {% else %}
              input_boolean.awaytestnighton
            {% endif %}

oops, my bad I missed the {% if …at the beginning of the template.

change the action to:

action:
  - service: input_boolean.turn_on
    data_template:
      entity_id: >
        {% if (as_timestamp(states.sun.sun.attributes.next_setting) - as_timestamp(now())) | int > 2700  and (as_timestamp(now()) -  as_timestamp(states.sensor.sunrise.state)) | int > 2700 %}
          input_boolean.awaytestdayon
        {% else %}
          input_boolean.awaytestnighton
        {% endif %}

else goes better with an if

Ok that solved the config error! Thank you! Now on to the next thing: when I run the test I get the following error in the logs:

Log Details (ERROR)

Tue Oct 01 2019 19:33:25 GMT-0600 (MDT)

Error rendering data template: UndefinedError: ‘None’ has no attribute ‘state’

So the logic is stating:

  • if the time of the next sunset, less the current time, is greater than 45 minutes

  • AND the current time, less today’s sunrise time, is greater than 45 minutes,

  • THEN turn on the “day” boolean.

  • ELSE turn on the “night” boolean.

Correct?

Really appreciate your help with this!

That might be a complaint about sensor.sunrise. Its state is referenced in the template but do you have that sensor defined somewhere?

It’s located near the end of the if statement:

as_timestamp(states.sensor.sunrise.state)

Hmmm no, good point. Is there a way to grab the value of today’s sunrise from the sun entity? In “States” I can only see next_rising as an attribute.

As a hack I tried to see if I could take the “next_rising” attribute and subtract 24 hours (86400 seconds), but that didn’t seem to work either (of course I may be doing it wrong):

    action:
      - service: input_boolean.turn_on
        data_template:
          entity_id: >
            {% if (as_timestamp(states.sun.sun.attributes.next_setting) - as_timestamp(now())) | int > 2700 and (as_timestamp(now()) - as_timestamp((states.sun.sun.attributes.next_rising) - 86400)) | int > 2700 %}
              input_boolean.awaytestdayscene
            {% else %}
              input_boolean.awaytestnightscene
            {% endif %}

Again, my bad.

I forgot I’m using the enhanced sun component by @pnbruckner and I had just worked on helping someone else with a sunrise/Sunset calculation and they used that component too.

You can either install that custom component or I can help figuring out another way to do what you want. I recommend the former because it adds a lot more flexibility by providing a bunch more information.

the reason next_rising - 86400 won’t work is because as soon as it’s after sunrise for today then the attribute changes to be tomorrows sunrise and the calculation resets.

that’s the problem with the standard sun component but using phil’s component fixes that and gives you a “today’s sunrise” sensor that won’t change until “tomorrow” (probably midnight is when the reset occurs but I’m not 100% sure of that).

No worries at all, I just appreciate the help! Gotcha - all things being equal if there’s a way to do it without a custom component I’d rather do that (I just say that because in the past I’ve had trouble with custom components and updates). I did actually come up with a really inelegant solution just using an input boolean as a trigger:

  - alias: Away Daytime Boolean On
    trigger:
      - platform: sun
        event: sunrise
        offset: "00:45:00"
    action:
      service: input_boolean.turn_on
      entity_id:
        - input_boolean.daytime

  - alias: Away Daytime Boolean Off
    trigger:
      - platform: sun
        event: sunset
        offset: "-00:45:00"
    action:
      service: input_boolean.turn_off
      entity_id:
        - input_boolean.daytime
        
  - alias: Away Off Lights On Day
    trigger:
      - platform: state
        entity_id: input_boolean.awaytestswitch
        to: 'off'
    condition:
      - condition: state
        entity_id: input_boolean.daytime
        state: 'on'
    action:
      service: input_boolean.turn_on
      entity_id:
        - input_boolean.awaytestdayon

  - alias: Away Off Lights On Night
    trigger:
      - platform: state
        entity_id: input_boolean.awaytestswitch
        to: 'off'
    condition:
      - condition: state
        entity_id: input_boolean.daytime
        state: 'off'
    action:
      service: input_boolean.turn_on
      entity_id:
        - input_boolean.awaytestnighton

If there’s a way to do it cleaner than that I’d love to, but this does appear to work without the need for the custom component.

I really wouldn’t go this route.
If you want your lights to have different levels then put them into groups having the same levels for the same parts of the day.
Then when ANY light switches on the group automation sets the light to the group level for that segment of the day (so you don’t have to run any fancy checks)
The levels change throughout the day and the lights take on those new levels
Thus they become independant of each other and easier to run

there may be better ways to do it but as long as it works for you and you understand it then I think that’s the way you should do it.

As far as custom components, I don’t think you should limit yourself with a bit of a bad experience. you will potentially lose out on many functionalities that you will never get from the built-in components.

And if it’s installation/updates that are the issue then consider looking into the HACS custom component. It pretty much streamlines installation and updates and is (almost…:wink:) foolproof.

Great suggestion @finity - I hadn’t heard of HACS but I’ll definitely check it out!