diff --git a/Climate/schedule_selector.yaml b/Climate/schedule_selector.yaml new file mode 100644 index 0000000..9d52674 --- /dev/null +++ b/Climate/schedule_selector.yaml @@ -0,0 +1,199 @@ +blueprint: + name: Heizplan Selector basierend auf Kalenderereignissen + description: > + Wählt automatisch einen Heizplan basierend auf Kalenderereignissen aus. + + Der Blueprint überwacht einen Kalender und wechselt zwischen verschiedenen + Schedule-Helfern basierend auf Keywords im Event-Titel oder der Beschreibung. + + **WICHTIG**: Die Anzahl der Scheduler und Keywordlisten muss übereinstimmen! + Jede Zeile in den Keywordlisten entspricht einem Scheduler an der gleichen Position. + + Bei Event-Ende wird zum Standard-Scheduler zurückgekehrt, außer ein anderes + Event ist bereits aktiv. + + Required = * + domain: automation + homeassistant: + min_version: "2024.6.0" + author: Me + input: + calendar_section: + name: Kalender-Einstellungen + description: Kalender und zeitlicher Offset für Events + collapsed: false + input: + calendar_entity: + name: Kalender * + description: Der Kalender, der für Event-Erkennung überwacht wird + selector: + entity: + filter: + - domain: calendar + + event_offset: + name: Zeitlicher Offset + description: > + Optional: Zeitlicher Versatz für Event-Start und -Ende. + Beispiel: "-00:15:00" startet 15 Minuten vor dem Event. + default: "00:00:00" + selector: + duration: + enable_day: false + + scheduler_section: + name: Scheduler-Konfiguration + description: Schedule-Helfer und zugeordnete Keywords + collapsed: false + input: + scheduler_list: + name: Scheduler-Liste * + description: > + Liste der Schedule-Helfer (schedule entities). + Die Reihenfolge muss mit den Keywordlisten übereinstimmen! + selector: + entity: + multiple: true + filter: + - domain: schedule + + keyword_lists: + name: Keywordlisten * + description: > + Eine Keywordliste pro Zeile (komma-separiert). + Beispiel: + urlaub,vacation,holiday + homeoffice,wfh,remote + normal,standard + + **Position in der Liste = Position im Scheduler!** + Zeile 1 → Scheduler 1, Zeile 2 → Scheduler 2, etc. + selector: + text: + multiline: true + type: text + + default_scheduler: + name: Standard-Scheduler * + description: > + Dieser Scheduler wird aktiviert, wenn kein Keyword matched + oder ein Event endet (und kein anderes aktiv ist). + selector: + entity: + filter: + - domain: schedule + + helper_section: + name: Helper-Entity + description: Entity zum Speichern des aktiven Schedulers + collapsed: false + input: + helper_entity: + name: Input Select Helper * + description: > + Die input_select Helper-Entity, in die der aktive Scheduler + geschrieben wird. Optionen sollten die Entity-IDs der Scheduler enthalten. + selector: + entity: + filter: + - domain: input_select + +mode: single +max_exceeded: silent + +triggers: + - platform: calendar + event: start + entity_id: !input calendar_entity + offset: !input event_offset + id: CALENDAR_START + + - platform: calendar + event: end + entity_id: !input calendar_entity + offset: !input event_offset + id: CALENDAR_END + +variables: + schedulers: !input scheduler_list + keywords_raw: !input keyword_lists + default_scheduler: !input default_scheduler + helper: !input helper_entity + calendar: !input calendar_entity + + # Keywords in Liste umwandeln (eine pro Zeile) + keyword_lists: > + {{ keywords_raw.split('\n') | select() | list }} + + # Bei Event-Start: Keywords matchen + matched_scheduler: > + {% set ns = namespace(scheduler = none) %} + {% if trigger.id == 'CALENDAR_START' %} + {% set event_text = (trigger.calendar_event.summary | lower) ~ ' ' ~ (trigger.calendar_event.description | default('') | lower) %} + {% for i in range(keyword_lists | length) %} + {% set keywords = keyword_lists[i].split(',') | map('trim') | map('lower') | list %} + {% set matched = namespace(found = false) %} + {% for keyword in keywords %} + {% if keyword in event_text %} + {% set matched.found = true %} + {% endif %} + {% endfor %} + {% if matched.found and i < (schedulers | length) %} + {% set ns.scheduler = schedulers[i] %} + {% break %} + {% endif %} + {% endfor %} + {% endif %} + {{ ns.scheduler }} + + # Bei Event-Ende: Prüfen ob ein anderes Event aktiv ist + other_event_active: > + {% if trigger.id == 'CALENDAR_END' %} + {% set start = state_attr(calendar, 'start_time') %} + {% set end = state_attr(calendar, 'end_time') %} + {% if start and end %} + {% set now_ts = now().timestamp() %} + {% set start_ts = as_timestamp(start) %} + {% set end_ts = as_timestamp(end) %} + {{ start_ts <= now_ts and now_ts <= end_ts }} + {% else %} + false + {% endif %} + {% else %} + false + {% endif %} + +conditions: [] + +actions: + - choose: + # Event-Start: Scheduler aktivieren wenn Keyword matched + - conditions: + - condition: trigger + id: CALENDAR_START + - condition: template + value_template: "{{ matched_scheduler is not none and matched_scheduler != '' }}" + sequence: + - service: input_select.select_option + target: + entity_id: !input helper_entity + data: + option: "{{ matched_scheduler }}" + alias: Event-Start - Scheduler aktivieren + + # Event-Ende: Zu Standard zurückkehren (nur wenn kein anderes Event aktiv) + - conditions: + - condition: trigger + id: CALENDAR_END + - condition: template + value_template: "{{ not other_event_active }}" + sequence: + - service: input_select.select_option + target: + entity_id: !input helper_entity + data: + option: "{{ default_scheduler }}" + alias: Event-Ende - Standard-Scheduler aktivieren + + default: [] +