commit adcec21a5c67854b3bd0ff75ebde887e4821e5f6 Author: bzoicas Date: Wed Jul 30 08:27:17 2025 +0300 BZO's Smart Climate Controller diff --git a/blueprints/automations/bzo_climate.yaml b/blueprints/automations/bzo_climate.yaml new file mode 100644 index 0000000..ab7787a --- /dev/null +++ b/blueprints/automations/bzo_climate.yaml @@ -0,0 +1,331 @@ +blueprint: + name: BZO's Smart Climate Controller + description: > + Automatically control a climate device based on indoor/outdoor temperatures, + using one command per update. Sends HVAC mode, temperature, and fan settings + only if different from current state. Supports external temp threshold for heat/cool switching, + presence, schedule, optional override, optional away mode, logging level, and optional window detection. + domain: automation + input: + climate_entity: + name: Climate Device + description: 'Selet the unit or units that will be controled.' + selector: + entity: + domain: climate + + room_temp_sensor: + name: Room Temperature Sensor + description: 'Sensor or group of sensors used to calculate thermostat values.' + selector: + entity: + domain: sensor + device_class: temperature + + outdoor_temp_sensor: + name: Outdoor Temperature Sensor + description: 'Used to determine HVAC mode ( cool or heat ).' + selector: + entity: + domain: sensor + device_class: temperature + + presence_entity: + name: Presence Sensor or Group + description: 'Used to tun off the units if house is empty.' + selector: + entity: + domain: person + + schedule_entity: + name: Schedule Helper + description: 'Schedule for the unit to run.' + selector: + entity: + domain: schedule + + override_switch: + name: (Optional) Manual Override Switch + description: 'Override presence and schedule and turn on the unit.' + default: '' + selector: + entity: + domain: input_boolean + + away_mode_helper: + name: (Optional) Away Mode Helper (turns off A/C) + default: '' + selector: + entity: + domain: input_boolean + + window_sensor: + name: (Optional) Window Sensor + default: '' + selector: + entity: + domain: binary_sensor + + delta_fan_low: + name: Temperature Delta for Mid Fan + default: 2 + selector: + number: + min: 1 + max: 5 + step: 0.5 + unit_of_measurement: °C + + delta_fan_high: + name: Temperature Delta for High Fan + default: 3 + selector: + number: + min: 2 + max: 10 + step: 0.5 + unit_of_measurement: °C + + external_temp_threshold: + name: External Temperature Heat/Cool Switch Threshold + default: 18 + selector: + number: + min: -10 + max: 35 + step: 1 + unit_of_measurement: °C + + target_temp_helper: + name: Target Temperature Helper + description: ' + Control your comfort temperature via automations or the UI, you can + specify an *[input_number](https://www.home-assistant.io/integrations/input_number/)* + entity here. + + + Create your helper [here](https://my.home-assistant.io/redirect/helpers/). ' + selector: + entity: + domain: input_number + + temp_adjust_threshold: + name: Temperature Delta Adjustment Threshold + description: 'The Delta value, representing the difference between the desired and actual temperature, will adjust the thermostat.' + default: 4 + selector: + number: + min: 0 + max: 10 + step: 0.5 + unit_of_measurement: °C + + temp_adjust_amount: + name: Temperature Adjustment Amount + description: 'How many degrees to add or subtract if the difference between the desired temp and actual temp is higher than Delta.' + default: 1 + selector: + number: + min: 0 + max: 5 + step: 0.5 + unit_of_measurement: °C + + fan_mode_profile: + name: Fan Mode Profile + description: 'Fan mode: Standard for Auto, High, mid, low and numerif for Auto, 1, 2, etc.' + default: standard + selector: + select: + options: + - standard + - numeric + + log_level: + name: Logging Level + default: info + selector: + select: + options: + - info + - debug + +mode: restart +max_exceeded: silent +trigger_variables: + override_switch: !input override_switch + +trigger: + - platform: time_pattern + minutes: "/5" + - platform: state + entity_id: !input schedule_entity + to: "on" + - platform: state + entity_id: !input target_temp_helper + +condition: + - condition: template + value_template: > + {{ override_switch == '' or is_state( override_switch, 'off') }} + - condition: state + entity_id: !input schedule_entity + state: "on" + - condition: state + entity_id: !input presence_entity + state: "home" + # - condition: template + # value_template: > + # {% set window = window_sensor %} + # {{ window == '' or is_state(window, 'off') }} + +action: + - variables: + climate: !input climate_entity + room_sensor: !input room_temp_sensor + outside_sensor: !input outdoor_temp_sensor + target_temp_entity: !input target_temp_helper + fan_profile: !input fan_mode_profile + away: !input away_mode_helper + adjust_threshold: !input temp_adjust_threshold + adjust_amount: !input temp_adjust_amount + delta_low: !input delta_fan_low + delta_high: !input delta_fan_high + threshold: !input external_temp_threshold + override_switch: !input override_switch + + room_temp: > + {% set r = states(room_sensor) %} + {{ r | float(0) if r not in ['unknown', 'unavailable'] else 0 }} + + outside_temp: > + {% set o = states(outside_sensor) %} + {{ o | float(999) if o not in ['unknown', 'unavailable'] else 999 }} + + desired_temp: > + {% set t = states(target_temp_entity) %} + {{ t | float(22) if t not in ['unknown', 'unavailable'] else 22 }} + + adjusted_temp: > + {% set delta = (room_temp - desired_temp) | abs %} + {% if delta >= adjust_threshold %} + {% if room_temp > desired_temp %} + {{ desired_temp - adjust_amount }} + {% else %} + {{ desired_temp + adjust_amount }} + {% endif %} + {% else %} + {{ desired_temp }} + {% endif %} + + hvac_mode: > + {% if outside_temp < threshold %} heat + {% elif outside_temp < 999 %} cool + {% else %} auto {% endif %} + + delta: "{{ room_temp - desired_temp }}" + + fan_mode: > + {% if fan_profile == 'standard' %} + {% if delta | abs >= delta_high %} high + {% elif delta | abs >= delta_low %} mid + {% else %} auto {% endif %} + {% else %} + {% if delta | abs >= delta_high %} "5" + {% elif delta | abs >= delta_low %} "3" + {% else %} "1" {% endif %} + {% endif %} + + - choose: + - conditions: + - condition: state + entity_id: !input schedule_entity + state: "off" + sequence: + - service: climate.turn_off + target: + entity_id: !input climate_entity + - service: logbook.log + data: + name: "Smart Climate" + message: "A/C turned off because schedule is OFF" + entity_id: !input climate_entity + + - choose: + - conditions: + - condition: template + value_template: > + {{ away != '' and is_state(away, 'on') }} + sequence: + - service: climate.turn_off + target: + entity_id: !input climate_entity + - service: logbook.log + data: + name: "Smart Climate" + message: "A/C turned off due to Away Mode" + entity_id: !input climate_entity + + - condition: template + value_template: > + {{ away == '' or is_state(away, 'off') }} + + - choose: + - conditions: + - condition: template + value_template: "{{ log_level == 'debug' }}" + sequence: + - service: logbook.log + data: + name: "Smart Climate" + message: > + External temp = {{ outside_temp }}°C, Threshold = {{ threshold }}°C → Mode = {{ hvac_mode }} + entity_id: !input climate_entity + + - service: logbook.log + data: + name: "Smart Climate DEBUG" + message: > + Current state = {{ states(climate) }}, HVAC = {{ state_attr(climate, 'hvac_modes') or 'unknown' }}, + Temp = {{ state_attr(climate, 'temperature') }}, Fan = {{ state_attr(climate, 'fan_mode') or 'unknown' }}; + Target: HVAC = {{ hvac_mode }}, Temp = {{ adjusted_temp }}, Fan = {{ fan_mode }} + entity_id: !input climate_entity + - conditions: + - condition: template + value_template: "{{ log_level == 'info' }}" + sequence: + - service: logbook.log + data: + name: "Smart Climate" + message: "Automation triggered (log level: info)" + entity_id: !input climate_entity + + - condition: or + conditions: + - condition: template + value_template: > + {{ states(climate) in ['off', 'unavailable', 'unknown'] }} + - condition: template + value_template: > + {% set state = states(climate) %} + {% set fan = (state_attr(climate, 'fan_mode') or 'unknown') | string %} + {% set temp = state_attr(climate, 'temperature') | float(999) %} + {{ state != hvac_mode or fan != fan_mode or (temp | round(1)) != (adjusted_temp | round(1)) }} + + - service: climate.set_temperature + target: + entity_id: !input climate_entity + data: + temperature: "{{ adjusted_temp | float }}" + hvac_mode: "{{ hvac_mode }}" + fan_mode: "{{ fan_mode }}" + + - service: logbook.log + data: + name: "Smart Climate" + message: > + Sent command: HVAC = {{ hvac_mode }}, Temp = {{ adjusted_temp }}°C, Fan = {{ fan_mode }} + entity_id: !input climate_entity + + - delay: + minutes: 1