10_EQ3BT: bugfixes and changes

git-svn-id: https://svn.fhem.de/fhem/trunk@12744 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
dominikkarall
2016-12-11 14:51:28 +00:00
parent 7fb9d06059
commit bbe82cee3f
2 changed files with 55 additions and 29 deletions

View File

@@ -1,5 +1,12 @@
# 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.
- bugfix: 10_EQ3BT: better error handling if no notification was received
allow multiple gatttools to be executed in parallel
remove error reading
add errorCounters based on function (update/...)
which will be increased if reading from the thermostat
fails 30 times for one command
remain consumption values after restart
- feature: 98_BOSEST: support shuffle/repeat - feature: 98_BOSEST: support shuffle/repeat
- bugfix: 98_BOSEST: NEW LIBRARY URI::Escape library required - bugfix: 98_BOSEST: NEW LIBRARY URI::Escape library required
support special characters support special characters

View File

@@ -6,10 +6,21 @@
# #
# FHEM module to communicate with EQ-3 Bluetooth thermostats # FHEM module to communicate with EQ-3 Bluetooth thermostats
# #
# Version: 1.1.2 # Version: 1.1.3
# #
############################################################# #############################################################
# #
# v1.1.3 - 20161211
# - BUGFIX: better error handling if no notification was received
# - BUGFIX: update system information fixed
# - CHANGE: allow multiple gatttools to be executed in parallel
# - CHANGE: remove error reading
# - CHANGE: add errorCounters based on function (update/...)
# which will be increased if reading from the thermostat
# fails 30 times for one command
# - BUGFIX: retry mechanism for commands with notifications (updateStatus)
# - BUGFIX: remain consumption values after restart
#
# v1.1.2 - 20161108 # v1.1.2 - 20161108
# - FEATURE: support set <name> eco (eco temperature) # - FEATURE: support set <name> eco (eco temperature)
# - FEATURE: support set <name> comfort (comfort temperature) # - FEATURE: support set <name> comfort (comfort temperature)
@@ -135,13 +146,11 @@ sub EQ3BT_Define($$) {
$hash->{MAC} = $a[2]; $hash->{MAC} = $a[2];
} }
$hash->{helper}{consumptionYesterday} = 0;
BlockingCall("EQ3BT_pairDevice", $name."|".$hash->{MAC}); BlockingCall("EQ3BT_pairDevice", $name."|".$hash->{MAC});
RemoveInternalTimer($hash); RemoveInternalTimer($hash);
InternalTimer(gettimeofday()+60, "EQ3BT_updateStatusWithTimer", $hash, 0); InternalTimer(gettimeofday()+60, "EQ3BT_updateStatusWithTimer", $hash, 0);
InternalTimer(gettimeofday()+20, "EQ3BT_updateSystemInformation", $hash, 0); InternalTimer(gettimeofday()+20, "EQ3BT_updateSystemInformationWithTimer", $hash, 0);
return undef; return undef;
} }
@@ -225,9 +234,14 @@ sub EQ3BT_Set($@) {
sub EQ3BT_updateSystemInformation { sub EQ3BT_updateSystemInformation {
my ($hash) = @_; my ($hash) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
$hash->{helper}{RUNNING_PID} = BlockingCall("EQ3BT_execGatttool", $name."|".$hash->{MAC}."|updateSystemInformation|0x0411|00", "EQ3BT_processGatttoolResult", 300, "EQ3BT_killGatttool", $hash); $hash->{helper}{RUNNING_PID} = BlockingCall("EQ3BT_execGatttool", $name."|".$hash->{MAC}."|updateSystemInformation|0x0411|00|listen", "EQ3BT_processGatttoolResult", 300, "EQ3BT_killGatttool", $hash);
}
sub EQ3BT_updateSystemInformationWithTimer {
my ($hash) = @_;
EQ3BT_updateSystemInformation($hash);
InternalTimer(gettimeofday()+7200+int(rand(180)), "EQ3BT_updateSystemInformation", $hash, 0); InternalTimer(gettimeofday()+7200+int(rand(180)), "EQ3BT_updateSystemInformation", $hash, 0);
return undef;
} }
sub EQ3BT_updateSystemInformationSuccessful { sub EQ3BT_updateSystemInformationSuccessful {
@@ -238,15 +252,15 @@ sub EQ3BT_updateSystemInformationSuccessful {
sub EQ3BT_updateSystemInformationRetry { sub EQ3BT_updateSystemInformationRetry {
my ($hash) = @_; my ($hash) = @_;
EQ3BT_retryGatttool($hash, "updateSystemInformation"); EQ3BT_updateSystemInformation($hash);
return undef; return undef;
} }
### updateStatus ### ### updateStatus ###
sub EQ3BT_updateStatusWithTimer { sub EQ3BT_updateStatusWithTimer {
my ($hash, $donotsettimer) = @_; my ($hash) = @_;
my $name = $hash->{NAME};
$hash->{helper}{RUNNING_PID} = BlockingCall("EQ3BT_execGatttool", $name."|".$hash->{MAC}."|updateStatus|0x0411|03|listen", "EQ3BT_processGatttoolResult", 300, "EQ3BT_killGatttool", $hash); EQ3BT_updateStatus($hash);
InternalTimer(gettimeofday()+160+int(rand(20)), "EQ3BT_updateStatusWithTimer", $hash, 0); InternalTimer(gettimeofday()+160+int(rand(20)), "EQ3BT_updateStatusWithTimer", $hash, 0);
} }
@@ -265,7 +279,7 @@ sub EQ3BT_updateStatusSuccessful {
sub EQ3BT_updateStatusRetry { sub EQ3BT_updateStatusRetry {
my ($hash) = @_; my ($hash) = @_;
EQ3BT_retryGatttool($hash, "updateStatus"); EQ3BT_updateStatus($hash);
return undef; return undef;
} }
@@ -385,7 +399,7 @@ sub EQ3BT_setComfortRetry {
### Gatttool functions ### ### Gatttool functions ###
sub EQ3BT_retryGatttool { sub EQ3BT_retryGatttool {
my ($hash, $workType) = @_; my ($hash, $workType) = @_;
$hash->{helper}{RUNNING_PID} = BlockingCall("EQ3BT_execGatttool", $hash->{NAME}."|".$hash->{MAC}."|$workType|".$hash->{helper}{"handle$workType"}."|".$hash->{helper}{"value$workType"}, "EQ3BT_processGatttoolResult", 60, "EQ3BT_killGatttool", $hash); $hash->{helper}{RUNNING_PID} = BlockingCall("EQ3BT_execGatttool", $hash->{NAME}."|".$hash->{MAC}."|$workType|".$hash->{helper}{"handle$workType"}."|".$hash->{helper}{"value$workType"}."|".$hash->{helper}{"listen$workType"}, "EQ3BT_processGatttoolResult", 60, "EQ3BT_killGatttool", $hash);
return undef; return undef;
} }
@@ -401,10 +415,10 @@ sub EQ3BT_execGatttool($) {
my $gtResult; my $gtResult;
while($wait) { while($wait) {
my $grepGatttool = qx(ps ax| grep \'hcitool\\|gatttool\' | grep -v grep); my $grepGatttool = qx(ps ax| grep \'hcitool\' | grep -v grep);
if(not $grepGatttool =~ /^\s*$/) { if(not $grepGatttool =~ /^\s*$/) {
#another gattool is running #another gattool is running
Log3 $name, 5, "EQ3BT ($name): another gatttool/hcitool process is running. waiting..."; Log3 $name, 5, "EQ3BT ($name): another hcitool process is running. waiting...";
sleep(1); sleep(1);
} else { } else {
$wait = 0; $wait = 0;
@@ -419,7 +433,7 @@ sub EQ3BT_execGatttool($) {
my $cmd = "gatttool -b $mac --char-write-req --handle=$handle --value=$value"; my $cmd = "gatttool -b $mac --char-write-req --handle=$handle --value=$value";
if(defined($listen) && $listen eq "listen") { if(defined($listen) && $listen eq "listen") {
$cmd = "timeout 13 ".$cmd." --listen"; $cmd = "timeout 5 ".$cmd." --listen";
} }
#redirect stderr to stdout #redirect stderr to stdout
@@ -435,7 +449,11 @@ sub EQ3BT_execGatttool($) {
if(defined($gtResultArr[1]) && $gtResultArr[1] =~ /Notification handle = 0x0421 value: (.*)/) { if(defined($gtResultArr[1]) && $gtResultArr[1] =~ /Notification handle = 0x0421 value: (.*)/) {
return "$name|$mac|ok|$workType|$handle|$value|$1"; return "$name|$mac|ok|$workType|$handle|$value|$1";
} else { } else {
return "$name|$mac|ok|$workType|$handle|$value"; if(defined($listen) && $listen eq "listen") {
return "$name|$mac|error|$workType|$handle|$value|notification missing";
} else {
return "$name|$mac|ok|$workType|$handle|$value";
}
} }
} else { } else {
return "$name|$mac|error|$workType|$handle|$value|$workType failed"; return "$name|$mac|error|$workType|$handle|$value|$workType failed";
@@ -464,6 +482,7 @@ sub EQ3BT_processGatttoolResult($) {
$hash->{helper}{"handle$workType"} = $handle; $hash->{helper}{"handle$workType"} = $handle;
$hash->{helper}{"value$workType"} = $value; $hash->{helper}{"value$workType"} = $value;
$hash->{helper}{"listen$workType"} = $notification;
if($ret eq "ok") { if($ret eq "ok") {
#process notification #process notification
@@ -478,14 +497,14 @@ sub EQ3BT_processGatttoolResult($) {
use strict "refs"; use strict "refs";
RemoveInternalTimer($hash, "EQ3BT_".$workType."Retry"); RemoveInternalTimer($hash, "EQ3BT_".$workType."Retry");
$hash->{helper}{"retryCounter$workType"} = 0; $hash->{helper}{"retryCounter$workType"} = 0;
readingsSingleUpdate($hash, "error", "", 1);
} else { } else {
$hash->{helper}{"retryCounter$workType"} = 0 if(!defined($hash->{helper}{"retryCounter$workType"})); $hash->{helper}{"retryCounter$workType"} = 0 if(!defined($hash->{helper}{"retryCounter$workType"}));
$hash->{helper}{"retryCounter$workType"}++; $hash->{helper}{"retryCounter$workType"}++;
Log3 $hash, 4, "EQ3BT ($name): $workType failed ($handle, $value, $notification)"; Log3 $hash, 4, "EQ3BT ($name): $workType failed ($handle, $value, $notification)";
if ($hash->{helper}{"retryCounter$workType"} > 20) { if ($hash->{helper}{"retryCounter$workType"} > 30) {
readingsSingleUpdate($hash, "error", "$workType, $value failed", 1); my $errorCount = ReadingsVal($hash->{NAME}, "errorCount-$workType", 0);
Log3 $hash, 3, "EQ3BT ($name): $workType, $handle, $value failed 20 times."; readingsSingleUpdate($hash, "errorCount-$workType", $errorCount+1, 1);
Log3 $hash, 3, "EQ3BT ($name): $workType, $handle, $value failed 30 times.";
$hash->{helper}{"retryCounter$workType"} = 0; $hash->{helper}{"retryCounter$workType"} = 0;
} else { } else {
InternalTimer(gettimeofday()+5, "EQ3BT_".$workType."Retry", $hash, 0); InternalTimer(gettimeofday()+5, "EQ3BT_".$workType."Retry", $hash, 0);
@@ -536,6 +555,7 @@ sub EQ3BT_processNotification {
my $timeSinceLastChange = ReadingsAge($hash->{NAME}, "valvePosition", 0); my $timeSinceLastChange = ReadingsAge($hash->{NAME}, "valvePosition", 0);
my $consumption = ReadingsVal($hash->{NAME}, "consumption", 0); my $consumption = ReadingsVal($hash->{NAME}, "consumption", 0);
my $consumptionToday = ReadingsVal($hash->{NAME}, "consumptionToday", 0); my $consumptionToday = ReadingsVal($hash->{NAME}, "consumptionToday", 0);
my $consumptionTodaySecSinceLastChange = ReadingsAge($hash->{NAME}, "consumptionToday", 0);
my $oldVal = ReadingsVal($hash->{NAME}, "valvePosition", 0); my $oldVal = ReadingsVal($hash->{NAME}, "valvePosition", 0);
my $consumptionDiff = 0; my $consumptionDiff = 0;
if($timeSinceLastChange < 300) { if($timeSinceLastChange < 300) {
@@ -543,10 +563,9 @@ sub EQ3BT_processNotification {
} }
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
if($yday ne $hash->{helper}{consumptionYesterday}) { if($consumptionTodaySecSinceLastChange > ($hour*3600+$min*60+$sec)) {
$hash->{helper}{consumptionYesterday} = $yday; readingsSingleUpdate($hash, "consumptionYesterday", $consumptionToday + $consumptionDiff/2, 1);
readingsSingleUpdate($hash, "consumptionYesterday", $consumptionToday, 1); readingsSingleUpdate($hash, "consumptionToday", 0 + $consumptionDiff/2, 1);
readingsSingleUpdate($hash, "consumptionToday", 0, 1);
} else { } else {
readingsSingleUpdate($hash, "consumptionToday", sprintf("%.3f", $consumptionToday+$consumptionDiff), 1); readingsSingleUpdate($hash, "consumptionToday", sprintf("%.3f", $consumptionToday+$consumptionDiff), 1);
} }
@@ -655,11 +674,11 @@ sub EQ3BT_Get($$) {
</ul> </ul>
<a name="EQ3BTget" id="EQ3BTget"></a> <a name="EQ3BTget" id="EQ3BTget"></a>
<b>Get</b> <b>Get</b>
<ul> <ul>
<code>n/a</code> <code>n/a</code>
</ul> </ul>
<br> <br>
</ul> </ul>