Talk2Fhem: Unterschied zwischen den Versionen

Aus FHEMWiki
K (Anker-Links auf Abschnitte innerhalb dieser Seite geändert)
 
(329 dazwischenliegende Versionen von 5 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
{{Infobox Modul
{{Infobox Modul
|ModPurpose=Das Modul stellt eine Verbindung zwischen natürlicher Sprache und FHEM Befehlen her
|ModPurpose=Das Modul stellt eine Verbindung zwischen natürlicher Sprache und FHEM Befehlen her
|ModType=h]
|ModType=d
|ModCmdRef=Talk2Fhem
|ModCmdRef=Talk2Fhem
|ModForumArea=Unterstützende Dienste
|ModForumArea=Frontends/Sprachsteuerung
|ModTechName=39_Talk2Fhem.pm
|ModTechName=39_Talk2Fhem.pm
|ModOwner=Oliver Georgi
|ModOwner=Oliver Georgi ({{Link2FU|10222|Phill}})
}}
}}


 
Diese Seite beschreibt die Funktionsweise und Konfiguration des Moduls Talk2Fhem.
 
{{Baustelle}}<br><br>
Diese Seite beschreibt die Funktionsweise und Konfiguration des Moduls 39_Talk2Fhem.pm


== Voraussetzungen ==
== Voraussetzungen ==
[[Datei:ModulTalk2FhemScreenshot.png|360px|thumb|right]]
[[Datei:ModulTalk2FhemScreenshot.png|360px|thumb|right]]
Es ist sehr zu empfehlen, für die Konfiguration des Moduls, im Webfrontend von FHEM die Syntaxhervorhebung zu aktivieren. Die Aktivierung des erweiterten Editors ist hier [[Konfiguration#Syntaxhervorhebung]] beschrieben.
Es ist sehr zu empfehlen, für die Konfiguration des Moduls, im Webfrontend von FHEM die Syntaxhervorhebung zu aktivieren. Die Aktivierung des erweiterten Editors ist [[Konfiguration#Syntaxhervorhebung|hier]] beschrieben.


Kenntnisse im Bereich Regulärer Ausdrücke (RegExp) in Perl sind hilfreich, aber nicht zwingend erforderlich. Ein kurzer Einstieg kann hier eingesehen werden. [[Modul_Talk2Fhem#Häufig_verwendete_RegExp]]
Kenntnisse im Bereich Regulärer Ausdrücke (RegExp) in Perl sind hilfreich, aber nicht zwingend erforderlich. Ein kurzer Einstieg kann hier eingesehen werden. [[Talk2Fhem#Häufig_verwendete_RegExp|Häufig_verwendete_RegExp]]


== Allgemeines ==
== Allgemeines ==
Das Modul Talk2Fhem stellt eine Verbindung zwischen natürlicher Sprache und FHEM Befehlen her. Es ist ein überaus flexibles und relativ einfach zu konfigurierendes Script mit dem man sehr natürlich kommunizieren kann. Die Konfiguration erfolgt dabei über das FHEM Webfrontend.  
Das Modul Talk2Fhem stellt eine Verbindung zwischen natürlicher Sprache und FHEM Befehlen her. Es ist ein überaus flexibles und relativ einfach zu konfigurierendes Script mit dem man sehr natürlich kommunizieren kann. Die Konfiguration erfolgt dabei über das FHEM Webfrontend.


Bei der Verarbeitung der Sprachbefehle erfolgt keine grammatikalische Analyse, sondern es wird auf definierte Schlüsselwörter reagiert. Das Modul erkennt von sich aus diverse Zeit- und Datumsangaben und löst bei Bedarf zu diesen Zeiten die FHEM Kommandos aus.
Es werden diverse [[#Zeitenerkennung|Zeit- und Datumsangaben]] erkannt. Außerdem ist es möglich [[#Eventenerkennung|Ereignisse zu formulieren]], welche die Befehle mit einer Bedingung verknüpfen. Bei der weiteren Verarbeitung der Sprachbefehle wird die Sprache mit definierten regulären Ausdrücken verglichen.
 
Es lassen sich Antworten generieren, die Abhängig von den gesendeten Sprachbefehlen sind. Das vom Author verfolgte Konzept ist aber: ''Erzeuge eine Meldung wenn etwas nicht verstanden oder fehlgeschlagen ist, ansonsten führe den Befehl mit einer kurzen Erfolgsmeldung wie "OK" oder "Gerne" aus.''
 
Die Text Ein- sowie Ausgabe der natürlichen Sprache übernehmen andere Anwendungen. Hierzu gibt es eine Reihe von Möglichkeiten die unter [[#Anwendung|Anwendung]] dargestellt sind. Funktionierende Lösungsansätze werden hier gerne mit aufgenommen.


=== Funktionsweise ===
=== Funktionsweise ===
Zeile 28: Zeile 29:
Die Zerlegung des Sprachbefehls erfolgt in mehreren Schritten.  
Die Zerlegung des Sprachbefehls erfolgt in mehreren Schritten.  
# Aufteilen des Sprachbefehls in einzelne Kommandos anhand des Wortes UND
# Aufteilen des Sprachbefehls in einzelne Kommandos anhand des Wortes UND
# Suchen nach Ereignisansagen und entfernen für die weitere Verarbeitung
# Erkennen von Zeit- und Datumsangaben und entfernen für die weitere Verarbeitung
# Erkennen von Zeit- und Datumsangaben und entfernen für die weitere Verarbeitung
# Entfernung unnötiger Wörter
# Entfernung überflüssiger Wörter
# Vergleich mit den definierten Schlüsselwörtern
# Vergleich mit den definierten regulären Ausdrücken
# Konvertieren in ein FHEM Kommando
# Konvertieren in ein FHEM Kommando
# Zeitgebundenes auslösen des FHEM Kommandos
# Antwortsatz bilden
# Zeit- und Eventgebundenes auslösen des FHEM Kommandos


== Installation ==
== Installation ==


Solange das Modul noch nicht offiziell aufgenommen wurde, muss die Datei 39_Talk2Fhem.pm manuell in das Verzeichnis FHEM/ kopiert werden. Siehe Forumsbeitrag. [https://forum.fhem.de/index.php/topic,80960.30.html]
update 39_Talk2Fhem
shutdown restart
 
Diskussion hier:
{{Link2Forum|Topic=80960|LinkText=Forumsbeitrag}}.


== Definition ==
== Definition ==
Zeile 43: Zeile 50:
Zum testen der Konfiguration ist es Ratsam vorerst das Attribut disable auf 1 zu setzen. Hierbei wird die Auslösung der FHEM Kommandos unterdrückt.
Zum testen der Konfiguration ist es Ratsam vorerst das Attribut disable auf 1 zu setzen. Hierbei wird die Auslösung der FHEM Kommandos unterdrückt.
  attr talk disable 1
  attr talk disable 1
attr global language DE
oder
attr talk T2F_language DE


== Anwendung ==
== Anwendung ==
Der Sprachbefehl wird über das Kommando "set" an das Modul geleitet.
Der Sprachbefehl wird über das Kommando '''set''' oder '''set !''' an das Modul übermittelt.
  set talk Guten Morgen liebes Zuhause
  set talk Guten Morgen liebes Zuhause
''Wird kein Text angehängt, wird der letzte Sprachbefehl erneut ausgeführt.''
=== Eingabemethoden ===
Die Herkunft der Sprachbefehle für das Modul sind vielfältig. Hier werden einige Methoden beschrieben wie der Sprachbefehl in das Modul gelangen kann.
==== Messenger Telegram ====
Ist ein [[TelegramBot]] telbot definiert, reicht ein einfaches "notify" um die Nachrichten an FHEM an Talk2Fhem weiterzuleiten.
define <span style='color:red'>n_telbot</span> notify <span style='color:red'>telbot</span>:msgText.* set talk $EVENT
Schon kann mit FHEM gechattet werden... ;)
Mit Telegram lässt sich auch leicht der Absender der Nachricht verarbeiten. Siehe hierzu [[#Personalifizierung]]
==== Google Home Geräte ====
Momentan ist es leider noch notwendig über einen Umweg die Sprache von einem GoogleHome in FHEM zu bringen. Hierzu ist es notwendig einen funktionierenden DNS Service am laufen zu haben. Damit FHEM per Webadresse im Internet erreichbar ist.
*Ein FHEMWEB Device anlegen
define api FHEMWEB 8087 global
attr api HTTPS 1
attr api allowfrom  1
attr api csrfToken  None
*Ein allowed Device anlegen
define allowed_api allowed api
attr allowed_api allowedCommands set
attr allowed_api allowedDevices talk
attr allowed_api basicAuth  {"$user:$password" eq 'user:passwort'}
attr allowed_api validFor  api
*Mit Googlekono bei IFTTT.com anmelden
*New Applet
*+this GoogleAssistant -> Say a phrase with a text ingredient
* Die drei Triggertexte wählen z.b.
**das Haus $
**sag dem Haus $
**frag das Haus $
***Problem bei zu kurzen Texten hat GoogleHome keine anderen Anfragen mehr angenommen.
*Einen Antworttext überlegen z.B. OK und in "What do you want the Assistant to say in response?" eintragen
*Language Deutsch
*+that Webhooks
*URL wählen
<nowiki>https://user:password@dnsservice:54387/fhem?cmd.talk=set talk <<<{{TextField}}>>>&XHR=1</nowiki>
*Fertig


=== Readings ===
Jetzt wird der gesamte Text bei dem genannten Triggerworten an FHEM weitergeleitet.


Im Reading '''set''' steht der letzte gesendete Sprachbefehl.
=== Readings / Ausgabemethoden ===
<br>Im Reading '''cmds''' steht das letzte ausgeführte FHEM-Kommando dessen Rückgabe in in das Reading '''fhem''' geschrieben wird.


Die Antworten und Modulinterne Fehler werden in den Readings '''answers''' und '''err''' ausgegben.  
Über die bereit gestellten Readings lassen sich weitere Module die z.B. für Sprachausgabe zuständig sind mit einbinden. 
*Im Reading '''set''' steht der letzte gesendete Sprachbefehl.
*Im Reading '''cmds''' steht das letzte ausgeführte FHEM-Kommando dessen Rückgabe, in den häufigsten Fällen ein Fehler, in das Reading '''response''' geschrieben wird.
*Die Antworten werden im Reading '''answers''' sofort ausgegeben.
*Die Modulinterne Fehler werden in dem Reading '''err''' ausgegben.
*In '''ifs''' stehen die Bedingungen mit der das letzte Kommando ausgeführt werden wird.
*'''notifies''' enthält eine Auflistung der Devices die für die aktuell wartenden bedingten Kommandos relevant sind. Auf diesen Devices liegt ein internes notify. 
*Das Reading '''origin''' enthält den erkannten Text der im Attribut T2F_origin definierten RegExp.


Das Reading '''status''' wird jedes mal gesetzt und erhält Werte nach folgender Priorität.
Das Reading '''status''' wird jedes mal gesetzt und erhält Werte nach folgender Priorität.
Zeile 61: Zeile 117:
|2.||'''disabled''' ||wenn das Attribute disable auf 1 steht
|2.||'''disabled''' ||wenn das Attribute disable auf 1 steht
|-
|-
|3.||'''err''' ||wenn der Befhel einen Fehler zurückgegeben hat
|3.||'''err''' ||wenn der Sprachbefehl einen Fehler zurückgegeben hat
|-
|-
|4.||'''answer''' ||wenn der Befehl eine Antwort ausgegeben hat
|4.||'''answer''' ||wenn der Sprachbefehl eine Antwort ausgegeben hat
|-
|-
|5.||'''done''' ||wenn keines der oberen Fälle eingetreten ist
|5.||'''done''' ||wenn keines der oberen Fälle eingetreten ist, also alles gut verlaufen ist
|}
|}


=== Beispiel ===
==== Beispiel 1 ====
Die FHEM Befehle werden eigenständig ausgeführt, sie können aber zur Überprüfung auch weitergeleitet werden. Das Beispiel zeigt auch wie auf Fehler und Antworten von Talk2Fhem reragiert werden kann.
Die FHEM Befehle werden eigenständig ausgeführt, sie können aber zur Überprüfung auch weitergeleitet werden. Das Beispiel zeigt auch wie auf Fehler und Antworten von Talk2Fhem reagiert werden kann.
Erstellen eines Notify
Erstellen eines Notify
  define n_talk notify talk:.* {}
  define n_talk notify talk:.* {}
Zeile 95: Zeile 151:
   
   
  }
  }
</syntaxhighlight>
==== Beispiel 2 Reading: Status ====
Eine weitere Möglichkeit Talk2Fhem mit anderen Modulen zu verbinden, ist über das Reading '''status''' möglich.
Die folgenden Lösung sieht auch eine Standardantwort vor.
'''!Achtung noch nicht getestet vom Author!'''
<syntaxhighlight lang="perl">
talk:status {
my $text = ReadingsVal("talk", $EVENT, "");
if ("$EVENT" eq "response") {
  #FHEM gibt bei Erfolg eig. keine Rückmeldung, also ist vermutlich was schief gelaufen
  $text = "Die Haussteuerung hat folgende Meldung gebracht. $text";
} elsif ("$EVENT" eq "err") {
  # Hier kann auch die Meldung noch detailierter an einen Messenger gesendet werden.
  $text = ["Das habe ich nicht verstanden!","Phuu das kann ich noch nicht!","Nein! Heute nicht.", "Wie bitte?"]->[rand(4)];
} elsif ("$EVENT" =~ /^answer/) {
  $text = ReadingsVal("talk", "answers", "Ich habe nichts zu sagen.");
} elsif ("$EVENT" eq "done") {
  $text = ["Ok.","Ja.","Gerne.", "Mach ich!"]->[rand(4)];
} else {
  $text = "Oh, es gibt etwas neues, bitte schau mal im Forum bei Talk2Fhem vorbei.";
}
fhem('set speaker speak "$text"') if $text;
}
</syntaxhighlight>
</syntaxhighlight>


== Modulinterne Spracherkennung ==
=== Zeitenerkennung ===
=== Zeitenerkennung ===
Die Zeit- und Datum Eingabe kann auf viele verschiedene Arten erfolgen.<br>
Die Zeit- und Datum Eingabe kann auf verschiedene Arten erfolgen.<br>
Die Datumerkennung umfasst folgende Phrasen:
Die Datumerkennung umfasst folgende Phrasen:
*morgen, übermorgen
*morgen, übermorgen
*in ... Wochen, Monat, Jahr
*in ... Wochen, Monat, Jahr
*in einem drei-,viertel,halben Jahr
*nächste Woche, Monat, Jahr
*nächste Woche, Monat, Jahr
*Wochentage
*Wochentage
Zeile 109: Zeile 197:
Die Zeiterkennung umfasst folgende Phrasen:
Die Zeiterkennung umfasst folgende Phrasen:
*in,nach ... stunden,minuten,sekunden
*in,nach ... stunden,minuten,sekunden
*in einer drei-,viertel,halben Stunde
*um ... (Uhr) (...)
*um ... (Uhr) (...)
*um drei-,viertel,halb,viertel vor/nach, 1-12
*heute - entspricht 12:00
*heute - entspricht 12:00
*früh - entspricht 9 Uhr
*früh - entspricht 9 Uhr
Zeile 122: Zeile 212:
*sofort
*sofort


Datum und Zeitangaben können natürlich kombiniert werden.
Datum und Zeitangaben können kombiniert werden. '''Morgen abend um 8 Uhr'''
<br>
<br>
Wird eine Zeit erfolgreich erkannt erfolgt die Ausführung des FHEM-Kommandos über das Modul '''at'''. Es wird ein at Eregnis angelegt welches den Namen ''at_<modulname>_<zeitindex>'' erhält.
Wird eine Zeit erfolgreich erkannt erfolgt die Ausführung des FHEM-Kommandos über das Modul '''at'''. Es wird ein at Ereignis angelegt welches den Namen ''at_<modulname>_<zeitindex>'' erhält.


Bei mehreren Kommandos über das Schlüsselwort ''UND'' wirkt sich der Zeitpunkt des ersten Kommandos auch auf das zweite und dritte ... aus.
Bei mehreren Kommandos über das Schlüsselwort ''und'' wirkt sich der Zeitpunkt des ersten Kommandos auch auf das zweite und dritte ... aus.
  Schalte die Heizung um 20 Uhr aus und mache die Rollläden runter
  Schalte die Heizung um 20 Uhr aus und mache die Rollläden runter
Beide Kommandos werden um 20 Uhr ausgelöst.
Beide Kommandos werden um 20 Uhr ausgelöst.
Zeile 132: Zeile 222:
Hat das zweite Kommando ebenfalls eine Zeitphrase wird diese Zeit genommen.
Hat das zweite Kommando ebenfalls eine Zeitphrase wird diese Zeit genommen.
  schalte die Heizung heute Abend ab und mache die Rollläden jetzt runter
  schalte die Heizung heute Abend ab und mache die Rollläden jetzt runter
==== Zeitenmodifikation ====
 
Wie oben gesehen wird der Zeitpunkt des ersten Kommandos vor dem "und" auch für das zweite nach dem "und" gesetzt. Vorausgesetzt er wird beim 2. Kommando nicht durch eine eigenständige Zeit (hier "jetzt") ersetzt.
Wie oben gesehen wird der Zeitpunkt des ersten Kommandos vor dem "und" auch für das zweite nach dem "und" gesetzt. Vorausgesetzt er wird beim 2. Kommando nicht durch eine eigenständige Zeit (hier "jetzt") ersetzt.
Wenn man die Zeit des zweiten Kommandos, relativ zum ersten setzen möchte, kann dies mit den Schlüsselwörtern ''dann'', ''danach'' oder ''wieder''  formuliert werden.
Wenn man die Zeit des zweiten Kommandos, relativ zum ersten setzen möchte, kann dies mit den Schlüsselwörtern ''dann'', ''danach'' oder ''wieder''  formuliert werden.
Zeile 139: Zeile 229:
  Mach am Freitag um 5 Uhr die Heizung aus und in einer Woche wieder an
  Mach am Freitag um 5 Uhr die Heizung aus und in einer Woche wieder an


Manchmal ist es notwendig etwas vor der angegebenen Zeit auszuführen. Hier lässt sich ein Offset zu dem ermittelten Zeitpunkt hinzufügen, um ihn zu ändern.
=== Objektverundung ===
<br>'''Beispiel'''
Es ist möglich Objekte in einer Auflistung in den Sätzen zu übergeben. Siehe hierzu [[#T2F_keywordlist|T2F_keywordlist]].
<syntaxhighlight lang='perl'>dusche\S?$ = (offset=>-3600, cmd=>'set d_log bad warm')</syntaxhighlight>
Rollos im Wohnzimmer, Esszimmer und in der Küche auf 70
Der Sprachbefehl
Schalte den Fernseher und die Soundanlage an
  ich will um 18:30 Uhr duschen
 
Legt folgendes at Ergnis an
=== Ereigniswiederholung ===
define at_assi_1513096200 at 2017-12-12T17:30:00 set d_log bad warm
Werden zwei Sätze über ein '''und''' miteinander verknüpft, kann im 2. Satz mit dem Wort '''wieder''' das Ereignis wiederholt werden.
 
'''Beispiel'''
schalte bitte die Klingel ab und in einer Stunde wieder ein
mach bitte die Garage auf und gleich wieder zu
Man benötigt hier nicht erneut den kompletten ersten Satz zu wiederholen.
 
''Um diese Funktion zu gewährleisten, sollte der anschließende Hinweis in [[#Klammer.C3.BCberf.C3.BChrung|Klammerüberführung]] beachtet werden.''
 
=== Eventabhängige Kommandos ===
Es lassen sich alle definierten Befehle mit Bedingungen verknüpfen, bei der Erfüllung diese dann ausgeführt werden.
 
'''Beispiel'''
Sag mir bescheid '''wenn es klingelt'''
  Mach die garage zu '''wenn es draußen dunkel wird'''
'''Wenn ich nach hause komme''' mach die Musik an
siehe hierzu [[#T2F_if]]


== Konfiguration ==
== Konfiguration ==


Die Konfiguration des Moduls wird hauptsächlich über die Definition (DEF) vorgenommen.
Die Konfiguration der Sprachbefehle wird Zeile für Zeile in der Definition (DEF) des angelegten Gerätes vorgenommen. Die einzelnen Definitionen müssen folgenden Schema entsprechen.
Eine Konfiguration beginnt immer mit der Definition der gesuchten Schlüsselwörtern gefolgt von einem Gleichheitszeichen ''(siehe Randnotiz)''. Diese werden Anhand von Regulären Ausdrücken (RegExp) beschrieben. Also z.B.:
garage auf =
Das bededutet, sobald die Wörter in der Reihenfolge "garage" und "auf" erkannt werden, wird der Kommandoteil der Konfiguration ausgeführt. Groß- und Kleinschreibung wird grundsätzlich ignoriert.
 
{{Randnotiz|RNText=Wichtig
{{Randnotiz|RNText=Wichtig
Vor und nach dem Gleichheitszeichen muss mindestens ein Trennzeichen vorhanden sein
Vor und nach dem Gleichheitszeichen muss mindestens ein Trennzeichen vorhanden sein
Zeile 159: Zeile 261:
*Nach dem "=" können zusätzlich auch Zeilenumbrüche eingefügt werden
*Nach dem "=" können zusätzlich auch Zeilenumbrüche eingefügt werden
}}
}}
<regexp> = <command>
=== RegExp-Teil ===
<RegExpPart> &#91;[[#Mehrere_RegExps|&&]] [[#RegExp_Optionen|[?!]]]<RegExpPart_n>] =
Eine Konfiguration beginnt immer mit der Definition der gesuchten Schlüsselwörter, gefolgt von einem Gleichheitszeichen ''(siehe Randnotiz)''. Diese werden Anhand von regulären Ausdrücken (RegExp) beschrieben. Also z.B.:
garage auf =
Das bededutet, sobald die Wörter in der Reihenfolge "garage" und "auf" erkannt werden, wird der Kommandoteil der Konfiguration ausgeführt. Groß- und Kleinschreibung wird grundsätzlich ignoriert.
=== Kommando-Teil ===
Der Kommandoteil folgt dem Gleichheitszeichen ''(siehe Randnotiz)''. Und kann auf folgende Arten vorliegen.
Der Kommandoteil folgt dem Gleichheitszeichen ''(siehe Randnotiz)''. Und kann auf folgende Arten vorliegen.
* FHEM Kommando
* FHEM Kommando
* { Perl Befehl }
* { Perl Befehl }
* ( [[Modul_Talk2Fhem#erweiterte_Befehlskonfiguration]] )
* ( [[#erweiterte_Befehlskonfiguration]] )
 
Im ganzen könnten die Konfigurationen folgendermaßen aussehen:
=== Übersicht ===
garage\S* auf = set dev_garage open
<regexp> = <command>
garage\S* zu = { if (Value("obj_garage") != "present")
    { fhem("set dev_garage open") }
  else
    { fhem("set tts speak Es befindet sich etwas im weg!") }
  }


Im ganzen könnte die Konfiguration dann so aussehen:
''\S* Siehe hierzu [[#Häufig_verwendete_RegExp|Häufig verwendete RegExp]].''
garage\S* auf = set dev_garage open
''\S* Siehe hierzu [[Modul_Talk2Fhem#Häufig_verwendete_RegExp]].''


Bei dem vorherigen Beispiel, würde der FHEM Befehl "set garage open" bei allen folgenden Sprachbefehlen ausgeführt werden.
Bei der ersten Konfiguration würde der FHEM Befehl "set garage open" bei den folgenden Sprachbefehlen ausgeführt werden.
  Mach bitte die Garage auf
  Mach bitte die Garage auf
Das haus soll das Garagentor aufmachen
  Garagentür in 5 Minuten auf
  Garagentür in 5 Minuten auf
  Die Garagen soll in einer Stunde aufgemacht werden
  Die Garagen soll in einer Stunde aufgemacht werden
Das haus soll das Garagentor wenn der Bewegungsmelder anspricht aufmachen
Durch die modulinterne Entfernung von Zeit- und Ereignisdefinitionen ist diese RegExp bei den letzten drei Beispielen ebenfalls erfolgreich.


=== Klammerüberführung ===
=== Klammerüberführung ===


Es ist nicht notwendig für jeden Zustand oder jedes Gerät eine eigene Konfigurationzeile zu erzeugen. Hierfür gibt es die Möglichkeit, wie bei Regulären Ausdrücken üblich, Klammern "( )" im <regex>-Teil zu erfassen. Dies erfolgt über die Standartvariablen $1, $2, ..., $n. "n" steht hier für die nte Klammer.
{{Randnotiz|RNText=Info
$0 stellt in diesem Zusammenhang eine Besonderheit dar, indem sie den Text der erkannten T2F_origin RegExp enthält.
}}
Es ist nicht notwendig für jeden Zustand oder jedes Gerät eine eigene Konfigurationzeile zu erzeugen. Hierfür gibt es die Möglichkeit, wie bei regulären Ausdrücken üblich, Klammern "( )" im <regex>-Teil zu erfassen. Dies erfolgt über die Standartvariablen $1, $2, ..., $n. "n" steht hier für die nte Klammer.
Zusätzlich gibt es in Talk2Fhem die Möglichkeit die Klammern zu modifizieren.
Zusätzlich gibt es in Talk2Fhem die Möglichkeit die Klammern zu modifizieren.


Zeile 185: Zeile 305:


Beispiel:
Beispiel:
  garage\S* (\S+) = set dev_garage $1
  garage\S* <span style='color:red'>(\S+)</span> = set dev_garage <span style='color:red'>$1</span>


Der Satz: "Mach die Garage auf" ergibt dann als FHEM Kommando
Ausgabe:
set dev_garage auf
{|  class="wikitable"
!Spracheingabe!!FHEM Kommando
|-
|Mach die Garage <span style='color:red'>auf</span>
|set dev_garage <span style='color:red'>auf</span>
|-
|Mach mit der Garage <span style='color:red'>irgendetwas</span>
|set dev_garage <span style='color:red'>irgendetwas</span>
|}
 
'''Damit die Verknüpfung zweier Kommandos mit dem Wort ''wieder'' zuverlässig funktioniert, sollte die Klammer die den gewünschten Zustand beschreibt die letzte verwendete sein.'''


=== Klammermodifikation ===
=== Klammermodifikation ===
Zeile 195: Zeile 325:


==== Variante 1: nach Typ ====
==== Variante 1: nach Typ ====
<hr>


Hier kann die Klammer auf ihren Typ hin modifiziert werden.
Hier kann die Klammer auf ihren Typ hin modifiziert werden.


===== Definition =====
===== Definition =====
{{Randnotiz|RNText=Info
Die genaue Definition der Typen lässt sich mit dem Befehl get modificationtypes anzeigen}}


  $n{ '''typ''' => '''modification''', typ2 => mod2, ..., typn => modn }
  $n{ '''typ''' => '''modification'''[, typ2 => mod2, ..., typn => modn] }
*'''typ''' kann eines der folgenden Wörtern enthalten:


'''typ''' kann eines der folgenden Wörtern enthalten:
{|  class="wikitable"
*''true'' sind alle Wörter die eine positive Richtung enthalten. Wie z.B. auf, ein, hoch, an, usw.
!typ!!Beschreibung
*''false'' sind alle Wörter die eine negative Richtung enthalten. Wie z.B. ab, aus, runter, zu, usw.
|-
*''integer'' Wort enthält eine Zahl
|'''true'''
*''empty'' Wort enthält eine Leere Zeichenkette
|sind alle Wörter die eine positive Richtung enthalten. Wie z.B. auf, ein, hoch, an, usw.
*''/<regexp>/'' Wort entspricht der <regexp> ###TODO###
|-
*''else'' Falls keines der Fälle zutrifft
|'''false'''
|sind alle Wörter die eine negative Richtung enthalten. Wie z.B. ab, aus, runter, zu, usw.
|-
|'''integer'''
|Wort enthält eine Zahl
|-
|'''numeral'''
|Wort enthält eine Zahl oder ein Zahlenwort
|-
|'''float'''
|Wort enthält eine Gleitkommazahl
|-
|'''/<regexp>/'''
|Wort entspricht der <regexp>
|-
|'''word'''
|Wort enthält gleich oder mehr als 4 Buchstaben
|-
|'''empty'''
|Wort enthält eine Leere Zeichenkette
|-
|'''else'''
|Falls keines der Fälle zutrifft
|}


'''modification''' enthält das einzufügende Wort.
*'''modification''' enthält das einzufügende Wort.
Wird hier ein Komma benötigt oder besteht die Möglichkeit, dass der Wert eine leere Zeichenkette beinhalten könnte, sollte das Wort in Anführungszeichen gesetzt werden. Kann ebenfalls $n oder andere Variablen beinhalten.


===== Beispiel =====
===== Beispiel =====
  garage\S* (\S*) = set dev_garage $1{true=>open,false=>close}
  garage\S* <span style='color:red'>(\S*)</span> = set dev_garage <span style='color:red'>$1</span>{ true => <span style='color:blue'>open</span> , false => <span style='color:blue'>close</span> }
Die Sätze:
Ausgabe:
  mach die Garage auf
{| class="wikitable"
bitte Garagentor schließen
!Spracheingabe!!FHEM Kommando
würden hier folgende Befehle auslösen
|-
set dev_garage open
|mach die Garage <span style='color:red'>auf</span>
set dev_garage close
|set dev_garage <span style='color:blue'>open</span>
 
|-
===== Befehlsumkehr =====
|bitte Garagentor <span style='color:red'>schließen</span>
Ein zusätzlicher Vorteil dieser Methode ist, dass über das Schlüsselwort "wieder" ein Befehlsumkehr ausgelöst werden kann.
|set dev_garage <span style='color:blue'>close</span>
 
|}
'''Beispiel'''
mach bitte die Garage auf und in 5 Minuten wieder zu


==== Variante 2: nach Liste ====
==== Variante 2: nach Liste ====
<hr>


Hier kann die Klammer anhand einer oder zweier Listen selektiert werden.
Hier kann die Klammer anhand einer oder zweier Listen selektiert werden.
Zeile 242: Zeile 399:


Beim ersten Beispiel wird eine Zahl im regex-Teil erwartet (\d+). Diese Zahl entscheidet welche Position aus der Modwordlist ausgewählt werden soll.
Beim ersten Beispiel wird eine Zahl im regex-Teil erwartet (\d+). Diese Zahl entscheidet welche Position aus der Modwordlist ausgewählt werden soll.
  ventilator auf (stufe )?(\d+) = set aircon $2[ off, level1, level2, level3 ]
  ventilator auf (stufe )?<span style='color:red'>(\d+)</span> = set aircon <span style='color:red'>$2</span>[ <span style='color:blue'>off, level1, level2, level3</span> ]                                                                                            
                <span style='color:gray'>          |------------------>  0      1      2      3</span>           
''(Stufe )?'' bedeutet: Das Wort Stufe kann, muss aber nicht.
''(Stufe )?'' bedeutet: Das Wort Stufe kann, muss aber nicht.


Die Sätze:
Ausgabe:
  Ventilator in 10 Minuten auf Stufe 0
{| class="wikitable"
Ventilator auf 3
!Spracheingabe!!FHEM Kommando
würden hier folgende Befehle auslösen
|-
set aircon off
|Ventilator in 10 Minuten auf Stufe <span style='color:red'>0</span>
set aircon level3
|set aircon <span style='color:blue'>off</span>
|-
|Ventilator auf <span style='color:red'>3</span>
|set aircon <span style='color:blue'>level3</span>
 
|}


===== Beispiel nach Vergleichsliste =====
===== Beispiel nach Vergleichsliste =====


Hier kommt eine weitere Liste ins Spiel. Die sogenannte Keywordlist ist im Eigentlichen eine RegExp "Ver-oder-ung".
Hier kommt eine weitere Liste ins Spiel. Die sogenannte Keywordlist ist im Eigentlichen eine RegExp "Ver-oder-ung".
  (key1|key2|...|keyn)
  ( key1 | key2 | ... | keyn )
oder
oder
  (@keylist)
  ( @keywordlist )
Diese Liste mit Schlüsselwörtern wird im <regex>-Teil angegeben. Hier entscheidet nicht eine Zahl über die Position, sondern die Position die in der Keywordlist einen Treffer hat wird in der Modwordlist ausgewählt. Im Attribut T2F_keywordlist können vordefinierte Listen angelegt werden und mit @keylist ausgewählt werden
Diese Liste mit Schlüsselwörtern wird im <regex>-Teil angegeben. Hier entscheidet nicht eine Zahl über die Position, sondern die Position die in der Keywordlist einen Treffer hat wird an selber Position in der Modwordlist ausgewählt. Im Attribut T2F_keywordlist können vordefinierte Listen angelegt werden und mit @keylist ausgewählt werden
 
blendet && <span style='color:red'>(Wohnzimmer|Esszimmer|Küche)</span> = set <span style='color:red'>$1</span>[<span style='color:blue'>act_lvgroom, act_dinroom, act_kitchen</span>] 70
              <span style='color:gray'>1__________2_______3___________________1_____________2____________3</span>
 
Ausgabe:
{|  class="wikitable"
!Spracheingabe!!FHEM Kommando
|-
|im <span style='color:red'>Esszimmer</span> blendet es
|set <span style='color:blue'>act_dinroom</span> 70
|-
|ich sitze geblendet im <span style='color:red'>Wohnzimmer</span>
|set <span style='color:blue'>act_lvgroom</span> 70
|-
|die sonne blendet in der <span style='color:red'>Küche</span>
|set <span style='color:blue'>act_kitchen</span> 70
|}


blendet.* (Wohnzimmer|Esszimmer|Küche) = set $1[act_lvgroom, act_dinroom, act_kitchen] 70
''' Auswahl des Listenelements '''
''.*'' beliebig viele Zeichen


Die Sätze:
Soll bei der Nutzung der Variable nicht der Wert aus dem Sprachbefehl, sondern der Wert der Liste genutzt werden, so wird an die Variable ein @ angehängt. So wird bei
blendet.* <span style='color:red'>(Wohnzimmer|Esszimmer|Küche)</span> = set act_<span style='color:red'>$1@</span> 70
 
Die Sätze  
  es blendet im Esszimmer
  es blendet im Esszimmer
  ich sitze geblendet im Wohnzimmer
  es blendet im esszimmer
die sonne blendet in der Küche
immer zu
würden hier folgende Befehle auslösen
  set act_Esszimmer 70
  set act_dinroom 70
 
set act_lvgroom 70
führen, da die Liste das Esszimmer großgeschrieben enthält.
set act_kitchen 70


===== Ergänzung =====
===== Ergänzung =====
Zeile 278: Zeile 459:
  else für alle anderen Fälle
  else für alle anderen Fälle
zugegriffen werden. Hierbei wird der Modwordlist einfach empty oder else gefolgt von dem gewünschten Wert als nächstes Element angehängt.
zugegriffen werden. Hierbei wird der Modwordlist einfach empty oder else gefolgt von dem gewünschten Wert als nächstes Element angehängt.
  $n[ wert1, wert2,,,, empty, wert3, else, wert4 ]
  $n[ wert1, wert2,,,, empty, leererwert, else, andernfallswert ]
 
Generell lassen sich @ Listen mit Werten erweitern.
$n[@rooms, empty, dev_alle]
 
=== Import von Konfigurationen ===
Umfangreiche Konfigurationen können in Dateien ausgelagert und über '''$inlcude''' importiert werden:
 
$include = FHEM/t2f.cfg
 
=== Mehrere RegExps ===
Wenn die Reihenfolge der Wörter Unbekannt ist, kann der <regexp>-Teil in mehrere Einzelteile aufgelöst werden:
<regexp> && <regexp> && ...
'''Beispiel'''
Licht && Wohnzimmer && schalte = ...
 
Akzeptiert werden hier
 
Schalte das Licht im Wohnzimmer
Im Wohnzimmer das Licht schalten
Schalte im Wohnzimmer das licht
 
=== RegExp Optionen ===
Die einzelnen RegExp Teile können zusätzlich mit den Zeichen '''?''' und '''!''' beeinflusst werden:
 
*Negierung !<regexp>
*Optional ?<regexp>
 
Beipiel:
 
Licht && ?Wohnzimmer && schalte && !aus = ...
 
akzeptiert
 
Schalte das Licht im Wohnzimmer ein
Schalte das Licht ein
 
aber nicht
 
Schalte das Licht im Wohnzimmer aus
Schalte das Licht aus
 
=== zusätzliche Variablen ===
Ergänzend zu den Listenvariablen stehen folgende Variablen zur Verfügung:
 
*'''$&''' Enthält alle gefundenen Wörter
*'''!$&''' Enthält den Rest der nicht von der RegExp eingeschlossen wurde
*'''$0''' Enthält den Text der erkannten T2F_origin RegExp
*'''$DATE''' Enthält den Zeit und Datumstext des Sprachbefehls
*'''$TIME''' Enthält die erkannte Zeit in Sekunden
*'''$IF''' Enthält den Text der erkannten T2F_if Konfiguration
*'''$NAME''' Enthält den Devicenamen
*'''$AGAIN''' Enthält das Wort wieder wenn es sich um ein wieder Kommando handelt (siehe Beispiele)


=== erweiterte Befehlskonfiguration ===
=== erweiterte Befehlskonfiguration ===
Zeile 287: Zeile 520:
               optn  => 'valuen' )  
               optn  => 'valuen' )  
Es stehen folgende Optionen zur Verfügung:
Es stehen folgende Optionen zur Verfügung:
*cmd   => enthält das FHEM Kommando.  Wie oben beschrieben.
*'''cmd'''    => enthält das FHEM Kommando.  Wie oben beschrieben. Wird bei bedarf Zeit- oder Ereignisgebunden ausgeführt.
*answer  =>  Ein in Anführungszeichen (" oder ') gesetzter Perl-Befehl, dessen Rückgabe in das Reading ''answer'' geschrieben wird.
*'''answer''' =>  Ein Perl-Befehl der direkt ausgeführt wird und dessen Rückgabe ein Text sein sollte. Das Ergebnis wird in das Reading ''answer'' geschrieben. Der Befehl muss in einem der folgenden Zeichenpaaren eingeschlossen sein. ( ), { }, " " oder ' '. Zu empfehlen sind einfache Anführungszeichen, da dieses verwendet werden müssen wenn Kommazeichen benötigt werden.  
* offset =>  Ganzzahliger Wert in Sekunden der dem Zeitpunkt addiert wird. Siehe [[Modul_Talk2Fhem#Zeitenmodifikation]]
*'''offset'''  =>  Ganzzahliger Wert in Sekunden der dem Zeitpunkt addiert wird. Siehe [[#Zeitenmodifikation]]
 
=== Zeitenmodifikation ===
Manchmal ist es notwendig etwas vor der angegebenen Zeit auszuführen. Hier lässt sich ein Offset zu dem ermittelten Zeitpunkt hinzufügen, um ihn zu ändern.
<br>'''Beispiel'''
dusche\S?$ = (offset=><span style='color:red'>-3600</span>, cmd=>'set d_log bad warm')
 
Ausgabe:
{|  class="wikitable"
!Spracheingabe!!FHEM Kommando
|-
|ich will um <span style='color:red'>18:30</span> Uhr duschen
|define at_talk_1513096200_0 at 2017-12-12T<span style='color:red'>17:30:00</span> set d_log bad warm
|}


=== Antworten ===
=== Antworten ===
In Talk2Fhem können Antworten, die das Modul ausgeben soll, definiert werden. Hier können Fragen verarbeitet werden oder auch den Erfolg eines Kommandos bestätigt werden.
In Talk2Fhem können Antworten, die das Modul ausgeben soll, definiert werden. Hier können Fragen verarbeitet werden oder auch der Erfolg eines Kommandos bestätigt werden. Die Antworten werden immer direkt ausgegeben ohne zeitlichen oder ereignisbehafteten Bezug.


Über die [[Modul_Talk2Fhem#erweiterte_Befehlskonfiguration]], erhält der Parameter "answer" einen Perl Befehl, dessen Rückgabe die Antwort darstellt.
Über die [[#erweiterte_Befehlskonfiguration]], erhält der Parameter "answer" einen Perl Befehl. Die Rückgabe muss ein Text sein, der als Antwort dient.


==== Beispiel Erfolgsmeldung ====
==== Beispiel Erfolgsmeldung ====
<syntaxhighlight lang="perl">tu was = ( cmd => "set tue es" , answer => '"Erledigt"' )</syntaxhighlight>
<syntaxhighlight lang="perl">tu was = ( cmd => "set tue es" , answer => ("Ja") )</syntaxhighlight>
Man beachte hier, dass die Parameter immer in Anführungszeichen gesetzt werden müssen. In diesem Fall der Perl Befehl. Ein Text in Perl wird ebenfalls in Anführungszeichen gesetzt, deswegen die doppelten Anführungszeichen!
 
Da '''answer''' immer sofort ausgeführt wird, hat das '''Ja''' keine Aussagekraft bei zeitlichen oder eventbezogenen Kommandos. Möchte man eine Rückmeldung zu diesem Zeitpunkt bekommen, müsste das dem FHEM Kommando hinzugefügt werden.
 
<syntaxhighlight lang="perl">tu was = ( cmd => "set tue es;; set tts speak Erledigt!" , answer => ("Ja") )</syntaxhighlight>


==== Beispiel Zustandsabfrage ====
==== Beispiel Zustandsabfrage ====
<syntaxhighlight lang="perl">wurde es getan = ( answer => 'Value("tue") eq "es" ? "Ja" : "Nein"')</syntaxhighlight>
<syntaxhighlight lang="perl">wurde es getan = ( answer => { Value("tue") eq "es" ? "Ja" : "Nein" })</syntaxhighlight>


==== Beispiel Temperaturabfragen ====
==== Beispiel Temperaturabfragen ====
Eine einfache Temperaturabfrage könnte so aussehen.
Eine einfache Temperaturabfrage könnte so aussehen.
<syntaxhighlight lang="perl">wie.*(grad|warm|temperatur) = ( answer => '"Die Temperatur beträgt ".ReadingsVal("tempdev", "temperature", "Fehler")' )</syntaxhighlight>
<syntaxhighlight lang="perl">wie.*(kalt|warm|grad|temperatur) =  
Für eine Raumbezogene Temperaturabfrage, siehe [[Modul_Talk2Fhem#Anwendungsbeispiele_und_Vorlagen]]
( answer =>  
      ' "Die Temperatur beträgt ".ReadingsVal("tempdev", "temperature", "Fehler") '  
)</syntaxhighlight>
Für eine Raumbezogene Temperaturabfrage, siehe [[#Raumbezogene_Temperaturansage]]
 
=== Personalifizierung ===
Für eine Personenbezogene Konfiguration gibt es die Hilfestellung des Attributs T2F_origin.
 
Der Gedanke dahinter ist, man fügt dem Sprachbefehl einen Zusatz, wie z.B. den Namen am Anfang des Satzes, hinzu.
 
Ein notify auf ein Telegramdevice könnte so ausehen:
<syntaxhighlight lang="perl">
telbot:msgText.* {
my $p=ReadingsVal("telbot", "msgPeer","");
fhem("set talk ".($p?$p."=":"").$EVENT=~s/^msgText: //r);
}
</syntaxhighlight>
Jetzt wird dem Textbefehl immer der Name (msgPeer) und anschließendem "=" dem Befehl hinzugefügt und an talk gesendet. Dieser Text kann mit T2F_origin verarbeitet werden.
 
siehe hierzu [[#T2F_origin]]


== Attribute ==
== Attribute ==
Folgende Attribute werden zur Zeit unterstützt
Folgende Attribute werden zur Zeit unterstützt
=== T2F_keywordlist ===
=== T2F_keywordlist ===
  <Name> = <Liste>
  <Name> = <kommaseparierte Liste mit RegExp>
Name: Name der Liste<br>
'''Beispiele'''
Liste: Eine Kommaseparierte Liste mit RegExp<br>
  &rooms = haus|überall|wohnung , wohnzimmer , bad\\S* , toilette|wc , büro , 'eg|erdgescho\S\S?' ...  
'''Beispiel'''
  names = Mama , Papa , Kevin , Jacqueline
  rooms = haus|überall|wohnung,wohnzimmer,bad\S*,toilette|wc,büro,...
  channels = ard|das erste , zdf , rtl , sat 1 , vox , rtl2 , prosieben , kabel eins , arte
  names = Mama,Papa,Kevin,Jacqueline
{{Randnotiz|RNText=Wichtig
  channels = ard|das erste,zdf,rtl,sat 1,vox,rtl2,prosieben,kabel eins,arte
Backslashes "\" und Kommas "," müssen geschützt werden. Das erfolgt über das Quoting. Mit einfachen Anführungszeichen oder doppelten Backslash. Siehe rooms.
}}Man beachte hier die möglichkeit der RegExp<br>
Das Schlüsselwort '''haus''' löst das selbe aus wie '''überall''' und '''wohnung'''
<br>Genauso '''bad''' oder '''badezimmer''' oder '''badeirgendewas'''
 
'''Achtung:'''<br>
Damit das Modul die Fähigkeit der '''Objektverundung''' erlangt, müssen die Objekte benannt werden die dafür geeignet sind. Hierzu muss lediglich  der Keywordliste mit den vorhandenen RegExp ein kaufmännisches Und '&' vorangestellt werden. Es ist nicht notwendig diese Keywordlisten in der Konfiguration zu verwenden. In der Regel handelt es sich hierbei um Räume oder Geräte. Siehe ''&rooms''.<br>
Dadurch lassen sich folgende beispielhaften Sätze formulieren.
mach das Licht im Wohnzimmer, in der Küche und im Esszimmer an
Rollos im Schlafzimmer und im Kinderzimmer runter
Diese Eigenschaft sollte nur bei sinnhaften Listen angewendet werden. Wenn notwendig kann eine separate Liste hierfür angelegt werden.
Eine Vorlage für Räume kann hier kopiert werden. [[#Keywordlist]]


=== T2F_modwordlist ===
=== T2F_modwordlist ===
  <Name> = <Liste>
  <Name> = <kommaseparierte Liste mir RegExp>
siehe ''T2F_keywordlist''
Die Positionen der gewählten Geräte, ist eine Zuordnung zu den Listen in''T2F_keywordlist''
  roll = rollos_alle,rollos_alle,d_rollo_wz,hm_roll_ess,hm_roll_bad.*,hm_roll_wc,hm_roll_buero.*,d_rollo_schlaf,hm_roll_umkleide
<br>Wenn Wohnzimmer in der keywordliste <rooms> an Position 2 steht muss der Rolladenaktor in der modworliste <roll> auch an Position 2 stehen.
  gtags = gtag_green,gtag_red,gtag_blue,gtag_white
  roll = rollos_alle , d_rollo_wz , hm_roll_bad.* , hm_roll_wc , hm_roll_buero.* , ...
lights = alle_lichte , '''"sw_wz1,sw_wz2"''' , sw_bad.* , sw_wc
Sollen einem Schlüsselwort mehrere Aktoren zugeordnet werden, geht das über sogenannte "Quotes". (Anführungszeichen) Siehe <lights>.
  "a,b"  oder  'a,b'  oder  a\,b
 
=== T2F_if ===
Möchte man einen Befehl erst zu einem bestimmten Ereignis oder zu einer Bedingung ausführen lassen, lässt sich das über dieses Attribut konfigurieren.
 
Die Syntax orientiert sich hier an der der Definition. Die Syntax der Bedingung entspricht der des FHEM-Befehls IF. Sobald hier das Device '''dev_ring''' den Status '''ring''' erhält, wird das zusätzlich erkannte Kommando ausgeführt.
wenn .*?klingel = [dev_ring] eq "ring"
'''Beispielsätze'''
'''wenn es klingelt'''
'''wenn jemand die klingel betätigt'''
Hier stehen genauso wie in der Definition Klammermodifikatoren zur Verfügung.
wenn die temperatur <span style='color:red'>(über|unter)</span> <span style='color:blue'>([\s\.,\d]+)</span> grad = [sens:temp] <span style='color:red'>$1[>,<]</span> <span style='color:blue'>$2{float=>"$2"}</span>
Ausgabe:
{|  class="wikitable"
!Spracheingabe!!FHEM Bedingung
|-
|wenn die temperatur <span style='color:red'>über</span> <span style='color:blue'>22</span> grad steigt
|[sens:temp] <span style='color:red'>></span> <span style='color:blue'>22</span>
|-
|wenn die temperatur <span style='color:red'>unter</span> <span style='color:blue'>21, 5</span> grad fällt
|[sens:temp] <span style='color:red'><</span> <span style='color:blue'>21.5</span>
|}
Erweiterte Optionen in dieser Konfigurationszeile sind möglich aber noch nicht relevant.
 
=== T2F_origin ===
 
Das Attribut '''T2F_origin''' kann für eine herkunftsabhängige Beeinflussung der Befehle genutzt werden. Das bedeutet abhängig davon, '''wer''' den Befehl gibt oder von '''wo''' der Befehl abgegeben wurde. Es enthält eine RegExp die generell vom ganzen Sprachbefehl entfernt und in der Variable $0 zu Verfügung gestellt wird
 
Der Inhalt des Attributs könnte folgender sein.
^\w+=
 
Nun wird ein am Anfang auftretendes '''wort=''' entfernt und als Origin behandelt.
 
'''Beispiel''' 
Spiele meine Musik = set mediaplayer play pop
 
Jetzt soll das Wort pop Personenbezogen umgeformt werden. 
 
Spiele meine Musik = set mediaplayer play $0{/kevin/=>hiphop,/jaqueline/=>gothik,else=>pop}
 
Folgender Satz setzt dann für das Wort pop hiphop ein.
kevin= spiele meine Musik bitte
Das ganze lässt sich auch verschachteln und mit Keywordlisten kombinieren. Siehe hierzu Beispiele.


=== T2F_disableumlautescaping ===
=== T2F_disableumlautescaping ===


Deaktiviert das Konvertieren der Umlaute in RegExp in '''\S\S?'''
Deaktiviert das Konvertieren der Umlaute innnerhalb von regulären Ausdrücken in '''\S\S?'''


=== T2F_language ===
=== T2F_language ===
Zeile 341: Zeile 665:
=== Keywordlist ===
=== Keywordlist ===
Eine typische Keywordlist wäre eine Auflistung der benötigten Räume
Eine typische Keywordlist wäre eine Auflistung der benötigten Räume
  rooms = haus|überall|wohnung,wohnzimmer,esszimmer,bad\S*,toilette|wc,büro,schlafzimmer,ankleide|garderobe,kinderzimmer,spielzimmer,flur|gang|diele,garage,garten,terrasse,balkon,eg|erdgescho\S*,og|obergescho\S*
  &rooms = haus|überall|wohnung,wohnzimmer,esszimmer,küche,bad\\S*,toilette|wc,
büro,schlafzimmer,ankleide|garderobe,kinderzimmer,spielzimmer,
flur|gang|diele,garage,garten,terrasse,balkon,
'eg|erdgescho\S*','og|obergescho\S*','\S*außen|außer haus|vor der tür'
Das '&' vor rooms ist eine Besonderheit der Objektverundung, und sollte nur bei ausgewählten Listen verwendet werden. Siehe [[#T2F_keywordlist|T2F_keywordlist]]


=== Einfaches schalten ===
=== Einfaches schalten ===
<u>'''1.  Beispiel'''</u>
  licht (\S+) = set <span style='color:red'>dev_light</span> $1{ true => <span style='color:red'>on</span>, false => <span style='color:red'>off</span> }
  licht (\S+) = set <span style='color:red'>dev_light</span> $1{ true => <span style='color:red'>on</span>, false => <span style='color:red'>off</span> }
<u>'''2.  mit eigenen Wörtern'''</u>


=== Einfaches schalten mit Räumen ===
Will man neben an/aus einen weiteren Zustand selbst definieren, kann das so geschehen.
  licht (\S+ ){0,2} (<span style='color:red'>wohnzimmer|esszimmer|küche|terrasse</span>) (\S+) = set $2(<span style='color:red'>light_wz,light_ez,light_kitchen,light_outside</span>) $3{ true => <span style='color:red'>on</span>, false => <span style='color:red'>off</span> }
garage (\S+) = set <span style='color:red'>dev_gate</span> $1{ /<span style='color:red'>kurz</span>/ => <span style='color:red'>open-for-timer 300</span>, true => open, false => close }
<u>'''3.  mit Räumen'''</u>
  licht (\S+ ){0,2}(<span style='color:red'>wohnzimmer</span>|<span style='color:blue'>esszimmer</span>|<span style='color:green'>küche</span>|<span style='color:purple'>terrasse</span>) (\S+) =
    set $2[<span style='color:red'>light_wz</span>,<span style='color:blue'>light_ez</span>,<span style='color:green'>light_kitchen</span>,<span style='color:purple'>light_outside</span>] $3{ true => <span style='color:red'>on</span>, false => <span style='color:red'>off</span> }
Bei größeren Mengen an Räumen und Geräten bietet sich das anlegen von Keyword- und Modwordlisten an.
licht (\S+ ){0,2}(<span style='color:red'>@rooms</span>) (\S+) = set $2[<span style='color:red'>@lights</span>] $3{ true => <span style='color:red'>on</span>, false => <span style='color:red'>off</span> }


=== Rolladen fahren ===
=== Rolladen fahren ===
Wir erzeugen eine Modwordlist ''rollos'' in der wir alle Rollladen "Devices" auflisten. Die Reihenfolge ist an der Keywordlist "rooms" ([[Modul_Talk2Fhem#Keywordlist]]) anzupassen.
Sind die Rollläden innerhalb von FHEM über das Attribut "room" den Räumen mit Klarnamen zugeordnet, lässt sich das ganze am einfachsten konfigurieren.<br>
<u>'''1.  nach Devicetyp'''</u>
rolll?(os?|\S\S?den) ?(\S+ ){0,2}(\S+) (auf )?(\S+) =
  set room~$3{/haus/=>.*,empty=>.*,else=>$3}
      :FILTER=a:subType=<span style='color:green'>blindActuator</span> $5{true=><span style='color:red'>on</span>, false=><span style='color:red'>off</span>, integer=><span style='color:red'>set_$5</span>}
 
'''Erklärung'''<br>
Wenn das Device vom subTyp "blindActuator" ist (HomeMatic Rolladenactor) und es im Raum aus der dritten Klammer ($3) ist, wird dieses Device gefahren.
 
 
<u>'''2.  nach Devicenamen'''</u>
  set room~$3{/haus/=>.*,empty=>.*,else=>$3}
      :FILTER=<span style='color:green'>rollo.*</span> $5{true=><span style='color:red'>on</span>, false=><span style='color:red'>off</span>, integer=><span style='color:red'>set_$5</span>}
'''Erklärung'''<br>
Gleiche wie oben, nur das alle Devices die mit rollo beginnen im Raum $3 gefahren werden. (rollo.*)
 
 
<u>'''3.  nach Benutzerdefinierten Räumen'''</u><br>
Ansonsten müssen wir dem Modul sagen in welchem Raum welches Device sitzt. Das hat dafür den Vorteil das die Räume als RegExp angegeben werden können.<br>Wir erzeugen eine Modwordlist ''rollos'' in der wir alle Rollladen "Devices" auflisten. Die Reihenfolge ist an der Keywordlist "rooms" ([[#Keywordlist]]) anzupassen.
  rollos = <span style='color:red'>r_alle</span>,<span style='color:red'>r_wz</span>,<span style='color:red'>r_ez</span>,,<span style='color:red'>r_buero</span>,...
  rollos = <span style='color:red'>r_alle</span>,<span style='color:red'>r_wz</span>,<span style='color:red'>r_ez</span>,,<span style='color:red'>r_buero</span>,...
<br>'''Definition'''
<br>'''Definition'''
Zeile 372: Zeile 725:
  mach schatten im Erdgeschoss
  mach schatten im Erdgeschoss


=== Erweiterte Personalisierung ===
Wie löst man das Problem mit dem Wort "ich" in Sätzen wie:
Wenn ich nach hause komme
Voraussetzung siehe [[#T2F_origin]]
T2F_keywordlist @names mit den Namen:
<span style='color:red'>names</span> = wir|alle|uns,ich|mein\S*,hans,jutta,kevin,jaqueline
T2F_modwordlist @devs mit den Geräten der Personen.
<span style='color:green'>devs</span> = d_alleda,,handyhans,handyjutta,handykevin,handyjac
Standardmäßig könnte eine Konfigurationszeile in T2F_if folgendermaßen definiert werden.
wenn (<span style='color:red'>@names</span>) (heim|nach hause) komm\S* =
  [<span style='color:blue'>$1</span>[<span style='color:green'>@devs</span>]<span></span>] =~ /ja|present/
Für das Device d_alleda wird angenommen das dieses ja und nein enthalten kann, und deswegen nicht mit present verglichen werden kann.
In @devs ist für '''ich''' kein Wert vorgesehen, da es sich ja um einen variablen Wert handelt. Deswegen erfassen wir erstmal '''ich''' über die /regexp/. Andernfalls wird die Liste @devs herangezogen.<br>
wenn (<span style='color:red'>@names</span>) (heim|nach hause) komm\S* =
  [<span style='color:blue'>$1</span>{/ich/=><span style='color:blue'>weristich</span>,else=>'<span style='color:blue'>$1</span>[<span style='color:green'>@devs</span>]'}] =~ /ja|present/
Nun weisen wir über die origin Variabel '''$0''' dem Platzhalter '''weristich''' die Geräte zu.
wenn (<span style='color:red'>@names</span>) (heim|nach hause) komm\S* =
  [<span style='color:blue'>$1</span>{/ich/=><span style='color:blue'>$0</span>{/hans/=>handyhans,
              /jutta/=>handyjutta,
              /kevin/=>handykevin,
              /jaque/=>handyjac},
    else=>'<span style='color:blue'>$1</span>[<span style='color:green'>@devs</span>]'}] =~ /ja|present/
Das Beispiel zeigt wie eine verschachtelte Personenzuordnung aussehen könnte. Die Abarbeitung der $n Modifikatoren erfolgt von rechts nach links.<br>
Folgende Sätze werden konvertiert in:
{|  class="wikitable"
!Sätze!!Ergebnis
|-
|jutta= wenn hans nach hause kommt
|&#91;handyhans&#93; =~ /ja&#124;present/
|-
|hans= wenn wir heim kommen
|&#91;d_alleda&#93; =~ /ja&#124;present/
|-
|kevin= wenn ich nach hause komme
|&#91;handykevin&#93; =~ /ja&#124;present/
|}
=== GoogleCast Befehle ===
Etwas bessere Lautstärkebefehle als die von Google.
Die Lautstärken müssten noch dem eigenen Geschmack angepasst werden
#GoogleCast Commandos
(leise\b|normale lautstärke|laut\b)      =  set <span style='color:red'>googlecastdevice</span> volume $1[14,20,30]
(ein wenig|etwas|viel)? ?(lauter|leiser)  =
  { fhem("set <span style='color:red'>googlecastdevice</span> volume ".(ReadingsVal("<span style='color:red'>googlecastdevice</span>","volume", 0)$2[+,-]$1[3,5,10,empty,7])) }
''' Beispielsätze '''
Mach leise
laut machen
Mach lauter
etwas leiser
viel lauter
Für eine raumbezogene Lautstärkenkonfiguration wären nur ein paar Änderungen notwendig.


Sind die Rollläden innerhalb von FHEM über das Attribut "room" den Räumen mit Klarnamen zugeordnet, lässt sich das ganze auch ohne extra Listen konfigurieren.<br>
  ?(@rooms) && (leise\b|normale lautstärke|laut\b)     = set <span style='color:red'>$1[@musicdevices,empty,standard]</span> volume $2[14,20,30]
'''Definition nach Devicetyp'''
?(@rooms) && (ein wenig|etwas|viel)? ?(lauter|leiser)  =
  rolll?(os?|\S\S?den) ?(\S+ ){0,2}(\S+) (auf )?(\S+) = { foreach (keys %defs) {
   { fhem("set $1[@musicdevices,empty,standard] volume ".(ReadingsVal("$1[@musicdevices,empty,standard]","volume", 0)$3[+,-]$2[3,5,10,empty,7])) }
  fhem("set $_ <span style='color:red'>$5</span>{true=>on, false=>off, integer=>'<span style='color:red'>set_$5</span>'}")
 
   if ($attr{$_}{"room"} =~ /$3/i and <span style='color:red'>$attr{$_}{"subType"} eq "blindActuator"</span>)
=== Talk Timer zurücksetzen ===
  }
Sollen alle von Talk2Fhem angelegten Timer gelöscht werden.
}
(timer|kommandos) (löschen|zurücksetzen) = <span style='color:red'>set cleartimers $NAME</span>
'''Erklärung'''<br>
'''Beispielsätze'''
Hier wird eine Schleife mit allen Devices durchlaufen (foreach (keys %defs)). Wenn in dem Device ($_) der Raumname ($3) im Attribut "room" gefunden wird und das Device vom Typ "blindActuator" ist (HomeMatic Rolladenactor), dann wird der FHEM Befehl ausgeführt.
bitte alle timer zurücksetzen
<br>'''Definition nach Devicenamen'''
zukünftige kommandos löschen
rolll?(os?|\S\S?den) ?(\S+ ){0,2}(\S+) (auf )?(\S+) = { foreach (keys %defs) {
  fhem("set $_ <span style='color:red'>$5</span>{true=>on, false=>off, integer=>'<span style='color:red'>set_$5</span>'}")
  if ($attr{$_}{"room"} =~ /$3/i and $_=~/<span style='color:red'>rollo.*</span>/)
  }
}
'''Erklärung'''<br>
Gleiche wie oben, nur das der Name des Device mit rollo beginnen muss. (rollo.*)


=== Frage Antwort ===
=== Frage Antwort ===
==== Raumbezogene Temperaturansage ====
==== Raumbezogene Temperaturansage ====
Wir erzeugen wieder unsere Modwordlist sagen wir @sens gefüllt mit den Temperaturfühler "Devices". Reihenfolge wie immer die der Keywordlist @rooms.
Wir erzeugen wieder unsere Modwordlist sagen wir @sens gefüllt mit den Temperaturfühler "Devices". Reihenfolge wie immer die der Keywordlist @rooms.
  wie.*(kalt|warm|grad|temperatur).*(<span style="Color:red">@rooms</span>) = ( answer => '"Die Temperatur beträgt ".ReadingsVal("$3[<span style="color:red">@sens</span>]", "<span style="Color:red">temperature</span>", "unbekannt")." grad"' )
  wie.*(kalt|warm|grad|temperatur).*(<span style="Color:red">@rooms</span>) =  
  (
  answer => '"Die Temperatur beträgt ".ReadingsVal("$2[<span style="color:red">@sens</span>]", "<span style="Color:red">temperature</span>", "unbekannt")." grad"'
  )
'''Beispielsätze'''
'''Beispielsätze'''
  wie warm ist es im Wohnzimmer
  wie warm ist es im Wohnzimmer
Zeile 403: Zeile 809:
  Hallo Haus = ( answer => '["Hallo auch!","Guten Tag!","Ahoi!"]->[rand(<span style="Color:red">3</span>)]' )  
  Hallo Haus = ( answer => '["Hallo auch!","Guten Tag!","Ahoi!"]->[rand(<span style="Color:red">3</span>)]' )  
Wählt zufällig eine der drei Aussagen.
Wählt zufällig eine der drei Aussagen.
==== Ausgabe eines oder mehrerer Zustände ====
Angenommen man möchte wissen ob das Haus abgeschlossen ist. Und in FHEM existiert ein Dummy der diesen Zustand wiederspiegelt und im Reading text die offenen Fenster und Türen aufgelistet sind. Kann man folgendermaßen den Status erfragen
(alles|das haus) (zu|abgeschlossen) = (
  answer => '(Value("<span style='color:red'>d_schliessung</span>") eq "<span style='color:red'>zu</span>")
              ? "Es ist alles zu"
              : "Nein, offen sind: ".ReadingsVal("<span style='color:red'>d_schliessung</span>","<span style='color:red'>text</span>","")'
==== Einfache Standardantwort ====
schalte etwas (\S+) = (
  cmd  => "set <span style='color:red'>etwas</span> $1{ true => on, false => off }",
  answer =>  ("OK") )
==== Schaltzustand als Feedback ====
Da answer immer sofort ausgeführt wird, wird OK direkt gesetzt unabhängig davon ob beim Kommando eine Zeit- oder Eventbedingung mitgegeben wurde. Möchte man eine Antwort zum Zeitpunkt des Ausführens bekommen, oder bei Dingen die kein offensichtliches Feedback erzeugen, ist folgendes eine Möglichkeit.
schalte etwas (\S+) = (
  cmd  =>
    "set <span style='color:red'>etwas</span> $1{ true => on, false => off };
    setreading $NAME answers Etwas wurde $1{true=><span style='color:blue'>eingeschaltet</span>,false=><span style='color:blue'>ausgeschaltet</span>};
    setreading $NAME status answer",
  answer =>  ("OK") )
==== Erfolgsmeldung ====
Soll die Antwort abhängig vom Erfolg des Befehls sein dann könnte es so aussehen.
schalte etwas (\S+) =
  set <span style='color:red'>etwas</span> $1{ true => on, false => off};
  defmod atdekofb at +00:00:01 IF ([<span style='color:red'>etwas</span>] eq "$1{ true => on, false => off}")
    (setreading $NAME answers Kommando erfolgreich.)
  ELSE
    (setreading $NAME answers Der Befehl war nicht erfolgreich.);;
  setreading $NAME status answer
Je nach der individuellen Auswertung des Reading "answers" ist die letzte Zeile (Reading status) notwendig oder auch nicht.


==== Zustandsabfrage anhand des Aliasnamen ====
==== Zustandsabfrage anhand des Aliasnamen ====
Möchte man alle Geräte anhand seines Attribut "alias" ansprechen, um dessen Status zu erfragen, könnte das so erfolgen.
Möchte man alle Geräte anhand seines Attribut "alias" ansprechen, um dessen Status zu erfragen, könnte das so erfolgen.
<br>'''Definition'''  
<br>'''Definition'''  
  (zustand|status) (\S+)* (\S+) = (answer=>'my $s=Value((grep { "$3" =~ /$attr{$_}{<span style='color:red'>alias</span>}/i } (keys %attr))[0]);; "Der Status ist ".$s if $s')
  (zustand|status)( \S+)* (\S+) =  
    ( answer => {"Der Status ist ".(Value((devspec2array('a:<span style='color:red'>alias</span>~$3'))[0]) || "unbekannt")} )
 
'''Beispielsätze'''
'''Beispielsätze'''
  Wie ist der Zustand der Lüftung
  Wie ist der Zustand der Lüftung
  sag mir den Status der Haustür
  sag mir den Status von der Haustür
Es ist auch möglich ein eigenes Attribut zu kreieren, und dieses als Klarnamenattribut zu verwenden. Hierzu einfach im Device global ein userattr hinzufügen. z.B.
Es ist auch möglich ein eigenes Attribut zu kreieren, und dieses als Klarnamenattribut zu verwenden. Hierzu einfach im Device global ein userattr hinzufügen. z.B.
  attr global userattr T2F_alias
  attr global userattr T2F_alias
Jetzt stehen in allen Devices das Attribut T2F_alias zur Verfügung. Vorteil ist das dann auch wieder RegExp verwendet werden können. Im oberen Beispiel noch das "alias" durch "T2F_alias" erseten.
Jetzt stehen in allen Devices das Attribut T2F_alias zur Verfügung. Vorteil ist das dann auch wieder RegExp verwendet werden können. Im oberen Beispiel müsste dann dass rot markierte "alias" durch "T2F_alias" ersetzt werden.
 
==== Ereignisbezogene Meldungen ====
Da '''answer''' immer sofort den Text ausgibt ist hier beschrieben wie man eine Antwort zu einem bestimmten Ereignisses erhalten kann.
 
Es genügt folgende Zeile anzulegen und seinen bedürfnissen anzupassen.
bescheid = set googlecastdevice speak "Ich sollte bescheid geben $IF"
 
Über die T2F_if Bedingungen bekommt man jetzt immer eine Aussage sobald eine Ereignis eintritt.
 
Sätze wie
gib bescheid wenn mama nach hause kommt
sag mir wenn die tür öffnet bescheid
wenn es draußen kalt ist sag mir bescheid
ergeben dann folgende Kommandos.
set googlecastdevice speak  "Ich sollte bescheid geben wenn mama nach hause kommt"
set googlecastdevice speak  "Ich sollte bescheid geben wenn die tür öffnet"
set googlecastdevice speak  "Ich sollte bescheid geben wenn es draußen kalt ist"
 
Man sollte darauf achten, dass die T2F_if Bedingungnen möglichst komplett von der RegExp erfasst werden. Dadurch können die Sätze komplett wiederholt werden.
 
=== Konfiguration innerhalb der Geräte ===
Neben der Identifikation der Geräte über die vorhandenen FHEM-Attribute (z.B. room, alias, ...) kann eine alternative Konfiguration auch über eigens für Talk2Fhem angelegte Attribute erfolgen. Die hierfür notwendigen Grundlagen und einige Beispiele sollen im Folgenden beschrieben werden.
 
==== Grundlagen / Voraussetzungen ====
1. Anlegen der notwendigen userattr am global-Device:
 
Erweiterung des Attributes userattr des Gerätes global um folgende Einträge:
  T2F_places:textField-long T2F_properties:textField-long T2F_rooms:textField-long T2F_types_color:textField-long T2F_types_heating:textField-long T2F_types_info:textField-long T2F_types_switch:textField-long
 
2. Optional: Hilfsfunktionen für das automatische Füllen der T2F_keywordlist im talk-Device bei Änderung eines T2F-Attributes eines Gerätes
 
2a. erstellen einer sub in der 99_myUtils.pm:
 
<syntaxhighlight lang="perl">  sub fill_T2F_keywordlist
  {
    my ($name, $t2f_device) = @_;
    $name =~ s/T2F_//g;
    if ($name eq 'userattr')
    {
      return;
    }
    Log 0, "List: ".$name;
    my $currentAttr = AttrVal($t2f_device,"T2F_keywordlist","");
    my @currentAttrParts = split(/$name = /, $currentAttr);
    my $currentAttrBeg = @currentAttrParts[0];
    $currentAttrBeg = substr($currentAttrBeg, 0, -1);
    my @currentAttrEnd = split(/\n/, @currentAttrParts[1], 2);
    my @array = devspec2array('a:T2F_'.$name.'=.+');
    my @attributes = ();
    if (@array > 0 and defined($defs{$array[0]}))
    {
      foreach (@array){
      my @attrVals = split(/\n/,AttrVal($_, 'T2F_'.$name, ''));
      foreach (@attrVals){
          my $attrVal = $_;
          $attrVal =~ s/  / /g;
          $attrVal =~ s/ => /=>/g;
          my @attrValParts = split(/=>/,$attrVal);
          $attrVal = @attrValParts[0];
          $attrVal =~ s/!//g;
          $attrVal =~ s/, /,/g;
          my @attr = split(/,/, $attrVal);
          push(@attributes, @attr);
        }
      }
    }
    my %hash  = map { $_ => 1 } @attributes;
    my @unique = keys %hash;
    my $result = $currentAttrBeg."\n".$name." = ".join(", ", @unique)."\n".@currentAttrEnd[1];
    $result =~ s/\n\n/\n/g;
    $result =~ s/  / /g;
    fhem('attr '.$t2f_device.' T2F_keywordlist '.$result);
  }</syntaxhighlight>
 
2b. Erstellen eines DOIFs zum Aufruf der sub:
 
  defmod talk.DI.fillAttr DOIF ([global:"^ATTR.*T2F_.*"]) ({my $val = ReadingsVal("$SELF", "e_global_events", ""); $val =~ m/(\S*) (\S*) (\S*) (.*)/; if ($2 ne '<span style='color:red'>talk</span>' && $2 ne 'global') { fill_T2F_keywordlist("$3", "<span style='color:red'>talk</span>");}})
  attr talk.DI.fillAttr do always
 
3. Optional: Erlauben von Umlauten in den T2F-Attributen:
 
  attr talk T2F_disableumlautescaping 1 
 
Nun können die T2F-Attribute pro FHEM-Device definiert und dann in den Talk2Fhem-Befehlen benutzt werden. Wurde der Punkt 2 abgearbeitet, so werden mit dem Füllen der Attribute am Geräte auch die Keywordlisten am talk-Device gefüllt. Wie diese dann verwendet werden können, sollen die folgenden Beispiele zeigen.
 
==== Schalten von Geräten ====
 
Ausgangssituation: Es gibt drei Lampen Lampe1, Lampe2, Lampe3 und ein Nachtlicht mit einer Eule mit folgenden Attributen:
 
  attr Lampe1 T2F_types_switch Lampe, !Licht
  attr Lampe1 T2F_rooms Haus, Obergeschoss, !Esszimmer
  attr Lampe1 T2F_places Decke, Tür
  attr Lampe1 T2F_properties hell,!
 
  attr Lampe2 T2F_types_switch Lampe, !Licht
  attr Lampe2 T2F_rooms Haus, Obergeschoss, !Esszimmer
  attr Lampe2 T2F_places Tisch, Esstisch
  attr Lampe2 T2F_properties dunkel,schwach,!
 
  attr Lampe3 T2F_types_switch Lampe, !Licht
  attr Lampe3 T2F_rooms Haus, Obergeschoss, !Küche
  attr Lampe3 T2F_places Besenschrank
 
  attr Nachtlicht T2F_types_switch Lampe, !Licht, Eule, Nachtlicht
  attr Nachtlicht T2F_rooms Haus, Obergeschoss, !Kinderschlafzimmer
  attr Nachtlicht T2F_places Steckdose
 
Durch die in Punkt 2 der Voraussetzungen genannten Funktionen wurden folgende T2F-keywordlisten automatisch angelegt:
 
  attr talk T2F_keywordlist rooms = Kinderschlafzimmer, Haus, Küche, Obergeschoss, Esszimmer
                            places = Tür, Steckdose, Tisch, Decke, Esstisch
                            properties = hell, dunkel, schwach
                            types_switch = Lampe, Licht, Eule
 
Die Definition für das T2F-Device lautet dann wie folgt:


*Angenommen man möchte wissen ob das Haus abgeschlossen ist. Und in FHEM sind
  #  1              2                3                4            5          6          7     
'(alles|das haus) zu' => (answer=>'(Value("di_eg_schliessung") eq "zu") ? "Es ist alles zu" : "Nein, offen sind: ".ReadingsVal("st_schliessung","text","").ReadingsVal("st_eg_fenster","text","").ReadingsVal("st_og_fenster","text","").ReadingsVal("st_kg_fenster","text","").ReadingsVal("st_tueren","text","")')
  ?(bitte) && ?(@properties) && (@types_switch) && ?(@rooms) && ?(@places) && (\S+)(schalten|machen)?$ =
,
  (cmd=>'set T2F_types_switch=.*$3@.*:FILTER=T2F_rooms=.*$4@.*:FILTER=T2F_properties=.*$2@.*:FILTER=T2F_places=.*$5@.* $6{true=>on, false=>off}',
  answer=>'"$AGAIN" ? "dann $DATE wieder $6{true=>ein, false=>aus}" : "$1{/bitte/=>Gern, else=>Das heißt Bitte}, ich schalte $1{/bitte/=>, else=>trotzdem} folgende Geräte $6{true=>ein, false=>aus}: ".T2F_answer("T2F_types_switch=.*$3@.*:FILTER=T2F_rooms=.*$4@.*:FILTER=T2F_properties=.*$2@.*:FILTER=T2F_places=.*$5@.*","T2F_types_switch")')
                           
Damit sind dann die folgenden Sprachbefehle möglich:
 
  Schalte das Licht in der Küche ein                      => schaltet Lampe3 ein
 
  Schalte die helle Lampe im Esszimmer an                => schaltet Lampe1 ein
 
  Schalte das Licht im Esszimmer über dem Esstisch ein    => schaltet Lampe2 ein
 
  Schalte die Eule ein                                    => schaltet Nachtlicht ein
 
  Schalte das Licht im Esszimmer aus}                    => schaltet Lampe1 und Lampe2 aus
 
  Schalte das Licht aus                                  => schaltet alle vier Lichter aus
 
Um in der Antwort die Liste der geschalteten Geräte genannt zu bekommen, wird die sub T2F_answer aus der 99_myUtils aufgerufen:
 
<syntaxhighlight lang="perl">
sub T2F_answer
{
  my ($filter, $type) = @_;
  my $answer = '';
  my @devices = devspec2array($filter);
  if (@devices > 0 and defined($defs{$devices[0]}))
  {
    foreach (@devices){
      my $devAttr = AttrVal($_, $type, '');
      if ($answer ne '')
      {
        $answer = $answer.", ";
      }
      if (substr($devAttr,-1) ne "!")
      {
        my @entries = split(/!/, $devAttr);
        if (@entries < 2)
        {
          @entries = split(/,/, $entries[0]);
        }
        else
        {
          @entries = split(/,/, $entries[1]);
        }
        if (@entries[0] ne "")
        {
          $answer = $answer.@entries[0]." ";
        }
      }
     
      $devAttr = AttrVal($_, 'T2F_properties', '');
      if (substr($devAttr,-1) ne "!")
      {
        my @entries = split(/!/, $devAttr);
        if (@entries < 2)
        {
          @entries = split(/,/, $entries[0]);
        }
        else
        {
          @entries = split(/,/, $entries[1]);
        }
        if (@entries[0] ne "")
        {
          $answer = $answer.@entries[0]." ";
        }
      }
     
      $devAttr = AttrVal($_, 'T2F_rooms', '');
      if (substr($devAttr,-1) ne "!")
      {
        my @entries = split(/!/, $devAttr);
        if (@entries < 2)
        {
          @entries = split(/,/, $entries[0]);
        }
        else
        {
          @entries = split(/,/, $entries[1]);
        }
        if (@entries[0] ne "")
        {
          $answer = $answer.@entries[0]." ";
        }
      }
     
      $devAttr = AttrVal($_, 'T2F_places', '');
      if (substr($devAttr,-1) ne "!")
      {
        my @entries = split(/!/, $devAttr);
        if (@entries < 2)
        {
          @entries = split(/,/, $entries[0]);
        }
        else
        {
          @entries = split(/,/, $entries[1]);
        }
        if (@entries[0] ne "")
        {
          $answer = $answer.@entries[0]." ";
        }
      }
    }
  }
  return $answer."";
}
</syntaxhighlight>
 
Die Benennung der Geräte erfolgt auf Basis derer T2F-Attribute: Typ, Eigenschaft, Raum, Ort. Ist das jeweilige Attribut leer, ist es auch in der Antwort leer. Enthält die jeweilige Attributliste ein Ausrufezeichen (!), so wird der Eintrag nach dem Ausrufezeichen für die Antwort verwendet (z.B. Esszimmer als Raum). Steht das Ausrufezeichen am Ende, so wird der Eintrag in der Antwort leer gelassen (z.B. die Eigenschaft bei Lampe1). Ist kein Ausrufezeichen vorhanden, so wird der erste Eintrag verwendet.
 
==== Einstellen der Heizung ====
 
Das gleiche Prinzp wie bei den Lampen kann auch für die Einstellung der Heizung verwendet werden.
 
Ausgangssituation: In der Küche, im Kinderschlafzimmer und im Esszimmer gibt es jeweils eine Heizung (Homematic HM-CC-RT-DN) mit folgenden Attributen:
 
  attr HeizungEsszimmer T2F_places Heizung,!
  attr HeizungEsszimmer T2F_rooms Haus,Obergeschoss,Essbereich,!Esszimmer
  attr HeizungEsszimmer T2F_types_heating Heizung,Temperatur,Esszimmer,Essbereich,!
 
  attr HeizungKüche T2F_places Heizung,!
  attr HeizungKüche T2F_rooms Haus,Obergeschoss,Essbereich,!Küche
  attr HeizungKüche T2F_types_heating Heizung,Temperatur,Küche,Essbereich,!
 
  attr HeizungKiSchla T2F_places Heizung,!
  attr HeizungKiSchla T2F_rooms Haus,Obergeschoss,!Kinderschlafzimmer
  attr HeizungKiSchla T2F_types_heating Heizung,Temperatur,Kinderschlafzimmer,!
 
 
Mit der T2F-Definition
 
  #  1            2                  3        4      5                 
  ?(bitte) && (@types_heating) && ?(@rooms) && (auf (\d+) grad|auto\S*)( stellen| setzen| einstellen| ein)?$ =
  (cmd=>'set T2F_types_heating=.*$2{empty=>.+, else=>$2@}.*:FILTER=T2F_rooms=.*$3@.* $5{integer=>desired-temp $5, else=>controlMode auto}',
  answer=>'"$AGAIN" ? "dann $DATE wieder auf Automatik" : "Die Durchschnittstemperatur beträgt dort zur Zeit ".averageTemp("T2F_types_heating=.*$2{empty=>.+, else=>$2@}.*:FILTER=T2F_rooms=.*$3@.*")." Grad\n$1{/bitte/=>Gern, else=>Das heißt Bitte}, ich stelle die Heizung in folgenden Räumen auf $5{integer=>$5 Grad, else=>Automatik}: ".T2F_answer("T2F_types_heating=.*$2{empty=>.+, else=>$2@}.*:FILTER=T2F_rooms=.*$3@.*","T2F_types_heating")')
 
funktionieren folgende Sprachbefehle:
 
  Bitte stell die Heizung im Esszimmer auf 21 Grad        => Stellt die Heizung im Esszimmer auf 21 Grad
 
  Bitte stell die Heizung im Essbereich auf 21 Grad      => Stellt die Heizungen im Esszimmer und in der Küche auf 21 Grad
 
  Bitte stell die Heizung im Obergeschoss auf Automatik  => Stellt die drei Heizungen auf Automatik
 
Dadurch, dass im Attribut T2F_types_heating auch die Räume aufgeführt sind, sind auch Befehle in folgender Form möglich:
 
  Bitte stell die Küche auf 21 Grad                      => Stellt die Heizung in der Küche auf 21 Grad
 
Auch kann in diesem (wie auch in den oben aufgeführten Schaltbefehlen) mit "wieder" gearbeitet werden:
 
  Bitte stell die Heizung im Essbereich auf 21 Grad und in 2 Stunden wieder auf Automatik
 
Für die Generierung der Antwort wird neben der bei den Schaltbefehlen bereits gezeigten sub T2F_answer eine weiter Funktion verwende, welche die Durchschnittstemperatur im zu schaltenden Bereich ermittelt und ausgibt:
 
<syntaxhighlight lang="perl">
  sub averageTemp($)
  {
    my ($filter) = @_;
    my @tempDevices = devspec2array($filter);
    my $count = 0;
    my $measuredTemp = 0;
    if (@tempDevices > 0 and defined($defs{$tempDevices[0]})){
      foreach (@tempDevices){
        $measuredTemp = $measuredTemp + ReadingsVal($_, "measured-temp", "");
        $count = $count + 1;
      }
      return $measuredTemp / $count;
    }
    return 0;
  }
</syntaxhighlight>
 
==== Einstellen der Farbe von Farbwechsellampen (Philips Hue, Wifilight, ...) ====
 
Für das Beispiel zum Einstellen der Lichtfarbe nehmen wir eine Farbwechsellampe LampeBunt an, welche den Befehl RGB unterstützt. Diese erhält folgende Attribute:
 
  attr LampeBunt T2F_places Decke,Couch,Sofa
  attr LampeBunt T2F_rooms Haus,Dachgeschoss,!Wohnzimmer
  attr LampeBunt T2F_types_color Lampe,Licht
  attr LampeBunt T2F_types_switch Lampe,Licht
 
Durch das Attribut T2F_types_switch lässt sich diese über die bereits beschriebene Schaltlogik ein und ausschalten. Durch die zusätzlich T2F-Definition
 
  #  1              2              3            4              5              6
  ?(bitte) && (@types_color) && ?(@rooms) && ?(@places) && auf (@colors)( schalten| stellen)?$ =
  (cmd=>'set T2F_types_color=.*$2@.*:FILTER=T2F_rooms=.*$3@.*:FILTER=T2F_places=.*$4@.* RGB $5[@rgb]',  
  answer=>'"Ich schalte folgende Geräte auf $5@: ".T2F_answer("T2F_types_color=.*$2@.*:FILTER=T2F_rooms=.*$3@.*:FILTER=T2F_places=.*$4@.*","T2F_types_color")')
 
und die entsprechenden Attribute am T2F-Device talk (HINWEIS: eigene Listen können Problemlos ergänzt werden, diese werden durch die Hilfsfunktionen NICHT überschrieben)
 
  attr talk T2F_keywordlist colors = Aus, Schwarz, Dunkles Schiefergrau, Schiefergrau, Helles Schiefergrau, Helles Stahlblau, Mattes Grau, Grau, Dunkelgrau, Silber, Hellgrau, Gainsboro, Rauchiges Weiß, Geisterweiß, Weiß, Schneeweiß, Elfenbein, Blütenweiß, Muschel, Altgold, Leinenfarbe, Antikes Weiß, Mandelweiß, Cremiges Papaya, Beige, Mais, Helles Goldrutengelb, Hellgelb, Chiffongelb, Blasse Goldrutenfarbe, Khaki, Gelb, Gold, Orange, Dunkles Orange, Goldrute, dunkle Goldrutenfarbe, Peru, Schokolade, Sattelbraun, Ocker, Braun, Dunkelrot, Kastanienbraun, Ziegelfarbe, Indischrot, Karmesinrot, Rot, Orangenrot, Tomatenrot, Koralle, Lachs, Helles Korallenrot, Dunkle Lachsfarbe, Helle Lachsfarbe, Sandbraun, Rosiges Braun, Gelbbraun, Grobes Braun, Weizen, Pfirsich, Navajoweiß, Tomatencreme, Rosige Lavenderfarbe, Altrosa, Rosa, Hellrosa, Leuchtendes Rosa, Fuchsie, Magentarot, Tiefrosa, Mittleres Violettrot, Blasses Violettrot, Pflaume, Distel, Lavendelfarbe, Violett, Orchidee, Dunkles Magentarot, Violett, Indigo, Blauviolett, Dunkles Violett, Dunkle Orchideenfarbe, Mittleres Violett, Mittlere Orchideenfarbe, Mittleres Schieferblau, Schieferblau, Dunkles Schieferblau, Mitternachtsblau, Marineblau, Dunkelblau, Mittelblau, Blau, Königsblau, Stahlblau, Kornblumenblau, Dodger-Blau, Tiefes Himmelblau, Helles Himmelblau, Himmelblau, Hellblau, Zyanblau, Blaugrün, Taubenblau, Helles Cyanblau, Aliceblau, Himmelblau, Cremig Pfefferminz, Honigmelone, Aquamarinblau, Türkis, Blasses Türkis, Mittleres Türkis, Dunkles Türkis, Mittleres Aquamarinblau, Helles Seegrün, Dunkles Zyanblau, Entenbraun, Kadettblau, Mittleres Seegrün, Dunkles Seegrün, Hellgrün, Blassgrün, Mittleres Frühlingsgrün, Frühlingsgrün, Zitronengrün, Gelbgrün, Seegrün, Waldgrün, Grün, Dunkelgrün, Olivfarbiges Graubraun, Dunkles Olivgrün, Olivgrün, Dunkles Khaki, Gelbgrün, Hellgrün, Grüngelb
 
  attr talk T2F_modwordlist rgb = 000000, 000000, 8FBC8F, 708090, 778899, B0C4DE, 696969, 808080, A9A9A9, C0C0C0, D3D3D3, DCDCDC, F5F5F5, F8F8FF, FFFFFF, FFFAFA, FFFFF0, FFFAF0, FFF5EE, FDF5E6, FAF0E6, FAEBD7, FFEBCD, FFEFD5, F5F5DC, FFF8DC, FAFAD2, FFFFE0, FFFACD, EEE8AA, F0E68C, FFFF00, FFD700, FFA500, FF8C00, DAA520, B8860B, CD853F, D2691E, 8B4513, A0522D, A52A2A, 8B0000, 800000, B22222, CD5C5C, DC143C, FF0000, FF4500, FF6347, FF7F50, FA8072, F08080, E9967A, FFA07A, F4A460, BC8F8F, D2B48C, DEB887, F5DEB3, FFDAB9, FFDEAD, FFE4C4, FFF0F5, FFE4E1, FFC0CB, FFB6C1, FF69B4, FF00FF, FF00FF, FF1493, C71585, DB7093, DDA0DD, D8BFD8, E6E6FA, EE82EE, DA70D6, 8B008B, 800080, 4B0082, 8A2BE2, 9400D3, 9932CC, 9370DB, BA55D3, 7B68EE, 6A5ACD, 483D8B, 191970, 000080, 00008B, 0000CD, 0000FF, 4169E1, 4682B4, 6495ED, 1E90FF, 00BFFF, 87CEFA, 87CEEB, ADD8E6, 00FFFF, 00FFFF, B0E0E6, E0FFFF, A0CE00, F0FFFF, F5FFFA, F0FFF0, 7FFFD4, 40E0D0, AFEEEE, 48D1CC, 00CED1, 66CDAA, 20B2AA, 008B8B, 008080, 5F9EA0, 3CB371, 8FBC8F, 90EE90, 98FB98, 00FA9A, 00FF7F, 00FF00, 32CD32, 2E8B57, 228B22, 008000, 006400, 6B8E23, 556B2F, 808000, BDB76B, 9ACD32, 7FFF00, ADFF2F
 
kann die Farbe nun auch über folgenden Sprachbefehle eingestellt werden:
 
  Bitte schalte die Lampe im Wohnzimmer an der Couch auf Olivfarbiges Graubraun
 
Dadurch, das die Liste colors den Wert "Aus" mit dem entsprechenden Wert "000000" in der Liste rgb enthält, kann die Lampe über die gleiche Logik auch ausgeschaltet werden:
 
  Bitte schalte das Licht im Wohnzimmer auf Pflaume und in einer Stunde wieder aus
 
==== Abfragen beliebiger Geräteinformationen ====
 
Das folgende Beispiel zeigt die Möglichkeit auf, die Antworten für Statusabfragen direkt am abgefragten Gerät zu definieren. Hierfür werden zunächst eine Definition am T2F-Device
 
  #              1            2                3            4
  Wie && ?(@properties)&& (@types_info) && ?(@rooms) && ?(@places) =
  (answer=>'T2F_getInfo("T2F_types_info=.*$2@.*:FILTER=T2F_rooms=.*$3@.*:FILTER=T2F_properties=.*$1@.*:FILTER=T2F_places=.*$4@.*","$2@")')
 
und eine Funktion in der 99_myUtils
 
<syntaxhighlight lang="perl">
sub T2F_getInfo
{
  my ($filter,$info) = @_;
  my @devices = devspec2array($filter);
  if (@devices > 0 and defined($defs{$devices[0]}))
  {
    my $answer = '';
 
    foreach (@devices){
      if ($answer ne '')
      {
        $answer = $answer.", ";
      }
      my $device = $_;
      my @attrVals = split(/\n/,AttrVal($device, 'T2F_types_info', ''));
      foreach (@attrVals){
        my $attrVal = $_;
        $attrVal =~ s/  / /g;
        $attrVal =~ s/ => /=>/g;
        my @attrValParts = split(/=>/,$attrVal);
        if (@attrValParts[0] =~ /$info/)
        {
          my $cmd = "' ".@attrValParts[1]."'";
          $cmd =~ s/=/\//g;
          $cmd =~ s/\)\(/\/r=~s\//g;
          $cmd =~ s/\)/\/r.'/g;
          $cmd =~ s/#\(/', '')=~s\//g;
          $cmd =~ s/ #/ '.ReadingsVal('$device', '/g;
          $cmd =~ s/#/', '').'/g;
          $cmd =~ s/T2F_answer/'.T2F_answer('$device', 'T2F_types_switch').'/g;
          $answer = $answer.' '.eval($cmd);
        }
      }
    }
    return $answer;
  }
}
</syntaxhighlight>
 
Die Konfiguration und Funktionsweise sind nun wie folgt: Das Gerät, dessen Status abgefragt werden sollen erhält neben den Oben bereits beschriebenen Attributen für Eigenschaft, Raum und Ort noch das Attribut T2F_types_info, welches Zeilenweise die abzufragenen Status in der folgenden Form enthält:
 
  abfragewert => Das ist die Antwort von Gerät T2F_answer mit den Wert #reading#(suchen1=ersetzen1)...(suchenn=ersetzenn)
 
Mit der Form #reading#(suchen1=ersetzen1)...(suchenn=ersetzenn) können die Werte von Readings des abgefragten Device zum Zeitpunkt der Abfrage ermittelt werden und im Ergebnis Ersetzungen vorgenommen werden (z.B. (on=an)(off=aus)). T2F_answer wird mit der T2F-Konfiguration (siehe oben) ersetzt. Für das Beispiel einer Heizung im Esszimmer wäre das zum Beispiel wie folgt möglich:
 
  attr HeizungEsszimmer T2F_places Heizung,!
  attr HeizungEsszimmer T2F_rooms Haus,Obergeschoss,Essbereich,!Esszimmer
  attr HeizungEsszimmer T2F_types_info warm,Temperatur => Die Temperatur T2F_answer beträgt #measured-temp# Grad und soll #desired-temp# Grad erreichen\
                                      modus,Betriebsart => Die Betriebsart T2F_answer ist #controlMode#(auto=Automatik)(manu=Hand)\
                                      Ventilstellung => Das Ventil T2F_answer ist #ValvePosition# Prozent geöffnet
 
Damit sind dann folgende Abfragen möglich:
 
  Wie warm ist die Heizung im Esszimmer?
 
  Wie ist die Temperatur der Heizung im Esszimmer?
 
  Wie ist die Ventilstellung der Heizung im Esszimmer?
 
  Wie warm sind die Heizungen?


== Häufig verwendete RegExp ==
== Häufig verwendete RegExp ==
Perl Regular Expression, also ein regulärer Ausdruck der Programmiersprache Perl, ist eine Werkzeug um Zeichenketten zu beschreiben. Hier wird versucht kurz einen Einblick auf die hier häufig benutzten RegExp zu geben.
Perl Regular Expression, also ein regulärer Ausdruck der Programmiersprache Perl, ist eine Werkzeug um Zeichenketten zu beschreiben. Hier wird ein kurzer Einblick auf die im Artikel häufig genutzten RegExp zu geben.


Eine kurze Übersicht der verwendeten Zeichen kann hier eingesehen werden. [http://jkorpela.fi/perl/regexp.html]
Eine Auflistung der Syntax kann hier eingesehen werden. [http://jkorpela.fi/perl/regexp.html]


{|class="wikitable"
{|class="wikitable"
Zeile 442: Zeile 1.270:
|}
|}


== Eingabemethoden ==
== Ausgabemethoden ==
Die Herkunft der Sprachbefehle für das Modul sind vielfältig. Hier werden einige Methoden beschrieben wie der Sprachbefehl in das Modul gelangen kann.
=== Messenger Telegram ===
Ist ein [[TelegramBot]] telbot definiert, reicht ein einfaches "notify" um die Nachrichten an FHEM an Talk2Fhem weiterzuleiten.
define n_telbot notify telbot:msgText.* set talk $EVENT
Schon kann mit FHEM gechattet werden... ;)


=== Google Home Geräte ===
Siehe hierzu [[#Beispiel|Anwendungsbeispiel]]
Momentan ist es leider noch notwendig über einen Umweg die Sprache von einem GoogleHome in FHEM zu bringen. Hierzu ist es notwendig einen funktionierenden DNS Service am laufen zu haben. Damit FHEM per Webadresse im Internet erreichbar ist.


*Ein FHEMWEB Device anlegen
define api FHEMWEB 8087 global
attr api HTTPS 1
attr api allowfrom  1
attr api csrfToken  None
*Ein allowed Device anlegen
define allowed_api allowed api
attr allowed_api allowedCommands set
attr allowed_api allowedDevices talk
attr allowed_api basicAuth  {"$user:$password" eq 'user:passwort'}
attr allowed_api validFor  api
*Mit Googlekono bei IFTTT.com anmelden
*New Applet
*+this GoogleAssistant -> Say a phrase with a text ingredient
* Die drei Triggertexte wählen z.b.
**das Haus $
**sag dem Haus $
**frag das Haus $
***Problem bei zu kurzen Texten hat GoogleHome keine anderen Anfragen mehr angenommen.
*Einen Antworttext überlegen z.B. OK und in "What do you want the Assistant to say in response?" eintragen
*Language Deutsch
*+that Webhooks
*URL wählen https://user:password@dnsservice:54387/fhem?cmd.talk=set talk {{TextField}}&XHR=1
*Fertig
Jetzt wird der gesamte Text bei dem genannten Triggerworten an FHEM weitergeleitet.
== Ausgabemethoden ==
Ebenfalls


== Links ==
[[Kategorie:Sprachsteuerung|Talk2FHEM]]

Aktuelle Version vom 27. November 2019, 11:30 Uhr

Talk2Fhem
Zweck / Funktion
Das Modul stellt eine Verbindung zwischen natürlicher Sprache und FHEM Befehlen her
Allgemein
Typ Gerätemodul
Details
Dokumentation EN / DE
Support (Forum) Frontends/Sprachsteuerung
Modulname 39_Talk2Fhem.pm
Ersteller Oliver Georgi (Phill )
Wichtig: sofern vorhanden, gilt im Zweifel immer die (englische) Beschreibung in der commandref!


Diese Seite beschreibt die Funktionsweise und Konfiguration des Moduls Talk2Fhem.

Voraussetzungen

ModulTalk2FhemScreenshot.png

Es ist sehr zu empfehlen, für die Konfiguration des Moduls, im Webfrontend von FHEM die Syntaxhervorhebung zu aktivieren. Die Aktivierung des erweiterten Editors ist hier beschrieben.

Kenntnisse im Bereich Regulärer Ausdrücke (RegExp) in Perl sind hilfreich, aber nicht zwingend erforderlich. Ein kurzer Einstieg kann hier eingesehen werden. Häufig_verwendete_RegExp

Allgemeines

Das Modul Talk2Fhem stellt eine Verbindung zwischen natürlicher Sprache und FHEM Befehlen her. Es ist ein überaus flexibles und relativ einfach zu konfigurierendes Script mit dem man sehr natürlich kommunizieren kann. Die Konfiguration erfolgt dabei über das FHEM Webfrontend.

Es werden diverse Zeit- und Datumsangaben erkannt. Außerdem ist es möglich Ereignisse zu formulieren, welche die Befehle mit einer Bedingung verknüpfen. Bei der weiteren Verarbeitung der Sprachbefehle wird die Sprache mit definierten regulären Ausdrücken verglichen.

Es lassen sich Antworten generieren, die Abhängig von den gesendeten Sprachbefehlen sind. Das vom Author verfolgte Konzept ist aber: Erzeuge eine Meldung wenn etwas nicht verstanden oder fehlgeschlagen ist, ansonsten führe den Befehl mit einer kurzen Erfolgsmeldung wie "OK" oder "Gerne" aus.

Die Text Ein- sowie Ausgabe der natürlichen Sprache übernehmen andere Anwendungen. Hierzu gibt es eine Reihe von Möglichkeiten die unter Anwendung dargestellt sind. Funktionierende Lösungsansätze werden hier gerne mit aufgenommen.

Funktionsweise

Die Zerlegung des Sprachbefehls erfolgt in mehreren Schritten.

  1. Aufteilen des Sprachbefehls in einzelne Kommandos anhand des Wortes UND
  2. Suchen nach Ereignisansagen und entfernen für die weitere Verarbeitung
  3. Erkennen von Zeit- und Datumsangaben und entfernen für die weitere Verarbeitung
  4. Entfernung überflüssiger Wörter
  5. Vergleich mit den definierten regulären Ausdrücken
  6. Konvertieren in ein FHEM Kommando
  7. Antwortsatz bilden
  8. Zeit- und Eventgebundenes auslösen des FHEM Kommandos

Installation

update 39_Talk2Fhem
shutdown restart

Diskussion hier:

Forumsbeitrag.

Definition

define talk Talk2Fhem

Zum testen der Konfiguration ist es Ratsam vorerst das Attribut disable auf 1 zu setzen. Hierbei wird die Auslösung der FHEM Kommandos unterdrückt.

attr talk disable 1
attr global language DE
oder
attr talk T2F_language DE

Anwendung

Der Sprachbefehl wird über das Kommando set oder set ! an das Modul übermittelt.

set talk Guten Morgen liebes Zuhause

Wird kein Text angehängt, wird der letzte Sprachbefehl erneut ausgeführt.

Eingabemethoden

Die Herkunft der Sprachbefehle für das Modul sind vielfältig. Hier werden einige Methoden beschrieben wie der Sprachbefehl in das Modul gelangen kann.

Messenger Telegram

Ist ein TelegramBot telbot definiert, reicht ein einfaches "notify" um die Nachrichten an FHEM an Talk2Fhem weiterzuleiten.

define n_telbot notify telbot:msgText.* set talk $EVENT

Schon kann mit FHEM gechattet werden... ;)

Mit Telegram lässt sich auch leicht der Absender der Nachricht verarbeiten. Siehe hierzu #Personalifizierung

Google Home Geräte

Momentan ist es leider noch notwendig über einen Umweg die Sprache von einem GoogleHome in FHEM zu bringen. Hierzu ist es notwendig einen funktionierenden DNS Service am laufen zu haben. Damit FHEM per Webadresse im Internet erreichbar ist.

  • Ein FHEMWEB Device anlegen
define api FHEMWEB 8087 global
attr api HTTPS 1
attr api allowfrom  1
attr api csrfToken  None
  • Ein allowed Device anlegen
define allowed_api allowed api
attr allowed_api allowedCommands set
attr allowed_api allowedDevices talk
attr allowed_api basicAuth  {"$user:$password" eq 'user:passwort'}
attr allowed_api validFor   api
  • Mit Googlekono bei IFTTT.com anmelden
  • New Applet
  • +this GoogleAssistant -> Say a phrase with a text ingredient
  • Die drei Triggertexte wählen z.b.
    • das Haus $
    • sag dem Haus $
    • frag das Haus $
      • Problem bei zu kurzen Texten hat GoogleHome keine anderen Anfragen mehr angenommen.
  • Einen Antworttext überlegen z.B. OK und in "What do you want the Assistant to say in response?" eintragen
  • Language Deutsch
  • +that Webhooks
  • URL wählen
https://user:password@dnsservice:54387/fhem?cmd.talk=set talk <<<{{TextField}}>>>&XHR=1
  • Fertig

Jetzt wird der gesamte Text bei dem genannten Triggerworten an FHEM weitergeleitet.

Readings / Ausgabemethoden

Über die bereit gestellten Readings lassen sich weitere Module die z.B. für Sprachausgabe zuständig sind mit einbinden.

  • Im Reading set steht der letzte gesendete Sprachbefehl.
  • Im Reading cmds steht das letzte ausgeführte FHEM-Kommando dessen Rückgabe, in den häufigsten Fällen ein Fehler, in das Reading response geschrieben wird.
  • Die Antworten werden im Reading answers sofort ausgegeben.
  • Die Modulinterne Fehler werden in dem Reading err ausgegben.
  • In ifs stehen die Bedingungen mit der das letzte Kommando ausgeführt werden wird.
  • notifies enthält eine Auflistung der Devices die für die aktuell wartenden bedingten Kommandos relevant sind. Auf diesen Devices liegt ein internes notify.
  • Das Reading origin enthält den erkannten Text der im Attribut T2F_origin definierten RegExp.

Das Reading status wird jedes mal gesetzt und erhält Werte nach folgender Priorität.

1. response wenn das FHEM Kommando eine Meldung ausgegeben hat
2. disabled wenn das Attribute disable auf 1 steht
3. err wenn der Sprachbefehl einen Fehler zurückgegeben hat
4. answer wenn der Sprachbefehl eine Antwort ausgegeben hat
5. done wenn keines der oberen Fälle eingetreten ist, also alles gut verlaufen ist

Beispiel 1

Die FHEM Befehle werden eigenständig ausgeführt, sie können aber zur Überprüfung auch weitergeleitet werden. Das Beispiel zeigt auch wie auf Fehler und Antworten von Talk2Fhem reagiert werden kann. Erstellen eines Notify

define n_talk notify talk:.* {}

Folgendes in der Definition von n_talk einfügen

 talk:.* {
 # Sende die Antwort per Telegram und gebe es über das GoogleHome aus
 	if ($EVENT =~ s/^answers: //) {
 		fhem("set telegram _msg \@USER $EVENT");
 		fhem("set d_googlespeak $EVENT");	
 	}
 
 # Schicke den Fehler per Telegram und sag am GoogleHome das es nicht geklappt hat.
 	if ($EVENT =~ s/^err: //) {
 		fhem("set telbot _msg \@Oliver $EVENT");
 		my @a = ("Das hat leider nicht geklappt", "Es gab leider einen Fehler", "Es tut mir leid. Das hat nicht funktioniert.", "Es ist leider zu einem Fehler gekommen","Könntest du das vielleicht nochmal anders sagen", "Mhhh, das kann ich so nicht verstehen");
 		fhem("set d_googlespeak $a[int(rand($#a))]");
 	} 
 
 # Schick mir alle ausgeführten Befehle als Telegram
 
 	if ($EVENT =~ s/^cmds: //) {
 		fhem("set telbot _msg \@USER $EVENT");
 	} 
 
 }

Beispiel 2 Reading: Status

Eine weitere Möglichkeit Talk2Fhem mit anderen Modulen zu verbinden, ist über das Reading status möglich.

Die folgenden Lösung sieht auch eine Standardantwort vor. !Achtung noch nicht getestet vom Author!

talk:status {
my $text = ReadingsVal("talk", $EVENT, "");

if ("$EVENT" eq "response") {
  #FHEM gibt bei Erfolg eig. keine Rückmeldung, also ist vermutlich was schief gelaufen
  $text = "Die Haussteuerung hat folgende Meldung gebracht. $text";

} elsif ("$EVENT" eq "err") {
  # Hier kann auch die Meldung noch detailierter an einen Messenger gesendet werden.
  $text = ["Das habe ich nicht verstanden!","Phuu das kann ich noch nicht!","Nein! Heute nicht.", "Wie bitte?"]->[rand(4)];

} elsif ("$EVENT" =~ /^answer/) {
  $text = ReadingsVal("talk", "answers", "Ich habe nichts zu sagen.");

} elsif ("$EVENT" eq "done") {
  $text = ["Ok.","Ja.","Gerne.", "Mach ich!"]->[rand(4)];

} else {
  $text = "Oh, es gibt etwas neues, bitte schau mal im Forum bei Talk2Fhem vorbei.";
}

fhem('set speaker speak "$text"') if $text;
}

Modulinterne Spracherkennung

Zeitenerkennung

Die Zeit- und Datum Eingabe kann auf verschiedene Arten erfolgen.
Die Datumerkennung umfasst folgende Phrasen:

  • morgen, übermorgen
  • in ... Wochen, Monat, Jahr
  • in einem drei-,viertel,halben Jahr
  • nächste Woche, Monat, Jahr
  • Wochentage
  • in ... Tagen
  • am DATUM

Die Zeiterkennung umfasst folgende Phrasen:

  • in,nach ... stunden,minuten,sekunden
  • in einer drei-,viertel,halben Stunde
  • um ... (Uhr) (...)
  • um drei-,viertel,halb,viertel vor/nach, 1-12
  • heute - entspricht 12:00
  • früh - entspricht 9 Uhr
  • abend - entspricht 18 Uhr
  • nachmittag - entspricht 16 Uhr
  • vormittag - entspricht 10:30 Uhr
  • mittag - entspricht 12 Uhr
  • gleich - entspricht 5 Minuten
  • nachher - entspricht 30 Minuten
  • später - entspricht 1 Stunde
  • jetzt
  • sofort

Datum und Zeitangaben können kombiniert werden. Morgen abend um 8 Uhr
Wird eine Zeit erfolgreich erkannt erfolgt die Ausführung des FHEM-Kommandos über das Modul at. Es wird ein at Ereignis angelegt welches den Namen at_<modulname>_<zeitindex> erhält.

Bei mehreren Kommandos über das Schlüsselwort und wirkt sich der Zeitpunkt des ersten Kommandos auch auf das zweite und dritte ... aus.

Schalte die Heizung um 20 Uhr aus und mache die Rollläden runter

Beide Kommandos werden um 20 Uhr ausgelöst.

Hat das zweite Kommando ebenfalls eine Zeitphrase wird diese Zeit genommen.

schalte die Heizung heute Abend ab und mache die Rollläden jetzt runter

Wie oben gesehen wird der Zeitpunkt des ersten Kommandos vor dem "und" auch für das zweite nach dem "und" gesetzt. Vorausgesetzt er wird beim 2. Kommando nicht durch eine eigenständige Zeit (hier "jetzt") ersetzt. Wenn man die Zeit des zweiten Kommandos, relativ zum ersten setzen möchte, kann dies mit den Schlüsselwörtern dann, danach oder wieder formuliert werden.

Fahre um 14 Uhr die Rollläden an der Terrasse runter und schalte dann in 2 Minuten die Bewässerung an

oder

Mach am Freitag um 5 Uhr die Heizung aus und in einer Woche wieder an

Objektverundung

Es ist möglich Objekte in einer Auflistung in den Sätzen zu übergeben. Siehe hierzu T2F_keywordlist.

Rollos im Wohnzimmer, Esszimmer und in der Küche auf 70
Schalte den Fernseher und die Soundanlage an

Ereigniswiederholung

Werden zwei Sätze über ein und miteinander verknüpft, kann im 2. Satz mit dem Wort wieder das Ereignis wiederholt werden.

Beispiel

schalte bitte die Klingel ab und in einer Stunde wieder ein
mach bitte die Garage auf und gleich wieder zu

Man benötigt hier nicht erneut den kompletten ersten Satz zu wiederholen.

Um diese Funktion zu gewährleisten, sollte der anschließende Hinweis in Klammerüberführung beachtet werden.

Eventabhängige Kommandos

Es lassen sich alle definierten Befehle mit Bedingungen verknüpfen, bei der Erfüllung diese dann ausgeführt werden.

Beispiel

Sag mir bescheid wenn es klingelt 
Mach die garage zu wenn es draußen dunkel wird
Wenn ich nach hause komme mach die Musik an

siehe hierzu #T2F_if

Konfiguration

Die Konfiguration der Sprachbefehle wird Zeile für Zeile in der Definition (DEF) des angelegten Gerätes vorgenommen. Die einzelnen Definitionen müssen folgenden Schema entsprechen.

Info green.pngWichtig

Vor und nach dem Gleichheitszeichen muss mindestens ein Trennzeichen vorhanden sein

  • Vor dem "=" mindestens ein Leer- oder Tabulatorzeichen
  • Nach dem "=" können zusätzlich auch Zeilenumbrüche eingefügt werden
<regexp> = <command>

RegExp-Teil

<RegExpPart> [&& [?!]<RegExpPart_n>] =

Eine Konfiguration beginnt immer mit der Definition der gesuchten Schlüsselwörter, gefolgt von einem Gleichheitszeichen (siehe Randnotiz). Diese werden Anhand von regulären Ausdrücken (RegExp) beschrieben. Also z.B.:

garage auf =

Das bededutet, sobald die Wörter in der Reihenfolge "garage" und "auf" erkannt werden, wird der Kommandoteil der Konfiguration ausgeführt. Groß- und Kleinschreibung wird grundsätzlich ignoriert.

Kommando-Teil

Der Kommandoteil folgt dem Gleichheitszeichen (siehe Randnotiz). Und kann auf folgende Arten vorliegen.

Im ganzen könnten die Konfigurationen folgendermaßen aussehen:

garage\S* auf = set dev_garage open
garage\S* zu = { if (Value("obj_garage") != "present") 
   { fhem("set dev_garage open") }
  else
   { fhem("set tts speak Es befindet sich etwas im weg!") }
  }

\S* Siehe hierzu Häufig verwendete RegExp.

Bei der ersten Konfiguration würde der FHEM Befehl "set garage open" bei den folgenden Sprachbefehlen ausgeführt werden.

Mach bitte die Garage auf
Garagentür in 5 Minuten auf
Die Garagen soll in einer Stunde aufgemacht werden
Das haus soll das Garagentor wenn der Bewegungsmelder anspricht aufmachen

Durch die modulinterne Entfernung von Zeit- und Ereignisdefinitionen ist diese RegExp bei den letzten drei Beispielen ebenfalls erfolgreich.

Klammerüberführung

Info green.pngInfo $0 stellt in diesem Zusammenhang eine Besonderheit dar, indem sie den Text der erkannten T2F_origin RegExp enthält.

Es ist nicht notwendig für jeden Zustand oder jedes Gerät eine eigene Konfigurationzeile zu erzeugen. Hierfür gibt es die Möglichkeit, wie bei regulären Ausdrücken üblich, Klammern "( )" im <regex>-Teil zu erfassen. Dies erfolgt über die Standartvariablen $1, $2, ..., $n. "n" steht hier für die nte Klammer. Zusätzlich gibt es in Talk2Fhem die Möglichkeit die Klammern zu modifizieren.

Soll die Garage auf und zugemacht werden, lässt sich folgendermaßen beschreiben.

Beispiel:

garage\S* (\S+) = set dev_garage $1

Ausgabe:

Spracheingabe FHEM Kommando
Mach die Garage auf set dev_garage auf
Mach mit der Garage irgendetwas set dev_garage irgendetwas

Damit die Verknüpfung zweier Kommandos mit dem Wort wieder zuverlässig funktioniert, sollte die Klammer die den gewünschten Zustand beschreibt die letzte verwendete sein.

Klammermodifikation

Da es in den meißten Fällen nicht gewünscht ist, nur das gefunde Wort in das FHEM Kommando zu überführen, lässt sich zusätzlich das gefundene Wort modifizieren.

Variante 1: nach Typ


Hier kann die Klammer auf ihren Typ hin modifiziert werden.

Definition
Info green.pngInfo Die genaue Definition der Typen lässt sich mit dem Befehl get modificationtypes anzeigen


$n{ typ => modification[, typ2 => mod2, ..., typn => modn] }
  • typ kann eines der folgenden Wörtern enthalten:
typ Beschreibung
true sind alle Wörter die eine positive Richtung enthalten. Wie z.B. auf, ein, hoch, an, usw.
false sind alle Wörter die eine negative Richtung enthalten. Wie z.B. ab, aus, runter, zu, usw.
integer Wort enthält eine Zahl
numeral Wort enthält eine Zahl oder ein Zahlenwort
float Wort enthält eine Gleitkommazahl
/<regexp>/ Wort entspricht der <regexp>
word Wort enthält gleich oder mehr als 4 Buchstaben
empty Wort enthält eine Leere Zeichenkette
else Falls keines der Fälle zutrifft
  • modification enthält das einzufügende Wort.

Wird hier ein Komma benötigt oder besteht die Möglichkeit, dass der Wert eine leere Zeichenkette beinhalten könnte, sollte das Wort in Anführungszeichen gesetzt werden. Kann ebenfalls $n oder andere Variablen beinhalten.

Beispiel
garage\S* (\S*) = set dev_garage $1{ true => open , false => close }

Ausgabe:

Spracheingabe FHEM Kommando
mach die Garage auf set dev_garage open
bitte Garagentor schließen set dev_garage close

Variante 2: nach Liste


Hier kann die Klammer anhand einer oder zweier Listen selektiert werden.

Definition
$n[ wert1, wert2,,,,, wertn ]

oder

$n[ @liste ]

Innerhalb der Klammern [ ] wird eine Komma separierte Liste mit Namen erwartet die als Modifikatorliste dient. Die sogenannte Modwordlist. Die Werte sind immer optional und können leer gelassen werden. Über das Attribut T2F_modwordlist können diese Listen zur Übersicht und Wiederverwendbarkeit angelegt werden. Siehe Attribute. Auf diese Listen, lässt sich über den Namen der Liste, mit einem vorangestelltes '@' zugreifen.

Beispiel nach Position

Beim ersten Beispiel wird eine Zahl im regex-Teil erwartet (\d+). Diese Zahl entscheidet welche Position aus der Modwordlist ausgewählt werden soll.

ventilator auf (stufe )?(\d+) = set aircon $2[ off, level1, level2, level3 ]                                                                                              
                          |------------------>  0      1       2       3            

(Stufe )? bedeutet: Das Wort Stufe kann, muss aber nicht.

Ausgabe:

Spracheingabe FHEM Kommando
Ventilator in 10 Minuten auf Stufe 0 set aircon off
Ventilator auf 3 set aircon level3
Beispiel nach Vergleichsliste

Hier kommt eine weitere Liste ins Spiel. Die sogenannte Keywordlist ist im Eigentlichen eine RegExp "Ver-oder-ung".

( key1 | key2 | ... | keyn )

oder

( @keywordlist )

Diese Liste mit Schlüsselwörtern wird im <regex>-Teil angegeben. Hier entscheidet nicht eine Zahl über die Position, sondern die Position die in der Keywordlist einen Treffer hat wird an selber Position in der Modwordlist ausgewählt. Im Attribut T2F_keywordlist können vordefinierte Listen angelegt werden und mit @keylist ausgewählt werden

blendet && (Wohnzimmer|Esszimmer|Küche) = set $1[act_lvgroom, act_dinroom, act_kitchen] 70
              1__________2_______3___________________1_____________2____________3

Ausgabe:

Spracheingabe FHEM Kommando
im Esszimmer blendet es set act_dinroom 70
ich sitze geblendet im Wohnzimmer set act_lvgroom 70
die sonne blendet in der Küche set act_kitchen 70

Auswahl des Listenelements

Soll bei der Nutzung der Variable nicht der Wert aus dem Sprachbefehl, sondern der Wert der Liste genutzt werden, so wird an die Variable ein @ angehängt. So wird bei

blendet.* (Wohnzimmer|Esszimmer|Küche) = set act_$1@ 70

Die Sätze

es blendet im Esszimmer
es blendet im esszimmer

immer zu

set act_Esszimmer 70

führen, da die Liste das Esszimmer großgeschrieben enthält.

Ergänzung

Ähnlich wie in Variante 1, könne auch hier auf die Schlüsselwörte

empty für leere Zeichenkette 

und

else für alle anderen Fälle

zugegriffen werden. Hierbei wird der Modwordlist einfach empty oder else gefolgt von dem gewünschten Wert als nächstes Element angehängt.

$n[ wert1, wert2,,,, empty, leererwert, else, andernfallswert ]

Generell lassen sich @ Listen mit Werten erweitern.

$n[@rooms, empty, dev_alle]

Import von Konfigurationen

Umfangreiche Konfigurationen können in Dateien ausgelagert und über $inlcude importiert werden:

$include = FHEM/t2f.cfg

Mehrere RegExps

Wenn die Reihenfolge der Wörter Unbekannt ist, kann der <regexp>-Teil in mehrere Einzelteile aufgelöst werden:

<regexp> && <regexp> && ...

Beispiel

Licht && Wohnzimmer && schalte = ...

Akzeptiert werden hier

Schalte das Licht im Wohnzimmer
Im Wohnzimmer das Licht schalten
Schalte im Wohnzimmer das licht

RegExp Optionen

Die einzelnen RegExp Teile können zusätzlich mit den Zeichen ? und ! beeinflusst werden:

  • Negierung !<regexp>
  • Optional ?<regexp>

Beipiel:

Licht && ?Wohnzimmer && schalte && !aus = ...

akzeptiert

Schalte das Licht im Wohnzimmer ein
Schalte das Licht ein

aber nicht

Schalte das Licht im Wohnzimmer aus
Schalte das Licht aus

zusätzliche Variablen

Ergänzend zu den Listenvariablen stehen folgende Variablen zur Verfügung:

  • $& Enthält alle gefundenen Wörter
  • !$& Enthält den Rest der nicht von der RegExp eingeschlossen wurde
  • $0 Enthält den Text der erkannten T2F_origin RegExp
  • $DATE Enthält den Zeit und Datumstext des Sprachbefehls
  • $TIME Enthält die erkannte Zeit in Sekunden
  • $IF Enthält den Text der erkannten T2F_if Konfiguration
  • $NAME Enthält den Devicenamen
  • $AGAIN Enthält das Wort wieder wenn es sich um ein wieder Kommando handelt (siehe Beispiele)

erweiterte Befehlskonfiguration

Um Talk2Fhem in den Konfigurationszeilen weitere Parameter zu übergeben, ist eine gesonderte Syntax zu verwenden.

<regexp> = ( option => 'value'  ,
             opt2   => 'value2' ,
             ... 
             optn   => 'valuen' ) 

Es stehen folgende Optionen zur Verfügung:

  • cmd => enthält das FHEM Kommando. Wie oben beschrieben. Wird bei bedarf Zeit- oder Ereignisgebunden ausgeführt.
  • answer => Ein Perl-Befehl der direkt ausgeführt wird und dessen Rückgabe ein Text sein sollte. Das Ergebnis wird in das Reading answer geschrieben. Der Befehl muss in einem der folgenden Zeichenpaaren eingeschlossen sein. ( ), { }, " " oder ' '. Zu empfehlen sind einfache Anführungszeichen, da dieses verwendet werden müssen wenn Kommazeichen benötigt werden.
  • offset => Ganzzahliger Wert in Sekunden der dem Zeitpunkt addiert wird. Siehe #Zeitenmodifikation

Zeitenmodifikation

Manchmal ist es notwendig etwas vor der angegebenen Zeit auszuführen. Hier lässt sich ein Offset zu dem ermittelten Zeitpunkt hinzufügen, um ihn zu ändern.
Beispiel

dusche\S?$ = (offset=>-3600, cmd=>'set d_log bad warm')

Ausgabe:

Spracheingabe FHEM Kommando
ich will um 18:30 Uhr duschen define at_talk_1513096200_0 at 2017-12-12T17:30:00 set d_log bad warm

Antworten

In Talk2Fhem können Antworten, die das Modul ausgeben soll, definiert werden. Hier können Fragen verarbeitet werden oder auch der Erfolg eines Kommandos bestätigt werden. Die Antworten werden immer direkt ausgegeben ohne zeitlichen oder ereignisbehafteten Bezug.

Über die #erweiterte_Befehlskonfiguration, erhält der Parameter "answer" einen Perl Befehl. Die Rückgabe muss ein Text sein, der als Antwort dient.

Beispiel Erfolgsmeldung

tu was = ( cmd => "set tue es" , answer => ("Ja") )

Da answer immer sofort ausgeführt wird, hat das Ja keine Aussagekraft bei zeitlichen oder eventbezogenen Kommandos. Möchte man eine Rückmeldung zu diesem Zeitpunkt bekommen, müsste das dem FHEM Kommando hinzugefügt werden.

tu was = ( cmd => "set tue es;; set tts speak Erledigt!" , answer => ("Ja") )

Beispiel Zustandsabfrage

wurde es getan = ( answer => { Value("tue") eq "es" ? "Ja" : "Nein" })

Beispiel Temperaturabfragen

Eine einfache Temperaturabfrage könnte so aussehen.

wie.*(kalt|warm|grad|temperatur) = 
( answer => 
       ' "Die Temperatur beträgt ".ReadingsVal("tempdev", "temperature", "Fehler") ' 
)

Für eine Raumbezogene Temperaturabfrage, siehe #Raumbezogene_Temperaturansage

Personalifizierung

Für eine Personenbezogene Konfiguration gibt es die Hilfestellung des Attributs T2F_origin.

Der Gedanke dahinter ist, man fügt dem Sprachbefehl einen Zusatz, wie z.B. den Namen am Anfang des Satzes, hinzu.

Ein notify auf ein Telegramdevice könnte so ausehen:

telbot:msgText.* {
	my $p=ReadingsVal("telbot", "msgPeer","");
	fhem("set talk ".($p?$p."=":"").$EVENT=~s/^msgText: //r);
}

Jetzt wird dem Textbefehl immer der Name (msgPeer) und anschließendem "=" dem Befehl hinzugefügt und an talk gesendet. Dieser Text kann mit T2F_origin verarbeitet werden.

siehe hierzu #T2F_origin

Attribute

Folgende Attribute werden zur Zeit unterstützt

T2F_keywordlist

<Name> = <kommaseparierte Liste mit RegExp>

Beispiele

&rooms = haus|überall|wohnung , wohnzimmer , bad\\S* , toilette|wc , büro , 'eg|erdgescho\S\S?' ... 
names = Mama , Papa , Kevin , Jacqueline
channels = ard|das erste , zdf , rtl , sat 1 , vox , rtl2 , prosieben , kabel eins , arte
Info green.pngWichtig Backslashes "\" und Kommas "," müssen geschützt werden. Das erfolgt über das Quoting. Mit einfachen Anführungszeichen oder doppelten Backslash. Siehe rooms.

Man beachte hier die möglichkeit der RegExp
Das Schlüsselwort haus löst das selbe aus wie überall und wohnung
Genauso bad oder badezimmer oder badeirgendewas

Achtung:
Damit das Modul die Fähigkeit der Objektverundung erlangt, müssen die Objekte benannt werden die dafür geeignet sind. Hierzu muss lediglich der Keywordliste mit den vorhandenen RegExp ein kaufmännisches Und '&' vorangestellt werden. Es ist nicht notwendig diese Keywordlisten in der Konfiguration zu verwenden. In der Regel handelt es sich hierbei um Räume oder Geräte. Siehe &rooms.
Dadurch lassen sich folgende beispielhaften Sätze formulieren.

mach das Licht im Wohnzimmer, in der Küche und im Esszimmer an
Rollos im Schlafzimmer und im Kinderzimmer runter

Diese Eigenschaft sollte nur bei sinnhaften Listen angewendet werden. Wenn notwendig kann eine separate Liste hierfür angelegt werden. Eine Vorlage für Räume kann hier kopiert werden. #Keywordlist

T2F_modwordlist

<Name> = <kommaseparierte Liste mir RegExp>

Die Positionen der gewählten Geräte, ist eine Zuordnung zu den Listen inT2F_keywordlist
Wenn Wohnzimmer in der keywordliste <rooms> an Position 2 steht muss der Rolladenaktor in der modworliste <roll> auch an Position 2 stehen.

roll = rollos_alle , d_rollo_wz , hm_roll_bad.* , hm_roll_wc , hm_roll_buero.* , ...
lights = alle_lichte , "sw_wz1,sw_wz2" , sw_bad.* , sw_wc

Sollen einem Schlüsselwort mehrere Aktoren zugeordnet werden, geht das über sogenannte "Quotes". (Anführungszeichen) Siehe <lights>.

"a,b"  oder  'a,b'  oder  a\,b

T2F_if

Möchte man einen Befehl erst zu einem bestimmten Ereignis oder zu einer Bedingung ausführen lassen, lässt sich das über dieses Attribut konfigurieren.

Die Syntax orientiert sich hier an der der Definition. Die Syntax der Bedingung entspricht der des FHEM-Befehls IF. Sobald hier das Device dev_ring den Status ring erhält, wird das zusätzlich erkannte Kommando ausgeführt.

wenn .*?klingel = [dev_ring] eq "ring"

Beispielsätze

wenn es klingelt
wenn jemand die klingel betätigt

Hier stehen genauso wie in der Definition Klammermodifikatoren zur Verfügung.

wenn die temperatur (über|unter) ([\s\.,\d]+) grad = [sens:temp] $1[>,<] $2{float=>"$2"}

Ausgabe:

Spracheingabe FHEM Bedingung
wenn die temperatur über 22 grad steigt [sens:temp] > 22
wenn die temperatur unter 21, 5 grad fällt [sens:temp] < 21.5

Erweiterte Optionen in dieser Konfigurationszeile sind möglich aber noch nicht relevant.

T2F_origin

Das Attribut T2F_origin kann für eine herkunftsabhängige Beeinflussung der Befehle genutzt werden. Das bedeutet abhängig davon, wer den Befehl gibt oder von wo der Befehl abgegeben wurde. Es enthält eine RegExp die generell vom ganzen Sprachbefehl entfernt und in der Variable $0 zu Verfügung gestellt wird

Der Inhalt des Attributs könnte folgender sein.

^\w+=

Nun wird ein am Anfang auftretendes wort= entfernt und als Origin behandelt.

Beispiel

Spiele meine Musik = set mediaplayer play pop

Jetzt soll das Wort pop Personenbezogen umgeformt werden.

Spiele meine Musik = set mediaplayer play $0{/kevin/=>hiphop,/jaqueline/=>gothik,else=>pop}

Folgender Satz setzt dann für das Wort pop hiphop ein.

kevin= spiele meine Musik bitte

Das ganze lässt sich auch verschachteln und mit Keywordlisten kombinieren. Siehe hierzu Beispiele.

T2F_disableumlautescaping

Deaktiviert das Konvertieren der Umlaute innnerhalb von regulären Ausdrücken in \S\S?

T2F_language

Legt die verwendete Sprache fest. Alternativ wird das Globale Attribut language verwendet werden.

disable

Deaktiviert das Ausführen des FHEM Kommandos

verbose

Anwendungsbeispiele und Vorlagen

Hier folgen diverse Vorlagen und Beispiele die jeweils an die eigenen Bedürfnisse angepassst werden sollten/müssen. Hierzu sind die entsprechenden Stellen rot markiert.

Keywordlist

Eine typische Keywordlist wäre eine Auflistung der benötigten Räume

&rooms = haus|überall|wohnung,wohnzimmer,esszimmer,küche,bad\\S*,toilette|wc,
büro,schlafzimmer,ankleide|garderobe,kinderzimmer,spielzimmer,
flur|gang|diele,garage,garten,terrasse,balkon,
'eg|erdgescho\S*','og|obergescho\S*','\S*außen|außer haus|vor der tür'

Das '&' vor rooms ist eine Besonderheit der Objektverundung, und sollte nur bei ausgewählten Listen verwendet werden. Siehe T2F_keywordlist

Einfaches schalten

1. Beispiel

licht (\S+) = set dev_light $1{ true => on, false => off }

2. mit eigenen Wörtern

Will man neben an/aus einen weiteren Zustand selbst definieren, kann das so geschehen.

garage (\S+) = set dev_gate $1{ /kurz/ => open-for-timer 300, true => open, false => close }

3. mit Räumen

licht (\S+ ){0,2}(wohnzimmer|esszimmer|küche|terrasse) (\S+) =
   set $2[light_wz,light_ez,light_kitchen,light_outside] $3{ true => on, false => off }

Bei größeren Mengen an Räumen und Geräten bietet sich das anlegen von Keyword- und Modwordlisten an.

licht (\S+ ){0,2}(@rooms) (\S+) = set $2[@lights] $3{ true => on, false => off }

Rolladen fahren

Sind die Rollläden innerhalb von FHEM über das Attribut "room" den Räumen mit Klarnamen zugeordnet, lässt sich das ganze am einfachsten konfigurieren.
1. nach Devicetyp

rolll?(os?|\S\S?den) ?(\S+ ){0,2}(\S+) (auf )?(\S+) = 
  set room~$3{/haus/=>.*,empty=>.*,else=>$3}
      :FILTER=a:subType=blindActuator $5{true=>on, false=>off, integer=>set_$5}

Erklärung
Wenn das Device vom subTyp "blindActuator" ist (HomeMatic Rolladenactor) und es im Raum aus der dritten Klammer ($3) ist, wird dieses Device gefahren.


2. nach Devicenamen

  set room~$3{/haus/=>.*,empty=>.*,else=>$3}
      :FILTER=rollo.* $5{true=>on, false=>off, integer=>set_$5}

Erklärung
Gleiche wie oben, nur das alle Devices die mit rollo beginnen im Raum $3 gefahren werden. (rollo.*)


3. nach Benutzerdefinierten Räumen
Ansonsten müssen wir dem Modul sagen in welchem Raum welches Device sitzt. Das hat dafür den Vorteil das die Räume als RegExp angegeben werden können.
Wir erzeugen eine Modwordlist rollos in der wir alle Rollladen "Devices" auflisten. Die Reihenfolge ist an der Keywordlist "rooms" (#Keywordlist) anzupassen.

rollos = r_alle,r_wz,r_ez,,r_buero,...


Definition

rolll?(os?|\S\S?den) ?(\S+ ){0,2}(@rooms)? (auf )?(\S+) = set $3[@rollos, empty, rollos_alle] $5{true=>on, false=>off, integer=>"set_$5"}

Beispielsätze

Rollos auf
Rolllos Überall schließen 
Rollo im Wohnzimmer hoch
Rolladen im Esszimmer runter
Rollläden in der Küche auf 50


Damit wäre eigentlich schon alles abgedeckt. Folgendes Beispiel ist aber auch noch nützlich.
Definition

 (blendet|schatte\S?) ?(\S+ ){0,2}(@rooms) = set $3[@rollos] set_70

Beispielsätze

es blendet im Esszimmer
ich werde geblendet in der Küche
die Sonne blendet mich im Badezimmer
beschatte das Haus
mach schatten im Erdgeschoss

Erweiterte Personalisierung

Wie löst man das Problem mit dem Wort "ich" in Sätzen wie:

Wenn ich nach hause komme

Voraussetzung siehe #T2F_origin

T2F_keywordlist @names mit den Namen:

names = wir|alle|uns,ich|mein\S*,hans,jutta,kevin,jaqueline

T2F_modwordlist @devs mit den Geräten der Personen.

devs = d_alleda,,handyhans,handyjutta,handykevin,handyjac 

Standardmäßig könnte eine Konfigurationszeile in T2F_if folgendermaßen definiert werden.

wenn (@names) (heim|nach hause) komm\S* =
  [$1[@devs]] =~ /ja|present/ 

Für das Device d_alleda wird angenommen das dieses ja und nein enthalten kann, und deswegen nicht mit present verglichen werden kann.

In @devs ist für ich kein Wert vorgesehen, da es sich ja um einen variablen Wert handelt. Deswegen erfassen wir erstmal ich über die /regexp/. Andernfalls wird die Liste @devs herangezogen.

wenn (@names) (heim|nach hause) komm\S* =
  [$1{/ich/=>weristich,else=>'$1[@devs]'}] =~ /ja|present/

Nun weisen wir über die origin Variabel $0 dem Platzhalter weristich die Geräte zu.

wenn (@names) (heim|nach hause) komm\S* =
  [$1{/ich/=>$0{/hans/=>handyhans,
              /jutta/=>handyjutta,
              /kevin/=>handykevin,
              /jaque/=>handyjac},
    else=>'$1[@devs]'}] =~ /ja|present/

Das Beispiel zeigt wie eine verschachtelte Personenzuordnung aussehen könnte. Die Abarbeitung der $n Modifikatoren erfolgt von rechts nach links.
Folgende Sätze werden konvertiert in:

Sätze Ergebnis
jutta= wenn hans nach hause kommt [handyhans] =~ /ja|present/
hans= wenn wir heim kommen [d_alleda] =~ /ja|present/
kevin= wenn ich nach hause komme [handykevin] =~ /ja|present/

GoogleCast Befehle

Etwas bessere Lautstärkebefehle als die von Google. Die Lautstärken müssten noch dem eigenen Geschmack angepasst werden

#GoogleCast Commandos
(leise\b|normale lautstärke|laut\b)      =  set googlecastdevice volume $1[14,20,30]
(ein wenig|etwas|viel)? ?(lauter|leiser)  =
  { fhem("set googlecastdevice volume ".(ReadingsVal("googlecastdevice","volume", 0)$2[+,-]$1[3,5,10,empty,7])) }

Beispielsätze

Mach leise
laut machen
Mach lauter
etwas leiser
viel lauter

Für eine raumbezogene Lautstärkenkonfiguration wären nur ein paar Änderungen notwendig.

?(@rooms) && (leise\b|normale lautstärke|laut\b)      =  set $1[@musicdevices,empty,standard] volume $2[14,20,30]
?(@rooms) && (ein wenig|etwas|viel)? ?(lauter|leiser)  =
  { fhem("set $1[@musicdevices,empty,standard] volume ".(ReadingsVal("$1[@musicdevices,empty,standard]","volume", 0)$3[+,-]$2[3,5,10,empty,7])) }

Talk Timer zurücksetzen

Sollen alle von Talk2Fhem angelegten Timer gelöscht werden.

(timer|kommandos) (löschen|zurücksetzen) = set cleartimers $NAME

Beispielsätze

bitte alle timer zurücksetzen
zukünftige kommandos löschen

Frage Antwort

Raumbezogene Temperaturansage

Wir erzeugen wieder unsere Modwordlist sagen wir @sens gefüllt mit den Temperaturfühler "Devices". Reihenfolge wie immer die der Keywordlist @rooms.

wie.*(kalt|warm|grad|temperatur).*(@rooms) = 
 (
  answer => '"Die Temperatur beträgt ".ReadingsVal("$2[@sens]", "temperature", "unbekannt")." grad"'
 )

Beispielsätze

wie warm ist es im Wohnzimmer
wie ist die Temperatur in der Küche
wie kalt ist es draußen

Multiple Antworten

Hallo Haus = ( answer => '["Hallo auch!","Guten Tag!","Ahoi!"]->[rand(3)]' ) 

Wählt zufällig eine der drei Aussagen.

Ausgabe eines oder mehrerer Zustände

Angenommen man möchte wissen ob das Haus abgeschlossen ist. Und in FHEM existiert ein Dummy der diesen Zustand wiederspiegelt und im Reading text die offenen Fenster und Türen aufgelistet sind. Kann man folgendermaßen den Status erfragen

(alles|das haus) (zu|abgeschlossen) = (
  answer => '(Value("d_schliessung") eq "zu") 
             ? "Es ist alles zu" 
             : "Nein, offen sind: ".ReadingsVal("d_schliessung","text","")'

Einfache Standardantwort

schalte etwas (\S+) = (
 cmd  => "set etwas $1{ true => on, false => off }",
 answer =>  ("OK") )

Schaltzustand als Feedback

Da answer immer sofort ausgeführt wird, wird OK direkt gesetzt unabhängig davon ob beim Kommando eine Zeit- oder Eventbedingung mitgegeben wurde. Möchte man eine Antwort zum Zeitpunkt des Ausführens bekommen, oder bei Dingen die kein offensichtliches Feedback erzeugen, ist folgendes eine Möglichkeit.

schalte etwas (\S+) = (
 cmd  => 
   "set etwas $1{ true => on, false => off };
    setreading $NAME answers Etwas wurde $1{true=>eingeschaltet,false=>ausgeschaltet};
    setreading $NAME status answer",
 answer =>  ("OK") )

Erfolgsmeldung

Soll die Antwort abhängig vom Erfolg des Befehls sein dann könnte es so aussehen.

schalte etwas (\S+) =
 set etwas $1{ true => on, false => off};
 defmod atdekofb at +00:00:01 IF ([etwas] eq "$1{ true => on, false => off}")
   (setreading $NAME answers Kommando erfolgreich.)
  ELSE
   (setreading $NAME answers Der Befehl war nicht erfolgreich.);;
  setreading $NAME status answer

Je nach der individuellen Auswertung des Reading "answers" ist die letzte Zeile (Reading status) notwendig oder auch nicht.

Zustandsabfrage anhand des Aliasnamen

Möchte man alle Geräte anhand seines Attribut "alias" ansprechen, um dessen Status zu erfragen, könnte das so erfolgen.
Definition

(zustand|status)( \S+)* (\S+) = 
   ( answer => {"Der Status ist ".(Value((devspec2array('a:alias~$3'))[0]) || "unbekannt")} )

Beispielsätze

Wie ist der Zustand der Lüftung
sag mir den Status von der Haustür

Es ist auch möglich ein eigenes Attribut zu kreieren, und dieses als Klarnamenattribut zu verwenden. Hierzu einfach im Device global ein userattr hinzufügen. z.B.

attr global userattr T2F_alias

Jetzt stehen in allen Devices das Attribut T2F_alias zur Verfügung. Vorteil ist das dann auch wieder RegExp verwendet werden können. Im oberen Beispiel müsste dann dass rot markierte "alias" durch "T2F_alias" ersetzt werden.

Ereignisbezogene Meldungen

Da answer immer sofort den Text ausgibt ist hier beschrieben wie man eine Antwort zu einem bestimmten Ereignisses erhalten kann.

Es genügt folgende Zeile anzulegen und seinen bedürfnissen anzupassen.

bescheid = set googlecastdevice speak "Ich sollte bescheid geben $IF"

Über die T2F_if Bedingungen bekommt man jetzt immer eine Aussage sobald eine Ereignis eintritt.

Sätze wie

gib bescheid wenn mama nach hause kommt
sag mir wenn die tür öffnet bescheid
wenn es draußen kalt ist sag mir bescheid

ergeben dann folgende Kommandos.

set googlecastdevice speak  "Ich sollte bescheid geben wenn mama nach hause kommt"
set googlecastdevice speak  "Ich sollte bescheid geben wenn die tür öffnet"
set googlecastdevice speak  "Ich sollte bescheid geben wenn es draußen kalt ist"

Man sollte darauf achten, dass die T2F_if Bedingungnen möglichst komplett von der RegExp erfasst werden. Dadurch können die Sätze komplett wiederholt werden.

Konfiguration innerhalb der Geräte

Neben der Identifikation der Geräte über die vorhandenen FHEM-Attribute (z.B. room, alias, ...) kann eine alternative Konfiguration auch über eigens für Talk2Fhem angelegte Attribute erfolgen. Die hierfür notwendigen Grundlagen und einige Beispiele sollen im Folgenden beschrieben werden.

Grundlagen / Voraussetzungen

1. Anlegen der notwendigen userattr am global-Device:

Erweiterung des Attributes userattr des Gerätes global um folgende Einträge:

 T2F_places:textField-long T2F_properties:textField-long T2F_rooms:textField-long T2F_types_color:textField-long T2F_types_heating:textField-long T2F_types_info:textField-long T2F_types_switch:textField-long

2. Optional: Hilfsfunktionen für das automatische Füllen der T2F_keywordlist im talk-Device bei Änderung eines T2F-Attributes eines Gerätes

2a. erstellen einer sub in der 99_myUtils.pm:

  sub fill_T2F_keywordlist
  {
    my ($name, $t2f_device) = @_;
    $name =~ s/T2F_//g;
    if ($name eq 'userattr')
    {
      return;
    }
    Log 0, "List: ".$name;
    my $currentAttr = AttrVal($t2f_device,"T2F_keywordlist","");
    my @currentAttrParts = split(/$name = /, $currentAttr);
    my $currentAttrBeg = @currentAttrParts[0];
    $currentAttrBeg = substr($currentAttrBeg, 0, -1);
    my @currentAttrEnd = split(/\n/, @currentAttrParts[1], 2);
    my @array = devspec2array('a:T2F_'.$name.'=.+');
    my @attributes = ();
    if (@array > 0 and defined($defs{$array[0]}))
    {
      foreach (@array){
      my @attrVals = split(/\n/,AttrVal($_, 'T2F_'.$name, ''));
      foreach (@attrVals){
          my $attrVal = $_;
          $attrVal =~ s/  / /g;
          $attrVal =~ s/ => /=>/g;
          my @attrValParts = split(/=>/,$attrVal);
          $attrVal = @attrValParts[0];
          $attrVal =~ s/!//g;
          $attrVal =~ s/, /,/g;
          my @attr = split(/,/, $attrVal);
          push(@attributes, @attr);
        }
      }
    }
    my %hash   = map { $_ => 1 } @attributes;
    my @unique = keys %hash;
    my $result = $currentAttrBeg."\n".$name." = ".join(", ", @unique)."\n".@currentAttrEnd[1];
    $result =~ s/\n\n/\n/g;
    $result =~ s/  / /g;
    fhem('attr '.$t2f_device.' T2F_keywordlist '.$result);
  }

2b. Erstellen eines DOIFs zum Aufruf der sub:

 defmod talk.DI.fillAttr DOIF ([global:"^ATTR.*T2F_.*"]) ({my $val = ReadingsVal("$SELF", "e_global_events", ""); $val =~ m/(\S*) (\S*) (\S*) (.*)/; if ($2 ne 'talk' && $2 ne 'global') { fill_T2F_keywordlist("$3", "talk");}})
 attr talk.DI.fillAttr do always

3. Optional: Erlauben von Umlauten in den T2F-Attributen:

 attr talk T2F_disableumlautescaping 1  
 

Nun können die T2F-Attribute pro FHEM-Device definiert und dann in den Talk2Fhem-Befehlen benutzt werden. Wurde der Punkt 2 abgearbeitet, so werden mit dem Füllen der Attribute am Geräte auch die Keywordlisten am talk-Device gefüllt. Wie diese dann verwendet werden können, sollen die folgenden Beispiele zeigen.

Schalten von Geräten

Ausgangssituation: Es gibt drei Lampen Lampe1, Lampe2, Lampe3 und ein Nachtlicht mit einer Eule mit folgenden Attributen:

 attr Lampe1 T2F_types_switch Lampe, !Licht
 attr Lampe1 T2F_rooms Haus, Obergeschoss, !Esszimmer
 attr Lampe1 T2F_places Decke, Tür
 attr Lampe1 T2F_properties hell,!
 attr Lampe2 T2F_types_switch Lampe, !Licht
 attr Lampe2 T2F_rooms Haus, Obergeschoss, !Esszimmer
 attr Lampe2 T2F_places Tisch, Esstisch
 attr Lampe2 T2F_properties dunkel,schwach,!
 attr Lampe3 T2F_types_switch Lampe, !Licht
 attr Lampe3 T2F_rooms Haus, Obergeschoss, !Küche
 attr Lampe3 T2F_places Besenschrank
 
 attr Nachtlicht T2F_types_switch Lampe, !Licht, Eule, Nachtlicht
 attr Nachtlicht T2F_rooms Haus, Obergeschoss, !Kinderschlafzimmer
 attr Nachtlicht T2F_places Steckdose

Durch die in Punkt 2 der Voraussetzungen genannten Funktionen wurden folgende T2F-keywordlisten automatisch angelegt:

 attr talk T2F_keywordlist rooms = Kinderschlafzimmer, Haus, Küche, Obergeschoss, Esszimmer 
                           places = Tür, Steckdose, Tisch, Decke, Esstisch
                           properties = hell, dunkel, schwach
                           types_switch = Lampe, Licht, Eule

Die Definition für das T2F-Device lautet dann wie folgt:

 #   1              2                 3                4            5          6          7      
 ?(bitte) && ?(@properties) && (@types_switch) && ?(@rooms) && ?(@places) && (\S+)(schalten|machen)?$ =
 (cmd=>'set T2F_types_switch=.*$3@.*:FILTER=T2F_rooms=.*$4@.*:FILTER=T2F_properties=.*$2@.*:FILTER=T2F_places=.*$5@.* $6{true=>on, false=>off}',
 answer=>'"$AGAIN" ? "dann $DATE wieder $6{true=>ein, false=>aus}" : "$1{/bitte/=>Gern, else=>Das heißt Bitte}, ich schalte $1{/bitte/=>, else=>trotzdem} folgende Geräte $6{true=>ein, false=>aus}: ".T2F_answer("T2F_types_switch=.*$3@.*:FILTER=T2F_rooms=.*$4@.*:FILTER=T2F_properties=.*$2@.*:FILTER=T2F_places=.*$5@.*","T2F_types_switch")')
                           

Damit sind dann die folgenden Sprachbefehle möglich:

 Schalte das Licht in der Küche ein                      => schaltet Lampe3 ein
 
 Schalte die helle Lampe im Esszimmer an                 => schaltet Lampe1 ein
 
 Schalte das Licht im Esszimmer über dem Esstisch ein    => schaltet Lampe2 ein
 
 Schalte die Eule ein                                    => schaltet Nachtlicht ein
 
 Schalte das Licht im Esszimmer aus}                     => schaltet Lampe1 und Lampe2 aus
 
 Schalte das Licht aus                                   => schaltet alle vier Lichter aus

Um in der Antwort die Liste der geschalteten Geräte genannt zu bekommen, wird die sub T2F_answer aus der 99_myUtils aufgerufen:

sub T2F_answer
{
  my ($filter, $type) = @_;
  my $answer = '';
  my @devices = devspec2array($filter);
  if (@devices > 0 and defined($defs{$devices[0]}))
  {
    foreach (@devices){
      my $devAttr = AttrVal($_, $type, '');
      if ($answer ne '')
      {
        $answer = $answer.", ";
      }
      if (substr($devAttr,-1) ne "!")
      {
        my @entries = split(/!/, $devAttr);
        if (@entries < 2)
        {
          @entries = split(/,/, $entries[0]);
        }
        else
        {
          @entries = split(/,/, $entries[1]);
        }
        if (@entries[0] ne "")
        {
          $answer = $answer.@entries[0]." ";
        }
      }
      
      $devAttr = AttrVal($_, 'T2F_properties', '');
      if (substr($devAttr,-1) ne "!")
      {
        my @entries = split(/!/, $devAttr);
        if (@entries < 2)
        {
          @entries = split(/,/, $entries[0]);
        }
        else
        {
          @entries = split(/,/, $entries[1]);
        }
        if (@entries[0] ne "")
        {
          $answer = $answer.@entries[0]." ";
        }
      }
      
      $devAttr = AttrVal($_, 'T2F_rooms', '');
      if (substr($devAttr,-1) ne "!")
      {
        my @entries = split(/!/, $devAttr);
        if (@entries < 2)
        {
          @entries = split(/,/, $entries[0]);
        }
        else
        {
          @entries = split(/,/, $entries[1]);
        }
        if (@entries[0] ne "")
        {
          $answer = $answer.@entries[0]." ";
        }
      }
      
      $devAttr = AttrVal($_, 'T2F_places', '');
      if (substr($devAttr,-1) ne "!")
      {
        my @entries = split(/!/, $devAttr);
        if (@entries < 2)
        {
          @entries = split(/,/, $entries[0]);
        }
        else
        {
          @entries = split(/,/, $entries[1]);
        }
        if (@entries[0] ne "")
        {
          $answer = $answer.@entries[0]." ";
        }
      }
    }
  }
  return $answer."";
}

Die Benennung der Geräte erfolgt auf Basis derer T2F-Attribute: Typ, Eigenschaft, Raum, Ort. Ist das jeweilige Attribut leer, ist es auch in der Antwort leer. Enthält die jeweilige Attributliste ein Ausrufezeichen (!), so wird der Eintrag nach dem Ausrufezeichen für die Antwort verwendet (z.B. Esszimmer als Raum). Steht das Ausrufezeichen am Ende, so wird der Eintrag in der Antwort leer gelassen (z.B. die Eigenschaft bei Lampe1). Ist kein Ausrufezeichen vorhanden, so wird der erste Eintrag verwendet.

Einstellen der Heizung

Das gleiche Prinzp wie bei den Lampen kann auch für die Einstellung der Heizung verwendet werden.

Ausgangssituation: In der Küche, im Kinderschlafzimmer und im Esszimmer gibt es jeweils eine Heizung (Homematic HM-CC-RT-DN) mit folgenden Attributen:

 attr HeizungEsszimmer T2F_places Heizung,!
 attr HeizungEsszimmer T2F_rooms Haus,Obergeschoss,Essbereich,!Esszimmer
 attr HeizungEsszimmer T2F_types_heating Heizung,Temperatur,Esszimmer,Essbereich,!
 attr HeizungKüche T2F_places Heizung,!
 attr HeizungKüche T2F_rooms Haus,Obergeschoss,Essbereich,!Küche
 attr HeizungKüche T2F_types_heating Heizung,Temperatur,Küche,Essbereich,!
 attr HeizungKiSchla T2F_places Heizung,!
 attr HeizungKiSchla T2F_rooms Haus,Obergeschoss,!Kinderschlafzimmer
 attr HeizungKiSchla T2F_types_heating Heizung,Temperatur,Kinderschlafzimmer,!


Mit der T2F-Definition

 #   1             2                  3        4      5                  
 ?(bitte) && (@types_heating) && ?(@rooms) && (auf (\d+) grad|auto\S*)( stellen| setzen| einstellen| ein)?$ = 
 (cmd=>'set T2F_types_heating=.*$2{empty=>.+, else=>$2@}.*:FILTER=T2F_rooms=.*$3@.* $5{integer=>desired-temp $5, else=>controlMode auto}',
 answer=>'"$AGAIN" ? "dann $DATE wieder auf Automatik" : "Die Durchschnittstemperatur beträgt dort zur Zeit ".averageTemp("T2F_types_heating=.*$2{empty=>.+, else=>$2@}.*:FILTER=T2F_rooms=.*$3@.*")." Grad\n$1{/bitte/=>Gern, else=>Das heißt Bitte}, ich stelle die Heizung in folgenden Räumen auf $5{integer=>$5 Grad, else=>Automatik}: ".T2F_answer("T2F_types_heating=.*$2{empty=>.+, else=>$2@}.*:FILTER=T2F_rooms=.*$3@.*","T2F_types_heating")')
 

funktionieren folgende Sprachbefehle:

 Bitte stell die Heizung im Esszimmer auf 21 Grad        => Stellt die Heizung im Esszimmer auf 21 Grad
 
 Bitte stell die Heizung im Essbereich auf 21 Grad       => Stellt die Heizungen im Esszimmer und in der Küche auf 21 Grad
 Bitte stell die Heizung im Obergeschoss auf Automatik   => Stellt die drei Heizungen auf Automatik
 

Dadurch, dass im Attribut T2F_types_heating auch die Räume aufgeführt sind, sind auch Befehle in folgender Form möglich:

 Bitte stell die Küche auf 21 Grad                       => Stellt die Heizung in der Küche auf 21 Grad

Auch kann in diesem (wie auch in den oben aufgeführten Schaltbefehlen) mit "wieder" gearbeitet werden:

 Bitte stell die Heizung im Essbereich auf 21 Grad und in 2 Stunden wieder auf Automatik
 

Für die Generierung der Antwort wird neben der bei den Schaltbefehlen bereits gezeigten sub T2F_answer eine weiter Funktion verwende, welche die Durchschnittstemperatur im zu schaltenden Bereich ermittelt und ausgibt:

  sub averageTemp($)
  {
    my ($filter) = @_;
    my @tempDevices = devspec2array($filter);
    my $count = 0;
    my $measuredTemp = 0;
    if (@tempDevices > 0 and defined($defs{$tempDevices[0]})){
      foreach (@tempDevices){
        $measuredTemp = $measuredTemp + ReadingsVal($_, "measured-temp", "");
        $count = $count + 1;
      }
      return $measuredTemp / $count;
    }
    return 0;
  }

Einstellen der Farbe von Farbwechsellampen (Philips Hue, Wifilight, ...)

Für das Beispiel zum Einstellen der Lichtfarbe nehmen wir eine Farbwechsellampe LampeBunt an, welche den Befehl RGB unterstützt. Diese erhält folgende Attribute:

 attr LampeBunt T2F_places Decke,Couch,Sofa
 attr LampeBunt T2F_rooms Haus,Dachgeschoss,!Wohnzimmer
 attr LampeBunt T2F_types_color Lampe,Licht
 attr LampeBunt T2F_types_switch Lampe,Licht
 

Durch das Attribut T2F_types_switch lässt sich diese über die bereits beschriebene Schaltlogik ein und ausschalten. Durch die zusätzlich T2F-Definition

 #   1              2               3             4              5               6 
 ?(bitte) && (@types_color) && ?(@rooms) && ?(@places) && auf (@colors)( schalten| stellen)?$ = 
 (cmd=>'set T2F_types_color=.*$2@.*:FILTER=T2F_rooms=.*$3@.*:FILTER=T2F_places=.*$4@.* RGB $5[@rgb]', 
 answer=>'"Ich schalte folgende Geräte auf $5@: ".T2F_answer("T2F_types_color=.*$2@.*:FILTER=T2F_rooms=.*$3@.*:FILTER=T2F_places=.*$4@.*","T2F_types_color")')

und die entsprechenden Attribute am T2F-Device talk (HINWEIS: eigene Listen können Problemlos ergänzt werden, diese werden durch die Hilfsfunktionen NICHT überschrieben)

 attr talk T2F_keywordlist colors = Aus, Schwarz, Dunkles Schiefergrau, Schiefergrau, Helles Schiefergrau, Helles Stahlblau, Mattes Grau, Grau, Dunkelgrau, Silber, Hellgrau, Gainsboro, Rauchiges Weiß, Geisterweiß, Weiß, Schneeweiß, Elfenbein, Blütenweiß, Muschel, Altgold, Leinenfarbe, Antikes Weiß, Mandelweiß, Cremiges Papaya, Beige, Mais, Helles Goldrutengelb, Hellgelb, Chiffongelb, Blasse Goldrutenfarbe, Khaki, Gelb, Gold, Orange, Dunkles Orange, Goldrute, dunkle Goldrutenfarbe, Peru, Schokolade, Sattelbraun, Ocker, Braun, Dunkelrot, Kastanienbraun, Ziegelfarbe, Indischrot, Karmesinrot, Rot, Orangenrot, Tomatenrot, Koralle, Lachs, Helles Korallenrot, Dunkle Lachsfarbe, Helle Lachsfarbe, Sandbraun, Rosiges Braun, Gelbbraun, Grobes Braun, Weizen, Pfirsich, Navajoweiß, Tomatencreme, Rosige Lavenderfarbe, Altrosa, Rosa, Hellrosa, Leuchtendes Rosa, Fuchsie, Magentarot, Tiefrosa, Mittleres Violettrot, Blasses Violettrot, Pflaume, Distel, Lavendelfarbe, Violett, Orchidee, Dunkles Magentarot, Violett, Indigo, Blauviolett, Dunkles Violett, Dunkle Orchideenfarbe, Mittleres Violett, Mittlere Orchideenfarbe, Mittleres Schieferblau, Schieferblau, Dunkles Schieferblau, Mitternachtsblau, Marineblau, Dunkelblau, Mittelblau, Blau, Königsblau, Stahlblau, Kornblumenblau, Dodger-Blau, Tiefes Himmelblau, Helles Himmelblau, Himmelblau, Hellblau, Zyanblau, Blaugrün, Taubenblau, Helles Cyanblau, Aliceblau, Himmelblau, Cremig Pfefferminz, Honigmelone, Aquamarinblau, Türkis, Blasses Türkis, Mittleres Türkis, Dunkles Türkis, Mittleres Aquamarinblau, Helles Seegrün, Dunkles Zyanblau, Entenbraun, Kadettblau, Mittleres Seegrün, Dunkles Seegrün, Hellgrün, Blassgrün, Mittleres Frühlingsgrün, Frühlingsgrün, Zitronengrün, Gelbgrün, Seegrün, Waldgrün, Grün, Dunkelgrün, Olivfarbiges Graubraun, Dunkles Olivgrün, Olivgrün, Dunkles Khaki, Gelbgrün, Hellgrün, Grüngelb
 attr talk T2F_modwordlist rgb = 000000, 000000, 8FBC8F, 708090, 778899, B0C4DE, 696969, 808080, A9A9A9, C0C0C0, D3D3D3, DCDCDC, F5F5F5, F8F8FF, FFFFFF, FFFAFA, FFFFF0, FFFAF0, FFF5EE, FDF5E6, FAF0E6, FAEBD7, FFEBCD, FFEFD5, F5F5DC, FFF8DC, FAFAD2, FFFFE0, FFFACD, EEE8AA, F0E68C, FFFF00, FFD700, FFA500, FF8C00, DAA520, B8860B, CD853F, D2691E, 8B4513, A0522D, A52A2A, 8B0000, 800000, B22222, CD5C5C, DC143C, FF0000, FF4500, FF6347, FF7F50, FA8072, F08080, E9967A, FFA07A, F4A460, BC8F8F, D2B48C, DEB887, F5DEB3, FFDAB9, FFDEAD, FFE4C4, FFF0F5, FFE4E1, FFC0CB, FFB6C1, FF69B4, FF00FF, FF00FF, FF1493, C71585, DB7093, DDA0DD, D8BFD8, E6E6FA, EE82EE, DA70D6, 8B008B, 800080, 4B0082, 8A2BE2, 9400D3, 9932CC, 9370DB, BA55D3, 7B68EE, 6A5ACD, 483D8B, 191970, 000080, 00008B, 0000CD, 0000FF, 4169E1, 4682B4, 6495ED, 1E90FF, 00BFFF, 87CEFA, 87CEEB, ADD8E6, 00FFFF, 00FFFF, B0E0E6, E0FFFF, A0CE00, F0FFFF, F5FFFA, F0FFF0, 7FFFD4, 40E0D0, AFEEEE, 48D1CC, 00CED1, 66CDAA, 20B2AA, 008B8B, 008080, 5F9EA0, 3CB371, 8FBC8F, 90EE90, 98FB98, 00FA9A, 00FF7F, 00FF00, 32CD32, 2E8B57, 228B22, 008000, 006400, 6B8E23, 556B2F, 808000, BDB76B, 9ACD32, 7FFF00, ADFF2F

kann die Farbe nun auch über folgenden Sprachbefehle eingestellt werden:

 Bitte schalte die Lampe im Wohnzimmer an der Couch auf Olivfarbiges Graubraun

Dadurch, das die Liste colors den Wert "Aus" mit dem entsprechenden Wert "000000" in der Liste rgb enthält, kann die Lampe über die gleiche Logik auch ausgeschaltet werden:

 Bitte schalte das Licht im Wohnzimmer auf Pflaume und in einer Stunde wieder aus
 

Abfragen beliebiger Geräteinformationen

Das folgende Beispiel zeigt die Möglichkeit auf, die Antworten für Statusabfragen direkt am abgefragten Gerät zu definieren. Hierfür werden zunächst eine Definition am T2F-Device

 #              1             2                3            4
 Wie && ?(@properties)&& (@types_info) && ?(@rooms) && ?(@places) = 
 (answer=>'T2F_getInfo("T2F_types_info=.*$2@.*:FILTER=T2F_rooms=.*$3@.*:FILTER=T2F_properties=.*$1@.*:FILTER=T2F_places=.*$4@.*","$2@")')
 

und eine Funktion in der 99_myUtils

sub T2F_getInfo
{
  my ($filter,$info) = @_;
  my @devices = devspec2array($filter);
  if (@devices > 0 and defined($defs{$devices[0]}))
  {
    my $answer = '';

    foreach (@devices){
      if ($answer ne '')
      {
        $answer = $answer.", ";
      }
      my $device = $_;
      my @attrVals = split(/\n/,AttrVal($device, 'T2F_types_info', ''));
      foreach (@attrVals){
        my $attrVal = $_;
        $attrVal =~ s/  / /g;
        $attrVal =~ s/ => /=>/g;
        my @attrValParts = split(/=>/,$attrVal);
        if (@attrValParts[0] =~ /$info/)
        {
          my $cmd = "' ".@attrValParts[1]."'";
          $cmd =~ s/=/\//g;
          $cmd =~ s/\)\(/\/r=~s\//g;
          $cmd =~ s/\)/\/r.'/g;
          $cmd =~ s/#\(/', '')=~s\//g;
          $cmd =~ s/ #/ '.ReadingsVal('$device', '/g;
          $cmd =~ s/#/', '').'/g;
          $cmd =~ s/T2F_answer/'.T2F_answer('$device', 'T2F_types_switch').'/g;
          $answer = $answer.' '.eval($cmd);
        }
      }
    }
    return $answer;
  }
}

Die Konfiguration und Funktionsweise sind nun wie folgt: Das Gerät, dessen Status abgefragt werden sollen erhält neben den Oben bereits beschriebenen Attributen für Eigenschaft, Raum und Ort noch das Attribut T2F_types_info, welches Zeilenweise die abzufragenen Status in der folgenden Form enthält:

 abfragewert => Das ist die Antwort von Gerät T2F_answer mit den Wert #reading#(suchen1=ersetzen1)...(suchenn=ersetzenn)
 

Mit der Form #reading#(suchen1=ersetzen1)...(suchenn=ersetzenn) können die Werte von Readings des abgefragten Device zum Zeitpunkt der Abfrage ermittelt werden und im Ergebnis Ersetzungen vorgenommen werden (z.B. (on=an)(off=aus)). T2F_answer wird mit der T2F-Konfiguration (siehe oben) ersetzt. Für das Beispiel einer Heizung im Esszimmer wäre das zum Beispiel wie folgt möglich:

 attr HeizungEsszimmer T2F_places Heizung,!
 attr HeizungEsszimmer T2F_rooms Haus,Obergeschoss,Essbereich,!Esszimmer
 attr HeizungEsszimmer T2F_types_info warm,Temperatur => Die Temperatur T2F_answer beträgt #measured-temp# Grad und soll #desired-temp# Grad erreichen\
                                      modus,Betriebsart => Die Betriebsart T2F_answer ist #controlMode#(auto=Automatik)(manu=Hand)\
                                      Ventilstellung => Das Ventil T2F_answer ist #ValvePosition# Prozent geöffnet

Damit sind dann folgende Abfragen möglich:

 Wie warm ist die Heizung im Esszimmer?
 
 Wie ist die Temperatur der Heizung im Esszimmer?
 
 Wie ist die Ventilstellung der Heizung im Esszimmer?
 
 Wie warm sind die Heizungen?

Häufig verwendete RegExp

Perl Regular Expression, also ein regulärer Ausdruck der Programmiersprache Perl, ist eine Werkzeug um Zeichenketten zu beschreiben. Hier wird ein kurzer Einblick auf die im Artikel häufig genutzten RegExp zu geben.

Eine Auflistung der Syntax kann hier eingesehen werden. [1]

RegExp Beschreibung
\S* Beliebig viele (*) nicht Leerzeichen (\S). Für unbekannten und unwichtigen Wortendungen
z.b. garage\S* ist bei Garage, Garagentor oder Garagentür erfolgreich
\S+ Mehr als ein Zeichen (+) welches kein Leerzeichen ist (\S)
\S\S? Ein oder zwei Zeichen die keine Leerzeichen sind. Das "?" wirkt hier nur auf das angrenzende "\S".
Sollte für Umlaute verwendet werden, da bei manchen Eingabemethoden Probleme mit Umlauten auftreten können.
(wort )? Ein bestimmtes Wort oder nicht.
(wort1|wort2) Entweder wort1 oder Wort2
wort$ Nur wenn das Wort am ende der Zeichenkette steht.
(\S+){0,2} Keins, eins oder zwei Wörter. Kann für Artikel wie z.B. "(in der|in dem|im|auf der|...)?" eingesetzt werden

Ausgabemethoden

Siehe hierzu Anwendungsbeispiel