[Voicecontrol] Button für Fhemweb

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

Vorheriges Thema - Nächstes Thema

schwatter

Zitat von: Prof. Dr. Peter Henning am 08 April 2026, 03:17:00Ohne das jetzt ausprobiert zu haben: Das würde mit ziemlicher Sicherheit in zwei auf den FHEM-Server geöffneten Browserfenstern zweimal die Audiodatei abspielen. Aus dem Grund habe ich einen "Shared Worker" implementiert.

LG

pah

Morgen,

genau das macht es. Das ist der Rundumschlag. Zum differenzieren schicken wir dann
die fw_id mit. Mit der wird nur eine Nachricht in dem Fenster abgespielt, welches
gerade geöffnet ist. Dazu muss es noch etwas abgeändert werden.

Gruß schwatter

Prof. Dr. Peter Henning

Es ging mir weniger ums Differenzieren, als darum, dass nur einmal abgespielt wird. Aber gut, der Weg ist tatsächlich einfacher als mit dem SSE-Server.

Da ich verschiedene FHEM-Server habe, wird mir als Titel der Seite jeweils das letzte Oktett der Server-IP angezeigt. Und bei dem FHEM mit dem SSE-Server kommt noch ein farbiger Punkt dazu, der den Status der SSE-Verbindung anzeigt. Rot=tot, Grün=SSE steht, Orange=wartet.

Wir bräuchten also in fhemweb.js auch noch eine Statusvariable. Dann könnte man z.B. bei blockiertem Audio wenigstens einen roten Punkt o.ä. anzeigen lassen.

LG

pah

//------------------------------------------------------------------------------------------------------
// Dynamisch Titel "FHEM <letztes Oktett der Server-IP>" setzen
//------------------------------------------------------------------------------------------------------

function setFhemHeaderFromServerIP() {
    try {
        const serverIP = new URL(window.location.href).hostname;
        const lastOctet = serverIP.split(".").pop();
        const hdr = document.getElementById("hdr");
       
        if (hdr && ! document.getElementById("fhem-title")) {
            const container = document.createElement("div");
            container.id = "fhem-title-container";
            container.style.cssText = "display: inline-block; margin: 0; padding: 0; vertical-align: middle;";
           
            const title = document.createElement("span");
            title.id = "fhem-title";
            title.textContent = "FHEM " + lastOctet;
            title.style.cssText = "display:inline;color:#6d77e2;font-size:24px;font-weight:bold;" +
            "text-shadow:2px 2px #c5c5c5;margin-right:6px;";
           
            const indicator = document.createElement("span");
            indicator.id = "sse-status";
            indicator.style.cssText = "display:inline-block;width:5px;height:5px;margin-left:4px;" +
            "border-radius:50%;vertical-align:middle;";
           
            container.appendChild(title);
            container.appendChild(indicator);
           
            hdr.insertBefore(container, hdr.firstChild);
        }
    }
    catch (e) {
        console.warn("Fehler beim Ermitteln der Server-IP: ", e);
    }
}

//------------------------------------------------------------------------------------------------------
// setHeaderStatusIcon (Farbwechsel für Statussymbol)
//------------------------------------------------------------------------------------------------------

function setHeaderStatusIcon(status) {
    const indicator = document.querySelector("#sse-status");
    if (! indicator || ! window.sseStatusAllowed) return;
   
    // Alle Statusklassen entfernen
    indicator.classList.remove("ok", "error", "waiting");
   
    // Neue Statusklasse setzen
    if (status === "ok") {
        indicator.classList.add("ok");
        indicator.style.backgroundColor = "#00cc00";
        indicator.title = "SSE-Verbindung aktiv";
    } else if (status === "error") {
        indicator.classList.add("error");
        indicator.style.backgroundColor = "#cc0000";
        indicator.title = "SSE-Verbindung fehlgeschlagen";
    } else if (status === "waiting") {
        indicator.classList.add("waiting");
        indicator.style.backgroundColor = "#ffcc00";
        indicator.title = "Verbindungsaufbau läuft";
    } else {
        indicator.remove();
    }
}

schwatter

#77
Nabend,

1. In Fhemweb.js am Ende einfügen

// --- FHEM Universal Audio & Speech Backend (Hybrid: Browser & Fully) ---
var fhemSelectedVoice = null;

function FW_audioControl(input) {
    if (!input || input.trim() === "") return;

    // --- 0. Variablen & Fully-Check ---
    var isFully = (typeof fully !== 'undefined' && typeof fully.textToSpeech === 'function');
    var onlyThisWindow = false;

    if (/\|actualWindow$/i.test(input)) {
        onlyThisWindow = true;
        input = input.replace(/\|actualWindow$/i, "").trim();
    }

    var myId = (document.querySelector('input[name="fw_id"]') || {}).value;
    if (onlyThisWindow && !myId) return;

    // --- 1. Stimmen-Management (nur für Standard-Browser nötig) ---
    var loadVoices = function() {
        if (isFully || typeof window.speechSynthesis === 'undefined') return;
        var voices = window.speechSynthesis.getVoices();
        if (voices.length > 0) {
            fhemSelectedVoice =
                voices.find(v => v.name.includes("Stefan")) ||
                voices.find(v => v.name.includes("Hans")) ||
                voices.find(v => v.lang.startsWith("de"));
        }
    };

    if (!isFully && window.speechSynthesis) {
        if (!fhemSelectedVoice) loadVoices();
        if (window.speechSynthesis.onvoiceschanged !== undefined) {
            window.speechSynthesis.onvoiceschanged = loadVoices;
        }
    }

    // --- 2. AUDIO-DATEI PLAYBACK (.mp3, .wav, .ogg) ---
    if (/\.(mp3|wav|ogg)$/i.test(input)) {
        var url = '/fhem/www/audio/' + input;
        console.log('FHEM_AUDIO PLAY:', url);
        var a = new Audio(url);
        a.play().catch(e => console.log('Audio blocked:', e));
    }
   
    // --- 3. SPRACHAUSGABE (TTS) ---
    else {
        console.log('FHEM_AUDIO SPEAK:', input);
       
        // Textreinigung (Markdown entfernen für Gemini)
        var cleanText = input.replace(/[_*#]/g, ' ').trim();
        cleanText = cleanText.replace(/\bOk\b/i, "Ok,,,");

        // A) Weg für Fully Kiosk (Tablet)
        if (isFully) {
            console.log('Using Fully Kiosk TTS');
            fully.textToSpeech(cleanText);
        }
        // B) Weg für Standard Browser (PC/Handy)
        else if (typeof SpeechSynthesisUtterance !== 'undefined' && window.speechSynthesis) {
            console.log('Using Web Speech API');
            try {
                window.speechSynthesis.cancel(); // Stau verhindern
                var utter = new SpeechSynthesisUtterance(cleanText);
                utter.lang = "de-DE";
                if (fhemSelectedVoice) utter.voice = fhemSelectedVoice;
                window.speechSynthesis.speak(utter);
            } catch (e) {
                console.error('TTS Error:', e);
            }
        } else {
            console.error('Keine Sprachausgabe-Engine verfügbar (Browser zu alt oder blockiert).');
        }
    }
}

// Optional: Einmaliges Vorab-Laden beim Start der Seite
if (window.speechSynthesis) {
    if (window.speechSynthesis.onvoiceschanged !== undefined) {
        window.speechSynthesis.onvoiceschanged = function() {
            var v = window.speechSynthesis.getVoices();
            if (v.length > 0 && !fhemSelectedVoice) {
                fhemSelectedVoice = v.find(s => s.name.includes("Stefan")) || v.find(s => s.lang.startsWith("de"));
            }
        };
    }
}

2. notify Beispiele

Aktuelles offenes Browserfenster
defmod n_audio_test notify Lampe01_Ez:on { FW_directNotify("#FHEMWEB:$FW_wname","FW_audioControl('ballhupe.mp3|actualWindow')","");; }
defmod n_audio_test notify Lampe01_Ez:on { FW_directNotify("#FHEMWEB:$FW_wname","FW_audioControl('Das ist ein Test|actualWindow')","");; }
Alle offenen Browser
defmod n_audio_test notify Lampe01_Ez:on { FW_directNotify("#FHEMWEB:$FW_wname","FW_audioControl('ballhupe.mp3')","");; }defmod n_audio_test notify Lampe01_Ez:on { FW_directNotify("#FHEMWEB:$FW_wname","FW_audioControl('Das ist ein Test')","");; }
EIn Statusicon ist noch nicht drin.

Gruß schwatter

Prof. Dr. Peter Henning

Zwei kleine Ergänzungen:

1. Da es vorkommen kann, dass eine eigene Datei für TTS-Funktionen, die FW_directNotify aufruft, vor FHEMWEB geladen wird, sollte zur Vermeidung einer Fehlermeldung in diese eigene Datei ein
use vars qw($FW_directNotify);
2. Beim Abspielen von MP3-Dateien, die aus einzelnen Stücken zusammengesetzt worden sind, verhalten sich Browser in einer Hinsicht sehr viel zickiger als andere Geräte: Die einzelnen MP3-Stücke sollten vor dem Zusammenfügen alle dieselbe Sampling-Rate und Bitrate haben.

Statusicon habe ich in Arbeit.

LG

pah

schwatter

#79
Moin,

ich habe die Funktion für fhemweb.js nochmal geändert. Diese verarbeitet jetzt nur Sprachausgabe und Audiodatei.
Wie die Funktion dauerhaft dort verbleiben kann, ja darüber grüble ich noch. Momentan sind zu viele spezifische
Settings drin. Da müsste entschlackt werden und sowas wie den Namen des Sprechers muss vom z.B notify kommen.
Die fw_id schiebe ich jetzt nicht mehr dahin (hatte oben auch nicht richtig funktioniert), sondern verarbeite sie
wieder direkt im notify. Außerdem habe ich die Idee aus dem anderen Thread aufgegriffen, mehrstuffig zu agieren um
erst lokale Befehle zu verarbeiten, um dann bei "Frage" an Gemini zu senden.

Dialog
Ich: James?!
James: Ja?
Ich: Frage, wie wird das Wetter heute in kurz.
James: In M*********** ist es heute bewölkt bei 20 Grad Celsius

1. fhemweb.js
// --- FHEM Universal Audio & Speech Backend (Hybrid: Browser & Fully) ---
var fhemSelectedVoice = null;

function FW_audioControl(input) {
    if (!input || input.trim() === "") return;

    // --- 0. Variablen & Fully-Check ---
    var isFully = (typeof fully !== 'undefined' && typeof fully.textToSpeech === 'function');

    // --- 1. Stimmen-Management (nur für Standard-Browser nötig) ---
    var loadVoices = function() {
        if (isFully || typeof window.speechSynthesis === 'undefined') return;
        var voices = window.speechSynthesis.getVoices();
        if (voices.length > 0) {
            fhemSelectedVoice =
                voices.find(v => v.name.includes("Stefan")) ||
                voices.find(v => v.name.includes("Hans")) ||
                voices.find(v => v.lang.startsWith("de"));
        }
    };

    if (!isFully && window.speechSynthesis) {
        if (!fhemSelectedVoice) loadVoices();
        if (window.speechSynthesis.onvoiceschanged !== undefined) {
            window.speechSynthesis.onvoiceschanged = loadVoices;
        }
    }

    // --- 2. AUDIO-DATEI PLAYBACK (.mp3, .wav, .ogg) ---
    if (/\.(mp3|wav|ogg)$/i.test(input)) {
        var url = '/fhem/www/audio/' + input;
        console.log('FHEM_AUDIO PLAY:', url);
        var a = new Audio(url);
        a.play().catch(e => console.log('Audio blocked:', e));
    }
   
    // --- 3. SPRACHAUSGABE (TTS) ---
    else {
        console.log('FHEM_AUDIO SPEAK:', input);
       
        // Textreinigung (Markdown entfernen für Gemini)
        var cleanText = input.replace(/[_*#]/g, ' ').trim();
        cleanText = cleanText.replace(/\bOk\b/i, "Ok,,,");

        // A) Weg für Fully Kiosk (Tablet)
        if (isFully) {
            console.log('Using Fully Kiosk TTS');
            fully.textToSpeech(cleanText);
        }
        // B) Weg für Standard Browser (PC/Handy)
        else if (typeof SpeechSynthesisUtterance !== 'undefined' && window.speechSynthesis) {
            console.log('Using Web Speech API');
            try {
                window.speechSynthesis.cancel(); // Stau verhindern
                var utter = new SpeechSynthesisUtterance(cleanText);
                utter.lang = "de-DE";
                if (fhemSelectedVoice) utter.voice = fhemSelectedVoice;
                window.speechSynthesis.speak(utter);
            } catch (e) {
                console.error('TTS Error:', e);
            }
        } else {
            console.error('Keine Sprachausgabe-Engine verfügbar (Browser zu alt oder blockiert).');
        }
    }
}

// Optional: Einmaliges Vorab-Laden beim Start der Seite
if (window.speechSynthesis) {
    if (window.speechSynthesis.onvoiceschanged !== undefined) {
        window.speechSynthesis.onvoiceschanged = function() {
            var v = window.speechSynthesis.getVoices();
            if (v.length > 0 && !fhemSelectedVoice) {
                fhemSelectedVoice = v.find(s => s.name.includes("Stefan")) || v.find(s => s.lang.startsWith("de"));
            }
        };
    }
}

2. Voicecontrol.js aus contrib oder wer einen Atom Echo hat, aus Post 1.
{ Svn_GetFile('contrib/voicecontrol.js', 'www/pgm2/voicecontrol.js') }attr WEBphone JavaScripts www/pgm2/voicecontrol.jsDann "shutdown restart"

Hinweis: Wer einen Atom Echo s3r für Wakeword benutzt, der muss außerdem das neue attr additionalInform pro
FHEMWEB-Device setzen

attr WEBtablet additionalInform atom_echos3r_9888e00f4280,global
3. Gemini installieren
https://github.com/ahlers2mi/FHEM-Gemini

4. notify für Fhemsteuerung. Bei dem Wort "Frage" und der anschließenden Frage, wird der Textbaustein an
das Modul Gemini geschickt.
defmod n_VoiceControl notify global:STT:.* {\
    # --- VORBEREITUNG ---\
    my ($cleanEvent, $clientId) = $EVENT =~ /^(.*)\s\[(.*)\]$/;;\
    $cleanEvent //= $EVENT;;\
    $clientId   //= "unknown";;\
    my @responses;; \
    my $ki_aktiv = 0;; # Merker für die KI-Frage\
\
    # --- KONFIGURATION: Zentrales Mapping ---\
    my %smartHomeDevices = (\
        "esszimmer:licht|lampe|deckenlampe" => { dev => "Lampe01_Ez", label => "Licht Esszimmer",  cmdOn => "on", cmdOff => "off" },\
        "esszimmer:aquarium" => { dev => "Aquarium_Aktor", label => "Aquarium", cmdOn => "on", cmdOff => "off" },\
        "küche" => { dev => "Deckenlampe_Kue", label => "Licht Küche", cmdOn => "on", cmdOff => "off" },\
        "wohnzimmer" => { dev => "Lampe06_Dek", label => "Licht Wohnzimmer", cmdOn => "on", cmdOff => "off" },\
        "fernseher|tv" => { dev => "VuPlus", label => "Fernseher", cmdOn => "on", cmdOff => "off" },\
        "rechner|pc" => { dev => "PC_Aktor", label => "PC", cmdOn => "on", cmdOff => "off" },\
        "garage|tor" => { dev => "Garagentor_Aktor", label => "Garagentor öffnen/schließen", cmdOn => "open", cmdOff => "close" },\
        "kaffee" => { dev => "Kaffeemaschine", label => "Kaffeemaschine", cmdOn => "on", cmdOff => "off" },\
        "roberto" => { dev => "MQTT2_valetudo_FlusteredUnequaledFish", label => "Lade Roberto", cmdOn => "charge" },\
        "ambiente" => { dev => "LampeSzeneAlle", label => "Zentrales Licht", type => "dimmer", cmdOn => "on", cmdOff => "off" },\
        "sauge|reinige|putze|staubsauger|roboter" => { dev => "MQTT2_valetudo_FlusteredUnequaledFish", label => "Staubsauger", type => "vacuum" },\
         "ambilight" => { label => "Ambilight", type => "system", cmd => "sshpass -p '1431Fhem1982' ssh -o StrictHostKeyChecking=no root\@192.168.1.46 '/usr/share/hyperhdr/scripts/hyperhdr_toggle.sh'" }\
    );;\
\
    my %vacRooms = ("arbeitszimmer" => "Arbeitszimmer", "badezimmer" => "Badezimmer", "esszimmer" => "Esszimmer", "flur" => "Flur", "küche" => "Küche", "wohnzimmer" => "Wohnzimmer");;\
\
    my $onRegEx  = '\b(an|ein|einschalten|starte|aktivier|aktiviere|öffne|öffnen|auf|hoch|lade)\b';;\
    my $offRegEx = '\b(aus|ausschalten|stop|stoppe|beende|deaktivier|deaktiviere|schließe|schließen|zu|runter)\b';;\
\
    my @commands = split(/\s*(?:und|dann|,)\s*/, lc($cleanEvent));;\
\
    # --- DER BEFEHLS-LOOP ---\
    foreach my $cmd_part (@commands) {\
        $cmd_part =~ s/^\s+|\s+$//g;;\
        my $is_on  = ($cmd_part =~ /$onRegEx/) ? 1 : 0;;\
        my $is_off = ($cmd_part =~ /$offRegEx/) ? 1 : 0;;\
        \
        # --- GEMINI KI FRAGE ---\
        if ($cmd_part =~ /\bfrage\b/i) {\
            my ($question) = $cmd_part =~ /\bfrage\s+(.*)$/i;;\
            if ($question) {\
                fhem("set GeminiAI ask $question");;\
                push(@responses, "Ich frage Gemini nach: $question");;\
                $ki_aktiv = 1;; # Wir haben eine KI Frage, also am Ende kein "erledigt"\
            } else {\
                push(@responses, "Wie lautet deine Frage?");;\
            }\
            next;; \
        }\
\
        $cmd_part =~ s/\b(ich|brauche|mach|bitte|kannst du|würdest du|mal|doch|den|das|die|im|in der)\b//g;;\
\
        # --- GENERISCHE STEUERUNG ---\
        my $match = 0;;\
        foreach my $key (sort { ($smartHomeDevices{$b}{type}//"") cmp ($smartHomeDevices{$a}{type}//"") } keys %smartHomeDevices) {\
            my ($main, $must) = split(/:/, $key);;\
            if ($cmd_part =~ /\b($main)\b/i) {\
                next if ($must && $cmd_part !~ /\b($must)\b/i);;\
                my $d = $smartHomeDevices{$key};;\
                my $action_text = $is_off ? "aus" : "an";;\
\
                if (($d->{type} // "") eq "system") {\
                    system($d->{cmd});;\
                    push(@responses, "$d->{label} erledigt");;\
                }\
                elsif (($d->{type} // "") eq "vacuum") {\
                    my @found = grep { $cmd_part =~ /\b$_\b/ } keys %vacRooms;;\
                    fhem(@found ? "set $d->{dev} clean_segment ".join(",", map { $vacRooms{$_} } @found) : "set $d->{dev} start");;\
                    push(@responses, @found ? "Reinigung gestartet in " . join(" und ", @found) : "Staubsauger gestartet");;\
                }\
                elsif (($d->{type} // "") eq "dimmer") {\
                    if ($cmd_part =~ /(\d+)/) {\
                        my $val = int(($1 > 100 ? 100 : $1));;\
                        fhem("set $d->{dev} brightness " . int($val * 2.55));;\
                        push(@responses, "$d->{label} auf $val Prozent");;\
                    } else {\
                        fhem("set $d->{dev} " . ($is_off ? "off" : "on")) if ($is_on || $is_off);;\
                        push(@responses, "$d->{label} $action_text") if ($is_on || $is_off);;\
                    }\
                }\
                else {\
                    my $fhem_cmd = $is_off ? ($d->{cmdOff} // "off") : ($d->{cmdOn} // "on");;\
                    if ($is_on || $is_off) {\
                        fhem("set $d->{dev} $fhem_cmd");;\
                        push(@responses, "$d->{label} $action_text");;\
                    }\
                }\
                $match = 1;; last;;\
            }\
        }\
        next if $match;;\
\
        if ($cmd_part =~ /(hilfe|kommandos|übersicht)/) {\
            push(@responses, "Übersicht wird angezeigt");;\
            my $h = '<div style="text-align:left;;min-width:250px;;font-family:sans-serif;;"><b>Befehlsübersicht:</b><br><br>';;\
            my %seen;;\
            for my $k (sort keys %smartHomeDevices) {\
                my $d = $smartHomeDevices{$k};;\
                next if $seen{$d->{label}}++;; \
                my $suffix = ($d->{cmdOn} && $d->{cmdOff} && $d->{label} !~ /(an\/aus|öffnen\/schließen)/i) ? " (an/aus)" : "";;\
                $suffix = " [0-100%]" if ($d->{type} // "") eq "dimmer";;\
                $h .= "• $d->{label}$suffix<br>";;\
            }\
            $h .= '<br><u>Staubsauger Räume</u><br>• '.join(", ", map { ucfirst($_) } sort keys %vacRooms).'<br></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");;\
        }\
    }\
\
    # --- SPRACHAUSGABE AN JAMES ---\
    if (@responses) {\
        # Nur "erledigt" setzen, wenn KEINE KI-Frage gestellt wurde\
        fhem("sleep 2;; setreading global voiceSpeak erledigt") if ($ki_aktiv == 0);;\
    }\
}

setstate n_VoiceControl 2026-04-12 09:26:44
setstate n_VoiceControl 2026-03-18 10:49:44 debug STT: kommandos [1773827299.67924]
setstate n_VoiceControl 2026-04-12 09:05:07 state active
setstate n_VoiceControl 2026-04-12 09:26:44 triggeredByDev global
setstate n_VoiceControl 2026-04-12 09:26:44 triggeredByEvent STT: frage wie wird das wetter heute [1775978374.82013]

5. notify für die Gemini-Sprachausgabe. Brauchen wir, weil wir eine neuen Event haben
defmod n_GeminiResponse notify GeminiAI:response:.* {\
    my $resp = ReadingsVal($NAME, "response", "");;\
    my $stt  = ReadingsVal("global", "STT", "");;\
    return if($resp eq "");;\
\
    # 1. ID extrahieren (wenn vorhanden)\
    my ($targetId) = $stt =~ /\[(.*?)\]/;;\
\
    # 2. Bereinigung für JavaScript\
    $resp =~ s/\*//g;; \
    $resp =~ s/['\r\n]/ /g;;\
    $resp =~ s/"/\\"/g;;\
\
    # 3. JavaScript-String zusammenbauen\
    my $js;;\
    if ($targetId) {\
        # Falls ID da ist: Nur ausführen, wenn die Browser-ID übereinstimmt\
        $js = "if(document.body.getAttribute('fw_id')==='$targetId'){FW_audioControl('$resp')}";;\
    } else {\
        # Falls keine ID da ist: Einfach an alle senden\
        $js = "FW_audioControl('$resp')";;\
    }\
\
    # 4. Senden\
    FW_directNotify("#FHEMWEB:$FW_wname", $js, "");;\
}

setstate n_GeminiResponse 2026-04-12 09:26:45
setstate n_GeminiResponse 2026-04-12 09:26:28 state active
setstate n_GeminiResponse 2026-04-12 09:26:45 triggeredByDev GeminiAI
setstate n_GeminiResponse 2026-04-12 09:26:45 triggeredByEvent response: In M********* ist es heute bewölkt bei 20 Grad Celsius



Gruß schwatter

Adimarantis

Zitat von: Beta-User am 26 März 2026, 09:41:49  f18_setWidePortrait();
+  if (typeof fully !== 'undefined')
+    FW_cmd(FW_root + "?cmd=set TYPE=FULLY:FILTER=deviceid=" + fully.getDeviceId() + " host " + fully.getHostname() + "&XHR=1");
 });

Diese Änderung führt bei mir jetzt dazu, dass ich in immer, wenn ich den Raum aufrufe in dem mein Fully Device steht diesen Fehler bekomme:
f18.js line 94:
Uncaught TypeError: fully.getDeviceId is not a function

Fehlt da in Fully noch ein Patch? Oder sollte es getDeviceInfo heissen (die Funktion gibt es in FULLY)

Gruß
Jörg
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU)/RfxTrx433XL/Zigbee
Module: 50_Signalbot, 48_HomeConnect, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

schwatter

Laut Webseite gibt es String fully.getDeviceId()
Schauh hier unter https://www.fully-kiosk.com/en/#websiteintegration --> Get device info aufklappen

Gruß schwatter

Adimarantis

Zitat von: schwatter am 12 April 2026, 10:52:18Laut Webseite gibt es String fully.getDeviceId()
Schauh hier unter https://www.fully-kiosk.com/en/#websiteintegration --> Get device info aufklappen

Gruß schwatter
Ok, da war ich erstmal falsch unterwegs - ist eine Javascript Routine und hat nichts mit dem FHEM Device zu tun.
Das Problem scheint daher zu kommen das mein FHEM device "fully" heisst - wenn ich das umbenenne verschwindet die Fehlermeldung.
Irgendwo glaubt das f18.js, dass das Javascript Objekt "fully" verfügbar wäre, wenn ein Raum ein Device namens "fully" enthält.

Jörg
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU)/RfxTrx433XL/Zigbee
Module: 50_Signalbot, 48_HomeConnect, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

rudolfkoenig

ZitatDas Problem scheint daher zu kommen das mein FHEM device "fully" heisst - wenn ich das umbenenne verschwindet die Fehlermeldung.
Liegt daran, dass Browser alle HTML Elemente mit einem #id als globale Variablen anlegen.
Die Abfrage
typeof fully !== 'undefined'ist also leider nicht genau, wir sollten es weiter einschraenken.

Prof. Dr. Peter Henning

Hat jemand einen Link für mich auf die Verwendung eines Atom Echo für Wakeword Detection?

LG

pah

schwatter

#85
https://github.com/esphome/wake-word-voice-assistants/blob/main/m5stack-atom-echo/m5stack-atom-echo.yaml

Von dem habe ich mein Template für den Echo s3r erstellt. Da ist allerdings viel drinne, was für Fhem keiner
braucht. Schau dir mal das Template auf Seite 1 dazu an.

edit:
Und beim bauen mit esphome nutze ich im python 3.12. Ab einer bestimmten neueren Version funktioniert es nicht mehr. Ab 3.13? Habs gerade nicht im Kopf.

Gruß schwatter