2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 06:39:11 +00:00

76_msgDialog: PBP canges, add confidgfile option

git-svn-id: https://svn.fhem.de/fhem/trunk@25740 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
Beta-User 2022-02-26 06:12:22 +00:00
parent 2b19e690bc
commit f9cae6e34b
2 changed files with 332 additions and 186 deletions

View File

@ -1,5 +1,7 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it. # Do not insert empty lines here, update check depends on it.
- feature: 76_mssDialog: Add option to define dialogues by file
- change: 76_mssDialog: PBP code restructured
- feature: 89_AndroidDB: Added new features - feature: 89_AndroidDB: Added new features
- bugfix: 89_AndroidDBHost: Bug fixes - bugfix: 89_AndroidDBHost: Bug fixes
- bugfix: 70_DENON_AVR: handled some uninitialized values - bugfix: 70_DENON_AVR: handled some uninitialized values

View File

@ -1,6 +1,6 @@
# Id ########################################################################## # Id ##########################################################################
# $Id$ # $Id$
#
# copyright ################################################################### # copyright ###################################################################
# #
# 76_msgDialog.pm # 76_msgDialog.pm
@ -23,90 +23,141 @@
# along with FHEM. If not, see <http://www.gnu.org/licenses/>. # along with FHEM. If not, see <http://www.gnu.org/licenses/>.
# packages #################################################################### # packages ####################################################################
package main; package FHEM::Communication::msgDialog; ##no critic qw(Package)
use strict; use strict;
use warnings; use warnings;
#use Carp qw(carp);
use GPUtils qw(GP_Import);
use JSON (); # qw(decode_json encode_json);
use Encode;
#use HttpUtils;
use utf8;
use Time::HiRes qw(gettimeofday);
sub ::msgDialog_Initialize { goto &Initialize }
# variables ################################################################### # variables ###################################################################
my $msgDialog_devspec = "TYPE=(ROOMMATE|GUEST):FILTER=msgContactPush=.+"; my $msgDialog_devspec = 'TYPE=(ROOMMATE|GUEST):FILTER=msgContactPush=.+';
# forward declarations ######################################################## BEGIN {
sub msgDialog_Initialize($);
sub msgDialog_Define($$); GP_Import( qw(
sub msgDialog_Set($@); addToDevAttrList
sub msgDialog_Get($@); readingsSingleUpdate
sub msgDialog_Notify($$); readingsBeginUpdate
readingsBulkUpdate
sub msgDialog_progress($$$;$); readingsEndUpdate
sub msgDialog_reset($); Log3
sub msgDialog_evalSpecials($$); defs attr modules L
sub msgDialog_updateAllowed; init_done
InternalTimer
RemoveInternalTimer
readingFnAttributes
IsDisabled
AttrVal
InternalVal
ReadingsVal
devspec2array
AnalyzeCommandChain
AnalyzeCommand
EvalSpecials
AnalyzePerlCommand
perlSyntaxCheck
parseParams
ResolveDateWildcards
FileRead
getAllSets
setNotifyDev setDisableNotifyFn
deviceEvents
trim
) )
};
# initialize ################################################################## # initialize ##################################################################
sub msgDialog_Initialize($) { sub Initialize {
my ($hash) = @_; my $hash = shift // return;
my $TYPE = "msgDialog"; $hash->{DefFn} = \&Define;
$hash->{SetFn} = \&Set;
$hash->{DefFn} = "$TYPE\_Define"; $hash->{GetFn} = \&Get;
$hash->{SetFn} = "$TYPE\_Set"; $hash->{AttrFn} = \&Attr;
$hash->{GetFn} = "$TYPE\_Get"; $hash->{NotifyFn} = \&Notify;
$hash->{AttrFn} = "$TYPE\_Attr";
$hash->{NotifyFn} = "$TYPE\_Notify";
$hash->{AttrList} = $hash->{AttrList} =
"allowed:multiple-strict,everyone ". "allowed:multiple-strict,everyone ".
"disable:0,1 ". "disable:0,1 ".
"disabledForIntervals ". "disabledForIntervals ".
"evalSpecials:textField-long ". "evalSpecials:textField-long ".
"msgCommand ". "msgCommand configFile ".
$readingFnAttributes $readingFnAttributes
; ;
return;
} }
# regular Fn ################################################################## # regular Fn ##################################################################
sub msgDialog_Define($$) { sub Define {
my ($hash, $def) = @_; my $hash = shift // return;
my ($SELF, $TYPE, $DEF) = split(/[\s]+/, $def, 3); my $def = shift // return;
my $rc = eval{ my ($SELF, $TYPE, $DEF) = split m{[\s]+}x, $def, 3;
if (!eval{
require JSON; require JSON;
JSON->import(); JSON->import();
1; 1;
}; } ) { return (
return(
"Error loading JSON. Maybe this module is not installed? ". "Error loading JSON. Maybe this module is not installed? ".
"\nUnder debian (based) system it can be installed using ". "\nUnder debian (based) system it can be installed using ".
"\"apt-get install libjson-perl\"" "\"apt-get install libjson-perl\""
) unless($rc); )
}
return $init_done ? firstInit($hash) : InternalTimer(time+1, \&firstInit, $hash );
}
sub firstInit {
my $hash = shift // return;
my $name = $hash->{NAME};
return( return(
"No global configuration device defined: ". "No global configuration device defined: ".
"Please define a msgConfig device first" "Please define a msgConfig device first"
) unless($modules{msgConfig}{defptr}); ) if !$modules{msgConfig}{defptr};
my $msgConfig = $modules{msgConfig}{defptr}{NAME}; my $msgConfig = $modules{msgConfig}{defptr}{NAME};
addToDevAttrList($msgConfig, "$TYPE\_evalSpecials:textField-long", 'msgDialog'); addToDevAttrList($msgConfig, 'msgDialog_evalSpecials:textField-long', 'msgDialog');
addToDevAttrList($msgConfig, "$TYPE\_msgCommand:textField", 'msgDialog'); addToDevAttrList($msgConfig, 'msgDialog_msgCommand:textField', 'msgDialog');
$DEF = msgDialog_evalSpecials($hash, $DEF); if (!IsDisabled($name) ) {
$DEF = eval{JSON->new->decode($DEF)}; setDisableNotifyFn($hash, 0);
setNotifyDev($hash,'TYPE=(ROOMMATE|GUEST)');
}
if($@){ my $cfg = AttrVal($name,'configFile',undef);
Log3($SELF, 2, "$TYPE ($SELF) - DEF is not a valid JSON: $@"); my $content;
return("Usage: define <name> $TYPE {JSON}\n\n$@"); if ($cfg) {
(my $ret, $content) = _readConfigFromFile($hash, $cfg);
return $ret if $ret;
$hash->{DIALOG} = $content;
} else {
$content = InternalVal($name, 'DEF', '{}');
delete $hash->{DIALOG};
}
delete $hash->{TRIGGER};
my $content2 = msgDialog_evalSpecials($hash, $content);
if ( !eval{ $content2 = JSON->new->decode($content2); 1;} ){ #decode_json will cause problems with utf8
Log3($hash, 2, "msgDialog ($name) - DEF or configFile is not a valid JSON: $@");
return("Usage: define <name> msgDialog {JSON}\n\n$@");
} }
my @TRIGGER; my @TRIGGER;
foreach (keys(%{$DEF})){ for (keys %{$content2}){
next if(defined($DEF->{$_}{setOnly})); next if ref $content2->{$_} ne 'HASH';
next if defined $content2->{$_}->{setOnly}; # && $content2->{$_}->{setOnly} eq 'true';
push(@TRIGGER, $_); push @TRIGGER, $_;
} }
$hash->{TRIGGER} = join(",", @TRIGGER); $hash->{TRIGGER} = join q{,}, @TRIGGER;
$hash->{NOTIFYDEV} = "TYPE=(ROOMMATE|GUEST)";
msgDialog_update_msgCommand($hash); msgDialog_update_msgCommand($hash);
msgDialog_reset($hash); msgDialog_reset($hash);
@ -115,42 +166,46 @@ sub msgDialog_Define($$) {
return; return;
} }
sub msgDialog_Set($@) { sub Set {
my ($hash, @a) = @_; my ($hash,$SELF,$argument,@values) = @_;
my $TYPE = $hash->{TYPE}; my $TYPE = $hash->{TYPE};
return "\"set $TYPE\" needs at least one argument" if(@a < 2); return qq("set $TYPE" needs at least one argument) if !$argument;
my $SELF = shift @a; my $value = join q{ }, @values;
my $argument = shift @a;
my $value = join(" ", @a) if (@a);
my %sets = ( my %sets = (
"reset" => "reset:noArg", reset => 'reset:noArg',
"say" => "say:textField", say => 'say:textField',
"updateAllowed" => "updateAllowed:noArg" updateAllowed => 'updateAllowed:noArg',
update => 'update:allowed,configFile'
); );
Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_Set"); Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_Set");
return( return
"Unknown argument $argument, choose one of ".join(" ", values %sets) "Unknown argument $argument, choose one of ".join q{ }, values %sets
) unless(exists($sets{$argument})); if !defined $sets{$argument};
if($argument eq "reset"){ if ( $argument eq 'reset' ){
msgDialog_reset($hash); return msgDialog_reset($hash);
} }
elsif($argument eq "updateAllowed"){ if( $argument eq 'update'){
msgDialog_updateAllowed(); return msgDialog_updateAllowed() if $values[0] eq 'allowed';
return firstInit($hash) if $values[0] eq 'configFile';
} }
return if(IsDisabled($SELF)); if( $argument eq 'updateAllowed'){
return msgDialog_updateAllowed();
}
if($argument eq "say" && $value){ return if IsDisabled($SELF);
my $recipients = join(",", ($value =~ m/@(\S+)\s+/g));
$recipients = AttrVal($SELF, "allowed", "") unless($recipients); 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); my (undef, $say) = ($value =~ m/(^|\s)([^@].+)/g);
return unless($recipients || $say); return if !$recipients && !$say;
msgDialog_progress($hash, $recipients, $say, 1); msgDialog_progress($hash, $recipients, $say, 1);
} }
@ -158,132 +213,146 @@ sub msgDialog_Set($@) {
return; return;
} }
sub msgDialog_Get($@) { sub Get {
my ($hash, @a) = @_; my ($hash,$SELF,$argument,@values) = @_;
my $TYPE = $hash->{TYPE}; my $TYPE = $hash->{TYPE};
return "\"get $TYPE\" needs at least one argument" if(@a < 2); return "\"get $TYPE\" needs at least one argument" if !$argument;
my $SELF = shift @a; my $value = join q{ }, @values;
my $argument = shift @a;
my $value = join(" ", @a) if (@a);
my %gets = ( my %gets = (
"trigger" => "trigger:noArg" trigger => 'trigger:noArg'
); );
Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_Get"); Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_Get");
return( return "Unknown argument $argument, choose one of ".join q{ }, values %gets
"Unknown argument $argument, choose one of ".join(" ", values %gets) if !exists $gets{$argument};
) unless(exists($gets{$argument}));
return if(IsDisabled($SELF)); return if IsDisabled($SELF);
if($argument eq "trigger"){ if($argument eq 'trigger'){
return(join("\n", split(",", InternalVal($SELF, "TRIGGER", undef)))); return join "\n", split q{,}, InternalVal($SELF, 'TRIGGER', undef); #we need the soft variant
} }
return; return;
} }
sub msgDialog_Attr(@) { sub Attr {
my ($cmd, $SELF, $attribute, $value) = @_; my ($cmd, $SELF, $attribute, $value) = @_;
my ($hash) = $defs{$SELF}; my $hash = $defs{$SELF};
my $TYPE = $hash->{TYPE}; my $TYPE = $hash->{TYPE};
Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_Attr"); Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_Attr");
if($attribute eq "disable"){ if ($attribute eq 'disable'){
if($cmd eq "set" and $value == 1){ if($cmd eq 'set' and $value == 1){
readingsSingleUpdate($hash, "state", "Initialized", 1); setDisableNotifyFn($hash, 1);
} return readingsSingleUpdate($hash, 'state', 'Initialized', 1); #Beta-User: really?!?
else{
readingsSingleUpdate($hash, "state", "disabled", 1);
} }
readingsSingleUpdate($hash, 'state', 'disabled', 1);
return firstInit($hash) if $init_done;
return;
} }
elsif($attribute eq "msgCommand"){
if($cmd eq "set"){ if ( $attribute eq 'msgCommand'){
if($cmd eq 'set'){
$attr{$SELF}{$attribute} = $value; $attr{$SELF}{$attribute} = $value;
} }
else{ else{
delete($attr{$SELF}{$attribute}); delete $attr{$SELF}{$attribute};
} }
msgDialog_update_msgCommand($hash); 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; return;
} }
sub msgDialog_Notify($$) { sub Notify {
my ($hash, $dev_hash) = @_; my $hash = shift // return;
my $dev_hash = shift // return;
my $SELF = $hash->{NAME}; my $SELF = $hash->{NAME};
my $TYPE = $hash->{TYPE}; my $TYPE = $hash->{TYPE};
my $device = $dev_hash->{NAME}; my $device = $dev_hash->{NAME};
Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_Notify"); Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_Notify");
return if(IsDisabled($SELF)); return if IsDisabled($SELF);
my @events = @{deviceEvents($dev_hash, 1)}; my @events = @{deviceEvents($dev_hash, 1)};
return unless( return if !@events || AttrVal($SELF, 'allowed', '') !~ m{\b(?:$device|everyone)(?:\b|\z)}xms;
@events && AttrVal($SELF, "allowed", "") =~ m/(^|,)($device|everyone)(,|$)/
);
foreach my $event (@events){ for my $event (@events){
next unless($event =~ m/(fhemMsgPushReceived|fhemMsgRcvPush): (.+)/); next if $event !~ m{(?:fhemMsgPushReceived|fhemMsgRcvPush):.(.+)}xms;
Log3($SELF, 4 , "$TYPE ($SELF) triggered by \"$device $event\""); Log3($SELF, 4 , "$TYPE ($SELF) triggered by \"$device $event\"");
msgDialog_progress($hash, $device, $2); msgDialog_progress($hash, $device, $1);
} }
return; return;
} }
# module Fn ################################################################### # module Fn ###################################################################
sub msgDialog_evalSpecials($$) { sub msgDialog_evalSpecials {
my ($hash, $string) = @_; my $hash = shift // return;
my $string = shift // return;
my $SELF = $hash->{NAME}; my $SELF = $hash->{NAME};
my $TYPE = $hash->{TYPE}; my $TYPE = $hash->{TYPE};
Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_evalSpecials"); Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_evalSpecials");
my $msgConfig = $modules{msgConfig}{defptr}{NAME} my $msgConfig;
if($modules{msgConfig}{defptr}); $msgConfig = $modules{msgConfig}{defptr}{NAME}
if $modules{msgConfig}{defptr};
$string =~ s/\$SELF/$SELF/g; $string =~ s/\$SELF/$SELF/g;
my $evalSpecials = my $evalSpecials = AttrVal($msgConfig, 'msgDialog_evalSpecials', '');
AttrVal($msgConfig, "$TYPE\_evalSpecials", ""). $evalSpecials .= ' ';
" ". $evalSpecials .= AttrVal($SELF, 'evalSpecials', '');
AttrVal($SELF, "evalSpecials", "")
;
return($string) if($evalSpecials eq " "); return $string if $evalSpecials eq ' ';
(undef, $evalSpecials) = parseParams($evalSpecials, "\\s", " "); (undef, $evalSpecials) = parseParams($evalSpecials, "\\s", " ");
return($string) unless($evalSpecials); return $string if !$evalSpecials;
foreach(keys(%{$evalSpecials})){ for ( keys %{$evalSpecials} ) {
$evalSpecials->{$_} = eval $evalSpecials->{$_} $evalSpecials->{$_} = AnalyzePerlCommand($hash, $evalSpecials->{$_})
if($evalSpecials->{$_} =~ m/^{.*}$/); if($evalSpecials->{$_} =~ m/^{.*}$/);
} }
my $specials = join("|", keys(%{$evalSpecials})); my $specials = join q{|}, keys %{$evalSpecials};
$string =~ s/%($specials)%/$evalSpecials->{$1}/g; $string =~ s{%($specials)%}{$evalSpecials->{$1}}g;
return($string); return $string;
} }
sub msgDialog_progress($$$;$) { sub msgDialog_progress {
my ($hash, $recipients, $message, $force) = @_; my $hash = shift // return;
my $recipients = shift // return;
my $message = shift // return;
my $force = shift;
my $SELF = $hash->{NAME}; my $SELF = $hash->{NAME};
my $TYPE = $hash->{TYPE}; my $TYPE = $hash->{TYPE};
$recipients = join(",", devspec2array($msgDialog_devspec)) $recipients = join q{,}, devspec2array($msgDialog_devspec)
if($recipients eq "everyone"); if $recipients eq 'everyone';
return unless($recipients); return if !$recipients;
Log3( Log3(
$SELF, 5 , "$TYPE ($SELF)" $SELF, 5 , "$TYPE ($SELF)"
@ -294,48 +363,55 @@ sub msgDialog_progress($$$;$) {
); );
my @oldHistory; my @oldHistory;
@oldHistory = split("\\|", ReadingsVal($SELF, "$recipients\_history", "")) @oldHistory = split "\\|", ReadingsVal($SELF, "$recipients\_history", "")
unless($force); if !$force;
push(@oldHistory, split("\\|", $message)); push @oldHistory, split "\\|", $message;
my (@history); my (@history);
my $dialog =$hash->{DEF}; my $dialog = $hash->{DIALOG} // $hash->{DEF} // q{};
$dialog = msgDialog_evalSpecials($hash, $dialog); $dialog = msgDialog_evalSpecials($hash, $dialog);
$dialog =~ s/\$recipient/$recipients/g; $dialog =~ s{\$recipient}{$recipients}g;
$dialog = eval{JSON->new->decode($dialog)}; if ( !eval{ $dialog = JSON->new->decode($dialog); 1;} ){
return Log3($SELF, 2, "$TYPE ($SELF) - Error decoding JSON: $@");
}
foreach (@oldHistory){ for (@oldHistory){
$message = $_; $message = $_;
if(defined($dialog->{$message})){ if ( defined $dialog->{$message} ){
$dialog = $dialog->{$message}; $dialog = $dialog->{$message};
push(@history, $message); push @history, $message;
} }
else{ else{
foreach (keys(%{$dialog})){ for (keys %{$dialog}){
next unless( next if $dialog->{$_} !~ m{HASH}
$dialog->{$_} =~ m/HASH/ && || !defined($dialog->{$_}{match})
defined($dialog->{$_}{match}) && || $message !~ m{\A$dialog->{$_}{match}\z}
$message =~ m/^$dialog->{$_}{match}$/ ;
);
$dialog = $dialog->{$_}; $dialog = $dialog->{$_};
push(@history, $_); push @history, $_;
last; last;
} }
} }
} }
return if(@history != @oldHistory || !$force && $dialog->{setOnly}); return if @history != @oldHistory || !$force && $dialog->{setOnly};
$dialog = eval{JSON->new->encode($dialog)}; #$dialog = eval{JSON->new->encode($dialog)};
$dialog =~ s/\$message/$message/g; if ( !eval{ $dialog = JSON->new->encode($dialog); 1;} ) {
$dialog = eval{JSON->new->decode($dialog)}; return Log3($SELF, 2, "$TYPE ($SELF) - Error encoding JSON: $@");
my $history = ""; }
foreach (keys(%{$dialog})){ $dialog =~ s{\$message}{$message}g;
if($_ !~ m/(setOnly|match|commands|message)/){ if ( !eval{ $dialog = JSON->new->decode($dialog); 1;} ) {
$history = join("|", @history); 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; last;
} }
@ -343,76 +419,86 @@ sub msgDialog_progress($$$;$) {
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
readingsBulkUpdate($hash, $_."_history", $history) readingsBulkUpdate($hash, $_."_history", $history)
foreach (split(",", $recipients)); for ( split q{,}, $recipients );
readingsBulkUpdate($hash, "state", "$recipients: $message"); readingsBulkUpdate($hash, 'state', "$recipients: $message");
readingsEndUpdate($hash, 1); readingsEndUpdate($hash, 1);
if($dialog->{commands}){ if($dialog->{commands}){
my @commands = my @commands =
$dialog->{commands} =~ m/ARRAY/ ? $dialog->{commands} =~ m{ARRAY} ?
@{$dialog->{commands}} @{$dialog->{commands}}
: $dialog->{commands} : $dialog->{commands}
; ;
foreach (@commands){ for (@commands){
$_ =~ s/;/;;/g if($_ =~ m/^{.*}$/s); $_ =~ s{;}{;;}g if $_ =~ m{\A\{.*\}\z}s;
my $ret = AnalyzeCommandChain(undef, $_); my $ret = AnalyzeCommandChain($hash, $_);
Log3($SELF, 4, "$TYPE ($SELF) - return from command \"$_\": $ret") Log3($SELF, 4, "$TYPE ($SELF) - return from command \"$_\": $ret")
if($ret); if $ret;
} }
} }
if($dialog->{message}){ return if !$dialog->{message};
my @message =
$dialog->{message} =~ m/ARRAY/ ? my @message =
$dialog->{message} =~ m{ARRAY} ?
@{$dialog->{message}} @{$dialog->{message}}
: $dialog->{message} : $dialog->{message}
; ;
foreach (@message){ for (@message){
if($_ =~ m/^{.*}$/s){ if($_ =~ m{\A\{.*\}\z}s){
$_ =~ s/;/;;/g; $_ =~ s{;}{;;}g;
$_ = AnalyzePerlCommand(undef, $_); $_ = AnalyzePerlCommand($hash, $_);
} }
}
my $message = join("\n", @message);
my $msgCommand = '"'.InternalVal($SELF, "MSGCOMMAND", "").'"';
$msgCommand = eval($msgCommand);
fhem($msgCommand);
} }
$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; return;
} }
sub msgDialog_reset($) { sub msgDialog_reset {
my ($hash) = @_; my $hash = shift // return;
my $SELF = $hash->{NAME}; my $SELF = $hash->{NAME};
my $TYPE = $hash->{TYPE}; my $TYPE = $hash->{TYPE};
Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_reset"); Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_reset");
delete($hash->{READINGS}); delete $hash->{READINGS};
readingsSingleUpdate($hash, "state", "Initialized", 1) readingsSingleUpdate($hash, 'state', 'Initialized', 1)
unless(IsDisabled($SELF)); if !IsDisabled($SELF);
return; return;
} }
sub msgDialog_updateAllowed { sub msgDialog_updateAllowed {
Log(5, "msgDialog - entering msgDialog_updateAllowed"); Log3('global',5, 'msgDialog - entering msgDialog_updateAllowed');
my $allowed = join(",", sort(devspec2array($msgDialog_devspec))); my $allowed = join q{,}, sort devspec2array($msgDialog_devspec);
$modules{msgDialog}{AttrList} =~ $modules{msgDialog}{AttrList} =~
s/allowed:multiple-strict,\S*/allowed:multiple-strict,everyone,$allowed/; s{allowed:multiple-strict,\S*}{allowed:multiple-strict,everyone,$allowed};
return;
} }
sub msgDialog_update_msgCommand($) { sub msgDialog_update_msgCommand {
my ($hash) = @_; my $hash = shift // return;
my $SELF = $hash->{NAME}; my $SELF = $hash->{NAME};
my $TYPE = $hash->{TYPE}; my $TYPE = $hash->{TYPE};
my $msgConfig = $modules{msgConfig}{defptr}{NAME}; my $msgConfig = $modules{msgConfig}{defptr}{NAME};
@ -420,7 +506,7 @@ sub msgDialog_update_msgCommand($) {
Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_update_msgCommand"); Log3($SELF, 5, "$TYPE ($SELF) - entering msgDialog_update_msgCommand");
$hash->{MSGCOMMAND} = $hash->{MSGCOMMAND} =
AttrVal($SELF, "msgCommand", AttrVal($SELF, 'msgCommand',
AttrVal($msgConfig, "$TYPE\_msgCommand", AttrVal($msgConfig, "$TYPE\_msgCommand",
'msg push \@$recipients $message' 'msg push \@$recipients $message'
) )
@ -430,14 +516,42 @@ sub msgDialog_update_msgCommand($) {
return; 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; 1;
__END__ __END__
# commandref ################################################################## # commandref ##################################################################
=pod =pod
=encoding utf8 =encoding utf8
=item helper =item helper
=item summary dialogs for instant messaging =item summary dialogs for instant messaging
=item summary_DE Dialoge f&uuml;r Sofortnachrichten =item summary_DE Dialoge f&uuml;r Sofortnachrichten
@ -448,8 +562,8 @@ __END__
<h3>msgDialog</h3> <h3>msgDialog</h3>
<ul> <ul>
With msgDialog you can define dialogs for instant messages via TelegramBot, Jabber and yowsup (WhatsApp).<br> With msgDialog you can define dialogs for instant messages via TelegramBot, Jabber and yowsup (WhatsApp).<br>
The communication uses the msg command. Therefore, a device of type msgConfig must be defined first.<br> The communication uses the msg command. Therefore, a device of type <a href="#msgConfig">msgConfig</a> must be defined first.<br>
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.<br> For each dialog you can define which person is authorized to do so. Devices of the type <a href="#ROOMMATE">ROOMMATE</a> or <a href="#GUEST">GUEST</a> with a defined msgContactPush attribute are required for this. Make sure that the reading fhemMsgRcvPush generates an event.<br>
<br> <br>
Prerequisites: Prerequisites:
<ul> <ul>
@ -579,6 +693,14 @@ __END__
<code>updateAllowed</code><br> <code>updateAllowed</code><br>
Updates the selection for the allowed attribute. Updates the selection for the allowed attribute.
</li> </li>
<a id="msgDialog-set-update"></a>
<li>
<code>update &lt;allowed or configFile&gt;</code><br>
<ul>
<li>allowed - updates the selection for the allowed attribute.</li>
<li>configFile - rereads configFile (e.g. after editing).</li>
</ul>
</li>
</ul> </ul>
<br> <br>
@ -635,6 +757,13 @@ __END__
<code>"msg push \@$recipients $message"</code>.<br> <code>"msg push \@$recipients $message"</code>.<br>
This attribute is available in the msgConfig device. This attribute is available in the msgConfig device.
</li> </li>
<li>
<a id="msgDialog-attr-configFile"></a><b>configFile</b><br>
<p>Path to a configuration file for the dialogue. This is an alternative way to using DEF.<br>
The file itself must contain a JSON-encoded dialogue structure - just as described in define.
<p>Example (placed in the same dir fhem.pl is located):</p>
<p><code>attr &lt;msgDialogDevice&gt; configFile ./metaDialogue.cfg</code></p>
</li>
</ul> </ul>
<br> <br>
@ -871,9 +1000,9 @@ plot=Waschkeller_washer_SVG
Mit msgDialog k&ouml;nnen Dialoge f&uuml;r Sofortnachrichten &uuml;ber Mit msgDialog k&ouml;nnen Dialoge f&uuml;r Sofortnachrichten &uuml;ber
TelegramBot, Jabber und yowsup (WhatsApp) definiert werden.<br> TelegramBot, Jabber und yowsup (WhatsApp) definiert werden.<br>
Die Kommunikation erfolgt &uuml;ber den msg Befehl. Daher muss ein Ger&auml;t Die Kommunikation erfolgt &uuml;ber den msg Befehl. Daher muss ein Ger&auml;t
vom Typ msgConfig zuerst definiert werden.<br> vom Typ <a href="#msgConfig">msgConfig</a> zuerst definiert werden.<br>
F&uuml;r jeden Dialog kann festgelegt werden welche Person dazu berechtigt F&uuml;r jeden Dialog kann festgelegt werden welche Person dazu berechtigt
ist. Dazu sind Ger&auml;te vom Typ ROOMMATE oder GUEST mit definiertem ist. Dazu sind Ger&auml;te vom Typ <a href="#ROOMMATE">ROOMMATE</a> oder <a href="#GUEST">GUEST</a> mit definiertem
msgContactPush Attribut erforderlich. Es ist darauf zu achten, dass das msgContactPush Attribut erforderlich. Es ist darauf zu achten, dass das
Reading fhemMsgRcvPush ein Event erzeugt.<br> Reading fhemMsgRcvPush ein Event erzeugt.<br>
<br> <br>
@ -1014,6 +1143,14 @@ plot=Waschkeller_washer_SVG
<code>updateAllowed</code><br> <code>updateAllowed</code><br>
Aktualisiert die Auswahl f&uuml;r das Attribut allowed. Aktualisiert die Auswahl f&uuml;r das Attribut allowed.
</li> </li>
<a id="msgDialog-set-update"></a>
<li>
<code>update &lt;allowed or configFile&gt;</code><br>
<ul>
<li>allowed - aktualisiert die Auswahl für das Attribut allowed.</li>
<li>configFile - liest die configFile neu ein (z.B. nach Änderung).</li>
</ul>
</li>
</ul> </ul>
<br> <br>
@ -1075,6 +1212,13 @@ plot=Waschkeller_washer_SVG
Dieses Attribut ist als "msgDialog_msgCommand" im msgConfig Gerät Dieses Attribut ist als "msgDialog_msgCommand" im msgConfig Gerät
vorhanden. vorhanden.
</li> </li>
<li>
<a id="msgDialog-attr-configFile"></a><b>configFile</b><br>
<p>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.<br>
Die Datei selbst muss den Dialog in einer JSON-Structur beinhalten (Kommentar-Zeilen beginnend mit # sind erlaubt) - ansonsten gilt dasselbe wie in define beschrieben.
<p>Beispiel (die Datei liegt im Modul-Verzeichnis):</p>
<p><code>attr &lt;msgDialogDevice&gt; configFile ./FHEM/metaDialogue.cfg</code></p>
</li>
</ul> </ul>
<br> <br>