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:
parent
84988f013d
commit
6a866508ec
@ -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>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user