Zum Hauptinhalt springen

Interaktiver Reinigungsplan mit Home Assistant

·3061 Wörter·15 min
Tobias Schulz
Autor
Tobias Schulz
고생 끝에 낙이 온다 · immer, weiter
Inhaltsverzeichnis
Ein guter Reinigungsplan plant sich selbst - du musst ihn nur einmal vernünftig aufschreiben.

Erinnerst du dich noch an mein Versprechen vom Ende des Scene-History Beitrags? Ich mich schon: denn ich hatte angekündigt, dass ich darüber schreibe, wie ich mit Local calendar, To-do list und Roborock einen interaktiven Reinigungsplan in Home Assistant gebaut habe. Das ist jetzt knapp zwei Jahre her, höchste Zeit also 😁.

Vorab eine ehrliche Ansage: das hier ist kein One-Click-Setup. Wir bauen mehrere Bausteine zusammen, jeder davon einzeln nicht weltbewegend, in Kombination aber überraschend mächtig. Wer schon Lust hat, kann sich die Reihenfolge gleich merken: Kalender als Plan, Template Sensor als heutige Wahrheit, Script für die eigentliche Reinigung, Todo-Liste als Statusanzeige für die Familie und zwei Automationen als Klebstoff.

Klingt nach Aufwand? Ist es auch. Klingt nach Spaß? Definitiv 😎.

Insgesamt sind es drei Automationen, die wir bauen: eine, die saugt, eine, die nachts die Status-Liste neu aufbaut, und eine, die nach dem Saugen die heute fälligen Räume in der Liste abhakt. Klingt nach viel, ist aber jede für sich kurz und folgt einer klaren Aufgabe.

Anforderungen an den Plan
#

Bevor ich angefangen habe, wollte ich für mich klären, was der Plan eigentlich können soll. Ohne klare Anforderung baust du sonst monatelang am Symptom statt an der Ursache. Mein Anspruch war konkret folgender:

  • Pro Raum eigener Rhythmus. Wohnzimmer und Flur fast täglich, Schlafzimmer zwei- bis dreimal die Woche, andere Räume nach Bedarf.
  • Wiederholungen pro Tag möglich. Manche Tage rechtfertigen einen zweiten Durchlauf, andere nicht. Soll der Plan steuern, nicht ich.
  • Nur, wenn niemand stört. Kein Roborock, wenn das Kind schläft, der Fernseher läuft oder jemand in der betroffenen Etage arbeitet.
  • Selbst-pflegende Status-Anzeige. Damit meine Frau und ich auf einen Blick sehen, was heute ansteht und was bereits erledigt ist - ganz ohne, dass jemand etwas händisch eintragen muss.
Info

Mein Setup besteht aus genau einem Roborock S7, der über Segment Cleaning gezielt einzelne Räume anfährt. Wenn du mehrere Sauger oder gar mehrere Stockwerke hast, lassen sich die Bausteine erweitern - das Grundprinzip bleibt aber identisch.

Die Bausteine im Überblick
#

Bevor ich in die Konfiguration einsteige, kurz die Architektur. Das hilft dir später, dich im Code zurechtzufinden:

BausteinAufgabe
calendar.auto_vacuumHält den Plan: welcher Raum, wie oft, in welchem Zeitfenster.
binary_sensor.auto_vacuum_scheduleLiest den Kalender und berechnet heute und als Nächstes.
script.turn_on_vacuum_segment_cleaningÜbersetzt Home Assistant Areas in Roborock-Segmente und löst die Reinigung aus.
todo.auto_vacuumStatus-Anzeige fürs Dashboard mit Fälligkeitsdatum pro Raum.
automation.staubsauger_startenKlebstoff: triggert bei passender Gelegenheit, prüft Bedingungen, ruft das Script auf.
automation.staubsauger_todos_bauenPflegt nachts die Todo-Liste neu, damit Fälligkeiten stimmen.
automation.staubsauger_todos_abhakenHakt die heute fälligen Items nach erfolgreicher Reinigung in der Todo-Liste ab.

Es lohnt sich, das einmal vor sich hinzuzeichnen. Stichwort: Skizze schlägt Schreibtisch 😁.

1. Der Plan im Kalender
#

Das Herzstück ist ein Local Calendar namens calendar.auto_vacuum. Anders als bei klassischen Reinigungsplänen ist mein Kalender allerdings nicht lesbar für Menschen, sondern lesbar für Home Assistant. Drei Event-Typen sind hinterlegt, alle mit eigenen Wiederholungs-Regeln (RRULE).

Bereich-Events geben an, an welchen Tagen welcher Raum dran ist. Der summary folgt strikt dem Schema area:<area_id>:

summary: area:wohnzimmer
rrule:   FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR,SA
summary: area:schlafzimmer
rrule:   FREQ=WEEKLY;BYDAY=TU,SA

Wiederholungs-Events geben an, wie oft an einem Tag zusätzlich gesaugt werden soll. Ohne Event bleibt es bei einem Durchgang, mit repeat:once gibt es einen Extra-Durchgang (also zwei), mit repeat:twice gibt es zwei Extras (also drei):

summary: repeat:once
rrule:   FREQ=WEEKLY;BYDAY=MO,FR
Tip

Es lohnt sich, hier mit Bedacht zu entscheiden. Drei Durchgänge bedeuten dreifache Laufzeit und dreifacher Lärm. Mein Roborock zieht im max-Modus außerdem ordentlich an der Batterie. repeat:once oder repeat:twice nutze ich nur an Tagen, an denen wir verlässlich nicht da sind.

Clean-Events definieren Zeitfenster, in denen die Reinigung überhaupt anlaufen darf. Das sind die einzigen Events mit dateTime statt date, weil hier eine Uhrzeit zählt:

summary: clean
start:   09:00, end: 13:00
rrule:   FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR,SA

Auf diese Weise habe ich vormittags und nachmittags je ein Fenster definiert. Innerhalb dieser Fenster sieht der Plan zu, dass die Sache passiert. Außerhalb wird gar nicht erst angefangen.

1a. Erläuterungen
#

Warum drei Event-Typen statt einem? Weil sie unabhängig voneinander geändert werden können. Wenn ich morgen entscheide, dass das Schlafzimmer nur noch einmal pro Woche dran ist, ändere ich genau ein area:-Event, nichts sonst. Wenn ich eine neue Putzphase mit drei Durchgängen ausprobieren möchte, lege ich ein repeat:twice-Event an. Und wenn der Bauarbeiter-Lärm in der Nachbarschaft mich zwingt, ein Zeitfenster zu verschieben, fasse ich nur das clean-Event an. Trennung der Zuständigkeiten, ganz wie beim Coden 😄.

2. Der Template Sensor: “Was steht heute an?”
#

Aus den Kalender-Events allein wird noch kein Reinigungsplan. Es braucht eine Stelle, die jeden Moment beantworten kann: “Welche Räume stehen heute an, wie oft, und wann das nächste Mal?”. Genau das tut mein Trigger-basierter Template Sensor binary_sensor.auto_vacuum_schedule.

Bevor wir in den YAML-Schlund steigen, zur Orientierung das Output-Schema, das der Sensor liefert. Sein State ist on, sobald ein clean-Fenster aktiv ist, sonst off. Die Attribute sind die interessante Stelle:

state: "off"  # oder "on", während eines clean-Fensters
attributes:
  today:
    areas:
      - wohnzimmer
      - flur
    repeat: 1
  next:
    areas:
      schlafzimmer: "2026-05-23"
      flur: "2026-05-22"
      wohnzimmer: "2026-05-22"
    repeat:
      once: "2026-05-22"

Und so sieht der Sensor in voller Schönheit aus:

- triggers:
    - trigger: homeassistant
      event: start
    - trigger: time_pattern
      hours: /1
  actions:
    - action: calendar.get_events
      data:
        start_date_time: "{{ now().date() }}"
        duration:
          days: 6
      target:
        entity_id: calendar.auto_vacuum
      response_variable: result
    - variables:
        clean_events: >
          {{ result["calendar.auto_vacuum"].events
              | selectattr("summary", "eq", "clean")
              | sort(attribute="start")
              | list }}
        next_areas: >
          {% set areas = result["calendar.auto_vacuum"].events
              | selectattr("summary", "search", "area:")
              | groupby(attribute="summary") %}
          {% set data = namespace(areas=[]) %}
          {% for area, items in areas %}
            {% set data.areas = data.areas + [(
              area | replace("area:", ""),
              items
                | sort(attribute="start")
                | map(attribute="start")
                | first
            )] %}
          {% endfor %}
          {{ dict(data.areas) }}
        next_repeat: >
          {% set repeat = result["calendar.auto_vacuum"].events
              | selectattr("summary", "search", "repeat:")
              | groupby(attribute="summary") %}
          {% set data = namespace(repeat=[]) %}
          {% for rep, items in repeat %}
            {% set data.repeat = data.repeat + [(
              rep | replace("repeat:", ""),
              items
                | sort(attribute="start")
                | map(attribute="start")
                | first
            )] %}
          {% endfor %}
          {{ dict(data.repeat) }}
  binary_sensor:
    - name: auto_vacuum_schedule
      unique_id: auto_vacuum_schedule
      state: >
        {% set clean_ev_start = clean_events
            | map(attribute="start")
            | map("as_datetime")
            | list %}
        {% set clean_ev_end = clean_events
            | map(attribute="end")
            | map("as_datetime")
            | list %}
        {% set clean_ev_map = zip(clean_ev_start, clean_ev_end) | list %}
        {{ clean_ev_map
            | rejectattr("0", "ge", now())
            | rejectattr("1", "lt", now())
            | list
            | count > 0 }}
      attributes:
        next: >
          {{ {
            "areas": next_areas,
            "repeat": next_repeat
          } }}
        today: >
          {% set data = namespace(areas=[], repeat=[]) %}
          {% for area in next_areas.keys() %}
            {% if (next_areas[area] | as_datetime).date() == now().date() %}
              {% set data.areas = data.areas + [area] %}
            {% endif %}
          {% endfor %}
          {% for rep in next_repeat.keys() %}
            {% if (next_repeat[rep] | as_datetime).date() == now().date() %}
              {% set data.repeat = data.repeat + [rep] %}
            {% endif %}
          {% endfor %}
          {{ {
            "areas": data.areas,
            "repeat":
              3 if "twice" in data.repeat
              else 2 if "once" in data.repeat
              else 1
          } }}

2a. Erläuterungen
#

Sieht nach viel aus, ist im Grunde aber überschaubar. Lass uns das einmal von oben nach unten durchgehen:

  1. Triggers. Der Sensor wird beim Home Assistant Start und einmal pro Stunde neu berechnet. Häufiger ist nicht nötig, weil sich der Kalender ohnehin nicht im Minutentakt ändert.
  2. calendar.get_events. Holt alle Events der nächsten sechs Tage und legt sie als result ab. Das ist die einzige externe Datenquelle, alles andere ist Rechenarbeit auf dem Ergebnis.
  3. Variable clean_events. Filtert auf die summary: clean-Einträge. Aus dieser Liste wird gleich der State berechnet.
  4. Variable next_areas. Gruppiert alle area:*-Events nach Bereich und schnappt sich pro Bereich den frühesten kommenden Termin. Ergibt das Dict im next.areas-Attribut.
  5. Variable next_repeat. Macht dasselbe für repeat:*-Events und liefert pro Wiederholungs-Typ (once, twice) den nächsten Termin.
  6. State. Vergleicht now() gegen die Start- und End-Zeiten der clean-Events. Sobald genau ein Fenster aktuell läuft, ist der Sensor on.
  7. Attribut next. Einfach die beiden Dicts gebündelt - das ist die Status-Ebene für die Todo-Liste.
  8. Attribut today. Filtert beide Dicts auf das heutige Datum. Aus den Wiederholungs-Treffern entsteht der numerische repeat-Wert: drei bei twice, zwei bei once, sonst eins. Das ist die Aktions-Ebene für die Automation.
Info

Beachte die Reihenfolge in der repeat-Logik: twice wird vor once geprüft. Wäre es umgekehrt, würde ein Tag, an dem beide Events liegen, fälschlich nur zwei Durchgänge bekommen. So gewinnt immer der höhere Wert.

Das schöne Detail an diesem Sensor ist, dass er komplett ohne Helfer auskommt. Keine input_*-Entities, keine externen Trigger-Quellen, kein Zustand außer dem Kalender. Wenn morgen mein Setup zerschießt, reichen Kalender plus Template-Sensor, um das System wieder ans Laufen zu bringen.

3. Das Script: Areas zu Roborock-Segmenten übersetzen
#

Home Assistant kennt Räume als area_id. Mein Roborock kennt Räume als numerische Segment-IDs, die er sich beim Mapping selbst vergibt. Das passt nicht zusammen. Also baue ich die Brücke in einem Skript namens script.turn_on_vacuum_segment_cleaning:

alias: Segmentreinigung starten
icon: mdi:robot-vacuum
fields:
  area:
    name: Raum
    description: Name des Raums
    required: true
    selector:
      area:
        multiple: true
  repeat:
    name: Wiederholungen
    description: Wie oft die Segmente gesaugt werden sollen
    required: false
    default: 1
    selector:
      number:
        min: 1
        max: 3
        step: 1
sequence:
  - action: roborock.get_maps
    data: {}
    target:
      entity_id: vacuum.roborock_s7
    response_variable: result
  - variables:
      segments: >
        {% set rooms = result["vacuum.roborock_s7"].maps
          | selectattr("name", "eq", "Obergeschoss")
          | map(attribute="rooms")
          | first %}
        {% set room_map = zip(
            rooms.values() | map("area_id"),
            rooms.keys()
          ) | list %}
        {{ room_map | selectattr("0", "in", area) | map(attribute="1") | list }}
  - action: vacuum.send_command
    data:
      command: app_segment_clean
      params:
        - segments: "{{ segments }}"
          repeat: "{{ repeat }}"
    target:
      entity_id: vacuum.roborock_s7

3a. Erläuterungen
#

Drei Schritte, drei Ideen:

  1. Das Script fragt die Roborock Integration per roborock.get_maps nach den bekannten Karten und legt die Antwort in result ab. Bei einer Karte pro Etage filtere ich gezielt die Karte namens Obergeschoss heraus.
  2. Aus den Räumen der Karte baue ich eine Mapping-Liste der Form (area_id, segment_id). Das ist das eigentliche Bindeglied zwischen Home-Assistant-Welt und Roborock-Welt.
  3. Anschließend filtere ich auf jene area_ids, die als Argument übergeben wurden, und feuere das proprietäre app_segment_clean-Kommando an den Sauger ab. Inklusive der gewünschten Wiederholungs-Anzahl.
Warning

Damit dieses Mapping funktioniert, müssen die Raumnamen im Roborock mit den Area-IDs in Home Assistant korrespondieren. Bei mir heißt der Roborock-Raum Wohnzimmer, die Area in HA wohnzimmer. Roborock leitet daraus dieselbe area_id ab. Wenn deine Namen abweichen, musst du die Map einmal manuell pflegen oder via Lookup-Tabelle ergänzen.

4. Die Trigger-Automation: “Saug, wenn’s niemanden stört”
#

Jetzt kommt der Klebstoff. Diese Automation entscheidet, wann der Sauger tatsächlich loslaufen darf:

alias: "Staubsauger: starten"
mode: single
trigger:
  - platform: state
    entity_id: input_select.presence_mode
    from: zuhause
    to: abwesend
    for: "00:15:00"
  - platform: state
    entity_id: person.partner
    to: not_home
    for: "00:30:00"
  - platform: time_pattern
    minutes: "/15"
    seconds: 40
  - platform: calendar
    entity_id: calendar.auto_vacuum
    event: start
condition:
  - condition: state
    entity_id: binary_sensor.auto_vacuum_schedule
    state: "on"
  - condition: state
    entity_id:
      - input_boolean.auto_vacuumed_today
      - input_boolean.vacation_mode
    state: "off"
  - condition: state
    entity_id: input_select.sleep_mode
    state: aus
  - condition: or
    conditions:
      - condition: state
        entity_id: input_select.presence_mode
        state: abwesend
        for: "00:15:00"
      - condition: not
        conditions:
          - condition: state
            entity_id: person.partner
            state: home
  - condition: state
    entity_id: media_player.wohnzimmer_tv
    state: "off"
    for: "00:10:00"
action:
  - action: script.turn_on_vacuum_segment_cleaning
    data:
      area: "{{ state_attr('binary_sensor.auto_vacuum_schedule', 'today').areas or [] }}"
      repeat: "{{ state_attr('binary_sensor.auto_vacuum_schedule', 'today').repeat or 1 }}"
  - wait_for_trigger:
      - platform: state
        entity_id: binary_sensor.roborock_s7_reinigen
        from: "off"
        to: "on"
    continue_on_timeout: true
    timeout: "00:05:00"
  - if:
      - condition: template
        value_template: "{{ not wait.trigger }}"
    then:
      - action: notify.mobile_app
        data:
          message: "Staubsauger sollte gestartet werden, reinigt aber nicht."
      - stop: "Der Staubsauger ist nicht losgefahren."
        error: true
  - action: input_boolean.turn_on
    target:
      entity_id: input_boolean.auto_vacuumed_today
  - action: vacuum.set_fan_speed
    target:
      entity_id: vacuum.roborock_s7
    data:
      fan_speed: max
  - action: select.select_option
    target:
      entity_id: select.roborock_s7_wisch_intensitat
    data:
      option: "off"

4a. Erläuterungen
#

Vier Trigger, eine Wahrheit:

  1. Presence-Mode wechselt auf abwesend für mindestens 15 Minuten. Wenn die ganze Familie das Haus verlässt, beginnt das Fenster.
  2. Partner geht außer Haus` für 30 Minuten. Mein Büro ist auf einem anderen Stockwerk, also kann gesaugt werden, wenn meine Frau nicht da ist.
  3. Alle 15 Minuten ein Tick, weil sich Zustände auch zwischendurch ändern können, ohne dass ein State-Trigger feuert.
  4. Kalender-Start eines clean-Events. Wenn das Zeitfenster aufgeht und gerade niemand da ist, soll der Sauger loslegen.

Die Conditions sind das eigentliche Hirn. Sie stellen sicher, dass der Sauger wirklich loslaufen darf:

  • binary_sensor.auto_vacuum_schedule muss on sein, sprich: heute steht etwas an und das Zeitfenster läuft.
  • Weder Urlaubsmodus noch heute schon gesaugt dürfen aktiv sein.
  • Kein Schlaf-Modus, kein laufender Fernseher seit mindestens 10 Minuten.
  • Die Anwesenheits-Bedingung wird im or-Block doppelt geprüft, damit das System bei einer einzelnen Person im Haus auch reagiert, sobald sie unterwegs ist.

Im action-Block wird das Script gerufen, dann fünf Minuten lang auf das Live-Signal “Sauger reinigt” gewartet. Springt er nicht an, gibt es eine Push-Notification - das hat mich am Anfang vor mehr als einem stillen Fehlversuch bewahrt 😄. Erfolg setzt das gesaugt-heute-Flag, schaltet den Lüfter auf maximale Saugstufe und deaktiviert die Wischfunktion, weil bei mir nur gesaugt wird.

Tip

Wer wischen will, lässt die select.select_option-Aktion einfach weg oder stellt sie auf den jeweilig sinnvollen Wert.

5. Die Todo-Liste: Status fürs Dashboard
#

Das Schöne an einem todo-Entity in Home Assistant ist, dass es als interaktive Liste auf dem Dashboard erscheint - inklusive Fälligkeitsdatum und Abhaken per Klick. Genau das wollte ich für meine Frau und mich: eine Anzeige, die zeigt, was heute ansteht und was schon erledigt ist.

Info

Klare Ansage vorweg, damit kein Missverständnis entsteht: die Todo-Liste ist in meinem Setup eine reine Statusanzeige, kein Steuer-Eingang. Die Trigger-Automation aus dem vorigen Kapitel liest sie nicht. Sie entscheidet allein anhand des Template-Sensors, welche Räume heute fällig sind. Die Todo-Liste wird also vom System geschrieben, aber nicht vom System gelesen.

Damit das Schreiben sauber funktioniert, kümmern sich zwei Automationen um die Liste: eine nächtliche Aufbau-Automation und eine Abhak-Automation nach erfolgreicher Reinigung.

5a. Nachts aufbauen
#

alias: "Staubsauger: Todos bauen"
mode: single
trigger:
  - platform: time
    at: "00:05:00"
action:
  - action: input_boolean.turn_off
    target:
      entity_id: input_boolean.auto_vacuumed_today
  - action: todo.get_items
    data:
      status:
        - completed
    response_variable: result
    target:
      entity_id: todo.auto_vacuum
  - repeat:
      for_each: "{{ result['todo.auto_vacuum']['items'] }}"
      sequence:
        - variables:
            new_due: >
              {% set nxt = state_attr("binary_sensor.auto_vacuum_schedule", "next").areas %}
              {{ nxt.get(repeat.item.summary | area_id) }}
        - if:
            - condition: template
              value_template: "{{ new_due is not none }}"
          then:
            - action: todo.update_item
              data:
                item: "{{ repeat.item.summary }}"
                status: needs_action
                due_date: "{{ new_due | as_timestamp | timestamp_custom('%Y-%m-%d') }}"
              target:
                entity_id: todo.auto_vacuum

5a. Erläuterungen
#

Diese Automation läuft um fünf nach Mitternacht und tut drei Dinge:

  1. Sie setzt das input_boolean.auto_vacuumed_today auf off, damit der neue Tag offen ist.
  2. Sie liest alle abgeschlossenen Items aus der Todo-Liste.
  3. Für jedes dieser Items prüft sie im next.areas-Attribut des Template-Sensors, wann der zugehörige Raum als Nächstes fällig ist. Stimmt das Datum, wird das Item wieder auf needs_action gesetzt und das Fälligkeitsdatum aktualisiert.

Die Filter-Zauberei mit repeat.item.summary | area_id ist die Stelle, an der die Magie greift: weil der Todo-Item-Titel exakt dem Raumnamen entspricht (zum Beispiel Wohnzimmer), kann Home Assistant daraus automatisch die area_id ableiten. Trennung der Zuständigkeiten, schon wieder.

5b. Nach Reinigung abhaken
#

alias: "Staubsauger: Todos abhaken"
mode: single
trigger:
  - platform: state
    entity_id: input_boolean.auto_vacuumed_today
    from: "off"
    to: "on"
action:
  - action: todo.get_items
    data:
      status:
        - needs_action
    response_variable: result
    target:
      entity_id: todo.auto_vacuum
  - repeat:
      for_each: "{{ result['todo.auto_vacuum']['items'] | selectattr('due', 'defined') | list }}"
      sequence:
        - if:
            - condition: template
              value_template: "{{ repeat.item.due | as_timestamp <= now().date() | as_timestamp }}"
          then:
            - action: todo.update_item
              data:
                item: "{{ repeat.item.summary }}"
                status: completed
              target:
                entity_id: todo.auto_vacuum

5b. Erläuterungen
#

Diese Automation triggert exakt dann, wenn input_boolean.auto_vacuumed_today von off auf on springt - also genau nach einer erfolgreichen automatischen Reinigung. Sie holt sich alle offenen Items und hakt jene ab, deren due-Datum heute oder früher liegt. Das deckt sich exakt mit den Räumen, die der Sauger gerade abgefahren hat.

Der input_boolean.auto_vacuumed_today ist hier das zentrale Signal, das die drei Automationen miteinander koppelt: er wird von der Trigger-Automation gesetzt, von der Abhak-Automation gelesen und von der Aufbau-Automation nachts zurückgesetzt. Ein Helfer, drei Rollen - so soll das sein 😄.

Was die Todo-Liste konkret leistet
#

Ergebnis: jeden Morgen schaut meine Frau aufs Dashboard und sieht “Wohnzimmer (heute), Flur (heute), Schlafzimmer (übermorgen)”. Sobald der Roboter fertig ist, fliegen die heutigen Räume in den erledigt-Stapel. Nachts wird die Liste neu sortiert und mit aktuellen Fälligkeitsdaten versehen.

Note

Manuelles Abhaken eines Items hat in diesem Setup keinen Einfluss auf die Reinigung. Wer also “Wohnzimmer” morgens abhakt, weil er mit dem Akkusauger durch war, sieht zwar die Liste hübscher aussehen, der Roboter fährt das Wohnzimmer aber trotzdem an. Das ist eine bewusste Designentscheidung: die Logik was wird gereinigt lebt im Kalender, nicht in der Todo-Liste. Wenn ich das ändern möchte, ändere ich den Kalender, nicht ein Häkchen.

Stolpersteine
#

Hier noch ein paar Beobachtungen aus dem Echtbetrieb:

Helfer-Inflation. Du brauchst mindestens drei Input-Booleans (auto_vacuumed_today, vacation_mode, plus eventuell weitere) und ein paar Input-Selects (presence_mode, sleep_mode). Das ist eine Menge Klick-Arbeit in der UI - lohnt sich aber, weil die Helfer in anderen Automationen wiederverwendet werden.

Karten-Namen sind fragil. Sobald du deine Roborock-Karte einmal umbenennst oder neu erstellst, ändern sich die Segment-IDs. Das Mapping im Script bleibt funktional, weil es über Namen läuft - aber genau hier liegt der Teufel im Detail.

Roborock cloud vs. local. Die offizielle Roborock Integration nutzt die Roborock-Cloud. Wer das nicht mag - ich kann das gut nachvollziehen, Stichwort Cloudzwang - findet auf GitHub Alternativen mit lokalem Zugriff. Das Setup hier funktioniert mit beiden, weil es nur die Standard-Services aufruft.

Wartezeit auf den Start. Manche Roborock-Modelle brauchen nach dem app_segment_clean-Kommando einige Sekunden, bis sie überhaupt aus der Dock fahren. Mein Timeout von fünf Minuten ist großzügig gewählt - es reichen wahrscheinlich zwei. Probier es aus.

Fazit
#

Was als zweijähriger Cliffhanger angefangen hat, ist heute eines der Setups, das mir im Alltag am wenigsten Aufmerksamkeit kostet und am meisten zurückgibt. Der Sauger läuft, wenn er soll. Er läuft nicht, wenn er nicht soll. Die Familie sieht den Status, ohne dass ich erklären müsste, was gerade automatisch passiert. Stichwort: Women Acceptance Factor, einmal mehr im grünen Bereich 😁.

Der eigentliche Aha-Moment war für mich, dass der Reinigungsplan jetzt textuell in einem Kalender lebt. Wenn ich morgen entscheide, dass das Schlafzimmer dreimal die Woche dran sein soll, ändere ich genau eine RRULE und der Rest der Pipeline zieht von selbst nach. Keine Skript-Anpassung, keine YAML-Migration, kein Helfer-Karussell.

Vielleicht magst du das Setup für dein Zuhause adaptieren. Vielleicht hast du eine bessere Idee, wie man das alles noch eleganter löst - dann schreib mir gern. Bis dahin: Viel Spaß beim Reinigen lassen 😎!


Das Titel-/Hintergrundbild stammt von YoonJae Baik auf Unsplash .

Verwandte Artikel