(WIP) FHEMWEB interaktiv (speziell mit RHASSPY)

Begonnen von Beta-User, 03 April 2026, 11:24:46

Vorheriges Thema - Nächstes Thema

Prof. Dr. Peter Henning

Bei mir sieht das so aus

A: Nur Sprache
- Wakeword-Engine detektiert Wakeword
- Liefert Event an FHEM
- FHEM fordert beim AMAD-Device "activateVoiceInput" an
- Tablet zeigt Sprachaufforderung
- Sprache wird vom Tablet an Google geschickt, kommt als Text zurück
- Text wird vom AMAD-Device zur Auswertung an Babble gesendet

B: Spracheingabebutton in FTUI3
- Button-Event wird vom Tablet an FHEM gesendet
- FHEM fordert beim AMAD-Device "activateVoiceInput" an (6 verschiedene Tablets)
- Tablet zeigt Sprachaufforderung
- Sprache wird vom Tablet an Google geschickt, kommt als Text zurück
- Text wird vom AMAD-Device zur Auswertung an Babble gesendet

Das Problem ist jetzt erstens, dass je nach Auslastung der Tablets durch FTUI3-Aufgaben durchaus 1-2 Sekunden vergehen können, bis die Spracheingabe aufgeht.

Und zweitens, dass das dumme Automagic zusammen mit Google nicht in der Lage ist, nach einem Timeout (fehlende Spracheingabe ...) sauber abzubrechen. Sondern dann ab und zu ein Fehlerfenster auf dem Bildschirm des Tablets stehen bleibt, das man auch durch ein AMAD-Skript nicht wegbekommt.

LG

pah

Beta-User

Zitat von: Prof. Dr. Peter Henning am 18 April 2026, 17:07:45- FHEM fordert beim AMAD-Device "activateVoiceInput" an
[...]
- Text wird vom AMAD-Device zur Auswertung an Babble gesendet
Für den ersten Schritt "activateVoiceInput" kennen wir - immer vorausgesetzt, die Verbindung zum Browser auf dem Endgerät (nicht beschränkt auf Android!) steht - zwischenzeitlich drei Alternativen, RHASSPY verwendet (allerdings derzeit nur zur Fortsetzung der Dialoge) den js-Aufruf von f18_stt() via devspec.
my $aVICommand = $hash->{helper}->{SpeechDialog}->{config}->{$device}->{activateVoiceInput};
         3053        $aVICommand //= 'set $DEVICE activateVoiceInput' if InternalVal($device, 'TYPE', '') eq 'AMADDevice';
         3054        $aVICommand //= q({ my $js = "if((document.querySelector('input[name=\"fw_id\"]')||{}).value==='$hash->{FW_ID}'){f18_stt()}"; FW_directNotify("#FHEMWEB:$_", $js, "")
         3055                for devspec2array("TYPE=FHEMWEB"); }) if InternalVal($device, 'TYPE', '') eq 'FULLY';
         3056        $aVICommand //= q({ FW_AsyncOutput($defs{$DEVICE},'',qq/["#FHEMWEB:","f18_stt()",""]/)}) if InternalVal($device, 'TYPE', '') eq 'FHEMWEB';
Den Text greift dann entweder das FULLY-Device ab, oder RHASSPY per NotifyFn() auf FHEMWEB-Events; da muss ich noch eventuelle Doppelungen rausoperieren...
Server: HP-elitedesk@Debian 13, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

schwatter

Zitat von: Beta-User am 18 April 2026, 11:32:41
Zitat von: schwatter am 18 April 2026, 07:15:12Daher ignoriere mich einfach...
Ungern ;D .

Brauchst du denn jetzt noch eine Anleitung oder nicht? Ich hatte neulich auf Basis meiner hier geposteten Notizen auf einem Testsystem die Installation nochmal gemacht, und das hat da ohne größere Umstände funktioniert. Dabei habe ich die Installation erst mit meinem Standarduser gemacht, und dann danach die Rechte auf /opt/piper auf fhem:dialout geändert und in der systemd-unit-file fhem als User angegeben.

Danke erstmal nicht. Komme zu einem späteren Zeitpunkt darauf zurück. Mir schwirrt der Kopf. Gerade weil soviel
Nachholbedarf besteht und viele Sachen sich gerade vermischen.
Da kommt schon wieder die nächste Idee. Ich habe gerade neben Rudi seinem STT Button noch einen Audiobutton eingebaut.
Damit konnte ich erfolgreich eine MP3 abspielen. Im Modul TTS kann auch der Pfad in einem Adressraum geändert werden,
den der Browser versteht.
Ziel: Button 1 x drücken, JS im f18 lauscht dauerhaft nach neuen TTS-Events und spielt direkt immer die aktuelle MP3 ab.
Hier kommt dann das neue attr additionalInform TTS ins Spiel.

Gruß schwatter

Prof. Dr. Peter Henning

Welche STT-Engine wird denn in f18_stt() benutzt? Versteh ich noch nicht so ganz.

LG

pah

Beta-User

#34
Zitat von: Prof. Dr. Peter Henning am 20 April 2026, 05:37:44Welche STT-Engine wird denn in f18_stt() benutzt? Versteh ich noch nicht so ganz.
Nach meinem Verständnis: der auf dem Endgerät eingestellte Default.

Vermutlich also in der Regel bei Android Google.

Nachtrag: schwatter hat das für Firefox auch mal auf einen lokalen, eigenen Server konfiguriert.
Server: HP-elitedesk@Debian 13, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

schwatter

Nabend,

ja genau, die Google STT Engine. Der Platzhirsch leider. Sonst sieht es mau aus. Aber super für
kleine Leistungsschwache Server wie mein Intel(R) Celeron(R) J4105 CPU.

Ich hatte mal mit Whisper experimentiert. Da war damals eine dauerhafte Verbindung notwendig.
Problem war A) das fehlende Wakeword und B) mein Celeron zu schwach. Reagiert hat es zischen 10 bis 20sek.
Aber funktional war es.

Gruß schwatter

Prof. Dr. Peter Henning

#36
Für mich ist die entscheidende Frage, wie f18_stt bei einer fehlenden Spracheingabe reagiert - kommt man da wieder raus?. Ich habe es noch nicht ausprobieren können.

Der Witz bei Rivescript ist ja, dass man da komplexe Dialoge führen kann. Etwa
-> spiele Musik
<- wo und von wem soll ich musik spielen
-> im wohnzimmer
<- von wem soll ich im wohnzimmer musik spielen
-> von mozart
<- ok, ich werde im wohnzimmer musik von mozart spielen aus dem album die zauberflöte

Das habe ich an verschiedenen Stellen in meiner Rivescript-Umgebung realisiert. Schwachpunkt ist immer, dass man bei einem activateVoiceInput über AMAD innerhalb sehr kurzer Zeit etwas sagen muss, sonst bleibt die Spracheingabe mit einem Fehlerfenster hängen.

LG

pah

Beta-User

#37
Zitat von: Prof. Dr. Peter Henning am 21 April 2026, 05:16:13Für mich ist die entscheidende Frage, wie f18_stt bei einer fehlenden Spracheingabe reagiert - kommt man da wieder raus?
Derzeit (!) zeigt f18_stt() "einfach" ein Dialogfeld, das auch eine "abbrechen"-Schalftfläche hat. Nicht schön anzusehen, keine angenehme user-experience, wenn man einfach so was sagen will und erwartet, dass das dann auch passiert, ohne nochmal einen Klick zu machen, ABER: Mir wäre nicht bekannt, dass es irgendeine zeitliche Grenze gäbe, innerhalb derer man was gesagt haben müßte, und noch weniger, dass der js-Code irgendwann nicht mehr auf die "abbrechen"-Schaltfläche reagieren würde.
Zugegebenermaßen: Ausgetestet habe ich das nicht...

Der Punkt ist:
Wir haben es bei dem Browser/js-basierten Ansatz in der Hand, WAS genau passiert, und wenn es nicht funktioniert, können wir das ändern, für f18_stt() hat Rudi nach meinem Verständnis ausdrücklich offen gelassen, wie wir das weiterentwickeln wollen. Bei AMAD läuft im Hintergrund irgendeine App (automagic oder eben tasker, falls man das ans Laufen bekommt...), von der man eben nicht genau weiß, was sie wie tut, und welche Funktionen aus dem OS sie benötigt. Daher auch meine Aussage an anderer Stelle, dass "automagic" als Option für AMAD letztlich "tot" ist. 

Zitat von: Prof. Dr. Peter Henning am 21 April 2026, 05:16:13Der Witz bei Rivescript ist ja, dass man da komplexe Dialoge führen kann. Etwa [...]
Der Witz bei RHASSPY ist, dass man genau diese Art Dialog ebenfalls führen kann (das wäre ein CustomIntent mit Dialog), und genau dafür steht das "interaktiv" im Thread-Titel.
Und ja: Das funktioniert derzeit bereits mit f18_stt() (i.V.m. dem "mini-patch", der das Ende der jeweiligen Sprachausgabe als Event wirft) - nur ist die user-Experience noch nicht so, wie ich das gerne hätte ;) .

@Rudi - falls du hier mitliest: Scheinbar hatte ich bisher noch nicht meine modifizierte f18_speak() mit dem "bin fertig"-Event gezeigt.

Hier die Roh-Fassung:
function
f18_speak(txt)
{
  let synth = window.speechSynthesis;
  if(!synth)
    return FW_okDialog("No speechSynthesis available");

  const utterance = new SpeechSynthesisUtterance(txt);
   
  // Good practice: Set listeners even if they're unreliable on all voices
  utterance.onend = () => {
        var fw_id = $("body").attr("fw_id");
        FW_cmd(`${FW_root}?cmd=setreading `+
               `TYPE=FHEMWEB:FILTER=FW_ID=${fw_id}:FILTER=inform=.%2B `+
               `TTS_state finished&XHR=1`);
  };

  synth.speak(utterance);
  //speechSynthesis.speak(new SpeechSynthesisUtterance(txt));
  //see https://iifx.dev/en/articles/457363230/chrome-tts-workarounds-solving-the-speechsynthesisutterance-event-and-initial-speak-failure for more info
}

@schwatter: Ich würde mir sowas auch für die "Text2Speech-Automatik" aus https://forum.fhem.de/index.php?msg=1362354 wünschen. Den zugehörigen Code sehe ich mir bei Gelegenheit an (ein angehängtes diff wäre evtl. hilfreich, um sich direkt in die Materie reinzudenken), und habe auch noch nicht verstanden, warum man das nicht per notify aus FHEM heraus macht.
Server: HP-elitedesk@Debian 13, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors