2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-25 09:49:20 +00:00

98_ComfoAir: Bugfixes

git-svn-id: https://svn.fhem.de/fhem/trunk@24283 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
StefanStrobel 2021-04-19 17:29:06 +00:00
parent 84988f013d
commit 6a866508ec

View File

@ -29,6 +29,12 @@
############################################################################## ##############################################################################
# 2014-04-18 initial version # 2014-04-18 initial version
#
# todo:
# - tests for interval timer and queue timer
# - Timeout-Timer as feature in utils
#
package ComfoAir; package ComfoAir;
use strict; use strict;
@ -108,7 +114,7 @@ BEGIN {
)); ));
}; };
my $Module_Version = '2.01 - 31.3.2021'; my $Module_Version = '2.03 - 13.4.2021';
# %parseInfo: # %parseInfo:
# replyCode => msgHashRef # replyCode => msgHashRef
@ -295,6 +301,7 @@ sub Initialize {
$hash->{UndefFn} = \&ComfoAir::UndefFn; $hash->{UndefFn} = \&ComfoAir::UndefFn;
$hash->{SetFn} = \&ComfoAir::SetFn; $hash->{SetFn} = \&ComfoAir::SetFn;
$hash->{GetFn} = \&ComfoAir::GetFn; $hash->{GetFn} = \&ComfoAir::GetFn;
$hash->{AttrFn} = \&ComfoAir::AttrFn;
@setList = (); @setList = ();
@getList = (); @getList = ();
@ -358,10 +365,10 @@ sub Initialize {
} }
} }
$hash->{AttrList}= "do_not_notify:1,0 " . $hash->{AttrList}= "do_not_notify:1,0 " .
"queueDelay " . 'queueDelay ' .
"timeout " . 'timeout ' .
"queueMax " . 'queueMax ' .
#"minSendDelay " . 'alignTime' .
join (" ", @pollList) . " " . # Def der zyklisch abzufragenden Nachrichten join (" ", @pollList) . " " . # Def der zyklisch abzufragenden Nachrichten
$main::readingFnAttributes; $main::readingFnAttributes;
return; return;
@ -387,12 +394,12 @@ sub DefineFn {
DevIo_OpenDev($hash, 0, 0); DevIo_OpenDev($hash, 0, 0);
} }
if (!$interval) { if (!$interval) {
$hash->{INTERVAL} = 0; $hash->{Interval} = 0;
Log3 $name, 3, "$name: interval is 0 or not specified - not sending requests - just listening!"; Log3 $name, 3, "$name: interval is 0 or not specified - not sending requests - just listening!";
} }
else { else {
$hash->{INTERVAL} = $interval; $hash->{Interval} = $interval;
InternalTimer(gettimeofday()+1, "GetUpdate", $hash, 0); UpdateTimer($hash, \&ComfoAir::GetUpdate, 'start');
} }
Log3 $name, 3, "$name: Defined with device $dev" . ($interval ? ", interval $interval" : ''); Log3 $name, 3, "$name: Defined with device $dev" . ($interval ? ", interval $interval" : '');
return; return;
@ -405,8 +412,38 @@ sub UndefFn {
my $name = $hash->{NAME}; my $name = $hash->{NAME};
DevIo_CloseDev($hash); DevIo_CloseDev($hash);
RemoveInternalTimer ("timeout:".$name); RemoveInternalTimer ("timeout:".$name);
RemoveInternalTimer ("queue:".$name); StopQueueTimer($hash, {silent => 1});
RemoveInternalTimer ($hash); UpdateTimer($hash, \&ComfoAir::GetUpdate, 'stop');
return;
}
#########################################################################
# Attr command
# if validation fails, return something so CommandAttr in fhem.pl doesn't assign a value to $attr
sub AttrFn {
my $cmd = shift; # 'set' or 'del'
my $name = shift; # the Fhem device name
my $aName = shift; # attribute name
my $aVal = shift // ''; # attribute value
my $hash = $defs{$name}; # reference to the Fhem device hash
Log3 $name, 5, "$name: attr $name $aName $aVal";
if ($cmd eq 'set') {
if ($aName eq 'alignTime') {
my ($alErr, $alHr, $alMin, $alSec, undef) = GetTimeSpec($aVal);
return "Invalid Format $aVal in $aName : $alErr" if ($alErr);
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
$hash->{'.TimeAlign'} = fhemTimeLocal($alSec, $alMin, $alHr, $mday, $mon, $year);
UpdateTimer($hash, \&ComfoAir::GetUpdate, 'start'); # change timer for alignment
}
}
elsif ($cmd eq 'del') { # Deletion of Attributes
#Log3 $name, 5, "$name: del attribute $aName";
if ($aName eq 'alignTime') {
delete $hash->{'.TimeAlign'};
}
}
return; return;
} }
@ -553,14 +590,13 @@ sub ParseFrames {
} }
# ACK? # ACK?
elsif ($frame =~ /\x07\xf3(.*)/s) { elsif ($frame =~ /\x07\xf3(.*)/s) {
my $level = ($hash->{INTERVAL} ? 4 : 5); my $level = ($hash->{Interval} ? 4 : 5);
Log3 $name, $level, "$name: read got Ack"; Log3 $name, $level, "$name: read got Ack";
$hash->{helper}{buffer} = $1; # only keep the rest after the frame $hash->{helper}{buffer} = $1; # only keep the rest after the frame
if (!$hash->{EXPECT}) { if (!$hash->{EXPECT}) {
$hash->{BUSY} = 0; $hash->{BUSY} = 0;
# es wird keine weitere Antwort erwartet -> gleich weiter Send Queue abarbeiten und nicht auf alten Timer warten # es wird keine weitere Antwort erwartet -> gleich weiter Send Queue abarbeiten und nicht auf alten Timer warten
RemoveInternalTimer ("timeout:".$name); RemoveInternalTimer ("timeout:".$name);
RemoveInternalTimer ("queue:".$name);
HandleSendQueue ("direct:".$name); # don't wait for next regular handle queue slot HandleSendQueue ("direct:".$name); # don't wait for next regular handle queue slot
} }
} }
@ -644,7 +680,7 @@ sub InterpretFrame {
} }
} }
} else { } else {
my $level = ($hash->{INTERVAL} ? 4 : 5); my $level = ($hash->{Interval} ? 4 : 5);
Log3 $name, $level, "$name: read: unknown cmd $hexcmd, len " . unpack ('C', $len) . Log3 $name, $level, "$name: read: unknown cmd $hexcmd, len " . unpack ('C', $len) .
", data $hexdata, chk $chk"; ", data $hexdata, chk $chk";
} }
@ -652,19 +688,19 @@ sub InterpretFrame {
# der letzte Request erwartet eine Antwort -> ist sie das? # der letzte Request erwartet eine Antwort -> ist sie das?
if ($hexcmd eq $hash->{EXPECT}) { if ($hexcmd eq $hash->{EXPECT}) {
$hash->{BUSY} = 0; $hash->{BUSY} = 0;
$hash->{EXPECT} = ""; $hash->{EXPECT} = '';
Log3 $name, 5, "$name: read got expected reply ($hexcmd), setting BUSY=0"; Log3 $name, 5, "$name: read got expected reply ($hexcmd), setting BUSY=0";
} else { } else {
Log3 $name, 3, "$name: read did not get expected reply (" . $hash->{EXPECT} . ") but $hexcmd"; Log3 $name, 3, "$name: read did not get expected reply (" . $hash->{EXPECT} . ") but $hexcmd";
} }
} }
SendAck($hash) if ($hash->{INTERVAL}); SendAck($hash) if ($hash->{Interval});
# todo: sowohl hier als auch am Ende von ParseFrames wird HandleSendQueue aufgerufen. Geht das nicht eleganter?
if (!$hash->{EXPECT}) { if (!$hash->{EXPECT}) {
# es wird keine Antwort mehr erwartet -> gleich weiter Send Queue abarbeiten und nicht auf Timer warten # es wird keine Antwort mehr erwartet -> gleich weiter Send Queue abarbeiten und nicht auf Timer warten
$hash->{BUSY} = 0; # zur Sicherheit falls ein Ack versäumt wurde $hash->{BUSY} = 0; # zur Sicherheit falls ein Ack versäumt wurde
RemoveInternalTimer ("timeout:".$name); RemoveInternalTimer ("timeout:".$name);
RemoveInternalTimer ("queue:".$name);
HandleSendQueue ("direct:".$name); # don't wait for next regular handle queue slot HandleSendQueue ("direct:".$name); # don't wait for next regular handle queue slot
} }
return; return;
@ -799,10 +835,11 @@ sub ReadyFn {
##################################### #####################################
sub GetUpdate { sub GetUpdate {
my ($hash) = @_; my $arg = shift; # called with a string type:$name
my $name = $hash->{NAME}; my ($calltype, $name) = split(':', $arg);
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "GetUpdate", $hash, 0) my $hash = $defs{$name};
if ($hash->{INTERVAL});
UpdateTimer($hash, \&ComfoAir::GetUpdate, 'next');
foreach my $msgHashRef (values %parseInfo) { foreach my $msgHashRef (values %parseInfo) {
if (defined($msgHashRef->{request})) { if (defined($msgHashRef->{request})) {
@ -881,21 +918,18 @@ sub HandleSendQueue {
my $param = shift; my $param = shift;
my (undef,$name) = split(':',$param); my (undef,$name) = split(':',$param);
my $hash = $defs{$name}; my $hash = $defs{$name};
my $arr = $hash->{QUEUE};
my $now = gettimeofday(); my $now = gettimeofday();
my $queueDelay = AttrVal($name, "queueDelay", 1); my $arr = $hash->{QUEUE};
Log3 $name, 5, "$name: handle send queue"; my $qlen = ($arr ? scalar(@{ $arr }) : 0 );
if(defined($arr) && @{$arr} > 0) { Log3 $name, 5, "$name: HandleSendQueue called from " . FhemCaller() . ", qlen = $qlen";
StopQueueTimer($hash, {silent => 1});
if($qlen) {
if (!$init_done) { # fhem not initialized, wait with IO if (!$init_done) { # fhem not initialized, wait with IO
RemoveInternalTimer ("queue:".$name); StartQueueTimer($hash, \&ComfoAir::HandleSendQueue, {log => 'init not done, delay sending from queue'});
InternalTimer($now+$queueDelay, "ComfoAir::HandleSendQueue", "queue:".$name, 0);
Log3 $name, 3, "$name: init not done, delay writing from queue";
return; return;
} }
if ($hash->{BUSY}) { # still waiting for reply to last request if ($hash->{BUSY}) { # still waiting for reply to last request
RemoveInternalTimer ("queue:".$name); StartQueueTimer($hash, \&ComfoAir::HandleSendQueue, {log => 'send busy, delay writing from queue'});
InternalTimer($now+$queueDelay, "ComfoAir::HandleSendQueue", "queue:".$name, 0);
Log3 $name, 5, "$name: send busy, delay writing from queue";
return; return;
} }
@ -932,8 +966,7 @@ sub HandleSendQueue {
if(@{$arr} == 0) { # last item was sent -> delete queue if(@{$arr} == 0) { # last item was sent -> delete queue
delete($hash->{QUEUE}); delete($hash->{QUEUE});
} else { # more items in queue -> schedule next handle invocation } else { # more items in queue -> schedule next handle invocation
RemoveInternalTimer ("queue:".$name); StartQueueTimer($hash, \&ComfoAir::HandleSendQueue);
InternalTimer($now+$queueDelay, "ComfoAir::HandleSendQueue", "queue:".$name, 0);
} }
} }
return; return;
@ -1126,6 +1159,10 @@ sub SendAck {
max length of the send queue, defaults to 50<br> max length of the send queue, defaults to 50<br>
<li><b>timeout</b></li> <li><b>timeout</b></li>
set the timeout for reads, defaults to 2 seconds <br> set the timeout for reads, defaults to 2 seconds <br>
<li><b>alignTime</b></li>
Aligns each periodic read request for the defined interval to this base time. This is typcally something like 00:00 (see the Fhem at command)
<br>
</ul> </ul>
<br> <br>
</ul> </ul>