blueprint: name: Klima Demand Hybrid Control (fix) description: > Demand Regelung für Klimageräte mit Außentemperatur, Raumkorrektur und Ramping. Rundet Demand auf gültige 5%-Schritte (30-100) domain: automation input: hvac: name: Klimagerät selector: entity: domain: climate room_sensor: name: Raumtemperatur selector: entity: domain: sensor device_class: temperature outdoor_sensor: name: Außentemperatur selector: entity: domain: sensor device_class: temperature demand_entity: name: Demand Select selector: entity: domain: select outdoor_curve: name: Heizkurve default: '[[ -10,70],[-5,60],[0,55],[5,50],[10,40],[15,30]]' selector: text: correction_curve: name: Raumkorrektur default: '[[-0.5,-10],[-0.2,-5],[0,0],[0.5,5],[1.0,10]]' selector: text: ramp_step: name: Maximaler Demand-Änderung pro Zyklus default: 5 selector: number: min: 1 max: 20 step: 1 unit_of_measurement: "%" demand_min: name: Minimal Demand default: 30 selector: number: min: 0 max: 100 step: 5 demand_max: name: Maximal Demand default: 100 selector: number: min: 0 max: 100 step: 5 overheat_threshold: name: Überheizschutz default: -0.4 selector: number: min: -2 max: 0 step: 0.1 unit_of_measurement: "°C" mode: restart trigger: - platform: state entity_id: - !input room_sensor - !input outdoor_sensor - platform: time_pattern minutes: "/2" condition: - condition: state entity_id: !input hvac state: heat action: - variables: hvac_entity: !input hvac room_sensor_entity: !input room_sensor outdoor_sensor_entity: !input outdoor_sensor demand_entity_var: !input demand_entity outdoor_curve_raw: !input outdoor_curve correction_curve_raw: !input correction_curve ramp_step: !input ramp_step demand_min: !input demand_min demand_max: !input demand_max overheat_threshold: !input overheat_threshold - variables: outdoor_curve: "{{ outdoor_curve_raw | from_json }}" correction_curve: "{{ correction_curve_raw | from_json }}" room: "{{ states(room_sensor_entity) | float(0) }}" target: "{{ state_attr(hvac_entity,'temperature') | float(0) }}" outdoor: "{{ states(outdoor_sensor_entity) | float(0) }}" diff: "{{ target - room }}" current_raw: "{{ states(demand_entity_var) }}" current: >- {% set m = current_raw | regex_findall_index('[0-9]+') %} {% if m is not none %} {{ m | float(0) }} {% else %} 0 {% endif %} - variables: base_demand: >- {% set pts = outdoor_curve %} {% set t = outdoor %} {% if t <= pts[0][0] %} {{ pts[0][1] }} {% elif t >= pts[-1][0] %} {{ pts[-1][1] }} {% else %} {% set ns = namespace(val=pts[0][1]) %} {% for i in range(pts|length - 1) %} {% set a = pts[i] %} {% set b = pts[i+1] %} {% if t >= a[0] and t <= b[0] %} {% set ratio = (t - a[0]) / (b[0] - a[0]) %} {% set ns.val = a[1] + ratio * (b[1] - a[1]) %} {% endif %} {% endfor %} {{ ns.val }} {% endif %} - variables: correction: >- {% set pts = correction_curve %} {% set d = diff %} {% if d <= pts[0][0] %} {{ pts[0][1] }} {% elif d >= pts[-1][0] %} {{ pts[-1][1] }} {% else %} {% set ns = namespace(val=0) %} {% for i in range(pts|length - 1) %} {% set a = pts[i] %} {% set b = pts[i+1] %} {% if d >= a[0] and d <= b[0] %} {% set ratio = (d - a[0]) / (b[0] - a[0]) %} {% set ns.val = a[1] + ratio * (b[1] - a[1]) %} {% endif %} {% endfor %} {{ ns.val }} {% endif %} - variables: target_demand: >- {% if diff < overheat_threshold %} {{ demand_min }} {% else %} {{ base_demand + correction }} {% endif %} - variables: ramped: >- {% set step = ramp_step | float %} {% set cur = current | float %} {% set tgt = target_demand | float %} {% if tgt > cur %} {{ [tgt, cur + step] | min }} {% elif tgt < cur %} {{ [tgt, cur - step] | max }} {% else %} {{ cur }} {% endif %} - variables: limited: "{{ [demand_max, [ramped, demand_min] | max] | min }}" - variables: rounded: "{{ (limited / 5) | round(0, 'ceil') * 5 }}" - variables: option: >- {% set val = rounded | int %} {% if val < demand_min %} {{ demand_min }} {% elif val > demand_max %} {{ demand_max }} {% else %} {{ val }} {% endif %} - condition: template value_template: "{{ states(demand_entity_var) | regex_findall_index('[0-9]+') | float(0) != option }}" - service: select.select_option target: entity_id: "{{ demand_entity_var }}" data: option: "{{ option }}"