Skip to content

Instantly share code, notes, and snippets.

@tim-peters
Last active January 15, 2026 12:38
Show Gist options
  • Select an option

  • Save tim-peters/8315fa060387e818b83f00ae6bdf9cda to your computer and use it in GitHub Desktop.

Select an option

Save tim-peters/8315fa060387e818b83f00ae6bdf9cda to your computer and use it in GitHub Desktop.
Home Assistant Blueprint, that adds a more advanced while functionality – enabling users to sync states between different entities. Sets any entities to a defined status AS LONG AS a master condition is met. When the condition is no longer met, the original or a defined fallback status is restored.
blueprint:
name: "While Condition - Expert Mode"
description: >
Setzt beliebige Entitäten in einen definierten Status, SOLANGE eine
Master-Bedingung erfüllt ist. Beim Verlassen der Bedingung wird der
ursprüngliche oder ein definierter Fallback-Status wiederhergestellt.
Unterstützt: Lichter (inkl. Helligkeit/Farbe), Schalter, Cover,
Climate, Media Player, Input-Helfer und mehr.
source_url: https://gist.githubusercontent.com/tim-peters/8315fa060387e818b83f00ae6bdf9cda/raw/while_expert.yaml
domain: automation
input:
# ═══════════════════════════════════════════════════════════════
# MASTER / TRIGGER KONFIGURATION
# ═══════════════════════════════════════════════════════════════
master_entity:
name: "🎛️ Master-Entität"
description: >
Die Entität, deren Status die Bedingung definiert.
Kann jeder Entitätstyp sein (Sensor, Binary Sensor, Input Select, etc.)
selector:
entity: {}
master_trigger_state:
name: "🎯 Trigger-Status des Masters"
description: >
Bei welchem Status des Masters sollen die Ziel-Entitäten gesetzt werden?
Beispiele: "on", "off", "home", "playing", "above_horizon", "heat", ">20", "<50"
Unterstützte Operatoren für numerische Vergleiche: >, <, >=, <=, ==, !=
default: "on"
selector:
text: {}
master_attribute:
name: "📊 Master-Attribut (optional)"
description: >
Falls nicht der Hauptstatus, sondern ein Attribut überwacht werden soll.
Leer lassen für Hauptstatus. Beispiele: "brightness", "temperature", "media_title"
default: ""
selector:
text: {}
# ═══════════════════════════════════════════════════════════════
# ZIEL-ENTITÄTEN KONFIGURATION
# ═══════════════════════════════════════════════════════════════
target_entities:
name: "🎯 Ziel-Entitäten"
description: >
Die Entitäten, die gesteuert werden sollen, wenn die Master-Bedingung erfüllt ist.
selector:
entity:
multiple: true
use_scene_mode:
name: "🎬 Szenen-Modus verwenden"
description: >
Wenn aktiviert, werden Szenen für die Status-Definition verwendet.
Dies ermöglicht komplexe Konfigurationen (Helligkeit, Farbe, etc.)
Wenn deaktiviert, wird ein einfacher Status-Text verwendet.
default: false
selector:
boolean: {}
# --- Einfacher Modus ---
target_active_state:
name: "✅ Ziel-Status (Aktiv)"
description: >
[Nur im einfachen Modus] Status, auf den die Ziel-Entitäten gesetzt
werden, wenn die Master-Bedingung ERFÜLLT ist.
Beispiele: "on", "off", "open", "closed", "50" (für Cover-Position)
default: "on"
selector:
text: {}
target_inactive_state:
name: "❌ Ziel-Status (Inaktiv)"
description: >
[Nur im einfachen Modus] Status, auf den die Ziel-Entitäten gesetzt
werden, wenn die Master-Bedingung NICHT MEHR erfüllt ist.
Beispiele: "on", "off", "open", "closed", "restore" (für vorherigen Status)
default: "off"
selector:
text: {}
# --- Szenen-Modus ---
scene_active:
name: "🎬 Szene (Aktiv)"
description: >
[Nur im Szenen-Modus] Szene, die aktiviert wird, wenn die
Master-Bedingung ERFÜLLT ist.
default: {}
selector:
entity:
domain: scene
scene_inactive:
name: "🎬 Szene (Inaktiv)"
description: >
[Nur im Szenen-Modus] Szene, die aktiviert wird, wenn die
Master-Bedingung NICHT MEHR erfüllt ist.
Leer lassen, um den vorherigen Status wiederherzustellen.
default: {}
selector:
entity:
domain: scene
# ═══════════════════════════════════════════════════════════════
# ERWEITERTE OPTIONEN
# ═══════════════════════════════════════════════════════════════
restore_previous_state:
name: "🔄 Vorherigen Status wiederherstellen"
description: >
Wenn aktiviert, wird der Status VOR der Aktivierung gespeichert
und beim Deaktivieren wiederhergestellt.
(Nur wenn keine Inaktiv-Szene definiert und Inaktiv-Status = "restore")
default: true
selector:
boolean: {}
scene_helper:
name: "💾 Szene für Statuswiederherstellung"
description: >
ERFORDERLICH wenn "Vorherigen Status wiederherstellen" aktiviert ist!
Erstelle eine leere Szene (z.B. "scene.temp_state_backup") die als
Speicher verwendet wird.
Anleitung: Einstellungen → Geräte & Dienste → Helfer → Szene erstellen
default: {}
selector:
entity:
domain: scene
additional_conditions:
name: "🔒 Zusätzliche Bedingungen"
description: >
Optionale zusätzliche Bedingungen, die erfüllt sein müssen.
Die Automation wird nur ausgeführt, wenn ALLE Bedingungen erfüllt sind.
default: []
selector:
condition: {}
activation_delay:
name: "⏱️ Aktivierungsverzögerung"
description: >
Wartezeit bevor die Ziel-Entitäten gesetzt werden, nachdem
die Master-Bedingung erfüllt wurde.
default:
hours: 0
minutes: 0
seconds: 0
selector:
duration: {}
deactivation_delay:
name: "⏱️ Deaktivierungsverzögerung"
description: >
Wartezeit bevor die Ziel-Entitäten zurückgesetzt werden, nachdem
die Master-Bedingung nicht mehr erfüllt ist.
default:
hours: 0
minutes: 0
seconds: 0
selector:
duration: {}
debounce_time:
name: "🔄 Debounce-Zeit"
description: >
Minimale Zeit zwischen zwei Ausführungen (verhindert Flackern).
default: 200
selector:
number:
min: 0
max: 10000
step: 100
unit_of_measurement: "ms"
mode: slider
only_on_change:
name: "🔀 Nur bei Statusänderung ausführen"
description: >
Wenn aktiviert, werden die Aktionen nur ausgeführt, wenn sich
der Erfüllungsstatus der Bedingung tatsächlich ändert.
default: true
selector:
boolean: {}
run_on_startup:
name: "🚀 Bei HA-Start ausführen"
description: >
Wenn aktiviert, wird die Automation auch beim Start von
Home Assistant ausgeführt, um den korrekten Status herzustellen.
default: true
selector:
boolean: {}
mode: restart
max_exceeded: silent
trigger:
# Haupttrigger: Master-Entität ändert sich
- platform: state
entity_id: !input master_entity
id: "master_changed"
# Optional: Bei HA-Start
- platform: homeassistant
event: start
id: "ha_start"
variables:
# Inputs laden
master_entity: !input master_entity
master_trigger_state: !input master_trigger_state
master_attribute: !input master_attribute
target_entities: !input target_entities
use_scene_mode: !input use_scene_mode
target_active_state: !input target_active_state
target_inactive_state: !input target_inactive_state
scene_active: !input scene_active
scene_inactive: !input scene_inactive
restore_previous: !input restore_previous_state
scene_helper: !input scene_helper
activation_delay: !input activation_delay
deactivation_delay: !input deactivation_delay
debounce: !input debounce_time
only_on_change: !input only_on_change
run_on_startup: !input run_on_startup
# Aktuellen Master-Wert ermitteln (Status oder Attribut)
current_master_value: >
{% if master_attribute and master_attribute | length > 0 %}
{{ state_attr(master_entity, master_attribute) }}
{% else %}
{{ states(master_entity) }}
{% endif %}
# Trigger-Wert parsen (Operatoren unterstützen)
trigger_operator: >
{% set ts = master_trigger_state | string | trim %}
{% if ts.startswith('>=') %}
>=
{% elif ts.startswith('<=') %}
<=
{% elif ts.startswith('!=') %}
!=
{% elif ts.startswith('==') %}
==
{% elif ts.startswith('>') %}
>
{% elif ts.startswith('<') %}
<
{% else %}
eq
{% endif %}
trigger_value: >
{% set ts = master_trigger_state | string | trim %}
{% if trigger_operator != 'eq' %}
{{ ts | replace('>=', '') | replace('<=', '') | replace('!=', '') | replace('==', '') | replace('>', '') | replace('<', '') | trim }}
{% else %}
{{ ts }}
{% endif %}
# Bedingung prüfen
condition_met: >
{% set current = current_master_value | string %}
{% set target = trigger_value | string %}
{% set op = trigger_operator %}
{% if current in ['unknown', 'unavailable'] %}
false
{% elif op == 'eq' %}
{{ current == target }}
{% elif op == '==' %}
{{ current | float(-999999) == target | float(-999998) }}
{% elif op == '!=' %}
{{ current | float(-999999) != target | float(-999998) }}
{% elif op == '>' %}
{{ current | float(-999999) > target | float }}
{% elif op == '<' %}
{{ current | float(-999999) < target | float }}
{% elif op == '>=' %}
{{ current | float(-999999) >= target | float }}
{% elif op == '<=' %}
{{ current | float(-999999) <= target | float }}
{% else %}
false
{% endif %}
# Vorheriger Bedingungsstatus (für Änderungserkennung)
previous_master_value: >
{% if trigger.from_state is defined and trigger.from_state is not none %}
{% if master_attribute and master_attribute | length > 0 %}
{{ trigger.from_state.attributes.get(master_attribute, '') }}
{% else %}
{{ trigger.from_state.state }}
{% endif %}
{% else %}
unknown
{% endif %}
previous_condition_met: >
{% set current = previous_master_value | string %}
{% set target = trigger_value | string %}
{% set op = trigger_operator %}
{% if current in ['unknown', 'unavailable', ''] %}
false
{% elif op == 'eq' %}
{{ current == target }}
{% elif op == '==' %}
{{ current | float(-999999) == target | float(-999998) }}
{% elif op == '!=' %}
{{ current | float(-999999) != target | float(-999998) }}
{% elif op == '>' %}
{{ current | float(-999999) > target | float }}
{% elif op == '<' %}
{{ current | float(-999999) < target | float }}
{% elif op == '>=' %}
{{ current | float(-999999) >= target | float }}
{% elif op == '<=' %}
{{ current | float(-999999) <= target | float }}
{% else %}
false
{% endif %}
# Hat sich der Erfüllungsstatus geändert?
condition_changed: "{{ condition_met != previous_condition_met }}"
# Ist es ein HA-Start-Event?
is_startup: "{{ trigger.id == 'ha_start' }}"
condition:
# Bei Startup prüfen ob aktiviert
- condition: template
value_template: >
{{ not is_startup or run_on_startup }}
# Nur bei Änderung ausführen (wenn aktiviert)
- condition: template
value_template: >
{{ not only_on_change or condition_changed or is_startup }}
# Zusätzliche benutzerdefinierte Bedingungen
- condition: !input additional_conditions
action:
# Debouncing
- delay:
milliseconds: "{{ debounce | int }}"
# Erneute Prüfung der Bedingung (könnte sich während Debounce geändert haben)
- variables:
current_condition_met: >
{% if master_attribute and master_attribute | length > 0 %}
{% set current = state_attr(master_entity, master_attribute) | string %}
{% else %}
{% set current = states(master_entity) %}
{% endif %}
{% set target = trigger_value | string %}
{% set op = trigger_operator %}
{% if current in ['unknown', 'unavailable'] %}
false
{% elif op == 'eq' %}
{{ current == target }}
{% elif op == '==' %}
{{ current | float(-999999) == target | float(-999998) }}
{% elif op == '!=' %}
{{ current | float(-999999) != target | float(-999998) }}
{% elif op == '>' %}
{{ current | float(-999999) > target | float }}
{% elif op == '<' %}
{{ current | float(-999999) < target | float }}
{% elif op == '>=' %}
{{ current | float(-999999) >= target | float }}
{% elif op == '<=' %}
{{ current | float(-999999) <= target | float }}
{% else %}
false
{% endif %}
- choose:
# ═══════════════════════════════════════════════════════════
# BEDINGUNG ERFÜLLT → AKTIVEN STATUS SETZEN
# ═══════════════════════════════════════════════════════════
- conditions:
- condition: template
value_template: "{{ current_condition_met }}"
sequence:
# Vorherigen Status speichern (falls aktiviert)
- if:
- condition: template
value_template: >
{{ restore_previous and scene_helper is defined and
scene_helper | length > 0 }}
then:
- service: scene.create
data:
scene_id: "{{ scene_helper.split('.')[1] }}"
snapshot_entities: "{{ target_entities }}"
# Aktivierungsverzögerung
- delay: !input activation_delay
# Erneute Prüfung nach Verzögerung
- condition: template
value_template: >
{% if master_attribute and master_attribute | length > 0 %}
{% set current = state_attr(master_entity, master_attribute) | string %}
{% else %}
{% set current = states(master_entity) %}
{% endif %}
{% set target = trigger_value | string %}
{% set op = trigger_operator %}
{% if current in ['unknown', 'unavailable'] %}
false
{% elif op == 'eq' %}
{{ current == target }}
{% elif op == '==' %}
{{ current | float(-999999) == target | float(-999998) }}
{% elif op == '!=' %}
{{ current | float(-999999) != target | float(-999998) }}
{% elif op == '>' %}
{{ current | float(-999999) > target | float }}
{% elif op == '<' %}
{{ current | float(-999999) < target | float }}
{% elif op == '>=' %}
{{ current | float(-999999) >= target | float }}
{% elif op == '<=' %}
{{ current | float(-999999) <= target | float }}
{% else %}
false
{% endif %}
# Status setzen
- choose:
# Szenen-Modus
- conditions:
- condition: template
value_template: "{{ use_scene_mode and scene_active is defined and scene_active | length > 0 }}"
sequence:
- service: scene.turn_on
target:
entity_id: "{{ scene_active }}"
# Einfacher Modus
default:
- choose:
# ON
- conditions:
- condition: template
value_template: "{{ target_active_state | lower == 'on' }}"
sequence:
- service: homeassistant.turn_on
target:
entity_id: "{{ target_entities }}"
# OFF
- conditions:
- condition: template
value_template: "{{ target_active_state | lower == 'off' }}"
sequence:
- service: homeassistant.turn_off
target:
entity_id: "{{ target_entities }}"
# OPEN (Cover)
- conditions:
- condition: template
value_template: "{{ target_active_state | lower == 'open' }}"
sequence:
- service: cover.open_cover
target:
entity_id: "{{ target_entities }}"
# CLOSED (Cover)
- conditions:
- condition: template
value_template: "{{ target_active_state | lower in ['closed', 'close'] }}"
sequence:
- service: cover.close_cover
target:
entity_id: "{{ target_entities }}"
# STOP (Cover)
- conditions:
- condition: template
value_template: "{{ target_active_state | lower == 'stop' }}"
sequence:
- service: cover.stop_cover
target:
entity_id: "{{ target_entities }}"
# LOCK
- conditions:
- condition: template
value_template: "{{ target_active_state | lower == 'lock' }}"
sequence:
- service: lock.lock
target:
entity_id: "{{ target_entities }}"
# UNLOCK
- conditions:
- condition: template
value_template: "{{ target_active_state | lower == 'unlock' }}"
sequence:
- service: lock.unlock
target:
entity_id: "{{ target_entities }}"
# PLAY (Media)
- conditions:
- condition: template
value_template: "{{ target_active_state | lower == 'play' }}"
sequence:
- service: media_player.media_play
target:
entity_id: "{{ target_entities }}"
# PAUSE (Media)
- conditions:
- condition: template
value_template: "{{ target_active_state | lower == 'pause' }}"
sequence:
- service: media_player.media_pause
target:
entity_id: "{{ target_entities }}"
# Numerischer Wert (Cover-Position, Licht-Helligkeit, etc.)
- conditions:
- condition: template
value_template: "{{ target_active_state | int(-999) != -999 }}"
sequence:
- choose:
# Cover: Position setzen
- conditions:
- condition: template
value_template: >
{{ target_entities | select('match', 'cover\\..*') | list | length > 0 }}
sequence:
- service: cover.set_cover_position
target:
entity_id: >
{{ target_entities | select('match', 'cover\\..*') | list }}
data:
position: "{{ target_active_state | int }}"
default: []
- choose:
# Light: Helligkeit setzen
- conditions:
- condition: template
value_template: >
{{ target_entities | select('match', 'light\\..*') | list | length > 0 }}
sequence:
- service: light.turn_on
target:
entity_id: >
{{ target_entities | select('match', 'light\\..*') | list }}
data:
brightness_pct: "{{ target_active_state | int }}"
default: []
- choose:
# Input Number: Wert setzen
- conditions:
- condition: template
value_template: >
{{ target_entities | select('match', 'input_number\\..*') | list | length > 0 }}
sequence:
- service: input_number.set_value
target:
entity_id: >
{{ target_entities | select('match', 'input_number\\..*') | list }}
data:
value: "{{ target_active_state | float }}"
default: []
default: []
# ═══════════════════════════════════════════════════════════
# BEDINGUNG NICHT ERFÜLLT → INAKTIVEN STATUS SETZEN
# ═══════════════════════════════════════════════════════════
default:
# Deaktivierungsverzögerung
- delay: !input deactivation_delay
# Erneute Prüfung nach Verzögerung
- condition: template
value_template: >
{% if master_attribute and master_attribute | length > 0 %}
{% set current = state_attr(master_entity, master_attribute) | string %}
{% else %}
{% set current = states(master_entity) %}
{% endif %}
{% set target = trigger_value | string %}
{% set op = trigger_operator %}
{% if current in ['unknown', 'unavailable'] %}
true
{% elif op == 'eq' %}
{{ current != target }}
{% elif op == '==' %}
{{ current | float(-999999) != target | float(-999998) }}
{% elif op == '!=' %}
{{ current | float(-999999) == target | float(-999998) }}
{% elif op == '>' %}
{{ current | float(-999999) <= target | float }}
{% elif op == '<' %}
{{ current | float(-999999) >= target | float }}
{% elif op == '>=' %}
{{ current | float(-999999) < target | float }}
{% elif op == '<=' %}
{{ current | float(-999999) > target | float }}
{% else %}
true
{% endif %}
# Status wiederherstellen/setzen
- choose:
# Szenen-Modus mit definierter Inaktiv-Szene
- conditions:
- condition: template
value_template: "{{ use_scene_mode and scene_inactive is defined and scene_inactive | length > 0 }}"
sequence:
- service: scene.turn_on
target:
entity_id: "{{ scene_inactive }}"
# Vorherigen Status wiederherstellen
- conditions:
- condition: template
value_template: >
{{ (target_inactive_state | lower == 'restore' or use_scene_mode) and
restore_previous and scene_helper is defined and
scene_helper | length > 0 }}
sequence:
- service: scene.turn_on
target:
entity_id: "{{ scene_helper }}"
# Einfacher Modus - Inaktiven Status setzen
default:
- choose:
# ON
- conditions:
- condition: template
value_template: "{{ target_inactive_state | lower == 'on' }}"
sequence:
- service: homeassistant.turn_on
target:
entity_id: "{{ target_entities }}"
# OFF
- conditions:
- condition: template
value_template: "{{ target_inactive_state | lower == 'off' }}"
sequence:
- service: homeassistant.turn_off
target:
entity_id: "{{ target_entities }}"
# OPEN
- conditions:
- condition: template
value_template: "{{ target_inactive_state | lower == 'open' }}"
sequence:
- service: cover.open_cover
target:
entity_id: "{{ target_entities }}"
# CLOSED
- conditions:
- condition: template
value_template: "{{ target_inactive_state | lower in ['closed', 'close'] }}"
sequence:
- service: cover.close_cover
target:
entity_id: "{{ target_entities }}"
# LOCK
- conditions:
- condition: template
value_template: "{{ target_inactive_state | lower == 'lock' }}"
sequence:
- service: lock.lock
target:
entity_id: "{{ target_entities }}"
# UNLOCK
- conditions:
- condition: template
value_template: "{{ target_inactive_state | lower == 'unlock' }}"
sequence:
- service: lock.unlock
target:
entity_id: "{{ target_entities }}"
# PLAY
- conditions:
- condition: template
value_template: "{{ target_inactive_state | lower == 'play' }}"
sequence:
- service: media_player.media_play
target:
entity_id: "{{ target_entities }}"
# PAUSE
- conditions:
- condition: template
value_template: "{{ target_inactive_state | lower == 'pause' }}"
sequence:
- service: media_player.media_pause
target:
entity_id: "{{ target_entities }}"
# Numerischer Wert
- conditions:
- condition: template
value_template: "{{ target_inactive_state | int(-999) != -999 }}"
sequence:
- choose:
- conditions:
- condition: template
value_template: >
{{ target_entities | select('match', 'cover\\..*') | list | length > 0 }}
sequence:
- service: cover.set_cover_position
target:
entity_id: >
{{ target_entities | select('match', 'cover\\..*') | list }}
data:
position: "{{ target_inactive_state | int }}"
default: []
- choose:
- conditions:
- condition: template
value_template: >
{{ target_entities | select('match', 'light\\..*') | list | length > 0 }}
sequence:
- service: light.turn_on
target:
entity_id: >
{{ target_entities | select('match', 'light\\..*') | list }}
data:
brightness_pct: "{{ target_inactive_state | int }}"
default: []
- choose:
- conditions:
- condition: template
value_template: >
{{ target_entities | select('match', 'input_number\\..*') | list | length > 0 }}
sequence:
- service: input_number.set_value
target:
entity_id: >
{{ target_entities | select('match', 'input_number\\..*') | list }}
data:
value: "{{ target_inactive_state | float }}"
default: []
default: []
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment