Das ist der erste Post einer Serie über den Umzug meiner Home-Assistant-Konfiguration von einer Instanz auf eine andere. Die alte Instanz läuft mit 2024.11.1 auf einer Azure-VM, die neue mit 2026.8.2 in Docker auf einem Hetzner-Server (was dieser Server kostet, steht in einem eigenen Post), und ich habe früher schon beschrieben, warum ich neu gebaut habe, statt zu aktualisieren. Die alte Instanz steuert KNX-Licht, Rollos und Heizung und liest einen PV-Wechselrichter per Modbus, in rund 4.800 Zeilen YAML. Beide Instanzen laufen eine Zeit lang nebeneinander, und die neue übernimmt Bereich für Bereich. Hier beschreibe ich die ersten Schritte: die neue Instanz an KNX-Bus und PV-Daten anbinden und ihre Zustände mit denen der alten vergleichen.
Die Regel für den Parallelbetrieb
Beide Instanzen hängen am selben KNX-Bus. Läuft dieselbe Automation auf beiden, passiert jede Aktion doppelt: Rollos bekommen zwei Befehle und mein Handy zwei Push-Nachrichten. Deshalb kommt jede übernommene Automation mit initial_state: false auf die neue Instanz. In meinen Notizen heißt das Schattenbetrieb. Ich schalte pro Bereich um und immer in derselben Reihenfolge. Zuerst schalte ich die Automation auf der alten Instanz aus, danach auf der neuen ein. Auf der neuen nehme ich außerdem initial_state: false aus dem YAML, sonst ist die Automation nach dem nächsten Neustart wieder aus.
# ein Package auf der NEUEN Instanz: übernommen, geladen, ausgeschaltet
automation:
- id: outdoor_light_on
alias: "Zeitsteuerung: Außenlicht ein"
initial_state: false # Schattenbetrieb, die alte Instanz schaltet noch
mode: single
triggers:
- trigger: time
at: input_datetime.outdoor_light_start
actions:
- action: switch.turn_on
target:
label_id: timer_outdoor_lightDie Bereiche sind nach Risiko geordnet. Energie und PV kamen zuerst, weil dieser Bereich vor allem rechnet und auf der neuen Instanz nichts steuert. Es folgen Helfer und Zeitsteuerung, dann Licht, Rollos und Heizung. Während aller Schritte in diesem Post liefen alle Automationen, die im Haus etwas schalten, weiter auf der alten Instanz.
Sensoren lesen, ohne auf den Bus zu schreiben
Automationen auf zwei Instanzen lassen sich erst sinnvoll vergleichen, wenn beide dieselben Zustände sehen. Ich habe 166 der 170 KNX-Entitäten übernommen, einschließlich der Kommentare aus der alten Config. Zwei Dinge habe ich bewusst weggelassen. Das eine ist expose, denn damit meldet Home Assistant selbst einen Zustand auf den Bus, und das ist aktives Senden. Das andere sind vier Schalter, bei denen ein versehentlicher Klick im neuen Dashboard echte Folgen hätte.
In aktuellen Versionen wird die KNX-Verbindung nicht mehr im YAML eingerichtet. Ich habe dafür den Einrichtungsdialog über die REST-API durchlaufen. Die neue Instanz bekam die zweite Tunnel-Adresse der KNX-Schnittstelle, die erste behält die alte. Zwei Dinge liefen anders als geplant. Der Config-Flow legt die Verbindung mit eingeschalteter Zustandsabfrage an und startet sie sofort. Die Option lässt sich erst danach im Options-Flow ändern, und bis dahin hatte die neue Instanz schon 96 Leseanfragen auf den Bus geschickt. Lesen ist harmlos, geplant hatte ich den Start trotzdem ohne jede Leseanfrage.
Die zweite Überraschung war, dass eine ausgeschaltete Zustandsabfrage nicht heißt, dass nie gelesen wird. Nach dem nächsten Neustart kamen weitere 52 Leseanfragen. Im Home-Assistant-Quellcode steht dazu der Kommentar True -> expire 60; False -> init. Aus bedeutet also einmal beim Start lesen und danach nie wieder. Für null Leseanfragen braucht jede einzelne Entität sync_state: false, und dann bleiben die Zustände unbekannt, bis zufällig ein Telegramm vorbeikommt. Für den Schattenbetrieb bin ich bei init geblieben: ein Abgleich beim Start, während die laufenden Abfragen bei der alten Instanz bleiben.
Die KNX-Integration speichert in dieser Version Telegramme in einer eigenen SQLite-Datenbank, so ließ sich hinterher auszählen, was die neue Instanz gesendet hatte. Das Ergebnis waren 148 Leseanfragen und 0 Schreibbefehle.
PV brauchte einen anderen Weg, weil der PV-Dongle nur wenige Modbus-Verbindungen verträgt. Die alte Instanz liest seit Längerem über einen kleinen Modbus-Cache-Server, der den Dongle alle 10 Sekunden abfragt und mehrere Clients bedient, und die neue Instanz habe ich an denselben Cache gehängt. Alle 17 Sensoren zeigen dieselben Werte wie auf der alten Instanz, mit Abweichungen nur in der letzten Nachkommastelle.
Gleiche Entity-IDs auf beiden Instanzen
Dashboards und Automationen der alten Instanz verweisen auf Entity-IDs. Weichen die IDs auf der neuen Instanz ab, muss beim Umzug jede Referenz angefasst werden. IDs entstehen aus dem Namen, und die alte Instanz hat über Jahre von Hand umbenannte IDs. Ich habe ein kleines Werkzeug geschrieben, das die Entity-Registry beider Instanzen über die WebSocket-API liest, Einträge über ihre unique_id zuordnet und auf der neuen Instanz umbenennt. Es hat 28 Entitäten umbenannt, und danach waren 183 von 183 zugeordneten IDs identisch.
Der Abgleich nur über die unique_id reicht bei KNX nicht. Die Integration nimmt die Gruppenadresse als unique_id, ein Bewegungsmelder, der ein Licht schaltet, und das Licht selbst haben deshalb dieselbe unique_id in verschiedenen Domains. Der erste Lauf hätte sechs Bewegungsmelder in Lampen umbenannt, und der Schlüssel ist jetzt Plattform plus Domain plus unique_id.
Die erste Automation, die auf beiden Instanzen läuft
Beim Licht hatte ich mit der meisten Arbeit gerechnet, aber dort hat Home Assistant kaum Logik. Die KNX-Bewegungsmelder schalten die Lampen selbst, direkt über den Bus, sodass das Licht auch geht, wenn Home Assistant ausfällt. Für eine Übersicht im Dashboard hatte ich in Home Assistant 7 Automationen, eine pro Melder, die den Zeitpunkt der letzten Bewegung in einen Helfer schreiben. Das Muster stammt aus diesem älteren Post. Die sieben unterschieden sich nur in zwei Namen, also wurde daraus eine Automation, die den Ziel-Helfer aus der Entity-ID des auslösenden Melders ableitet. Das gekürzte Beispiel unten enthält zwei der sieben Melder. Jeder Melder braucht dafür einen vorhandenen Datum-und-Zeit-Helfer mit passender Endung.
# eine Automation statt sieben, auf beiden Instanzen aktiv
automation:
- id: remember_last_motion
alias: "Letzte Bewegung je Melder merken"
mode: parallel # zwei Melder in derselben Sekunde
triggers:
- trigger: state
entity_id:
- binary_sensor.motion_detector_a
- binary_sensor.motion_detector_b
from: "off" # alt: nur to "on", das galt auch für unavailable -> on
to: "on"
actions:
- action: input_datetime.set_datetime
target:
entity_id: >-
{{ trigger.entity_id | replace('binary_sensor.motion_detector_', 'input_datetime.last_motion_') }}
data:
datetime: "{{ now().strftime('%Y-%m-%d %H:%M:%S') }}"Auch der Trigger hat sich geändert. Die alten Automationen reagierten auf on ohne from und lösten deshalb auch aus, wenn ein Melder nach einem Neustart oder KNX-Reconnect von unavailable auf on wechselte. Auf der alten Instanz stand der Wert für die letzte Bewegung eines Melders auf exakt der Sekunde, in der am selben Abend die KNX-Integration neu geladen worden war.
Diese Automation ist auf beiden Instanzen sofort aktiv. Sie schreibt nur in Helfer der eigenen Instanz und schickt nichts auf den Bus, zwei Instanzen, die parallel dasselbe mitschreiben, stören sich also nicht. Die Helfer-Werte der alten Instanz habe ich per REST-API übernommen und dann auf die nächste echte Bewegung gewartet, sie kam um 21:05:54. Beide Instanzen haben für diese Bewegung denselben Zeitstempel gespeichert, auf die Sekunde. Alle 7 Helfer waren auf beiden gleich, wobei ich die Ausgangswerte übernommen und nur dieses eine Ereignis beobachtet hatte. Das war der erste Punkt, an dem die neue Instanz nachweislich in Echtzeit dasselbe tat wie die alte. Sie hatte zu diesem Zeitpunkt 11 Automationen, die meisten davon noch im Schattenbetrieb.
Der erste vollständige Zustandsvergleich
Als Nächstes waren die 43 Rollos dran, bei denen ich mit viel Arbeit gerechnet hatte. Auch dort hat Home Assistant keine eigene Logik. Die Rollos werden über KNX-Taster und Zentralfunktionen direkt am Bus gefahren. Ich habe den Schritt stattdessen für einen Vergleich aller Zustände zwischen alt und neu genutzt, an einem Samstagmorgen nach der ersten Nacht. Verglichen habe ich nur Entitäten, die es auf beiden Instanzen gibt. Die Zustände stimmten bei 51 von 51 Lichtern überein, bei 11 von 11 Thermostaten, 43 von 43 Rollos, 32 von 33 Binärsensoren und 16 von 29 Schaltern. Die zwei Tageszähler für Energie stimmten auf die Nachkommastelle. Der eine abweichende Binärsensor ist gewollt, ein Kontakt, dessen Polarität ich auf der neuen Instanz an der Quelle korrigiert hatte.
Der Vergleich hat zwei Lücken aufgedeckt, die auf beiden Instanzen bestehen. Von den 43 Rollos sind 33 auf beiden unbekannt, weil im ETS-Projekt für diese Antriebe keine Positions- oder Endlagen-Rückmeldung angelegt ist. Zu dem Zeitpunkt ging ich davon aus, dass sich das im ETS beheben lässt. Ein späterer Blick in die Aktorprogramme zeigte, dass es bei den meisten dieser Antriebe eine Hardwaregrenze ist, dazu kommt ein eigener Beitrag in dieser Serie. Und 25 Schalter haben kein Status-Objekt. Home Assistant zeigt dort den zuletzt mitgelesenen Schaltwert, auch wenn der tatsächliche Zustand inzwischen anders ist. Wo die beiden Instanzen bei diesen Schaltern abweichen, zeigt die alte aus und die neue unbekannt. Ich halte unbekannt für die zutreffendere Anzeige, weil ich nicht weiß, wie alt der gespeicherte Wert aus auf der alten Instanz ist.
Was nicht doppelt laufen darf, und was offen ist
Benachrichtigungen sind ein anderer Fall als die Bewegungs-Automation. Ein Push bei Sonnenauf- und -untergang oder beim Heimkommen käme doppelt an, wenn beide Instanzen ihn eingeschaltet hätten, also bleiben diese Automationen auf der neuen im Schattenbetrieb. Umschalt-Befehle (toggle) sind die gefährlichste Kategorie im Parallelbetrieb. Ein doppeltes Ein ist bei Licht harmlos, und ein doppelter Umschalt-Befehl bewirkt das Gegenteil des Gewollten, deshalb werden solche Automationen immer zuerst auf der alten Instanz ausgeschaltet.
Dieser Post zeigt keine abgeschlossene Umschaltung eines Bereichs, der im Haus etwas bewirkt. Bis zum Vergleich hat weiterhin nur die alte Instanz geschaltet. Offen war zu diesem Zeitpunkt auch die fehlende Rückmeldung für 25 Schalter und 33 Rollos. Vier Tage später habe ich im ETS an den Objekten der Schaltaktoren das Lese-Flag gesetzt, und seitdem liest Home Assistant den Zustand von 52 Lichtern und Schaltern beim Start auf ihrer Schaltadresse.
Häufige Fragen
Können zwei Home-Assistant-Instanzen dieselbe KNX-Schnittstelle nutzen?
In meinem Aufbau ja. Die neue Instanz bekam die zweite Tunnel-Adresse der KNX-Schnittstelle, die erste behält die alte. Die automatische Suche braucht Multicast und fand von der neuen Instanz aus keinen Tunnel, das Formular ging also direkt in die manuelle Eingabe.
Verhindert eine ausgeschaltete Zustandsabfrage alle Leseanfragen auf dem KNX-Bus?
Nein. Beim Start liest die Integration weiterhin einmal, bei mir waren das 52 Leseanfragen. Erst sync_state: false an jeder Entität verhindert auch diese, und dann bleibt ein Zustand unbekannt, bis ein Telegramm kommt.
Welche Automationen dürfen auf beiden Instanzen gleichzeitig aktiv sein?
Nur solche, die in Helfer der eigenen Instanz schreiben und weder ein Gerät steuern noch eine Benachrichtigung schicken.



