Home Assistant Emulator

Emuliert einen minimalen Home Assistant Server, sodass Geräte mit Home-Assistant-Dashboard-Unterstützung beliebige Web-URLs anzeigen können.

Aktueller Release
1.46.1
Entwickler
krobi
Lizenz
MIT

Manche Wanddisplays sprechen ausschließlich mit einem Home-Assistant-Server. Sie durchlaufen die HA-Einrichtung und zeigen danach ein HA-Dashboard — und sonst nichts. hassemu beantwortet genau die Teile des HA-Protokolls, nach denen diese Displays fragen. Die Einrichtung geht dadurch durch, und anschließend schickt der Adapter das Display auf die Webseite deiner Wahl: eine VIS-Ansicht, ein Aura-Dashboard, Grafana, Node-RED, eine selbstgebaute Seite.

Der Adapter ist keine Home-Assistant-Anbindung. Es wird nichts aus HA importiert, und keine ioBroker-Datenpunkte werden als HA-Geräte angeboten. Der Adapter stellt nur so viel HA-Server dar, dass das Display ihn akzeptiert — und hält sich danach heraus.

Diese Seite ist die ausführliche Anleitung. Die README ist die Kurzfassung.

Voraussetzungen

  • Node.js 22 oder neuer
  • ioBroker js-controller 7.2.2 oder neuer
  • ioBroker Admin 8.0.11 oder neuer
  • Display und ioBroker im selben Netz

Der Adapter lauscht auf Port 8123, weil HA-Clients genau diesen Port erwarten; er ist nicht einstellbar. Deshalb läuft je ioBroker-Rechner normalerweise eine Instanz — eine zweite auf demselben Rechner geht nur, wenn jede an eine eigene Schnittstelle gebunden ist. Mehrere ioBroker-Rechner im Netz dürfen je eine betreiben; die Displays sehen dann getrennte Server.

Shelly Wall Display

Die Shelly-Wall-Display-Familie gibt es als ältere Modelle (Stargate, X2) und als neuere (XL, X2i, X1i, U1, D1). Ein Display erreicht hassemu auf einem von zwei Wegen:

  • über die eingebaute Home-Assistant-Seite — der ursprüngliche Weg; Firmware 2.7.0 hat sie nicht mehr als veraltet markiert
  • über die Home-Assistant-App auf dem Gerät ab Firmware 2.6.0 — sie durchläuft dieselbe Einrichtung wie die Companion-App auf einem Handy

hassemu bedient beide. Firmware 2.7.0 hat außerdem WebView-Cache leeren gebracht (Einstellungen → Home Assistant). Das löscht das Erkennungsmerkmal des Displays: Danach erscheint es einmal unter einer neuen Kennung und durchläuft die Einrichtung erneut. Den alten Eintrag über seinen remove-Knopf entfernen.

Einrichtung

1. Instanz anlegen

Adapter installieren, Instanz 0 starten. In den Instanz-Einstellungen musst du zunächst nichts ändern: mDNS ist an, die Anmeldung ist aus, und der Adapter lauscht auf allen Schnittstellen.

Hat dein ioBroker-Rechner mehrere Netzwerkkarten, stell Interface binden auf die, in der deine Displays hängen. Der Adapter kündigt sich unter dieser Adresse an — kündigt er eine an, die das Display nicht erreicht, ist das der häufigste Grund dafür, dass die Erkennung scheinbar klappt, die Verbindung danach aber nicht.

2. Server am Display eintragen

Am Display einen Home-Assistant-Server hinzufügen.

  • Mit mDNS findet das Display den Server von allein. Er erscheint unter dem Namen aus Service-Name (Vorgabe ioBroker).
  • Ohne mDNS — oder wenn das Display nicht sucht — die Adresse von Hand eintragen: http://<IP-deines-ioBroker>:8123. Es muss http sein, siehe Anmeldung und dein Netz.

Android 17 und neuer: Erlaube der Home-Assistant-App den Zugriff auf das lokale Netzwerk, wenn sie danach fragt. Ohne ihn findet die App hassemu nicht und erreicht es in deinem Netz auch nicht — hassemu läuft nur im Heimnetz, einen Umweg über eine Cloud gibt es nicht.

3. Einrichtung abschließen

Das Display durchläuft jetzt die HA-Anmeldung. Ist die Anmeldung aus, klickst du einfach durch. Ist sie an, gibst du Benutzernamen und Passwort aus den Instanz-Einstellungen ein.

Hinter diesem Klick tauschen Display und Adapter ein Zugangsmerkmal aus, und der Adapter hinterlegt ein Erkennungsmerkmal (Cookie) auf dem Display. Das ist von da an die Identität des Displays: Es übersteht Neustarts, Adresswechsel und Umbenennungen — deshalb behält ein Display seine Seite, ohne neu eingerichtet zu werden.

4. Das Display wartet jetzt

Ist die Einrichtung durch, zeigt das Display eine kleine Seite mit einer Geräte-Kennung. Diese Seite bedeutet: verbunden, aber noch keine Seite gewählt. Über die Kennung findest du das Display im Objektbaum wieder.

5. Dem Display sagen, was es zeigen soll

Im ioBroker-Objektbaum das Display unter hassemu.0.clients.<Kennung> öffnen und mode setzen:

  • eines der gefundenen Dashboards aus der Auswahlliste nehmen, oder
  • Manuelle URL wählen und die Adresse daneben in manualUrl eintragen.

Das Display lädt innerhalb von etwa 30 Sekunden neu.

Sollen alle Displays dieselbe Seite zeigen, nimm hassemu.0.global.mode (und global.manualUrl) und schalte global.enabled ein, statt jedes Display einzeln zu setzen.

Was ein Display anzeigt

Jedes Display trägt seinen eigenen mode. Der Adapter löst ihn bei jeder Anfrage auf:

modeWas das Display bekommt
eine URLdiese Seite
Manuelle URLwas in manualUrl dieses Displays steht
Globale URLworauf global.mode hinausläuft
--- (keine Wahl)die Warteseite mit der Geräte-Kennung

global.mode wird genauso aufgelöst, nur darf er selbst nicht Globale URL sein — das zeigte auf sich selbst, und der Adapter weist den Schreibvorgang ab.

Der Hauptschalter

global.enabled ist kein Zustand, in dem ein Display sein kann, sondern eine Sammelaktion über alle:

  • Einschalten setzt jedes Display auf Globale URL.
  • Ausschalten setzt jedes Display zurück auf ---.

Ausschalten stellt also nicht wieder her, was die Displays vorher hatten — es leert sie alle. Danach die gewünschten Displays einzeln setzen. Neue Displays starten immer auf ---, nie auf einer Seite, die du für sie nicht ausgewählt hast.

Was im Objektbaum liegt

hassemu.0.
├── info.
│   ├── connection      der Adapter läuft
│   ├── serverUuid      die Identität, an der die Displays den Server wiedererkennen
│   └── refreshUrls     Knopf: erneut nach Dashboards suchen
├── global.
│   ├── enabled         Hauptschalter (siehe oben)
│   ├── mode            die Seite für alle Displays, die auf Globale URL stehen
│   └── manualUrl       freie Adresse, genutzt wenn global.mode auf Manuelle URL steht
└── clients.
    └── <Kennung>       ein Eintrag je Display, benannt nach Hostname oder Adresse
        ├── mode        was dieses Display zeigt
        ├── manualUrl   freie Adresse, genutzt wenn mode auf Manuelle URL steht
        ├── resolvedUrl die Adresse, an die dieses Display tatsächlich geschickt wurde
        ├── ip          die Adresse, unter der das Display zuletzt gesehen wurde
        └── remove      Knopf: dieses Display vergessen

serverUuid ist gut zu kennen: Daran erkennen die Displays den Server wieder. Sie wird einmal erzeugt und behalten, damit ein Adapter-Neustart für das Display nicht wie ein anderer Server aussieht. Änderte sie sich, wollte sich jedes Display neu einrichten.

remove löscht den Eintrag und damit die Identität des Displays. Verbindet es sich das nächste Mal, ist es ein neues und startet auf ---. Gedacht für Displays, die du abgebaut hast; Einträge, die 30 Tage nicht gesehen wurden, räumt der Adapter ohnehin selbst weg.

resolvedUrl beantwortet die Frage „wo ist dieses Display tatsächlich gelandet". Der Wert ist nur lesbar und folgt jeder Änderung: Wählst du ein Dashboard, steht dessen Adresse drin; steht das Display auf Globale URL, das Ergebnis der globalen Einstellung; nimmst du die Auswahl zurück, ist er leer, weil das Display seine Startseite zeigt. Praktisch bei Displays auf Globale URL — sonst müsstest du dich für das Ergebnis durch zwei Einstellungen arbeiten.

ip ist nur zur Information. Displays werden über ihr Erkennungsmerkmal identifiziert, nicht über die Adresse — eine neue Adresse vom Router legt also keinen zweiten Eintrag an.

Die drei Seiten des Adapters

Neben deinem Dashboard kann das Display drei Seiten zeigen, die vom Adapter selbst kommen.

Die Warteseite — Geräte-Kennung und ein Hinweis. Bedeutet: verbunden, keine Seite gewählt. Sie lädt sich alle 15 Sekunden selbst neu und verschwindet damit von allein, sobald du einen Modus setzt.

„hassemu offline" — der Adapter ist gestoppt oder nicht erreichbar. Das Display merkt es nach etwa 1,5 Minuten, bietet einen Knopf zum Neuladen und kehrt von selbst zu deinem Dashboard zurück, sobald der Adapter wieder da ist. Eine Einschränkung: Ein Display, das startet, während der Adapter aus ist, kann diese Seite nicht laden und zeigt stattdessen seinen eigenen Verbindungsfehler.

„Weiterleitungsziel nicht erreichbar" — der Adapter läuft, aber die Seite, auf die er das Display schickt, antwortet nicht. Ohne diese Karte sähst du nur Schwarz. Sie nennt die Zieladresse und bietet Neuladen an; das Display kehrt von selbst zum Dashboard zurück, sobald das Ziel wieder antwortet.

Der Adapter urteilt dabei zurückhaltend: Jede HTTP-Antwort zählt als erreichbar, auch eine Anmeldeseite oder eine Fehlerseite — dort läuft ja ein Server. Nur eine abgelehnte Verbindung oder eine Zeitüberschreitung lässt die Karte erscheinen. Zertifikate prüft er nicht, denn bei einem Dashboard zu Hause sind selbstsignierte Zertifikate der Normalfall.

Woher die Auswahlliste kommt

Der Adapter durchsucht den ioBroker-Rechner nach Seiten, die sich anzubieten lohnen:

  • VIS und VIS-2 — ein Eintrag je Projekt und einer je Ansicht darin, für jede vorhandene web-Instanz
  • Aura — ein Eintrag je laufender Instanz, mit dem Port, auf den diese Instanz tatsächlich eingestellt ist
  • Admin-Kacheln — alles, was ein Adapter für die ioBroker-Startseite anbietet (Grafana, jarvis, material, deine eigene Web-Oberfläche …)

Gesucht wird beim Start und immer dann, wenn eine Adapter-Instanz dazukommt, verschwindet oder umkonfiguriert wird. Nach dem Anlegen oder Umbenennen eines VIS-2-Projekts oder einer Ansicht setzt du info.refreshUrls auf true, um ohne Adapter-Neustart neu zu suchen.

Wird etwas nicht gefunden, ist es nicht verloren: Manuelle URL wählen und die Adresse einsetzen. Adressen mit javascript:, data: oder file: weist der Adapter ab — das sind keine Seiten, das ist Programmcode.

Anmeldung und dein Netz

Alles auf Port 8123 läuft unverschlüsselt über HTTP. Das ist keine Abkürzung, sondern das, was die HA-Clients auf diesem Weg verlangen; HTTPS machen sie hier nicht mit. Daraus folgen zwei Dinge, die man klar sagen sollte:

  • Behandle Port 8123 als etwas, das nur in dein Heimnetz gehört. Leite ihn nicht aus dem Internet herein.
  • Ist die Anmeldung an, laufen Benutzername, Passwort und Zugangsmerkmale unverschlüsselt durch dein Netz. Die Anmeldung hält andere Geräte in deinem Netz von der HA-Schnittstelle fern — sie ist kein Schutz gegen eine Öffnung ins Internet.

Reverse-Proxy-Header vertrauen bleibt aus, solange nicht wirklich ein Reverse-Proxy davor steht, der die Verschlüsselung beendet und die vom Client mitgeschickten X-Forwarded-*-Header entfernt. Ohne einen solchen eingeschaltet, kann jedes Gerät bei jeder einzelnen Anfrage eine andere Adresse behaupten. Der Adapter protokolliert dann falsche Adressen, und seine Grenze für neue Display-Einträge je Adresse begrenzt nichts mehr. Seit Version 1.40.0 gibt es deshalb eine zweite Grenze, die nicht an der Adresse hängt — höchstens 100 neue Display-Einträge pro Stunde insgesamt. Eine Fehlkonfiguration kann die Datenbank damit nicht mehr vollschreiben. Displays funktionieren weiter, solange diese Grenze greift; sie bekommen nur keine gespeicherte Identität, bis der Schwall vorbei ist. Die Grenze deckelt den Schaden — sie macht die Einstellung nicht sicher.

Ports

PortRichtungWofür der Adapter ihn braucht
8123 / TCPeingehenddie HA-Schnittstelle, mit der das Display spricht
5353 / UDPeingehendmDNS, damit Displays den Server von allein finden

Für Uptime-Monitore und Container-Healthchecks http://<IP-deines-ioBroker>:8123/health nehmen. Diese Adresse antwortet, ohne etwas anzulegen. Ein GET / ist das, was ein Display bei seinem ersten Besuch schickt — ein Monitor dort erschiene als neues Display; ein HEAD / legt nichts an.

Häufige Fragen

Kann ich zwei Instanzen betreiben? Nicht auf derselben Schnittstelle. Port 8123 ist von den HA-Clients vorgegeben, also gehen zwei Instanzen auf einem Rechner nur, wenn jede an eine eigene Schnittstelle gebunden ist. Zwei ioBroker-Rechner dürfen je eine betreiben; die Displays sehen dann zwei getrennte Server.

Muss das Display dauerhaft mit dem Adapter verbunden bleiben? Ja. Es holt seine Seite über den Adapter, und die Offline-Seite wie auch die Ziel-Prüfung hängen daran. Stoppt der Adapter, bleibt das Dashboard noch etwa 1,5 Minuten stehen; dann zeigt das Display die Offline-Seite und kehrt von selbst zum Dashboard zurück, sobald der Adapter wieder da ist.

Kann ich ein Display umbenennen? Ja — das Objekt clients.<Kennung> im Objektbaum umbenennen. Der Adapter behält deinen Namen und überschreibt ihn nicht, auch nicht, wenn sich Adresse oder Hostname des Displays ändern.

Warum gibt es zwei Einträge für dasselbe Display? Das Display hat sein Erkennungsmerkmal nicht zurückgeschickt — meist nach einem Zurücksetzen auf Werkseinstellungen, einem geleerten Browser- oder WebView-Speicher (Shelly ab Firmware 2.7.0: Einstellungen → Home Assistant) oder in einem Privatmodus, der Cookies verwirft. Den alten Eintrag über seinen remove-Knopf entfernen. Die Ursache liegt am Display, nicht am Adapter.

Brauche ich ein installiertes Home Assistant? Nein. Der Adapter beantwortet das HA-Protokoll selbst. In diesem Aufbau gibt es nirgends ein Home Assistant.

Kann das Display ioBroker steuern? Nein. Über die Verbindung laufen die Einrichtung und die Seitenadresse, sonst nichts. Es werden keine Datenpunkte angeboten und keine Befehle angenommen.

Herausfinden, was schiefgelaufen ist

Stell die Protokollstufe der Instanz auf debug. Der Adapter schreibt dann jede Entscheidung mit: welches Display erkannt wurde, wie die Anmeldung lief, welche Dashboards gefunden wurden, und wie er den Modus je Anfrage zu einer Adresse aufgelöst hat. Die meisten Probleme lassen sich direkt aus diesem Protokoll ablesen.

Ist mDNS an, im Protokoll steht aber keine Zeile mDNS: Broadcasting, ging die Ankündigung nicht raus — meist, weil etwas anderes Port 5353 belegt. Dann mDNS ausschalten und die Adresse am Display von Hand eintragen; alles Übrige bleibt gleich.

Findet die Home-Assistant-App unter Android 17 oder neuer nichts und verbindet sich auch mit von Hand eingetragener Adresse nicht, fehlt ihr der Zugriff auf das lokale Netzwerk — in den App-Einstellungen erlauben.

Changelog

1.46.1 (2026-09-25) — stable

  • Improved: switching the master switch and refreshing the dashboard list now log their result — how many displays changed and how many dashboards were found

1.46.0 (2026-09-25)

  • Fixed: a start that fails (port briefly in use, database not up yet) now restarts after 30 seconds instead of leaving the instance off until someone starts it by hand
  • Fixed: displays are no longer all removed after the adapter or its host was off for more than 30 days — the cleanup now counts from the most recently seen display
  • Fixed: an update from 1.0 or 1.1 no longer resets the global URL choice on every start — the URL you had set before the update stays in place for good
  • Fixed: on iOS the Home Assistant app no longer keeps its loading screen over the dashboard, and on Android the bottom of the dashboard no longer hides behind the navigation bar
  • Fixed: uptime monitors and container health checks no longer create display entries, and the adapter settings name the /health address meant for them
  • Fixed: stopping the adapter no longer waits on open connections or hangs while a display is mid-request, and a stop during the start no longer brings the server up
  • Fixed: room and function assignments move along reliably when an old datapoint is replaced, and a read error no longer gives the server a new identity
  • Changed: the sign-in hands its code to an unknown address only after a click on Continue, and a signed-in app is disconnected when its display is removed
  • Improved: mDNS announces an address the displays can reach — no link-local, container or VPN address — and announces again when the host's address changes
  • Improved: the reverse proxy option in the settings and the offline card on the display explain themselves in plain words, in all eleven languages

1.45.0 (2026-09-17) — stable

  • Fixed: refreshing the dashboard list no longer removes a display's mode datapoint from its rooms and functions, and the datapoint no longer disappears for a moment while it is rewritten
  • Fixed: a failed request or migration now names its cause instead of "[object Object]", and an unexpected error inside the web server no longer breaks its own error answer to the display
  • Improved: when updating from a version before 1.37.0, the room and function assignments of the renamed URL datapoints move to their successors instead of being lost

1.44.0 (2026-09-15)

  • Fixed: writing the master switch with the value it already has (a script re-asserting it) no longer resets every display's own choice — only a real change reaches the displays
  • Fixed: a disabled web instance no longer adds dashboard entries pointing at a port nobody listens on, and labels get an instance suffix only when more than one web server runs
  • Fixed: a display that signed in while the new-display throttle was active got a login that failed on its next request — the sign-in is now refused and works once the throttle lifts
  • Improved: a restart no longer rewrites every display's last-seen stamp and target address, and an instance with many displays comes up faster
  • Changed: the listen address moved to the standard setting key; an existing value is carried over automatically and the instance restarts once after the update
  • Changed: the instance settings now show the fixed port 8123, so the admin can warn when another instance on the same host already holds it

1.43.1 (2026-09-07)

  • Changed: the button that removes a display now carries a description — it deletes the display's folder and all its states, and the display returns as a new entry on its next request

License

MIT License

Copyright (c) 2026 krobi krobi@power-dreams.com

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


Developed with assistance from Claude.ai