Zum Inhalt springen

FHEMWEB/VoiceControl: Web-STT & Hardware-Wakeword

Aus FHEMWiki
Mini
Mini

VoiceControl – Sprachsteuerung via Browser und Atom Echo S3

Diese Lösung ermöglicht eine flexible Sprachsteuerung für FHEM. Sprache wird in Text (Speech-to-Text) umgewandelt und als Reading STT im Device global bereitgestellt. Dieses Reading kann anschließend zentral (z. B. über notify oder DOIF) ausgewertet werden.

Das System unterstützt zwei unterschiedliche Wege zur Spracherfassung:

  • Weg 1️⃣ (Software): Browser-basierte Komplettlösung
  • Weg 2️⃣ (Hybrid): Hardware-Wakeword + Browser-Spracherkennung

Hilfe

Dort befinden sich in Post #1 auch alle benötigten Dateien.


Funktionen

Grundprinzip

  • Sprache → Speech-to-Text
  • Ergebnis → Reading STT im Device global
  • Zentrale Logik verarbeitet Befehle

Betriebsarten

  • Push-to-Talk (nur Browser)
  • Always-On mit Wakeword
  • Hardware-Wakeword (Hybrid)

Rückmeldungen

  • Sprachausgabe (TTS)
  • Visuelle Bubble im Browser
  • Optional gezielte Rückmeldung per Client-ID


Weg 1️⃣: Browser-Lösung (voicecontrol.js)

Das Script nutzt die Google Web Speech API. Unterstützt werden Chromium-basierte Browser (Chrome, Edge, Fully Browser). Firefox wird aktuell nicht unterstützt.

Bedienung

Push-to-Talk

  • Button gedrückt halten (~450 ms)
  • Direkt sprechen (kein Wakeword nötig)
  • Befehl wird sofort verarbeitet

Always-On

  • Kurzer Klick aktiviert Dauerbetrieb
  • Wakeword erforderlich (Standard: „James“)
  • Nach Aktivierung permanentes Mithören

Wakeword

  • Standard: james
  • Anpassbar im Script:
const wakewords = ["james"];

Ablauf:

  1. „James“ sagen
  2. System antwortet „Ja?“
  3. Zeitfenster (~6 Sekunden) für Befehl
  4. Danach automatische Verarbeitung oder Abbruch


Installation

Datei kopieren

voicecontrol.js nach: /opt/fhem/www/voicecontrol/

Einbindung

attr WEBphone JavaScripts voicecontrol/voicecontrol.js

Hinweis (HTTP ohne HTTPS)

Chrome benötigt Freigabe für Mikrofon:

  • chrome://flags/#unsafely-treat-insecure-origin-as-secure
  • Eigene URL hinzufügen
  • Auf Enabled setzen


Weg 2️⃣: Hybrid-Lösung mit Browser + Atom Echo (voicecontrol_echo.js)

Diese Variante kombiniert Hardware und Software:

  • Wakeword-Erkennung erfolgt auf dem ESP (Atom Echo S3)
  • Die eigentliche Sprachverarbeitung (Speech-to-Text) erfolgt im Browser

Funktionsweise

  1. Wakeword wird auf dem ESP erkannt
  2. FHEM erzeugt Event (z. B. james_detected)
  3. Browser empfängt Event via WebSocket
  4. Speech-to-Text startet im Browser
  5. Ergebnis wird an FHEM übertragen

Aktivierung

  • Kurzer Klick auf Button aktiviert/deaktiviert System
  • Baut WebSocket-Verbindung zu FHEM auf
  • Kein Push-to-Talk-Modus

Konfiguration im Javascript

const DEVICE  = "atom_echos3r_9888e00f4280";
const TRIGGER = "james_detected";
const FHEM_IP = "192.168.1.76:8085";
  • DEVICE → FHEM-Device des ESP
  • TRIGGER → Event bei Wakeword
  • FHEM_IP → FHEM-Server

Konfiguration in der Yaml

Damit sich der ESP mit eurem MQTT-Server und WLAN verbindet, müssen folgende Stellen angepasst werden.

  wifi:
    ssid: "YOUR_SSID"
    password: "YOUR_PW"
    fast_connect: true
  mqtt:
    broker: 192.168.1.76
    port: 1884
    username: "YOUR_USERNAME"
    password: "YOUR_PW"
    topic_prefix: atom_echo


Wakeword (ESP / ESPHome)

Das Wakeword wird direkt auf dem ESP definiert:

  • Umsetzung über ESPHome
  • Eine große Auswahl an Wakewords sind hier zu finden:
  https://github.com/TaterTotterson/microWakeWords

Hier ein Beispiel, wie das Wakeword definiert wird.

  micro_wake_word:
    id: mww
    microphone: echo_mic
    models:
      - model: "https://github.com/TaterTotterson/microWakeWords/raw/main/microWakeWordsV2/james.json"
        id: james_model
        probability_cutoff: 0.6   

Kommunikation

  • WebSocket-Verbindung zu FHEM
  • Lauscht auf Device-Events
  • Automatischer Reconnect bei Abbruch

Ablauf nach Wakeword

  1. System sagt „Ja?“
  2. Browser startet SpeechRecognition
  3. Nutzer spricht Befehl
  4. Befehl wird verarbeitet
  5. Rückmeldung „Erledigt“

Installation

siehe oben wie unter Punkt 1.

Zentrale Auswertung (Logik)

Beide Wege schreiben in:

global:STT

Die Verarbeitung erfolgt zentral über ein notify.

Beispiel: notify

defmod n_VoiceControl notify global:STT:.* {\
    # Parsing: Befehl und ID trennen\
    my ($cleanEvent, $clientId) = $EVENT =~ /^(.*)\s\[(.*)\]$/;;\
    $cleanEvent //= $EVENT;;\
    $clientId   //= "unknown";;\
    my $event_lc = lc($cleanEvent);;\
\
    # Befehlmapping\
    my %simpleCmds = (\
        "stt: esszimmer licht an"  => "set Lampe01_Ez on",\
        "stt: esszimmer licht aus" => "set Lampe01_Ez off",\
        "stt: küche licht an"      => "set Deckenlampe_Kue on",\
        "stt: küche licht aus"     => "set Deckenlampe_Kue off",\
        "stt: fernseher an"        => "set VuPlus on",\
        "stt: fernseher aus"       => "set VuPlus off",\
        "stt: lade roberto"        => "set MQTT2_valetudo_FlusteredUnequaledFish charge",\
        "stt: ambilight"    => '{ system("sshpass -p \'1431Fhem1982\' ssh -o StrictHostKeyChecking=no root\@192.168.1.46 \"/usr/share/hyperhdr/scripts/hyperhdr_toggle.sh\"") }',\
    );;\
\
    if (exists $simpleCmds{$event_lc}) {\
        fhem($simpleCmds{$event_lc});;\
    }\
\
    # Valetudo\
    elsif ($event_lc =~ /reinige/) {\
        my %rooms = (\
        "arbeitszimmer" =>"Arbeitszimmer",\
        "badezimmer"    =>"Badezimmer",\
        "esszimmer"     =>"Esszimmer",\
        "flur"          =>"Flur",\
        "küche"         =>"Küche",\
        "wohnzimmer"    =>"Wohnzimmer");;\
        my @found = grep { index($event_lc, $_) != -1 } keys %rooms;;\
        fhem("set MQTT2_valetudo_FlusteredUnequaledFish clean_segment ".join(",", map { $rooms{$_} } @found)) if @found;;\
    }\
    # Lampenscene\
    elsif ($event_lc =~ /ambiente/) {\
        if    ($event_lc =~ /(\d+)/) { my $b = ($1 > 255 ? 255 : ($1 < 1 ? 1 : $1));; fhem("set LampeSzeneAlle brightness $b") }\
        elsif ($event_lc =~ /an/)     { fhem("set LampeSzeneAlle on") }\
        elsif ($event_lc =~ /aus/)    { fhem("set LampeSzeneAlle off") }\
    }\
    # Kommandoübersicht\
    elsif ($event_lc =~ /kommandos/) {\
        my $h = '<div style="text-align:left;;min-width:200px;;font-family:sans-serif;;"><b>Befehlsübersicht:</b><br><br>';;\
        $h .= "• ".($_ =~ s/^stt: //r)."<br>" for sort keys %simpleCmds;;\
        $h .= "• reinige [küche, bad, ...]<br>• ambiente [an|aus|0-255]</div>";;\
        $h =~ s/'/\\"/g;;\
\
        my $js = "if((document.querySelector('input[name=\"fw_id\"]')||{}).value==='$clientId'){FW_okDialog('$h')}";;\
        FW_directNotify("#FHEMWEB:$_", $js, "")\
            for devspec2array("TYPE=FHEMWEB");;\
    }\
}


Unterschiede der Wege

Feature Browser Hybrid (Atom Echo S3)
Wakeword Browser ESP (Hardware)
Push-to-Talk Ja Nein
Always-On Ja (bedingt) Ja
Audioaufnahme Möglich Nur nach Trigger
Architektur Software Software + Hardware
Stabilität Stabil Sehr stabil (Wakeword extern)


FireOS mit Fully Browser (Plus)

Damit die Spracherkennung funktioniert:

  • Apps installieren:
  Google
  Speech Recognition & Synthesis
  • FireOS:
  „Tastatur und Sprache“ → „Text-to-Speech“
  • Fully Browser:
  Enable JavaScriptInterface (PLUS) aktivieren