Hinweis: Der Beitrag wurde mit KI-Unterstützung (Claude Code) verfasst und manuell nachbearbeitet.
HA Widgets — alle Teile: Teil 1: Überblick · Teil 2: Wie fängt man an? · Teil 3: Architektur · Teil 4: Architektur-Checks · Teil 5: HA-Infrastruktur · Teil 6: LCARS-Design
Teil 1 hat gezeigt was am Ende dabei rauskommt. Dieser Teil beschreibt den Einstieg: Claude Code einrichten, erstes Vue-3-Projekt aufsetzen, in HA als iFrame einbinden, erste WebSocket-Verbindung.
Claude Code einrichten
Claude Code ist ein CLI-Tool von Anthropic — KI im Terminal, die direkt mit den Dateien im Projektordner arbeitet. Kein grafisches Interface, kein Klicken. Man gibt Aufgaben in natürlicher Sprache, Claude liest und schreibt Dateien, schlägt Änderungen vor.
Installation (Node.js vorausgesetzt):
npm install -g @anthropic-ai/claude-code
Beim ersten Start einloggen:
claude
Der Login-Flow führt durch die Authentifizierung mit einem Anthropic-Account. Danach ist es einsatzbereit.
Wie man damit sinnvoll arbeitet
Claude Code ist kein Code-Generator. Sinnvoll eingesetzt ist es ein Pair-Programmer: beschreiben was man will, Vorschlag prüfen, korrigieren oder akzeptieren. Das Wichtigste: verstehen was passiert. Vorschläge nicht blind übernehmen.
Was gut funktioniert: - Architektur besprechen bevor Code geschrieben wird ("ich will X umsetzen, wie würdest du das angehen?") - Kleine, konkrete Aufgaben ("füge eine Computed-Property hinzu die X berechnet") - Fehlermeldungen direkt hineinkopieren und erklären lassen - Regeln definieren die Claude einhalten muss
Was nicht funktioniert: - Zu vage Aufgaben ("bau mir eine App") - Vorschläge ohne Lesen übernehmen
CLAUDE.md — das Regelwerk
Claude Code liest beim Start eine CLAUDE.md-Datei im Projektordner. Dort stehen Regeln, die bei jeder Interaktion gelten. Beispiele aus diesem Projekt:
- Kein
anyin TypeScript (einzige Ausnahme:catch (e: any)) - Kein
fetch()direkt in Vue-Komponenten — gehört in einen Composable - Keine hardcodierten Entity-IDs im Template
- Nach jeder Änderung:
npx tsc --noEmitin allen Apps
Ohne dieses Regelwerk driftet der Code über viele Sessions auseinander. Mit CLAUDE.md bleibt der Stil konsistent — Claude kennt die Regeln und hält sich daran.

Projekt aufsetzen
Vite ist der Build-Tool der Wahl für Vue 3. Neues Projekt anlegen:
npm create vite@latest meine-ha-app -- --template vue-ts
cd meine-ha-app
npm install
Das erzeugt ein Vue-3-Projekt mit TypeScript. Danach die HA WebSocket-Library installieren:
npm install home-assistant-js-websocket
Zum Entwickeln:
npm run dev
Der Dev-Server läuft unter http://localhost:5173. Noch keine HA-Verbindung, aber die App läuft.
Verbindung zu Home Assistant
Die Verbindung zu HA läuft über home-assistant-js-websocket. Nötig sind URL und ein Access Token.
Access Token anlegen: HA → Profil → Sicherheit → Langlebige Zugriffstoken.
Der elegante Teil: weil die App später als iFrame in HA läuft, ist window.location.origin automatisch die URL des HA-Servers. Kein Config-File, keine Umgebungsvariable.
const HA_URL = window.location.origin
Für das Token empfiehlt sich, es einmalig abzufragen und im localStorage zu speichern — dann ist es nicht im Quellcode und landet nicht versehentlich in einem Repository.
Beim ersten Start prüfen ob ein Token vorhanden ist:
const HA_TOKEN = localStorage.getItem('ha_token') ?? prompt('HA Access Token:') ?? ''
if (HA_TOKEN) localStorage.setItem('ha_token', HA_TOKEN)
Für ein echtes Projekt empfiehlt sich statt prompt() eine eigene Dialog-Komponente — mit Fehlerbehandlung und automatischem Retry bei ungültigem Token. Aber als Einstieg reicht das Prinzip oben.
Verbindung herstellen:
import { createConnection, createLongLivedTokenAuth } from 'home-assistant-js-websocket'
const auth = createLongLivedTokenAuth(HA_URL, HA_TOKEN)
const connection = await createConnection({ auth })
Das war's. Kein kompliziertes Auth-Handling, kein OAuth-Flow.
Ersten Sensor lesen
Mit bestehender Verbindung alle Entities abonnieren:
import { subscribeEntities } from 'home-assistant-js-websocket'
subscribeEntities(connection, (entities) => {
const temp = entities['sensor.temperatur_wohnzimmer']?.state
console.log(temp) // z.B. "21.4"
})
Der Callback wird bei jedem State-Update aufgerufen — kein Polling.
Ersten Schalter toggeln
import { callService } from 'home-assistant-js-websocket'
await callService(connection, 'light', 'toggle', { entity_id: 'light.licht_wohnzimmer' })
Das sind die zwei Grundbausteine: Entities abonnieren, Dienste aufrufen. Alles weitere baut darauf auf.
Die App in HA einbinden
Build erzeugen:
npm run build
Den Inhalt des dist/-Ordners auf den HA-Server kopieren, z.B. nach /config/www/meine-app/. In HA ist dieser Ordner dann unter /local/meine-app/ erreichbar.
Im Lovelace-Dashboard einbinden:
type: iframe
url: /local/meine-app/index.html
aspect_ratio: "16:9"
Cache-Busting nicht vergessen: Browser cachen iFrame-Inhalte aggressiv. Nach einem Update sieht man oft noch die alte Version. Lösung: einen Query-Parameter an die URL hängen der bei jedem Deploy geändert wird:
url: /local/meine-app/index.html?v=x7k2q
Das lässt sich im Deploy-Script automatisieren — zufälliger String, per HA-API ins Dashboard-YAML schreiben, Dashboard neu laden.
Wie geht es weiter?
Sobald eine App funktioniert und man merkt dass man mehr braucht — eine zweite App, gemeinsame Logik, Daten die hin- und herfließen — stellt sich die Architektur-Frage. Das ist Thema von Teil 3.
Fazit
- Claude Code per
npm install -g @anthropic-ai/claude-codeinstallieren - CLAUDE.md mit Coding-Regeln anlegen — hält den Stil über viele Sessions konsistent
- Projekt mit
npm create vite@latest -- --template vue-tsaufsetzen home-assistant-js-websocketfür die Verbindung:window.location.originals URL, Token im localStorage- Entities abonnieren per
subscribeEntities, Dienste aufrufen percallService - App als statische Dateien nach
/config/www/deployen, per iFrame-Card einbinden - Cache-Busting beim Deploy nicht vergessen
