[Voicecontrol] Button für Fhemweb

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

Vorheriges Thema - Nächstes Thema

Beta-User

Zitat von: schwatter am 03 April 2026, 18:46:05das voicecontrol.js liegt jetzt im contrib. Das ist die Version für PushToTalk oder kurz AlwaysOn.
Thx!

Zitat von: schwatter am 03 April 2026, 18:46:05Mh, anpassen muss man da eigentlich nichts?
Sorry, falsche Referenz, geht um "FW_root". Das ist nicht zwangsläufig in jeder Installation "/fhem".
Habe das jetzt in der modifizierten Fassung so drin:
FW_cmd(FW_root+"?cmd=setreading TYPE=FHEMWEB:FILTER=FW_ID="+$("body").attr("fw_id")+
                        " STT "+encodeURIComponent(finalCommand)+"&XHR=1");

Damit landet die STT-Info in der betreffenden (temporären) FHEMWEB-Instanz. Hat den Nachteil, dass es nur solange "lebt", wie diese Instanz eben existiert, aber man kann dann das notify (bzw. künftig die NotifyFn() in RHASSPY&Co.) direkt darauf ansetzen und muss nicht erst den FW_ID-Teil rausoperieren (was zugegebenermaßen auch kein großer Aufwand ist).
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

ZitatHabe nochmal etwas rumexperimentiert mit "interimResults".
Habe es uebernommen.
Und dabei etwas modernere JS Sprachelemente genutzt (implementiert seit 10+ Jahren in den meisten Browsern), wenn jemand noch ein iPad 1 oder Internet Explorer verwendet, wird damit vmtl. keine Freude haben.

ZitatDamit landet die STT-Info in der betreffenden (temporären) FHEMWEB-Instanz.
Habe die Idee leicht angepasst uebernommen, und eine mini f18_speak Funktion eingebaut.
Damit ist Folgendes moeglich:
defmod sn notify WEB.*STT:.* { $EVENT=~s/STT: //;; FW_AsyncOutput($defs{$NAME},'',qq/["#FHEMWEB:","f18_speak('Got $EVENT')",""]/)}
Voraussetzung ist z.Bsp. mit Chrome @ Android die installierte und aktivierte Sprachsynthese App von Google.

Man kann mit der obigen Methode auch direkt Nachrichten schicken, allerdings werden sie nur dann vorgelesen, wenn Chrome sichtbar ist.

schwatter

Hallo Rudi

danke. Ich habe ein paar Fragen

1. Beta_User und Rudi
Beta-User sagt: "FW_root". Das ist nicht zwangsläufig in jeder Installation "/fhem".
Wie ist das gemeint. Es ist ja hier dokumentiert:
https://wiki.fhem.de/wiki/DevelopmentFHEMWEB-API

2. Kann man Fhemweb direkt ein Inform rauskitzeln, das ein Device betrifft, was nicht im selben Raum ist,
oder wenn man sich nicht gerade in der Deviceübersicht befindet. Was dann funktioniert, wie eine
Websocketverbindung im Hintergrund. Nach meinem Verständnis kann ich über Fhemweb nur Devices auslesen,
die Direkt im sichtbaren Bereich sind.

3.
Mir ist beim anschauen per F12 Konsole aufgefallen, das Werte von Readings immer gedoppelt sind.
Warum ist das so? Beispiel:
13:10:13.353 Rcvd: ["MQTT2_valetudo_UrbanBrownKoala-signal","-69","-69"]
fhemweb.js:613 13:10:13.354 Rcvd: ["MQTT2_valetudo_UrbanBrownKoala-signal-ts","2026-04-04 13:10:13","2026-04-04 13:10:13"]

Gruß schwatter

rudolfkoenig

ZitatBeta-User sagt: "FW_root". Das ist nicht zwangsläufig in jeder Installation "/fhem".
Wie ist das gemeint.
So wie er das sagt :)
FW_root ist auf der JavaScript Seite der Wert des FHEMWEB Attributes webname.

ZitatNach meinem Verständnis kann ich über Fhemweb nur Devices auslesen,
die Direkt im sichtbaren Bereich sind.
Auslesen kannst Du jederzeit z.Bsp. mit jsonlist2, nur eine Benachrichtigung kriegst Du nicht.
Man kann mit einer inform=XXX Nachricht eine andere Benachrichtigung bestellen, was die Aktuelle ersetzt.

ZitatMir ist beim anschauen per F12 Konsole aufgefallen, das Werte von Readings immer gedoppelt sind.
Die erste Zeile ist Wert, die Zweite Zeitstempel, historisch gewachsen.
Parameter 2 und 3 im Array sind fuer readingsUpdates gleich, in anderen Faellen nicht.

schwatter

Zu 1.
Oha, ich habe das falsch interpretiert. Ich dachte ich solle fw_root nicht nehmen. Es war anderherum gemeint,
Asche auf mein Haupt  ::)

Zu 2.
Anders gefragt, es gibt ja in fhemweb.js die FW_longpoll(). Die hat diverse Filter, die mich meiner Meinung nach
daran hindern, direkt inform=xxx zu nutzen, von Devices welche nicht im Raum oder in der Deviceübersicht vorhanden
sind.

Ich nutze dazu momentan:
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}`);

Wie findest du es, wenn man mit einem geladenen JS in Fhemweb direkt an der Stelle per inform=xxx abonieren könnte?

Gruß schwatter

Beta-User

Zitat von: rudolfkoenig am 04 April 2026, 12:17:00und eine mini f18_speak Funktion eingebaut.
Komme mir vor wie wenn Weihnachten und Ostern zusammenfallen ;D  ;D  ;D  ;D  ;D

Vielen Dank!

Bin bei der Frage, wie das mit dem automatisierten Wieder-Öffnen des Mikros gehen könnte dann über das hier gestolpert:
https://iifx.dev/en/articles/457363230/chrome-tts-workarounds-solving-the-speechsynthesisutterance-event-and-initial-speak-failure (Stand: 11/25), und habe daraufhin jetzt mal auf die Schnelle den Code so erweitert:

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);
}

Mein eigentlicher Gedanke war gewesen, das direkt in JavaScript zu lösen (erst mal nicht unbedingt "modern", aber halt funktional... ::) ), aber wenn das nicht in allen Browsern/Systemen verlässlich geht, kann ich mir wohl auch mit NotifyFn() in RHASSPY behelfen und alternativ einen (längeren) InternalTimer setzen, um den Dialog fortzusetzen.

Jetzt gibt es erst mal Frühstück, meine Rest-Wunschliste niederzuschreiben muss erst mal noch warten :)
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

#66
Nabend Rudolf,

ich habe mich mal genauer mit FHEMWEB.pm und fhemweb.js beschäftig. Mir ist es gelungen, ein Device in einem
Raum per inform mit hinzuzufügen ohne das das Device vorhanden ist.

1. Änderungen in fhemweb.js
A) Ganz oben in der Datei (bei den anderen Variablen):
var FW_additionalInformIds = [];

B) Innerhalb der function FW_longpoll():
// Suche die Zeile mit 'var since = "null";' und ändere den Block darunter so ab:

  var since = "null";
  if(FW_serverGenerated)
    since = FW_serverLastMsg + (FW_serverGenerated-FW_serverFirstMsg);

  // --- START PATCH ---
  var informString = "type=status;filter="+filter+";since="+since+";fmt=JSON";

  // IDs aus dem globalen Array hinzufügen, falls vorhanden
  if(typeof FW_additionalInformIds !== "undefined" && FW_additionalInformIds.length > 0) {
      informString += ";addIds=" + FW_additionalInformIds.join(",");
  }

  var inform = encodeURIComponent(informString);
  // --- END PATCH ---

  var query = "?XHR=1"+
              "&inform="+inform+
// ... Rest der Funktion bleibt gleich

2. Änderungen in 01_FHEMWEB.pm
Suche die sub FW_initInform($$).

Perl
# --- In 01_FHEMWEB.pm ---
# Suche die Zeile: my %h = map { $_ => 1 } devspec2array($filter);
# Füge direkt danach diesen Block ein:

  my %h = map { $_ => 1 } devspec2array($filter);

  # --- START PATCH ---
  if($me->{inform} && $me->{inform}{addIds}) {
    foreach my $d (split(",", $me->{inform}{addIds})) {
      if($defs{$d}) {
        $h{$d} = 1;
        $FW_visibleDeviceHash{$d} = 1;
      }
    }
  }
  # --- END PATCH ---

  $h{global} = 1 if( $me->{inform}{addglobal} );
// ... Rest der Funktion bleibt gleich

Danach kann ich in der Browserkonsole den Inform auslösen:
window.FW_additionalInformIds = ["Pumpe_FBH_Pwr"];
FW_closeConn(); setTimeout(FW_longpoll, 500);


Danach kam mir aber die Idee, das das nicht so dolle ist. Jedesmal stoppen um dann wieder zu starten.
Wie wäre es, wenn direkt in FHEMWEB-Device ein attr additionalInformID hinzugefügt wird. Da kann dann
eine Liste mit Device(s) eingetragen werden, welche in jedem Raum verfügbar sein soll.

Gruß schwatter {"frohe": "Ostern"}


schwatter

#67
So,

damit geht es nur mit 01_FHEMWEB.pm

  # Initialize internal structures
  map { addToAttrList($_, "FHEMWEB") } (
    "additionalInformIds",
    "cmdIcon",
    "devStateIcon:textField-long",
    "devStateStyle",
    "icon",
    "sortby",
    "webCmd",
    "webCmdLabel:textField-long",
    "widgetOverride"
  );

  my %h = map { $_ => 1 } devspec2array($filter);
  # --- Manuelle IDs in den Überwachungs-Hash injizieren (start)---
  my $addIds = AttrVal($FW_wname, "additionalInformIds", undef);
  if(my $addIds = AttrVal($FW_wname, "additionalInformIds", undef)) {
    map { $h{$_} = $FW_visibleDeviceHash{$_} = 1 if($defs{$_}) } split(/\s*,\s*/, $addIds);
  }
  # --- Manuelle IDs in den Überwachungs-Hash injizieren (ende)---
  $h{global} = 1 if( $me->{inform}{addglobal} );

attr WEBphone additionalInformIds Pumpe_FBH_Pwr,Kuehlschrank
Gruß schwatter

Prof. Dr. Peter Henning

#68
Wenn wir schon über solche Dinge diskutieren: Im Juli letzten Jahres habe ich die Javascript-Programme veröffentlicht, mit denen ich FHEM dazu bringen kann, per push in einem der modernen Browser eine von FHEM gelieferte MP3-Datei abzuspielen. Anders ausgedrückt: Sprachausgabe direkt im Browser.

Dazu wird im Browser ein Shared Worker für Server Side Events gestartet, der auf einen bestimmten Port am FHEM-Server lauscht. Am FHEM-Server wird dann, wenn benötigt, ein Push auf diesen Port ausgelöst.

Das könnte man eigentlich problemlos in das Standard-Frontend integrieren und hätte dann nicht nur die eine Richtung.

LG

pah

rudolfkoenig

ZitatBin bei der Frage, wie das mit dem automatisierten Wieder-Öffnen des Mikros gehen könnte dann über das hier gestolpert:
Wieso oeffnet das gezeigte Code-Stueck das Micro wieder?
Und warum will man das ueberhaupt? :)


Zitatdamit geht es nur mit 01_FHEMWEB.pm
Habs leicht abgewandelt als additionalInform eingebaut.


ZitatDas könnte man eigentlich problemlos in das Standard-Frontend integrieren und hätte dann nicht nur die eine Richtung.
Push ist seit 28.3 in f18.js eingebaut (siehe https://forum.fhem.de/index.php?topic=143778.msg1360637#msg1360637), und fuer TTS siehe meinen Beitrag hier von vorgestern.

Beta-User

#70
Zitat von: rudolfkoenig am 06 April 2026, 12:02:47Wieso oeffnet das gezeigte Code-Stueck das Micro wieder?
Der Code wirft jetzt "nur" einen "bin fertig mit sprechen" Event, damit man auf der FHEM-Seite den Zeitpunkt kennt, ab wann man das Mikro wieder aufmachen kann, WENN man weitere Infos vom Sprecher haben möchte.
ZitatUnd warum will man das ueberhaupt? :)
Das scheine ich nicht gut erklärt zu haben. "Man" will das nicht zwangsläufig immer, sondern nur in gewissen Fällen. Wenn es auf der js-Seite sicher klappen würde, hätte ich dementsprechend versucht, das mit der Übergabe eines weiteren Parameters zu steuern, ob danach das Mikro wieder aktiviert werden soll :) .
So ist jetzt der "AMAD-Weg" der Plan; das wirft auch einen Event, wenn die jeweilige Anweisung "durch" ist.

Nachtrag: die eben eingecheckte Version von RHASSPY enthält eine erste funktionsfähige Event-Verarbeitung in diesem Sinne, so dass wir uns jetzt dann (optionalen) optischen und funktionalen Fragen zu wenden könnten (und ich die in CustomIntent mit Dialog (https://forum.fhem.de/index.php?topic=139337.0) begonnenen Erweiterungen fortsetzen kann).

ZitatPush ist seit 28.3 in f18.js eingebaut (siehe https://forum.fhem.de/index.php?topic=143778.msg1360637#msg1360637),
Mit den Neuerungen bzgl. push und additionalInform muss ich mich erst mal befassen, wie das in dem Zusammenhang zweckmäßigerweise einzubauen ist.

Zitatund fuer TTS siehe meinen Beitrag hier von vorgestern.
Wenn ich das richtig verstanden habe, geht es pah nicht darum, die TTS-Fähigeit des Endgeräts direkt zu nutzen, sondern "Jeannie" (?) sprechen zu lassen, damit die Sprachausgabe aus FHEM auf allen Endgeräten gleich klingt.
Dazu wird vorab Audio generiert (und zwischengespeichert) und dann das passende Audio abgespielt.
Da will ich (zumindest als Option) letztlich auch hinkommen, nur dass meine Audios nirgends gespeichert werden, sondern via piper-tts-Server on the fly generiert werden sollen.

Dementsprechend sollte die Push-Anweisung dahin gehen, das Audio (ggf. unter Angabe der Stimme für unterschiedliche Sprachen, je nach "Gesprächspartner") abzuholen, abzuspielen, und danach den Event "bin fertig mit Sprechen" zu generieren (oder eben das Mikro bei entsprechendem flag wieder direkt aufzumachen).
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