]",
+# ....
+# }
+####################################################################################################
+sub DbRep_autoForward ($$$) {
+ my ($name,$reading,$value) = @_;
+ my $hash = $defs{$name};
+ my $av = AttrVal($name, "autoForward", "");
+ my ($sr,$af);
+
+ return if(!$av);
+
+ $av =~ m/^\{(.*)\}/s;
+ $av = $1;
+ $av =~ s/["\n]//g;
+
+ my @a = split(",",$av);
+
+ $av = "{ ";
+ my $i = 0;
+ foreach (@a) {
+ $av .= "\"$i\" => \"$_\",";
+ $i++;
+ }
+ $av .= " }";
+
+ $af = eval $av;
+ if($@ || ref($af) ne "HASH") {
+ Log3($name, 2, "$name - Values specified in attribute \"autoForward\" are not defined as HASH ... exiting !") if(ref($af) ne "HASH");
+ Log3($name, 2, "$name - Error while evaluate: ".$@) if($@);
+ return;
+ }
+
+ foreach my $key (keys %{$af}) {
+ my ($srr,$ddev,$dr) = split("=>", $af->{$key});
+ $srr = DbRep_trim($srr) if($srr);
+ $ddev = DbRep_trim($ddev) if($ddev);
+ $dr = DbRep_trim($dr) if($dr);
+ next if(!$ddev);
+ if(!$defs{$ddev}) { # Vorhandensein Destination Device prüfen
+ Log3($name, 2, "$name - WARNING - Forward reading \"$reading\" not possible, device \"$ddev\" doesn't exist");
+ next;
+ }
+
+ if(!$srr || $reading !~ /^$srr$/) {
+ # Log3($name, 4, "$name - Reading \"$reading\" doesn't match autoForward-Regex: ".($srr?$srr:"")." - no forward to \"$ddev\" ");
+ next;
+ }
+
+ eval { $sr = $srr };
+ $dr = $dr ? $dr : ($sr ne ".*") ? $sr : $reading; # Destination Reading = Source Reading wenn Destination Reading nicht angegeben
+ $dr = makeReadingName($dr); # Destination Readingname validieren / entfernt aus dem übergebenen Readingname alle ungültigen Zeichen und ersetzt diese durch einen Unterstrich "_"
+ Log3($name, 4, "$name - Forward reading \"$reading\" to \"$ddev:$dr\" ");
+ CommandSetReading(undef, "$ddev $dr $value");
+ }
+
+return;
+}
+
####################################################################################################
# Anzeige von laufenden Blocking Prozessen
####################################################################################################
-sub DbRep_getblockinginfo($@) {
+sub DbRep_getblockinginfo ($) {
my ($hash) = @_;
my $name = $hash->{NAME};
@@ -9868,7 +9958,7 @@ sub DbRep_getblockinginfo($@) {
ReadingsBulkUpdateValue ($hash,"Blocking_Count",$#rows+1);
ReadingsBulkUpdateTimeState($hash,undef,undef,"done");
- readingsEndUpdate($hash, 1);
+ readingsEndUpdate ($hash, 1);
return;
}
@@ -10165,6 +10255,7 @@ sub DbRep_userexit ($$$) {
$cmd = "{".$cmd."}";
my $r = AnalyzeCommandChain(undef, $cmd);
}
+
return;
}
@@ -11143,15 +11234,17 @@ sub DbRep_WriteToDB($$$@) {
if (lc($DbLogType) =~ m(history)) {
# insert history mit/ohne primary key
- if ($usepkh && $dbloghash->{MODEL} eq 'MYSQL') {
- eval { $sth_ih = $dbh->prepare_cached("INSERT IGNORE INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"); };
- } elsif ($usepkh && $dbloghash->{MODEL} eq 'SQLITE') {
- eval { $sth_ih = $dbh->prepare_cached("INSERT OR IGNORE INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"); };
- } elsif ($usepkh && $dbloghash->{MODEL} eq 'POSTGRESQL') {
- eval { $sth_ih = $dbh->prepare_cached("INSERT INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?) ON CONFLICT DO NOTHING"); };
- } else {
- eval { $sth_ih = $dbh->prepare_cached("INSERT INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"); };
- }
+ eval {
+ if ($usepkh && $dbloghash->{MODEL} eq 'MYSQL') {
+ $sth_ih = $dbh->prepare_cached("INSERT IGNORE INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)");
+ } elsif ($usepkh && $dbloghash->{MODEL} eq 'SQLITE') {
+ $sth_ih = $dbh->prepare_cached("INSERT OR IGNORE INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)");
+ } elsif ($usepkh && $dbloghash->{MODEL} eq 'POSTGRESQL') {
+ $sth_ih = $dbh->prepare_cached("INSERT INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?) ON CONFLICT DO NOTHING");
+ } else {
+ $sth_ih = $dbh->prepare_cached("INSERT INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)");
+ }
+ };
if ($@) {
$err = $@;
Log3 ($name, 2, "DbRep $name - $@");
@@ -11604,14 +11697,14 @@ sub DbRep_modAssociatedWith ($$$) {
foreach my $e (@edvs) {
$e =~ s/%/\.*/g if($e !~ /^%$/); # SQL Wildcard % auflösen
@edvspcs = devspec2array($e);
- @edvspcs = map {s/\.\*/%/g; $_; } @edvspcs;
+ @edvspcs = map { my $e = $_; $e =~ s/\.\*/%/xg; } @edvspcs;
if((map {$_ =~ /%/;} @edvspcs) && $edevice !~ /^%$/) { # Devices mit Wildcard (%) aussortieren, die nicht aufgelöst werden konnten
$edevswc .= "|" if($edevswc);
$edevswc .= join(" ",@edvspcs);
} else {
$edevs .= "|" if($edevs);
- $edevs .= join("|",@edvspcs);
- }
+ $edevs .= join("|",@edvspcs);
+ }
}
}
@@ -13409,6 +13502,35 @@ return $ret;
allowDeletion - unlocks the delete-function
+
+ autoForward - if activated, the result threads of a function are transferred to one or more devices.
+ The definition takes the form:
+
+
+{
+ "<source-reading> => "<dest.device> [=> <dest.-reading>]",
+ "<source-reading> => "<dest.device> [=> <dest.-reading>]",
+ ...
+}
+
+
+ Wildcards (.*) are permitted in the specification <source-reading>.
+
+
+{
+ ".*" => "Dum.Rep.All",
+ ".*AVGAM.*" => "Dum.Rep => average",
+ ".*SUM.*" => "Dum.Rep.Sum => summary",
+}
+# all readings are transferred to device "Dum.Rep.All", reading name remains in the target
+# readings with "AVGAM" in the name are transferred to the "Dum.Rep" device in the reading "average"
+# readings with "SUM" in the name are transferred to the device "Dum.Rep.Sum" in the reading "summary"
+
+
+
+
averageCalcForm - specifies the calculation variant of average peak by "averageValue".
@@ -15985,6 +16107,37 @@ return $ret;
allowDeletion - schaltet die Löschfunktion des Moduls frei
+
+ autoForward - wenn aktiviert, werden die Ergebnisreadings einer Funktion in ein oder mehrere Devices
+ übertragen.
+ Die Definition erfolgt in der Form:
+
+
+{
+ "<source-reading> => "<dest.device> [=> <dest.-reading>]",
+ "<source-reading> => "<dest.device> [=> <dest.-reading>]",
+ ...
+}
+
+
+ In der Angabe <source-reading> sind Wildcards (.*) erlaubt.
+
+
+{
+ ".*" => "Dum.Rep.All",
+ ".*AVGAM.*" => "Dum.Rep => average",
+ ".*SUM.*" => "Dum.Rep.Sum => summary",
+}
+# alle Readings werden zum Device "Dum.Rep.All" übertragen, Readingname bleibt im Ziel erhalten
+# Readings mit "AVGAM" im Namen werden zum Device "Dum.Rep" in das Reading "average" übertragen
+# Readings mit "SUM" im Namen werden zum Device "Dum.Rep.Sum" in das Reading "summary" übertragen
+
+
+
+
+
averageCalcForm - legt die Berechnungsvariante für die Ermittlung des Durchschnittswertes mit "averageValue"
fest.