1246 lines
50 KiB
YAML
1246 lines
50 KiB
YAML
###############################################################################
|
|
# PACKAGE: Outdoor lighting controls
|
|
###############################################################################
|
|
#
|
|
# Version:
|
|
# 2026-07-20 v0.3
|
|
# - Synchronized the documented Number 16 schedule with the implementation.
|
|
#
|
|
# 2026-05-09 v0.2
|
|
# - Refactored scheduled control to use editable schedule lists.
|
|
# - Switched lights now use explicit ON/OFF schedule entries instead of
|
|
# ON plus duration.
|
|
# - Added dimmer schedule event tracking so long ramps are not restarted by
|
|
# the 5 minute scheduler.
|
|
# - Added manual-on start tracking for switched lights so scheduled events
|
|
# can override a temporary manual-on period.
|
|
#
|
|
# 2026-05-09 v0.1
|
|
# - Initial package for outdoor switched and dimmable lighting.
|
|
#
|
|
# Notes:
|
|
# - Edit schedules inside the per-light reconcile/apply scripts below.
|
|
# - The schedule rows are deliberately near the top of each script.
|
|
# - Dimmable schedule format:
|
|
# trigger: sunset, offset_minutes, target_brightness, ramp_minutes
|
|
# trigger: time, at, target_brightness, ramp_minutes
|
|
# - Switched schedule format:
|
|
# trigger: sunset, offset_minutes, target_state
|
|
# trigger: time, at, target_state
|
|
# - For dimmable schedules, fixed time entries override sun based entries if
|
|
# the real sunset offset would occur after the following fixed time.
|
|
# - The scheduler runs every 5 minutes. Dimming ramps also step every 5 minutes
|
|
# by default.
|
|
# - Manual-off suppression lasts until the next day's first scheduled ON.
|
|
#
|
|
###############################################################################
|
|
|
|
input_boolean:
|
|
outdoor_lighting_automation_enable:
|
|
name: Outdoor Lighting Automation - Master Enable
|
|
icon: mdi:outdoor-lamp
|
|
initial: true
|
|
|
|
outdoor_lighting_deck_coloured_automation_enable:
|
|
name: Outdoor Lighting Automation - Deck Coloured Lights
|
|
icon: mdi:string-lights
|
|
initial: true
|
|
|
|
outdoor_lighting_patio_automation_enable:
|
|
name: Outdoor Lighting Automation - Patio Lights
|
|
icon: mdi:coach-lamp
|
|
initial: true
|
|
|
|
outdoor_lighting_number_16_automation_enable:
|
|
name: Outdoor Lighting Automation - View Road Number 16
|
|
icon: mdi:numeric-16-box
|
|
initial: true
|
|
|
|
outdoor_lighting_main_entrance_automation_enable:
|
|
name: Outdoor Lighting Automation - Main Entrance Outside LEDs
|
|
icon: mdi:led-strip-variant
|
|
initial: true
|
|
|
|
input_datetime:
|
|
outdoor_lighting_deck_suppress_until:
|
|
name: Outdoor Lighting Deck Suppress Until
|
|
has_date: true
|
|
has_time: true
|
|
|
|
outdoor_lighting_deck_manual_on_started:
|
|
name: Outdoor Lighting Deck Manual On Started
|
|
has_date: true
|
|
has_time: true
|
|
|
|
outdoor_lighting_patio_suppress_until:
|
|
name: Outdoor Lighting Patio Suppress Until
|
|
has_date: true
|
|
has_time: true
|
|
|
|
outdoor_lighting_patio_manual_on_started:
|
|
name: Outdoor Lighting Patio Manual On Started
|
|
has_date: true
|
|
has_time: true
|
|
|
|
outdoor_lighting_number_16_last_schedule_event:
|
|
name: Outdoor Lighting Number 16 Last Schedule Event
|
|
has_date: true
|
|
has_time: true
|
|
|
|
outdoor_lighting_main_entrance_suppress_until:
|
|
name: Outdoor Lighting Main Entrance Suppress Until
|
|
has_date: true
|
|
has_time: true
|
|
|
|
outdoor_lighting_main_entrance_last_schedule_event:
|
|
name: Outdoor Lighting Main Entrance Last Schedule Event
|
|
has_date: true
|
|
has_time: true
|
|
|
|
outdoor_lighting_main_entrance_last_override_press:
|
|
name: Outdoor Lighting Main Entrance Last Override Press
|
|
has_date: true
|
|
has_time: true
|
|
|
|
input_select:
|
|
outdoor_lighting_main_entrance_override_mode:
|
|
name: Outdoor Lighting Main Entrance Override Mode
|
|
options:
|
|
- none
|
|
- return_to_schedule
|
|
- turn_off
|
|
initial: none
|
|
icon: mdi:gesture-tap-button
|
|
|
|
timer:
|
|
outdoor_lighting_deck_manual_on:
|
|
name: Outdoor Lighting Deck Manual On Timer
|
|
duration: "01:00:00"
|
|
|
|
outdoor_lighting_patio_manual_on:
|
|
name: Outdoor Lighting Patio Manual On Timer
|
|
duration: "01:00:00"
|
|
|
|
outdoor_lighting_main_entrance_override:
|
|
name: Outdoor Lighting Main Entrance Override Timer
|
|
duration: "01:00:00"
|
|
|
|
script:
|
|
#############################################################################
|
|
# Shared dimmable ramp scripts
|
|
#############################################################################
|
|
|
|
outdoor_lighting_ramp_number_16:
|
|
alias: Outdoor Lighting - Ramp View Road Number 16
|
|
mode: restart
|
|
fields:
|
|
target_brightness:
|
|
description: Target brightness from 0 to 100. Zero means off.
|
|
ramp_seconds:
|
|
description: Ramp duration in seconds.
|
|
sequence:
|
|
- variables:
|
|
brightness_entity: number.front_entranceway_led_light_controls_number_16_led_light_brightness
|
|
switch_entity: switch.front_entranceway_led_light_controls_number_16_led_light
|
|
ramp_update_seconds: 300
|
|
target: >
|
|
{% set raw = target_brightness | int(0) %}
|
|
{{ [[raw, 0] | max, 100] | min }}
|
|
ramp_s: "{{ ramp_seconds | int(0) }}"
|
|
current: >
|
|
{% if is_state(switch_entity, 'on') %}
|
|
{{ states(brightness_entity) | float(0) }}
|
|
{% else %}
|
|
0
|
|
{% endif %}
|
|
raw_steps: >
|
|
{% if ramp_s | int(0) <= 0 %}
|
|
0
|
|
{% else %}
|
|
{{ ((ramp_s | int(0)) / (ramp_update_seconds | int(300))) | round(0, 'ceil') | int }}
|
|
{% endif %}
|
|
steps: >
|
|
{% if ramp_s | int(0) <= 0 %}
|
|
1
|
|
{% else %}
|
|
{{ (raw_steps | int(0)) + 1 }}
|
|
{% endif %}
|
|
step_delay_seconds: >
|
|
{% if (steps | int(1)) <= 1 %}
|
|
0
|
|
{% else %}
|
|
{{ ((ramp_s | int(0)) / ((steps | int(1)) - 1)) | round(0, 'ceil') | int }}
|
|
{% endif %}
|
|
|
|
- repeat:
|
|
count: "{{ steps | int(1) }}"
|
|
sequence:
|
|
- variables:
|
|
next_value: >
|
|
{% set val = (current | float(0)) + (((target | float(0)) - (current | float(0))) * (repeat.index | int) / (steps | int(1))) %}
|
|
{{ [[val | round(0) | int, 0] | max, 100] | min }}
|
|
|
|
- action: number.set_value
|
|
target:
|
|
entity_id: number.front_entranceway_led_light_controls_number_16_led_light_brightness
|
|
data:
|
|
value: "{{ next_value | int(0) }}"
|
|
|
|
- if:
|
|
- condition: template
|
|
value_template: "{{ (target | int(0)) > 0 and is_state('switch.front_entranceway_led_light_controls_number_16_led_light', 'off') }}"
|
|
then:
|
|
- action: switch.turn_on
|
|
target:
|
|
entity_id: switch.front_entranceway_led_light_controls_number_16_led_light
|
|
|
|
- if:
|
|
- condition: template
|
|
value_template: "{{ repeat.index < (steps | int(1)) }}"
|
|
then:
|
|
- delay:
|
|
seconds: "{{ step_delay_seconds | int(0) }}"
|
|
|
|
- if:
|
|
- condition: template
|
|
value_template: "{{ (target | int(0)) <= 0 }}"
|
|
then:
|
|
- action: switch.turn_off
|
|
target:
|
|
entity_id: switch.front_entranceway_led_light_controls_number_16_led_light
|
|
|
|
outdoor_lighting_ramp_main_entrance:
|
|
alias: Outdoor Lighting - Ramp Main Entrance Outside LEDs
|
|
mode: restart
|
|
fields:
|
|
target_brightness:
|
|
description: Target brightness from 0 to 100. Zero means off.
|
|
ramp_seconds:
|
|
description: Ramp duration in seconds.
|
|
sequence:
|
|
- variables:
|
|
brightness_entity: number.front_entranceway_led_light_controls_main_entrance_outside_led_lights_brightness
|
|
switch_entity: switch.front_entranceway_led_light_controls_main_entrance_outside_led_lights
|
|
ramp_update_seconds: 300
|
|
target: >
|
|
{% set raw = target_brightness | int(0) %}
|
|
{{ [[raw, 0] | max, 100] | min }}
|
|
ramp_s: "{{ ramp_seconds | int(0) }}"
|
|
current: >
|
|
{% if is_state(switch_entity, 'on') %}
|
|
{{ states(brightness_entity) | float(0) }}
|
|
{% else %}
|
|
0
|
|
{% endif %}
|
|
raw_steps: >
|
|
{% if ramp_s | int(0) <= 0 %}
|
|
0
|
|
{% else %}
|
|
{{ ((ramp_s | int(0)) / (ramp_update_seconds | int(300))) | round(0, 'ceil') | int }}
|
|
{% endif %}
|
|
steps: >
|
|
{% if ramp_s | int(0) <= 0 %}
|
|
1
|
|
{% else %}
|
|
{{ (raw_steps | int(0)) + 1 }}
|
|
{% endif %}
|
|
step_delay_seconds: >
|
|
{% if (steps | int(1)) <= 1 %}
|
|
0
|
|
{% else %}
|
|
{{ ((ramp_s | int(0)) / ((steps | int(1)) - 1)) | round(0, 'ceil') | int }}
|
|
{% endif %}
|
|
|
|
- repeat:
|
|
count: "{{ steps | int(1) }}"
|
|
sequence:
|
|
- variables:
|
|
next_value: >
|
|
{% set val = (current | float(0)) + (((target | float(0)) - (current | float(0))) * (repeat.index | int) / (steps | int(1))) %}
|
|
{{ [[val | round(0) | int, 0] | max, 100] | min }}
|
|
|
|
- action: number.set_value
|
|
target:
|
|
entity_id: number.front_entranceway_led_light_controls_main_entrance_outside_led_lights_brightness
|
|
data:
|
|
value: "{{ next_value | int(0) }}"
|
|
|
|
- if:
|
|
- condition: template
|
|
value_template: "{{ (target | int(0)) > 0 and is_state('switch.front_entranceway_led_light_controls_main_entrance_outside_led_lights', 'off') }}"
|
|
then:
|
|
- action: switch.turn_on
|
|
target:
|
|
entity_id: switch.front_entranceway_led_light_controls_main_entrance_outside_led_lights
|
|
|
|
- if:
|
|
- condition: template
|
|
value_template: "{{ repeat.index < (steps | int(1)) }}"
|
|
then:
|
|
- delay:
|
|
seconds: "{{ step_delay_seconds | int(0) }}"
|
|
|
|
- if:
|
|
- condition: template
|
|
value_template: "{{ (target | int(0)) <= 0 }}"
|
|
then:
|
|
- action: switch.turn_off
|
|
target:
|
|
entity_id: switch.front_entranceway_led_light_controls_main_entrance_outside_led_lights
|
|
|
|
#############################################################################
|
|
# 1) Outdoor Deck Coloured Lights
|
|
# Switch: switch.esp_downstloungeoutside_relay_1_outside_lights
|
|
# Override: binary_sensor.esp_downstloungeoutside_button_1_outside_lights
|
|
#############################################################################
|
|
|
|
outdoor_lighting_reconcile_deck_coloured:
|
|
alias: Outdoor Lighting - Reconcile Deck Coloured Lights
|
|
mode: restart
|
|
sequence:
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_automation_enable
|
|
state: "on"
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_deck_coloured_automation_enable
|
|
state: "on"
|
|
|
|
###########################################################################
|
|
# EDIT SCHEDULE HERE
|
|
# Format: trigger, offset_minutes, target_state
|
|
# Current schedule:
|
|
# - sunset +60, ON
|
|
# - sunset +240, OFF
|
|
###########################################################################
|
|
- variables:
|
|
schedule:
|
|
- trigger: sunset
|
|
offset_minutes: 60
|
|
target_state: "on"
|
|
- trigger: sunset
|
|
offset_minutes: 240
|
|
target_state: "off"
|
|
|
|
- variables:
|
|
selected_schedule: >
|
|
{% set now_ts = as_timestamp(now()) %}
|
|
{% set next_setting_raw = state_attr('sun.sun', 'next_setting') %}
|
|
{% if next_setting_raw %}
|
|
{% set next_setting = as_datetime(next_setting_raw) | as_local %}
|
|
{% if next_setting.date() == now().date() %}
|
|
{% set today_sunset = next_setting %}
|
|
{% else %}
|
|
{% set today_sunset = next_setting - timedelta(days=1) %}
|
|
{% endif %}
|
|
{% else %}
|
|
{% set today_sunset = none %}
|
|
{% endif %}
|
|
{% set ns = namespace(best_ts=0, best_state='off') %}
|
|
{% for day_offset in [-1, 0] %}
|
|
{% for item in schedule %}
|
|
{% if item.trigger == 'sunset' and today_sunset %}
|
|
{% set event_dt = today_sunset + timedelta(days=day_offset) + timedelta(minutes=item.offset_minutes | int(0)) %}
|
|
{% elif item.trigger == 'time' %}
|
|
{% set event_dt = today_at(item.at) + timedelta(days=day_offset) %}
|
|
{% else %}
|
|
{% set event_dt = none %}
|
|
{% endif %}
|
|
{% if event_dt %}
|
|
{% set event_ts = as_timestamp(event_dt, 0) %}
|
|
{% if event_ts <= now_ts and event_ts > ns.best_ts %}
|
|
{% set ns.best_ts = event_ts %}
|
|
{% set ns.best_state = item.target_state %}
|
|
{% endif %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% endfor %}
|
|
{{ ns.best_state }}|{{ ns.best_ts | int(0) }}
|
|
selected_target_state: "{{ selected_schedule.split('|')[0] }}"
|
|
selected_event_ts: "{{ selected_schedule.split('|')[1] | int(0) }}"
|
|
suppress_active: >
|
|
{% set ts = as_timestamp(states('input_datetime.outdoor_lighting_deck_suppress_until'), 0) %}
|
|
{{ ts > as_timestamp(now()) }}
|
|
manual_on_active: "{{ is_state('timer.outdoor_lighting_deck_manual_on', 'active') }}"
|
|
manual_on_started_ts: "{{ as_timestamp(states('input_datetime.outdoor_lighting_deck_manual_on_started'), 0) }}"
|
|
manual_on_still_valid: >
|
|
{{ manual_on_active | bool and (selected_event_ts | int(0)) <= (manual_on_started_ts | int(0)) }}
|
|
should_be_on: >
|
|
{% if suppress_active | bool %}
|
|
false
|
|
{% elif manual_on_still_valid | bool %}
|
|
true
|
|
{% else %}
|
|
{{ selected_target_state == 'on' }}
|
|
{% endif %}
|
|
schedule_has_overridden_manual: >
|
|
{{ manual_on_active | bool and not (manual_on_still_valid | bool) }}
|
|
|
|
- if:
|
|
- condition: template
|
|
value_template: "{{ schedule_has_overridden_manual | bool }}"
|
|
then:
|
|
- action: timer.cancel
|
|
target:
|
|
entity_id: timer.outdoor_lighting_deck_manual_on
|
|
|
|
- choose:
|
|
- conditions:
|
|
- condition: template
|
|
value_template: "{{ should_be_on | bool }}"
|
|
sequence:
|
|
- action: switch.turn_on
|
|
target:
|
|
entity_id: switch.esp_downstloungeoutside_relay_1_outside_lights
|
|
default:
|
|
- action: switch.turn_off
|
|
target:
|
|
entity_id: switch.esp_downstloungeoutside_relay_1_outside_lights
|
|
|
|
#############################################################################
|
|
# 2) Patio Lights
|
|
# Switch: switch.esp_garageentrylights_relay_2_patio_lights
|
|
# Override: binary_sensor.esp_garageentrylights_button_2_patio_lights
|
|
#############################################################################
|
|
|
|
outdoor_lighting_reconcile_patio:
|
|
alias: Outdoor Lighting - Reconcile Patio Lights
|
|
mode: restart
|
|
sequence:
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_automation_enable
|
|
state: "on"
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_patio_automation_enable
|
|
state: "on"
|
|
|
|
###########################################################################
|
|
# EDIT SCHEDULE HERE
|
|
# Format: trigger, offset_minutes, target_state
|
|
# Current schedule:
|
|
# - sunset -30, ON
|
|
# - sunset +150, OFF
|
|
###########################################################################
|
|
- variables:
|
|
schedule:
|
|
- trigger: sunset
|
|
offset_minutes: -30
|
|
target_state: "on"
|
|
- trigger: sunset
|
|
offset_minutes: 150
|
|
target_state: "off"
|
|
|
|
- variables:
|
|
selected_schedule: >
|
|
{% set now_ts = as_timestamp(now()) %}
|
|
{% set next_setting_raw = state_attr('sun.sun', 'next_setting') %}
|
|
{% if next_setting_raw %}
|
|
{% set next_setting = as_datetime(next_setting_raw) | as_local %}
|
|
{% if next_setting.date() == now().date() %}
|
|
{% set today_sunset = next_setting %}
|
|
{% else %}
|
|
{% set today_sunset = next_setting - timedelta(days=1) %}
|
|
{% endif %}
|
|
{% else %}
|
|
{% set today_sunset = none %}
|
|
{% endif %}
|
|
{% set ns = namespace(best_ts=0, best_state='off') %}
|
|
{% for day_offset in [-1, 0] %}
|
|
{% for item in schedule %}
|
|
{% if item.trigger == 'sunset' and today_sunset %}
|
|
{% set event_dt = today_sunset + timedelta(days=day_offset) + timedelta(minutes=item.offset_minutes | int(0)) %}
|
|
{% elif item.trigger == 'time' %}
|
|
{% set event_dt = today_at(item.at) + timedelta(days=day_offset) %}
|
|
{% else %}
|
|
{% set event_dt = none %}
|
|
{% endif %}
|
|
{% if event_dt %}
|
|
{% set event_ts = as_timestamp(event_dt, 0) %}
|
|
{% if event_ts <= now_ts and event_ts > ns.best_ts %}
|
|
{% set ns.best_ts = event_ts %}
|
|
{% set ns.best_state = item.target_state %}
|
|
{% endif %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% endfor %}
|
|
{{ ns.best_state }}|{{ ns.best_ts | int(0) }}
|
|
selected_target_state: "{{ selected_schedule.split('|')[0] }}"
|
|
selected_event_ts: "{{ selected_schedule.split('|')[1] | int(0) }}"
|
|
suppress_active: >
|
|
{% set ts = as_timestamp(states('input_datetime.outdoor_lighting_patio_suppress_until'), 0) %}
|
|
{{ ts > as_timestamp(now()) }}
|
|
manual_on_active: "{{ is_state('timer.outdoor_lighting_patio_manual_on', 'active') }}"
|
|
manual_on_started_ts: "{{ as_timestamp(states('input_datetime.outdoor_lighting_patio_manual_on_started'), 0) }}"
|
|
manual_on_still_valid: >
|
|
{{ manual_on_active | bool and (selected_event_ts | int(0)) <= (manual_on_started_ts | int(0)) }}
|
|
should_be_on: >
|
|
{% if suppress_active | bool %}
|
|
false
|
|
{% elif manual_on_still_valid | bool %}
|
|
true
|
|
{% else %}
|
|
{{ selected_target_state == 'on' }}
|
|
{% endif %}
|
|
schedule_has_overridden_manual: >
|
|
{{ manual_on_active | bool and not (manual_on_still_valid | bool) }}
|
|
|
|
- if:
|
|
- condition: template
|
|
value_template: "{{ schedule_has_overridden_manual | bool }}"
|
|
then:
|
|
- action: timer.cancel
|
|
target:
|
|
entity_id: timer.outdoor_lighting_patio_manual_on
|
|
|
|
- choose:
|
|
- conditions:
|
|
- condition: template
|
|
value_template: "{{ should_be_on | bool }}"
|
|
sequence:
|
|
- action: switch.turn_on
|
|
target:
|
|
entity_id: switch.esp_garageentrylights_relay_2_patio_lights
|
|
default:
|
|
- action: switch.turn_off
|
|
target:
|
|
entity_id: switch.esp_garageentrylights_relay_2_patio_lights
|
|
|
|
#############################################################################
|
|
# 3) View Road Street Number 16
|
|
# Brightness: number.front_entranceway_led_light_controls_number_16_led_light_brightness
|
|
# Switch: switch.front_entranceway_led_light_controls_number_16_led_light
|
|
#############################################################################
|
|
|
|
outdoor_lighting_apply_number_16_current_target:
|
|
alias: Outdoor Lighting - Apply Current Target - View Road Number 16
|
|
mode: restart
|
|
fields:
|
|
force_reconcile:
|
|
description: Force immediate reconciliation even if the schedule event has already been applied.
|
|
ramp_seconds:
|
|
description: Optional ramp seconds override. Use -1 or omit to use the schedule ramp.
|
|
sequence:
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_automation_enable
|
|
state: "on"
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_number_16_automation_enable
|
|
state: "on"
|
|
|
|
###########################################################################
|
|
# EDIT SCHEDULE HERE
|
|
# Format: trigger, offset_minutes/at, target_brightness, ramp_minutes
|
|
# Current schedule:
|
|
# - sunset -30, 60, 30
|
|
# - 20:00, 50, 120
|
|
# - 01:00, 20, 120
|
|
# - 06:00, 0, 120
|
|
###########################################################################
|
|
- variables:
|
|
schedule:
|
|
- trigger: sunset
|
|
offset_minutes: -30
|
|
target_brightness: 60
|
|
ramp_minutes: 30
|
|
- trigger: time
|
|
at: "20:00:00"
|
|
target_brightness: 50
|
|
ramp_minutes: 120
|
|
- trigger: time
|
|
at: "01:00:00"
|
|
target_brightness: 20
|
|
ramp_minutes: 120
|
|
- trigger: time
|
|
at: "06:00:00"
|
|
target_brightness: 0
|
|
ramp_minutes: 120
|
|
|
|
- variables:
|
|
selected_schedule: >
|
|
{% set now_ts = as_timestamp(now()) %}
|
|
{% set next_setting_raw = state_attr('sun.sun', 'next_setting') %}
|
|
{% if next_setting_raw %}
|
|
{% set next_setting = as_datetime(next_setting_raw) | as_local %}
|
|
{% if next_setting.date() == now().date() %}
|
|
{% set today_sunset = next_setting %}
|
|
{% else %}
|
|
{% set today_sunset = next_setting - timedelta(days=1) %}
|
|
{% endif %}
|
|
{% else %}
|
|
{% set today_sunset = none %}
|
|
{% endif %}
|
|
{% set ns = namespace(best_ts=0, best_target=0, best_ramp=0) %}
|
|
{% for day_offset in [-1, 0] %}
|
|
{% for item in schedule %}
|
|
{% if item.trigger == 'sunset' and today_sunset %}
|
|
{% set event_dt = today_sunset + timedelta(days=day_offset) + timedelta(minutes=item.offset_minutes | int(0)) %}
|
|
{% elif item.trigger == 'time' %}
|
|
{% set event_dt = today_at(item.at) + timedelta(days=day_offset) %}
|
|
{% else %}
|
|
{% set event_dt = none %}
|
|
{% endif %}
|
|
{% if event_dt %}
|
|
{% set valid = namespace(ok=true) %}
|
|
{% if item.trigger == 'sunset' %}
|
|
{% set idx = loop.index0 %}
|
|
{% set nxt = namespace(found=false, dt=none) %}
|
|
{% for step in range(1, schedule | length) %}
|
|
{% set j = (idx + step) % (schedule | length) %}
|
|
{% set next_item = schedule[j] %}
|
|
{% if not nxt.found and next_item.trigger == 'time' %}
|
|
{% set next_dt = today_at(next_item.at) + timedelta(days=day_offset) %}
|
|
{% if next_dt <= event_dt %}
|
|
{% set next_dt = next_dt + timedelta(days=1) %}
|
|
{% endif %}
|
|
{% set nxt.dt = next_dt %}
|
|
{% set nxt.found = true %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% if nxt.found and event_dt >= nxt.dt %}
|
|
{% set valid.ok = false %}
|
|
{% endif %}
|
|
{% endif %}
|
|
{% set event_ts = as_timestamp(event_dt, 0) %}
|
|
{% if valid.ok and event_ts <= now_ts and event_ts > ns.best_ts %}
|
|
{% set ns.best_ts = event_ts %}
|
|
{% set ns.best_target = item.target_brightness | int(0) %}
|
|
{% set ns.best_ramp = (item.ramp_minutes | int(0) * 60) %}
|
|
{% endif %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% endfor %}
|
|
{{ ns.best_target }}|{{ ns.best_ramp }}|{{ ns.best_ts | int(0) }}
|
|
selected_target: "{{ selected_schedule.split('|')[0] | int(0) }}"
|
|
selected_ramp_seconds: "{{ selected_schedule.split('|')[1] | int(0) }}"
|
|
selected_event_ts: "{{ selected_schedule.split('|')[2] | int(0) }}"
|
|
last_event_ts: "{{ as_timestamp(states('input_datetime.outdoor_lighting_number_16_last_schedule_event'), 0) | int(0) }}"
|
|
do_force: "{{ force_reconcile | default(false) | bool }}"
|
|
requested_ramp_seconds: "{{ ramp_seconds | default(-1) | int(-1) }}"
|
|
ramp_to_use: >
|
|
{% if requested_ramp_seconds | int(-1) >= 0 %}
|
|
{{ requested_ramp_seconds | int(0) }}
|
|
{% elif do_force | bool %}
|
|
0
|
|
{% else %}
|
|
{{ selected_ramp_seconds | int(0) }}
|
|
{% endif %}
|
|
should_apply: >
|
|
{{ do_force | bool or (selected_event_ts | int(0)) != (last_event_ts | int(0)) }}
|
|
|
|
- if:
|
|
- condition: template
|
|
value_template: "{{ should_apply | bool }}"
|
|
then:
|
|
- action: input_datetime.set_datetime
|
|
target:
|
|
entity_id: input_datetime.outdoor_lighting_number_16_last_schedule_event
|
|
data:
|
|
datetime: "{{ (selected_event_ts | int(0)) | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }}"
|
|
- action: script.outdoor_lighting_ramp_number_16
|
|
data:
|
|
target_brightness: "{{ selected_target | int(0) }}"
|
|
ramp_seconds: "{{ ramp_to_use | int(0) }}"
|
|
|
|
#############################################################################
|
|
# 4) Main Entrance Outside LED Lights
|
|
# Brightness: number.front_entranceway_led_light_controls_main_entrance_outside_led_lights_brightness
|
|
# Switch: switch.front_entranceway_led_light_controls_main_entrance_outside_led_lights
|
|
# Override: binary_sensor.esp_entrancelightswitch_button_2_external_light_controller
|
|
#############################################################################
|
|
|
|
outdoor_lighting_apply_main_entrance_current_target:
|
|
alias: Outdoor Lighting - Apply Current Target - Main Entrance Outside LEDs
|
|
mode: restart
|
|
fields:
|
|
force_reconcile:
|
|
description: Force immediate reconciliation even if the schedule event has already been applied.
|
|
ramp_seconds:
|
|
description: Optional ramp seconds override. Use -1 or omit to use the schedule ramp.
|
|
sequence:
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_automation_enable
|
|
state: "on"
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_main_entrance_automation_enable
|
|
state: "on"
|
|
- condition: state
|
|
entity_id: input_select.outdoor_lighting_main_entrance_override_mode
|
|
state: "none"
|
|
|
|
###########################################################################
|
|
# EDIT SCHEDULE HERE
|
|
# Format: trigger, offset_minutes/at, target_brightness, ramp_minutes
|
|
# Current schedule:
|
|
# - sunset -30, 30, 30
|
|
# - 20:00, 20, 30
|
|
# - 23:00, 0, 30
|
|
###########################################################################
|
|
- variables:
|
|
schedule:
|
|
- trigger: sunset
|
|
offset_minutes: -30
|
|
target_brightness: 30
|
|
ramp_minutes: 30
|
|
- trigger: time
|
|
at: "20:00:00"
|
|
target_brightness: 20
|
|
ramp_minutes: 30
|
|
- trigger: time
|
|
at: "23:00:00"
|
|
target_brightness: 0
|
|
ramp_minutes: 30
|
|
|
|
- variables:
|
|
suppress_active: >
|
|
{% set ts = as_timestamp(states('input_datetime.outdoor_lighting_main_entrance_suppress_until'), 0) %}
|
|
{{ ts > as_timestamp(now()) }}
|
|
selected_schedule: >
|
|
{% set now_ts = as_timestamp(now()) %}
|
|
{% set next_setting_raw = state_attr('sun.sun', 'next_setting') %}
|
|
{% if next_setting_raw %}
|
|
{% set next_setting = as_datetime(next_setting_raw) | as_local %}
|
|
{% if next_setting.date() == now().date() %}
|
|
{% set today_sunset = next_setting %}
|
|
{% else %}
|
|
{% set today_sunset = next_setting - timedelta(days=1) %}
|
|
{% endif %}
|
|
{% else %}
|
|
{% set today_sunset = none %}
|
|
{% endif %}
|
|
{% set ns = namespace(best_ts=0, best_target=0, best_ramp=0) %}
|
|
{% for day_offset in [-1, 0] %}
|
|
{% for item in schedule %}
|
|
{% if item.trigger == 'sunset' and today_sunset %}
|
|
{% set event_dt = today_sunset + timedelta(days=day_offset) + timedelta(minutes=item.offset_minutes | int(0)) %}
|
|
{% elif item.trigger == 'time' %}
|
|
{% set event_dt = today_at(item.at) + timedelta(days=day_offset) %}
|
|
{% else %}
|
|
{% set event_dt = none %}
|
|
{% endif %}
|
|
{% if event_dt %}
|
|
{% set valid = namespace(ok=true) %}
|
|
{% if item.trigger == 'sunset' %}
|
|
{% set idx = loop.index0 %}
|
|
{% set nxt = namespace(found=false, dt=none) %}
|
|
{% for step in range(1, schedule | length) %}
|
|
{% set j = (idx + step) % (schedule | length) %}
|
|
{% set next_item = schedule[j] %}
|
|
{% if not nxt.found and next_item.trigger == 'time' %}
|
|
{% set next_dt = today_at(next_item.at) + timedelta(days=day_offset) %}
|
|
{% if next_dt <= event_dt %}
|
|
{% set next_dt = next_dt + timedelta(days=1) %}
|
|
{% endif %}
|
|
{% set nxt.dt = next_dt %}
|
|
{% set nxt.found = true %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% if nxt.found and event_dt >= nxt.dt %}
|
|
{% set valid.ok = false %}
|
|
{% endif %}
|
|
{% endif %}
|
|
{% set event_ts = as_timestamp(event_dt, 0) %}
|
|
{% if valid.ok and event_ts <= now_ts and event_ts > ns.best_ts %}
|
|
{% set ns.best_ts = event_ts %}
|
|
{% set ns.best_target = item.target_brightness | int(0) %}
|
|
{% set ns.best_ramp = (item.ramp_minutes | int(0) * 60) %}
|
|
{% endif %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% endfor %}
|
|
{{ ns.best_target }}|{{ ns.best_ramp }}|{{ ns.best_ts | int(0) }}
|
|
selected_target: >
|
|
{% if suppress_active | bool %}
|
|
0
|
|
{% else %}
|
|
{{ selected_schedule.split('|')[0] | int(0) }}
|
|
{% endif %}
|
|
selected_ramp_seconds: "{{ selected_schedule.split('|')[1] | int(0) }}"
|
|
selected_event_ts: "{{ selected_schedule.split('|')[2] | int(0) }}"
|
|
last_event_ts: "{{ as_timestamp(states('input_datetime.outdoor_lighting_main_entrance_last_schedule_event'), 0) | int(0) }}"
|
|
do_force: "{{ force_reconcile | default(false) | bool }}"
|
|
requested_ramp_seconds: "{{ ramp_seconds | default(-1) | int(-1) }}"
|
|
ramp_to_use: >
|
|
{% if requested_ramp_seconds | int(-1) >= 0 %}
|
|
{{ requested_ramp_seconds | int(0) }}
|
|
{% elif do_force | bool %}
|
|
0
|
|
{% else %}
|
|
{{ selected_ramp_seconds | int(0) }}
|
|
{% endif %}
|
|
ramp_script_active: "{{ is_state('script.outdoor_lighting_ramp_main_entrance', 'on') }}"
|
|
should_apply: >
|
|
{% if suppress_active | bool and ramp_script_active | bool %}
|
|
false
|
|
{% else %}
|
|
{{ do_force | bool or suppress_active | bool or (selected_event_ts | int(0)) != (last_event_ts | int(0)) }}
|
|
{% endif %}
|
|
|
|
- if:
|
|
- condition: template
|
|
value_template: "{{ should_apply | bool }}"
|
|
then:
|
|
- if:
|
|
- condition: template
|
|
value_template: "{{ not (suppress_active | bool) }}"
|
|
then:
|
|
- action: input_datetime.set_datetime
|
|
target:
|
|
entity_id: input_datetime.outdoor_lighting_main_entrance_last_schedule_event
|
|
data:
|
|
datetime: "{{ (selected_event_ts | int(0)) | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }}"
|
|
- action: script.outdoor_lighting_ramp_main_entrance
|
|
data:
|
|
target_brightness: "{{ selected_target | int(0) }}"
|
|
ramp_seconds: "{{ ramp_to_use | int(0) }}"
|
|
|
|
#############################################################################
|
|
# Reconcile all
|
|
#############################################################################
|
|
|
|
outdoor_lighting_reconcile_all:
|
|
alias: Outdoor Lighting - Reconcile All Outdoor Lights
|
|
mode: restart
|
|
fields:
|
|
force_reconcile:
|
|
description: Force dimmable lights to reconcile immediately.
|
|
sequence:
|
|
- action: script.outdoor_lighting_reconcile_deck_coloured
|
|
- action: script.outdoor_lighting_reconcile_patio
|
|
- action: script.outdoor_lighting_apply_number_16_current_target
|
|
data:
|
|
force_reconcile: "{{ force_reconcile | default(false) | bool }}"
|
|
ramp_seconds: >
|
|
{% if force_reconcile | default(false) | bool %}
|
|
0
|
|
{% else %}
|
|
-1
|
|
{% endif %}
|
|
- action: script.outdoor_lighting_apply_main_entrance_current_target
|
|
data:
|
|
force_reconcile: "{{ force_reconcile | default(false) | bool }}"
|
|
ramp_seconds: >
|
|
{% if force_reconcile | default(false) | bool %}
|
|
0
|
|
{% else %}
|
|
-1
|
|
{% endif %}
|
|
|
|
automation:
|
|
#############################################################################
|
|
# Startup, scheduler, and enable switch cleanup
|
|
#############################################################################
|
|
|
|
- id: outdoor_lighting_reconcile_on_start
|
|
alias: Outdoor Lighting - Reconcile On Home Assistant Start
|
|
mode: single
|
|
trigger:
|
|
- platform: homeassistant
|
|
event: start
|
|
action:
|
|
- delay: "00:00:30"
|
|
- action: input_select.select_option
|
|
target:
|
|
entity_id: input_select.outdoor_lighting_main_entrance_override_mode
|
|
data:
|
|
option: none
|
|
- action: timer.cancel
|
|
target:
|
|
entity_id:
|
|
- timer.outdoor_lighting_deck_manual_on
|
|
- timer.outdoor_lighting_patio_manual_on
|
|
- timer.outdoor_lighting_main_entrance_override
|
|
- action: script.outdoor_lighting_reconcile_all
|
|
data:
|
|
force_reconcile: true
|
|
|
|
- id: outdoor_lighting_scheduler_tick
|
|
alias: Outdoor Lighting - Scheduler Tick
|
|
mode: single
|
|
trigger:
|
|
- platform: time_pattern
|
|
minutes: "/5"
|
|
condition:
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_automation_enable
|
|
state: "on"
|
|
action:
|
|
- action: script.outdoor_lighting_reconcile_all
|
|
data:
|
|
force_reconcile: false
|
|
|
|
- id: outdoor_lighting_reconcile_when_enable_changes
|
|
alias: Outdoor Lighting - Reconcile When Automation Enable Changes
|
|
mode: queued
|
|
trigger:
|
|
- platform: state
|
|
entity_id:
|
|
- input_boolean.outdoor_lighting_automation_enable
|
|
- input_boolean.outdoor_lighting_deck_coloured_automation_enable
|
|
- input_boolean.outdoor_lighting_patio_automation_enable
|
|
- input_boolean.outdoor_lighting_number_16_automation_enable
|
|
- input_boolean.outdoor_lighting_main_entrance_automation_enable
|
|
to: "on"
|
|
action:
|
|
- action: script.outdoor_lighting_reconcile_all
|
|
data:
|
|
force_reconcile: true
|
|
|
|
- id: outdoor_lighting_cleanup_when_master_disabled
|
|
alias: Outdoor Lighting - Cleanup When Master Automation Disabled
|
|
mode: single
|
|
trigger:
|
|
- platform: state
|
|
entity_id: input_boolean.outdoor_lighting_automation_enable
|
|
to: "off"
|
|
action:
|
|
- action: script.turn_off
|
|
target:
|
|
entity_id:
|
|
- script.outdoor_lighting_ramp_number_16
|
|
- script.outdoor_lighting_ramp_main_entrance
|
|
- script.outdoor_lighting_apply_number_16_current_target
|
|
- script.outdoor_lighting_apply_main_entrance_current_target
|
|
- action: timer.cancel
|
|
target:
|
|
entity_id:
|
|
- timer.outdoor_lighting_deck_manual_on
|
|
- timer.outdoor_lighting_patio_manual_on
|
|
- timer.outdoor_lighting_main_entrance_override
|
|
- action: input_select.select_option
|
|
target:
|
|
entity_id: input_select.outdoor_lighting_main_entrance_override_mode
|
|
data:
|
|
option: none
|
|
|
|
#############################################################################
|
|
# Switched light override buttons
|
|
#############################################################################
|
|
|
|
- id: outdoor_lighting_deck_coloured_override_button
|
|
alias: Outdoor Lighting - Deck Coloured Lights - Override Button
|
|
mode: restart
|
|
trigger:
|
|
- platform: state
|
|
entity_id: binary_sensor.esp_downstloungeoutside_button_1_outside_lights
|
|
to: "on"
|
|
condition:
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_automation_enable
|
|
state: "on"
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_deck_coloured_automation_enable
|
|
state: "on"
|
|
action:
|
|
- variables:
|
|
was_on_at_press: "{{ is_state('switch.esp_downstloungeoutside_relay_1_outside_lights', 'on') }}"
|
|
- delay: "00:00:01"
|
|
- choose:
|
|
- conditions:
|
|
- condition: template
|
|
value_template: "{{ was_on_at_press | bool }}"
|
|
sequence:
|
|
- action: input_datetime.set_datetime
|
|
target:
|
|
entity_id: input_datetime.outdoor_lighting_deck_suppress_until
|
|
data:
|
|
datetime: >-
|
|
{%- set next_setting_raw = state_attr('sun.sun', 'next_setting') -%}
|
|
{%- set next_setting = as_datetime(next_setting_raw) | as_local -%}
|
|
{%- if next_setting.date() == now().date() -%}
|
|
{%- set today_sunset = next_setting -%}
|
|
{%- else -%}
|
|
{%- set today_sunset = next_setting - timedelta(days=1) -%}
|
|
{%- endif -%}
|
|
{{ (today_sunset + timedelta(days=1, minutes=60)).strftime('%Y-%m-%d %H:%M:%S') }}
|
|
- action: timer.cancel
|
|
target:
|
|
entity_id: timer.outdoor_lighting_deck_manual_on
|
|
- action: switch.turn_off
|
|
target:
|
|
entity_id: switch.esp_downstloungeoutside_relay_1_outside_lights
|
|
default:
|
|
- action: input_datetime.set_datetime
|
|
target:
|
|
entity_id: input_datetime.outdoor_lighting_deck_suppress_until
|
|
data:
|
|
datetime: "1970-01-01 00:00:00"
|
|
- action: input_datetime.set_datetime
|
|
target:
|
|
entity_id: input_datetime.outdoor_lighting_deck_manual_on_started
|
|
data:
|
|
datetime: "{{ now().strftime('%Y-%m-%d %H:%M:%S') }}"
|
|
- action: switch.turn_on
|
|
target:
|
|
entity_id: switch.esp_downstloungeoutside_relay_1_outside_lights
|
|
- action: timer.start
|
|
target:
|
|
entity_id: timer.outdoor_lighting_deck_manual_on
|
|
data:
|
|
duration: "01:00:00"
|
|
|
|
- id: outdoor_lighting_patio_override_button
|
|
alias: Outdoor Lighting - Patio Lights - Override Button
|
|
mode: restart
|
|
trigger:
|
|
- platform: state
|
|
entity_id: binary_sensor.esp_garageentrylights_button_2_patio_lights
|
|
to: "on"
|
|
condition:
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_automation_enable
|
|
state: "on"
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_patio_automation_enable
|
|
state: "on"
|
|
action:
|
|
- variables:
|
|
was_on_at_press: "{{ is_state('switch.esp_garageentrylights_relay_2_patio_lights', 'on') }}"
|
|
- delay: "00:00:01"
|
|
- choose:
|
|
- conditions:
|
|
- condition: template
|
|
value_template: "{{ was_on_at_press | bool }}"
|
|
sequence:
|
|
- action: input_datetime.set_datetime
|
|
target:
|
|
entity_id: input_datetime.outdoor_lighting_patio_suppress_until
|
|
data:
|
|
datetime: >-
|
|
{%- set next_setting_raw = state_attr('sun.sun', 'next_setting') -%}
|
|
{%- set next_setting = as_datetime(next_setting_raw) | as_local -%}
|
|
{%- if next_setting.date() == now().date() -%}
|
|
{%- set today_sunset = next_setting -%}
|
|
{%- else -%}
|
|
{%- set today_sunset = next_setting - timedelta(days=1) -%}
|
|
{%- endif -%}
|
|
{{ (today_sunset + timedelta(days=1, minutes=-30)).strftime('%Y-%m-%d %H:%M:%S') }}
|
|
- action: timer.cancel
|
|
target:
|
|
entity_id: timer.outdoor_lighting_patio_manual_on
|
|
- action: switch.turn_off
|
|
target:
|
|
entity_id: switch.esp_garageentrylights_relay_2_patio_lights
|
|
default:
|
|
- action: input_datetime.set_datetime
|
|
target:
|
|
entity_id: input_datetime.outdoor_lighting_patio_suppress_until
|
|
data:
|
|
datetime: "1970-01-01 00:00:00"
|
|
- action: input_datetime.set_datetime
|
|
target:
|
|
entity_id: input_datetime.outdoor_lighting_patio_manual_on_started
|
|
data:
|
|
datetime: "{{ now().strftime('%Y-%m-%d %H:%M:%S') }}"
|
|
- action: switch.turn_on
|
|
target:
|
|
entity_id: switch.esp_garageentrylights_relay_2_patio_lights
|
|
- action: timer.start
|
|
target:
|
|
entity_id: timer.outdoor_lighting_patio_manual_on
|
|
data:
|
|
duration: "01:00:00"
|
|
|
|
- id: outdoor_lighting_deck_coloured_manual_on_timer_finished
|
|
alias: Outdoor Lighting - Deck Coloured Lights - Manual On Timer Finished
|
|
mode: single
|
|
trigger:
|
|
- platform: event
|
|
event_type: timer.finished
|
|
event_data:
|
|
entity_id: timer.outdoor_lighting_deck_manual_on
|
|
action:
|
|
- action: input_datetime.set_datetime
|
|
target:
|
|
entity_id: input_datetime.outdoor_lighting_deck_manual_on_started
|
|
data:
|
|
datetime: "1970-01-01 00:00:00"
|
|
- action: script.outdoor_lighting_reconcile_deck_coloured
|
|
|
|
- id: outdoor_lighting_patio_manual_on_timer_finished
|
|
alias: Outdoor Lighting - Patio Lights - Manual On Timer Finished
|
|
mode: single
|
|
trigger:
|
|
- platform: event
|
|
event_type: timer.finished
|
|
event_data:
|
|
entity_id: timer.outdoor_lighting_patio_manual_on
|
|
action:
|
|
- action: input_datetime.set_datetime
|
|
target:
|
|
entity_id: input_datetime.outdoor_lighting_patio_manual_on_started
|
|
data:
|
|
datetime: "1970-01-01 00:00:00"
|
|
- action: script.outdoor_lighting_reconcile_patio
|
|
|
|
#############################################################################
|
|
# Main entrance dimmable override button
|
|
#############################################################################
|
|
|
|
- id: outdoor_lighting_main_entrance_override_button
|
|
alias: Outdoor Lighting - Main Entrance Outside LEDs - Override Button
|
|
mode: restart
|
|
trigger:
|
|
- platform: state
|
|
entity_id: binary_sensor.esp_entrancelightswitch_button_2_external_light_controller
|
|
to: "on"
|
|
condition:
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_automation_enable
|
|
state: "on"
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_main_entrance_automation_enable
|
|
state: "on"
|
|
action:
|
|
- variables:
|
|
override_ramp_seconds: 60
|
|
was_on_at_press: "{{ is_state('switch.front_entranceway_led_light_controls_main_entrance_outside_led_lights', 'on') }}"
|
|
|
|
- delay: "00:00:01"
|
|
|
|
- variables:
|
|
last_press_age_seconds: >
|
|
{% set last_ts = as_timestamp(states('input_datetime.outdoor_lighting_main_entrance_last_override_press'), 0) %}
|
|
{% if last_ts <= 0 %}
|
|
999999
|
|
{% else %}
|
|
{{ (as_timestamp(now()) - last_ts) | int(999999) }}
|
|
{% endif %}
|
|
|
|
- choose:
|
|
- conditions:
|
|
- condition: template
|
|
value_template: >
|
|
{{ not is_state('input_select.outdoor_lighting_main_entrance_override_mode', 'none')
|
|
and (last_press_age_seconds | int(999999)) <= 60 }}
|
|
sequence:
|
|
- action: timer.cancel
|
|
target:
|
|
entity_id: timer.outdoor_lighting_main_entrance_override
|
|
- action: input_select.select_option
|
|
target:
|
|
entity_id: input_select.outdoor_lighting_main_entrance_override_mode
|
|
data:
|
|
option: none
|
|
- action: input_datetime.set_datetime
|
|
target:
|
|
entity_id: input_datetime.outdoor_lighting_main_entrance_suppress_until
|
|
data:
|
|
datetime: >-
|
|
{%- set next_setting_raw = state_attr('sun.sun', 'next_setting') -%}
|
|
{%- set next_setting = as_datetime(next_setting_raw) | as_local -%}
|
|
{%- if next_setting.date() == now().date() -%}
|
|
{%- set today_sunset = next_setting -%}
|
|
{%- else -%}
|
|
{%- set today_sunset = next_setting - timedelta(days=1) -%}
|
|
{%- endif -%}
|
|
{%- set tomorrow_sun_on = today_sunset + timedelta(days=1, minutes=-30) -%}
|
|
{%- set tomorrow_2000 = today_at('20:00:00') + timedelta(days=1) -%}
|
|
{%- if tomorrow_sun_on < tomorrow_2000 -%}
|
|
{{ tomorrow_sun_on.strftime('%Y-%m-%d %H:%M:%S') }}
|
|
{%- else -%}
|
|
{{ tomorrow_2000.strftime('%Y-%m-%d %H:%M:%S') }}
|
|
{%- endif -%}
|
|
- action: script.outdoor_lighting_ramp_main_entrance
|
|
data:
|
|
target_brightness: 0
|
|
ramp_seconds: "{{ override_ramp_seconds }}"
|
|
|
|
- conditions:
|
|
- condition: template
|
|
value_template: >
|
|
{{ not is_state('input_select.outdoor_lighting_main_entrance_override_mode', 'none')
|
|
and (last_press_age_seconds | int(999999)) > 60
|
|
and (last_press_age_seconds | int(999999)) <= 3600 }}
|
|
sequence:
|
|
- action: timer.cancel
|
|
target:
|
|
entity_id: timer.outdoor_lighting_main_entrance_override
|
|
- action: input_select.select_option
|
|
target:
|
|
entity_id: input_select.outdoor_lighting_main_entrance_override_mode
|
|
data:
|
|
option: none
|
|
- action: script.outdoor_lighting_apply_main_entrance_current_target
|
|
data:
|
|
force_reconcile: true
|
|
ramp_seconds: "{{ override_ramp_seconds }}"
|
|
|
|
default:
|
|
- action: input_datetime.set_datetime
|
|
target:
|
|
entity_id: input_datetime.outdoor_lighting_main_entrance_last_override_press
|
|
data:
|
|
datetime: "{{ now().strftime('%Y-%m-%d %H:%M:%S') }}"
|
|
|
|
- choose:
|
|
- conditions:
|
|
- condition: template
|
|
value_template: "{{ was_on_at_press | bool }}"
|
|
sequence:
|
|
- action: input_select.select_option
|
|
target:
|
|
entity_id: input_select.outdoor_lighting_main_entrance_override_mode
|
|
data:
|
|
option: return_to_schedule
|
|
default:
|
|
- action: input_select.select_option
|
|
target:
|
|
entity_id: input_select.outdoor_lighting_main_entrance_override_mode
|
|
data:
|
|
option: turn_off
|
|
|
|
- action: script.outdoor_lighting_ramp_main_entrance
|
|
data:
|
|
target_brightness: 100
|
|
ramp_seconds: "{{ override_ramp_seconds }}"
|
|
|
|
- action: timer.start
|
|
target:
|
|
entity_id: timer.outdoor_lighting_main_entrance_override
|
|
data:
|
|
duration: "01:00:00"
|
|
|
|
- id: outdoor_lighting_main_entrance_override_timer_finished
|
|
alias: Outdoor Lighting - Main Entrance Outside LEDs - Override Timer Finished
|
|
mode: single
|
|
trigger:
|
|
- platform: event
|
|
event_type: timer.finished
|
|
event_data:
|
|
entity_id: timer.outdoor_lighting_main_entrance_override
|
|
condition:
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_automation_enable
|
|
state: "on"
|
|
- condition: state
|
|
entity_id: input_boolean.outdoor_lighting_main_entrance_automation_enable
|
|
state: "on"
|
|
action:
|
|
- variables:
|
|
override_ramp_seconds: 60
|
|
mode_at_finish: "{{ states('input_select.outdoor_lighting_main_entrance_override_mode') }}"
|
|
|
|
- action: input_select.select_option
|
|
target:
|
|
entity_id: input_select.outdoor_lighting_main_entrance_override_mode
|
|
data:
|
|
option: none
|
|
|
|
- choose:
|
|
- conditions:
|
|
- condition: template
|
|
value_template: "{{ mode_at_finish == 'return_to_schedule' }}"
|
|
sequence:
|
|
- action: script.outdoor_lighting_apply_main_entrance_current_target
|
|
data:
|
|
force_reconcile: true
|
|
ramp_seconds: "{{ override_ramp_seconds }}"
|
|
|
|
- conditions:
|
|
- condition: template
|
|
value_template: "{{ mode_at_finish == 'turn_off' }}"
|
|
sequence:
|
|
- action: script.outdoor_lighting_ramp_main_entrance
|
|
data:
|
|
target_brightness: 0
|
|
ramp_seconds: "{{ override_ramp_seconds }}"
|