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