CustomIntent mit Dialog

Begonnen von gregorv, 03 Oktober 2024, 10:54:24

Vorheriges Thema - Nächstes Thema

gregorv

Zitat# just copied from setDialogTimeout
die Kommentare sind hauptsächlich nur für Dich und sollten raus- dieser speziell war markiert, weil man da eine sub draus machen könnte. Ich meine, dass die Mimik noch öfter vorkommt.

Du kennst Dich besser im Code aus, ich hatte hauptsächlich die Funktion im Auge. Fühl Dich frei alles umzuwerfen.

Ich habe inzwischen mal meine Intents aufgeräumt. Die subs sind angehängt (Blind custom intents.pm) am einfachsten kopiert man die 'as is' in die 99_myUtils.pm, weil dann die zugehörige rhasspyIntents Einstellung passt (in Einstellungen.txt). Da ist auch der Auszug von Sentences.ini und ein Dump von einem Rolladen Device (ich habe Dooya).
Im Code und Sentences wäre da für eine HM Steuerung nur pos duch pct (und zum Lesen position duch pct) zu ersetzen. und in den Sentences die entsprechenden Kommandos für Auf,Zu,Stop.

Ich selbst habe für die Tests allerdings die fhem("set ... Zeilen auskommentiert. Sonst machen sich die Nachbarn Gedanken um meinen Gesundheitszustand :)




Beta-User

Zitat von: gregorv am 16 Oktober 2024, 15:41:17die Kommentare sind hauptsächlich nur für Dich
Na ja, das war von meiner Seite nur wegen der Code-Stelle, auf die sich das bezog. Das kann jedenfalls so nicht "sauber" funktionieren, auch wenn das Ergebnis ggf. so aussehen sollte als ob ;) ...

Zitat von: gregorv am 16 Oktober 2024, 15:41:17war markiert, weil man da eine sub draus machen könnte. Ich meine, dass die Mimik noch öfter vorkommt.
_Vielleicht_ gibt es dazu schon eine sub - configure_DialogManager().

Aber vielleicht nochmal ein Schritt zurück:
- Die CustomIntents-Schnittstelle ist funktional, aber "eigentlich" hat sich bisher keiner so richtig für die Funktionalität im Detail interessiert. An sich _sollte_ die Rückgabe vollen Zugriff auf die RHASSPY/Rhasspy-Funktionalität erlauben. Da habe ich im Moment große Zweifel, würde andererseits aber auch nicht mehr dazu "raten", notfalls selbst im RHASSPY-Hash rumzumalen oder Funktionen wie configure_DialogManager() direkt aufzurufen. Geht zwar alles, bringt aber Probleme mit sich, falls (!) wir doch mal an den Punkt kommen, irgendein neues Interface für "Rhasspy 4.x" (oder was anderes ?) zu basteln.
- Ich bin "damals" den Weg gegangen, alle gewünschten Funktionalitäten möglichst direkt im Modul unterzubringen, weswegen der Code im Prinzip auch schon so angelegt ist, dass diverse Dinge modular aufgerufen werden können, je nach Bedarf. Ist sicher nicht 100% fertig, wie wir jetzt sehen, aber es ging wohl nach meinem jetzigen Gefühl deutlich in diese Richtung.
- ergo sollten wir mAn. nun versuchen, die CustomIntent-Schnittstelle so aufzubohren, dass man mit entsprechenden Schlüsseln auch alle Tore so aufbekommt, dass das auch noch paßt, wenn wir größer renovieren müssen.

Etwas andere Baustelle:
Der eigentliche Wunsch war ja, nach (z.B.) einem "setNumeric" den Dialog offen zu halten. Die eigentlichen Kommandos, die für die Dooya erforderlich wären, scheint RHASSPY ja zu erkennen, auch "stop" oder so sollte (außer dem Zeitproblem) ohne weiteres umsetzbar sein.
Daraus könnte man auch den Schluss ziehen, dass man statt eines "lasse generell das Mikro noch eine Zeitlang offen" ein "mache in speziellen Fällen das Mikro nicht aus" direkt im Modul vorsieht. Lösen liese sich das ggf. über zwei Wege:
- einen "continueDialogue"-Key, den man (wie den anderen neuen Key) überall setzen kann, und der dann (optional) einen Wert für die Dauer enthalten könnte, und/oder
- ein rhasspySpecial, der das für einzelne Geräte/Kommandos (?) konfigurierbar macht.

Vermutlich ließe sich der erste Ansatz mit dem key "relativ leicht" lösen (abgesehen von den vielen Detailfragen, die ich im Moment vermutlich übersehe..., und der Zeit, die das ggf. kostet, die ich im Moment nicht wirklich aufbringen kann).

Meinungen dazu?
Server: HP-elitedesk@Debian 12, 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

gregorv

Zitatnun versuchen, die CustomIntent-Schnittstelle so aufzubohren, dass man mit entsprechenden Schlüsseln auch alle Tore so aufbekommt
Sehr gut, so habe ich mir das vorgestellt. Keys für Dialog offen lassen, optional Dauer, optional Response abschalten ...

Für die möglichen Parameter könnte man noch Ideen anderer FHEM-Rhasspy Nutzer sammeln.


ZitatEtwas andere Baustelle:
Das wäre sogar noch besser, wenn die zusätzlichen Parameter auch bei Standard Intents machbar wären.
Das sollte am Device konfigurierbar sein, weil man so ggf. Attribute oder Readings mit übergeben kann. Ich nutze z.B. das Attribut drive-up-time-to-open für die Dialog Dauer und das Reading position um z.B mit dem Kommando weiter die Fahrrichtung zu ermitteln und eine neue Position x% höher oder tiefer anzufahren. (Readings müssten während der Dialog Dauer aktuell sein.)

Mehrfach hintereinander (ohne vorher jedes mal das Wake Word) Lauter / Leiser wäre ein anderes Beispiel oder mehrfach hintereinander Programmwahl - so zu sagen: Zappen ...

Ich glaube kaum, dass HA oder Alexa da mitkommen  :o


Beta-User

#63
Zitat von: gregorv am 17 Oktober 2024, 11:21:19Ich glaube kaum, dass HA oder Alexa da mitkommen  :o
Weiß nicht, habe keine Erfahrung damit. Meine persönliche Intention war, die Gadgets in meiner Hausautomatisierung einigermaßen flexibel per Sprachsteuerung steuern bzw. abfragen zu können, irgendwas "externes" (Wetter in Haithi etc.) war nie mein Fokus. Und das Ganze sollte ohne cloud laufen.

Den Job macht Rhasspy/RHASSPY (abgesehen von ein paar Kleinigkeiten, an denen man noch feilen könnte) zu meiner vollen Zufriedenheit, und ich kann mir auch nicht vorstellen, dass eine externe Lösung das "stressfreier" (oder mit weniger Missverständnissen) hinbekommen könnte.

Von daher ist das vermutlich bereits heute so, ohne, dass wir den Code nochmal anfassen 8) .
Zitat von: gregorv am 03 Oktober 2024, 21:09:40Ich hatte mir heute mal OpenVoiceOS angeschaut aber mein erster Eindruck war, dass das noch viel komplexer wird. Meinst Du, das wäre echt eine Alternative zu Rhasspy ?
Hatte jetzt auch mal die Tage einen (theoretischen) Blick darauf geworfen. Nach dem letzten statement von dkreutz ist er bis dato nicht dazu gekommen, seinen skill auf OpenVoiceOSS anzupassen. Was in der mycroft-Lösung an Optionen angeboten (bzw. dokumentiert) ist, bleibt - zumindest für mich und auf den ersten Blick - deutlich hinter dem zurück, was mit RHASSPY geht.

Von daher lohnt es sich m.E., RHASSPY weiter zu entwickeln, allerdings eben so, dass wir uns nach Möglichkeit nicht irgendwelche Eigentore schießen, falls wir künftig irgendwann einen anderen Unterbau dazu verwenden könnten ;) .

Zum eigentlichen:
Zitat von: gregorv am 17 Oktober 2024, 11:21:19Das wäre sogar noch besser, wenn die zusätzlichen Parameter auch bei Standard Intents machbar wären.
Danke für die spontane Rückmeldung!

ZitatDas sollte am Device konfigurierbar sein, weil man so ggf. Attribute oder Readings mit übergeben kann. Ich nutze z.B. das Attribut drive-up-time-to-open für die Dialog Dauer und das Reading position um z.B mit dem Kommando weiter die Fahrrichtung zu ermitteln und eine neue Position x% höher oder tiefer anzufahren. (Readings müssten während der Dialog Dauer aktuell sein.)
Puh, das klingt schon wieder nach "zu viel Auswertung", und ich habe im Moment Zweifel, ob sich dieser Aufwand wirklich lohnt.

Aber bevor wir darüber diskutieren, sollten wir m.E. mal definieren, wie wir vorgehen wollen. Mein Vorschlag:
- Das mit "resetInput" fertig machen und einchecken. Dazu müßte man m.E. die angehängten Dateien checken, ob das Zusammenspiel soweit paßt, dass bisherige User keine Probleme haben.
- Danach könnte man sich mit einem globalen (sentences-) Key für "führe den Dialog weiter" befassen. Ziel auch hier: Zwischenversion einchecken.
- Dann eventuell checken, ob man "specials" findet (Zwischenversion...)
- zuletzt wäre das mit myUtils dran.
Vermutlich entspricht diese Liste nicht deinen persönlichen Präferenzen, aber so herum bekommen wir es in (hoffentlich) handhabbare Häppchen aufgedröselt und können ggf. gleich entscheinden, welche generischen Code-Brocken wir brauchen (bzw. schon haben), und wie man die am besten einsetzt... (feedback welcome)

Grundsätzlich fehlt mir grade v.a. die Zeit zum Testen, von daher werde ich mal im Hauptthread darauf hinweisen, dass wir hier am diskutieren sind. Vielleicht findet sich zumindest jemand, der testet, dass es mit diesen Zwischenversionen keine Probleme mit seiner bisherigen Funktionalität gibt?!?

Zitat von: gregorv am 17 Oktober 2024, 11:21:19Für die möglichen Parameter könnte man noch Ideen anderer FHEM-Rhasspy Nutzer sammeln.
Dann geht es m.E. nämlich nicht nur um "mögliche Parameter", sondern v.a. auch um Ideen, welche Funktionalitäten ggf. noch wie (im Detail) umsetzbar wären (ohne sich irgendwie "tot konfigurieren" zu müssen...).

EDIT: Fehlerkorrektur in RHASSPY.pm
Server: HP-elitedesk@Debian 12, 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

gregorv

Zitatneue 10_RHASSPY.pm
werde gleich mit intensiveren Tests starten, schon mal vorab, damit das Modul lädt:
Korrektur Zeile 106 ':' zu '=>'

Gibt aber wohl noch ein paar Dinge:
resetInput geht nicht, weil der CustomIntent BlindStop nicht mehr aufgerufen wird und damit resetInput nicht da ist. Ich versuch das mal einzugrenzen.

Unabhängig von den neuen Funktionen:
Falls das Wake-Word erkannt wurde in nichts gesagt wird, gibt es ja den timeout. Die session wird jetzt sauber (und still) beendet. vorher war: response = "Da hat etwas zu lange gedauert" im Log zu sehen mit einer anschließenden Fehlermeldung.

ZitatDanach könnte man sich mit einem globalen (sentences-) Key für "führe den Dialog weiter" befassen
In Rhasspy ist der Key: sendIntentNotRecognized (warum auch immer so heißt) - jedenfalls habe ich bei Tests gesehen, dass sendIntentNotRecognized = "true" die session offen hält und sendIntentNotRecognized -> 0 (oder nicht vorhanden) die session sofort schließt. In der sub setDialogTimeout ist das ja mit "true" 'hart verdrahtet', was da auch Sinn macht. Also offen beibt er jetzt schon und erkennt auch Kommandos - quittiert aber alle mit IntentNotRecognized.

Melde mich später noch einmal.

Danke, Gregor

Beta-User

Zitat von: gregorv am 17 Oktober 2024, 18:49:46Korrektur Zeile 106 ':' zu '=>'
Thx, Datei im post angepaßt.
Zitat von: gregorv am 17 Oktober 2024, 18:49:46resetInput geht nicht, weil der CustomIntent BlindStop nicht mehr aufgerufen wird und damit resetInput nicht da ist. Ich versuch das mal einzugrenzen.
Na ja, das sollte ja vom design her in jedem Intent funktionieren.

Generell würde ich gerne v.a. den (Einzel-) Intent setNumeric (und evtl. setOnOff) zum Testen und Weiterentwickeln verwenden, von daher würde es sich m.E. anbieten, das da mal testweise reinzuknödeln.

Da es ja aber mal funktioniert hat, sollten wir Schritt 1 eigentlich relativ schnell abhaken können, oder? Zumal die Änderungen marginal sind.

Die allgemeine "Warnung" vor updates ist ja raus, von daher kann sich keiner beschweren, falls wir dann doch ein Problem finden O:-) .

Für den 2. Schritt habe ich mal in den Code geschaut, und da v.a. alles rund um die sub respond(). Da ist ja schon vorgesehen, dass man ein $delay mit übergeben kann. Genutzt wird das intern aber selten, eigentlich nur von handleIntentCancelAction(), und es ist der Funktion (bis auf den Ausnahmefall, dass es sich nicht um einen generischen Rhasspy-Satelliten handelt (v.a. AMAD)) eigentlich auch egal, welcher Wert (außer 0) da übergeben wird...

Komisch kommt mir grade nur vor, dass da in handleIntentCancelAction() erst "respond" mit $delay aufgerufen wird, dort intern intentFilter gesetzt wird (die Formatierung macht mittels des letzten Parameters configure_DialogManager() ;) ), und dann nochmal configure_DialogManager() direkt aufgerufen. Letzteres macht eigentlich keinen Sinn, aber mir dünkt, dass ggf. sonst das "pure" "intentFilter"-Feld in $sendData nichts bewirkt? Aber dann wäre das mit dem CustomIntent bei dir auch schief gegangen...?!? Oder war da was mit einem session-intentFilter und einem globalen intentFilter (per Satellit?)? Jedenfalls sind die deaktivierten Intents etwas unterschiedlich, default deaktivert auch "Cancel", mit $delay ist das nicht mit drin.

Hmmm, da müssen wir wohl noch das eine oder andere austesten.

Generell scheint es mir sinnvoll, auch die zu deaktivierenden Intents mit übergeben zu können. Da muss ich aber auch noch etwas rumhirnen, eine kommaseparierte Liste wäre hier m.E. das einfachste.


Was CustomIntents angeht: Da sollte man einen Schalter haben, anhand dessen entschieden werden kann, ob setDialogTimeout() aufgerufen wird oder das ganze (default) in respond() gehen soll.
Erstere Funktion sehe ich als "Fortsetzungsfunktion" zu einem Thema, respond() ist entweder "nur" eine Ausgabefunktion, oder eben (mit $delay) eine universelle Möglichkeit, ggf. auch direkt einen neuen Dialog zu beginnen (oder den bestehenden fortzuführen). Mit
Zitat von: Beta-User am 17 Oktober 2024, 13:17:39führe den Dialog weiter"
wäre demnach eher "mach unmittelbar einen neuen Dialog auf" gemeint, ohne irgendwelche bereits gesetzten Filter usw.. Dafür gibt es - soweit ich das erkennen kann - im Moment keinen Code.
Zitat von: gregorv am 17 Oktober 2024, 18:49:46Also offen beibt er jetzt schon und erkennt auch Kommandos - quittiert aber alle mit IntentNotRecognized.
Das scheint mir die Folge des session-intentFilters zu sein. Falls da was falsch gesetzt sein sollte, kommt halt schlicht nichts mehr durch - falls mich meine Erinnerung nicht trügt.

Wollte nur mal meine Gedanken erst mal sortieren und hoffe, das ist soweit verständlich und nachvollziehbar?
Server: HP-elitedesk@Debian 12, 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

Beta-User

Nachdem die (v.a. bzgl. Doku/commandref noch etwas abgeänderten) Dateien "unfallfrei" geladen werden können, habe ich das ganze eben eingecheckt. Mal sehen, wann sich der erste beschwert  ;D O:-) ...
Server: HP-elitedesk@Debian 12, 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

gregorv

@Beta-User

ich habe den Fehler gefunden und außerdem noch den Code noch optimiert.

In der sub handleIntentNotRecognized ist der Parameter intentFilter gar nicht erforderlich, damit wird das da erheblich kürzer:
#@@@
     $data->{requestType} //= $data_old->{requestType} // 'voice';   
     my $response = getResponse( $hash, 'RetryIntent');
     my $reaction = {
     text => $response,    
         sendIntentNotRecognized => 'true',
         customData => $data->{customData}
         };
    respond( $hash, $data, $reaction);
    return $hash->{NAME};
ZitatDas scheint mir die Folge des session-intentFilters zu sei
Das  Problem hängt tatsächlich mit dem IntentFilter zusammen. In der sub handleCustomIntent stehen die von der sub CustomIntent (bei mir Blinds) angehängten Daten in $error (hash, komplett) und das kann nicht als response (4.) Parameter an die sub setDialogTimeout übergeben werden, die erwartet da einen oder mehr strings und kein hash. Jeden falls habe ich da nichts gefunden, was den hash auseinander nimmt, auswertet oder weiterleitet. Damit ist auch der IntentFilter weg, obwohl der in $error drin steht.
statt:
return setDialogTimeout($hash, $data, $timeout, $error);wie folgt:
return setDialogTimeout($hash, $data, $timeout, $resonse, $intentFilter);Der Aufruf der sub setDialogTimeout mit obigen Daten liefert das erwartete Ergebnis.
Da die Rückgabewerte der sub CustomIntent aber nicht in $data stehen gehen die verloren. Es bleibt nur die Möglichkeit die Daten aus $error in $data zu übertragen. Oder siehst Du da eine andere Möglichkeit ?

Ich habe daher den Code in der sub handleCustomIntent:
    $timeout = $error->{sessionTimeout} if defined $error->{sessionTimeout} && looks_like_number( $error->{sessionTimeout} );
        return setDialogTimeout($hash, $data, $timeout, $error);
wie folgt geändert:
# @@@
        $data->{customData} = $error->{customData} // undef ;
        $data->{silent} = $error->{silent} // undef ;
        my $resonse = $error->{text} // getResponse($hash, 'DefaultConfirmation');
my $intentFilter = $error->{intentFilter} if( ref $error->{intentFilter} eq 'ARRAY') // [qw(CancelAction)];
    $timeout = $error->{sessionTimeout} if defined $error->{sessionTimeout} && looks_like_number( $error->{sessionTimeout} );
        return setDialogTimeout($hash, $data, $timeout, $resonse, $intentFilter);

Eigentlich wäre das besser in der sub setDialogTimeout aufgehoben (reines Bauchgefühl). Ich hab es nur nicht gemacht, weil ein Fehler da sich auch auf andere Intents auswirkt.

Da die obigen Änderungen sich nur bei CustomIntents auswirken können und da auch nur bei denen, die ein hash als return liefern, dürfte das für alle Nutzer die keine solchen CustomIntents verwenden ohne jegliche Auswirkung sein.

ZitatErstere Funktion sehe ich als "Fortsetzungsfunktion" zu einem Thema, respond() ist entweder "nur" eine Ausgabefunktion, oder eben (mit $delay)
Das hatte ich in meinem vorherigen Code schon drin. Das war der Parameter "what"=>"true". Abgefragt hatte ich aber nur, ob der existiert. In sub handleIntentNotRecognized hatte ich dafür das Codestock ganz oben in:
if ($data_old->{what} // undef ) {
...
}
eingefasst.
Ich habe es mal wieder eingebaut, wie der Parameter benannt werden soll, kann man ja noch ändern und auch, ob man den am Device konfigurieren sollte.

Die neue Version hänge ich noch nicht dran, weil da noch eine Änderung nötig ist:
In der sub RHASSPY_DialogTimeout klemmt es noch mit 'SilentClosure' obwohl da ein Leerzeichen drin ist. Ich meine das ging früher.
Die getResponse liefert als return einen Leerstring. Der wiederum wird von der sub respond durch die Fehlermeldung ersetzt.






Beta-User

Moin,

kurze Antwort, sorry, heute ist wenig bis keine Zeit dafür...

Inhaltlich schaue ich mir deine Antwort bei Gelegenheit näher an, die Änderungen in der commandref bedeuten aber: Ich habe arge Zweifel, dass es richtig ist, wenn nach handleCustomIntent() dann zwangsweise setDialogTimeout() aufgerufen werden muss, sobald komplexe Daten kommen. Ich meine nach der gestrigen Analyse, dass es besser wäre, diesen default zu ändern, und den User aufzufordern, es explizit mitzuteilen, wenn er diese Funktion haben will und nicht das "einfache" respond()...

Eben weil respond() schon besser mit HASH-Type Rückgaben umgehen kann.

Nett war irgendwie, wieder über den [0.5...]-Thread zu stolpern. Dein Thread hier knüpft ja unmittelbar an die dortigen noch offenen "Wackeligkeiten" an.
Server: HP-elitedesk@Debian 12, 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

gregorv

ZitatEben weil respond() schon besser mit HASH-Type Rückgaben ...
Interesant, hatte heute morgen die gleiche Idee, da habe ich mir nämlich die respond() mal genauer angeschaut (wegen SilentClosure Problem).
Dafür habe ich inzwischen eine Lösung.
Das Problem ist, dass die getResponse() den Antwort Text aus $hash->{helper}{lng} holt (weil getKeyValFromAttr mangels response Attribut am Device nichts liefert. Damit der Text aber aus $hash->{helper}{lng} geholt werden kann, muss SilentClosure in der Datei rhasspy-xx.cfg drin sein. Also kommt wieder ein Leerstring heraus und die respond() steigt aus.
Ich habe mal folgende Änderung eingebaut:
In der getResponse() am Anfang die Zeile:
    if ( $identifier eq 'SilentClosure' ) { return 'silent'; }
eingefügt.
Damit steigt die respond() schon mal nicht mehr aus.
In der respond() dann auch am Anfang die Zeile:
    if ( $response eq 'silent' ) { $response = q{}; }
eingefügt.
Ab der Stelle scheint ein Leerstring als Antworttext sauber zu funktionieren (auch im Log). Auch stellt dieser Lösungsansatz sicher, dass die 'NoValidResponse' response noch funtioniert, für den Fall, dass in der Language Datei mal ein respons Identifier fehlen sollte
2024.10.19 09:43:21 1: XXX->getResponse starting identifier = :SilentClosure
2024.10.19 09:43:21 1: XXX->respond starting response = :silent
2024.10.19 09:43:21 5: published hermes/dialogueManager/endSession {"customData":{"name": "links","prevPos": "0","room": "arbeitszimmer"},
   "intentFilter": null,"sessionId": "arbeitszimmer-Roberta_de_linux_v3_0_0-99f18e55-0308-4d4b-a497-dad59175ecd7","siteId": "arbeitszimmer","text": ""} <----- !

Unschön sind die Ifs, weil 'Sonderlocke', die man vermeiden sollte, und die Inkonsistenz für den Identifier, weil der in den $languagevars nun gar nicht mehr drin sein muss.
Wenn Dir was besseres einfällt - die Problem-Analyse steht ja oben. Ein Leerzeichen als Antworttext quittiert mein Satellit übrigens mit der leisen, aber deutlich hörbaren Audio Ausgabe 'pffft'. In hermes/dialogueManager/endSession ... sollte der Value von text ein echter Leerstring sein (siehe Log oben).
Als Alternative wäre die Lösung 'SilentClosure' => " ", also eher nicht geeignet - abgesehen davon dass dieser Parameter da wenig Sinn macht.

Ich werde mich mit dem Thema respond() statt setDialogTimeout() mal etwas beschäftigen. Und mir den  [0.5...]-Thread mal anschauen.

gregorv

ZitatIch werde mich mit dem Thema respond() statt setDialogTimeout()...
Das war eine harte Nuss!
response() statt setDialogTimeout() wäre zwar möglich, aber dann muss man fast alles nachbauen, was in setDialogTimeout() schon drin ist. (setDialogTimeout() von response() aufrufen geht nicht, weil response() wieder setDialogTimeout() aufruft ->  Endlos-Schleife!)
Die gefundene Variante erweitert setDialogTimeout(), damit es mit dem response() Parameter ($error, von der CustomIntent()), was anfangen kann.
nötig ist zwischen die Zeilen:
    my $siteId = $data->{siteId};und:
    $data->{'.ENABLED'} = $toEnable; #dialog folgende Erweiterung:
    my $sendIntentNotRecognized = "true";
    if ( ref $response eq 'HASH' ) {
        $sendIntentNotRecognized = $response->{sendIntentNotRecognized};
        $toEnable = $response->{intentFilter} if $toEnable ~~ [qw(ConfirmAction CancelAction)];   
        $timeout = $response->{sessionTimeout} if defined $response->{sessionTimeout} && looks_like_number( $response->{sessionTimeout} ) && $timeout == _getDialogueTimeout($hash) ;
        delete $response->{intent};
        delete $response->{intentFilter};
        for my $key (keys %{$response}) {
            $data->{$key} = $response->{$key};
        }
    }
*1 my $sendIntentNotRecognized = "true";     -> damit es wie vorher funktioniert, falls die CustomIntent() das nicht abschaltet.
falls $ response ein hash ist
*2 $sendIntentNotRecognized = $response->{sendIntentNotRecognized}; -> das ist "true" oder nicht vorhanden - meine CustmIntenet() (Blinds() muss es also als "true" mitliefern
*3 $toEnable = $response->{intentFilter} -> wird später mit dem alten Code weiterbearbeitet, übergebener Parameter $toEnable hat Vorrang.
*4 $timeout = $response->{sessionTimeout} -> wird später mit dem alten Code weiterbearbeitet, übergebener Parameter $timeout hat Vorrang
*5 delete $response->{intent}; und delete $response->{intentFilter}; löscht diese Keys aus dem $response array (intent würde sonst den alten richtigen Wert überschreiben)
*6 for my $key (keys %{$response}) {... kopiert den Rest von $response in $data damit es später noch zur Verfügung steht

zusätzlich wird die Zeile:
            sendIntentNotRecognized => 'true', #'false',zu:
            sendIntentNotRecognized => $sendIntentNotRecognized,geändert. (siehe *1)

In der handleCustomIntent werden sämtlich Änderungen wieder entfernt. Also nur noch:
        return setDialogTimeout($hash, $data, $timeout, $error);

Vorteile gegenüber der vorherigen Variante in handleCustomIntent:
* die Bearbeitung von erweiterten Daten kann von allen Intents genutzt werden.
* zusätzliche keys im return hash können frei hinzugefügt werden und sind über die Laufzeit der session verfügbar.

Nachteil: Die Änderung erfolgt in einer sub, die von anderen Intent auch benutzt wird - das Risiko einer Störung schätze ich als sehr gering ein. Notfalls kann man die Bedingung:
if ( ref $response eq 'HASH' )um
if ( ref $response eq 'HASH' && defined $response->{SezifischerKey} )erweitern.

Viel Spass beim Testen

10_RHASSPY.pm angehängt und alle Änderungen mit @@@ markiert.




gregorv

@Beta-User
Für eine Funktionserweiterung meines CustomIntent habe ich den Group Parameter in $data gesetzt und RHASSPY::handleIntentSetOnOffGroup() aufgefufen. Das funktioniert soweit, aber mir ist aufgefallen, dass die handleIntentSetOnOffGroup() und auch die handleIntentSetOnOff() nur 'on' und 'off' kennt. Ich habe mal folgendes probiert:
in handleIntentSetOnOffGroup() hinter der Zeile:
my $cmdOff = $mapping->{cmdOff} // 'off';die Zeile:
#my $cmd = $value eq 'on' ? $cmdOn : $cmdOff;auskommentiert, und folgende Zeilen hinzugefügt:
        my $cmdAny = $mapping->(cmdAny) // $value;
        my $cmd;
        if ( $value eq 'on' ) { $cmd = $cmdOn;
        }elsif ( $value eq 'off' ) { $cmd = $cmdOff;
        }else { $cmd = $cmdAny; }
 
Damit ist es möglich einen beliebigen Wert für $Value zu nutzen. Es greifen da die original Steuer Befehle für ein Device und auch (!!!) die im eventMap Attribut konfigurierten Übersetzungen z.B.:
on:Zu off:Auf stop:Stop open:Offen closed:GeschlossenDamit kann man auch Befehle wie 'hoch/runter' oder 'Auf/Zu' (case Sensitiv) direkt im Rhasspy Sentence verwenden, wenn das in eventMap passend zugewiesen wird.

* $cmdAny = $mapping->(cmdAny) // $value;  -> als weiteren Parameter in Attribut rhasspyMapping, falls man den $value mit situtionsabhängigen Werten überschreiben will, falls nicht ist es der pure Inhalt von $value.
* if ( $value eq 'on' )... -> hier gibt es nun drei Alternativen, die mit elsif der Variablen $cmd zugewiesen werden.

Bitte schau Dir das mal an, ob das gefahrlos so eingebaut werden kann - ich weiß nicht ob es nicht an anderer Stelle stört. Es muss ja einen Grund gegeben haben, warum mit rhasspyMapping ein eigenes Attribut geschaffen wurde. Für FHEM scheint es mir nicht nötig ???

Beta-User

Zitat von: gregorv am 23 Oktober 2024, 14:02:37Bitte schau Dir das mal an, ob das gefahrlos so eingebaut werden kann - ich weiß nicht ob es nicht an anderer Stelle stört. Es muss ja einen Grund gegeben haben, warum mit rhasspyMapping ein eigenes Attribut geschaffen wurde. Für FHEM scheint es mir nicht nötig ???
Lustige Sichtweise:
rhasspyMapping war "immer schon" da, ich fand das nur ziemlich unnötig und habe das so umgebaut, dass es in der Regel ohne geht 8) .

Deinen Vorschlag schaue ich mir bei Gelegenheit mal intensiver an, für den ersten Eindruck wehrt sich da ziemlich viel in mir. Kurzform:
- Der Versuch mit OnOff war, das absolut (Sprach-) neutral zu gestalten (=> Prinzipverstoß)
- eventMap ist ein Attribut, das ich hasse. Ist nur Kosmetik und mAn. effektiv ziemlich verwirrend (ist emotional, ist aber halt so). Finde "sprechende" Icons für das Web-Interface besser.
- Wenn man schon ein mapping braucht, kann man doch auch gleich die onOff-Werte (auf der FHEM-Seite) passend setzen. Hat es funktionale Vorteile, die Optionen zu doppeln (oder ist es gar nicht doppelt)?
- eventMap kennt mehrere Facetten (siehe HASH-Variante!). Vielleicht geht es bei dir direkt, wenn du die "richtige" Variante wählst?

Hier noch mein onOff-Intent:

[de.fhem:SetOnOff]
rooms=([(im|in dem|auf dem|in der|auf der)] $de.fhem.Room{Room})
morerooms=(und [(im|in dem|auf dem|in der|auf der)] $de.fhem.Room{Room1})
devSetOnOff=($de.fhem.Device-SetOnOff{Device})
onOff=((an|ein){Value:on}|aus{Value:off})
an=((an|ein){Value:on})
aus=(aus{Value:off})
den=(den|die|das)
cmdmulti=(schalte|schalt|mache|mach|stelle|stell)
cmddrive=(fahre|fahr)
cmdopenclose=(öffne{Value:on}|(schließe|schließ){Value:off})
openclose=((hoch|auf){Value:on} | (zu|runter){Value:off})
grpMark=<de.fhem:SetOnOffGroup.grpMark>

(<cmdmulti>|starte) [<den>] <devSetOnOff> [und [<den>] $de.fhem.Device-SetOnOff{Device1}] [<rooms> [<morerooms>]] <onOff>
<cmddrive> [<den>] $de.fhem.Device-blind{Device} [und [<den>] $de.fhem.Device-blind{Device1}] [<rooms> [<morerooms>]] <openclose>
<cmdopenclose>[<den>] $de.fhem.Device-blind{Device} [und [<den>] $de.fhem.Device-blind{Device1}] [<rooms>[<morerooms>]]
<cmdmulti> [<den>] $de.fhem.Device-blind{Device} [und [<den>] $de.fhem.Device-blind{Device1}] [<rooms> [<morerooms>]] <openclose>
Server: HP-elitedesk@Debian 12, 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

gregorv

Zitat- Der Versuch mit OnOff war, das absolut (Sprach-) neutral zu gestalten (=> Prinzipverstoß)
stimmt schon, passt eigentlich eher zu einem Intent Generic oder so. Ich hatte cmdAny nur vermisst, weil mein CustomIntent ja Auf/Zu kann. Der Aufruf einer vorhandenen handle...() von 99_myUtils aus sollte das auch können und noch ein weiterer Punkt ist aufgefallen. Wenn man z.B. die handleIntentSetOnOffGroup() aufruft wird ja auch der Dialog mit eigener Ansage beendet wegen respond() am Ende, weshalb ich den Aufruf noch an eine Bedingung geknüpft habe.:
respond( $hash, $data, getResponse($hash, 'DefaultConfirmation') ) if ( ! defined $data->{silent});Es ist sehr hilfreich, wenn man aus den selbstgebauten Intent die handleIntentSetOnOffGroup(), oder ggf. auch andere, aufrufen kann. Eventuell könnte man die Kernfunktionen von handleIntentSetOnOffGroup() in eine helper...() Funktion auslagern, die von handleIntentSetOnOffGroup() aufgerufen wird. Ein Custom Intent könnte dann die helper...() aufrufen.
So kann meine Blinds() nun auch Gruppen von Rollläden und im Code muss man nur die Gruppe ermitteln, bzw. prüfen ob das was in $data->{Device} steht, auch wirklich eine Gruppe ist und die handleIntentSetOnOffGroup() mit:
  if (defined $group){
    $data->{Group} = $group;
    $data->{silent} = 1;
    RHASSPY::handleIntentSetOnOffGroup($hash, $data);
    $response = "alle rolläden gestartet";
  }else{
Group erwartet die Funktion und silent, damit sie nicht mit respond und mit ihrer eigenen Ansage den Dialog beendet.
Das cmdAny ist da hauptsächlich Kosmetik, weil ich sonst in meinem Rhasspy Intent im sentence einmal {Value:Zu} und für Gruppen {Value:on} hätte, gar nicht zu reden davon, dass mein letzter FS20 Rollladen on/off genau umgekehrt versteht, weshalb ich da eventMap verwenden musste.
Im übrigen - zum Thema eventMap - habe ich einige FHEM Devices für die ich mehrere Infos in mehren Zeilen anzeige (die zwei devices im Bild).
 Du darfst diesen Dateianhang nicht ansehen.
Für die Umwälzpumpe gibt es z.B. kein on/off Zustand-Icon und die Standart Glühlampe statt An ist eher unpassend. Dazu kommt noch, dass ich Devices habe wie das von der Heizung, wo ich mal länger nicht hinschaue und dann mit einem schnellen Blick nicht sofort weiß, dass das Icon Brenner in dieser Farbe auch Status An bedeutet - mit dem Text An ist das gleich klar.
Uff, das war ja jetzt ein richtiges Plädoyer für eventMap. Das ist aber gerade, was ich an FHEM so gut finde, nämlich, dass man sehr flexibel in der Gestaltung für verschiedenste persönliche Vorlieben ist. Das look&feel von HA gefällt mir einfach nicht.
Zitatzu doppeln (oder ist es gar nicht doppelt)?
Nein, ist es nicht, für meine Rollläden habe gar kein rhasspyMapping gesetzt - nur eventMap.
ZitatVielleicht geht es bei dir direkt, wenn du die "richtige" Variante wählst
Mhhh -das wäre aber Zufall, ich nutze das eigentlich nur so:
on:Zu off:Auf stop:Stop open:Offen closed:GeschlossenOffenbar ist mir die andere Variante noch nicht über den Weg gelaufen. :)
ZitatSetOnOffGroup.grpMark>
ist das wirklich das, was ich vermute, nämlich dass Rhasspy damit automatisch $data->{Group} füllt - das hätte mir eine Menge Zeit erspart in meiner Blinds(), wo ich mühselig durch die Group Einträge loope. Na ja, was am meisten Zeit brauchte war die Fehlersuche, dauernde FHEM restarts, bis ich herausgefunden hatte, dass man in perl eine loop nicht mit exit beendet sondern mit last - das ist nun wirklich unique >:(

Beta-User

Zitat von: gregorv am 23 Oktober 2024, 23:56:55ist das wirklich das, was ich vermute
Nope, das ist einfach ein Fehler :o ....
Diese Variable wird in diesem Intent dann gar nicht genutzt, sondern nur im Ausgangs-Gruppen-Intent:
[de.fhem:SetOnOffGroup]
grpRooms=( (überall|im ganzen Haus){Room:global} | <de.fhem:SetOnOff.rooms> )
grpMark=( die | alle | sämtliche | (überall|im ganzen Haus){Room:global} )
Zitat von: gregorv am 23 Oktober 2024, 23:56:55hatte cmdAny nur vermisst, weil mein CustomIntent ja Auf/Zu kann. Der Aufruf einer vorhandenen handle...() von 99_myUtils aus sollte das auch können
Bin ehrlich gesagt bisher nicht auf den Gedanken gekommen, dass man die internen Funktionen auch aus CustomIntent-Code heraus aufrufen könnte, aber na ja, das macht uU. Sinn. Als Bedingung würde ich nur was wählen wollen, was "selbsterklärend" ist; "noResponse"?

Aber "cmdAny" mit eigenem Code zu begründen, ist m.E. ein Zirkelschluss :)) .

Zitat von: gregorv am 23 Oktober 2024, 23:56:55
Zitatzu doppeln (oder ist es gar nicht doppelt)?
Nein, ist es nicht, für meine Rollläden habe gar kein rhasspyMapping gesetzt - nur eventMap.
Mit "doppeln" war gemeint: Gibt es bereits heute eine Möglichkeit, das gewünschte Ergebnis zu erzielen (ohne sich zu verrenken)? Da _glaube_ ich immer noch, dass es "einfacher" ist, neben eventMap dann eben auch rhasspyMapping zu setzen. Mit "einfacher" ist gemeint:
- Man kann es jedem User erklären. Wer mappt, muss es halt konsequent machen ;) . Ist zwar oft nicht nötig, aber andererseits auch nicht verboten, eigene rhasspyMappings zu setzen :) .
- Der Code bleibt klar und eindeutig und ich muss mir nicht überlegen, was sich jemand bei dem Zusatzcode gedacht hat, wenn mich jemand anderes in ein paar Monaten oder Jahren fragt, wie das im Detail funktionieren soll. Dazu müßte man es dokumentieren, und ich _vermute_ (nach meinen bisherigen Erfahrungen mit sowas), dass mehr Erklärungstext am Ende nur zu mehr Verwirrung führen wird.

Daher die Bitte: Es gibt eine einfache Option, das bestehende rhasspyMapping pro Device zu exportieren (get <RHASSPY> export_mapping <device>) => nehmen, ändern und gut ist?
Wenn das nicht klappt, schaust du dir an, wie das mit komplexeren eventMaps geht ("The explicit variant...").
Was den "umgekehrten" FS20-Aktor angeht: Weiß nicht mehr, ob es irgendwo eine Option gab, die Funktion in Software umzubiegen (also auch die level zu invertieren), aber wieso drehst du nicht die Leitungen (bzw. den Aktor in der Dose) einfach um?

Für den Code brauche ich noch etwas...
Server: HP-elitedesk@Debian 12, 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