VoiceButton für Fhemweb

Begonnen von schwatter, 14 März 2026, 17:25:25

Vorheriges Thema - Nächstes Thema

schwatter

Tag,

hier eine kleine JS Sammlung für Voicecontrol.

##########################################
# 1. VoiceButton
##########################################

# Zweck:
Der Button setzt beim Berühren einen Dummy auf 'on'
und beim Loslassen sofort wieder auf 'off'.
Geeignet, um ein Mikrofon-Device aufzuwecken.

# Schritt 1: Datei kopieren
voicebutton.js nach /opt/fhem/www/voicecontrol kopieren

# Schritt 2: JavaScript einbinden
attr WEBphone JavaScripts voicecontrol/voicebutton.js
# Schritt 3: Dummy-Modul erstellen
define VoiceButton dummy
attr VoiceButton readingList state
attr VoiceButton room Test
attr VoiceButton setList state

setstate VoiceButton off
setstate VoiceButton 2026-03-14 17:24:00 state off

# Schritt 4: FHEM neu starten
Änderungen speichern und FHEM neustarten

##########################################
# 2. VoiceControl (Speech-to-Text)
##########################################

# Zweck:
Wandelt Sprache in Text um und schreibt den Text in den Dummy VoiceControl(state).

# Schritt 1: Dateien kopieren
voicecontrol.js nach /opt/fhem/www/voicecontrol kopieren

# Schritt 2: JavaScript einbinden
attr WEBphone JavaScripts voicecontrol/voicecontrol.js
# Schritt 3: Auswertung
voicecontrol schreibt per setreading den Text nach global in das Reading STT.


# Schritt 4: Beispiel notify
defmod n_VoiceControl notify global:STT:.* {\
\
  fhem('setreading n_VoiceControl_Licht debug '.$EVENT);;\
\
  if ($EVENT eq "STT: Esszimmer Licht an") {\
    fhem("set Lampe01_Ez on");;\
    fhem("set TTS tts Im Esszimmer ist jetzt Licht an");;\
  }\
\
  elsif ($EVENT eq "STT: Esszimmer Licht aus") {\
    fhem("set Lampe01_Ez off");;\
    fhem("set TTS tts Im Esszimmer ist jetzt Licht aus");;\
  }\
\
  elsif ($EVENT =~ /Roberto reinige/) {\
\
    my @rooms;;\
\
    push @rooms, "Arbeitszimmer" if ($EVENT =~ /Arbeitszimmer/);;\
    push @rooms, "Badezimmer"    if ($EVENT =~ /Badezimmer/);;\
    push @rooms, "Esszimmer"     if ($EVENT =~ /Esszimmer/);;\
    push @rooms, "Flur"          if ($EVENT =~ /Flur/);;\
    push @rooms, "Küche"         if ($EVENT =~ /Küche/);;\
    push @rooms, "Wohnzimmer"    if ($EVENT =~ /Wohnzimmer/);;\
\
    if (@rooms) {\
      my $segments = join(",", @rooms);;\
      fhem("set MQTT2_valetudo_FlusteredUnequaledFish clean_segment $segments");;\
      fhem("set TTS tts Roberto reinigt jetzt $segments");;\
    }\
  }\
\
  elsif ($EVENT eq "STT: Roberto laden") {\
    fhem("set MQTT2_valetudo_FlusteredUnequaledFish charge");;\
  }\
\
}

setstate n_VoiceControl 2026-03-15 11:00:05
setstate n_VoiceControl 2026-03-15 10:37:56 debug STT: Roberto laden
setstate n_VoiceControl 2026-03-15 10:59:06 state active
setstate n_VoiceControl 2026-03-15 11:00:05 triggeredByDev global
setstate n_VoiceControl 2026-03-15 11:00:05 triggeredByEvent STT: Roberto laden

# Schritt 5: FHEM neu starten
Änderungen speichern und FHEM neustarten

# Hinweis für HTTP-Server ohne HTTPS:
In Chrome muss die Flag aktiviert werden: chrome://flags/#unsafely-treat-insecure-origin-as-secure
und die eigene Serveradresse hinzufügen, z.B.: http://192.168.178.50:8083
Für die Spracheingabe den Button dücken und halten.

Wichtig, denkt an den Browserrefresh mit STRG + F5


Gruß schwatter

schwatter

Aso, ich hatte auch mit webkitSpeechRecognition gespielt. Aber mein Chrome lässt mich nicht das Mikro
unter http freischalten. Da ist wohl https erforderlich  :( Oder irre ich mich?

Gruß schwatter

Dr. Boris Neubert

Zitat von: schwatter am 14 März 2026, 17:25:25defmod VoiceControl dummy
attr VoiceControl readingList state
attr VoiceControl room Test
attr VoiceControl setList state

setstate VoiceControl off
setstate VoiceControl 2026-03-14 17:24:00 state off

Wie ist denn das Widget mit dem Dummy verknüpft? Braucht man da nicht noch ein widgetOverride?
FHEM-Developer seit 2007, Mitgründer und Förder-Mitglied des FHEM e.V.
Bitte keine unaufgeforderten privaten Nachrichten!

schwatter

Das ist in dem JS voicebutton.js fest drinne

    function voiceOn() {
      console.log("Voice ON");
      FW_cmd('/fhem?cmd=set VoiceControl state on&XHR=1');
    }

    function voiceOff() {
      console.log("Voice OFF");
      FW_cmd('/fhem?cmd=set VoiceControl state off&XHR=1');
    }

Gruß schwatter

schwatter

Oh,

ok ich bin etwas weiter. Wer wie ich noch http benutzt kann in Chrome z.B
chrome://flags/#unsafely-treat-insecure-origin-as-secure aktivieren und in dem Feld
darunter den Link zu Fhem eintragen: http://192.168.1.76:8084
Jetzt habe ich zugriff auf das Mikro, bzw es ist freigeschaltet. Ich schaue mal.

Gruß schwatter

schwatter

Super,

jetzt funktioniert es. Am Laptop spinnt das Mikro. Konnte auf dem Handy gerade erfolgreich in den
state vom Dummy VoiceControl VoicetoText übertragen. Dazu beim sprechen den Button halten.
Update im ersten Post.

Gruß schwatter

rudolfkoenig

Ich habe f18.js mit STT erweitert.

Im Select-Style/f18 Menu gibt es einw STT Option, was das Micro oben einschaltet.

Beim Druecken auf das Micro kommt ein Dialog, da kann man was sagen, und das Ergebnis zu FHEM schicken.
In FHEM wird im dazugehoerigen FHEMWEB ein STT Reading gesetzt bzw. ein Event ausgeloest.
Die Sprache (DE oder EN) haengt vom "attr global language" ab, Voreinstellung ist EN.
Ich habe es mit Chromium, deutsch und englisch getestet. Es funktioniert auch ohne https.

schwatter

#7
Funktioniert!  :)

Aber bei mir mit http auf Chrome Android auch erst nachdem ich Insecure... aktiviert habe.
Vorher wird das Micro nicht aktiviert.

Edit:
Und bei mir werden relativ schnell doppelte/dreifache Wörter aufgenommen.
setstate WEBphone 2026-03-14 21:59:52 STT EsszimmerEsszimmerEsszimmerEsszimmer Licht Licht aus
Gruß schwatter

schwatter

Update im ersten Post.
Beispiel notify für den Voicebutton hinzugefügt.

Gruß schwatter

Beta-User

Wow!

Vielen Dank erst mal an euch beide!!! Kommt mir vor wie Ostern und Weihnachten zusammen ;D .

Habe erst mal zum Testen Rudis Variante aktiviert, weil das "direkt in FHEM" ohne große Umwege für die Allgemeinheit zur Verfügung steht. Erste Eindrücke (http):

- unter firefox@Linux kam "SpeechRecognition Interface missing"
- selbes Gerät, Chromium: Dialogfeld öffnet sich, aber ohne die Einstellung "chrome://flags/#unsafely-treat-insecure-origin-as-secure" passiert nichts. Wenn das für die FHEMWEB-Instanz freigegeben wird, kommt die Anfrage, ob man das Mikro freigeben will => OK. Leider wird dann aber immer noch nichts aufgenommen, das Mikro an sich ist aber an.

- firefox unter Android: wieder "SpeechRecognition Interface missing"
- chrome, Android: Nach Freigabe von "unsafely" und Mikrozugriff: Aufnahme, aber mit Wortwiederholungen (s.u.)
- fully, Android: Funktioniert ootb, aber mit Wortwiederholungen

Wortwiederholungen meint: Aus "Das ist ein Test" wird "setstate WEB 2026-03-15 07:19:02 STT dasdas istdas ist ein Test".
Es werden also (bereits im Dialogfeld so sichtbar) alle bereits erkannten Bestandteile wiederholt, sobald das nächste Wort fertig ist.

Ich vermute, dass man das Dialogfeld nach jedem Wort erst wieder leeren sollte?


Anmerkungen, Wünsche und Anregungen ::) :
  • Für "submit" würde ich mir (optional?) wünschen, dass das einfach nach einer "üblichen Ruhepause" beim Sprechen dann abgeschickt wird. Also: 2 Sekunden "silence" => automatisch absenden
  • Die Lösung via FHEMWEB hat mich zunächst irritiert, aber das ist generisch und funktioniert prinzipiell auf jedem Endgerät. SUPER!
  • Die Kehrseite: Einfache Texteingaben und notify sind nur ein sehr kleiner Ausschnitt dessen, was ich mir eigentlich vorstelle: Im Kern sollte das Ganze "dialogisch" ablaufen können, s.u.
  • Das Dialogfeld ist pragmatisch, aber als "hübsch" (im Sinne eines modern ausschauenden User-Interfaces) kann man das nicht wirklich bezeichnen ;D

Zum etwas größeren Bild, was schwebt mir eigentlich vor?

Verschiedene Endgeräte sollen dialogisch (per Sprachein- und -ausgabe) mit FHEM interagieren können.

Also sowas sollte möglich sein:
Zitat von: Beta-User am 19 November 2025, 07:31:05(ich) "Mach deutlich lauter"
(Handy) "soll das Radio im Wohnzimmer oder in der Küche lauter gemacht werden?"
(Anm: Sowas kann bei RHASSPY vorkommen, wenn grade beide Audio-Geräte angeschaltet sind und unklar ist, in welchem Raum sich der Sprechende befindet...)

Oder für sowas:
(ich) "Schalte den Fernseher aus"
(Handy) "soll ich wirklich den Fernseher ausschalten?"
(ich) "ja, mach!" (oder "ja bitte")
(Handy) "wird erledigt" (oder "okay", "aber gerne doch", "Aye, Sir!" usw.)

Hier läuft sowas (zumindest im Moment) mit RHASSPY, das ginge aber wohl genausogut mit Babble oder anderen FHEM-Methoden.

Dazu notwändig wäre m.E., dass man
  • zum einen identifizieren kann, von welchem Endgerät der STT-Text kam
  • dahin dann eine Rückmeldung (entweder Audio oder als TTS-Anweisung) senden kann, und
  • optimalerweise nach Ende der Ausgabe dieser Rückmeldung die Möglichkeit hätte, das Mikro wieder für weitere Eingaben zu aktivieren
Vermutlich liese sich der f18-js-Teil relativ leicht dahingehend aufbohren, dass zumindest klar ist, welche IP-Adresse das betreffende Endgerät hat, super wäre, direkt die betreffende Browser-Seite (asynchron) wieder ansprechen zu können (jedenfalls, solange diese offen ist). Keine Ahnung, ob das besonders kompliziert wäre...

Viele Wünsche, ich weiß O:-) .
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

#10
Moin,

- Ich finde FHEMWEB nicht ideal. Besser sowas wie global. Das ist leichter bei mehreren FHEMWEB's. Ein Knotenpunkt. Deswegen habe ich den dummy.
- Zu Dialog führen. Kann der Text nicht einfach per notify an Rhasspy weitergereicht werden?

Gruß schwatter

schwatter

Update im ersten Post - voicecontrol.js

- Der Text wird jetzt mit setreading nach global STT geschrieben. Dummy fällt weg.
- Es gibt eine 2te Bubble für den erkannten Text.

Gruß schwatter

Beta-User

#12
Zitat von: schwatter am 15 März 2026, 08:54:52- Zu Dialog führen. Kann der Text nicht einfach per notify an Rhasspy weitergereicht werden?
RHASSPY hat eine NotifyFn() und setzt -abängig von der Konfiguration- NOTIFYDEF derzeit maximal auf "TYPE=(AMADCommBridge|AMADDevice|ROOMMATE|GUEST),global"

AMAD.* ist der "historische" Weg, um über TTS-Ereignisse und das Ende von Sprachausgaben informiert zu werden, ROOMMATE und GUEST dienen zum Chatten (hier via Telegram). In allen Fällen wird "angefragter Text" dann an Rhasspy bzw. die dortige Intent-Auswertung übergeben und das Ergebnis dann wieder in FHEM verarbeitet, alles selbstredend asynchron. RHASSPY "merkt" sich dabei, wohin ggf. dann welche Rückmeldung von Rhasspy zu senden ist, so dass auch - theoretisch - viele parallele Sitzungen möglich sind.

 
Zitat von: schwatter am 15 März 2026, 08:54:52- Ich finde FHEMWEB nicht ideal. Besser sowas wie global. Das ist leichter bei mehreren FHEMWEB's. Ein Knotenpunkt. Deswegen habe ich den dummy.
Für meine Zwecke ist es letztlich egal, wo das Event ausgelöst wird. Das NOTIFYDEF auf TYPE=FHEMWEB auszuweiten wäre jedenfalls kein Problem, und auch (in den meisten Installationen) begrenzter als alle dummy-TYPE-Instanzen mit auszuwerten. Events an "global" (zusätzlich anders) auszuwerten ginge selbstredend auch.

Unabhängig davon: AMADCommBridge nimmt die TTS-Info entgegen UND auch die Info, von welcher AMADDevice-Instanz die Anfrage stammt. So kann RHASSPY die zu sprechende Antwort genau dahin schicken, wo die Anweisung ursprünglich her war. (Für ROOMMATE|GUEST ist es sowieso klar).
Für meine Zwecke MUSS es also in jedem Fall eine zweite Info geben, wohin die Antwort (bzw. ggf. Rückfrage...) gesendet werden soll.

"Schön" wäre es, wenn auch das Ende einer von FHEM ausgelösten Sprachausgabe signalisiert werden könnte, und dafür erscheint mir "global" nicht der passende Ort zu sein; das ist bei FHEMWEB schon schwierig, weil da ja mehrere Sitzungen offen sein können...
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

rudolfkoenig

Das Firefox Problem habe ich jetzt in Prinzip (s.u.) gefixt.
Zum Aktivieren muss in about:config media.webspeech.recognition.enable auf true gesetzt werden.
Dann oeffnet sich das Dialog, nach Sprachaufnahme kommt aber die Meldung: Error connecting to the service.
Chrome@Android meldet bei mir nichtmal Audio started, keine Ahnung, was da falsch laeuft.

Die Doppelung der Texte lag vielleicht an stt.interimResults=true, das habe ich jetzt entfernt.
Bei mir hat das keinen Unterschied bewirkt.

Die anderen Punkte:
- eine eindeutige Zuordnung des Clients ist kein Problem, will aber (mit dem Rest auch) abwarten, welchen Weg wir gehen wollen
- Sprachausgabe ist laut Doku moeglich, habs aber nicht getestet
- Dialog veraltet: ich habe gerne ein Feedback, solange die Erkennung nicht perfekt ist. Was schwebt Dir vor?

HTTPS mit einem gueltigen Zertifikat hat den Vorteil, dass man damit eine WebApp installieren kann, was wiederum Benachrichtigungen empfangen kann (ungetestet).
Weiss (noch) nicht, ob man damit auch Sprachausgabe ausloesen kann, bin eher skeptisch.
Gueltige Zertifikate kann man auch selbst erstellen, das Zertifikat muss auf dem Client dann installiert werden.

schwatter

Ich habe jetzt auch versucht bei Firefox mit http Zugriff zu bekommen. Klappt nicht.
Habe in about:config folgende auf true gesetzt. Aber auch danach kein Glück:
media.webspeech.recognition.enable true
media.devices.enumerate.legacy.enabled true
media.getusermedia.insecure.enabled true

Du hattest ja manifest schon hinzugefügt. Wäre es nicht sinnvoll, dem User direkt beim installieren
https zur Verfügung zu stellen, ohne das er sich mit der Einrichtung beschäftigen muss.

Gruß schwatter