# Id ########################################################################## # $Id$ # copyright ################################################################### # # 76_msgDialog.pm # # Copyright by igami # # This file is part of FHEM. # # FHEM is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # FHEM is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with FHEM. If not, see . # packages #################################################################### package main; use strict; use warnings; # variables ################################################################### my $msgDialog_devspec = "TYPE=(ROOMMATE|GUEST):FILTER=msgContactPush=.+"; # forward declarations ######################################################## sub msgDialog_Initialize($); sub msgDialog_Define($$); sub msgDialog_Set($@); sub msgDialog_Get($@); sub msgDialog_Notify($$); sub msgDialog_progress($$$;$); sub msgDialog_reset($); sub msgDialog_evalSpecials($$); sub msgDialog_updateAllowed; # initialize ################################################################## sub msgDialog_Initialize($) { my ($hash) = @_; my $TYPE = "msgDialog"; $hash->{DefFn} = "$TYPE\_Define"; $hash->{SetFn} = "$TYPE\_Set"; $hash->{GetFn} = "$TYPE\_Get"; $hash->{AttrFn} = "$TYPE\_Attr"; $hash->{NotifyFn} = "$TYPE\_Notify"; $hash->{AttrList} = "allowed:multiple-strict,everyone ". "disable:0,1 ". "disabledForIntervals ". "evalSpecials:textField-long ". "msgCommand ". $readingFnAttributes ; } # regular Fn ################################################################## sub msgDialog_Define($$) { my ($hash, $def) = @_; my ($SELF, $TYPE, $DEF) = split(/[\s]+/, $def, 3); my $rc = eval{ require JSON; JSON->import(); 1; }; return( "Error loading JSON. Maybe this module is not installed? ". "\nUnder debian (based) system it can be installed using ". "\"apt-get install libjson-perl\"" ) unless($rc); return( "No global configuration device defined: ". "Please define a msgConfig device first" ) unless($modules{msgConfig}{defptr}); my $msgConfig = $modules{msgConfig}{defptr}{NAME}; addToDevAttrList($msgConfig, "$TYPE\_evalSpecials:textField-long "); addToDevAttrList($msgConfig, "$TYPE\_msgCommand:textField "); $DEF = msgDialog_evalSpecials($hash, $DEF); $DEF = eval{JSON->new->decode($DEF)}; if($@){ Log3($SELF, 2, "$TYPE ($SELF) - DEF is not a valid JSON: $@"); return("Usage: define $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 if($_ =~ m/^{.*}$/s); 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

=end html =begin html_DE

msgDialog

=end html_DE =cut