###############################################################################
# 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
