From fc3a5721714039c8b8833183b677524de35116e6 Mon Sep 17 00:00:00 2001 From: andreas Date: Fri, 5 Dec 2025 12:19:01 +0100 Subject: [PATCH] Update ha-smart-thermostat-control.yaml manual adjustments are out --- ha-smart-thermostat-control.yaml | 188 ++++++------------------------- 1 file changed, 32 insertions(+), 156 deletions(-) diff --git a/ha-smart-thermostat-control.yaml b/ha-smart-thermostat-control.yaml index ce37cfa..26d17b2 100644 --- a/ha-smart-thermostat-control.yaml +++ b/ha-smart-thermostat-control.yaml @@ -2,11 +2,9 @@ blueprint: name: "Smart Thermostat Controller" author: Andreas Gammelgaard Damsbo description: | - Advanced thermostat automation with window/door sensors, presence detection, time schedules, and holiday calendar integration. - - SETUP REQUIRED: - 1. Create an input_boolean helper (Settings > Devices & Services > Helpers > Toggle) for manual override tracking - 2. Create a timer helper (Settings > Devices & Services > Helpers > Timer) for override duration + Smart thermostat automation based on window/door sensors, outside temperature (winter mode), time schedules, and holiday calendar integration. + + * **Day Temperature is now controlled by a separate Input Number Helper.** domain: automation source_url: https://gdamsbo.dk/forgejo/andreas/ha-smart-thermostat-control/raw/branch/main/ha-smart-thermostat-control.yaml input: @@ -18,33 +16,6 @@ blueprint: domain: - climate multiple: true - manual_override_helper: - name: Manual Override Helper - description: Select an input_boolean helper to track manual temperature overrides. Create one in Settings > Devices & Services > Helpers. - selector: - entity: - domain: - - input_boolean - multiple: false - override_timer: - name: Override Timer - description: Select a timer helper to manage override duration. Create one in Settings > Devices & Services > Helpers > Timer. - selector: - entity: - domain: - - timer - multiple: false - override_duration: - name: Manual Override Duration - description: 'How long manual temperature changes should override the schedule. This sets the timer duration. (Default = 120 minutes)' - default: 120 - selector: - number: - mode: box - min: 30.0 - max: 480.0 - unit_of_measurement: minutes - step: 30.0 window_sensor: name: Window / Door Sensor Group description: Select your grouped or single window / door sensor. @@ -102,16 +73,14 @@ blueprint: domain: - schedule multiple: false - day_temp: - name: Day Time Temperature Target - default: 21 + day_temp_helper: + name: Day Time Temperature Input Number + description: Select an input_number helper that stores the desired Day Time temperature. (Create one in Settings > Devices & Services > Helpers). selector: - number: - step: 0.5 - min: 10.0 - max: 30.0 - unit_of_measurement: °C or °F - mode: slider + entity: + domain: + - input_number + multiple: false night_temp: name: Night Time Temperature Target default: 18 @@ -175,17 +144,8 @@ trigger: entity_id: !input schedule_helper id: schedule_change - platform: state - entity_id: !input thermostat - attribute: temperature - id: manual_adjustment - - platform: state - entity_id: !input manual_override_helper - to: 'off' - id: override_expired - - platform: state - entity_id: !input override_timer - to: 'idle' - id: timer_finished + entity_id: !input day_temp_helper # Trigger when the input number changes + id: day_temp_change - platform: calendar event: end entity_id: !input away_calendar @@ -205,86 +165,23 @@ trigger: variables: thermostat_entities: !input thermostat triggered_thermostat: "{{ trigger.entity_id | default('none') }}" - # Access temperature safely: - # 1. Get the 'to_state', defaulting to a simple object/dict if missing. - # 2. Get the 'attributes' from that object, defaulting to a dict if missing. - # 3. Get the 'temperature' from the attributes, defaulting to 0, then convert to float. - new_temperature: > - {{ trigger.to_state.attributes.temperature | default(0) | float(0) - if trigger.to_state is defined and trigger.to_state.attributes is defined - else 0 }} - old_temperature: > - {{ trigger.from_state.attributes.temperature | default(0) | float(0) - if trigger.from_state is defined and trigger.from_state.attributes is defined - else 0 }} - override_helper: !input manual_override_helper - override_duration_id: !input override_duration - day_temp_input: !input day_temp - night_temp_input: !input night_temp - away_temp_input: !input away_temp + + # Entity ID variables for safe templating in action conditions schedule_helper_id: !input schedule_helper away_calendar_id: !input away_calendar - + + # --- REVISED VARIABLE: Get state value from helper --- + day_temp_input: "{{ states(!input day_temp_helper) | float(21) }}" + # --- END REVISED VARIABLE --- + + night_temp_input: !input night_temp + away_temp_input: !input away_temp + condition: [] action: - choose: - # Priority 0: Manual Adjustment - Detect and enable override - - conditions: - - condition: trigger - id: manual_adjustment - # Only if temperature actually changed - - condition: template - value_template: "{{ (new_temperature - old_temperature) | abs > 0.1 }}" - # Only if the new temp is different from current schedule targets - - condition: template - value_template: > - {% if is_state(away_calendar_id, 'on') %} - {{ (new_temperature - away_temp_input) | abs > 0.1 }} - {% elif is_state(schedule_helper_id, 'on') %} - {{ (new_temperature - day_temp_input) | abs > 0.1 }} - {% else %} - {{ (new_temperature - night_temp_input) | abs > 0.1 }} - {% endif %} - sequence: - - service: logbook.log - data: - name: Smart Thermostat - message: 'Manual Override: {{ triggered_thermostat }} changed to {{ new_temperature }}°, syncing others' - # Sync temperature to all other thermostats - - repeat: - for_each: "{{ thermostat_entities | reject('eq', triggered_thermostat) | list }}" - sequence: - - service: climate.set_temperature - target: - entity_id: "{{ repeat.item }}" - data: - temperature: "{{ new_temperature }}" - # Enable manual override mode - - service: input_boolean.turn_on - target: - entity_id: !input manual_override_helper - # Start timer - - service: timer.start - target: - entity_id: !input override_timer - data: - duration: "{{ (override_duration_id * 60) | int }}" - - # Priority 0b: Timer Finished - Disable override and resume schedule - - conditions: - - condition: trigger - id: timer_finished - sequence: - - service: input_boolean.turn_off - target: - entity_id: !input manual_override_helper - - service: logbook.log - data: - name: Smart Thermostat - message: 'Manual Override: Timer expired, resuming schedule' - - # Priority 1: Windows/Doors Open - Turn OFF heating (overrides manual) + # Priority 1: Windows/Doors Open - Turn OFF heating - conditions: - condition: state entity_id: !input window_sensor @@ -294,18 +191,12 @@ action: - service: climate.turn_off target: entity_id: !input thermostat - - service: input_boolean.turn_off - target: - entity_id: !input manual_override_helper - - service: timer.cancel - target: - entity_id: !input override_timer - service: logbook.log data: name: Smart Thermostat message: 'Heating OFF: Window or door is open' - # Priority 2: Too Warm Outside - Turn OFF heating (overrides manual) + # Priority 2: Too Warm Outside - Turn OFF heating - conditions: - condition: numeric_state entity_id: !input outdoor @@ -314,29 +205,12 @@ action: - service: climate.turn_off target: entity_id: !input thermostat - - service: input_boolean.turn_off - target: - entity_id: !input manual_override_helper - - service: timer.cancel - target: - entity_id: !input override_timer - service: logbook.log data: name: Smart Thermostat message: 'Heating OFF: Outside temperature above threshold' - # Priority 3: Manual Override Active - Do nothing, keep manual temperature - - conditions: - - condition: state - entity_id: !input manual_override_helper - state: 'on' - sequence: - - service: logbook.log - data: - name: Smart Thermostat - message: 'Manual override active - maintaining user-set temperature' - - # Priority 4: Away/Holiday Mode - Set to away temperature + # Priority 3: Away/Holiday Mode - Set to away temperature - conditions: - condition: state entity_id: !input away_calendar @@ -360,7 +234,7 @@ action: name: Smart Thermostat message: 'Away Mode: Heating set to away temperature' - # Priority 5: Schedule Day Time - Set to day temperature + # Priority 4: Schedule Day Time - Set to day temperature - conditions: - condition: state entity_id: !input schedule_helper @@ -380,14 +254,16 @@ action: target: entity_id: !input thermostat data: - temperature: !input day_temp + # --- REVISED ACTION: Use the variable which holds the helper state --- + temperature: "{{ day_temp_input }}" + # --- END REVISED ACTION --- hvac_mode: heat - service: logbook.log data: name: Smart Thermostat - message: 'Day Mode: Heating set to day temperature' + message: 'Day Mode: Heating set to dynamic day temperature' - # Priority 6: Schedule Night Time - Set to night temperature + # Priority 5: Schedule Night Time - Set to night temperature - conditions: - condition: state entity_id: !input schedule_helper @@ -424,5 +300,5 @@ action: name: Smart Thermostat message: 'Heating OFF: No active heating conditions met' -mode: single +mode: restart max_exceeded: silent \ No newline at end of file