70_PylonLowVoltage: new attr waitTimeBetweenRS485Cmd
git-svn-id: https://svn.fhem.de/fhem/trunk@29103 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
# 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: 70_PylonLowVoltage: new attr waitTimeBetweenRS485Cmd
|
||||||
- feature: 70_PylonLowVoltage: implement pylon groups
|
- feature: 70_PylonLowVoltage: implement pylon groups
|
||||||
- bugfix: 36_Shelly.pm: reading 'ble' (bluetooth) fixed
|
- bugfix: 36_Shelly.pm: reading 'ble' (bluetooth) fixed
|
||||||
- change: 70_PylonLowVoltage: internal code changes
|
- change: 70_PylonLowVoltage: internal code changes
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ package FHEM::PylonLowVoltage; ## no critic
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use GPUtils qw(GP_Import GP_Export); # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt
|
use GPUtils qw(GP_Import GP_Export); # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt
|
||||||
use Time::HiRes qw(gettimeofday ualarm);
|
use Time::HiRes qw(gettimeofday ualarm sleep);
|
||||||
use IO::Socket::INET;
|
use IO::Socket::INET;
|
||||||
use Errno qw(ETIMEDOUT EWOULDBLOCK);
|
use Errno qw(ETIMEDOUT EWOULDBLOCK);
|
||||||
use Scalar::Util qw(looks_like_number);
|
use Scalar::Util qw(looks_like_number);
|
||||||
@@ -76,6 +76,7 @@ BEGIN {
|
|||||||
AttrNum
|
AttrNum
|
||||||
BlockingCall
|
BlockingCall
|
||||||
BlockingKill
|
BlockingKill
|
||||||
|
devspec2array
|
||||||
data
|
data
|
||||||
defs
|
defs
|
||||||
fhemTimeLocal
|
fhemTimeLocal
|
||||||
@@ -120,6 +121,7 @@ BEGIN {
|
|||||||
|
|
||||||
# Versions History intern (Versions history by Heiko Maaz)
|
# Versions History intern (Versions history by Heiko Maaz)
|
||||||
my %vNotesIntern = (
|
my %vNotesIntern = (
|
||||||
|
"1.1.0" => "25.08.2024 manage time shift for active gateway connections of all defined devices ",
|
||||||
"1.0.0" => "24.08.2024 implement pylon groups ",
|
"1.0.0" => "24.08.2024 implement pylon groups ",
|
||||||
"0.4.0" => "23.08.2024 Log output for timeout changed, automatic calculation of checksum, preparation for pylon groups ",
|
"0.4.0" => "23.08.2024 Log output for timeout changed, automatic calculation of checksum, preparation for pylon groups ",
|
||||||
"0.3.0" => "22.08.2024 extend battery addresses up to 16 ",
|
"0.3.0" => "22.08.2024 extend battery addresses up to 16 ",
|
||||||
@@ -155,6 +157,7 @@ my $definterval = 30; # default A
|
|||||||
my $defto = 0.5; # default connection Timeout zum RS485 Gateway
|
my $defto = 0.5; # default connection Timeout zum RS485 Gateway
|
||||||
my @blackl = qw(state nextCycletime); # Ausnahmeliste deleteReadingspec
|
my @blackl = qw(state nextCycletime); # Ausnahmeliste deleteReadingspec
|
||||||
my $age1def = 60; # default Zyklus Abrufklasse statische Werte (s)
|
my $age1def = 60; # default Zyklus Abrufklasse statische Werte (s)
|
||||||
|
my $wtbRS485cmd = 0.1; # default Wartezeit zwischen RS485 Kommandos
|
||||||
my $pfx = "~"; # KommandoPräfix
|
my $pfx = "~"; # KommandoPräfix
|
||||||
my $sfx = "\x{0d}"; # Kommandosuffix
|
my $sfx = "\x{0d}"; # Kommandosuffix
|
||||||
|
|
||||||
@@ -325,6 +328,7 @@ sub Initialize {
|
|||||||
"interval ".
|
"interval ".
|
||||||
"timeout ".
|
"timeout ".
|
||||||
"userBatterytype ".
|
"userBatterytype ".
|
||||||
|
"waitTimeBetweenRS485Cmd:slider,0.1,0.1,2.0,1 ".
|
||||||
$readingFnAttributes;
|
$readingFnAttributes;
|
||||||
|
|
||||||
eval { FHEM::Meta::InitMod( __FILE__, $hash ) }; ## no critic 'eval'
|
eval { FHEM::Meta::InitMod( __FILE__, $hash ) }; ## no critic 'eval'
|
||||||
@@ -467,7 +471,7 @@ sub Attr {
|
|||||||
InternalTimer(gettimeofday()+1.0, "FHEM::PylonLowVoltage::manageUpdate", $hash, 0);
|
InternalTimer(gettimeofday()+1.0, "FHEM::PylonLowVoltage::manageUpdate", $hash, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($aName eq 'timeout') {
|
if ($aName =~ /timeout|waitTimeBetweenRS485Cmd/xs) {
|
||||||
if (!looks_like_number($aVal)) {
|
if (!looks_like_number($aVal)) {
|
||||||
return qq{The value for $aName is invalid, it must be numeric!};
|
return qq{The value for $aName is invalid, it must be numeric!};
|
||||||
}
|
}
|
||||||
@@ -495,37 +499,54 @@ sub manageUpdate {
|
|||||||
|
|
||||||
my $interval = AttrVal ($name, 'interval', $definterval); # 0 -> manuell gesteuert
|
my $interval = AttrVal ($name, 'interval', $definterval); # 0 -> manuell gesteuert
|
||||||
my $timeout = AttrVal ($name, 'timeout', $defto);
|
my $timeout = AttrVal ($name, 'timeout', $defto);
|
||||||
my $readings;
|
my ($readings, $new);
|
||||||
|
|
||||||
if (!$interval) {
|
if (!$interval) {
|
||||||
$hash->{OPMODE} = 'Manual';
|
$hash->{OPMODE} = 'Manual';
|
||||||
$readings->{nextCycletime} = 'Manual';
|
$readings->{nextCycletime} = 'Manual';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
my $new = gettimeofday() + $interval;
|
$new = gettimeofday() + $interval;
|
||||||
InternalTimer ($new, "FHEM::PylonLowVoltage::manageUpdate", $hash, 0); # Wiederholungsintervall
|
InternalTimer ($new, "FHEM::PylonLowVoltage::manageUpdate", $hash, 0); # Wiederholungsintervall
|
||||||
|
|
||||||
$hash->{OPMODE} = 'Automatic';
|
$hash->{OPMODE} = 'Automatic';
|
||||||
$readings->{nextCycletime} = FmtTime($new);
|
$readings->{nextCycletime} = FmtTime($new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete $hash->{HELPER}{BKRUNNING} if(defined $hash->{HELPER}{BKRUNNING} && $hash->{HELPER}{BKRUNNING}{pid} =~ /DEAD/xs);
|
||||||
|
|
||||||
|
for my $dev ( devspec2array ('TYPE=PylonLowVoltage') ) {
|
||||||
|
if (defined $defs{$dev}->{HELPER}{BKRUNNING} || defined $defs{$dev}->{HELPER}{GWSESSION}) {
|
||||||
|
$hash->{POSTPONED} += 1;
|
||||||
|
|
||||||
|
RemoveInternalTimer ($hash);
|
||||||
|
$new = gettimeofday() + 1;
|
||||||
|
InternalTimer (gettimeofday() + 1, "FHEM::PylonLowVoltage::manageUpdate", $hash, 0);
|
||||||
|
|
||||||
|
$readings->{nextCycletime} = FmtTime ($new);
|
||||||
|
$readings->{state} = "cycle postponed due to active gateway connection of $dev";
|
||||||
|
createReadings ($hash, 1, $readings);
|
||||||
|
|
||||||
|
if (defined $defs{$dev}->{HELPER}{BKRUNNING}) {
|
||||||
|
Log3 ($name, 4, qq{$name - another Gateway Call from $dev with PID "$defs{$dev}->{HELPER}{BKRUNNING}{pid}" is already running ... start Update postponed});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log3 ($name, 4, qq{$name - another Gateway Call from $dev is already running ... start Update postponed});
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Log3 ($name, 4, "$name - START request cycle to battery number >$hash->{BATADDRESS}<, group >$hash->{GROUP}< at host:port $hash->{HOST}:$hash->{PORT}");
|
Log3 ($name, 4, "$name - START request cycle to battery number >$hash->{BATADDRESS}<, group >$hash->{GROUP}< at host:port $hash->{HOST}:$hash->{PORT}");
|
||||||
|
|
||||||
if ($timeout < 1.0) {
|
if ($timeout < 1.0) {
|
||||||
BlockingKill ($hash->{HELPER}{BKRUNNING}) if(defined $hash->{HELPER}{BKRUNNING});
|
$hash->{HELPER}{GWSESSION} = 1;
|
||||||
Log3 ($name, 4, qq{$name - Cycle started in main process with battery read timeout: >$timeout<});
|
Log3 ($name, 4, qq{$name - Cycle started in main process with battery read timeout: >$timeout<});
|
||||||
startUpdate ({name => $name, timeout => $timeout, readings => $readings, age1 => $age1});
|
startUpdate ({name => $name, timeout => $timeout, readings => $readings, age1 => $age1});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
delete $hash->{HELPER}{BKRUNNING} if(defined $hash->{HELPER}{BKRUNNING} && $hash->{HELPER}{BKRUNNING}{pid} =~ /DEAD/xs);
|
my $blto = sprintf "%.0f", ($timeout + (AttrVal ($name, 'waitTimeBetweenRS485Cmd', $wtbRS485cmd) * 15));
|
||||||
|
|
||||||
if (defined $hash->{HELPER}{BKRUNNING}) {
|
|
||||||
Log3 ($name, 3, qq{$name - another BlockingCall PID "$hash->{HELPER}{BKRUNNING}{pid}" is already running ... start Update aborted});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $blto = sprintf "%.0f", ($timeout + 10);
|
|
||||||
|
|
||||||
$hash->{HELPER}{BKRUNNING} = BlockingCall ( "FHEM::PylonLowVoltage::startUpdate",
|
$hash->{HELPER}{BKRUNNING} = BlockingCall ( "FHEM::PylonLowVoltage::startUpdate",
|
||||||
{name => $name, timeout => $timeout, readings => $readings, age1 => $age1, block => 1},
|
{name => $name, timeout => $timeout, readings => $readings, age1 => $age1, block => 1},
|
||||||
@@ -560,12 +581,16 @@ sub startUpdate {
|
|||||||
|
|
||||||
my $hash = $defs{$name};
|
my $hash = $defs{$name};
|
||||||
my $success = 0;
|
my $success = 0;
|
||||||
|
my $wtb = AttrVal ($name, 'waitTimeBetweenRS485Cmd', $wtbRS485cmd); # Wartezeit zwischen RS485 Kommandos
|
||||||
|
my $uat = $block ? $timeout * 1000000 + $wtb * 1000000 : $timeout * 1000000;
|
||||||
|
|
||||||
|
Log3 ($name, 4, "$name - used wait time between RS485 commands: ".($block ? $wtb : 0)." seconds");
|
||||||
|
|
||||||
my ($socket, $serial);
|
my ($socket, $serial);
|
||||||
|
|
||||||
eval { ## no critic 'eval'
|
eval { ## no critic 'eval'
|
||||||
local $SIG{ALRM} = sub { croak 'gatewaytimeout' };
|
local $SIG{ALRM} = sub { croak 'gatewaytimeout' };
|
||||||
ualarm ($timeout * 1000000); # ualarm in Mikrosekunden
|
ualarm ($timeout * 1000000); # ualarm in Mikrosekunden -> 1s
|
||||||
|
|
||||||
$socket = _openSocket ($hash, $timeout, $readings);
|
$socket = _openSocket ($hash, $timeout, $readings);
|
||||||
|
|
||||||
@@ -573,21 +598,33 @@ sub startUpdate {
|
|||||||
$serial = encode_base64 (Serialize ( {name => $name, readings => $readings} ), "");
|
$serial = encode_base64 (Serialize ( {name => $name, readings => $readings} ), "");
|
||||||
$block ? return ($serial) : return \&finishUpdate ($serial);
|
$block ? return ($serial) : return \&finishUpdate ($serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local $SIG{ALRM} = sub { croak 'batterytimeout' };
|
||||||
|
|
||||||
if (ReadingsAge ($name, "serialNumber", 6000) >= $age1) { # Abrufklasse statische Werte
|
if (ReadingsAge ($name, "serialNumber", 6000) >= $age1) { # Abrufklasse statische Werte
|
||||||
|
ualarm ($uat);
|
||||||
|
|
||||||
for my $idx (sort keys %fns1) {
|
for my $idx (sort keys %fns1) {
|
||||||
if (&{$fns1{$idx}{fn}} ($hash, $socket, $readings)) {
|
if (&{$fns1{$idx}{fn}} ($hash, $socket, $readings)) {
|
||||||
$serial = encode_base64 (Serialize ( {name => $name, readings => $readings} ), "");
|
$serial = encode_base64 (Serialize ( {name => $name, readings => $readings} ), "");
|
||||||
$block ? return ($serial) : return \&finishUpdate ($serial);
|
$block ? return ($serial) : return \&finishUpdate ($serial);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ualarm(0);
|
||||||
|
sleep $wtb if($block);
|
||||||
}
|
}
|
||||||
|
|
||||||
for my $idx (sort keys %fns2) { # Abrufklasse dynamische Werte
|
for my $idx (sort keys %fns2) { # Abrufklasse dynamische Werte
|
||||||
|
ualarm ($uat);
|
||||||
|
|
||||||
if (&{$fns2{$idx}{fn}} ($hash, $socket, $readings)) {
|
if (&{$fns2{$idx}{fn}} ($hash, $socket, $readings)) {
|
||||||
$serial = encode_base64 (Serialize ( {name => $name, readings => $readings} ), "");
|
$serial = encode_base64 (Serialize ( {name => $name, readings => $readings} ), "");
|
||||||
$block ? return ($serial) : return \&finishUpdate ($serial);
|
$block ? return ($serial) : return \&finishUpdate ($serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ualarm(0);
|
||||||
|
sleep $wtb if($block);
|
||||||
}
|
}
|
||||||
|
|
||||||
$success = 1;
|
$success = 1;
|
||||||
@@ -596,7 +633,10 @@ sub startUpdate {
|
|||||||
if ($@) {
|
if ($@) {
|
||||||
my $errtxt;
|
my $errtxt;
|
||||||
if ($@ =~ /gatewaytimeout/xs) {
|
if ($@ =~ /gatewaytimeout/xs) {
|
||||||
$errtxt = 'Timeout in communication to RS485 gateway';
|
$errtxt = 'Timeout while establish RS485 gateway connection';
|
||||||
|
}
|
||||||
|
elsif ($@ =~ /batterytimeout/xs) {
|
||||||
|
$errtxt = 'Timeout reading battery';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$errtxt = $@;
|
$errtxt = $@;
|
||||||
@@ -639,7 +679,8 @@ sub finishUpdate {
|
|||||||
my $readings = $paref->{readings};
|
my $readings = $paref->{readings};
|
||||||
my $hash = $defs{$name};
|
my $hash = $defs{$name};
|
||||||
|
|
||||||
delete($hash->{HELPER}{BKRUNNING}) if(defined $hash->{HELPER}{BKRUNNING});
|
delete $hash->{HELPER}{BKRUNNING};
|
||||||
|
delete $hash->{HELPER}{GWSESSION};
|
||||||
|
|
||||||
if ($success) {
|
if ($success) {
|
||||||
Log3 ($name, 4, "$name - got data from battery number >$hash->{BATADDRESS}<, group >$hash->{GROUP}< successfully");
|
Log3 ($name, 4, "$name - got data from battery number >$hash->{BATADDRESS}<, group >$hash->{GROUP}< successfully");
|
||||||
@@ -651,7 +692,7 @@ sub finishUpdate {
|
|||||||
deleteReadingspec ($hash);
|
deleteReadingspec ($hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
createReadings ($hash, $success, $readings); # Readings erstellen
|
createReadings ($hash, $success, $readings); # Readings erstellen
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -666,7 +707,8 @@ sub abortUpdate {
|
|||||||
|
|
||||||
Log3 ($name, 1, "$name -> BlockingCall $hash->{HELPER}{BKRUNNING}{fn} pid:$hash->{HELPER}{BKRUNNING}{pid} aborted: $cause");
|
Log3 ($name, 1, "$name -> BlockingCall $hash->{HELPER}{BKRUNNING}{fn} pid:$hash->{HELPER}{BKRUNNING}{pid} aborted: $cause");
|
||||||
|
|
||||||
delete($hash->{HELPER}{BKRUNNING});
|
delete $hash->{HELPER}{BKRUNNING};
|
||||||
|
delete $hash->{HELPER}{GWSESSION};
|
||||||
|
|
||||||
deleteReadingspec ($hash);
|
deleteReadingspec ($hash);
|
||||||
readingsSingleUpdate ($hash, 'state', 'Update (Child) process timed out', 1);
|
readingsSingleUpdate ($hash, 'state', 'Update (Child) process timed out', 1);
|
||||||
@@ -1750,6 +1792,15 @@ return;
|
|||||||
The automatically determined battery type (Reading batteryType) is replaced by the specified string.
|
The automatically determined battery type (Reading batteryType) is replaced by the specified string.
|
||||||
</li>
|
</li>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
<a id="PylonLowVoltage-attr-waitTimeBetweenRS485Cmd"></a>
|
||||||
|
<li><b>waitTimeBetweenRS485Cmd <Sekunden></b><br>
|
||||||
|
Waiting time between the execution of RS485 commands in seconds. <br>
|
||||||
|
This parameter only has an effect if the “timeout” attribute is set to a value >= 1. <br>
|
||||||
|
(default: 0.1)
|
||||||
|
</li>
|
||||||
|
<br>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<a id="PylonLowVoltage-readings"></a>
|
<a id="PylonLowVoltage-readings"></a>
|
||||||
@@ -1988,6 +2039,15 @@ return;
|
|||||||
Der automatisch ermittelte Batterietyp (Reading batteryType) wird durch die angegebene Zeichenfolge ersetzt.
|
Der automatisch ermittelte Batterietyp (Reading batteryType) wird durch die angegebene Zeichenfolge ersetzt.
|
||||||
</li>
|
</li>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
<a id="PylonLowVoltage-attr-waitTimeBetweenRS485Cmd"></a>
|
||||||
|
<li><b>waitTimeBetweenRS485Cmd <Sekunden></b><br>
|
||||||
|
Wartezeit zwischen der Ausführung von RS485 Befehlen in Sekunden. <br>
|
||||||
|
Dieser Parameter hat nur Auswirkung wenn das Attribut "timeout" auf einen Wert >= 1 gesetzt ist. <br>
|
||||||
|
(default: 0.1)
|
||||||
|
</li>
|
||||||
|
<br>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<a id="PylonLowVoltage-readings"></a>
|
<a id="PylonLowVoltage-readings"></a>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ package FHEM::PylonLowVoltage; ## no critic
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use GPUtils qw(GP_Import GP_Export); # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt
|
use GPUtils qw(GP_Import GP_Export); # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt
|
||||||
use Time::HiRes qw(gettimeofday ualarm);
|
use Time::HiRes qw(gettimeofday ualarm sleep);
|
||||||
use IO::Socket::INET;
|
use IO::Socket::INET;
|
||||||
use Errno qw(ETIMEDOUT EWOULDBLOCK);
|
use Errno qw(ETIMEDOUT EWOULDBLOCK);
|
||||||
use Scalar::Util qw(looks_like_number);
|
use Scalar::Util qw(looks_like_number);
|
||||||
@@ -76,6 +76,7 @@ BEGIN {
|
|||||||
AttrNum
|
AttrNum
|
||||||
BlockingCall
|
BlockingCall
|
||||||
BlockingKill
|
BlockingKill
|
||||||
|
devspec2array
|
||||||
data
|
data
|
||||||
defs
|
defs
|
||||||
fhemTimeLocal
|
fhemTimeLocal
|
||||||
@@ -120,6 +121,7 @@ BEGIN {
|
|||||||
|
|
||||||
# Versions History intern (Versions history by Heiko Maaz)
|
# Versions History intern (Versions history by Heiko Maaz)
|
||||||
my %vNotesIntern = (
|
my %vNotesIntern = (
|
||||||
|
"1.1.0" => "25.08.2024 manage time shift for active gateway connections of all defined devices ",
|
||||||
"1.0.0" => "24.08.2024 implement pylon groups ",
|
"1.0.0" => "24.08.2024 implement pylon groups ",
|
||||||
"0.4.0" => "23.08.2024 Log output for timeout changed, automatic calculation of checksum, preparation for pylon groups ",
|
"0.4.0" => "23.08.2024 Log output for timeout changed, automatic calculation of checksum, preparation for pylon groups ",
|
||||||
"0.3.0" => "22.08.2024 extend battery addresses up to 16 ",
|
"0.3.0" => "22.08.2024 extend battery addresses up to 16 ",
|
||||||
@@ -155,6 +157,7 @@ my $definterval = 30; # default A
|
|||||||
my $defto = 0.5; # default connection Timeout zum RS485 Gateway
|
my $defto = 0.5; # default connection Timeout zum RS485 Gateway
|
||||||
my @blackl = qw(state nextCycletime); # Ausnahmeliste deleteReadingspec
|
my @blackl = qw(state nextCycletime); # Ausnahmeliste deleteReadingspec
|
||||||
my $age1def = 60; # default Zyklus Abrufklasse statische Werte (s)
|
my $age1def = 60; # default Zyklus Abrufklasse statische Werte (s)
|
||||||
|
my $wtbRS485cmd = 0.1; # default Wartezeit zwischen RS485 Kommandos
|
||||||
my $pfx = "~"; # KommandoPräfix
|
my $pfx = "~"; # KommandoPräfix
|
||||||
my $sfx = "\x{0d}"; # Kommandosuffix
|
my $sfx = "\x{0d}"; # Kommandosuffix
|
||||||
|
|
||||||
@@ -325,6 +328,7 @@ sub Initialize {
|
|||||||
"interval ".
|
"interval ".
|
||||||
"timeout ".
|
"timeout ".
|
||||||
"userBatterytype ".
|
"userBatterytype ".
|
||||||
|
"waitTimeBetweenRS485Cmd:slider,0.1,0.1,2.0,1 ".
|
||||||
$readingFnAttributes;
|
$readingFnAttributes;
|
||||||
|
|
||||||
eval { FHEM::Meta::InitMod( __FILE__, $hash ) }; ## no critic 'eval'
|
eval { FHEM::Meta::InitMod( __FILE__, $hash ) }; ## no critic 'eval'
|
||||||
@@ -467,7 +471,7 @@ sub Attr {
|
|||||||
InternalTimer(gettimeofday()+1.0, "FHEM::PylonLowVoltage::manageUpdate", $hash, 0);
|
InternalTimer(gettimeofday()+1.0, "FHEM::PylonLowVoltage::manageUpdate", $hash, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($aName eq 'timeout') {
|
if ($aName =~ /timeout|waitTimeBetweenRS485Cmd/xs) {
|
||||||
if (!looks_like_number($aVal)) {
|
if (!looks_like_number($aVal)) {
|
||||||
return qq{The value for $aName is invalid, it must be numeric!};
|
return qq{The value for $aName is invalid, it must be numeric!};
|
||||||
}
|
}
|
||||||
@@ -495,37 +499,54 @@ sub manageUpdate {
|
|||||||
|
|
||||||
my $interval = AttrVal ($name, 'interval', $definterval); # 0 -> manuell gesteuert
|
my $interval = AttrVal ($name, 'interval', $definterval); # 0 -> manuell gesteuert
|
||||||
my $timeout = AttrVal ($name, 'timeout', $defto);
|
my $timeout = AttrVal ($name, 'timeout', $defto);
|
||||||
my $readings;
|
my ($readings, $new);
|
||||||
|
|
||||||
if (!$interval) {
|
if (!$interval) {
|
||||||
$hash->{OPMODE} = 'Manual';
|
$hash->{OPMODE} = 'Manual';
|
||||||
$readings->{nextCycletime} = 'Manual';
|
$readings->{nextCycletime} = 'Manual';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
my $new = gettimeofday() + $interval;
|
$new = gettimeofday() + $interval;
|
||||||
InternalTimer ($new, "FHEM::PylonLowVoltage::manageUpdate", $hash, 0); # Wiederholungsintervall
|
InternalTimer ($new, "FHEM::PylonLowVoltage::manageUpdate", $hash, 0); # Wiederholungsintervall
|
||||||
|
|
||||||
$hash->{OPMODE} = 'Automatic';
|
$hash->{OPMODE} = 'Automatic';
|
||||||
$readings->{nextCycletime} = FmtTime($new);
|
$readings->{nextCycletime} = FmtTime($new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete $hash->{HELPER}{BKRUNNING} if(defined $hash->{HELPER}{BKRUNNING} && $hash->{HELPER}{BKRUNNING}{pid} =~ /DEAD/xs);
|
||||||
|
|
||||||
|
for my $dev ( devspec2array ('TYPE=PylonLowVoltage') ) {
|
||||||
|
if (defined $defs{$dev}->{HELPER}{BKRUNNING} || defined $defs{$dev}->{HELPER}{GWSESSION}) {
|
||||||
|
$hash->{POSTPONED} += 1;
|
||||||
|
|
||||||
|
RemoveInternalTimer ($hash);
|
||||||
|
$new = gettimeofday() + 1;
|
||||||
|
InternalTimer (gettimeofday() + 1, "FHEM::PylonLowVoltage::manageUpdate", $hash, 0);
|
||||||
|
|
||||||
|
$readings->{nextCycletime} = FmtTime ($new);
|
||||||
|
$readings->{state} = "cycle postponed due to active gateway connection of $dev";
|
||||||
|
createReadings ($hash, 1, $readings);
|
||||||
|
|
||||||
|
if (defined $defs{$dev}->{HELPER}{BKRUNNING}) {
|
||||||
|
Log3 ($name, 4, qq{$name - another Gateway Call from $dev with PID "$defs{$dev}->{HELPER}{BKRUNNING}{pid}" is already running ... start Update postponed});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log3 ($name, 4, qq{$name - another Gateway Call from $dev is already running ... start Update postponed});
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Log3 ($name, 4, "$name - START request cycle to battery number >$hash->{BATADDRESS}<, group >$hash->{GROUP}< at host:port $hash->{HOST}:$hash->{PORT}");
|
Log3 ($name, 4, "$name - START request cycle to battery number >$hash->{BATADDRESS}<, group >$hash->{GROUP}< at host:port $hash->{HOST}:$hash->{PORT}");
|
||||||
|
|
||||||
if ($timeout < 1.0) {
|
if ($timeout < 1.0) {
|
||||||
BlockingKill ($hash->{HELPER}{BKRUNNING}) if(defined $hash->{HELPER}{BKRUNNING});
|
$hash->{HELPER}{GWSESSION} = 1;
|
||||||
Log3 ($name, 4, qq{$name - Cycle started in main process with battery read timeout: >$timeout<});
|
Log3 ($name, 4, qq{$name - Cycle started in main process with battery read timeout: >$timeout<});
|
||||||
startUpdate ({name => $name, timeout => $timeout, readings => $readings, age1 => $age1});
|
startUpdate ({name => $name, timeout => $timeout, readings => $readings, age1 => $age1});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
delete $hash->{HELPER}{BKRUNNING} if(defined $hash->{HELPER}{BKRUNNING} && $hash->{HELPER}{BKRUNNING}{pid} =~ /DEAD/xs);
|
my $blto = sprintf "%.0f", ($timeout + (AttrVal ($name, 'waitTimeBetweenRS485Cmd', $wtbRS485cmd) * 15));
|
||||||
|
|
||||||
if (defined $hash->{HELPER}{BKRUNNING}) {
|
|
||||||
Log3 ($name, 3, qq{$name - another BlockingCall PID "$hash->{HELPER}{BKRUNNING}{pid}" is already running ... start Update aborted});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $blto = sprintf "%.0f", ($timeout + 10);
|
|
||||||
|
|
||||||
$hash->{HELPER}{BKRUNNING} = BlockingCall ( "FHEM::PylonLowVoltage::startUpdate",
|
$hash->{HELPER}{BKRUNNING} = BlockingCall ( "FHEM::PylonLowVoltage::startUpdate",
|
||||||
{name => $name, timeout => $timeout, readings => $readings, age1 => $age1, block => 1},
|
{name => $name, timeout => $timeout, readings => $readings, age1 => $age1, block => 1},
|
||||||
@@ -560,12 +581,16 @@ sub startUpdate {
|
|||||||
|
|
||||||
my $hash = $defs{$name};
|
my $hash = $defs{$name};
|
||||||
my $success = 0;
|
my $success = 0;
|
||||||
|
my $wtb = AttrVal ($name, 'waitTimeBetweenRS485Cmd', $wtbRS485cmd); # Wartezeit zwischen RS485 Kommandos
|
||||||
|
my $uat = $block ? $timeout * 1000000 + $wtb * 1000000 : $timeout * 1000000;
|
||||||
|
|
||||||
|
Log3 ($name, 4, "$name - used wait time between RS485 commands: ".($block ? $wtb : 0)." seconds");
|
||||||
|
|
||||||
my ($socket, $serial);
|
my ($socket, $serial);
|
||||||
|
|
||||||
eval { ## no critic 'eval'
|
eval { ## no critic 'eval'
|
||||||
local $SIG{ALRM} = sub { croak 'gatewaytimeout' };
|
local $SIG{ALRM} = sub { croak 'gatewaytimeout' };
|
||||||
ualarm ($timeout * 1000000); # ualarm in Mikrosekunden
|
ualarm ($timeout * 1000000); # ualarm in Mikrosekunden -> 1s
|
||||||
|
|
||||||
$socket = _openSocket ($hash, $timeout, $readings);
|
$socket = _openSocket ($hash, $timeout, $readings);
|
||||||
|
|
||||||
@@ -573,21 +598,33 @@ sub startUpdate {
|
|||||||
$serial = encode_base64 (Serialize ( {name => $name, readings => $readings} ), "");
|
$serial = encode_base64 (Serialize ( {name => $name, readings => $readings} ), "");
|
||||||
$block ? return ($serial) : return \&finishUpdate ($serial);
|
$block ? return ($serial) : return \&finishUpdate ($serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local $SIG{ALRM} = sub { croak 'batterytimeout' };
|
||||||
|
|
||||||
if (ReadingsAge ($name, "serialNumber", 6000) >= $age1) { # Abrufklasse statische Werte
|
if (ReadingsAge ($name, "serialNumber", 6000) >= $age1) { # Abrufklasse statische Werte
|
||||||
|
ualarm ($uat);
|
||||||
|
|
||||||
for my $idx (sort keys %fns1) {
|
for my $idx (sort keys %fns1) {
|
||||||
if (&{$fns1{$idx}{fn}} ($hash, $socket, $readings)) {
|
if (&{$fns1{$idx}{fn}} ($hash, $socket, $readings)) {
|
||||||
$serial = encode_base64 (Serialize ( {name => $name, readings => $readings} ), "");
|
$serial = encode_base64 (Serialize ( {name => $name, readings => $readings} ), "");
|
||||||
$block ? return ($serial) : return \&finishUpdate ($serial);
|
$block ? return ($serial) : return \&finishUpdate ($serial);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ualarm(0);
|
||||||
|
sleep $wtb if($block);
|
||||||
}
|
}
|
||||||
|
|
||||||
for my $idx (sort keys %fns2) { # Abrufklasse dynamische Werte
|
for my $idx (sort keys %fns2) { # Abrufklasse dynamische Werte
|
||||||
|
ualarm ($uat);
|
||||||
|
|
||||||
if (&{$fns2{$idx}{fn}} ($hash, $socket, $readings)) {
|
if (&{$fns2{$idx}{fn}} ($hash, $socket, $readings)) {
|
||||||
$serial = encode_base64 (Serialize ( {name => $name, readings => $readings} ), "");
|
$serial = encode_base64 (Serialize ( {name => $name, readings => $readings} ), "");
|
||||||
$block ? return ($serial) : return \&finishUpdate ($serial);
|
$block ? return ($serial) : return \&finishUpdate ($serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ualarm(0);
|
||||||
|
sleep $wtb if($block);
|
||||||
}
|
}
|
||||||
|
|
||||||
$success = 1;
|
$success = 1;
|
||||||
@@ -596,7 +633,10 @@ sub startUpdate {
|
|||||||
if ($@) {
|
if ($@) {
|
||||||
my $errtxt;
|
my $errtxt;
|
||||||
if ($@ =~ /gatewaytimeout/xs) {
|
if ($@ =~ /gatewaytimeout/xs) {
|
||||||
$errtxt = 'Timeout in communication to RS485 gateway';
|
$errtxt = 'Timeout while establish RS485 gateway connection';
|
||||||
|
}
|
||||||
|
elsif ($@ =~ /batterytimeout/xs) {
|
||||||
|
$errtxt = 'Timeout reading battery';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$errtxt = $@;
|
$errtxt = $@;
|
||||||
@@ -639,7 +679,8 @@ sub finishUpdate {
|
|||||||
my $readings = $paref->{readings};
|
my $readings = $paref->{readings};
|
||||||
my $hash = $defs{$name};
|
my $hash = $defs{$name};
|
||||||
|
|
||||||
delete($hash->{HELPER}{BKRUNNING}) if(defined $hash->{HELPER}{BKRUNNING});
|
delete $hash->{HELPER}{BKRUNNING};
|
||||||
|
delete $hash->{HELPER}{GWSESSION};
|
||||||
|
|
||||||
if ($success) {
|
if ($success) {
|
||||||
Log3 ($name, 4, "$name - got data from battery number >$hash->{BATADDRESS}<, group >$hash->{GROUP}< successfully");
|
Log3 ($name, 4, "$name - got data from battery number >$hash->{BATADDRESS}<, group >$hash->{GROUP}< successfully");
|
||||||
@@ -651,7 +692,7 @@ sub finishUpdate {
|
|||||||
deleteReadingspec ($hash);
|
deleteReadingspec ($hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
createReadings ($hash, $success, $readings); # Readings erstellen
|
createReadings ($hash, $success, $readings); # Readings erstellen
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -666,7 +707,8 @@ sub abortUpdate {
|
|||||||
|
|
||||||
Log3 ($name, 1, "$name -> BlockingCall $hash->{HELPER}{BKRUNNING}{fn} pid:$hash->{HELPER}{BKRUNNING}{pid} aborted: $cause");
|
Log3 ($name, 1, "$name -> BlockingCall $hash->{HELPER}{BKRUNNING}{fn} pid:$hash->{HELPER}{BKRUNNING}{pid} aborted: $cause");
|
||||||
|
|
||||||
delete($hash->{HELPER}{BKRUNNING});
|
delete $hash->{HELPER}{BKRUNNING};
|
||||||
|
delete $hash->{HELPER}{GWSESSION};
|
||||||
|
|
||||||
deleteReadingspec ($hash);
|
deleteReadingspec ($hash);
|
||||||
readingsSingleUpdate ($hash, 'state', 'Update (Child) process timed out', 1);
|
readingsSingleUpdate ($hash, 'state', 'Update (Child) process timed out', 1);
|
||||||
@@ -1750,6 +1792,15 @@ return;
|
|||||||
The automatically determined battery type (Reading batteryType) is replaced by the specified string.
|
The automatically determined battery type (Reading batteryType) is replaced by the specified string.
|
||||||
</li>
|
</li>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
<a id="PylonLowVoltage-attr-waitTimeBetweenRS485Cmd"></a>
|
||||||
|
<li><b>waitTimeBetweenRS485Cmd <Sekunden></b><br>
|
||||||
|
Waiting time between the execution of RS485 commands in seconds. <br>
|
||||||
|
This parameter only has an effect if the “timeout” attribute is set to a value >= 1. <br>
|
||||||
|
(default: 0.1)
|
||||||
|
</li>
|
||||||
|
<br>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<a id="PylonLowVoltage-readings"></a>
|
<a id="PylonLowVoltage-readings"></a>
|
||||||
@@ -1988,6 +2039,15 @@ return;
|
|||||||
Der automatisch ermittelte Batterietyp (Reading batteryType) wird durch die angegebene Zeichenfolge ersetzt.
|
Der automatisch ermittelte Batterietyp (Reading batteryType) wird durch die angegebene Zeichenfolge ersetzt.
|
||||||
</li>
|
</li>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
<a id="PylonLowVoltage-attr-waitTimeBetweenRS485Cmd"></a>
|
||||||
|
<li><b>waitTimeBetweenRS485Cmd <Sekunden></b><br>
|
||||||
|
Wartezeit zwischen der Ausführung von RS485 Befehlen in Sekunden. <br>
|
||||||
|
Dieser Parameter hat nur Auswirkung wenn das Attribut "timeout" auf einen Wert >= 1 gesetzt ist. <br>
|
||||||
|
(default: 0.1)
|
||||||
|
</li>
|
||||||
|
<br>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<a id="PylonLowVoltage-readings"></a>
|
<a id="PylonLowVoltage-readings"></a>
|
||||||
|
|||||||
Reference in New Issue
Block a user