$TYPE {JSON}\n\n$@");
+ }
+
+ my @TRIGGER;
+
+ foreach (keys(%{$DEF})){
+ next if(defined($DEF->{$_}{setOnly}));
+
+ push(@TRIGGER, $_);
+ }
+
+ $hash->{TRIGGER} = join(",", @TRIGGER);
+ $hash->{NOTIFYDEV} = "TYPE=(ROOMMATE|GUEST)";
+
+ msgDialog_update_msgCommand($hash);
+ msgDialog_reset($hash);
+ msgDialog_updateAllowed();
+
+ return;
+}
+
+sub msgDialog_Set($@) {
+ my ($hash, @a) = @_;
+ my $TYPE = $hash->{TYPE};
+
+ return "\"set $TYPE\" needs at least one argument" if(@a < 2);
+
+ my $SELF = shift @a;
+ my $argument = shift @a;
+ my $value = join(" ", @a) if (@a);
+ my %sets = (
+ "reset" => "reset:noArg",
+ "say" => "say:textField",
+ "updateAllowed" => "updateAllowed:noArg"
+ );
+
+ Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_Set");
+
+ return(
+ "Unknown argument $argument, choose one of ".join(" ", values %sets)
+ ) unless(exists($sets{$argument}));
+
+ if($argument eq "reset"){
+ msgDialog_reset($hash);
+ }
+ elsif($argument eq "updateAllowed"){
+ msgDialog_updateAllowed();
+ }
+
+ return if(IsDisabled($SELF));
+
+ if($argument eq "say" && $value){
+ my $recipients = join(",", ($value =~ m/@(\S+)\s+/g));
+ $recipients = AttrVal($SELF, "allowed", "") unless($recipients);
+ my (undef, $say) = ($value =~ m/(^|\s)([^@].+)/g);
+
+ return unless($recipients || $say);
+
+ msgDialog_progress($hash, $recipients, $say, 1);
+ }
+
+ return;
+}
+
+sub msgDialog_Get($@) {
+ my ($hash, @a) = @_;
+ my $TYPE = $hash->{TYPE};
+
+ return "\"get $TYPE\" needs at least one argument" if(@a < 2);
+
+ my $SELF = shift @a;
+ my $argument = shift @a;
+ my $value = join(" ", @a) if (@a);
+ my %gets = (
+ "trigger" => "trigger:noArg"
+ );
+
+ Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_Get");
+
+ return(
+ "Unknown argument $argument, choose one of ".join(" ", values %gets)
+ ) unless(exists($gets{$argument}));
+
+ return if(IsDisabled($SELF));
+
+ if($argument eq "trigger"){
+ return(join("\n", split(",", InternalVal($SELF, "TRIGGER", undef))));
+ }
+
+ return;
+}
+
+sub msgDialog_Attr(@) {
+ my ($cmd, $SELF, $attribute, $value) = @_;
+ my ($hash) = $defs{$SELF};
+ my $TYPE = $hash->{TYPE};
+
+ Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_Attr");
+
+ if($attribute eq "disable"){
+ if($cmd eq "set" and $value == 1){
+ readingsSingleUpdate($hash, "state", "Initialized", 1);
+ }
+ else{
+ readingsSingleUpdate($hash, "state", "disabled", 1);
+ }
+ }
+ elsif($attribute eq "msgCommand"){
+ if($cmd eq "set"){
+ $attr{$SELF}{$attribute} = $value;
+ }
+ else{
+ delete($attr{$SELF}{$attribute});
+ }
+
+ msgDialog_update_msgCommand($hash);
+ }
+
+ return;
+}
+
+sub msgDialog_Notify($$) {
+ my ($hash, $dev_hash) = @_;
+ my $SELF = $hash->{NAME};
+ my $TYPE = $hash->{TYPE};
+ my $device = $dev_hash->{NAME};
+
+ Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_Notify");
+
+ return if(IsDisabled($SELF));
+
+ my @events = @{deviceEvents($dev_hash, 1)};
+
+ return unless(
+ @events && AttrVal($SELF, "allowed", "") =~ m/(^|,)($device|everyone)(,|$)/
+ );
+
+ foreach my $event (@events){
+ next unless($event =~ m/(fhemMsgPushReceived|fhemMsgRcvPush): (.+)/);
+
+ Log3($SELF, 4 , "$TYPE ($SELF) triggered by \"$device $event\"");
+
+ msgDialog_progress($hash, $device, $2);
+ }
+
+ return;
+}
+
+# module Fn ###################################################################
+sub msgDialog_evalSpecials($$) {
+ my ($hash, $string) = @_;
+ my $SELF = $hash->{NAME};
+ my $TYPE = $hash->{TYPE};
+
+ Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_evalSpecials");
+
+ my $msgConfig = $modules{msgConfig}{defptr}{NAME}
+ if($modules{msgConfig}{defptr});
+ $string =~ s/\$SELF/$SELF/g;
+ my $evalSpecials =
+ AttrVal($msgConfig, "$TYPE\_evalSpecials", "").
+ " ".
+ AttrVal($SELF, "evalSpecials", "")
+ ;
+
+ return($string) if($evalSpecials eq " ");
+
+ (undef, $evalSpecials) = parseParams($evalSpecials, "\\s", " ");
+
+ return($string) unless($evalSpecials);
+
+ foreach(keys(%{$evalSpecials})){
+ $evalSpecials->{$_} = eval $evalSpecials->{$_}
+ if($evalSpecials->{$_} =~ m/^{.*}$/);
+ }
+
+ my $specials = join("|", keys(%{$evalSpecials}));
+ $string =~ s/%($specials)%/$evalSpecials->{$1}/g;
+
+ return($string);
+}
+
+sub msgDialog_progress($$$;$) {
+ my ($hash, $recipients, $message, $force) = @_;
+ my $SELF = $hash->{NAME};
+ my $TYPE = $hash->{TYPE};
+ $recipients = join(",", devspec2array($msgDialog_devspec))
+ if($recipients eq "everyone");
+
+ return unless($recipients);
+
+ Log3(
+ $SELF, 5 , "$TYPE ($SELF)"
+ . "\n entering msgDialog_progress"
+ . "\n recipients: $recipients"
+ . "\n message: $message"
+ . "\n force: ".($force ? $force : 0)
+ );
+
+ my @oldHistory;
+ @oldHistory = split("\\|", ReadingsVal($SELF, "$recipients\_history", ""))
+ unless($force);
+ push(@oldHistory, split("\\|", $message));
+ my (@history);
+ my $dialog =$hash->{DEF};
+ $dialog = msgDialog_evalSpecials($hash, $dialog);
+ $dialog =~ s/\$recipient/$recipients/g;
+ $dialog = eval{JSON->new->decode($dialog)};
+
+ foreach (@oldHistory){
+ $message = $_;
+
+ if(defined($dialog->{$message})){
+ $dialog = $dialog->{$message};
+ push(@history, $message);
+ }
+ else{
+ foreach (keys(%{$dialog})){
+ next unless(
+ $dialog->{$_} =~ m/HASH/ &&
+ defined($dialog->{$_}{match}) &&
+ $message =~ m/^$dialog->{$_}{match}$/
+ );
+
+ $dialog = $dialog->{$_};
+ push(@history, $_);
+
+ last;
+ }
+ }
+ }
+
+ return if(@history != @oldHistory || !$force && $dialog->{setOnly});
+
+ $dialog = eval{JSON->new->encode($dialog)};
+ $dialog =~ s/\$message/$message/g;
+ $dialog = eval{JSON->new->decode($dialog)};
+ my $history = "";
+
+ foreach (keys(%{$dialog})){
+ if($_ !~ m/(setOnly|match|commands|message)/){
+ $history = join("|", @history);
+
+ last;
+ }
+ }
+
+ readingsBeginUpdate($hash);
+ readingsBulkUpdate($hash, $_."_history", $history)
+ foreach (split(",", $recipients));
+ readingsBulkUpdate($hash, "state", "$recipients: $message");
+ readingsEndUpdate($hash, 1);
+
+ if($dialog->{commands}){
+ my @commands =
+ $dialog->{commands} =~ m/ARRAY/ ?
+ @{$dialog->{commands}}
+ : $dialog->{commands}
+ ;
+
+ foreach (@commands){
+ $_ =~ s/;/;;/g;
+ my $ret = AnalyzeCommandChain(undef, $_);
+
+ Log3($SELF, 4, "$TYPE ($SELF) - return from command \"$_\": $ret")
+ if($ret);
+ }
+ }
+
+ if($dialog->{message}){
+ my @message =
+ $dialog->{message} =~ m/ARRAY/ ?
+ @{$dialog->{message}}
+ : $dialog->{message}
+ ;
+
+ foreach (@message){
+ if($_ =~ m/^{.*}$/s){
+ $_ =~ s/;/;;/g;
+ $_ = AnalyzePerlCommand(undef, $_);
+ }
+ }
+
+ my $message = join("\n", @message);
+ my $msgCommand = '"'.InternalVal($SELF, "MSGCOMMAND", "").'"';
+ $msgCommand = eval($msgCommand);
+
+ fhem($msgCommand);
+ }
+
+ return;
+}
+
+sub msgDialog_reset($) {
+ my ($hash) = @_;
+ my $SELF = $hash->{NAME};
+ my $TYPE = $hash->{TYPE};
+
+ Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_reset");
+
+ delete($hash->{READINGS});
+
+ readingsSingleUpdate($hash, "state", "Initialized", 1)
+ unless(IsDisabled($SELF));
+
+ return;
+}
+
+sub msgDialog_updateAllowed {
+ Log(5, "msgDialog - entering msgDialog_updateAllowed");
+
+ my $allowed = join(",", sort(devspec2array($msgDialog_devspec)));
+
+ $modules{msgDialog}{AttrList} =~
+ s/allowed:multiple-strict,\S*/allowed:multiple-strict,everyone,$allowed/;
+}
+
+sub msgDialog_update_msgCommand($) {
+ my ($hash) = @_;
+ my $SELF = $hash->{NAME};
+ my $TYPE = $hash->{TYPE};
+ my $msgConfig = $modules{msgConfig}{defptr}{NAME};
+
+ Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_update_msgCommand");
+
+ $hash->{MSGCOMMAND} =
+ AttrVal($SELF, "msgCommand",
+ AttrVal($msgConfig, "$TYPE\_msgCommand",
+ 'msg push \@$recipients $message'
+ )
+ )
+ ;
+
+ return;
+}
+
+1;
+
+# commandref ##################################################################
+=pod
+=item helper
+=item summary dialogs for instant messaging
+=item summary_DE Dialoge für Sofortnachrichten
+
+=begin html
+
+
+msgDialog
+
+ With msgDialog you can define dialogs for instant messages via TelegramBot, Jabber and yowsup (WhatsApp).
+ The communication uses the msg command. Therefore, a device of type msgConfig must be defined first.
+ For each dialog you can define which person is authorized to do so. Devices of the type ROOMMATE or GUEST with a defined msgContactPush attribute are required for this. Make sure that the reading fhemMsgRcvPush generates an event.
+
+ Prerequisites:
+
+ The Perl module "JSON" is required.
+ Under Debian (based) system, this can be installed using
+ "apt-get install libjson-perl"
.
+
+
+
+
+ Define
+
+ define <name> msgDialog <JSON>
+ Because of the complexity, it is easiest to define an empty dialog first.
+ define <name> msgDialog {}
+ Then edit the DEF in the detail view.
+
+{
+ "<TRIGGER>": {
+ "match": "<regex>",
+ "setOnly": (true|false),
+ "commands": "(fhem command|{perl code})",
+ "message": [
+ "{perl code}",
+ "text"
+ ],
+ "<NEXT TRIGGER 1>": {
+ ...
+ },
+ "<NEXT TRIGGER 2>": {
+ ...
+ }
+ }
+}
+
+
+ TRIGGER
+ Can be any text. The device checks whether the incoming message equals it. If so, the dialogue will be continued at this point.
+
+
+
+ match
+ If you do not want to allow only one message, you can specify a regex. The regex must apply to the whole incoming message.
+
+
+
+ setOnly
+ Can be optionally set to true or false. In both cases, the TRIGGER will
+ not be returned at "get <name> trigger".
+ If setOnly is set to true, the dialog at this point cannot be triggered
+ by incoming messages, but only by using "get <name> say
+ TRIGGER".
+ This can be used to initiate a dialog from FHEM.
+
+
+
+ commands
+ Can contain a single or multiple commands:
+
+"commands": "single command"
+
+"commands": [
+"command 1",
+"command 2",
+"{perl command}"
+]
+
+
+
+ message
+ Can contain a single or multiple text that is connected by a line break:
+
+"message": "text"
+
+"message": [
+"text 1",
+"text 2",
+"{return from perl command}"
+]
+
+
+ For multi-level dialogs, this structure is specified nested.
+
+ Variables and placeholders defined under the attribute evalSpecials are
+ evaluated.
+ Variables:
+
+ $SELF
+ name of the msgDialog
+
+
+
+ $message
+ received message
+
+
+
+ $recipient
+ Name of the dialog partner
+
+
+
+
+
+ Set
+
+ -
+
reset
+ Resets the dialog for all users.
+
+
+ -
+
+ say [@<recipient1>[,<recipient2>,...]]
+ <TRIGGER>[|<NEXT TRIGGER>|...]
+
+ The dialog is continued for all specified recipients at the specified
+ position.
+ If no recipients are specified, the dialog is continued for all
+ recipients specified under the allowed attribute.
+
+
+ -
+
updateAllowed
+ Updates the selection for the allowed attribute.
+
+
+
+
+
+ Get
+
+ -
+
trigger
+ Lists all TRIGGERs of the first level where setOnly is not specified.
+
+
+
+
+
+ Attribute
+
+ -
+
allowed
+ List with all RESIDENTS and ROOMMATE that are authorized for this dialog.
+
+
+ -
+
disable 1
+ Dialog is deactivated.
+
+
+ -
+
+
disabledForIntervals HH:MM-HH:MM HH:MM-HH-MM ...
+
+
+
+ -
+
evalSpecials key1=value1 key2=value2 ...
+ Space Separate list of name=value pairs.
+ Value may contain spaces if included in "" or {}.
+ Value is evaluated as a perl expression if it is included in {}.
+ In the DEF, %Name% strings are replaced by the corresponding value.
+ This attribute is available as "msgDialog_evalSpecials" in the msgConfig
+ device.
+ If the same name was defined in the msgConfig and msgDialog, the value
+ from msgDialog is used.
+
+
+ -
+
msgCommand <command>
+ Command used to send a message.
+ The default is
+ "msg push \@$recipients $message"
.
+ This attribute is available as "msgDialog_msgCommand" in the msgConfig device.
+
+
+
+
+
+ Reading
+
+ -
+
$recipient_history
+ | separated list of TRIGGERS to save the current state of the dialog.
+ A readings is created for each dialog partner. When the dialog is
+ finished, the reading will be cleared.
+
+
+
+
+
+ Notes for use with TelegramBot:
+
+ It may be necessary to set the attribute "utf8specials" to 1 in the
+ TelegramBot, for messages with special characters to be sent.
+
+ The msg command supports the TelegramBot_MTYPE. The default is message. The
+ queryInline value can be used to create an inline keyboard.
+
+
+
+
+ Notes for use with Jabber:
+
+ The msg command supports the TelegramBot_MTYPE. The default is empty. The
+ value otr can be used to send an OTR message.
+
+
+
+
+ Notes for use with yowsub (WhatsApp):
+
+ No experiences so far.
+
+
+
+
+ Examples:
+
+
+
+ The following example codes can be imported by "Raw defnition".
+
+
+
+
+ All examples are designed for communication via the TelegramBot. When using
+ Jabber or yowsup, they may need to be adjusted.
+ It is assumed that the msgConfig device contains the evalSpecials "me" with
+ a name which is used to call the bot.
+
+ Meta dialog for listing all authorized dialogs:
+
+defmod meta_Dialog msgDialog {\
+ "%me%": {\
+ "match": "\/?(start|%me%)",\
+ "commands": "deletereading TYPE=msgDialog $recipient_history",\
+ "message": [\
+ "{return('(' . join(') (', sort(split('\n', fhem('get TYPE=msgDialog:FILTER=NAME!=$SELF:FILTER=allowed=.*($recipient|everyone).* trigger'))), 'abbrechen') . ') ')}",\
+ "Ich kann folgendes für dich tun:"\
+ ]\
+ },\
+ "zurück": {\
+ "commands": "set $recipient_history=.+|.+ say @$recipient {(ReadingsVal($DEV, '$recipient_history', '') =~ m/(.+)\\|.+$/;; return $2 ? $2 : $1;;)}"\
+ },\
+ "abbrechen": {\
+ "match": "\/?abbrechen",\
+ "commands": "deletereading TYPE=msgDialog $recipient_history",\
+ "message": [\
+ "TelegramBot_MTYPE=queryInline (%me%) ",\
+ "Dialog abgebrochen."\
+ ]\
+ },\
+ "beenden": {\
+ "match": "\/?beenden",\
+ "commands": "deletereading TYPE=msgDialog $recipient_history",\
+ "message": [\
+ "TelegramBot_MTYPE=queryInline (%me%) ",\
+ "Dialog beendet."\
+ ]\
+ }\
+}
+attr meta_Dialog allowed everyone
+
+
+ Request of current fuel prices
+
+defmod Tankstelle_Dialog msgDialog {\
+ "Tankstelle": {\
+ "message": [\
+ "TelegramBot_MTYPE=queryInline (%me%) ",\
+ "Die Krafstoffpreise der betragen aktuell folgende Werte:",\
+ "",\
+ "AIVA",\
+ "",\
+ "[%AIVA%:Diesel] €/l Diesel",\
+ "[%AIVA%:Super] €/l Super",\
+ "[%AIVA%:E10] €/l E10",\
+ "[%AIVA%:Autogas] €/l Autogas"\
+ ]\
+ }\
+}
+attr Tankstelle_Dialog evalSpecials AIVA=AIVA_petrolStation
+
+
+ Programming of the washing machine
+
+defmod Waschmaschine_Dialog msgDialog { "Waschmaschine": {\
+ "message": [\
+ "{return('(Zeitprogramm stoppen) ') if(ReadingsVal('%controlUnit%', 'controlMode', '') eq 'auto')}",\
+ "{return('(programmieren) ') if(ReadingsVal('%actor%', 'state', '') ne 'on')}",\
+ "{return('(einschalten) ') if(ReadingsVal('%actor%', 'state', '') ne 'on')}",\
+ "(Verlaufsdiagramm) ",\
+ "(abbrechen) ",\
+ "{return('Waschmaschine: ' . (ReadingsVal('%actor%', 'state', '') eq 'on' ? 'eingeschaltet' : 'ausgeschaltet'))}",\
+ "{return('Modus: ' . (ReadingsVal('%controlUnit%', 'controlMode', '') eq 'auto' ? 'Automatik' : 'Manuell (' . ReadingsVal('%controlUnit%', 'time', '') . ')'))}"\
+ ],\
+ "Zeitprogramm stoppen": {\
+ "commands": "set %controlUnit% controlMode manual",\
+ "message": [\
+ "TelegramBot_MTYPE=queryInline (%me%) ",\
+ "Das Zeitprogramm wurde gestoppt."\
+ ]\
+ },\
+ "programmieren": {\
+ "message": [\
+ "(bestätigen|zurück|abbrechen) ",\
+ "( 00:00 | 00:15 | 00:30 | 00:45 ) ",\
+ "( 01:00 | 01:15 | 01:30 | 01:45 ) ",\
+ "( 02:00 | 02:15 | 02:30 | 02:45 ) ",\
+ "( 03:00 | 03:15 | 03:30 | 03:45 ) ",\
+ "( 04:00 | 04:15 | 04:30 | 04:45 ) ",\
+ "( 05:00 | 05:15 | 05:30 | 05:45 ) ",\
+ "( 06:00 | 06:15 | 06:30 | 06:45 ) ",\
+ "( 07:00 | 07:15 | 07:30 | 07:45 ) ",\
+ "( 08:00 | 08:15 | 08:30 | 08:45 ) ",\
+ "( 09:00 | 09:15 | 09:30 | 09:45 ) ",\
+ "( 10:00 | 10:15 | 10:30 | 10:45 ) ",\
+ "( 11:00 | 11:15 | 11:30 | 11:45 ) ",\
+ "( 12:00 | 12:15 | 12:30 | 12:45 ) ",\
+ "( 13:00 | 13:15 | 13:30 | 13:45 ) ",\
+ "( 14:00 | 14:15 | 14:30 | 14:45 ) ",\
+ "( 15:00 | 15:15 | 15:30 | 15:45 ) ",\
+ "( 16:00 | 16:15 | 16:30 | 16:45 ) ",\
+ "( 17:00 | 17:15 | 17:30 | 17:45 ) ",\
+ "( 18:00 | 18:15 | 18:30 | 18:45 ) ",\
+ "( 19:00 | 19:15 | 19:30 | 19:45 ) ",\
+ "( 20:00 | 20:15 | 20:30 | 20:45 ) ",\
+ "( 21:00 | 21:15 | 21:30 | 21:45 ) ",\
+ "( 22:00 | 22:15 | 22:30 | 22:45 ) ",\
+ "( 23:00 | 23:15 | 23:30 | 23:45 ) ",\
+ "Wann soll die Wäsche fertig sein?",\
+ "Bitte Uhrzeit in HH:MM angeben.",\
+ "Aktuell ist [%controlUnit%:time] Uhr eingestellt."\
+ ],\
+ "Uhrzeit": {\
+ "match": " ?([0-1][0-9]|2[0-3]):[0-5][0-9] ?",\
+ "commands": [\
+ "set %controlUnit% time $message",\
+ "set $SELF say @$recipient Waschmaschine|programmieren|bestätigen"\
+ ]\
+ },\
+ "bestätigen": {\
+ "commands": "set %controlUnit% controlMode auto",\
+ "message": [\
+ "TelegramBot_MTYPE=queryInline (%me%) ",\
+ "Das Zeitprogramm wurde eingestellt.",\
+ "Die Wäsche wird voraussichtlich um [%controlUnit%:time] Uhr fertig sein.",\
+ "Bitte die Waschmaschine vorbereiten."\
+ ]\
+ }\
+ },\
+ "einschalten": {\
+ "commands": [\
+ "set %controlUnit% controlMode manual",\
+ "set %actor% on"\
+ ]\
+ },\
+ "Verlaufsdiagramm": {\
+ "commands": "set %TelegramBot% cmdSend {plotAsPng('%plot%')}",\
+ "message": "TelegramBot_MTYPE=queryInline (%me%) $message"\
+ }\
+ },\
+ "auto": {\
+ "setOnly": true,\
+ "commands": [\
+ "set %actor% on",\
+ "set %controlUnit% controlMode manual"\
+ ],\
+ "message": [\
+ "TelegramBot_MTYPE=queryInline (%me%) ",\
+ "Die Wachmaschine wurde automatisch eingeschaltet."\
+ ]\
+ },\
+ "manual": {\
+ "setOnly": true,\
+ "message": [\
+ "TelegramBot_MTYPE=queryInline (%me%) ",\
+ "Die Wachmaschine wurde manuell eingeschaltet."\
+ ]\
+ },\
+ "done": {\
+ "setOnly": true,\
+ "commands": "set %actor% off",\
+ "message": [\
+ "TelegramBot_MTYPE=queryInline (%me%) ",\
+ "Die Wachmaschine ist fertig."\
+ ]\
+ }\
+}
+attr Waschmaschine_Dialog evalSpecials actor=HM_2C10D8_Sw\
+controlUnit=Waschkeller_washer_controlUnit\
+plot=Waschkeller_washer_SVG
+
+
+
+
+
+=end html
+
+=begin html_DE
+
+
+msgDialog
+
+ Mit msgDialog können Dialoge für Sofortnachrichten über
+ TelegramBot, Jabber und yowsup (WhatsApp) definiert werden.
+ Die Kommunikation erfolgt über den msg Befehl. Daher muss ein Gerät
+ vom Typ msgConfig zuerst definiert werden.
+ Für jeden Dialog kann festgelegt werden welche Person dazu berechtigt
+ ist. Dazu sind Geräte vom Typ ROOMMATE oder GUEST mit definiertem
+ msgContactPush Attribut erforderlich. Es ist darauf zu achten, dass das
+ Reading fhemMsgRcvPush ein Event erzeugt.
+
+ Vorraussetzungen:
+
+ Das Perl-Modul "JSON" wird benötigt.
+ Unter Debian (basierten) System, kann dies mittels
+ "apt-get install libjson-perl"
installiert werden.
+
+
+
+
+ Define
+
+ define <name> msgDialog <JSON>
+ Aufgrunder komplexität ist es am einfachsten erst einen leeren Dialog
+ zu definieren.
+ define <name> msgDialog {}
+ Anschließend die DEF dann in der Detail-Ansicht bearbeiten.
+
+{
+ "<TRIGGER>": {
+ "match": "<regex>",
+ "setOnly": (true|false),
+ "commands": "(fhem command|{perl code})",
+ "message": [
+ "{perl code}",
+ "text"
+ ],
+ "<NEXT TRIGGER 1>": {
+ ...
+ },
+ "<NEXT TRIGGER 2>": {
+ ...
+ }
+ }
+}
+
+
+ TRIGGER
+ Kann ein beliebiger Text sein. Es wird geprüft ob die eingehende
+ Nachricht damit übereinstimmt. Falls ja, wird der Dialog an dieser
+ Stelle fortgesetzt.
+
+
+
+ match
+ Wenn nicht nur genau eine Nachricht zugelassen werden soll, kann noch
+ eine regex angegeben werden. Die regex muss auf die gesamte eingehnde
+ Nachricht zutreffen.
+
+
+
+ setOnly
+ Kann optional auf true oder false gestellt werden. In beiden
+ fällen wird der TRIGGER dann nicht bei "get <name> trigger"
+ zurück gegeben.
+ Wenn setOnly auf true gestellt wird kann der Dialog an dieser Stelle
+ nicht durch eingehnde Nachrichten ausgelöst werden, sondern nur
+ über "get <name> say TRIGGER".
+ Dies kann dazu genutzt werden um einen Dialog von FHEM zu aus zu
+ initieren.
+
+
+
+ commands
+ Kann einen einzelnen oder mehrere Befehle enthalten:
+
+"commands": "single command"
+
+"commands": [
+"command 1",
+"command 2",
+"{perl command}"
+]
+
+
+
+ message
+ Kann einen einzelnen oder mehrere Textte enthalten die mit einen
+ Zeilenumbruch verbunden werden:
+
+"message": "text"
+
+"message": [
+"text 1",
+"text 2",
+"{return from perl command}"
+]
+
+
+ Bei mehrstufigen Dialogen wird diese Struktur ineinander verschachtelt
+ angegeben.
+
+ Es werden Variablen und unter dem Attribut evalSpecials definierte
+ Platzhalter ausgewertet.
+ Variablen:
+
+ $SELF
+ Eigenname des msgDialog
+
+
+
+ $message
+ eingegangene Nachricht
+
+
+
+ $recipient
+ Name des Dialogpartners
+
+
+
+
+
+ Set
+
+ -
+
reset
+ Setzt den Dialog für alle Benutzer zurück.
+
+
+ -
+
+ say [@<recipient1>[,<recipient2>,...]]
+ <TRIGGER>[|<NEXT TRIGGER>|...]
+
+ Der Dialog wird für alle angegeben Empänger an der angegeben
+ Stelle fortgeführt.
+ Sind keine Empfänger angegeben wird der Dialog für alle unter
+ dem Attribut allowed angegebenen Empfänger fortgeführt.
+
+
+ -
+
updateAllowed
+ Aktualisiert die Auswahl für das Attribut allowed.
+
+
+
+
+
+ Get
+
+ -
+
trigger
+ Listet alle TRIGGER der ersten Ebene auf bei denen nicht setOnly
+ angegeben ist.
+
+
+
+
+
+ Attribute
+
+ -
+
allowed
+ Liste mit allen RESIDENTS und ROOMMATE die für diesen Dialog
+ berechtigt sind.
+
+
+ -
+
disable 1
+ Dialog ist deaktiviert.
+
+
+ -
+
+
disabledForIntervals HH:MM-HH:MM HH:MM-HH-MM ...
+
+
+
+ -
+
evalSpecials key1=value1 key2=value2 ...
+ Leerzeichen getrennte Liste von Name=Wert Paaren.
+ Wert kann Leerzeichen enthalten, falls es in "" oder {} eingeschlossen
+ ist.
+ Wert wird als
+ perl-Ausdruck ausgewertet, falls es in {} eingeschlossen ist.
+ In der DEF werden %Name% Zeichenketten durch den zugehörigen Wert
+ ersetzt.
+ Dieses Attribut ist als "msgDialog_evalSpecials" im msgConfig Gerät
+ vorhanden.
+ Wenn der selbe Name im msgConfig und msgDialog definiert wurde, wird der
+ Wert aus msgDialog verwendet.
+
+
+ -
+
msgCommand <command>
+ Befehl der zum Versenden einer Nachricht verwendet wird.
+ Die Vorgabe ist
+ "msg push \@$recipients $message"
+ Dieses Attribut ist als "msgDialog_msgCommand" im msgConfig Gerät
+ vorhanden.
+
+
+
+
+
+ Reading
+
+ -
+
$recipient_history
+ Durch | getrennte Liste von TRIGGERN um den aktuellen Zustand des Dialogs
+ zu sichern.
+ Für jeden Dialogpartner wird ein Readings angelegt. Wenn der Dialog
+ beendet ist wird das Reading zurückgesetzt.
+
+
+
+
+
+ Hinweise zur Benutzung mit Telegram:
+
+ Es kann notwendig sein, dass im TelegramBot das Attribut "utf8specials" auf
+ 1 gesetzt wird, damit Nachrichten mit Umlauten gesendert werden.
+
+ Bei dem msg Befehl kann der TelegramBot_MTYPE angegeben werden. Die Vorgabe
+ ist message. Durch den Wert queryInline lässt sich ein inline Keyboard
+ erzeugen.
+
+
+
+
+ Hinweise zur Benutzung mit Jabber:
+
+ Bei dem msg Befehl kann der Jabber_MTYPE angegeben werden. Die Vorgabe ist
+ leer. Durch den Wert otr lässt sich eine OTR Nachricht versenden.
+
+
+
+
+ Hinweise zur Benutzung mit yowsub (WhatsApp):
+
+ Bisher noch keine Erfahungen.
+
+
+
+
+ Beispiele:
+
+
+
+ Die folgenden beispiel Codes können nur per "Raw defnition"
+ importiert werden.
+
+
+
+
+ Alle Beispiele sind für die Kommunikation über den TelegramBot
+ ausgelegt. Bei der Verwendung von Jabber oder yowsup müssen diese
+ gegebenenfalls angepasst werden.
+ Es wird davon ausgegangen, dass im msgConfig Gerät das evalSpecials
+ "me" mit einem Namen gepflegt ist, über welchen der Bot angesprochen
+ wird.
+
+ Meta Dialog zur auflistung aller Berechtigten Dialoge:
+
+defmod meta_Dialog msgDialog {\
+ "%me%": {\
+ "match": "\/?(start|%me%)",\
+ "commands": "deletereading TYPE=msgDialog $recipient_history",\
+ "message": [\
+ "{return('(' . join(') (', sort(split('\n', fhem('get TYPE=msgDialog:FILTER=NAME!=$SELF:FILTER=allowed=.*($recipient|everyone).* trigger'))), 'abbrechen') . ') ')}",\
+ "Ich kann folgendes für dich tun:"\
+ ]\
+ },\
+ "zurück": {\
+ "commands": "set $recipient_history=.+|.+ say @$recipient {(ReadingsVal($DEV, '$recipient_history', '') =~ m/(.+)\\|.+$/;; return $2 ? $2 : $1;;)}"\
+ },\
+ "abbrechen": {\
+ "match": "\/?abbrechen",\
+ "commands": "deletereading TYPE=msgDialog $recipient_history",\
+ "message": [\
+ "TelegramBot_MTYPE=queryInline (%me%) ",\
+ "Dialog abgebrochen."\
+ ]\
+ },\
+ "beenden": {\
+ "match": "\/?beenden",\
+ "commands": "deletereading TYPE=msgDialog $recipient_history",\
+ "message": [\
+ "TelegramBot_MTYPE=queryInline (%me%) ",\
+ "Dialog beendet."\
+ ]\
+ }\
+}
+attr meta_Dialog allowed everyone
+
+
+ Abfrage der aktuellen Krafstoffpreise
+
+defmod Tankstelle_Dialog msgDialog {\
+ "Tankstelle": {\
+ "message": [\
+ "TelegramBot_MTYPE=queryInline (%me%) ",\
+ "Die Krafstoffpreise der betragen aktuell folgende Werte:",\
+ "",\
+ "AIVA",\
+ "",\
+ "[%AIVA%:Diesel] €/l Diesel",\
+ "[%AIVA%:Super] €/l Super",\
+ "[%AIVA%:E10] €/l E10",\
+ "[%AIVA%:Autogas] €/l Autogas"\
+ ]\
+ }\
+}
+attr Tankstelle_Dialog evalSpecials AIVA=AIVA_petrolStation
+
+
+ Programmierung der Waschmaschine
+
+defmod Waschmaschine_Dialog msgDialog { "Waschmaschine": {\
+ "message": [\
+ "{return('(Zeitprogramm stoppen) ') if(ReadingsVal('%controlUnit%', 'controlMode', '') eq 'auto')}",\
+ "{return('(programmieren) ') if(ReadingsVal('%actor%', 'state', '') ne 'on')}",\
+ "{return('(einschalten) ') if(ReadingsVal('%actor%', 'state', '') ne 'on')}",\
+ "(Verlaufsdiagramm) ",\
+ "(abbrechen) ",\
+ "{return('Waschmaschine: ' . (ReadingsVal('%actor%', 'state', '') eq 'on' ? 'eingeschaltet' : 'ausgeschaltet'))}",\
+ "{return('Modus: ' . (ReadingsVal('%controlUnit%', 'controlMode', '') eq 'auto' ? 'Automatik' : 'Manuell (' . ReadingsVal('%controlUnit%', 'time', '') . ')'))}"\
+ ],\
+ "Zeitprogramm stoppen": {\
+ "commands": "set %controlUnit% controlMode manual",\
+ "message": [\
+ "TelegramBot_MTYPE=queryInline (%me%) ",\
+ "Das Zeitprogramm wurde gestoppt."\
+ ]\
+ },\
+ "programmieren": {\
+ "message": [\
+ "(bestätigen|zurück|abbrechen) ",\
+ "( 00:00 | 00:15 | 00:30 | 00:45 ) ",\
+ "( 01:00 | 01:15 | 01:30 | 01:45 ) ",\
+ "( 02:00 | 02:15 | 02:30 | 02:45 ) ",\
+ "( 03:00 | 03:15 | 03:30 | 03:45 ) ",\
+ "( 04:00 | 04:15 | 04:30 | 04:45 ) ",\
+ "( 05:00 | 05:15 | 05:30 | 05:45 ) ",\
+ "( 06:00 | 06:15 | 06:30 | 06:45 ) ",\
+ "( 07:00 | 07:15 | 07:30 | 07:45 ) ",\
+ "( 08:00 | 08:15 | 08:30 | 08:45 ) ",\
+ "( 09:00 | 09:15 | 09:30 | 09:45 ) ",\
+ "( 10:00 | 10:15 | 10:30 | 10:45 ) ",\
+ "( 11:00 | 11:15 | 11:30 | 11:45 ) ",\
+ "( 12:00 | 12:15 | 12:30 | 12:45 ) ",\
+ "( 13:00 | 13:15 | 13:30 | 13:45 ) ",\
+ "( 14:00 | 14:15 | 14:30 | 14:45 ) ",\
+ "( 15:00 | 15:15 | 15:30 | 15:45 ) ",\
+ "( 16:00 | 16:15 | 16:30 | 16:45 ) ",\
+ "( 17:00 | 17:15 | 17:30 | 17:45 ) ",\
+ "( 18:00 | 18:15 | 18:30 | 18:45 ) ",\
+ "( 19:00 | 19:15 | 19:30 | 19:45 ) ",\
+ "( 20:00 | 20:15 | 20:30 | 20:45 ) ",\
+ "( 21:00 | 21:15 | 21:30 | 21:45 ) ",\
+ "( 22:00 | 22:15 | 22:30 | 22:45 ) ",\
+ "( 23:00 | 23:15 | 23:30 | 23:45 ) ",\
+ "Wann soll die Wäsche fertig sein?",\
+ "Bitte Uhrzeit in HH:MM angeben.",\
+ "Aktuell ist [%controlUnit%:time] Uhr eingestellt."\
+ ],\
+ "Uhrzeit": {\
+ "match": " ?([0-1][0-9]|2[0-3]):[0-5][0-9] ?",\
+ "commands": [\
+ "set %controlUnit% time $message",\
+ "set $SELF say @$recipient Waschmaschine|programmieren|bestätigen"\
+ ]\
+ },\
+ "bestätigen": {\
+ "commands": "set %controlUnit% controlMode auto",\
+ "message": [\
+ "TelegramBot_MTYPE=queryInline (%me%) ",\
+ "Das Zeitprogramm wurde eingestellt.",\
+ "Die Wäsche wird voraussichtlich um [%controlUnit%:time] Uhr fertig sein.",\
+ "Bitte die Waschmaschine vorbereiten."\
+ ]\
+ }\
+ },\
+ "einschalten": {\
+ "commands": [\
+ "set %controlUnit% controlMode manual",\
+ "set %actor% on"\
+ ]\
+ },\
+ "Verlaufsdiagramm": {\
+ "commands": "set %TelegramBot% cmdSend {plotAsPng('%plot%')}",\
+ "message": "TelegramBot_MTYPE=queryInline (%me%) $message"\
+ }\
+ },\
+ "auto": {\
+ "setOnly": true,\
+ "commands": [\
+ "set %actor% on",\
+ "set %controlUnit% controlMode manual"\
+ ],\
+ "message": [\
+ "TelegramBot_MTYPE=queryInline (%me%) ",\
+ "Die Wachmaschine wurde automatisch eingeschaltet."\
+ ]\
+ },\
+ "manual": {\
+ "setOnly": true,\
+ "message": [\
+ "TelegramBot_MTYPE=queryInline (%me%) ",\
+ "Die Wachmaschine wurde manuell eingeschaltet."\
+ ]\
+ },\
+ "done": {\
+ "setOnly": true,\
+ "commands": "set %actor% off",\
+ "message": [\
+ "TelegramBot_MTYPE=queryInline (%me%) ",\
+ "Die Wachmaschine ist fertig."\
+ ]\
+ }\
+}
+attr Waschmaschine_Dialog evalSpecials actor=HM_2C10D8_Sw\
+controlUnit=Waschkeller_washer_controlUnit\
+plot=Waschkeller_washer_SVG
+
+
+
+
+
+=end html_DE
+=cut
diff --git a/fhem/MAINTAINER.txt b/fhem/MAINTAINER.txt
index 5641b0633..57a12dcd3 100644
--- a/fhem/MAINTAINER.txt
+++ b/fhem/MAINTAINER.txt
@@ -328,6 +328,7 @@ FHEM/74_THINKINGCLEANER.pm loredo Unterstuetzende Dienste
FHEM/74_Unifi.pm rapster Automatisierung
FHEM/75_MSG.pm loredo Automatisierung
FHEM/75_msgConfig.pm loredo Automatisierung
+FHEM/76_msgDialog.pm igami Frontends/Sprachsteuerung
FHEM/76_MSGFile.pm gandy Automatisierung
FHEM/76_MSGMail.pm gandy Automatisierung
FHEM/76_SMAInverter.pm DS_Starter Sonstige Systeme