mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 12:49:34 +00:00
- Softwarebuffer for FHT devices with queuing unsent commands and repeating commands by transmission failure
- FHT low temperatur warning and setting for lowtemp-offset - Change naming for state into warnings git-svn-id: https://svn.fhem.de/fhem/trunk@101 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
72b261d6aa
commit
04a95a803f
@ -348,3 +348,6 @@
|
||||
- feature: webpgm2 output reformatted
|
||||
- feature: webpgm2 can display multiple plots.
|
||||
- feature: FHT lime-protection code discovered by Dirk (7.10)
|
||||
- feature: Softwarebuffer for FHT devices with queuing unsent commands and repeating commands by transmission failure (Dirk 17.10)
|
||||
- feature: FHT low temperatur warning and setting for lowtemp-offset (Dirk 17.10)
|
||||
- change: Change naming for state into warnings (Dirk 17.10)
|
@ -68,7 +68,7 @@ FHZ_Initialize($)
|
||||
$hash->{SetFn} = "FHZ_Set";
|
||||
$hash->{StateFn} = "FHZ_SetState";
|
||||
$hash->{ParseFn} = "FHZ_Parse";
|
||||
$hash->{AttrList}= "do_not_notify:1,0 dummy:1,0 filtertimeout repeater:1,0 showtime:1,0 model:fhz1000,fhz1300 loglevel:0,1,2,3,4,5,6";
|
||||
$hash->{AttrList}= "do_not_notify:1,0 dummy:1,0 filtertimeout repeater:1,0 showtime:1,0 model:fhz1000,fhz1300 loglevel:0,1,2,3,4,5,6 softbuffer softrepeat softmaxretry";
|
||||
}
|
||||
|
||||
#####################################
|
||||
@ -160,6 +160,24 @@ FHZ_Get($@)
|
||||
return "$a[0] $a[1] => $v";
|
||||
}
|
||||
|
||||
#####################################
|
||||
# get the FHZ hardwarebuffer without logentry
|
||||
# and as decimal value
|
||||
sub getFhzBuffer()
|
||||
{
|
||||
my $msg = "Timeout";
|
||||
|
||||
while (index($msg,"Timeout") >= 0) { # try getting FHZ buffer until no Timeout occurs
|
||||
FHZ_Write($defs{FHZ}, "04", "c90185") if(!IsDummy("FHZ"));
|
||||
$msg = FHZ_ReadAnswer($defs{FHZ}, "fhtbuf");
|
||||
}
|
||||
|
||||
my $v = substr($msg, 16, 2);
|
||||
$v = hex $v;
|
||||
|
||||
return "$v";
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
FHZ_SetState($$$$)
|
||||
@ -346,7 +364,8 @@ FHZ_ReadAnswer($$)
|
||||
|
||||
my $buf = $hash->{PortObj}->input();
|
||||
|
||||
Log 5, "FHZ/RAW: " . unpack('H*',$buf);
|
||||
# Log 5, "FHZ/RAW: " . unpack('H*',$buf);
|
||||
Log 4, "FHZ/RAW: " . unpack('H*',$buf);
|
||||
$mfhzdata .= $buf;
|
||||
next if(length($mfhzdata) < 2);
|
||||
|
||||
|
@ -50,7 +50,8 @@ my %codes = (
|
||||
"XX0069" => "measured-temp", # sum of next. two, never "really" sent
|
||||
"420069" => "measured-low",
|
||||
"430069" => "measured-high",
|
||||
"440069" => "state",
|
||||
"440069" => "warnings",
|
||||
"450069" => "manu-temp", # Manuelle Temperatur keine ahnung was das bewirkt
|
||||
"600069" => "year",
|
||||
"610069" => "month",
|
||||
"620069" => "day",
|
||||
@ -59,10 +60,9 @@ my %codes = (
|
||||
"650069" => "init",
|
||||
"820069" => "day-temp",
|
||||
"840069" => "night-temp",
|
||||
"850069" => "unknown_85",
|
||||
"850069" => "lowtemp-offset", # Alarm-Temp.-Differenz
|
||||
"8a0069" => "windowopen-temp",
|
||||
"00002a" => "lime-protection",
|
||||
|
||||
"0000aa" => "code_0000aa",
|
||||
"0000ba" => "code_0000ba",
|
||||
"430079" => "code_430079",
|
||||
@ -86,7 +86,7 @@ my %cantset = (
|
||||
"measured-temp" => 1,
|
||||
"measured-high" => 1,
|
||||
"measured-low" => 1,
|
||||
"state" => 1,
|
||||
"warnings" => 1,
|
||||
"init" => 1,
|
||||
"lime-protection"=>1,
|
||||
|
||||
@ -104,12 +104,25 @@ my %nosetarg = (
|
||||
"refreshvalues" => 1,
|
||||
);
|
||||
|
||||
my %priority = (
|
||||
"desired-temp" => 1,
|
||||
"mode" => 2,
|
||||
"refreshvalues" => 3,
|
||||
"holiday1" => 4,
|
||||
"holiday2" => 5,
|
||||
"day-temp" => 6,
|
||||
"night-temp" => 7,
|
||||
);
|
||||
|
||||
my %c2m = (0 => "auto", 1 => "manual", 2 => "holiday", 3 => "holiday_short");
|
||||
my %m2c; # Reverse c2m
|
||||
my %c2b; # command->button hash (reverse of codes)
|
||||
my %c2bset; # Setteable values
|
||||
my %m2c; # Reverse c2m
|
||||
my %c2b; # command->button hash (reverse of codes)
|
||||
my %c2bset; # Setteable values
|
||||
my %defptr;
|
||||
|
||||
my $timerCheckBufferIsRunning = 0; # set to 1 if the timer is running
|
||||
my $minFhzHardwareBufferSpace = 10; # min. bytes free in hardware buffer before sending commands
|
||||
my $fhzHardwareBufferSpace = 0; # actual hardware buffer space in fhz
|
||||
|
||||
#####################################
|
||||
sub
|
||||
@ -143,29 +156,115 @@ FHT_Initialize($)
|
||||
$hash->{AttrList} = "do_not_notify:0,1 model;fht80b dummy:0,1 showtime:0,1 loglevel:0,1,2,3,4,5,6";
|
||||
}
|
||||
|
||||
|
||||
#####################################
|
||||
sub
|
||||
FHT_Set($@)
|
||||
# Parse the incomming commands and send them via sendCommand to the FHZ
|
||||
# or via toSendbuffer in the Softwarebuffer (queue)
|
||||
#
|
||||
sub FHT_Set($@)
|
||||
{
|
||||
my ($hash, @a) = @_;
|
||||
my $ret = undef;
|
||||
my ($hash, @a) = @_;
|
||||
my $ret = undef;
|
||||
my $arg = "020183" . $hash->{CODE} . $c2bset{$a[1]};
|
||||
my $val = $a[2];
|
||||
|
||||
return "\"set $a[0]\" needs two parameters" if(@a < 2);
|
||||
return "Unknown argument $a[1], choose one of " .
|
||||
join(" ", sort {$c2bset{$a} cmp $c2bset{$b} } keys %c2bset)
|
||||
if(!defined($c2bset{$a[1]}));
|
||||
return "\"set $a[0]\" needs two parameters"
|
||||
if(@a != 3 && !(@a == 2 && $nosetarg{$a[1]}));
|
||||
|
||||
Log GetLogLevel($a[0],2), "FHT set " . join(" ", @a);
|
||||
|
||||
my $arg = "020183" . $hash->{CODE} . $c2bset{$a[1]};
|
||||
if(@a != 3 && !(@a == 2 && $nosetarg{$a[1]}));
|
||||
|
||||
if($a[1] eq "refreshvalues") {
|
||||
|
||||
} elsif ($a[1] =~ m/-temp/) {
|
||||
return "Invalid temperature, use NN.N" if($val !~ m/^\d*\.?\d+$/);
|
||||
|
||||
# additional check for temperature
|
||||
return "Invalid temperature, must between 5.5 and 30.5" if($val < 5.5 || $val > 30.5);
|
||||
|
||||
my $a = int($val*2);
|
||||
$arg .= sprintf("%02x", $a);
|
||||
$ret = sprintf("Rounded temperature to %.1f", $a/2) if($a/2 != $val);
|
||||
$val = sprintf("%.1f", $a/2) if($a/2 != $val);
|
||||
$val = sprintf("%.1f", $val);
|
||||
|
||||
} elsif($a[1] =~ m/-from/ || $a[1] =~ m/-to/) {
|
||||
return "Invalid timeformat, use HH:MM" if($val !~ m/^([0-2]\d):([0-5]\d)/);
|
||||
my $a = ($1*6) + ($2/10);
|
||||
$arg .= sprintf("%02x", $a);
|
||||
|
||||
my $nt = sprintf("%02d:%02d", $1, ($2/10)*10);
|
||||
$val = $nt if($nt ne $val);
|
||||
$ret = "Rounded time to $nt" if($nt ne $val);
|
||||
|
||||
} elsif($a[1] eq "mode") {
|
||||
return "Invalid mode, use one of " . join(" ", sort keys %m2c)
|
||||
if(!defined($m2c{$val}));
|
||||
$arg .= sprintf("%02x", $m2c{$val});
|
||||
|
||||
} elsif ($a[1] eq "lowtemp-offset") {
|
||||
return "Invalid lowtemperature-offset, use N" if($val !~ m/^\d*\.?\d+$/);
|
||||
|
||||
# additional check for temperature
|
||||
return "Invalid lowtemperature-offset, must between 1 and 5" if($val < 1 || $val > 5);
|
||||
|
||||
my $a = int($val);
|
||||
$arg .= sprintf("%02x", $a);
|
||||
$ret = sprintf("Rounded temperature to %d.0", $a) if($a != $val);
|
||||
$val = "$a.0";
|
||||
|
||||
} else { # Holiday1, Holiday2
|
||||
$arg .= sprintf("%02x", $val);
|
||||
}
|
||||
|
||||
my $dev = $hash->{CODE};
|
||||
my $def = $defptr{$dev};
|
||||
my $name = $def->{NAME};
|
||||
my $type = $a[1];
|
||||
my $sbCount = keys(%{$def->{SENDBUFFER}}); # Count of sendbuffer
|
||||
|
||||
# get firsttime hardware buffer of FHZ if $fhzHardwareBufferSpace not set
|
||||
$fhzHardwareBufferSpace = getFhzBuffer () if ($fhzHardwareBufferSpace == 0);
|
||||
|
||||
# set default values for config value attr FHZ softbuffer
|
||||
$attr{FHZ}{softbuffer} = 1 if (!defined($attr{FHZ}{softbuffer}));
|
||||
|
||||
$val = "" if (!defined($val));
|
||||
|
||||
if ( ($sbCount == 0 && $fhzHardwareBufferSpace >= $minFhzHardwareBufferSpace) || $attr{FHZ}{softbuffer} == 0) {
|
||||
sendCommand ($hash, $arg, $name, $type, $val); # send command direct to FHZ
|
||||
} else {
|
||||
|
||||
Log GetLogLevel($name,2), "FHT set $name $type $val (Enqueue to buffer)" if ($fhzHardwareBufferSpace >= $minFhzHardwareBufferSpace);
|
||||
|
||||
Log GetLogLevel($name,2), "Can't send command set $name $type $val. " .
|
||||
"No space left in FHZ hardware buffer." if($fhzHardwareBufferSpace < $minFhzHardwareBufferSpace);
|
||||
|
||||
}
|
||||
|
||||
# only if softbuffer not disabled via config
|
||||
if ($attr{FHZ}{softbuffer} == 1) {
|
||||
toSendbuffer ($hash, $type, $val, $arg, "", 0); # send command also to buffer
|
||||
|
||||
if ($timerCheckBufferIsRunning == 0 && $init_done) {
|
||||
$timerCheckBufferIsRunning = 1; # set $timerCheckBufferIsRunning to 1 to remeber a timer is running
|
||||
InternalTimer(gettimeofday()+70, "timerCheckBuffer", $hash); # start internal Timer to periodical check the buffer
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
# Send command to FHZ
|
||||
#
|
||||
sub sendCommand ($$$$$)
|
||||
{
|
||||
|
||||
my ($hash, $arg, $name, $type, $val) = @_;
|
||||
|
||||
if($type eq "refreshvalues") {
|
||||
# This is special. Without the sleep the next FHT won't send its data
|
||||
if(!IsDummy($a[0])) {
|
||||
if(!IsDummy($name)) {
|
||||
my $havefhz;
|
||||
$havefhz = 1 if($hash->{IODev} && defined($hash->{IODev}->{FD}));
|
||||
|
||||
@ -174,36 +273,40 @@ FHT_Set($@)
|
||||
IOWrite($hash, "04", "c90185"); # Check the fht buffer
|
||||
sleep(1) if($havefhz);
|
||||
}
|
||||
return $ret;
|
||||
|
||||
} elsif($a[1] =~ m/-temp/) {
|
||||
return "Invalid temperature, use NN.N" if($a[2] !~ m/^\d*\.?\d+$/);
|
||||
my $a = int($a[2]*2);
|
||||
$arg .= sprintf("%02x", $a);
|
||||
$ret = "Rounded temperature to " . $a/2 if($a/2 != $a[2]);
|
||||
|
||||
} elsif($a[1] =~ m/-from/ || $a[1] =~ m/-to/) {
|
||||
return "Invalid timeformat, use HH:MM" if($a[2] !~ m/^([0-2]\d):([0-5]\d)/);
|
||||
my $a = ($1*6) + ($2/10);
|
||||
$arg .= sprintf("%02x", $a);
|
||||
|
||||
my $nt = sprintf("%02d:%02d", $1, ($2/10)*10);
|
||||
$ret = "Rounded time to $nt" if($nt ne $a[2]);
|
||||
|
||||
} elsif($a[1] eq "mode") {
|
||||
return "Invalid mode, use one of " . join(" ", sort keys %m2c)
|
||||
if(!defined($m2c{$a[2]}));
|
||||
$arg .= sprintf("%02x", $m2c{$a[2]});
|
||||
|
||||
} else { # Holiday1, Holiday2
|
||||
$arg .= sprintf("%02x", $a[2]);
|
||||
|
||||
} else {
|
||||
IOWrite($hash, "04", $arg) if(!IsDummy($name));
|
||||
}
|
||||
|
||||
IOWrite($hash, "04", $arg) if(!IsDummy($a[0]));
|
||||
return $ret;
|
||||
Log GetLogLevel($name,2), "FHT set $name $type $val";
|
||||
|
||||
# decrease $fhzHardwareBufferSpace for each command sending to the FHZ
|
||||
$fhzHardwareBufferSpace = $fhzHardwareBufferSpace -5 if(!IsDummy($name));
|
||||
}
|
||||
|
||||
|
||||
sub resendCommand ($)
|
||||
{
|
||||
|
||||
my ($buffer) = @_;
|
||||
my $hash = $buffer->{HASH};
|
||||
my $dev = $hash->{CODE};
|
||||
my $def = $defptr{$dev};
|
||||
my $nRetry = $buffer->{RETRY} + 1;
|
||||
|
||||
if ($fhzHardwareBufferSpace > $minFhzHardwareBufferSpace) {
|
||||
Log GetLogLevel($def->{NAME},2), "Resending command to FHT set " . $def->{NAME} . " " . $buffer->{TYPE} . " " . $buffer->{VAL} .
|
||||
" (Retry $nRetry / ". $attr{FHZ}{softmaxretry} . ")";
|
||||
|
||||
sendCommand ($buffer->{HASH}, $buffer->{ARG}, $buffer->{NAME}, $buffer->{TYPE}, $buffer->{VAL});
|
||||
toSendbuffer ($buffer->{HASH}, $buffer->{TYPE}, $buffer->{VAL}, $buffer->{ARG}, $buffer->{KEY}, $nRetry); # send command also to buffer
|
||||
|
||||
} else {
|
||||
Log GetLogLevel($def->{NAME},2), "Can't send command \"set " . $def->{NAME} . " " . $buffer->{TYPE} . " " . $buffer->{VAL} .
|
||||
"\". No space in FHZ hardware buffer left. Resending next time if free bufferspace available.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#####################################
|
||||
sub
|
||||
FHT_SetState($$$$)
|
||||
@ -252,24 +355,24 @@ FHT_Undef($$)
|
||||
sub
|
||||
FHT_Parse($$)
|
||||
{
|
||||
my ($hash,$msg) = @_;
|
||||
my ($hash, $msg) = @_;
|
||||
|
||||
my $dev = substr($msg, 16, 4);
|
||||
my $cde = substr($msg, 20, 6);
|
||||
my $val = substr($msg, 26, 2) if(length($msg) > 26);
|
||||
my $confirm = 0;
|
||||
|
||||
$fhzHardwareBufferSpace = getFhzBuffer () if ($fhzHardwareBufferSpace == 0);
|
||||
|
||||
if(!defined($defptr{$dev})) {
|
||||
Log 3, "FHT Unknown device $dev, please define it";
|
||||
return "UNDEFINED FHT $dev";
|
||||
}
|
||||
|
||||
|
||||
my $def = $defptr{$dev};
|
||||
|
||||
# Unknown, but don't want report it. Should come with c409c401
|
||||
if($cde eq "00") {
|
||||
return "";
|
||||
}
|
||||
return "" if($cde eq "00");
|
||||
|
||||
if(length($cde) < 6) {
|
||||
my $name = $def->{NAME};
|
||||
@ -284,7 +387,18 @@ FHT_Parse($$)
|
||||
# it looks like a real message, and let the rest parse it
|
||||
Log 4, "FHT $def->{NAME} confirmation: $cde)";
|
||||
$val = substr($cde, 2, 2);
|
||||
|
||||
# get the free hardware buffer space in the FHZ after each confirmation message
|
||||
$fhzHardwareBufferSpace = hex substr($cde, 4, 2);
|
||||
|
||||
# increase $fhzHardwareBufferSpace at 5 because the confirmed command is deleted in the FHZ after confirmation
|
||||
$fhzHardwareBufferSpace = $fhzHardwareBufferSpace + 5;
|
||||
Log 4, "FHZ new FHT Buffer: $fhzHardwareBufferSpace";
|
||||
|
||||
$cde = substr($cde, 0, 2) . "0069";
|
||||
|
||||
# set help var to remember this is a confirmation
|
||||
$confirm = 1;
|
||||
}
|
||||
|
||||
my $type;
|
||||
@ -303,7 +417,6 @@ FHT_Parse($$)
|
||||
return $def->{NAME};
|
||||
}
|
||||
|
||||
|
||||
my $tn = TimeNow();
|
||||
|
||||
###########################
|
||||
@ -348,13 +461,26 @@ FHT_Parse($$)
|
||||
} elsif($type =~ m/.*-temp/) {
|
||||
$val = sprintf("%.1f (Celsius)", $val / 2)
|
||||
|
||||
} elsif($type eq "state") {
|
||||
} elsif($type eq "warnings") {
|
||||
|
||||
my $nval;
|
||||
$nval = "Bat: " . (($val & 1) ? "empty" : "ok");
|
||||
$nval .= ", Window: " . (($val & 32) ? "open" : "closed");
|
||||
$nval .= ", Fault: " . (($val & 16) ? "yes" : "no");
|
||||
$val = $nval;
|
||||
my @nVal;
|
||||
$nVal[0] = "Battery low" if ($val & 1);
|
||||
$nVal[1] = "Window open" if ($val & 32);
|
||||
$nVal[2] = "Fault on window sensor" if ($val & 16);
|
||||
$nVal[3] = "Temperature to low" if ($val & 2);
|
||||
|
||||
if ($val > 0) {
|
||||
$val = "";
|
||||
foreach (@nVal) {
|
||||
$val .= "$_; " if (defined($_));
|
||||
}
|
||||
$val = substr($val, 0, length($val)-2);
|
||||
} else {
|
||||
$val = "none";
|
||||
}
|
||||
|
||||
} elsif($type eq "lowtemp-offset") {
|
||||
$val = sprintf("%d.0 (Celsius)", $val)
|
||||
|
||||
} elsif($type =~ m/echo_/) { # Ignore these messages
|
||||
return "";
|
||||
@ -365,9 +491,192 @@ FHT_Parse($$)
|
||||
$def->{READINGS}{$type}{VAL} = $val;
|
||||
|
||||
Log 4, "FHT $def->{NAME} ($type: $val)";
|
||||
|
||||
###########################################################################
|
||||
# here starts the processing the confirmation to control the softwarebuffer
|
||||
#
|
||||
|
||||
$attr{FHZ}{softbuffer} = 1 if (!defined($attr{FHZ}{softbuffer})); # set default values for config value attr FHZ softbuffer
|
||||
|
||||
my $sbCount = keys(%{$def->{SENDBUFFER}}); # count the existing sendbuffer
|
||||
my $nsCount = keys(%{$def->{NOTSEND}}); # count the existing failbuffer
|
||||
|
||||
if ($confirm && ($sbCount > 0 || $nsCount > 0) && $attr{FHZ}{softbuffer} == 1) {
|
||||
$type = "refreshvalues" if ($type eq "init");
|
||||
|
||||
my ($sbPr, $sbTs);
|
||||
my $sbType = "";
|
||||
my $sbVal;
|
||||
my $dKey;
|
||||
|
||||
my ($val2) = split (/\s/, $val);
|
||||
|
||||
# if the confirmation message for a command recive to late
|
||||
# (the command moved to the notsend list yet)
|
||||
# found the specific command ond delete them from the notsend list
|
||||
foreach my $c (sort keys %{$def->{NOTSEND}}) { # go through the notsend list
|
||||
($sbPr, $sbTs, $sbType) = split (/:/, $c);
|
||||
$sbVal = $def->{NOTSEND}->{$c}{VAL};
|
||||
$dKey = $c;
|
||||
|
||||
$sbVal = $val2 if ($type eq "refreshvalues"); # refreshvalues have no value
|
||||
if ($sbType eq $type && $sbVal eq $val2) {
|
||||
|
||||
Log GetLogLevel($def->{NAME},2), "FHT $def->{NAME} late - confirmation ".
|
||||
"($sbType: $sbVal) (delete from NOTSEND)";
|
||||
|
||||
delete($def->{NOTSEND}{$dKey}); # delete command from notsend list
|
||||
last; # we can leave the loop because the command was deleted from the list
|
||||
}
|
||||
}
|
||||
|
||||
# get the next entry from the buffer queue
|
||||
foreach my $c (sort keys %{$def->{SENDBUFFER}}) {
|
||||
($sbPr, $sbTs, $sbType) = split (/:/, $c);
|
||||
$sbVal = $def->{SENDBUFFER}->{$c}{VAL};
|
||||
$dKey = $c;
|
||||
last; # exit foreach because we need the first entry only
|
||||
}
|
||||
|
||||
$sbVal = $val2 if ($type eq "refreshvalues"); # refreshvalues have no value
|
||||
|
||||
# if the actual confirmation message part of the first command in the queue
|
||||
if ($sbType eq $type && $sbVal eq $val2) {
|
||||
delete($def->{SENDBUFFER}{$dKey}); # this buffer entry can deleted
|
||||
|
||||
foreach my $c (sort keys %{$def->{SENDBUFFER}}) { # get the next buffer entry
|
||||
my $nType = $def->{SENDBUFFER}->{$c}{TYPE};
|
||||
my $nArg = $def->{SENDBUFFER}->{$c}{ARG};
|
||||
my $nName = $def->{SENDBUFFER}->{$c}{NAME};
|
||||
my $nHash = $def->{SENDBUFFER}->{$c}{HASH};
|
||||
my $nVal = $def->{SENDBUFFER}->{$c}{VAL};
|
||||
my $nKey = $def->{SENDBUFFER}->{$c}{KEY};
|
||||
|
||||
sendCommand ($nHash, $nArg, $nName, $nType, $nVal); # nächsten Buffereintrag senden
|
||||
toSendbuffer ($nHash, $nType, $nVal, $nArg, $nKey, 0); # send command also to buffer
|
||||
|
||||
last; # exit foreach because we need the next entry only
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# end processing confirmation to control the softwarebuffer
|
||||
###########################################################################
|
||||
|
||||
$def->{CHANGED}[0] = "$type: $val";
|
||||
$def->{STATE} = "$type: $val" if($type eq "measured-temp");
|
||||
return $def->{NAME};
|
||||
}
|
||||
|
||||
# check are commands in softwarebuffer
|
||||
# ans send the next command to the FHZ
|
||||
sub timerCheckBuffer ($)
|
||||
{
|
||||
|
||||
Log 4, "Timer (Checking for unsend FHT commands)";
|
||||
|
||||
my ($hash) = @_;
|
||||
my $bufCount = 0; # help counter
|
||||
my $now = gettimeofday();
|
||||
my $ts = time;
|
||||
|
||||
# set default values for config value attr FHZ softbuffer
|
||||
$attr{FHZ}{softrepeat} = 240 if (!defined($attr{FHZ}{softrepeat}));
|
||||
$attr{FHZ}{softmaxretry} = 3 if (!defined($attr{FHZ}{softmaxretry}));
|
||||
|
||||
# loop to process all FHT devices
|
||||
foreach my $d (keys %defptr) {
|
||||
my $def = $defptr{$d}; # the actual FHT device
|
||||
|
||||
# process all buffer entries
|
||||
foreach my $c (sort keys %{$def->{SENDBUFFER}}) {
|
||||
my ($rPr, undef, $rType) = split (/:/, $c); # priority and type
|
||||
my $rVal = $def->{SENDBUFFER}{$c}{VAL}; # value
|
||||
my $rTs = $def->{SENDBUFFER}{$c}{SENDTIME}; # the time of the sending moment to the FHT
|
||||
my $rRetry = $def->{SENDBUFFER}{$c}{RETRY}; # retry counter
|
||||
$rRetry ++ if ($fhzHardwareBufferSpace > $minFhzHardwareBufferSpace); # increase retrycounter if enough hardwarebuffer available
|
||||
my $rKey = $c; # the bufferkey
|
||||
|
||||
$rVal = "" if (!defined($rVal)); # set value to "" if value not defined (e.g. "refreshvalues" have no value)
|
||||
$bufCount ++; # increase $bufCount
|
||||
|
||||
my $buffer = $def->{SENDBUFFER}{$c}; # actual buffer entry
|
||||
|
||||
# if the forst command in buffer to old, resend them again to the FHZ
|
||||
if ($ts-$rTs > $attr{FHZ}{softrepeat}) {
|
||||
if ($rRetry <= $attr{FHZ}{softmaxretry}) { # resend the command only if the max resend amount not reached
|
||||
resendCommand ($buffer); # resend the actual command
|
||||
} else {
|
||||
# command resend fail after "softmaxretry" attempt to send
|
||||
Log GetLogLevel($def->{NAME},2), $def->{NAME} . " $rType $rVal no confirmation after $rRetry retry";
|
||||
$def->{NOTSEND}{$rKey} = $def->{SENDBUFFER}{$rKey}; # put the buffer entry to the notsend list
|
||||
$def->{NOTSEND}{$rKey}{RETRY} = $rRetry;
|
||||
delete($def->{SENDBUFFER}{$rKey}); # delete command from buffer queue
|
||||
}
|
||||
}
|
||||
last # exit foreach because we need only the first buffer value
|
||||
}
|
||||
}
|
||||
|
||||
if ($bufCount > 0) {
|
||||
Log 4, "Refresh FHT resend timer";
|
||||
InternalTimer(gettimeofday()+70, "timerCheckBuffer", $hash); # restart the internal Timer if any buffer contains commands
|
||||
} else {
|
||||
$timerCheckBufferIsRunning = 0; # remember timer is not running anymore
|
||||
}
|
||||
}
|
||||
|
||||
# set given command tothe internal software buffer
|
||||
# each command queued until the previous command become a confirmation
|
||||
#
|
||||
sub toSendbuffer ($$$$)
|
||||
{
|
||||
|
||||
my ($hash, $type, $val, $arg, $nBufferKey, $retry) = @_;
|
||||
|
||||
if (!$init_done || $attr{FHZ}{softbuffer} == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
my $dev = $hash->{CODE};
|
||||
my $def = $defptr{$dev};
|
||||
|
||||
my $tn = TimeNow(); # Readable time
|
||||
my $ts = time; # Unix timestamp
|
||||
my $pr = 9; # Default priority for command
|
||||
my $sendTime = 0; # Timestamp for last sending command
|
||||
my $sbCount = keys(%{$def->{SENDBUFFER}}); # Count of sendbuffer
|
||||
|
||||
$pr = $priority{$type} if (defined($priority{$type})); # get priority for specific command type
|
||||
$val = "" if (!defined($val));
|
||||
|
||||
if ($sbCount == 0) {
|
||||
$pr = 0; # First command in buffer have always priority 0 (highest)
|
||||
$sendTime = $ts;
|
||||
}
|
||||
|
||||
my $bufferKey = "$pr:$ts:$type"; #Default bufferkey
|
||||
|
||||
# if bufferkey existing. delete the entry and save the entry with a new buffer
|
||||
if ($nBufferKey ne "") {
|
||||
$sendTime = $ts;
|
||||
$bufferKey = $nBufferKey;
|
||||
($pr, $ts, $type) = split (/:/, $bufferKey);
|
||||
delete($def->{SENDBUFFER}{$bufferKey}); # delete "old" bufferentry
|
||||
|
||||
$bufferKey = "0:$ts:$type"; # new bufferkey für new bufferentry
|
||||
}
|
||||
|
||||
$def->{SENDBUFFER}{$bufferKey}{TIME} = $tn;
|
||||
$def->{SENDBUFFER}{$bufferKey}{VAL} = $val;
|
||||
$def->{SENDBUFFER}{$bufferKey}{NAME} = $def->{NAME};
|
||||
$def->{SENDBUFFER}{$bufferKey}{TYPE} = $type;
|
||||
$def->{SENDBUFFER}{$bufferKey}{ARG} = $arg;
|
||||
$def->{SENDBUFFER}{$bufferKey}{SENDTIME} = $sendTime;
|
||||
$def->{SENDBUFFER}{$bufferKey}{RETRY} = $retry;
|
||||
$def->{SENDBUFFER}{$bufferKey}{KEY} = $bufferKey;
|
||||
$def->{SENDBUFFER}{$bufferKey}{HASH} = $hash;
|
||||
}
|
||||
|
||||
1;
|
||||
|
10
fhem/HISTORY
10
fhem/HISTORY
@ -147,3 +147,13 @@
|
||||
- weblinks added. Used by webpgm2 to display more than one plot at once
|
||||
- webpgm2 output reformatted. Using CSS to divide the screen area in 3
|
||||
parts: command line, room-list and rest
|
||||
|
||||
- Dirk Wed Oct 7 12:45:09 MEST 2007
|
||||
- FHT lime-protection code discovered
|
||||
|
||||
- Dirk Wed Oct 18 23:28:00 MEST 2007
|
||||
- Softwarebuffer for FHT devices with queuing unsent commands and
|
||||
repeating commands by transmission failure
|
||||
- FHT low temperatur warning and setting for lowtemp-offset
|
||||
- Change naming for state into warnings
|
||||
Tagged as dirkh_20071019_0
|
@ -56,7 +56,7 @@ You can use all of the following commands in in two ways:
|
||||
<a href="#define">define</a> lamp FS20 8765 01</pre>
|
||||
For other configuration files see the examples subdirectory.<br>
|
||||
<br>
|
||||
</li>
|
||||
</li>
|
||||
|
||||
<li>Through the TCP/IP connection, which you can either use in a "session"
|
||||
(via telnet) or single client command (via fhem.pl). Example:
|
||||
@ -70,7 +70,7 @@ You can use all of the following commands in in two ways:
|
||||
<ul>
|
||||
<code>fhem.pl 7072 "set lamp off"</code>
|
||||
</ul>
|
||||
</li>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
There are three types of commands: "fhem" commands (described in this document),
|
||||
@ -149,7 +149,7 @@ split in multiple lines<br><br>
|
||||
lost. E.g. it makes sense to set the <a href="FHZset">FHTcode</a> in
|
||||
this file or the coordinates of your house via
|
||||
<a href="#at">sunrise_coord</at>
|
||||
</li><br>
|
||||
</li><br>
|
||||
|
||||
<a name="logfile"></a>
|
||||
<li>logfile<br>
|
||||
@ -157,7 +157,7 @@ split in multiple lines<br><br>
|
||||
stdout, in this case the server won't background itself.<br>
|
||||
The logfile name can also take wildcards for easier logfile rotation,
|
||||
see the <a href="#FileLog">FileLog</a> section.
|
||||
</li><br>
|
||||
</li><br>
|
||||
|
||||
<a name="modpath"></a>
|
||||
<li>modpath<br>
|
||||
@ -165,7 +165,7 @@ split in multiple lines<br><br>
|
||||
should <b>not</b> contain the directory FHEM. Every file there with the
|
||||
name pattern <number>_<name>.pm will be loaded in the order
|
||||
of the number.
|
||||
</li><br>
|
||||
</li><br>
|
||||
|
||||
<a name="pidfilename"></a>
|
||||
<li>pidfilename<br>
|
||||
@ -173,12 +173,12 @@ split in multiple lines<br><br>
|
||||
server runs as a daemon, and some distributions would like to check by
|
||||
the pid if we are still running. The file will be deleted upon
|
||||
shutdown.
|
||||
</li><br>
|
||||
</li><br>
|
||||
|
||||
<a name="pidfilename"></a>
|
||||
<li>pidfilename<br>
|
||||
Works for the global "device"<br>
|
||||
</li><br>
|
||||
</li><br>
|
||||
|
||||
<a name="port"></a>
|
||||
<li>port<br>
|
||||
@ -187,14 +187,14 @@ split in multiple lines<br><br>
|
||||
will only listen for connections from the localhost per default. If
|
||||
there is a second value "global" then the server will listen for
|
||||
non-localhost connections too.
|
||||
</li><br>
|
||||
</li><br>
|
||||
|
||||
<a name="statefile"></a>
|
||||
<li>statefile<br>
|
||||
Set the filename where the state and certain <a href="#at">at</a>
|
||||
information will be saved before shutdown. If it is not specified, then
|
||||
no information will be saved.
|
||||
</li><br>
|
||||
</li><br>
|
||||
|
||||
<a name="title"></a>
|
||||
<li>title<br>
|
||||
@ -223,7 +223,7 @@ split in multiple lines<br><br>
|
||||
<li>5 - is for debugging.</li>
|
||||
</ul>
|
||||
Recommended level is 3 for normal use.
|
||||
</li>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<br>
|
||||
@ -328,29 +328,29 @@ split in multiple lines<br><br>
|
||||
Plots on as 1 and off as 0. The corresponding filelog definition
|
||||
for the device fs20dev is:<br>
|
||||
define FileLog fslog fs20dev /var/log/fs20dev-%Y-%U.log
|
||||
</li>
|
||||
</li>
|
||||
<li>fht<br>
|
||||
Plots the measured-temp/desired-temp/actuator lines. The
|
||||
corresponding filelog definitions (for the FHT device named
|
||||
fht1) looks like:<br>
|
||||
define FileLog fhtlog1 fht1:.*(temp|actuator).*
|
||||
/var/log/fht1-%Y-%U.log
|
||||
</li>
|
||||
</li>
|
||||
<li>ks300_1<br>
|
||||
Plots the temperature and rain (per hour and per day) of a
|
||||
ks300. The corresponding filelog definitions (for the KS300
|
||||
device named ks300) looks like:<br>
|
||||
define FileLog ks300log ks300:.*H:.*
|
||||
/var/log/ks300-%Y-%U.log
|
||||
</li>
|
||||
</li>
|
||||
<li>ks300_2<br>
|
||||
Plots the humidity and wind values of a
|
||||
ks300. The corresponding filelog definition is the same as
|
||||
above, both programs evaluate the same log.
|
||||
</li>
|
||||
</li>
|
||||
<li>text<br>
|
||||
Shows the logfile as it is (plain text).
|
||||
</li>
|
||||
</li>
|
||||
</ul>
|
||||
The corresponding gnuplot files (up to the "text" one) must be
|
||||
installed, see the fhemweb.pl configuration for the destination
|
||||
@ -433,9 +433,27 @@ split in multiple lines<br><br>
|
||||
<a name="skip_next"></a>
|
||||
<li>skip_next<br>
|
||||
Can be applied to at devices.<br>
|
||||
Used for at commands: skip the execution of the command the next time.
|
||||
</li><br>
|
||||
Used for at commands: skip the execution of the command the next time.</li><br />
|
||||
|
||||
<a name="softbuffer" id="softbuffer"></a>
|
||||
<li>softbuffer<br />
|
||||
Can be applied to FHZ devices.<br />
|
||||
Used to disable the FHZ softbuffer for FHT deviced (enabled by default).<br />
|
||||
<strong>Note:</strong> By disabling the softbuffer FHEM works like in version 4.1. It is posible to lost commands to FHT devices by overflow the FHZ hardwarebuffer or on transmission failures.<br />
|
||||
<br />
|
||||
<a name="softbuffer" id="softbuffer"></a> </li>
|
||||
<li>softrepeat<br />
|
||||
Can be applied to FHZ devices.<br />
|
||||
Used to set the repeating time while FHEM tries to resend a FHT command which failed (default 240).<br />
|
||||
<strong>Note:</strong> Don't set this time to small. In this case it is posible that the FHZ Hardwarebuffer runs full in a short time. Than it is posible it takes long time to process the following commands. Normaly it should not necesary to change this value.<br />
|
||||
<br />
|
||||
<a name="softbuffer" id="softbuffer"></a> </li>
|
||||
<li>softmaxretry<br />
|
||||
Can be applied to FHZ devices.<br />
|
||||
Used to set the maximal retries in which FHEM try to resend a failed command to FHT devices (default 3).<br />
|
||||
<strong>Note:</strong> Don't set this value to height. In this case it is posible that the FHZ Hardwarebuffer runs full in a short time. Than it is posible it takes long time to process the following commands. Normaly it should not necesary to change this value. <br />
|
||||
<br>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
Examples:
|
||||
@ -443,8 +461,11 @@ split in multiple lines<br><br>
|
||||
<code>attr global verbose 3</code><br>
|
||||
<code>attr lamp room kitchen</code><br>
|
||||
<code>attr lamp dummy</code><br>
|
||||
<code>attr lamp loglevel 6</code><br>
|
||||
</ul>
|
||||
<code>attr lamp loglevel 6</code><br />
|
||||
<br>
|
||||
<code>attr FHZ softbuffer 0 # disable the softbuffer for FHT devices</code><br />
|
||||
<code>attr FHZ softrepeat 300 # resend failed commands to FHT devices after 300 seconds </code><br />
|
||||
<code>attr FHZ softmaxretry 4 # stop resending failed commands to FHT devices after 4 retries.</code> </ul>
|
||||
<br>
|
||||
|
||||
Notes:<br>
|
||||
@ -829,7 +850,7 @@ split in multiple lines<br><br>
|
||||
this case the command will be saved to the statefile (as it
|
||||
considered volatile, i.e. entered by cronjob) and not to the
|
||||
configfile (see the <a href="#save">save</a> command.)
|
||||
</li>
|
||||
</li>
|
||||
|
||||
<li>if the current time is greater then the time specified, then the
|
||||
command will be executed tomorrow. This is why the relative forms
|
||||
@ -842,12 +863,12 @@ split in multiple lines<br><br>
|
||||
file, as in the above example. If you are not using sunrise_coord, then
|
||||
the coordinates for Frankfurt am Main, Germany will be used.
|
||||
You also have to install the Datetime::Event::Sunrise perl module.
|
||||
</li>
|
||||
</li>
|
||||
|
||||
<li>For even more complex date handling you either have to call fhem from
|
||||
cron or filter the date in a perl expression, see the last example and
|
||||
the section <a href="#perl">Perl special</a>.
|
||||
</li>
|
||||
</li>
|
||||
</ul>
|
||||
<br>
|
||||
</ul>
|
||||
@ -992,7 +1013,7 @@ split in multiple lines<br><br>
|
||||
<ul>
|
||||
<li>The mentioned codes are needed for initializing the FHZ1X00</li>
|
||||
<li>The answer for a command is also displayed by <code>list FHZ</code>
|
||||
</li>
|
||||
</li>
|
||||
<li>
|
||||
The FHZ1000PC has a message buffer for the FHT, as it
|
||||
only can send messages to it every 2 (or so) minutes. If the buffer
|
||||
@ -1105,6 +1126,7 @@ split in multiple lines<br><br>
|
||||
2006-11-02 04:13:31 fri-from1 06:00
|
||||
2006-11-02 04:13:31 fri-to1 23:50
|
||||
2006-11-02 04:11:30 init 255
|
||||
2006-11-02 04:13:36 lowtemp-offset 2.0 (Celsius)
|
||||
2006-11-02 10:40:06 measured-high 0
|
||||
2006-11-02 10:40:06 measured-low 211
|
||||
2006-11-02 10:40:06 measured-temp 21.1 (Celsius)
|
||||
@ -1114,18 +1136,18 @@ split in multiple lines<br><br>
|
||||
2006-11-02 04:13:35 night-temp 18.0 (Celsius)
|
||||
2006-11-02 04:13:32 sat-from1 08:00
|
||||
2006-11-02 04:13:33 sat-to1 23:50
|
||||
2006-11-02 10:40:07 state Bat: ok, Window: closed
|
||||
2006-11-02 04:13:34 sun-from1 08:00
|
||||
2006-11-02 04:13:34 sun-to1 23:00
|
||||
2006-11-02 04:13:29 thu-from1 06:00
|
||||
2006-11-02 04:13:29 thu-to1 23:00
|
||||
2006-11-02 04:13:26 tue-from1 06:00
|
||||
2006-11-02 04:13:26 tue-to1 23:00
|
||||
2006-11-02 04:13:36 unknown_85 4
|
||||
2006-11-02 10:40:07 warnings Battery low
|
||||
2006-11-02 04:13:27 wed-from1 06:00
|
||||
2006-11-02 04:13:28 wed-to1 23:00
|
||||
2006-11-02 04:13:36 windowopen-temp 12.0 (Celsius)
|
||||
|
||||
Send buffer:<br /> 2007-10-19 00:31:24 desired-temp 22.5
|
||||
2007-10-19 00:33:20 mode auto<br />
|
||||
</code></pre>
|
||||
</ul>
|
||||
|
||||
@ -1307,7 +1329,7 @@ split in multiple lines<br><br>
|
||||
Notes:
|
||||
<ul>
|
||||
<li>Use reset with care: the device forgets even the housecode.
|
||||
</li>
|
||||
</li>
|
||||
<li>As the FS20 protocol needs about 0.22 seconds to transmit a
|
||||
sequence, a pause of 0.22 seconds is inserted after each command.
|
||||
</li>
|
||||
@ -1377,7 +1399,6 @@ split in multiple lines<br><br>
|
||||
mode
|
||||
holiday1
|
||||
holiday2
|
||||
mode
|
||||
desired-temp
|
||||
day-temp
|
||||
night-temp
|
||||
@ -1386,11 +1407,15 @@ split in multiple lines<br><br>
|
||||
day
|
||||
hour
|
||||
minute
|
||||
refreshvalues</pre>
|
||||
refreshvalues
|
||||
lowtemp-offset
|
||||
</pre>
|
||||
Notes:
|
||||
<ul>
|
||||
<li>All <code>*-temp</code> values need a temperature
|
||||
as argument, which will be rounded to 0.5 Celsius</li>
|
||||
as argument, which will be rounded to 0.5 Celsius.<br />
|
||||
Temperature values
|
||||
must between 5.5 and 30.5 Celsius. Value 5.5 set the actuator to OFF, value 30.5 set the actuator to ON </li>
|
||||
<li><code>mode</code> is one of <code>auto, manual, holiday or
|
||||
holiday_short.<br>If the mode is holiday, then
|
||||
<ul>
|
||||
@ -1402,7 +1427,7 @@ split in multiple lines<br><br>
|
||||
<li>holiday1 sets the time, in 10-minute steps</li>
|
||||
<li>holiday2 sets number of days from now on.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</li>
|
||||
<li>The <code>*-from1/*-from2/*-to1/*-to2</code> valuetypes need a time
|
||||
spec as argument in the HH:MM format. They define the periods, where
|
||||
the day-temp is valid. The minute (MM) will be rounded to 10, and
|
||||
@ -1410,13 +1435,22 @@ split in multiple lines<br><br>
|
||||
<li><code>refreshvalues</code> does not need an argument, but sends a
|
||||
plea to the FHT device, so it may send its parameters. If you want
|
||||
to get these values regularly, then schedule:<br>
|
||||
<code>at +*01:00:00 set <name> refreshvalues</code><br>
|
||||
</li>
|
||||
<code>at +*01:00:00 set <name> refreshvalues</code></li>
|
||||
<li><code>lowtemp-offset</code> need a temperature
|
||||
as argument, which will be rounded to 1.0 Celsius.<br />
|
||||
Temperature values must between 1.0 and 5.0 Celsius.<br />
|
||||
The
|
||||
<code>lowtemp-offset</code> is used for temperature warning (to low temperature in a room within more than 1,5 hours after the last desired-temp changing). The low temperatur warning it relates to the actual desired temperature.<br>
|
||||
</li>
|
||||
<li>The FHT is very economical (or lazy), it receives messages from the
|
||||
FHZ1000 every 2 minutes (or so). Don't be surprized if your command
|
||||
FHZ1x00 every 2 minutes (or so). Don't be surprized if your command
|
||||
is accepted 10 minutes later by the device. See the related
|
||||
<code>fhtbuf</code> entry in the <code><a href="#get">get</a></code>
|
||||
section.
|
||||
section.<br />
|
||||
<li>For FHT devices, FHEM have an internal software buffer for sending commands step by step. This buffer should prevent lost commands. In case of transmission failures FHEM tries to resend commands. You can see the queued unsent and the failed commands with the <a href="#list">list</a> command. If a command don't picked up from a FHT device within a <a href="#softrepeat">given time</a>, the command sends again until <a href="#softmaxretry">softmaxretry</a> reached. <br />
|
||||
<li>To prevent long time waiting for sending important command, there is a priority list. Commands send in this importance:<br />
|
||||
<code>desired-temp, mode, refreshvalues,holiday1,holiday2,day-temp,night-temp, [all other commands]</code> <br />
|
||||
<br />
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
|
@ -31,6 +31,10 @@ Formerly known as fhz1000.pl
|
||||
<li> bugfix: SCIVT solar controller (peterp, 1.7)
|
||||
<li> bugfix: WS300 loglevel change (from 2 to 5 or device specific loglevel)
|
||||
<li> feature: First steps for a Fritz!Box port. See the fritzbox.html
|
||||
<li>feature: FHT lime-protection code discovered by Dirk (7.10)
|
||||
<li>feature: Softwarebuffer for FHT devices with queuing unsent commands and repeating commands by transmission failure (Dirk 17.10)
|
||||
<li> feature: FHT low temperatur warning and setting for lowtemp-offset (Dirk 17.10)
|
||||
<li>change: Change naming for state into warnings (Dirk 17.10)
|
||||
</ul>
|
||||
|
||||
</ul>
|
||||
@ -51,7 +55,9 @@ Currently implemented features:<br>
|
||||
<li>reading and sending FS20 events (on/off/dimming, timer commands)<br>
|
||||
<li>support of FS20 address features function group, local and global master
|
||||
<li>reading and changing FHT80b parameters (temp, actuator, etc).<br>
|
||||
The FHT8b seems to work too. <b>Note:</b> the FHT8 wont work.</li>
|
||||
The FHT8b seems to work too. <b>Note:</b> the FHT8 wont work.<br />
|
||||
For FHT8b devices, FHEM have an internal software buffer for sending commands step by step. This buffer should prevent lost commands. In case of transmission failures FHEM tries to resend commands. <br />
|
||||
</li>
|
||||
<li>reading HMS data (HMS100-T,-TF,-WD,-MG,-TFK and RM100-2)</li>
|
||||
<li>reading KS300 data</li>
|
||||
</ul>
|
||||
|
52
fhem/fhem.pl
52
fhem/fhem.pl
@ -134,7 +134,7 @@ my %intAt; # Internal at timer hash.
|
||||
my $intAtCnt=0;
|
||||
my $reread_active = 0;
|
||||
my $AttrList = "room comment";
|
||||
my $cvsid = '$Id: fhem.pl,v 1.26 2007-09-24 07:09:17 rudolfkoenig Exp $';
|
||||
my $cvsid = '$Id: fhem.pl,v 1.27 2007-10-19 09:29:00 dirkh Exp $';
|
||||
|
||||
$init_done = 0;
|
||||
|
||||
@ -1044,10 +1044,58 @@ CommandList($$)
|
||||
if($r) {
|
||||
$str .= "Readings:\n";
|
||||
foreach my $c (sort keys %{$r}) {
|
||||
$str .= sprintf(" %-19s %-15s %s\n",$r->{$c}{TIME},$c,$r->{$c}{VAL});
|
||||
my $val = "";
|
||||
if (defined($r->{$c}{VAL})) {
|
||||
$val = $r->{$c}{VAL};
|
||||
}
|
||||
$str .= sprintf(" %-19s %-15s %s\n",$r->{$c}{TIME},$c,$val);
|
||||
}
|
||||
}
|
||||
|
||||
$attr{FHZ}{softbuffer} = 1 if (!defined($attr{FHZ}{softbuffer}));
|
||||
|
||||
if ($attr{FHZ}{softbuffer} == 1) {
|
||||
my %lists = (
|
||||
"SENDBUFFER" => "Send buffer",
|
||||
"NOTSEND" => "Send fail list",
|
||||
);
|
||||
|
||||
foreach my $list (keys %lists) {
|
||||
my $l = $d->{$list};
|
||||
if(keys (%{$l}) > 0) {
|
||||
$str .= $lists{$list} .":\n";
|
||||
foreach my $c (sort keys %{$l}) {
|
||||
my (undef, undef, $vC) = split (/:/, $c);
|
||||
# $str .= sprintf(" %-19s %-15s %-10s %s\n",$l->{$c}{TIME},$c,$l->{$c}{VAL},$l->{$c}{SENDTIME});
|
||||
$str .= sprintf(" %-19s %-15s %s\n",$l->{$c}{TIME},$vC,$l->{$c}{VAL});
|
||||
}
|
||||
}
|
||||
|
||||
if ($defs{$param}->{NAME} eq "FHZ") {
|
||||
$str .= $lists{$list} .":\n";
|
||||
|
||||
foreach my $d (sort keys %defs) {
|
||||
my $p = $defs{$d};
|
||||
my $t = $p->{TYPE};
|
||||
|
||||
if ($t eq "FHT") {
|
||||
|
||||
$l = $p->{$list};
|
||||
if(keys (%{$l}) > 0) {
|
||||
foreach my $c (sort keys %{$l}) {
|
||||
my (undef, undef, $vC) = split (/:/, $c);
|
||||
my $val = "";
|
||||
if (defined($l->{$c}{VAL})) {
|
||||
$val = $l->{$c}{VAL};
|
||||
}
|
||||
$str .= sprintf(" %-19s %-15s %-15s %s\n",$l->{$c}{TIME},$p->{NAME},$vC,$val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $str;
|
||||
|
Loading…
Reference in New Issue
Block a user