#:########################################################################################:#
# PACKAGE: Free Power Time Automation                                                     #
#:########################################################################################:#
# VERSION:
#   1.2.0 - 2026-07-24
#     - Added startup catch-up to end_actions: when HA starts outside the
#       free power window, the end actions (chargers off, dehumidifier off)
#       are applied immediately.
#
#   1.1.0 - 2026-06-24
#     - Changed gas-to-heatpump handover so the heat pump setpoint is offset from
#       the gas heater setpoint.
#     - Default heat pump offset is now -5 degrees C.
#     - The offset remains YAML-only and can be changed inside
#       script.free_power_gas_heater_changeover.
#
#   1.0.0 - 2026-05-08
#     - Initial package.
#     - Adds editable free power start/end times.
#     - Adds master enable switch and per-action enable switches.
#     - Adds announcement, gas-to-heatpump changeover, tool charger control,
#       and underhouse dehumidifier control.
#
# NOTES:
#   - Free power start/end times can be changed in Home Assistant.
#   - Start time default is 9:00pm.
#   - End time default is midnight.
#   - YAML-only gas heater settings are in script.free_power_gas_heater_changeover:
#       gas_heater_shutdown_delay_seconds
#       heatpump_setpoint_offset_c
#
# IMPORTANT:
#   - input_datetime initial values are used to provide defaults.
#   - If you later want UI changes to survive every HA restart, remove the
#     initial lines after the helpers have been created and set once.
#:########################################################################################:#

#:########################################################################################:#
# INPUT DATETIME                                                                          #
#:########################################################################################:#

input_datetime:
  free_power_start_time:
    name: Free Power - Start Time
    has_date: false
    has_time: true
    initial: "21:00:00"
    icon: mdi:clock-start

  free_power_end_time:
    name: Free Power - End Time
    has_date: false
    has_time: true
    initial: "00:00:00"
    icon: mdi:clock-end

#:########################################################################################:#
# ENABLE SWITCHES                                                                         #
#:########################################################################################:#

input_boolean:
  free_power_automation_enabled:
    name: Free Power - Master Automation Enable
    icon: mdi:transmission-tower

  free_power_announcement_enabled:
    name: Free Power - Announcement Enable
    icon: mdi:bullhorn

  free_power_gas_heater_changeover_enabled:
    name: Free Power - Gas Heater Changeover Enable
    icon: mdi:heat-pump-outline

  free_power_tool_battery_chargers_enabled:
    name: Free Power - Tool Battery Chargers Enable
    icon: mdi:battery-charging

  free_power_underhouse_dehumidifier_enabled:
    name: Free Power - Underhouse Dehumidifier Enable
    icon: mdi:air-humidifier

#:########################################################################################:#
# TEMPLATE SENSORS                                                                        #
#:########################################################################################:#

template:
  - binary_sensor:
      - name: Free Power Time Active
        unique_id: free_power_time_active
        icon: mdi:transmission-tower
        state: >-
          {% set start = states('input_datetime.free_power_start_time') %}
          {% set end = states('input_datetime.free_power_end_time') %}
          {% set now_mins = now().hour * 60 + now().minute %}
          {% set start_mins = (start[0:2] | int(0)) * 60 + (start[3:5] | int(0)) %}
          {% set end_mins = (end[0:2] | int(0)) * 60 + (end[3:5] | int(0)) %}

          {% if start_mins == end_mins %}
            false
          {% elif start_mins < end_mins %}
            {{ start_mins <= now_mins < end_mins }}
          {% else %}
            {{ now_mins >= start_mins or now_mins < end_mins }}
          {% endif %}

#:########################################################################################:#
# SCRIPTS                                                                                 #
#:########################################################################################:#

script:
  free_power_start_actions:
    alias: Free Power - Start Actions
    mode: single
    sequence:
      - condition: state
        entity_id: input_boolean.free_power_automation_enabled
        state: "on"

      - variables:
          free_power_time_label: >-
            {%- set raw_time = states('input_datetime.free_power_start_time') -%}
            {%- set hour = raw_time[0:2] | int(0) -%}
            {%- set minute = raw_time[3:5] | int(0) -%}
            {%- set suffix = 'am' if hour < 12 else 'pm' -%}
            {%- set hour12 = hour % 12 -%}
            {%- set hour12 = 12 if hour12 == 0 else hour12 -%}
            {{- hour12 ~ suffix if minute == 0 else hour12 ~ ':' ~ '%02d' | format(minute) ~ suffix -}}

      ###########################################################################
      # 1) Free Power Time Announcement
      ###########################################################################

      - if:
          - condition: state
            entity_id: input_boolean.free_power_announcement_enabled
            state: "on"
        then:
          - action: script.view_road_announcement
            data:
              channels: "lounge_google_home_voice, sony_tv_lounge"
              title: "View Road "
              short_announcement: "{{ free_power_time_label }}: Free power time"
              long_announcement: "It is {{ free_power_time_label }}."

      ###########################################################################
      # 2) Gas Heater Changeover
      ###########################################################################

      - if:
          - condition: state
            entity_id: input_boolean.free_power_gas_heater_changeover_enabled
            state: "on"
        then:
          - action: script.free_power_gas_heater_changeover

      ###########################################################################
      # 3) Tool Battery Chargers On
      ###########################################################################

      - if:
          - condition: state
            entity_id: input_boolean.free_power_tool_battery_chargers_enabled
            state: "on"
        then:
          - action: switch.turn_on
            target:
              entity_id:
                - switch.ryobi_charger_left_power_monitor_x17pp
                - switch.ryobi_charger_right_power_monitor_x16pp

      ###########################################################################
      # 4) Underhouse Dehumidifier On
      ###########################################################################

      - if:
          - condition: state
            entity_id: input_boolean.free_power_underhouse_dehumidifier_enabled
            state: "on"
        then:
          - action: switch.turn_on
            target:
              entity_id:
                - switch.underhouse_dehumidifier_power_plug_x10pp

  free_power_end_actions:
    alias: Free Power - End Actions
    mode: single
    sequence:
      - condition: state
        entity_id: input_boolean.free_power_automation_enabled
        state: "on"

      ###########################################################################
      # 3) Tool Battery Chargers Off
      #
      # If this action is enabled, the chargers are switched off at free power
      # end even if something else turned them on.
      ###########################################################################

      - if:
          - condition: state
            entity_id: input_boolean.free_power_tool_battery_chargers_enabled
            state: "on"
        then:
          - action: switch.turn_off
            target:
              entity_id:
                - switch.ryobi_charger_left_power_monitor_x17pp
                - switch.ryobi_charger_right_power_monitor_x16pp

      ###########################################################################
      # 4) Underhouse Dehumidifier Off
      #
      # If this action is enabled, the dehumidifier is switched off at free power
      # end even if something else turned it on.
      ###########################################################################

      - if:
          - condition: state
            entity_id: input_boolean.free_power_underhouse_dehumidifier_enabled
            state: "on"
        then:
          - action: switch.turn_off
            target:
              entity_id:
                - switch.underhouse_dehumidifier_power_plug_x10pp

  free_power_gas_heater_changeover:
    alias: Free Power - Gas Heater Changeover
    mode: single
    sequence:
      ###########################################################################
      # YAML-only settings
      #
      # heatpump_setpoint_offset_c:
      #   This is added to the current gas heater setpoint.
      #
      #   Example:
      #     Gas heater setpoint:       22
      #     heatpump_setpoint_offset:  -5
      #     Heat pump setpoint:        17
      #
      #   To make the heat pump only 4 degrees lower, change this to -4.
      #   To match the gas heater setpoint exactly, change this to 0.
      ###########################################################################

      - variables:
          gas_heater_operation_entity: switch.rinnai_neo_gas_heater_heater_operation
          gas_heater_setpoint_entity: number.rinnai_neo_gas_heater_rinnai_neo_gas_heater_setpoint
          heatpump_climate_entity: climate.lounge

          gas_heater_shutdown_delay_seconds: 60
          heatpump_setpoint_offset_c: -0.5

          heatpump_setpoint: >-
            {{
              (
                (states(gas_heater_setpoint_entity) | float(0))
                + (heatpump_setpoint_offset_c | float(0))
              ) | round(1)
            }}

      ###########################################################################
      # Only change over if the gas heater is currently on.
      ###########################################################################

      - condition: template
        value_template: "{{ is_state(gas_heater_operation_entity, 'on') }}"

      ###########################################################################
      # Only continue if the gas setpoint can be read.
      ###########################################################################

      - condition: template
        value_template: >-
          {{ states(gas_heater_setpoint_entity) not in ['unknown', 'unavailable', 'none', 'None', ''] }}

      ###########################################################################
      # Set the Panasonic heat pump to heat mode.
      #
      # The target temperature is the gas heater setpoint plus the YAML-only
      # offset above. With the default offset of -5, a gas heater setpoint of
      # 22 degrees will set the heat pump to 17 degrees.
      ###########################################################################

      - action: climate.set_temperature
        target:
          entity_id: "{{ heatpump_climate_entity }}"
        data:
          hvac_mode: heat
          temperature: "{{ heatpump_setpoint }}"

      ###########################################################################
      # Give the heat pump time to start before turning the gas heater off.
      ###########################################################################

      - delay:
          seconds: "{{ gas_heater_shutdown_delay_seconds | int(60) }}"

      - action: switch.turn_off
        target:
          entity_id: "{{ gas_heater_operation_entity }}"

#:########################################################################################:#
# AUTOMATIONS                                                                             #
#:########################################################################################:#

automation:
  - id: free_power_time_start_actions
    alias: Free Power Time - Start Actions
    mode: single
    triggers:
      - trigger: time
        at: input_datetime.free_power_start_time
    actions:
      - action: script.free_power_start_actions

  - id: free_power_time_end_actions
    alias: Free Power Time - End Actions
    mode: single
    triggers:
      - trigger: time
        at: input_datetime.free_power_end_time
      - trigger: homeassistant
        event: start
    conditions:
      - condition: state
        entity_id: binary_sensor.free_power_time_active
        state: "off"
    actions:
      - action: script.free_power_end_actions
