Merge pull request 'Docs: README bereinigen (keine climate/RoomList/GetTemperatureIntent-Reste mehr)' (#2) from docs/readme-cleanup into main

Reviewed-on: #2
This commit was merged in pull request #2.
This commit is contained in:
2026-08-25 05:44:29 +02:00
2 changed files with 188 additions and 216 deletions
+22 -216
View File
@@ -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
+166
View File
@@ -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