Du hast einen Wecker in Home Assistant. Du gehst in den Urlaub. Du schaltest den Wecker manuell aus. Du vergisst, ihn wieder einzuschalten. Oder du schaltest ihn zu frueh ein und wirst am letzten Urlaubstag geweckt.

Die Loesung: Der Kalender ist die einzige Quelle der Wahrheit. Wenn dort “Urlaub” steht, schweigt der Wecker. Wenn das Event endet, feuert er wieder. Ohne Schalter, ohne Extra-Automation.

TL;DR

  1. Shell-Script auf dem HA-Server fragt per CalDAV, ob heute ein “urlaub”-Event aktiv ist
  2. command_line Binary Sensor in HA: on = Urlaub, off = kein Urlaub
  3. Wecker-Automations pruefen condition: not auf diesen Sensor — fail-open
  4. Drei Pitfalls die euch Zeit sparen: CalDAV Config Flow, deprecated YAML-Platform, BusyBox-date

Die Architektur

Kalender-Server (CalDAV)
    |
    v  (curl REPORT, alle 15 Min)
HA: check_urlaub.sh
    |
    v
binary_sensor.urlaub_kalender  [on/off]
    |
    v  (condition: not → state: on)
Set_Weekday_Alarm / Set_Weekend_Alarm

Der Binary Sensor pollt alle 15 Minuten den CalDAV-Server. Fuer mehrtaegige Urlaubs-Events ist das mehr als ausreichend.

Das Script: CalDAV-Abfrage

Das Script laeuft direkt im HA-Container und fragt per CalDAV REPORT (RFC 4791) die heutigen Events ab. Wenn ein Event mit “urlaub” im Titel gefunden wird: ON. Sonst: OFF.

#!/bin/bash
# /config/check_urlaub.sh
CALDAV_URL="https://mail.deathstar.lan/dav/calendars/luke.skywalker@rebellion.local/Kalender/"
CALDAV_USER="c3po@rebellion.local"
CALDAV_PASS="<DEIN-CALDAV-PASSWORT>"

START=$(date -u +%Y%m%dT000000Z)
# BusyBox-kompatibel (siehe Pitfall 3)
END=$(date -u -D %s -d $(($(date +%s) + 86400)) +%Y%m%dT000000Z)

RESULT=$(curl -s --max-time 10 -u "$CALDAV_USER:$CALDAV_PASS" \
  -X REPORT -H "Depth: 1" -H "Content-Type: application/xml" \
  "$CALDAV_URL" \
  -d "<?xml version=\"1.0\"?>\
<c:calendar-query xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\
<d:prop><c:calendar-data/></d:prop>\
<c:filter><c:comp-filter name=\"VCALENDAR\">\
<c:comp-filter name=\"VEVENT\">\
<c:time-range start=\"$START\" end=\"$END\"/>\
</c:comp-filter></c:comp-filter></c:filter>\
</c:calendar-query>")

if echo "$RESULT" | grep -qi "urlaub"; then
  echo "ON"
else
  echo "OFF"
fi

Wichtig: Der CalDAV-User braucht Leserechte auf den Kalender des Ziel-Users. Bei Grommunio:

grommunio-admin exmdb luke.skywalker@rebellion.local folder grant 0x9 \
    c3po@rebellion.local foldervisible readany

0x9 ist der Store Root — ohne foldervisible dort sieht SabreDAV die Kalender-Kollektionen im PROPFIND nicht.

HA-Konfiguration

Binary Sensor (configuration.yaml)

command_line:
  - binary_sensor:
      name: "Urlaub Kalender"
      unique_id: urlaub_kalender_caldav
      command: "bash /config/check_urlaub.sh"
      device_class: occupancy
      payload_on: "ON"
      payload_off: "OFF"
      scan_interval: 900

Automation-Condition (automations.yaml)

Die Urlaubs-Pruefung kommt als erste Condition in den bestehenden Wecker:

- id: 'weekday_alarm'
  alias: Set_Weekday_Alarm
  triggers:
  - at: input_datetime.alarm
    trigger: time
  conditions: []
  actions:
  - choose:
    - conditions:
      # Urlaub? → Wecker aus
      - condition: not
        conditions:
          - condition: state
            entity_id: binary_sensor.urlaub_kalender
            state: 'on'
      # Normaler Wochentag?
      - condition: time
        weekday: [mon, tue, wed, thu, fri]
      # Wecker eingeschaltet?
      - condition: state
        entity_id: input_boolean.alarm_on_off
        state: 'on'
      sequence:
        # ... Licht, Musik, Kaffeemaschine

Warum condition: not statt state: 'off'?

Fail-open. Wenn der CalDAV-Server nicht erreichbar ist, wird die Entity unavailable:

Sensor-Statecondition: not → onstate: 'off'
on (Urlaub)Wecker ausWecker aus
off (kein Urlaub)Wecker anWecker an
unavailableWecker anWecker aus

Mit state: 'off' wuerde ein CalDAV-Ausfall den Wecker dauerhaft stumm schalten. condition: not kehrt die Logik um: nur ein explizites on unterdrueckt den Wecker. Alles andere — inklusive Fehler — laesst ihn feuern.

Faustregel: Wenn der Fehlerfall “Wecker klingelt obwohl Urlaub” vs. “Wecker schweigt obwohl Arbeitstag” ist — waehle ersteres.

Die drei Pitfalls

Pitfall 1: CalDAV Config Flow geht nicht fuer Cross-Account

HA hat eine CalDAV-Integration in der UI (Einstellungen → Integrationen → CalDAV). Die funktioniert — aber nur fuer den Kalender des authentifizierten Users.

Wenn User A den Kalender von User B lesen soll (z.B. ein Service-Account liest den Chef-Kalender), folgt die Config Flow trotzdem dem Principal von User A. Die Entity zeigt dann einen leeren Kalender.

Kein Fehler, kein Log-Eintrag. Die Entity existiert, hat 0 Events, und man sucht den Fehler woanders.

Workaround: command_line Binary Sensor mit direktem curl-CalDAV-REPORT auf die URL des Ziel-Kalenders. Umgeht die Discovery komplett.

Pitfall 2: YAML CalDAV-Platform ist deprecated (silent fail)

Die alte YAML-Variante:

calendar:
  - platform: caldav
    url: https://...
    username: ...
    password: ...
    custom_calendars:
      - name: "Urlaub"
        calendar: "Kalender"
        search: "(?i)urlaub"

wird in aktuellen HA-Versionen ohne Fehlermeldung ignoriert. config/core/check_config meldet valid. Kein Log-Eintrag. Die Entity wird nie erstellt.

Das ist besonders tueckisch, weil die YAML-Platform frueher Features hatte die der Config Flow nicht bietet (custom_calendars mit search-Filter). Man konfiguriert es, startet HA neu, alles sieht OK aus — nur die Entity fehlt.

Pitfall 3: BusyBox-date im HA-Container

Home Assistant OS laeuft auf Alpine Linux. Der Container hat BusyBox statt GNU coreutils. Das betrifft date:

# GNU date (funktioniert auf Debian/Ubuntu):
date -d "+1 day" +%Y%m%dT000000Z

# BusyBox date (HA Container):
date: invalid date '+1 day'

BusyBox-kompatible Alternative:

date -u -D %s -d $(($(date +%s) + 86400)) +%Y%m%dT000000Z

Betrifft alle shell_command und command_line Sensoren in HA OS.

Der Workflow

  1. Urlaubs-Event im Kalender eintragen (beliebiger Client — Outlook, Thunderbird, Handy)
  2. Warten bis der naechste 15-Minuten-Poll laeuft
  3. binary_sensor.urlaub_kalender wechselt auf on
  4. Wecker-Automations pruefen die Condition und schweigen
  5. Event endet → Sensor geht auf off → Wecker feuert wieder

Kein manueller Eingriff. Eine Quelle der Wahrheit.

Lessons Learned

  • Fail-open schlaegt fail-closed bei Weckern. Lieber einmal zu viel geweckt als verschlafen.
  • CalDAV Config Flow in HA ist nicht CalDAV — sie ist eine opinionated Abstraktion. Fuer Cross-Account-Zugriff braucht man den Rohweg ueber curl.
  • Silent deprecation ist schlimmer als ein Breaking Change. Fehlermeldungen helfen. Stilles Ignorieren kostet Stunden.
  • Alpine/BusyBox-Kompatibilitaet ist ein Evergreen-Problem. Jedes Shell-Script das im HA-Container laeuft braucht einen Test im Container, nicht auf dem Entwickler-Rechner.

Checkliste

  • CalDAV-User hat Leserechte auf den Ziel-Kalender
  • check_urlaub.sh im HA-Container getestet (docker exec homeassistant bash /config/check_urlaub.sh)
  • Binary Sensor in Developer Tools → States sichtbar und mit korrektem State
  • Wecker-Automation nutzt condition: not (fail-open)
  • Kalender-Event angelegt und Sensor reagiert