msgDialog {JSON}\n\n$@");
}
my @TRIGGER;
for (keys %{$content2}){
next if ref $content2->{$_} ne 'HASH';
next if defined $content2->{$_}->{setOnly}; # && $content2->{$_}->{setOnly} eq 'true';
push @TRIGGER, $_;
}
$hash->{TRIGGER} = join q{,}, @TRIGGER;
msgDialog_update_msgCommand($hash);
msgDialog_reset($hash);
msgDialog_updateAllowed();
return;
}
sub Set {
my ($hash,$SELF,$argument,@values) = @_;
my $TYPE = $hash->{TYPE};
return qq("set $TYPE" needs at least one argument) if !$argument;
my $value = join q{ }, @values;
my %sets = (
reset => 'reset:noArg',
say => 'say:textField',
updateAllowed => 'updateAllowed:noArg',
update => 'update:allowed,configFile'
);
Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_Set");
return
"Unknown argument $argument, choose one of ".join q{ }, values %sets
if !defined $sets{$argument};
if ( $argument eq 'reset' ){
return msgDialog_reset($hash);
}
if( $argument eq 'update'){
return msgDialog_updateAllowed() if $values[0] eq 'allowed';
return firstInit($hash) if $values[0] eq 'configFile';
}
if( $argument eq 'updateAllowed'){
return msgDialog_updateAllowed();
}
return if IsDisabled($SELF);
if ( $argument eq 'say' && $value ){
my $recipients = join q{,}, ($value =~ m/@(\S+)\s+/g);
$recipients = AttrVal($SELF, 'allowed', '') if !$recipients;
my (undef, $say) = ($value =~ m/(^|\s)([^@].+)/g);
return if !$recipients && !$say;
msgDialog_progress($hash, $recipients, $say, 1);
}
return;
}
sub Get {
my ($hash,$SELF,$argument,@values) = @_;
my $TYPE = $hash->{TYPE};
return "\"get $TYPE\" needs at least one argument" if !$argument;
my $value = join q{ }, @values;
my %gets = (
trigger => 'trigger:noArg'
);
Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_Get");
return "Unknown argument $argument, choose one of ".join q{ }, values %gets
if !exists $gets{$argument};
return if IsDisabled($SELF);
if($argument eq 'trigger'){
return join "\n", split q{,}, InternalVal($SELF, 'TRIGGER', undef); #we need the soft variant
}
return;
}
sub 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){
setDisableNotifyFn($hash, 1);
return readingsSingleUpdate($hash, 'state', 'Initialized', 1); #Beta-User: really?!?
}
readingsSingleUpdate($hash, 'state', 'disabled', 1);
return firstInit($hash) if $init_done;
return;
}
if ( $attribute eq 'msgCommand'){
if($cmd eq 'set'){
$attr{$SELF}{$attribute} = $value;
}
else{
delete $attr{$SELF}{$attribute};
}
return msgDialog_update_msgCommand($hash);
}
if ( $attribute eq 'configFile' ) {
if ($cmd ne 'set') {
delete $hash->{CONFIGFILE};
delete $hash->{DIALOG};
$value = undef;
delete $attr{$SELF}{$attribute};
}
$attr{$SELF}{$attribute} = $value;
return firstInit($hash);
}
return;
}
sub Notify {
my $hash = shift // return;
my $dev_hash = shift // return;
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 if !@events || AttrVal($SELF, 'allowed', '') !~ m{\b(?:$device|everyone)(?:\b|\z)}xms;
for my $event (@events){
next if $event !~ m{(?:fhemMsgPushReceived|fhemMsgRcvPush):.(.+)}xms;
Log3($SELF, 4 , "$TYPE ($SELF) triggered by \"$device $event\"");
msgDialog_progress($hash, $device, $1);
}
return;
}
# module Fn ###################################################################
sub msgDialog_evalSpecials {
my $hash = shift // return;
my $string = shift // return;
my $SELF = $hash->{NAME};
my $TYPE = $hash->{TYPE};
Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_evalSpecials");
my $msgConfig;
$msgConfig = $modules{msgConfig}{defptr}{NAME}
if $modules{msgConfig}{defptr};
$string =~ s/\$SELF/$SELF/g;
my $evalSpecials = AttrVal($msgConfig, 'msgDialog_evalSpecials', '');
$evalSpecials .= ' ';
$evalSpecials .= AttrVal($SELF, 'evalSpecials', '');
return $string if $evalSpecials eq ' ';
(undef, $evalSpecials) = parseParams($evalSpecials, "\\s", " ");
return $string if !$evalSpecials;
for ( keys %{$evalSpecials} ) {
$evalSpecials->{$_} = AnalyzePerlCommand($hash, $evalSpecials->{$_})
if($evalSpecials->{$_} =~ m/^{.*}$/);
}
my $specials = join q{|}, keys %{$evalSpecials};
$string =~ s{%($specials)%}{$evalSpecials->{$1}}g;
return $string;
}
sub msgDialog_progress {
my $hash = shift // return;
my $recipients = shift // return;
my $message = shift // return;
my $force = shift;
my $SELF = $hash->{NAME};
my $TYPE = $hash->{TYPE};
$recipients = join q{,}, devspec2array($msgDialog_devspec)
if $recipients eq 'everyone';
return if !$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", "")
if !$force;
push @oldHistory, split "\\|", $message;
my (@history);
my $dialog = $hash->{DIALOG} // $hash->{DEF} // q{};
$dialog = msgDialog_evalSpecials($hash, $dialog);
$dialog =~ s{\$recipient}{$recipients}g;
if ( !eval{ $dialog = JSON->new->decode($dialog); 1;} ){
return Log3($SELF, 2, "$TYPE ($SELF) - Error decoding JSON: $@");
}
for (@oldHistory){
$message = $_;
if ( defined $dialog->{$message} ){
$dialog = $dialog->{$message};
push @history, $message;
}
else{
for (keys %{$dialog}){
next if $dialog->{$_} !~ m{HASH}
|| !defined($dialog->{$_}{match})
|| $message !~ m{\A$dialog->{$_}{match}\z}
;
$dialog = $dialog->{$_};
push @history, $_;
last;
}
}
}
return if @history != @oldHistory || !$force && $dialog->{setOnly};
#$dialog = eval{JSON->new->encode($dialog)};
if ( !eval{ $dialog = JSON->new->encode($dialog); 1;} ) {
return Log3($SELF, 2, "$TYPE ($SELF) - Error encoding JSON: $@");
}
$dialog =~ s{\$message}{$message}g;
if ( !eval{ $dialog = JSON->new->decode($dialog); 1;} ) {
return Log3($SELF, 2, "$TYPE ($SELF) - Error decoding JSON: $@");
}
my $history = '';
for ( keys %{$dialog} ) {
if($_ !~ m{(?:setOnly|match|commands|message)}){
$history = join q{|}, @history;
last;
}
}
readingsBeginUpdate($hash);
readingsBulkUpdate($hash, $_."_history", $history)
for ( split q{,}, $recipients );
readingsBulkUpdate($hash, 'state', "$recipients: $message");
readingsEndUpdate($hash, 1);
if($dialog->{commands}){
my @commands =
$dialog->{commands} =~ m{ARRAY} ?
@{$dialog->{commands}}
: $dialog->{commands}
;
for (@commands){
$_ =~ s{;}{;;}g if $_ =~ m{\A\{.*\}\z}s;
my $ret = AnalyzeCommandChain($hash, $_);
Log3($SELF, 4, "$TYPE ($SELF) - return from command \"$_\": $ret")
if $ret;
}
}
return if !$dialog->{message};
my @message =
$dialog->{message} =~ m{ARRAY} ?
@{$dialog->{message}}
: $dialog->{message}
;
for (@message){
if($_ =~ m{\A\{.*\}\z}s){
$_ =~ s{;}{;;}g;
$_ = AnalyzePerlCommand($hash, $_);
}
}
$message = join "\n", @message; #we need the soft variant
my $msgCommand = InternalVal($SELF, 'MSGCOMMAND', '');
my %specials = (
"%SELF" => $SELF,
"%TYPE" => $TYPE,
"%recipients" => $recipients,
"%message" => $message
);
$msgCommand = EvalSpecials($msgCommand, %specials);
$msgCommand =~ s{\\[\@]}{@}x;
AnalyzeCommandChain($hash, $msgCommand);
#$msgCommand =~ s{\\[\@]}{@}x;
#$msgCommand =~ s{(\$\w+)}{$1}eegx;
#AnalyzeCommand($hash, $msgCommand);
return;
}
sub msgDialog_reset {
my $hash = shift // return;
my $SELF = $hash->{NAME};
my $TYPE = $hash->{TYPE};
Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_reset");
delete $hash->{READINGS};
readingsSingleUpdate($hash, 'state', 'Initialized', 1)
if !IsDisabled($SELF);
return;
}
sub msgDialog_updateAllowed {
Log3('global',5, 'msgDialog - entering msgDialog_updateAllowed');
my $allowed = join q{,}, devspec2array($msgDialog_devspec);
$modules{msgDialog}{AttrList} =~
s{allowed:multiple-strict,\S*}{allowed:multiple-strict,everyone,$allowed};
return;
}
sub msgDialog_update_msgCommand {
my $hash = shift // return;
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;
}
sub _getDataFile {
my $hash = shift // return;
my $filename = shift;
my $name = $hash->{NAME};
$filename = $filename // AttrVal($name,'configFile',undef);
my @t = localtime gettimeofday();
$filename = ResolveDateWildcards($filename, @t);
$hash->{CONFIGFILE} = $filename; # for configDB migration
return $filename;
}
sub _readConfigFromFile {
my $hash = shift // return 'no device reference provided!', undef;
my $cfg = shift // return 'no filename provided!', undef;
my $name = $hash->{NAME};
my $filename = _getDataFile($hash, $cfg);
Log3($name, 5, "trying to read config from $filename");
my ($ret, @content) = FileRead($filename);
if ($ret) {
Log3($name, 1, "$name failed to read configFile $filename!") ;
return $ret, undef;
}
my @cleaned = grep { $_ !~ m{\A\s*[#]}x } @content;
return 0, join q{ }, @cleaned;
}
1;
__END__
# commandref ##################################################################
=pod
=encoding utf8
=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 "set <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.
-
update <allowed or configFile>
- allowed - updates the selection for the allowed attribute.
- configFile - rereads configFile (e.g. after editing).
Get
-
trigger
Lists all TRIGGERs of the first level where setOnly is not specified.
Attributes
-
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 in the msgConfig device.
-
configFile
Path to a configuration file for the dialogue. This is an alternative way to using DEF.
The file itself must contain a JSON-encoded dialogue structure - just as described in define.
Example (placed in the same dir fhem.pl is located):
attr <msgDialogDevice> configFile ./metaDialogue.cfg
Readings
-
$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):
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 "set <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.
-
update <allowed or configFile>
- allowed - aktualisiert die Auswahl für das Attribut allowed.
- configFile - liest die configFile neu ein (z.B. nach Änderung).
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.
-
configFile
Alternativ zur Eingabe des Dialogs in der DEF kann eine Datei eingelesen werden, die die Konfigurationsinformationen zum Dialog enthält. Anzugeben ist der Pfad zu dieser Datei.
Die Datei selbst muss den Dialog in einer JSON-Structur beinhalten (Kommentar-Zeilen beginnend mit # sind erlaubt) - ansonsten gilt dasselbe wie in define beschrieben.
Beispiel (die Datei liegt im Modul-Verzeichnis):
attr <msgDialogDevice> configFile ./FHEM/metaDialogue.cfg
Readings
-
$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