Code Review: Turning lights off/on at sunset/runrise

I have the following working automations for turning lights OFF and sunset and ON and sunrise. I’d like to see the ways I can improve this. The main thing I’m looking to improve right now is the fact that I have to repeat “-5” in four different places. It would be nice to have something like a global variable I can set -5 to, and then reference that variable in all the places that need it, so that as I make adjustments to this I don’t need to make so many repetitive changes.

Also the two automations are similar enough that I wonder if I can reasonably combine the two into one somehow.

Lastly, I added the home assistant start & automation reload triggers because I want to see the lights turn on if those situations happen. On restart is certainly important (in case HASS had been down for a number of hours), the automation reload I’m not sure if I need or not.

- alias: "Front Lights: Turn on at sunset"
  id: 32028da4-5fa8-42e5-aac9-16948d6d8617
  trigger:
    - platform: numeric_state
      entity_id: sun.sun
      attribute: elevation
      below: -5.0
    - platform: homeassistant
      event: start
    - platform: event
      event_type: automation_reloaded
  condition:
    - condition: template
      value_template: "{{ state_attr('sun.sun', 'elevation') < -5 }}"
  action:
    - service: homeassistant.turn_on
      entity_id: group.outside_lights

- alias: "Front Lights: Turn off at sunrise"
  id: 8fe79782-9036-4e46-aba7-9b0aa5816ef7
  trigger:
    - platform: numeric_state
      entity_id: sun.sun
      attribute: elevation
      above: -5.0
    - platform: homeassistant
      event: start
    - platform: event
      event_type: automation_reloaded
  condition:
    - condition: template
      value_template: "{{ state_attr('sun.sun', 'elevation') > -5 }}"
  action:
    - service: homeassistant.turn_off
      entity_id: group.outside_lights

In what ways can I clean this up?

Try this:


alias: "Front Lights: Turn on or off at sunset or sunrise"
description: ""
trigger:
  - platform: numeric_state
    entity_id: sun.sun
    attribute: elevation
    below: -5
  - platform: numeric_state
    entity_id: sun.sun
    attribute: elevation
    above: -5
  - platform: homeassistant
    event: start
  - platform: event
    event_type: automation_reloaded
condition: []
action:
  - service: >-
      homeassistant.turn_{{ iif(state_attr('sun.sun', 'elevation') < -5, 'on',
      'off') }}
    entity_id: group.outside_lights
2 Likes

-5 can be set as “helper” or input number and you can then use {{ input_number.elevation }} or whatever you name it in your automation.

To combine it into one you can:

  • Change your trigger to just state changes (remove above or below)
  • remove your conditions
  • use if/then in your actions to determine what should happen if above or below. (Script Syntax - Home Assistant)

That will make the automation trigger all the time and not only when it crosses the threshold (-5 in this case), so if he turns off the lights manually the system will turn on it back right after any small change at the angle (which is all the time).
But if that is the desired effect (it will turn on/off when restart or when reload the automations anyways) then you’re right, it will be even cleaner.

How exactly do you specify a helper or input number? Can you show a YAML example?

Unless you want to have a card in your dashboard to select this threshold, I wouldn’t use a helper for this.
If your goal is just to reduce the points of maintenance in your c8de you should consider using Blueprints.

Have you ever looked at blueprints?

Templating and/or Variables

Example with Variable and Template triggers
alias: "Front Lights: Turn on or off at sunset or sunrise"
description: ""
variables:
  ele_value: -5
trigger:
  - platform: template
    value_template: "{{ state_attr('sun.sun', 'elevation') | float(0) < ele_value }}"
  - platform: template
    value_template: "{{ state_attr('sun.sun', 'elevation') | float(0) > ele_value }}"
  - platform: homeassistant
    event: start
  - platform: event
    event_type: automation_reloaded
condition: []
action:
  - service: >-
      homeassistant.turn_{{ iif(state_attr('sun.sun', 'elevation') < ele_value, 'on',
      'off') }}
    entity_id: group.outside_lights

You can also use templating to define your variable based on an input number helper which can be modified from the frontend.

Above example using Input number Helper
alias: "Front Lights: Turn on or off at sunset or sunrise"
description: ""
variables:
  ele_threshold: "{{ states('input_number.sun_elevation_threshold') | float(0) }}"
trigger:
  - platform: template
    value_template: "{{ state_attr('sun.sun', 'elevation') | float(0) < ele_threshold }}"
  - platform: template
    value_template: "{{ state_attr('sun.sun', 'elevation') | float(0) > ele_threshold }}"
  - platform: homeassistant
    event: start
  - platform: event
    event_type: automation_reloaded
condition: []
action:
  - service: >-
      homeassistant.turn_{{ iif(state_attr('sun.sun', 'elevation') < ele_value, 'on',
      'off') }}
    entity_id: group.outside_lights
1 Like

I cannot test the code right now, but it would be something like this:

Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

blueprint:
  domain: automation
  name: Turn lights on or off at sunset or sunrise
  description: This automatioj will turn lights on or off whe  the Sun crossed an elevation threshold.
  source_url: https://community.home-assistant.io/t/code-review-turning-lights-off-on-at-sunset-runrise/473105/8
  input:
    light_entities:
      name: Lights
      description: Please select the lights or switches you want to toggle when the Suj crosses the threshold.
      default: [ ]
      selector:
        entity:
          multiple: true
          domain: [light, switch, group]
  
    sun_threshold:
      name: Sun threshold
      description: Select the Sun angle where the lights will toggle.
      default: -5
      selector:
        number:
          min: -90
          max: 90
          step: 0.1
          mode: slider
          unit_of_measurement: °

    sun_entity: # It's good to ask for this entity as some user might have changed from sun.sun.
      name: Sun entity
      description: 'Typically is ''sun.sun'' (which can be added with the Sun integration).'
      default: 'sun.sun'
      selector:
        entity:
          multiple: false
          domain: [sun]

mode: single

trigger:
  - platform: numeric_state
    entity_id: !input sun_entity
    attribute: elevation
    below: !input sun_threshold
  - platform: numeric_state
    entity_id: !input sun_entity
    attribute: elevation
    above: !input sun_threshold
  - platform: homeassistant
    event: start
  - platform: event
    event_type: automation_reloaded
condition: []

variables:
  sun_threshold: !input sun_threshold
  sun_entity: !input sun_entity

action:
  - service: >-
      homeassistant.turn_{{ iif(state_attr(sun_entity, 'elevation') < sun_threshold, 'on',
      'off') }}
    entity_id: !input light_entities

By the way, I noticed you are using the old group mode to group your lights. Try to create a group helper (Settings > Device & Services > Helpers). Personally, I like more, as the group behaves just like a normal light entity and it’s almost transparent to the system, making easier to use it.
It would create a new light entity, like light.outside_lights and you will be able to use in light.turn_on service, etc.

1 Like

The advantage of the legacy groups is that they can include entities from multiple domains without having to also set up proxy light entities using Template lights or Switch as X.

1 Like

That’s right.

Great examples! I would like to share some more triggers which I use for my switch with sun elevation-based automation:

  • when switch returns from unavailable state after power failure
  • when input number helper value is changed (if used)
My automation using input number helper:
alias: "Turn on/off at sunset or sunrise"
description: ""
trigger:
  - platform: numeric_state
    entity_id: sun.sun
    attribute: elevation
    above: input_number.sun_elevation
  - platform: numeric_state
    entity_id: sun.sun
    below: input_number.sun_elevation
    attribute: elevation
  - platform: homeassistant
    event: start
  - platform: event
    event_type: automation_reloaded
  - platform: state
    entity_id:
      - switch.plug_01
    from: unavailable
  - platform: state
    entity_id:
      - input_number.sun_elevation
condition:
  - condition: not
    conditions:
      - condition: state
        entity_id: switch.plug_01
        state: unavailable
action:
  - if:
      - condition: numeric_state
        entity_id: sun.sun
        below: input_number.sun_elevation
        attribute: elevation
    then:
      - service: homeassistant.turn_on
        data: {}
        target:
          entity_id: switch.plug_01
    else:
      - service: homeassistant.turn_off
        data: {}
        target:
          entity_id: switch.plug_01