Neues Modul 98_questions: Frage/Antwort System

Begonnen von xanker, 25 April 2016, 20:29:25

Vorheriges Thema - Nächstes Thema

xanker

Hallo fhem-Community,

ich bin erst seit zwei Monaten dabei mein Smart Home mit fhem aufzubauen. Mit Hilfe der vorhandenen Module ist es mir möglich so ziemlich alles umzusetzen was ich gern hätte, an dieser Stelle auch ein großes Dank an alle Entwickler.

Es gibt allerdings eine Sache, die mir bisher gefehlt hatte. Eine Vollautomatisierung ist zwar an vielen Stellen eine schöne Sache, aber es gibt auch einzelne Aktionen die Moment abhängig sind, die also nur ausgeführt werden sollen, wenn ich es in diesem Moment explizit will.

Als kleines Beispiel: wenn ich das Haus verlasse (erkannt über PRESENCE Modul), dann wird nach 15 min Abwesenheit alles abgeschaltet (sofern noch eines der Geräte an war), das passiert dann aber auch wenn ich nach 16 Minuten wieder daheim ankomme. An dieser Stelle wäre es doch schön wenn man (z.B. über das yowsup (Whatsapp) Modul) eine Nachricht bekommt (z.B. "Es ist seit 15min niemand zuhause, aber es sind noch Geräte an. Soll ich sie abschalten?"), auf die man antworten kann. In diesem Fall wäre das "Ja" oder "Nein".
Ein anderes Beispiel: wenn ich meinen Wecker am Handy stelle (erkannt über AMAD2 Modul), dann soll fhem das interpretieren, dass ich (bald) schlafen gehe und schaltet entsprechend alles ab (nach einer definierten Zeit). Hier wäre es schön wenn ich gefragt werde "Wann soll ich alles ausschalten?" und darauf antworten kann (z.B über Sprachausgabe/-eingabe mit dem WebViewControl Modul).

Meines Wissens nach, lässt sich das bisher nur relativ umständlich mit dummies und notifies realisieren. Wenn man das für mehrere Fragen/Antworten so umsetzen will, wird das schon etwas mühselig. Daher habe ich mich dran gemacht, ein Modul für dieses Problem zu erstellen und würde dies gerne mit euch teilen. Ich hoffe ich habe dafür das richtige Unterforum erwischt, ansonsten bitte verschieben :)

Da ich mich jetzt auch erst seit fhem mit perl beschäftige, ist der Code sicher an manchen Stellen noch verbesserungswürdig. Ich würde es auf dem aktuellen Stand mal als "beta" bezeichnen. Damit das Modul läuft, wird das perl Modul String::Interpolate benötigt (siehe unten).

Ich will hier nur kurz beschreiben wie man das Modul nutzt, die genaue Beschreibung kann man sich dann in der commandref anschauen.

Es besteht die Möglichkeit für jede Frage ein eigenes Device anzulegen, damit wird alles über das define festgelegt. Man kann aber auch ein "Masterdevice" anlegen, welchem dann mehrere Fragen zugewiesen werden können, welche dann als readings gespeichert werde. Letzteres eignet sich für temporäre Fragen, die man z.B. nur einmalig stellt, oder wenn man die Anzahl an devices minimieren will, allerdings sind hier dann Änderungen an einer Frage umständlicher als über DEF.

Genug geredet, hier mal das define für ein "single question device":
define <name> questions "<question>" [<recipients>] "<answer1>":"<cmd1>" ["<answer2>":"<cmd2>" [ ... ["<answerX>":"<cmdX>"]]]
Als <recipients> werden bisher nur yowsup (Whatsapp) und webViewControl Devices unterstützt. Sofern ein oder mehrere Empfänger (getrennt durch ",") definiert sind, wird die Frage <question> direkt weiter geleitet, also eine WhatsApp Nachricht gesendet, oder per Sprache ausgegeben. Zudem wird bei webViewControl Devices danach die Spracheingabe gestartet, sodass man direkt antworten kann. Wenn nun per WhatsApp bzw. Sprache geantwortet wird, dann wird die Antwort direkt mit allen Antwortmöglichkeiten <answer1>...<answerX> verglichen (die Antwortmöglichkeiten werden als regex behandelt). Sollte eine Antwort auf eins der regex matchen, so wird das entsprechende Kommando <cmd?> ausgeführt (fhem(<cmd?>)). Man benötigt also kein Notify sofern man <recipients> definiert hat.

Hier mal ein Beispiel:
define Frage1 questions "Wie hell soll ich die Lampe schalten?" androidTablet "^[^\d]*(\d+)[ \t]*(%|Prozent).*$":"set LEDs brightness $1"
Bei androidTablet handelt es sich um ein webViewControl Device. LEDs ist ein MilightDevice, also eine Lampe bei der ich die Helligkeit prozentual einstellen kann. Das androidTablet startet nun die Sprachausgabe mit "Wie hell soll ich die Lampe schalten?" und startet danach die Spracheingabe. Nun kann ich z.B. sagen "Dimme die Lampe bitte auf 50 Prozent". Die "50" wird dann (aufgrund vom regex) weitergegeben, sodass das Kommando "set LEDs brightness 50" ausgeführt wird.

Für letzteres wird übrigens String::Interpolate benötigt, oder gibt es noch eine andere Möglichkeit, einen schon definierten String im nachhinein zu interpolieren?
Ich hoffe ich finde hier ein paar Interessenten für dieses Modul und würde mich freuen über Ratschläge wie ich das Modul noch verbessern könnte. Selbstverständlich kann ich auch weitere Devicetypen als <recipients> implementieren, einfach hier anfragen.

Was aktuell auf der TODO-Liste steht:

  • eine Frage, die schon beantwortet wurde, darf nicht erneut beantwortet werden, bevor sie erneut gestellt wurde.
  • eine schöne Lösung finden, wie im Falle von mehreren unbeantworteten Fragen, entschieden wird welche beantwortet werden soll.

Der zweite Punkt ist nur wichtig, wenn eine Antwort auf die Antwortmöglichkeiten von unterschiedlichen Fragen matched und das auch nur wenn diese unterschiedlichen Fragen auch an gleiche <recipients> gegangen sind. Man kann ja nicht immer davon ausgehen, dass eine Frage immer sofort beantwortet wird, zumindest dann wenn die Frage z.B. über WhatsApp gesendet wird, so besteht ja die Möglichkeit, dass bis zum beantworten eine zweite Frage gestellt wird. Man könnte entweder mit IDs arbeiten, die bei der Antwort mit angegeben werden müssen, was aber nicht so schön ist, oder dass ein <recipient> immer nur die ihm zuletzt gestellt Frage beantworten kann. Ich tendiere zu letzterem, andere Vorschläge sind aber willkommen :)

Ich hoffe ich hab nicht zu viele Rechtschreibfehler drin, keine Lust das selbst nochmal alles zu lesen :D
Maintainer vom flex Style.
Intel NUC mit fhem in Docker Container | Homematic | SIGNALduino 433MHz | HUE Bridge | Harmony HUB | lepresenced | alexa-fhem ...

Prof. Dr. Peter Henning

#1
Hm, guter Versuch, aber so nicht wirklich brauchbar. Also mal ehrliche Kritik, als Ansporn gemeint:

Ich halte es für schlechten Stil, für jede Frage ein eigenes Device anzulegen. Stattdessen sollte es EIN Device geben, dessen String-Kommando-Paare in einer separaten Datei stehen, die nach einer Änderung per Modulkommando wieder neu eingelesen werden kann. Ich selbst habe so etwas in Betrieb, um meine Voice-Kommandos an FHEM zu interpretieren..

Außerdem ist hier kommentarfreier Code  geliefert worden. :P

LG

pah

igami

Etwas ähnliches habe ich mir mit DOIF gebastelt.
Dialoge die ich per Telegram führen kann. Aktuell um die Waschmaschine zu programmieren, offene Fenster angezeigt zu bekommen, meine Grilltemperatur zu überwachen, oder fhem auf updates zu prüfen. Das ganze ist aber noch sehr unausgereift.
Pi3 mit fhem.cfg + DbLog/logProxy
Komm vorbei zum FHEM Treffen im Kreis Gütersloh! Das nächste Mal im April 2020.

MAINTAINER: archetype, LuftdatenInfo, monitoring, msgDialog, Nmap, powerMap
ToDo: AVScene, FluxLED

Prof. Dr. Peter Henning

Das Problem ist dabei die Semantik.

Um nur ein Beispiel zu nennen: Das Google-Voice-Api liefert drei verschiedene Schreibweisen zurück, wenn ich dem Tablet eine Uhrzeit nenne (diese Anwendung, als "Smarter Wecker", ist im Buch detailliert aufgeführt).  Das bedeutet: Sobald man mehr als nur eine Speziallösung haben will, wird es echt schwierig.

LG

pah

xanker

#4
Für jede Frage ein eigenes Device anzulegen finden ich auch suboptimal, daher biete ich ja auch die Möglichkeit nur ein "Masterdevice" anzulegen (siehe commandref), welchem dann beliebig viele Fragen zugewiesen werden können, diese werden dann (inkl. der Kommandos) als Readings gespeichert. Anstatt sichtbare Readings zu verwenden, habe ich mir auch überlegt, diese "hidden" zu machen und dann Änderungen über Internals zuzulassen. Alternativ könnte ich es auch so umsetzen, dass alle Fragen in der Definition des Masterdevices festgelegt werden, das hat allerdings die Folge, dass es bei vielen Fragen recht unübersichtlich werden könnte. Es wäre natürlich auch kein Problem anstatt Readings, Dateien zu verwenden um die Fragen zu speichern.

Das Problem mit der Semantik besteht ja ohnehin immer, außer man entwickelt ein Grammatik Modul, was aber sehr aufwendig ist und dann wird sicher auch nie jeder Fall abgedeckt. Somit ist es dem Nutzer selbst überlassen die entsprechenden Antwort-regex "richtig" zu definieren. Zudem soll das Modul ja auch auf Nachrichten (und nicht nur auf Sprache) reagieren, dann muss der Nutzer natürlich selbst darauf achten, dass er die Antwort richtig formuliert.

Ich halte es allerdings dennoch für sinnvoll, das ganze als Modul zu haben, da eine Lösung mit DOIF, Notify, etc. auch nicht gerade schön ist, vorallem wenn nicht jede Frage an das gleiche Device gehen soll (bzw. nicht von jedem Device beantwortet werden können soll).

Zu den fehlenden Kommentaren: ich gelobe Besserung und werde das noch ausführlich kommentieren, ich wollte hier nur erstmal ein paar Anregungen sammeln, was ich im Allgemeinen noch verbessern könnte.

An der Stelle auch Danke an igami, dein Kommentar hat mich auf die Idee gebracht, das Modul in der Hinsicht zu erweitern, dass man z.B. ein Schlüsselwort (wie in deinem Beispiel "/start") definieren kann und einem dann mögliche Operationen angeboten werden. Zudem wäre es auch eine Lösung, wenn eine Antwort auf mehrere Fragen matcht, dass man dann gefragt wird, welches Kommando dann ausgeführt werden soll.


Edit:
gibt es überhaupt eine Möglichkeit Internals im FHEMWEB zu ändern, also so wie DEF per Draufklicken? und dann auch auf eine Änderung zu reagieren?
Maintainer vom flex Style.
Intel NUC mit fhem in Docker Container | Homematic | SIGNALduino 433MHz | HUE Bridge | Harmony HUB | lepresenced | alexa-fhem ...