fix temperature bug if temp negativ

rewrite parts of code
This commit is contained in:
Marko Oldenburg 2022-01-15 20:43:08 +01:00
parent 2468631700
commit 3dce1c8328

View File

@ -1,8 +1,8 @@
############################################################################### ###############################################################################
# #
# Developed with Kate # Developed with VSCodium and richterger perl plugin.
# #
# (c) 2017-2020 Copyright: Marko Oldenburg (leongaultier at gmail dot com) # (c) 2017-2022 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net)
# All rights reserved # All rights reserved
# #
# Special thanks goes to: # Special thanks goes to:
@ -37,30 +37,28 @@
package FHEM::XiaomiBTLESens; package FHEM::XiaomiBTLESens;
my $missingModul = q{};
use strict; use strict;
use warnings; use warnings;
use experimental qw /switch/;
use POSIX; use POSIX;
use FHEM::Meta; use FHEM::Meta;
use GPUtils qw(GP_Import GP_Export); use GPUtils qw(GP_Import GP_Export);
my $missingModul = q{};
# try to use JSON::MaybeXS wrapper # try to use JSON::MaybeXS wrapper
# for chance of better performance + open code # for chance of better performance + open code
eval { eval {
require JSON::MaybeXS; require JSON::MaybeXS;
import JSON::MaybeXS qw( decode_json encode_json ); import JSON::MaybeXS qw( decode_json encode_json );
1; 1;
}; } or do {
if ($@) {
$@ = undef;
# try to use JSON wrapper # try to use JSON wrapper
# for chance of better performance # for chance of better performance
eval { eval {
# JSON preference order # JSON preference order
local $ENV{PERL_JSON_BACKEND} = local $ENV{PERL_JSON_BACKEND} =
'Cpanel::JSON::XS,JSON::XS,JSON::PP,JSON::backportPP' 'Cpanel::JSON::XS,JSON::XS,JSON::PP,JSON::backportPP'
@ -69,10 +67,7 @@ if ($@) {
require JSON; require JSON;
import JSON qw( decode_json encode_json ); import JSON qw( decode_json encode_json );
1; 1;
}; } or do {
if ($@) {
$@ = undef;
# In rare cases, Cpanel::JSON::XS may # In rare cases, Cpanel::JSON::XS may
# be installed but JSON|JSON::MaybeXS not ... # be installed but JSON|JSON::MaybeXS not ...
@ -80,10 +75,7 @@ if ($@) {
require Cpanel::JSON::XS; require Cpanel::JSON::XS;
import Cpanel::JSON::XS qw(decode_json encode_json); import Cpanel::JSON::XS qw(decode_json encode_json);
1; 1;
}; } or do {
if ($@) {
$@ = undef;
# In rare cases, JSON::XS may # In rare cases, JSON::XS may
# be installed but JSON not ... # be installed but JSON not ...
@ -91,10 +83,7 @@ if ($@) {
require JSON::XS; require JSON::XS;
import JSON::XS qw(decode_json encode_json); import JSON::XS qw(decode_json encode_json);
1; 1;
}; } or do {
if ($@) {
$@ = undef;
# Fallback to built-in JSON which SHOULD # Fallback to built-in JSON which SHOULD
# be available since 5.014 ... # be available since 5.014 ...
@ -102,22 +91,19 @@ if ($@) {
require JSON::PP; require JSON::PP;
import JSON::PP qw(decode_json encode_json); import JSON::PP qw(decode_json encode_json);
1; 1;
}; } or do {
if ($@) {
$@ = undef;
# Fallback to JSON::backportPP in really rare cases # Fallback to JSON::backportPP in really rare cases
require JSON::backportPP; require JSON::backportPP;
import JSON::backportPP qw(decode_json encode_json); import JSON::backportPP qw(decode_json encode_json);
1; 1;
} };
} };
} };
} };
} };
eval "use Blocking;1" or $missingModul .= "Blocking "; eval { require Blocking; 1 } or $missingModul .= "Blocking ";
#use Data::Dumper; only for Debugging #use Data::Dumper; only for Debugging
@ -153,14 +139,6 @@ BEGIN {
); );
} }
#-- Export to main context with different name
GP_Export(
qw(
Initialize
stateRequestTimer
)
);
my %XiaomiModels = ( my %XiaomiModels = (
flowerSens => { flowerSens => {
'rdata' => '0x35', 'rdata' => '0x35',
@ -206,6 +184,8 @@ my %CallBatteryAge = (
'48h' => 172800 '48h' => 172800
); );
sub ::XiaomiBTLESens_Initialize { goto &Initialize }
sub Initialize { sub Initialize {
my $hash = shift; my $hash = shift;
@ -242,9 +222,12 @@ sub Initialize {
sub Define { sub Define {
my $hash = shift; my $hash = shift;
my $arg_ref = shift; my $arg_ref = shift;
my $version;
return $@ if ( !FHEM::Meta::SetInternals($hash) ); return $@ unless ( FHEM::Meta::SetInternals($hash) );
use version 0.60; our $VERSION = FHEM::Meta::Get( $hash, 'version' );
$version = FHEM::Meta::Get( $hash, 'version' );
our $VERSION = $version;
return 'too few parameters: define <name> XiaomiBTLESens <BTMAC>' return 'too few parameters: define <name> XiaomiBTLESens <BTMAC>'
if ( scalar( @{$arg_ref} ) != 3 ); if ( scalar( @{$arg_ref} ) != 3 );
@ -296,72 +279,76 @@ sub Attr {
my ( $cmd, $name, $attrName, $attrVal ) = @_; my ( $cmd, $name, $attrName, $attrVal ) = @_;
my $hash = $defs{$name}; my $hash = $defs{$name};
if ( $attrName eq 'disable' ) { given ($attrName) {
if ( $cmd eq 'set' && $attrVal == 1 ) { when ('disable') {
if ( $cmd eq 'set' && $attrVal == 1 ) {
RemoveInternalTimer($hash);
readingsSingleUpdate( $hash, 'state', 'disabled', 1 );
Log3( $name, 3, "XiaomiBTLESens ($name) - disabled" );
}
elsif ( $cmd eq 'del' ) {
Log3( $name, 3, "XiaomiBTLESens ($name) - enabled" );
}
}
when ('disabledForIntervals') {
if ( $cmd eq 'set' ) {
## no critic (Only use a capturing group if you plan to use the captured value)
return
'check disabledForIntervals Syntax HH:MM-HH:MM or HH:MM-HH:MM HH:MM-HH:MM ...'
if ( $attrVal !~ /^((\d{2}:\d{2})-(\d{2}:\d{2})\s?)+$/x );
## use critic
Log3( $name, 3,
"XiaomiBTLESens ($name) - disabledForIntervals" );
stateRequest($hash);
}
elsif ( $cmd eq 'del' ) {
Log3( $name, 3, "XiaomiBTLESens ($name) - enabled" );
readingsSingleUpdate( $hash, 'state', 'active', 1 );
}
}
when ('interval') {
RemoveInternalTimer($hash); RemoveInternalTimer($hash);
readingsSingleUpdate( $hash, 'state', 'disabled', 1 ); if ( $cmd eq 'set' ) {
Log3( $name, 3, "XiaomiBTLESens ($name) - disabled" ); if ( $attrVal < 120 ) {
} Log3( $name, 3,
elsif ( $cmd eq 'del' ) {
Log3( $name, 3, "XiaomiBTLESens ($name) - enabled" );
}
}
elsif ( $attrName eq 'disabledForIntervals' ) {
if ( $cmd eq 'set' ) {
return
'check disabledForIntervals Syntax HH:MM-HH:MM or HH:MM-HH:MM HH:MM-HH:MM ...'
if ( $attrVal !~ /^((\d{2}:\d{2})-(\d{2}:\d{2})\s?)+$/ );
Log3( $name, 3, "XiaomiBTLESens ($name) - disabledForIntervals" );
stateRequest($hash);
}
elsif ( $cmd eq 'del' ) {
Log3( $name, 3, "XiaomiBTLESens ($name) - enabled" );
readingsSingleUpdate( $hash, 'state', 'active', 1 );
}
}
elsif ( $attrName eq 'interval' ) {
RemoveInternalTimer($hash);
if ( $cmd eq 'set' ) {
if ( $attrVal < 120 ) {
Log3( $name, 3,
"XiaomiBTLESens ($name) - interval too small, please use something >= 120 (sec), default is 300 (sec)" "XiaomiBTLESens ($name) - interval too small, please use something >= 120 (sec), default is 300 (sec)"
); );
return return
'interval too small, please use something >= 120 (sec), default is 300 (sec)'; 'interval too small, please use something >= 120 (sec), default is 300 (sec)';
}
else {
$hash->{INTERVAL} = $attrVal;
Log3( $name, 3,
"XiaomiBTLESens ($name) - set interval to $attrVal" );
}
} }
else {
$hash->{INTERVAL} = $attrVal; elsif ( $cmd eq 'del' ) {
$hash->{INTERVAL} = 300;
Log3( $name, 3, Log3( $name, 3,
"XiaomiBTLESens ($name) - set interval to $attrVal" ); "XiaomiBTLESens ($name) - set interval to default" );
} }
} }
elsif ( $cmd eq 'del' ) { when ('blockingCallLoglevel') {
$hash->{INTERVAL} = 300; if ( $cmd eq 'set' ) {
Log3( $name, 3, $hash->{loglevel} = $attrVal;
"XiaomiBTLESens ($name) - set interval to default" ); Log3( $name, 3,
} "XiaomiBTLESens ($name) - set blockingCallLoglevel to $attrVal"
} );
}
elsif ( $attrName eq 'blockingCallLoglevel' ) { elsif ( $cmd eq 'del' ) {
if ( $cmd eq 'set' ) { $hash->{loglevel} = 4;
$hash->{loglevel} = $attrVal; Log3( $name, 3,
Log3( $name, 3, "XiaomiBTLESens ($name) - set blockingCallLoglevel to default"
"XiaomiBTLESens ($name) - set blockingCallLoglevel to $attrVal" );
); }
}
elsif ( $cmd eq 'del' ) {
$hash->{loglevel} = 4;
Log3( $name, 3,
"XiaomiBTLESens ($name) - set blockingCallLoglevel to default"
);
} }
} }
@ -385,35 +372,24 @@ sub Notify {
( (
( (
( (
grep /^DEFINED.$name$/, grep { /^DEFINED.$name$/x } @{$events}
@{$events} or grep { /^DELETEATTR.$name.disable$/x } @{$events}
or grep /^DELETEATTR.$name.disable$/, or grep { /^ATTR.$name.disable.0$/x } @{$events}
@{$events} or grep { /^DELETEATTR.$name.interval$/x } @{$events}
or grep /^ATTR.$name.disable.0$/, or grep { /^DELETEATTR.$name.model$/x } @{$events}
@{$events} or grep { /^ATTR.$name.model.+/x } @{$events}
or grep /^DELETEATTR.$name.interval$/, or grep { /^ATTR.$name.interval.[0-9]+/x } @{$events}
@{$events}
or grep /^DELETEATTR.$name.model$/,
@{$events}
or grep /^ATTR.$name.model.+/,
@{$events}
or grep /^ATTR.$name.interval.[0-9]+/,
@{$events}
) )
&& $devname eq 'global' && $devname eq 'global'
) )
or grep /^resetBatteryTimestamp$/, or grep { /^resetBatteryTimestamp$/x } @{$events}
@{$events}
) )
&& $init_done && $init_done
|| ( || (
( (
grep /^INITIALIZED$/, grep { /^INITIALIZED$/x } @{$events}
@{$events} or grep { /^REREADCFG$/x } @{$events}
or grep /^REREADCFG$/, or grep { /^MODIFIED.$name$/x } @{$events}
@{$events}
or grep /^MODIFIED.$name$/,
@{$events}
) )
&& $devname eq 'global' && $devname eq 'global'
) )
@ -427,8 +403,7 @@ sub Notify {
|| AttrVal( $name, 'model', 'mijiaLYWSD03MMC' ) eq 'mijiaLYWSD03MMC' || AttrVal( $name, 'model', 'mijiaLYWSD03MMC' ) eq 'mijiaLYWSD03MMC'
) )
&& $devname eq $name && $devname eq $name
&& grep /^$name.firmware.+/, && grep { /^$name.firmware.+/x } @{$events}
@{$events}
); );
return; return;
@ -509,7 +484,7 @@ sub stateRequestTimer {
stateRequest($hash); stateRequest($hash);
InternalTimer( gettimeofday() + $hash->{INTERVAL} + int( rand(300) ), InternalTimer( gettimeofday() + $hash->{INTERVAL} + int( rand(300) ),
'XiaomiBTLESens_stateRequestTimer', $hash ); \&FHEM::XiaomiBTLESens::stateRequestTimer, $hash );
Log3( $name, 4, Log3( $name, 4,
"XiaomiBTLESens ($name) - stateRequestTimer: Call Request Timer" ); "XiaomiBTLESens ($name) - stateRequestTimer: Call Request Timer" );
@ -517,7 +492,7 @@ sub stateRequestTimer {
return; return;
} }
sub Set($$@) { sub Set {
my $hash = shift; my $hash = shift;
my $arg_ref = shift; my $arg_ref = shift;
my $name = shift @$arg_ref; my $name = shift @$arg_ref;
@ -585,14 +560,14 @@ sub Get {
elsif ( $cmd eq 'firmware' ) { elsif ( $cmd eq 'firmware' ) {
return 'usage: firmware' if ( scalar( @{$arg_ref} ) != 0 ); return 'usage: firmware' if ( scalar( @{$arg_ref} ) != 0 );
$mod = 'read'; $mod = 'read';
$handle = $XiaomiModels{ AttrVal( $name, 'model', '' ) }{firmware}; $handle = $XiaomiModels{ AttrVal( $name, 'model', '' ) }{firmware};
} }
elsif ( $cmd eq 'devicename' ) { elsif ( $cmd eq 'devicename' ) {
return "usage: devicename" if ( scalar( @{$arg_ref} ) != 0 ); return "usage: devicename" if ( scalar( @{$arg_ref} ) != 0 );
$mod = 'read'; $mod = 'read';
$handle = $XiaomiModels{ AttrVal( $name, 'model', '' ) }{devicename}; $handle = $XiaomiModels{ AttrVal( $name, 'model', '' ) }{devicename};
} }
@ -670,7 +645,9 @@ sub CreateParamGatttool {
} }
sub Gatttool_executeCommand { sub Gatttool_executeCommand {
my $command = join q{ }, @_; my @command = @_;
## no critic (Backtick operator used . Use IPC::Open3 instead)
my $command = join q{ }, @command;
return ( $_ = qx{$command 2>&1}, $? >> 8 ); return ( $_ = qx{$command 2>&1}, $? >> 8 );
} }
@ -683,8 +660,11 @@ sub ExecGatttool_Run {
my $gatttool; my $gatttool;
my $json_notification; my $json_notification;
$gatttool = qx(which gatttool) if ( $sshHost eq 'none' ); ## no critic (Backtick operator used . Use IPC::Open3 instead)
$gatttool = qx(which gatttool) if ( $sshHost eq 'none' );
$gatttool = qx(ssh $sshHost 'which gatttool') if ( $sshHost ne 'none' ); $gatttool = qx(ssh $sshHost 'which gatttool') if ( $sshHost ne 'none' );
## use critic
chomp $gatttool; chomp $gatttool;
if ( defined($gatttool) && ($gatttool) ) { if ( defined($gatttool) && ($gatttool) ) {
@ -692,12 +672,11 @@ sub ExecGatttool_Run {
my $cmd; my $cmd;
my $loop; my $loop;
my @gtResult; my @gtResult;
my $wait = 1; my $wait = 1;
my $sshHost = AttrVal( $name, 'sshHost', 'none' ); my $hci = AttrVal( $name, 'hciDevice', 'hci0' );
my $hci = AttrVal( $name, 'hciDevice', 'hci0' );
$cmd .= "ssh $sshHost '" if ( $sshHost ne 'none' ); $cmd .= "ssh $sshHost '" if ( $sshHost ne 'none' );
$cmd .= "timeout 10 " if ($listen); $cmd .= "timeout 10 " if ($listen);
$cmd .= "gatttool -i $hci -b $mac "; $cmd .= "gatttool -i $hci -b $mac ";
$cmd .= "--char-read -a $handle" if ( $gattCmd eq 'read' ); $cmd .= "--char-read -a $handle" if ( $gattCmd eq 'read' );
$cmd .= "--char-write-req -a $handle -n $value" $cmd .= "--char-write-req -a $handle -n $value"
@ -724,17 +703,17 @@ sub ExecGatttool_Run {
"XiaomiBTLESens ($name) - ExecGatttool_Run: Execute Command $psCommand | grep -E $gatttoolCmdlineStaticEscaped" "XiaomiBTLESens ($name) - ExecGatttool_Run: Execute Command $psCommand | grep -E $gatttoolCmdlineStaticEscaped"
); );
# $grepGatttool = qx(ps ax| grep -E \'$gatttoolCmdlineStaticEscaped\') ## no critic (Backtick operator used . Use IPC::Open3 instead)
$grepGatttool = $grepGatttool =
qx($psCommand | grep -E \'$gatttoolCmdlineStaticEscaped\') qx($psCommand | grep -E \'$gatttoolCmdlineStaticEscaped\')
if ( $sshHost eq 'none' ); if ( $sshHost eq 'none' );
# $grepGatttool = qx(ssh $sshHost 'ps ax| grep -E "$gatttoolCmdlineStaticEscaped"')
$grepGatttool = $grepGatttool =
qx(ssh $sshHost '$psCommand | grep -E "$gatttoolCmdlineStaticEscaped"') qx(ssh $sshHost '$psCommand | grep -E "$gatttoolCmdlineStaticEscaped"')
if ( $sshHost ne 'none' ); if ( $sshHost ne 'none' );
## use critic
if ( not $grepGatttool =~ /^\s*$/ ) { if ( not $grepGatttool =~ /^\s*$/x ) {
Log3( $name, 3, Log3( $name, 3,
"XiaomiBTLESens ($name) - ExecGatttool_Run: another gatttool process is running. waiting..." "XiaomiBTLESens ($name) - ExecGatttool_Run: another gatttool process is running. waiting..."
); );
@ -755,11 +734,15 @@ qx(ssh $sshHost '$psCommand | grep -E "$gatttoolCmdlineStaticEscaped"')
); );
( $returnString, $returnCode ) = Gatttool_executeCommand($cmd); ( $returnString, $returnCode ) = Gatttool_executeCommand($cmd);
@gtResult = split /:\s/, $returnString; @gtResult = split /:\s/x, $returnString;
Log3( $name, 5, Log3(
$name,
5,
"XiaomiBTLESens ($name) - ExecGatttool_Run: gatttool loop result " "XiaomiBTLESens ($name) - ExecGatttool_Run: gatttool loop result "
. join q{,}, @gtResult ); . join q{,},
@gtResult
);
$returnCode = 2 $returnCode = 2
if ( !defined( $gtResult[0] ) ); if ( !defined( $gtResult[0] ) );
@ -770,9 +753,13 @@ qx(ssh $sshHost '$psCommand | grep -E "$gatttoolCmdlineStaticEscaped"')
"XiaomiBTLESens ($name) - ExecGatttool_Run: errorcode: \"$returnCode\", ErrorString: \"$returnString\"" "XiaomiBTLESens ($name) - ExecGatttool_Run: errorcode: \"$returnCode\", ErrorString: \"$returnString\""
) if ( $returnCode != 0 && $returnCode != 124 ); ) if ( $returnCode != 0 && $returnCode != 124 );
Log3( $name, 4, Log3(
$name,
4,
"XiaomiBTLESens ($name) - ExecGatttool_Run: gatttool result " "XiaomiBTLESens ($name) - ExecGatttool_Run: gatttool result "
. join q{,}, @gtResult ); . join q{,},
@gtResult
);
$handle = '0x35' $handle = '0x35'
if ( $sshHost ne 'none' if ( $sshHost ne 'none'
@ -788,12 +775,12 @@ qx(ssh $sshHost '$psCommand | grep -E "$gatttoolCmdlineStaticEscaped"')
if ( $gtResult[1] ne 'no data response' && $listen ) { if ( $gtResult[1] ne 'no data response' && $listen ) {
( $gtResult[1] ) = split '\n', $gtResult[1]; ( $gtResult[1] ) = split '\n', $gtResult[1];
$gtResult[1] =~ s/\\n//g; $gtResult[1] =~ s/\\n//xg;
} }
$json_notification = encodeJSON( $gtResult[1] ); $json_notification = encodeJSON( $gtResult[1] );
if ( $gtResult[1] =~ /^([0-9a-f]{2}(\s?))*$/ ) { if ( $gtResult[1] =~ /^([0-9a-f]{2}(\s?))*$/x ) {
return "$name|$mac|ok|$gattCmd|$handle|$json_notification"; return "$name|$mac|ok|$gattCmd|$handle|$json_notification";
} }
elsif ( $returnCode == 0 && $gattCmd eq 'write' ) { elsif ( $returnCode == 0 && $gattCmd eq 'write' ) {
@ -822,7 +809,7 @@ sub ExecGatttool_Done {
my $string = shift; my $string = shift;
my ( $name, $mac, $respstate, $gattCmd, $handle, $json_notification ) = my ( $name, $mac, $respstate, $gattCmd, $handle, $json_notification ) =
split /\|/, $string; split( /\|/x, $string );
my $hash = $defs{$name}; my $hash = $defs{$name};
@ -844,7 +831,8 @@ sub ExecGatttool_Done {
); );
} }
if ( $respstate eq 'ok' if ( $respstate
&& $respstate eq 'ok'
&& $gattCmd eq 'write' && $gattCmd eq 'write'
&& AttrVal( $name, 'model', 'none' ) eq 'flowerSens' ) && AttrVal( $name, 'model', 'none' ) eq 'flowerSens' )
{ {
@ -852,7 +840,9 @@ sub ExecGatttool_Done {
$XiaomiModels{ AttrVal( $name, 'model', '' ) }{rdata} ); $XiaomiModels{ AttrVal( $name, 'model', '' ) }{rdata} );
} }
elsif ( $respstate eq 'ok' ) { elsif ($respstate
&& $respstate eq 'ok' )
{
ProcessingNotification( $hash, $gattCmd, $handle, ProcessingNotification( $hash, $gattCmd, $handle,
$decode_json->{gtResult} ); $decode_json->{gtResult} );
@ -913,111 +903,120 @@ sub ProcessingNotification {
} }
elsif ( AttrVal( $name, 'model', 'none' ) eq 'thermoHygroSens' ) { elsif ( AttrVal( $name, 'model', 'none' ) eq 'thermoHygroSens' ) {
if ( $handle eq '0x18' ) { given ($handle) {
### Thermo/Hygro Sens - Read Battery Data when ('0x18') {
Log3( $name, 4, ### Thermo/Hygro Sens - Read Battery Data
"XiaomiBTLESens ($name) - ProcessingNotification: handle 0x18" Log3( $name, 4,
); "XiaomiBTLESens ($name) - ProcessingNotification: handle 0x18"
);
$readings = ThermoHygroSensHandle0x18( $hash, $notification ); $readings = ThermoHygroSensHandle0x18( $hash, $notification );
} }
elsif ( $handle eq '0x10' ) { when ('0x10') {
### Thermo/Hygro Sens - Read Sensor Data ### Thermo/Hygro Sens - Read Sensor Data
Log3( $name, 4, Log3( $name, 4,
"XiaomiBTLESens ($name) - ProcessingNotification: handle 0x10" "XiaomiBTLESens ($name) - ProcessingNotification: handle 0x10"
); );
$readings = ThermoHygroSensHandle0x10( $hash, $notification ); $readings = ThermoHygroSensHandle0x10( $hash, $notification );
} }
elsif ( $handle eq '0x24' ) { when ('0x24') {
### Thermo/Hygro Sens - Read Firmware Data ### Thermo/Hygro Sens - Read Firmware Data
Log3( $name, 4, Log3( $name, 4,
"XiaomiBTLESens ($name) - ProcessingNotification: handle 0x24" "XiaomiBTLESens ($name) - ProcessingNotification: handle 0x24"
); );
$readings = ThermoHygroSensHandle0x24( $hash, $notification ); $readings = ThermoHygroSensHandle0x24( $hash, $notification );
} }
elsif ( $handle eq '0x3' ) { when ('0x3') {
### Thermo/Hygro Sens - Read and Write Devicename ### Thermo/Hygro Sens - Read and Write Devicename
Log3( $name, 4, Log3( $name, 4,
"XiaomiBTLESens ($name) - ProcessingNotification: handle 0x3" ); "XiaomiBTLESens ($name) - ProcessingNotification: handle 0x3"
);
return CreateParamGatttool( $hash, 'read', return CreateParamGatttool( $hash, 'read',
$XiaomiModels{ AttrVal( $name, 'model', '' ) }{devicename} ) $XiaomiModels{ AttrVal( $name, 'model', '' ) }{devicename} )
if ( $gattCmd ne 'read' ); if ( $gattCmd ne 'read' );
$readings = ThermoHygroSensHandle0x3( $hash, $notification ); $readings = ThermoHygroSensHandle0x3( $hash, $notification );
}
} }
} }
elsif ( AttrVal( $name, 'model', 'none' ) eq 'mijiaLYWSD03MMC' ) { elsif ( AttrVal( $name, 'model', 'none' ) eq 'mijiaLYWSD03MMC' ) {
if ( $handle eq '0x1b' ) { given ($handle) {
### mijiaLYWSD03MMC - Read Battery Data when ('0x1b') {
Log3( $name, 4, ### mijiaLYWSD03MMC - Read Battery Data
"XiaomiBTLESens ($name) - ProcessingNotification: handle 0x1b" Log3( $name, 4,
); "XiaomiBTLESens ($name) - ProcessingNotification: handle 0x1b"
);
$readings = mijiaLYWSD03MMC_Handle0x1b( $hash, $notification ); $readings = mijiaLYWSD03MMC_Handle0x1b( $hash, $notification );
} }
elsif ( $handle eq '0x38' ) { when ('0x38') {
### mijiaLYWSD03MMC - Read Sensor Data ### mijiaLYWSD03MMC - Read Sensor Data
Log3( $name, 4, Log3( $name, 4,
"XiaomiBTLESens ($name) - ProcessingNotification: handle 0x38" "XiaomiBTLESens ($name) - ProcessingNotification: handle 0x38"
); );
$readings = mijiaLYWSD03MMC_Handle0x38( $hash, $notification ); $readings = mijiaLYWSD03MMC_Handle0x38( $hash, $notification );
} }
elsif ( $handle eq '0x12' ) { when ('0x12') {
### mijiaLYWSD03MMC - Read Firmware Data ### mijiaLYWSD03MMC - Read Firmware Data
Log3( $name, 4, Log3( $name, 4,
"XiaomiBTLESens ($name) - ProcessingNotification: handle 0x12" "XiaomiBTLESens ($name) - ProcessingNotification: handle 0x12"
); );
$readings = mijiaLYWSD03MMC_Handle0x12( $hash, $notification ); $readings = mijiaLYWSD03MMC_Handle0x12( $hash, $notification );
} }
elsif ( $handle eq '0x3' ) { when ('0x3') {
### mijiaLYWSD03MMC - Read and Write Devicename ### mijiaLYWSD03MMC - Read and Write Devicename
Log3( $name, 4, Log3( $name, 4,
"XiaomiBTLESens ($name) - ProcessingNotification: handle 0x3" ); "XiaomiBTLESens ($name) - ProcessingNotification: handle 0x3"
);
return CreateParamGatttool( $hash, 'read', return CreateParamGatttool( $hash, 'read',
$XiaomiModels{ AttrVal( $name, 'model', '' ) }{devicename} ) $XiaomiModels{ AttrVal( $name, 'model', '' ) }{devicename} )
unless ( $gattCmd eq 'read' ); unless ( $gattCmd eq 'read' );
$readings = mijiaLYWSD03MMC_Handle0x3( $hash, $notification ); $readings = mijiaLYWSD03MMC_Handle0x3( $hash, $notification );
}
} }
} }
elsif ( AttrVal( $name, 'model', 'none' ) eq 'clearGrassSens' ) { elsif ( AttrVal( $name, 'model', 'none' ) eq 'clearGrassSens' ) {
if ( $handle eq '0x3b' ) { given ($handle) {
### Clear Grass Sens - Read Battery Data when ('0x3b') {
Log3( $name, 4, ### Clear Grass Sens - Read Battery Data
"XiaomiBTLESens ($name) - ProcessingNotification: handle 0x3b" Log3( $name, 4,
); "XiaomiBTLESens ($name) - ProcessingNotification: handle 0x3b"
);
$readings = ClearGrassSensHandle0x3b( $hash, $notification ); $readings = ClearGrassSensHandle0x3b( $hash, $notification );
} }
elsif ( $handle eq '0x1e' ) { when ('0x1e') {
### Clear Grass Sens - Read Sensor Data ### Clear Grass Sens - Read Sensor Data
Log3( $name, 4, Log3( $name, 4,
"XiaomiBTLESens ($name) - ProcessingNotification: handle 0x1e" "XiaomiBTLESens ($name) - ProcessingNotification: handle 0x1e"
); );
$readings = ClearGrassSensHandle0x1e( $hash, $notification ); $readings = ClearGrassSensHandle0x1e( $hash, $notification );
} }
elsif ( $handle eq '0x2a' ) { when ('0x2a') {
### Clear Grass Sens - Read Firmware Data ### Clear Grass Sens - Read Firmware Data
Log3( $name, 4, Log3( $name, 4,
"XiaomiBTLESens ($name) - ProcessingNotification: handle 0x2a" "XiaomiBTLESens ($name) - ProcessingNotification: handle 0x2a"
); );
$readings = ClearGrassSensHandle0x2a( $hash, $notification ); $readings = ClearGrassSensHandle0x2a( $hash, $notification );
} }
elsif ( $handle eq '0x3' ) { when ('0x3') {
### Clear Grass Sens - Read and Write Devicename ### Clear Grass Sens - Read and Write Devicename
Log3( $name, 4, Log3( $name, 4,
"XiaomiBTLESens ($name) - ProcessingNotification: handle 0x3" ); "XiaomiBTLESens ($name) - ProcessingNotification: handle 0x3"
);
return CreateParamGatttool( $hash, 'read', return CreateParamGatttool( $hash, 'read',
$XiaomiModels{ AttrVal( $name, 'model', '' ) }{devicename} ) $XiaomiModels{ AttrVal( $name, 'model', '' ) }{devicename} )
if ( $gattCmd ne 'read' ); if ( $gattCmd ne 'read' );
$readings = ClearGrassSensHandle0x3( $hash, $notification ); $readings = ClearGrassSensHandle0x3( $hash, $notification );
}
} }
} }
@ -1034,7 +1033,7 @@ sub FlowerSensHandle0x38 {
Log3( $name, 4, "XiaomiBTLESens ($name) - FlowerSens Handle0x38" ); Log3( $name, 4, "XiaomiBTLESens ($name) - FlowerSens Handle0x38" );
my @dataBatFw = split /\s/, $notification; my @dataBatFw = split /\s/x, $notification;
### neue Vereinheitlichung für Batteriereadings Forum #800017 ### neue Vereinheitlichung für Batteriereadings Forum #800017
$readings{'batteryPercent'} = hex( "0x" . $dataBatFw[0] ); $readings{'batteryPercent'} = hex( "0x" . $dataBatFw[0] );
@ -1062,7 +1061,7 @@ sub FlowerSensHandle0x35 {
Log3( $name, 4, "XiaomiBTLESens ($name) - FlowerSens Handle0x35" ); Log3( $name, 4, "XiaomiBTLESens ($name) - FlowerSens Handle0x35" );
my @dataSensor = split /\s/, $notification; my @dataSensor = split /\s/x, $notification;
return stateRequest($hash) return stateRequest($hash)
if ( $dataSensor[0] eq "aa" if ( $dataSensor[0] eq "aa"
@ -1110,7 +1109,7 @@ sub ThermoHygroSensHandle0x18 {
Log3( $name, 4, "XiaomiBTLESens ($name) - Thermo/Hygro Sens Handle0x18" ); Log3( $name, 4, "XiaomiBTLESens ($name) - Thermo/Hygro Sens Handle0x18" );
chomp($notification); chomp($notification);
$notification =~ s/\s+//g; $notification =~ s/\s+//xg;
### neue Vereinheitlichung für Batteriereadings Forum #800017 ### neue Vereinheitlichung für Batteriereadings Forum #800017
$readings{'batteryPercent'} = hex( "0x" . $notification ); $readings{'batteryPercent'} = hex( "0x" . $notification );
@ -1134,14 +1133,14 @@ sub ThermoHygroSensHandle0x10 {
Log3( $name, 4, "XiaomiBTLESens ($name) - Thermo/Hygro Sens Handle0x10" ); Log3( $name, 4, "XiaomiBTLESens ($name) - Thermo/Hygro Sens Handle0x10" );
return stateRequest($hash) return stateRequest($hash)
if ( $notification !~ /^([0-9a-f]{2}(\s?))*$/ ); if ( $notification !~ /^([0-9a-f]{2}(\s?))*$/x );
my @numberOfHex = split /\s/, $notification; my @numberOfHex = split /\s/x, $notification;
$notification =~ s/\s+//g; $notification =~ s/\s+//xg;
$readings{'temperature'} = pack( 'H*', substr( $notification, 4, 8 ) ); $readings{'temperature'} = pack( 'H*', substr( $notification, 4, 8 ) );
$readings{'humidity'} = pack( $readings{'humidity'} = pack(
'H*', 'H*',
substr( substr(
$notification, $notification,
@ -1170,7 +1169,7 @@ sub ThermoHygroSensHandle0x24 {
Log3( $name, 4, "XiaomiBTLESens ($name) - Thermo/Hygro Sens Handle0x24" ); Log3( $name, 4, "XiaomiBTLESens ($name) - Thermo/Hygro Sens Handle0x24" );
$notification =~ s/\s+//g; $notification =~ s/\s+//xg;
$readings{'firmware'} = pack( 'H*', $notification ); $readings{'firmware'} = pack( 'H*', $notification );
@ -1189,7 +1188,7 @@ sub ThermoHygroSensHandle0x3 {
Log3( $name, 4, "XiaomiBTLESens ($name) - Thermo/Hygro Sens Handle0x3" ); Log3( $name, 4, "XiaomiBTLESens ($name) - Thermo/Hygro Sens Handle0x3" );
$notification =~ s/\s+//g; $notification =~ s/\s+//xg;
$readings{'devicename'} = pack( 'H*', $notification ); $readings{'devicename'} = pack( 'H*', $notification );
@ -1198,7 +1197,7 @@ sub ThermoHygroSensHandle0x3 {
return \%readings; return \%readings;
} }
sub mijiaLYWSD03MMC_Handle0x1b($$) { sub mijiaLYWSD03MMC_Handle0x1b {
### mijiaLYWSD03MMC - Battery Data ### mijiaLYWSD03MMC - Battery Data
my ( $hash, $notification ) = @_; my ( $hash, $notification ) = @_;
@ -1208,7 +1207,7 @@ sub mijiaLYWSD03MMC_Handle0x1b($$) {
Log3( $name, 4, "XiaomiBTLESens ($name) - mijiaLYWSD03MMC Handle0x1b" ); Log3( $name, 4, "XiaomiBTLESens ($name) - mijiaLYWSD03MMC Handle0x1b" );
chomp($notification); chomp($notification);
$notification =~ s/\s+//g; $notification =~ s/\s+//xg;
### neue Vereinheitlichung für Batteriereadings Forum #800017 ### neue Vereinheitlichung für Batteriereadings Forum #800017
$readings{'batteryPercent'} = $notification; ###hex( "0x" . $notification ); $readings{'batteryPercent'} = $notification; ###hex( "0x" . $notification );
@ -1220,7 +1219,7 @@ sub mijiaLYWSD03MMC_Handle0x1b($$) {
return \%readings; return \%readings;
} }
sub mijiaLYWSD03MMC_Handle0x38($$) { sub mijiaLYWSD03MMC_Handle0x38 {
### mijiaLYWSD03MMC - Read Sensor Data ### mijiaLYWSD03MMC - Read Sensor Data
my ( $hash, $notification ) = @_; my ( $hash, $notification ) = @_;
@ -1230,20 +1229,25 @@ sub mijiaLYWSD03MMC_Handle0x38($$) {
Log3( $name, 4, "XiaomiBTLESens ($name) - mijiaLYWSD03MMC Handle0x38" ); Log3( $name, 4, "XiaomiBTLESens ($name) - mijiaLYWSD03MMC Handle0x38" );
return stateRequest($hash) return stateRequest($hash)
unless ( $notification =~ /^([0-9a-f]{2}(\s?))*$/ ); unless ( $notification =~ /^([0-9a-f]{2}(\s?))*$/x );
my @splitVal = split /\s/, $notification; my @splitVal = split /\s/x, $notification;
$notification =~ s/\s+//g; $notification =~ s/\s+//xg;
$readings{'temperature'} = hex( "0x" . $splitVal[1] . $splitVal[0] ) / 100; $readings{'temperature'} =
$readings{'humidity'} = hex( "0x" . $splitVal[2] ); hex( "0x" . $splitVal[1] . $splitVal[0] ) > 20000
? ( -65536 + hex( "0x" . $splitVal[1] . $splitVal[0] ) ) / 100
: hex( "0x" . $splitVal[1] . $splitVal[0] ) / 100;
$readings{'humidity'} = hex( "0x" . $splitVal[2] );
$hash->{helper}{CallBattery} = 0; $hash->{helper}{CallBattery} = 0;
return \%readings; return \%readings;
} }
sub mijiaLYWSD03MMC_Handle0x12($$) { sub mijiaLYWSD03MMC_Handle0x12 {
### mijiaLYWSD03MMC - Read Firmware Data ### mijiaLYWSD03MMC - Read Firmware Data
my ( $hash, $notification ) = @_; my ( $hash, $notification ) = @_;
@ -1252,15 +1256,16 @@ sub mijiaLYWSD03MMC_Handle0x12($$) {
Log3( $name, 4, "XiaomiBTLESens ($name) - mijiaLYWSD03MMC Handle0x12" ); Log3( $name, 4, "XiaomiBTLESens ($name) - mijiaLYWSD03MMC Handle0x12" );
$notification =~ s/\s+//g; $notification =~ s/\s+//xg;
$readings{'firmware'} = pack( 'H*', $notification ); $readings{'firmware'} = pack( 'H*', $notification );
$hash->{helper}{CallBattery} = 0; $hash->{helper}{CallBattery} = 0;
return \%readings; return \%readings;
} }
sub mijiaLYWSD03MMC_Handle0x3($$) { sub mijiaLYWSD03MMC_Handle0x3 {
### mijiaLYWSD03MMC - Read and Write Devicename ### mijiaLYWSD03MMC - Read and Write Devicename
my ( $hash, $notification ) = @_; my ( $hash, $notification ) = @_;
@ -1269,11 +1274,12 @@ sub mijiaLYWSD03MMC_Handle0x3($$) {
Log3( $name, 4, "XiaomiBTLESens ($name) - mijiaLYWSD03MMC Handle0x3" ); Log3( $name, 4, "XiaomiBTLESens ($name) - mijiaLYWSD03MMC Handle0x3" );
$notification =~ s/\s+//g; $notification =~ s/\s+//xg;
$readings{'devicename'} = pack( 'H*', $notification ); $readings{'devicename'} = pack( 'H*', $notification );
$hash->{helper}{CallBattery} = 0; $hash->{helper}{CallBattery} = 0;
return \%readings; return \%readings;
} }
@ -1288,7 +1294,7 @@ sub ClearGrassSensHandle0x3b {
Log3( $name, 4, "XiaomiBTLESens ($name) - Clear Grass Sens Handle0x3b" ); Log3( $name, 4, "XiaomiBTLESens ($name) - Clear Grass Sens Handle0x3b" );
chomp($notification); chomp($notification);
$notification =~ s/\s+//g; $notification =~ s/\s+//xg;
### neue Vereinheitlichung für Batteriereadings Forum #800017 ### neue Vereinheitlichung für Batteriereadings Forum #800017
$readings{'batteryPercent'} = hex( substr( $notification, 14, 2 ) ); $readings{'batteryPercent'} = hex( substr( $notification, 14, 2 ) );
@ -1312,11 +1318,11 @@ sub ClearGrassSensHandle0x1e {
Log3( $name, 4, "XiaomiBTLESens ($name) - Clear Grass Sens Handle0x1e" ); Log3( $name, 4, "XiaomiBTLESens ($name) - Clear Grass Sens Handle0x1e" );
return stateRequest($hash) return stateRequest($hash)
if ( $notification !~ /^([0-9a-f]{2}(\s?))*$/ ); if ( $notification !~ /^([0-9a-f]{2}(\s?))*$/x );
my @numberOfHex = split /\s/, $notification; my @numberOfHex = split /\s/x, $notification;
$notification =~ s/\s+//g; $notification =~ s/\s+//xg;
$readings{'temperature'} = hex( substr( $notification, 4, 2 ) ) / 10; $readings{'temperature'} = hex( substr( $notification, 4, 2 ) ) / 10;
$readings{'humidity'} = $readings{'humidity'} =
@ -1338,7 +1344,7 @@ sub ClearGrassSensHandle0x2a {
Log3( $name, 4, "XiaomiBTLESens ($name) - Clear Grass Sens Handle0x2a" ); Log3( $name, 4, "XiaomiBTLESens ($name) - Clear Grass Sens Handle0x2a" );
$notification =~ s/\s+//g; $notification =~ s/\s+//xg;
$readings{'firmware'} = pack( 'H*', $notification ); $readings{'firmware'} = pack( 'H*', $notification );
@ -1357,7 +1363,7 @@ sub ClearGrassSensHandle0x3 {
Log3( $name, 4, "XiaomiBTLESens ($name) - Clear Grass Sens Handle0x3" ); Log3( $name, 4, "XiaomiBTLESens ($name) - Clear Grass Sens Handle0x3" );
$notification =~ s/\s+//g; $notification =~ s/\s+//xg;
$readings{'devicename'} = pack( 'H*', $notification ); $readings{'devicename'} = pack( 'H*', $notification );
@ -1519,6 +1525,8 @@ sub CallBattery_Timestamp {
$hash->{helper}{updateTimeCallBattery} = $hash->{helper}{updateTimeCallBattery} =
gettimeofday(); # in seconds since the epoch gettimeofday(); # in seconds since the epoch
$hash->{helper}{updateTimestampCallBattery} = FmtDateTime( gettimeofday() ); $hash->{helper}{updateTimestampCallBattery} = FmtDateTime( gettimeofday() );
return;
} }
sub CallBattery_UpdateTimeAge { sub CallBattery_UpdateTimeAge {
@ -1553,7 +1561,7 @@ sub BTLE_CmdlinePreventGrepFalsePositive {
# avoid an *additional* grep process plus pipe... # avoid an *additional* grep process plus pipe...
my $cmdline = shift; my $cmdline = shift;
$cmdline =~ s/(.)(.*)/[$1]$2/; $cmdline =~ s/(.)(.*)/[$1]$2/x;
return $cmdline; return $cmdline;
} }
@ -1747,7 +1755,7 @@ sub BTLE_CmdlinePreventGrepFalsePositive {
], ],
"release_status": "stable", "release_status": "stable",
"license": "GPL_2", "license": "GPL_2",
"version": "v3.0.0", "version": "v3.0.1",
"author": [ "author": [
"Marko Oldenburg <leongaultier@gmail.com>" "Marko Oldenburg <leongaultier@gmail.com>"
], ],