From 3a4b0f897fed614837733ab052457af779371c11 Mon Sep 17 00:00:00 2001 From: Oliver Vogt Date: Tue, 25 Aug 2026 05:05:10 +0200 Subject: [PATCH 1/2] README.md: aktualisiert, keine climate/RoomList/GetTemperatureIntent-Reste mehr, verweist auf SETUP.md --- home-assistant-skill/README.md | 238 +++------------------------------ 1 file changed, 22 insertions(+), 216 deletions(-) diff --git a/home-assistant-skill/README.md b/home-assistant-skill/README.md index 2ec852a..edc10b7 100644 --- a/home-assistant-skill/README.md +++ b/home-assistant-skill/README.md @@ -1,11 +1,10 @@ # Home Assistant Alexa Skill -Ein privater, selbst gehosteter Alexa Custom Skill, mit dem du Home Assistant per Sprache abfragen kannst — Raumtemperaturen, Stromverbrauch, Stromkosten, sowie Waschmaschine und Trockner. Läuft als **Alexa-hosted Skill** (Node.js), keine eigene AWS-Infrastruktur nötig. +Ein privater, selbst gehosteter Alexa Custom Skill, mit dem du Home Assistant per Sprache abfragen kannst — Stromverbrauch, Stromkosten, sowie Waschmaschine und Trockner. Läuft als **Alexa-hosted Skill** (Node.js), keine eigene AWS-Infrastruktur nötig. + +**Hinweis:** Raumtemperaturen laufen mittlerweile **nicht mehr** über diesen Custom Skill, sondern über die native Nabu-Casa-Smart-Home-Integration (Entitäten in der Alexa-App den Räumen zugewiesen). Details dazu in [SETUP.md](SETUP.md). **Beispiele:** -> "Alexa, frag Home Assistant wie warm es im Wohnzimmer ist" -> → "Die Temperatur im Wohnzimmer beträgt 24.4 Grad." - > "Alexa, frag Home Assistant was ist die aktuelle Leistung" > → "Der aktuelle Stromverbrauch beträgt 645 Watt." @@ -24,17 +23,24 @@ Ein privater, selbst gehosteter Alexa Custom Skill, mit dem du Home Assistant pe ``` home-assistant-skill/ -├── index.js # Lambda-Handler (Alexa-hosted Skill Code) -├── package.json # Node-Abhängigkeiten (ask-sdk-core, dotenv, ...) -├── .env.example # Vorlage für HA_URL / HA_TOKEN -└── README.md # diese Anleitung +├── index.js # Config: ruft die Factories mit den echten Entity-IDs auf, +│ # registriert die Handler +├── factories.js # makeApplianceIntent, makeSimpleSensorIntent, +│ # makeSlotSensorIntent, PERIOD_PHRASES +├── ha-client.js # getHaState() - HA REST API Client +├── static-handlers.js # Launch/Help/Cancel/Fallback/Error (Pflicht-Handler) +├── package.json # Node-Abhängigkeiten (ask-sdk-core, dotenv, ...) +├── .env.example # Vorlage für HA_URL / HA_TOKEN +├── ARCHITECTURE.md # Details zur Factory-Struktur, Beispiele für neue Sensoren +├── SETUP.md # Vollständige Schritt-für-Schritt-Anleitung +└── README.md # diese Übersicht ``` --- ## Warum ein Custom Skill (statt nur die native Nabu-Casa-Integration)? -Home Assistant über Nabu Casa bietet bereits einen offiziellen **Smart Home Skill**, der native Sprachbefehle wie "Alexa, wie warm ist es im Wohnzimmer" *ohne* Skill-Namen unterstützt — das funktioniert zuverlässig, sobald die Entität freigegeben und einem Raum in der Alexa-App zugeordnet ist. Für **Temperatur** ist das die einfachste Lösung. +Home Assistant über Nabu Casa bietet bereits einen offiziellen **Smart Home Skill**, der native Sprachbefehle wie "Alexa, wie warm ist es im Wohnzimmer" *ohne* Skill-Namen unterstützt — das funktioniert zuverlässig, sobald die Entität freigegeben und einem Raum in der Alexa-App zugeordnet ist. Für **Temperatur** ist das die einfachste Lösung, und genau darüber laufen Temperaturabfragen bei uns inzwischen — nicht mehr über diesen Custom Skill. Für alles darüber hinaus (Stromverbrauch, Stromkosten, Gerätestatus wie Waschmaschine/Trockner) hat Alexa aber **keine eingebaute Sprachgrammatik** — die native Integration unterstützt praktisch nur Temperatursensoren. Dafür ist dieser Custom Skill gedacht. Nachteil: Du musst immer den Invocation Name sagen (z.B. "frag Home Assistant ..."), das ist eine feste Grammatikregel von Alexa für alle Custom Skills und lässt sich nicht umgehen. @@ -42,222 +48,22 @@ Für alles darüber hinaus (Stromverbrauch, Stromkosten, Gerätestatus wie Wasch ## Voraussetzungen -- Amazon Developer Account (Identitätsverifizierung ggf. erforderlich — Amazon fordert bei manchen Accounts einen Ausweis-Upload unter "Verify Identity") +- Amazon Developer Account (Identitätsverifizierung ggf. erforderlich) - Home Assistant Instanz, die per HTTPS von außen erreichbar ist (Nabu Casa Cloud, eigener Reverse Proxy oder Tunnel) - Long-Lived Access Token aus Home Assistant ---- +Die vollständige Schritt-für-Schritt-Anleitung (Skill anlegen, Intents, Slots, Code einrichten, Testen) steht in **[SETUP.md](SETUP.md)**. -## Schritt-für-Schritt-Anleitung - -### 1. Skill in der Alexa Developer Console anlegen - -1. Auf [developer.amazon.com](https://developer.amazon.com) einloggen → **Alexa** → **Alexa Skills Kit** -2. **Create Skill** -3. Namen vergeben (z.B. "HomeAssistantSkill") -4. Locale: **German (DE)** -5. Modell: **Custom** -6. Hosting-Methode: **Alexa-hosted (Node.js)** -7. Hosting-Region: **EU (Ireland)** (geringste Latenz für Nutzer in Europa) -8. Template: **Start from Scratch** -9. **Create Skill** klicken - -### 2. Invocation Name festlegen - -- Build-Tab → **Invocations** → Invocation Name setzen, z.B. `home assistant` -- Damit sprichst du den Skill später an: *"Alexa, frag home assistant ..."* -- Save klicken - -### 3. Slot Types anlegen - -**RoomList** (für Temperatur-Abfragen): - -- Build-Tab → **Slot Types** → **+ Add** → Namen `RoomList` → "Create custom slot type" -- Für jeden Raum einen **Value** eintragen, plus eine saubere **ID** (klein, ohne Umlaute/Leerzeichen): - -| Value | ID | -|---|---| -| Diele | diele | -| Gäste WC | gaeste_wc | -| Badezimmer | badezimmer | -| Balkon Hinten | balkon_hinten | -| Balkon Vorne | balkon_vorne | -| Kammer | kammer | -| Kinderzimmer | kinderzimmer | -| Schlafzimmer | schlafzimmer | -| Wohnzimmer | wohnzimmer | -| Küche | kueche | - -**PeriodList** (für Stromkosten-Abfragen): - -- Genauso vorgehen, Namen `PeriodList`: - -| Value | ID | -|---|---| -| Tag | tag | -| Woche | woche | -| Monat | monat | - -Die ID ist jeweils wichtig: Der Code liest den sauberen, festen Wert über die Slot-Resolution aus — nicht den roh gesprochenen Text (der z.B. durch angehängte Wörter wie "ist" verfälscht sein kann). - -- Save klicken - -### 4. Intents anlegen - -Build-Tab → **Intents** → den vom Template vorgegebenen `HelloWorldIntent` löschen. Danach folgende fünf Intents anlegen (**+ Add Intent** → Namen eingeben → "Create custom intent" → Sample Utterances eintragen → Save): - -**GetTemperatureIntent** (mit Slot `{Room}`, Slot Type `RoomList`): -``` -wie warm ist es im {Room} -wie warm ist es in der {Room} -wie ist die temperatur im {Room} -wie ist die temperatur in der {Room} -temperatur im {Room} -``` -Beim ersten Eintippen von `{Room}` erscheint ein Popup "Create a new slot" → **Add** klicken. Danach im Bereich **Intent Slots** beim Slot `Room` als **Slot Type** `RoomList` auswählen. - -**GetPowerUsageIntent** (kein Slot): -``` -wie hoch ist der aktuelle stromverbrauch -was ist die aktuelle leistung -wie viel strom verbrauchen wir gerade -wie hoch ist die aktuelle leistung -``` - -**GetEnergyCostIntent** (mit Slot `{Period}`, Slot Type `PeriodList`): -``` -wie hoch sind die stromkosten diesen {Period} -was kostet der strom diesen {Period} -wie viel strom kosten haben wir diesen {Period} -stromkosten {Period} -``` -Genauso wie bei `{Room}`: Slot `Period` anlegen lassen, danach als Slot Type `PeriodList` zuweisen. - -**GetWashingMachineIntent** (kein Slot): -``` -wie lange läuft die waschmaschine noch -wann ist die waschmaschine fertig -ist die waschmaschine fertig -wie weit ist die waschmaschine -wie ist der fortschritt der waschmaschine -``` - -**GetDryerIntent** (kein Slot): -``` -wie lange läuft der trockner noch -wann ist der trockner fertig -ist der trockner fertig -wie weit ist der trockner -wie ist der fortschritt des trockners -``` - -> Die Standard-Intents `AMAZON.CancelIntent`, `AMAZON.HelpIntent`, `AMAZON.StopIntent`, `AMAZON.NavigateHomeIntent` und `AMAZON.FallbackIntent` bleiben unverändert — die sind Pflicht und werden im Code bereits gehandhabt. - -### 5. Modell bauen - -- Oben rechts **Build Skill** klicken (dauert ca. 1 Minute) -- **Wichtig:** Nach *jeder* Änderung an Utterances/Intents/Slots muss neu gebaut werden — sonst bleiben Änderungen im Simulator/auf dem Gerät unwirksam. Das ist der häufigste Grund, warum ein neuer Intent zunächst nur die Fallback-Antwort auslöst. - -### 6. Long-Lived Access Token in Home Assistant erstellen - -- In Home Assistant: Profil (unten links) → ganz nach unten scrollen zu **"Long-lived access tokens"** -- **Token erstellen** → Namen vergeben (z.B. "Alexa Skill") → Token **sofort kopieren** (wird nur einmal angezeigt) - -### 7. Code einrichten - -- Im Skill: Tab **Code** -- `index.js` Inhalt durch den Code aus diesem Repo ersetzen (`home-assistant-skill/index.js`) -- `package.json` Inhalt durch die Version aus diesem Repo ersetzen (enthält zusätzlich `dotenv`) -- Neue Datei `.env` anlegen (New File → Name `.env`, im `lambda`-Ordner, gleiche Ebene wie `index.js`) und Inhalt aus `.env.example` übernehmen, mit deinen echten Werten: - ``` - HA_URL=https://deine-ha-domain.de - HA_TOKEN=dein-long-lived-access-token - ``` - -> **Hinweis:** Alexa-hosted Skills bieten *keine* Environment-Variables-Oberfläche in der Konsole (im Gegensatz zu selbst verwalteten AWS-Lambda-Funktionen). Die `.env`-Datei ist daher die praktikabelste Lösung, um Secrets wenigstens von der Programmlogik getrennt zu halten. Sicherheitsrelevant bleibt sie trotzdem — nicht öffentlich teilen oder in ein öffentliches Repo pushen (dieses Gitea-Repo ist privat, das reicht für den Zweck). - -- Die Entity-IDs in `index.js` an deine echte Home-Assistant-Installation anpassen (siehe [Entity-Referenz](#entity-referenz) unten). Entity-IDs findest du in Home Assistant unter **Entwicklerwerkzeuge → Zustände**. - -- **Save** → **Deploy** klicken - -### 8. Testen - -- Tab **Test** → Skill-Testing auf **Development** stellen -- Im Simulator eintippen oder sprechen, z.B.: - ``` - frag home assistant wie warm es im wohnzimmer ist - frag home assistant was ist die aktuelle leistung - frag home assistant wie hoch sind die stromkosten diesen monat - frag home assistant wie lange läuft die waschmaschine noch - frag home assistant wie lange läuft der trockner noch - ``` -- Bei Erfolg antwortet der Simulator mit dem entsprechenden Wert -- Sobald es im Simulator funktioniert, ist der Skill automatisch auch auf allen Echo-Geräten verfügbar, die mit demselben Amazon-Konto verknüpft sind — keine separate Veröffentlichung nötig - ---- - -## Entity-Referenz - -Diese Home-Assistant-Entity-IDs sind aktuell in `index.js` hinterlegt und müssen ggf. an deine Installation angepasst werden: - -**Temperatur** (`roomToClimateEntity`): -```js -badezimmer: 'climate.badezimmer_heizungssteuerung', -kinderzimmer: 'climate.kinderzimmer_heizungssteuerung', -kueche: 'climate.kueche_heizungssteuerung', -schlafzimmer: 'climate.schlafzimmer_heizungssteuerung', -wohnzimmer: 'climate.wohnzimmer_heizungssteuerung', -``` - -**Stromverbrauch** (aktuelle Leistung in Watt): -```js -POWER_ENTITY = 'sensor.kammer_netzbezug_plus_keller_power_calc' -``` - -**Stromkosten** (je Zeitraum): -```js -tag: 'sensor.netzbezug_kosten_tag', -woche: 'sensor.netzbezug_kosten_woche', -monat: 'sensor.netzbezug_kosten_monat', -``` - -**Waschmaschine:** -```js -WASHING_MACHINE_STATUS_ENTITY = 'sensor.waschmaschine_betriebszustand' // optional, wird toleriert falls nicht vorhanden -WASHING_MACHINE_PROGRESS_ENTITY = 'sensor.waschmaschine_programm_fortschritt' // Prozent, z.B. "96" -WASHING_MACHINE_END_TIME_ENTITY = 'sensor.waschmaschine_programm_endzeit' // ISO-Zeitstempel, z.B. "2026-08-22T19:30:00+00:00" -``` - -**Trockner** (identisches Schema): -```js -DRYER_STATUS_ENTITY = 'sensor.trockner_betriebszustand' -DRYER_PROGRESS_ENTITY = 'sensor.trockner_programm_fortschritt' -DRYER_END_TIME_ENTITY = 'sensor.trockner_programm_endzeit' -``` - -**Wie die Waschmaschine/Trockner-Logik funktioniert:** -1. Falls der optionale `*_betriebszustand`-Sensor existiert und einen Wert wie `fertig`, `inaktiv`, `finished` oder `inactive` liefert → Antwort: "läuft aktuell nicht" -2. Falls Fortschritt oder Endzeit `unknown`/`unavailable`/`none` sind → ebenfalls "läuft aktuell nicht" -3. Ist die Endzeit bereits verstrichen → "ist fertig" -4. Sonst → Prozent gerundet + Endzeit als `HH:MM Uhr` in der Zeitzone `Europe/Berlin`, z.B. "ist 96 Prozent fertig und endet um 21:30 Uhr" - ---- - -## Fehlersuche - -- **Fehlermeldung im Simulator:** JSON Output rechts prüfen — zeigt meist den genauen Fehler (z.B. HTTP-Statuscode von Home Assistant) -- **"Das habe ich nicht verstanden" (Fallback) direkt nach dem Anlegen eines neuen Intents:** Meistens wurde nach dem Speichern der Utterances nicht auf **"Build Skill"** geklickt — das Modell im Simulator läuft dann noch gegen den alten Stand. -- **"Ich konnte keine Verbindung herstellen":** Prüfen, ob `HA_URL` korrekt ist (kein Pfad, kein abschließender Slash) und ob Home Assistant tatsächlich von außen per HTTPS erreichbar ist -- **"Ich kenne den Raum ... nicht":** Slot-Erkennung hat nicht gegriffen — meist hilft eine zusätzliche Sample Utterance mit der genauen Formulierung, die genutzt wurde, plus erneutes "Build Skill" -- **Zahlen werden falsch vorgelesen (z.B. Dezimalzahlen als Ziffernfolge statt als Zahl):** Alexas deutsche TTS-Engine liest Dezimalpunkte manchmal falsch vor. Lösung im Code: Werte runden (`Math.round`) bzw. mit Komma statt Punkt formatieren (`.toFixed(2).replace('.', ',')`) — ist für Stromverbrauch und -kosten bereits so umgesetzt. -- **Ausführlichere Logs:** Code-Tab → **CloudWatch Logs** (führt zu den AWS-Logs der Lambda-Funktion) +Details zur Code-Architektur (Factory-Funktionen, wie man neue Sensoren/Geräte ergänzt) stehen in **[ARCHITECTURE.md](ARCHITECTURE.md)**. --- ## Status -✅ `GetTemperatureIntent` — Raumtemperaturen -✅ `GetPowerUsageIntent` — aktueller Stromverbrauch +✅ `GetPowerUsageIntent` — aktueller Stromverbrauch (Netzbezug + Keller) +✅ `GetPowerKammerUsageIntent` — aktueller Stromverbrauch Kammer-Serverschrank ✅ `GetEnergyCostIntent` — Stromkosten nach Tag/Woche/Monat +✅ `GetEnergyCostKammerIntent` — Stromkosten Kammer-Serverschrank nach Tag/Woche/Monat ✅ `GetWashingMachineIntent` — Waschmaschinen-Fortschritt und Endzeit ✅ `GetDryerIntent` — Trockner-Fortschritt und Endzeit +✅ Temperatur — läuft über native Nabu-Casa-Smart-Home-Integration, nicht mehr über diesen Skill From 70946ffac3ea34050facc3d3d11a8ee77ff37c0c Mon Sep 17 00:00:00 2001 From: Oliver Vogt Date: Tue, 25 Aug 2026 05:07:34 +0200 Subject: [PATCH 2/2] =?UTF-8?q?SETUP.md:=20vollst=C3=A4ndige=20Schritt-f?= =?UTF-8?q?=C3=BCr-Schritt-Anleitung,=20ohne=20Temperatur/RoomList-Reste?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- home-assistant-skill/SETUP.md | 166 ++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 home-assistant-skill/SETUP.md diff --git a/home-assistant-skill/SETUP.md b/home-assistant-skill/SETUP.md new file mode 100644 index 0000000..664563e --- /dev/null +++ b/home-assistant-skill/SETUP.md @@ -0,0 +1,166 @@ +# Setup-Anleitung: Home Assistant Alexa Skill + +## Schritt-für-Schritt-Anleitung + +### 1. Skill in der Alexa Developer Console anlegen + +1. Auf [developer.amazon.com](https://developer.amazon.com) einloggen → **Alexa** → **Alexa Skills Kit** +2. **Create Skill** +3. Namen vergeben (z.B. "HomeAssistantSkill") +4. Locale: **German (DE)** +5. Modell: **Custom** +6. Hosting-Methode: **Alexa-hosted (Node.js)** +7. Hosting-Region: **EU (Ireland)** +8. Template: **Start from Scratch** +9. **Create Skill** klicken + +### 2. Invocation Name festlegen + +- Build-Tab → **Invocations** → Invocation Name setzen, z.B. `home assistant` +- Save klicken + +### 3. Slot Type anlegen + +**PeriodList** (für Stromkosten-Abfragen, wird von mehreren Intents wiederverwendet): + +- Build-Tab → **Slot Types** → **+ Add** → Namen `PeriodList` → "Create custom slot type" + +| Value | ID | +|---|---| +| Tag | tag | +| Woche | woche | +| Monat | monat | + +Tipp: Beim Value "Tag" als Synonym z.B. "heute" ergänzen. + +Die ID ist wichtig: Der Code liest den sauberen, festen Wert über die Slot-Resolution aus. + +- Save klicken + +### 4. Intents anlegen + +Build-Tab → **Intents** → `HelloWorldIntent` löschen. Danach folgende Intents anlegen: + +**GetPowerUsageIntent** (kein Slot): +``` +wie hoch ist der aktuelle stromverbrauch +was ist die aktuelle leistung +wie viel strom verbrauchen wir gerade +``` + +**GetPowerKammerUsageIntent** (kein Slot): +``` +wie hoch ist der aktuelle stromverbrauch in der kammer +was ist die aktuelle leistung in der kammer +``` + +**GetEnergyCostIntent** (mit Slot `{Period}`, Slot Type `PeriodList`): +``` +wie hoch sind die stromkosten diesen {Period} +wie hoch sind die stromkosten {Period} +was kostet der strom diesen {Period} +``` +Beim Eintippen von `{Period}` Popup "Create a new slot" → **Add**. Danach bei Intent Slots `Period` als Slot Type `PeriodList`. + +**GetEnergyCostKammerIntent** (mit Slot `{Period}`, Slot Type `PeriodList`): +``` +wie hoch sind die stromkosten für die kammer diesen {Period} +was kostet die kammer diesen {Period} +``` + +**GetWashingMachineIntent** (kein Slot): +``` +wie lange läuft die waschmaschine noch +wann ist die waschmaschine fertig +ist die waschmaschine fertig +``` + +**GetDryerIntent** (kein Slot): +``` +wie lange läuft der trockner noch +wann ist der trockner fertig +ist der trockner fertig +``` + +> Die Standard-Intents (Cancel/Help/Stop/NavigateHome/Fallback) bleiben unverändert. + +### 5. Modell bauen + +- Oben rechts **Build Skill** klicken +- Nach *jeder* Änderung an Utterances/Intents/Slots muss neu gebaut werden. + +### 6. Long-Lived Access Token erstellen + +- Home Assistant: Profil → runterscrollen zu **"Long-lived access tokens"** → Token erstellen → sofort kopieren + +### 7. Code einrichten + +- Skill → Tab **Code** +- `index.js`, `factories.js`, `ha-client.js`, `static-handlers.js` aus diesem Repo übernehmen (per **New File** anlegen) +- `package.json` ersetzen +- Neue Datei `.env` anlegen, Inhalt aus `.env.example` mit echten Werten: + ``` + HA_URL=https://deine-ha-domain.de + HA_TOKEN=dein-long-lived-access-token + ``` +- Entity-IDs in `index.js` an deine Installation anpassen +- **Save** → **Deploy** + +### 8. Temperaturabfragen (native Integration) + +1. Home Assistant → Einstellungen → Sprachassistenten → Alexa → `climate`-Entitäten freigeben +2. Alexa-App: Gerät dem passenden Raum zuweisen +3. Falls nötig: Geräte neu suchen lassen +4. Danach: *"Alexa, wie warm ist es im Wohnzimmer"* — ohne Skill-Namen + +### 9. Testen + +- Tab **Test** → Development +- Simulator, z.B.: `frag home assistant was ist die aktuelle leistung` + +--- + +## Entity-Referenz + +**Stromverbrauch:** +```js +GetPowerUsageIntentHandler: 'sensor.kammer_netzbezug_plus_keller_power_calc' +GetPowerKammerUsageIntentHandler: 'sensor.kammer_serverschrank_leistung' +``` + +**Stromkosten:** +```js +// GetEnergyCostIntentHandler +tag: 'sensor.netzbezug_kosten_tag', +woche: 'sensor.netzbezug_kosten_woche', +monat: 'sensor.netzbezug_kosten_monat', + +// GetEnergyCostKammerIntentHandler +tag: 'sensor.kammer_serverschrank_kosten_tag', +woche: 'sensor.kammer_serverschrank_kosten_woche', +monat: 'sensor.kammer_serverschrank_kosten_monat', +``` + +**Waschmaschine:** +```js +statusEntity: 'sensor.waschmaschine_betriebszustand' +progressEntity: 'sensor.waschmaschine_programm_fortschritt' +endTimeEntity: 'sensor.waschmaschine_programm_endzeit' +``` + +**Trockner:** +```js +statusEntity: 'sensor.trockner_betriebszustand' +progressEntity: 'sensor.trockner_programm_fortschritt' +endTimeEntity: 'sensor.trockner_programm_endzeit' +``` + +--- + +## Fehlersuche + +- **Fehlermeldung im Simulator:** JSON Output rechts prüfen +- **Fallback direkt nach neuem Intent:** "Build Skill" vergessen +- **Keine Verbindung:** `HA_URL` prüfen (kein Pfad, kein Slash am Ende), HA von außen erreichbar? +- **Zahlen falsch vorgelesen:** Werte runden bzw. mit Komma formatieren (bereits umgesetzt) +- **Ausführliche Logs:** Code-Tab → CloudWatch Logs