FHEM Forum

FHEM => Frontends => Sprachsteuerung => Thema gestartet von: Beta-User am 03 April 2026, 11:24:46

Titel: (WIP) FHEMWEB interaktiv (speziell mit RHASSPY)
Beitrag von: Beta-User am 03 April 2026, 11:24:46
Hallo zusammen,

mal wieder ein "work in Progress"-Thread...

Was bisher geschah:
Rudi hat f18 etwas aufgebohrt, so dass man per Klick gesprochene Sprache an FHEM übermitteln kann, die Vorarbeiten (nochmals ein FETTES DANKE an @schwatter) sind in [Voicecontrol] Button für Fhemweb (https://forum.fhem.de/index.php?topic=144147.0) zu finden.

Mein Ausgangspunkt war eigentlich, das FULLY-Modul so zu erweitern, das es mit RHASSPY in Punkto Sprachein- und -ausgabe so zusammenarbeitet, wie das vorher mit AMAD möglich gewesen war, insbesondere also interaktive Dialoge möglich sind. Wie es im Moment aussieht, braucht es dafür aber auch einiges an javascript, so dass es letztlich (fast) völlig egal ist, welchen Browser man verwendet...

Wer hier also mit testen und entwickeln will: Am unkompliziertesten scheint Chrome (unter Android) zu sein, den man zwischenzeitlich auch mit FHEM als "WebApp" fullscreen starten kann (super Anleitung hier https://forum.fhem.de/index.php?msg=1360621).

Mein erster Stolpersteil war die Frage, wie man das Mikro wieder aktivieren kann. Dazu hier erst mal ein snipplet (Danke an schwatter für die Vorlage!), wie das mit dem in f18 eingebauten stt-Code geht:

        my $js = "if((document.querySelector('input[name=\"fw_id\"]')||{}).value==='$hash->{FW_ID}'){f18_stt()}";
        FW_directNotify("#FHEMWEB:$_", $js, "")
            for devspec2array("TYPE=FHEMWEB");

Was aus mir bisher nicht bekannten Gründen nicht funktioniert:
     
        FW_directNotify("#FHEMWEB:$_", "f18_stt()", "")
            for devspec2array("TYPE=FHEMWEB:FILTER=FW_ID=$hash->{FW_ID}");


Wo soll das hinführen?

1. Spracheingabe wird aktiviert
2. Man sagt was (z.B. "wie spät ist es")
3. Es gibt ein Event am FHEMWEB-Device, so dass identifizierbar ist, wo genau der Text eingesprochen wurde. Stand jetzt wäre es auch an der FULLY-Instanz sichtbar, und FULLY leitet das auch schon zur Beantwortung an RHASSPY weiter.
4. Das Event wird verarbeitet in einer NotifyFn() (bzw. in FULLY direkt per spezieller set-Anweisung), also ein Gerät wird geschaltet, oder hier einfach: Die Antwort auf die Frage wird ermittelt.
5. (optional): Der Antworttext wird in Audio umgewandelt
6. An der Stelle, von der die Frage (bzw. Anweisung) kam, erfolgt eine Ausgabe, entweder als TTS-Anweisung, oder als "play audio"-Befehl (mit FULLY+RHASSPY bereits als TTS-Anweisung funktional)
=> der Einsprechende erhält seine Rückmeldung.

7. (optional) Er kann eine weitere Anweisung einsprechen, oder ggf. eine Rückfrage beantworten. Hier kommt dann das obige snipplet zum Tragen, und das Spiel kann von vorne (bei 2.) beginnen. Das (nächste zu lösende) Problem ist demnach: Wann ist der richtige Zeitpunkt dafür? Tendenziell muss unser javascript noch ein paar Events erzeugen, aus dem man ablesen kann, was der Status der Audio-Geräte (Mikro/Sounausgabe) gerade ist.

Wie man sieht: Das hat im Kern wenig mit RHASSPY zu tun, das funktioniert auch z.B. mit Babble vermutlich kaum anders...

Das soll es für den Moment erst mal gewesen sein :) .

Wer mitexperimentieren will, kann sich einfach hier melden.
Titel: Aw: (WIP) FHEMWEB interaktiv (speziell mit RHASSPY)
Beitrag von: Beta-User am 03 April 2026, 21:00:25
Als Basis erst mal ein JavaScript auf Basis der Vorarbeit von schwatter. Liegt bei mir in www/pgm2 und ist via Javascripts-Attribut in FHEMWEB aktiviert.

Da ist im Moment noch nicht viel anders wie vorher, außer dass es unter Chromium@Linux nicht läuft, unter Chrome@Android aber schon...+

Anders ist:
- Der eingesprochene Text wird kurz angezeigt ("eigentlich" sollte das "on-the-fly" auch mit Teilen erfolgen...) und dann automatisch an FHEM übermittelt
- Die Aktivierung erfolgt im Moment nur durch Klicken, es sollte auch gehen, das von FHEM aus zu aktivieren.
- Da man dazu die FW_ID benötigt, erzeugt diese Version die STT-Events/Readings (auch*) an der temporären FHEMWEB-Instanz, die zur betreffenden Verbindung gehört.
*Zusätzlich kommt ein Event an der FULLY-Instanz, falls man fully als Browser benutzt und die deviceid paßt.

Braucht alles noch Feinschliff, geht erst mal v.a. drum, auch die Zwischenschritte zu dokumentieren...
Titel: Aw: (WIP) FHEMWEB interaktiv (speziell mit RHASSPY)
Beitrag von: schwatter am 03 April 2026, 21:06:16
Nabend,

zu dem Codesnippet oben. Wo probiert du das gerade aus? In Fully, FHEMWEB oder mit f18. Muss fragen,
da ich den Überblick verloren habe.
Vielleicht noch ein paar Details zu deinen Devices, um sich ein Bild zu machen.

Edit:
Ich sehe du hast schon geantwortet. Ich gehe mal dem Problem mit Chromium nach.
Ich muss gestehen, das ich hier und da geschrieben habe Chrome/Chromium funktioniert,
ich habe es aber nie selber ausprobiert. Bin einfach davon ausgegangen, datt geht.
Melde mich wegen Chromium.

Gruß schwatter
Titel: Aw: (WIP) FHEMWEB interaktiv (speziell mit RHASSPY)
Beitrag von: Beta-User am 03 April 2026, 21:31:29
Der JavaScript-Code wird via FHEMWEB-Instanz geladen, vermutlich werde ich dazu künftig zu weiteren Tests eine eigene Instanz aufmachen.

Das Mikro wird dann (außer bei Chromium@Linux) in FF@Linux/Android, Chrome@Android und fully unten angezeigt.

Getestet habe ich dann unter Android sowohl mit fully wie mit Chrome.

fully spricht den set-Command an der betreffenden FULLY-Instanz an, der dann (gesteuert über ein Attribut) den Text an RHASSPY weiterleitet. Das wertet (analog zu deinem notify, aber sehr viel differenzierter...) den Text aus, schaltet ggf. entsprechend der Anweisungen ("Schalte das Radio im Esszimmer und Wohnzimmer an und das Licht am Esstisch aus"...) und gibt Rückmeldung (als Text) an FULLY, der das dann an fully aussprechen läßt (derzeit...).

Chrome erzeugt im Moment nur Events. Der Plan ist, RHASSPY per NotifyFn() darauf anzusetzen und dann direkt in FHEMWEB (via FW_directNotify()) die Antwort aussprechen zu lassen. (Der Code ist im Prinzip derselbe wir für AMAD, also zu 90% schon da...)

Letzteres ist dann mein nächster Step, wobei dazu optimalerweise ein "speak" mit nachgelagertem "schalte das Mikro wieder scharf, wenn du fertig mit sprechen bist" in den Code kommt...

Raw-Definitionen von den Devices dürften im Moment nicht viel weiterhelfen. Doku zu RHASSPY gibt es ausführlich im Wiki (https://wiki.fhem.de/wiki/RHASSPY).
Auszugsweise, was man (außer, das in RHASSPY per devspec zu erfassen) konfigurieren muss, um das vernünftig (an/aus, Helligkeit, colortemp, Farbe...) aus RHASSPY heraus schalten zu können:
defmod Licht_Essen MQTT2_DEVICE zigbee_Esstisch
attr Licht_Essen genericDeviceType light
attr Licht_Essen rhasspyName licht am esstisch

Oder der Receiver:
defmod Yamaha_Main YAMAHA_AVR <IP-Adresse>
attr Yamaha_Main genericDeviceType media
attr Yamaha_Main rhasspyMapping GetNumeric:currentVal=volume,type=volume\
SetNumeric:currentVal=volume,cmd=volume,minVal=0,maxVal=99,step=2,type=volume\
SetOnOff:cmdOn=on,cmdOff=off\
GetOnOff:currentVal=state,valueOff=off\
GetState:response=Verstärker ist [Yamaha_Main:state] die Lautstärke ist [Yamaha_Main:volume]
attr Yamaha_Main rhasspyName verstärker,receiver,radio
attr Yamaha_Main rhasspyRoom wohnzimmer
attr Yamaha_Main rhasspySpecials scenes:scene1="Musik hören" scene2="Film ansehen" scene3=none scene4="vorderen Eingang auswählen"\
priority: inRoom=volume outsideRoom=volume,scene\
confirm: SetOnOff="wirklich $target $Value schalten?" SetScene

Ist das jetzt etwas klarer?
Titel: Aw: (WIP) FHEMWEB interaktiv (speziell mit RHASSPY)
Beitrag von: schwatter am 03 April 2026, 21:46:11
Ok,
danke. Dein JS habe ich kurz reingeschaut. Du hast einfach den Freischaltprocess ausgeschaltet um direkt Google SpeechToText zu starten.
Ja Chromium, da werde ich nochmal in Ruhe schauen warum der Button nicht auftaucht.
5 Minuten Suche im Internet hat mir aber offenbart, genau so schlecht wie bei Firefox.
Quasi wie ein AOSP Rom für ein Androidhandy. Der is blank. Keys kann man selber einbauen aber....ist mist. Fully z.B greift da auf Android Systemdienste zu.

Gruß schwatter
Titel: Aw: (WIP) FHEMWEB interaktiv (speziell mit RHASSPY)
Beitrag von: schwatter am 04 April 2026, 08:27:51
Moin,

hier mal ein Codeschnipsel mit dem du TextToSpeach machen kannst. 2ter Informchannel auf ein reading deiner
Wahl. Mein notify macht jetzt am Ende ein setreading voiceSpeak in global.

    function startExternalTunnel() {
        if (!isJamesActive) return;

        if (jamesSocket) jamesSocket.close();
        if (globalSocket) globalSocket.close();

        const protocol = location.protocol === "https:" ? "wss:" : "ws:";
        const combinedFilter = `(${DEVICE}|global)`;
        jamesSocket = new WebSocket(`${protocol}//${FHEM_IP}/fhem?XHR=1&inform=type=status;filter=${combinedFilter}`);

        jamesSocket.onmessage = (e) => {
            if (!isJamesActive) return;
            if (!isWaitingForCommand && !isSpeaking && e.data.includes(DEVICE) && e.data.includes(TRIGGER)) {
                startJamesSTT();
            }
            if (e.data.includes("global-voiceSpeak")) {
                let raw = e.data.split('global-voiceSpeak')[1];
                let txt = raw.replace(/^[^\w\däöüÄÖÜß]+/, '').split(/[",\]<]/)[0];
               
                txt = txt.replace(/_/g, ' ').trim();
                if (txt && txt !== "no" && txt !== "definition") {
                    showBubble("🤖 " + txt);
                    speak(txt);
                }
            }
        };
       
        jamesSocket.onopen = () => console.log("DEBUG: James-Kombi-Socket verbunden");
    }

edit:
Nochmal angepasst auf eine Websocketverbindung mit Filter.
 

Gruß schwatter
Titel: Aw: (WIP) FHEMWEB interaktiv (speziell mit RHASSPY)
Beitrag von: Beta-User am 04 April 2026, 09:28:31
Zitat von: schwatter am 03 April 2026, 21:46:11Ja Chromium, da werde ich nochmal in Ruhe schauen warum der Button nicht auftaucht.
Bei meinem Code dachte ich, es läge nach der JS-Konsole an der Syntax. Jetzt ist das Mikro aber auch an Chromium@Linux da. Es tut nur nix in Richtung STT-Reading :o .

Zitat von: schwatter am 04 April 2026, 08:27:512ter Informchannel auf ein reading deiner Wahl
:)
Der Ansatz, dafür einen socket von der JS-Seite her aufzumachen, will zumindest im Moment nicht zu meinen Design-Vorstellungen passen:
Der js-Code soll am Ende ganz ohne irgendwelche Vorab-Parametrierungen (const DEVICE = "atom_echos3r_9888e00f4280"; und so) auskommen, der diesbezügliche Block am Anfang ist im Moment nur noch deswegen drin, weil der Code erst mal nicht zu sehr verändert werden sollte, um die Lauffähigkeit zu erhalten ;D .

Die Idee wäre, aus dem Endgerät (und eventuell dem verwendeten wakeword oä.) abzulesen, wer da gerade sprechen will, um dann die Parametrierung des aktuell im Browser laufenden Codes und/oder von FHEM so anzupassen, dass z.B. "er" auf seinem Endgerät deutsche Ein- und Ausgaben erhält, und "sie" auf ihrem spanische...
(Oder die Kinder bestimmte Dinge nicht dürfen?)

Vielleicht wäre eine Funktion hilfreich, die einen JSON-Blob entgegennimmt, aus dem sich alle jeweils aktuell erforderlichen Infos ableiten lassen. Falls du da eine Idee hast: Gerne!!!
Titel: Aw: (WIP) FHEMWEB interaktiv (speziell mit RHASSPY)
Beitrag von: schwatter am 04 April 2026, 10:00:35
Ich konnte die Websocketverbindung auf eine reduzieren. Siehe oben. Aber so wie bei
dir, das passt auch nicht zu meinen Designvorstellungen. Problem, fhemweb.js
Lebt ihm hier und jetzt, bzw abonniert nur Devices bei Raum- oder Deviceübersicht.
Direkt ans Backendfiltern klappt nicht? Wenn doch, vielleicht hat wer ein Beispiel?
Oder ich bin gerade zu doof  :-[

Gruß schwatter
Titel: Aw: (WIP) FHEMWEB interaktiv (speziell mit RHASSPY)
Beitrag von: Beta-User am 04 April 2026, 11:48:18
Zitat von: schwatter am 04 April 2026, 10:00:35Lebt ihm hier und jetzt, bzw abonniert nur Devices bei Raum- oder Deviceübersicht.
Das ist in der Tat ein Problem.

Zitat von: schwatter am 04 April 2026, 10:00:35Wenn doch, vielleicht hat wer ein Beispiel?
Hmm, ich _glaube_, du hattest ein passendes Beispiel geliefert!!!

Meine Mikro-Aktivierung
Zitat von: Beta-User am 03 April 2026, 11:24:46        my $js = "if((document.querySelector('input[name=\"fw_id\"]')||{}).value==='$hash->{FW_ID}'){f18_stt()}";
        FW_directNotify("#FHEMWEB:$_", $js, "")
            for devspec2array("TYPE=FHEMWEB");
basiert auf deinem notify-Code, jetzt zu finden unter https://wiki.fhem.de/wiki/FHEMWEB/VoiceControl:_Web-STT_%26_Hardware-Wakeword#Beispiel:_notify, dort der Abschnitt #Hilfe.
Damit machst du was genau? Du sendest an eine mehr oder weniger unbekannte Stelle formatierten Text hin, um den in genau einem FHEMWEB-Client anzuzeigen... Das müßte doch eigentlich genauso für TTS-Infos gehen ;) , oder stehe ich auf dem Schlauch?