369 lines
11 KiB
YAML
369 lines
11 KiB
YAML
###############################################################################
|
|
# PACKAGE: Lounge Blinds - Sunrise / Sunset Automation
|
|
###############################################################################
|
|
#
|
|
# VERSION:
|
|
# v1.2 - 2026-05-08
|
|
# - Updated input_boolean.lounge_blinds control logic.
|
|
# - input_boolean.lounge_blinds ON now closes the blinds.
|
|
# - input_boolean.lounge_blinds OFF now opens the blinds.
|
|
# - Removed the sync guard helper.
|
|
# - Added state checks so cover feedback does not create command loops.
|
|
#
|
|
# v1.1 - 2026-05-08
|
|
# - Added input_boolean.lounge_blinds as a manual control/status helper.
|
|
# - Added cover state sync back to input_boolean.lounge_blinds.
|
|
#
|
|
# v1.0 - 2026-05-08
|
|
# - Initial package.
|
|
# - Opens lounge blinds at sunrise.
|
|
# - Closes lounge blinds at sunset.
|
|
# - Includes sunrise/sunset minute offsets.
|
|
# - Includes repeated command attempts for Zigbee reliability.
|
|
# - Opens blinds in list order: A, B, C.
|
|
# - Closes blinds in reverse list order: C, B, A.
|
|
#
|
|
# NOTES:
|
|
# - input_boolean.lounge_blinds is treated as:
|
|
# ON = blinds closed
|
|
# OFF = blinds open
|
|
#
|
|
# - Turning input_boolean.lounge_blinds ON will close the blinds.
|
|
# - Turning input_boolean.lounge_blinds OFF will open the blinds.
|
|
# - If all blinds are closed by another method, the boolean will turn ON.
|
|
# - If all blinds are opened by another method, the boolean will turn OFF.
|
|
# - If blinds are in a mixed/partial state, the boolean is left unchanged.
|
|
#
|
|
# - The blind entity list is inside:
|
|
# script.lounge_blinds_run_sequence
|
|
# script.lounge_blinds_sync_status
|
|
# automation.lounge_blinds_control_from_input_boolean
|
|
#
|
|
# - If you add more blinds, update the blind list in those three places.
|
|
#
|
|
###############################################################################
|
|
|
|
input_boolean:
|
|
lounge_blinds:
|
|
name: Lounge Blinds Closed
|
|
icon: mdi:blinds
|
|
|
|
input_number:
|
|
lounge_blinds_sunrise_offset_minutes:
|
|
name: Lounge Blinds Sunrise Offset
|
|
icon: mdi:weather-sunset-up
|
|
min: -180
|
|
max: 180
|
|
step: 1
|
|
mode: box
|
|
unit_of_measurement: min
|
|
initial: 0
|
|
|
|
lounge_blinds_sunset_offset_minutes:
|
|
name: Lounge Blinds Sunset Offset
|
|
icon: mdi:weather-sunset-down
|
|
min: -180
|
|
max: 180
|
|
step: 1
|
|
mode: box
|
|
unit_of_measurement: min
|
|
initial: 0
|
|
|
|
lounge_blinds_per_blind_delay_seconds:
|
|
name: Lounge Blinds Per-Blind Delay
|
|
icon: mdi:timer-outline
|
|
min: 0
|
|
max: 60
|
|
step: 1
|
|
mode: box
|
|
unit_of_measurement: sec
|
|
initial: 2
|
|
|
|
lounge_blinds_command_repeats:
|
|
name: Lounge Blinds Command Repeats
|
|
icon: mdi:repeat
|
|
min: 1
|
|
max: 5
|
|
step: 1
|
|
mode: box
|
|
initial: 2
|
|
|
|
lounge_blinds_retry_delay_seconds:
|
|
name: Lounge Blinds Retry Delay
|
|
icon: mdi:timer-refresh-outline
|
|
min: 0
|
|
max: 120
|
|
step: 1
|
|
mode: box
|
|
unit_of_measurement: sec
|
|
initial: 10
|
|
|
|
input_datetime:
|
|
lounge_blinds_next_open_time:
|
|
name: Lounge Blinds Next Open Time
|
|
has_date: true
|
|
has_time: true
|
|
|
|
lounge_blinds_next_close_time:
|
|
name: Lounge Blinds Next Close Time
|
|
has_date: true
|
|
has_time: true
|
|
|
|
script:
|
|
lounge_blinds_update_sun_times:
|
|
alias: Lounge Blinds - Update Sun Times
|
|
mode: single
|
|
sequence:
|
|
- variables:
|
|
sunrise_offset_seconds: >
|
|
{{ states('input_number.lounge_blinds_sunrise_offset_minutes') | int(0) * 60 }}
|
|
sunset_offset_seconds: >
|
|
{{ states('input_number.lounge_blinds_sunset_offset_minutes') | int(0) * 60 }}
|
|
next_sunrise_timestamp: >
|
|
{{ as_timestamp(state_attr('sun.sun', 'next_rising')) + sunrise_offset_seconds }}
|
|
next_sunset_timestamp: >
|
|
{{ as_timestamp(state_attr('sun.sun', 'next_setting')) + sunset_offset_seconds }}
|
|
|
|
- action: input_datetime.set_datetime
|
|
target:
|
|
entity_id: input_datetime.lounge_blinds_next_open_time
|
|
data:
|
|
datetime: >
|
|
{{ next_sunrise_timestamp | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }}
|
|
|
|
- action: input_datetime.set_datetime
|
|
target:
|
|
entity_id: input_datetime.lounge_blinds_next_close_time
|
|
data:
|
|
datetime: >
|
|
{{ next_sunset_timestamp | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }}
|
|
|
|
lounge_blinds_run_sequence:
|
|
alias: Lounge Blinds - Run Open/Close Sequence
|
|
mode: queued
|
|
fields:
|
|
blind_action:
|
|
name: Blind Action
|
|
description: Use open or close.
|
|
required: true
|
|
selector:
|
|
select:
|
|
options:
|
|
- open
|
|
- close
|
|
|
|
sequence:
|
|
- variables:
|
|
blind_list:
|
|
- cover.lounge_blind_a_xbl11
|
|
- cover.lounge_blind_b_xbl12
|
|
- cover.lounge_blind_c_xbl13
|
|
|
|
command_repeats: >
|
|
{{ states('input_number.lounge_blinds_command_repeats') | int(2) }}
|
|
|
|
retry_delay_seconds: >
|
|
{{ states('input_number.lounge_blinds_retry_delay_seconds') | int(10) }}
|
|
|
|
per_blind_delay_seconds: >
|
|
{{ states('input_number.lounge_blinds_per_blind_delay_seconds') | int(2) }}
|
|
|
|
- repeat:
|
|
count: "{{ command_repeats }}"
|
|
sequence:
|
|
- choose:
|
|
- conditions:
|
|
- condition: template
|
|
value_template: "{{ blind_action == 'open' }}"
|
|
sequence:
|
|
- repeat:
|
|
for_each: "{{ blind_list }}"
|
|
sequence:
|
|
- action: cover.open_cover
|
|
target:
|
|
entity_id: "{{ repeat.item }}"
|
|
|
|
- delay:
|
|
seconds: "{{ per_blind_delay_seconds }}"
|
|
|
|
- conditions:
|
|
- condition: template
|
|
value_template: "{{ blind_action == 'close' }}"
|
|
sequence:
|
|
- repeat:
|
|
for_each: "{{ blind_list | reverse | list }}"
|
|
sequence:
|
|
- action: cover.close_cover
|
|
target:
|
|
entity_id: "{{ repeat.item }}"
|
|
|
|
- delay:
|
|
seconds: "{{ per_blind_delay_seconds }}"
|
|
|
|
- if:
|
|
- condition: template
|
|
value_template: "{{ repeat.index < command_repeats }}"
|
|
then:
|
|
- delay:
|
|
seconds: "{{ retry_delay_seconds }}"
|
|
|
|
- action: script.lounge_blinds_sync_status
|
|
|
|
lounge_blinds_sync_status:
|
|
alias: Lounge Blinds - Sync Status
|
|
mode: queued
|
|
sequence:
|
|
- variables:
|
|
blind_list:
|
|
- cover.lounge_blind_a_xbl11
|
|
- cover.lounge_blind_b_xbl12
|
|
- cover.lounge_blind_c_xbl13
|
|
|
|
blind_states: >
|
|
{{ expand(blind_list) | map(attribute='state') | list }}
|
|
|
|
all_blinds_closed: >
|
|
{{ blind_states | select('eq', 'closed') | list | count == blind_list | count }}
|
|
|
|
all_blinds_open: >
|
|
{{ blind_states | select('eq', 'open') | list | count == blind_list | count }}
|
|
|
|
- choose:
|
|
- conditions:
|
|
- condition: template
|
|
value_template: >
|
|
{{ all_blinds_closed and is_state('input_boolean.lounge_blinds', 'off') }}
|
|
sequence:
|
|
- action: input_boolean.turn_on
|
|
target:
|
|
entity_id: input_boolean.lounge_blinds
|
|
|
|
- conditions:
|
|
- condition: template
|
|
value_template: >
|
|
{{ all_blinds_open and is_state('input_boolean.lounge_blinds', 'on') }}
|
|
sequence:
|
|
- action: input_boolean.turn_off
|
|
target:
|
|
entity_id: input_boolean.lounge_blinds
|
|
|
|
automation:
|
|
- id: lounge_blinds_update_sun_times
|
|
alias: Lounge Blinds - Update Sun Times
|
|
mode: restart
|
|
trigger:
|
|
- platform: homeassistant
|
|
event: start
|
|
|
|
- platform: time
|
|
at: "00:05:00"
|
|
|
|
- platform: state
|
|
entity_id:
|
|
- input_number.lounge_blinds_sunrise_offset_minutes
|
|
- input_number.lounge_blinds_sunset_offset_minutes
|
|
|
|
action:
|
|
- action: script.lounge_blinds_update_sun_times
|
|
|
|
- id: lounge_blinds_open_at_sunrise
|
|
alias: Lounge Blinds - Open At Sunrise
|
|
mode: single
|
|
trigger:
|
|
- platform: time
|
|
at: input_datetime.lounge_blinds_next_open_time
|
|
|
|
action:
|
|
- action: script.lounge_blinds_run_sequence
|
|
data:
|
|
blind_action: open
|
|
|
|
- id: lounge_blinds_close_at_sunset
|
|
alias: Lounge Blinds - Close At Sunset
|
|
mode: single
|
|
trigger:
|
|
- platform: time
|
|
at: input_datetime.lounge_blinds_next_close_time
|
|
|
|
action:
|
|
- action: script.lounge_blinds_run_sequence
|
|
data:
|
|
blind_action: close
|
|
|
|
- id: lounge_blinds_control_from_input_boolean
|
|
alias: Lounge Blinds - Control From Input Boolean
|
|
mode: restart
|
|
trigger:
|
|
- platform: state
|
|
entity_id: input_boolean.lounge_blinds
|
|
to: "on"
|
|
|
|
- platform: state
|
|
entity_id: input_boolean.lounge_blinds
|
|
to: "off"
|
|
|
|
action:
|
|
- variables:
|
|
blind_list:
|
|
- cover.lounge_blind_a_xbl11
|
|
- cover.lounge_blind_b_xbl12
|
|
- cover.lounge_blind_c_xbl13
|
|
|
|
blind_states: >
|
|
{{ expand(blind_list) | map(attribute='state') | list }}
|
|
|
|
all_blinds_closed: >
|
|
{{ blind_states | select('eq', 'closed') | list | count == blind_list | count }}
|
|
|
|
all_blinds_open: >
|
|
{{ blind_states | select('eq', 'open') | list | count == blind_list | count }}
|
|
|
|
- choose:
|
|
- conditions:
|
|
- condition: state
|
|
entity_id: input_boolean.lounge_blinds
|
|
state: "on"
|
|
|
|
- condition: template
|
|
value_template: "{{ not all_blinds_closed }}"
|
|
sequence:
|
|
- action: script.lounge_blinds_run_sequence
|
|
data:
|
|
blind_action: close
|
|
|
|
- conditions:
|
|
- condition: state
|
|
entity_id: input_boolean.lounge_blinds
|
|
state: "off"
|
|
|
|
- condition: template
|
|
value_template: "{{ not all_blinds_open }}"
|
|
sequence:
|
|
- action: script.lounge_blinds_run_sequence
|
|
data:
|
|
blind_action: open
|
|
|
|
- id: lounge_blinds_sync_input_boolean_from_cover_states
|
|
alias: Lounge Blinds - Sync Input Boolean From Cover States
|
|
mode: restart
|
|
trigger:
|
|
- platform: homeassistant
|
|
event: start
|
|
|
|
- platform: state
|
|
entity_id:
|
|
- cover.lounge_blind_a_xbl11
|
|
- cover.lounge_blind_b_xbl12
|
|
- cover.lounge_blind_c_xbl13
|
|
to: "open"
|
|
|
|
- platform: state
|
|
entity_id:
|
|
- cover.lounge_blind_a_xbl11
|
|
- cover.lounge_blind_b_xbl12
|
|
- cover.lounge_blind_c_xbl13
|
|
to: "closed"
|
|
|
|
action:
|
|
- action: script.lounge_blinds_sync_status
|