From 7c01c1c7903a01069b7c6e80e475727e5d40d4a7 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Mon, 31 Jan 2022 19:43:20 +0100 Subject: [PATCH 01/13] make parseJSON function to run asynchron in installations wirh many of Gardena devices, the parseJSON function run long time. This patch make the parseJSON function asybchron [Ticket: #47] --- FHEM/73_GardenaSmartBridge.pm | 527 ++++++++++++++++++-------------- FHEM/74_GardenaSmartDevice.pm | 399 ++++++++++++++---------- controls_GardenaSmartDevice.txt | 4 +- 3 files changed, 534 insertions(+), 396 deletions(-) diff --git a/FHEM/73_GardenaSmartBridge.pm b/FHEM/73_GardenaSmartBridge.pm index 88bdc0b..4a80358 100644 --- a/FHEM/73_GardenaSmartBridge.pm +++ b/FHEM/73_GardenaSmartBridge.pm @@ -1,8 +1,8 @@ ############################################################################### # -# Developed with Kate +# Developed with VSCodium and richterger perl plugin. # -# (c) 2017-2021 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) +# (c) 2017-2022 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) # All rights reserved # # Special thanks goes to comitters: @@ -57,7 +57,6 @@ package FHEM::GardenaSmartBridge; use GPUtils qw(GP_Import GP_Export); - use strict; use warnings; use POSIX; @@ -183,7 +182,7 @@ BEGIN { #-- Export to main context with different name GP_Export( qw( - Initialize + Initialize ) ); @@ -237,12 +236,10 @@ sub Define { my $name = shift @$aArg; $hash->{BRIDGE} = 1; $hash->{URL} = - AttrVal( $name, 'gardenaBaseURL', - 'https://smart.gardena.com' ) - . '/v1'; + AttrVal( $name, 'gardenaBaseURL', 'https://smart.gardena.com' ) . '/v1'; $hash->{VERSION} = version->parse($VERSION)->normal; $hash->{INTERVAL} = 60; - $hash->{NOTIFYDEV} = "global,$name"; + $hash->{NOTIFYDEV} = "global,$name"; CommandAttr( undef, $name . ' room GardenaSmart' ) if ( AttrVal( $name, 'room', 'none' ) eq 'none' ); @@ -261,7 +258,7 @@ sub Undef { my $hash = shift; my $name = shift; - RemoveInternalTimer($hash, "FHEM::GardenaSmartBridge::getDevices"); + RemoveInternalTimer( $hash, "FHEM::GardenaSmartBridge::getDevices" ); delete $modules{GardenaSmartBridge}{defptr}{BRIDGE} if ( defined( $modules{GardenaSmartBridge}{defptr}{BRIDGE} ) ); @@ -282,7 +279,8 @@ sub Attr { if ( $attrName eq 'disable' ) { if ( $cmd eq 'set' && $attrVal eq '1' ) { - RemoveInternalTimer($hash, "FHEM::GardenaSmartBridge::getDevices"); + RemoveInternalTimer( $hash, + "FHEM::GardenaSmartBridge::getDevices" ); readingsSingleUpdate( $hash, 'state', 'inactive', 1 ); Log3 $name, 3, "GardenaSmartBridge ($name) - disabled"; } @@ -307,13 +305,15 @@ sub Attr { if ( $cmd eq 'set' ) { return 'Interval must be greater than 0' if ( $attrVal == 0 ); - RemoveInternalTimer($hash, "FHEM::GardenaSmartBridge::getDevices"); + RemoveInternalTimer( $hash, + "FHEM::GardenaSmartBridge::getDevices" ); $hash->{INTERVAL} = $attrVal; Log3 $name, 3, "GardenaSmartBridge ($name) - set interval: $attrVal"; } elsif ( $cmd eq 'del' ) { - RemoveInternalTimer($hash, "FHEM::GardenaSmartBridge::getDevices"); + RemoveInternalTimer( $hash, + "FHEM::GardenaSmartBridge::getDevices" ); $hash->{INTERVAL} = 60; Log3 $name, 3, "GardenaSmartBridge ($name) - delete User interval and set default: 60"; @@ -360,14 +360,9 @@ sub Notify { ) ) - || ( - $devtype eq 'GardenaSmartBridge' - && ( - grep /^gardenaAccountPassword.+/, - @{$events} - ) - ) - && $init_done + || ( $devtype eq 'GardenaSmartBridge' + && ( grep /^gardenaAccountPassword.+/, @{$events} ) ) + && $init_done ); getDevices($hash) @@ -387,7 +382,7 @@ sub Notify { && ( grep /^state:.Connected$/, @{$events} or grep /^lastRequestState:.request_error$/, - @{$events} + @{$events} ) ) { @@ -399,6 +394,7 @@ sub Notify { return; } + sub Get { my $hash = shift // return; my $aArg = shift // return; @@ -410,15 +406,16 @@ sub Get { if ( lc $cmd eq 'debug_devices_list' ) { my $device = shift @$aArg; $hash->{helper}{debug_device} = $device; - Write($hash, undef, undef, undef, undef); - return undef; - } else { + Write( $hash, undef, undef, undef, undef ); + return; + } + else { my $list = ""; - $list .= " debug_devices_list:" - .join( ',', @{ $hash->{helper}{deviceList} }) - if ( AttrVal( $name, "debugDEVICE", "none") ne "none" - && exists($hash->{helper}{deviceList}) ); - return "Unknown argument $cmd,choose one of $list"; + $list .= + " debug_devices_list:" . join( ',', @{ $hash->{helper}{deviceList} } ) + if ( AttrVal( $name, "debugDEVICE", "none" ) ne "none" + && exists( $hash->{helper}{deviceList} ) ); + return "Unknown argument $cmd,choose one of $list"; } } @@ -427,8 +424,9 @@ sub Set { my $aArg = shift // return; my $name = shift @$aArg // return; - my $cmd = shift @$aArg // return qq{"set $name" needs at least one argument}; - + my $cmd = shift @$aArg + // return qq{"set $name" needs at least one argument}; + # Das Argument für das Passwort, also das Passwort an sich darf keine = enthalten!!! if ( lc $cmd eq 'getdevicesstate' ) { @@ -478,21 +476,22 @@ sub Write { my ( $session_id, $header, $uri, $method ); ( $payload, $session_id, $header, $uri, $method, $deviceId, $service_id ) = - createHttpValueStrings( $hash, $payload, $deviceId, $abilities, $service_id ); + createHttpValueStrings( $hash, $payload, $deviceId, $abilities, + $service_id ); HttpUtils_NonblockingGet( { - url => $hash->{URL} . $uri, - timeout => 15, + url => $hash->{URL} . $uri, + timeout => 15, incrementalTimeout => 1, - hash => $hash, - device_id => $deviceId, - data => $payload, - method => $method, - header => $header, - doTrigger => 1, - cl => $hash->{CL}, - callback => \&ErrorHandling + hash => $hash, + device_id => $deviceId, + data => $payload, + method => $method, + header => $header, + doTrigger => 1, + cl => $hash->{CL}, + callback => \&ErrorHandling } ); @@ -500,8 +499,8 @@ sub Write { "GardenaSmartBridge ($name) - Send with URL: $hash->{URL}$uri, HEADER: secret!, DATA: secret!, METHOD: $method" ); - # Log3($name, 3, - # "GardenaSmartBridge ($name) - Send with URL: $hash->{URL}$uri, HEADER: $header, DATA: $payload, METHOD: $method"); +# Log3($name, 3, +# "GardenaSmartBridge ($name) - Send with URL: $hash->{URL}$uri, HEADER: $header, DATA: $payload, METHOD: $method"); return; } @@ -519,7 +518,7 @@ sub ErrorHandling { if ( defined( $param->{'device_id'} ) ); my $dname = $dhash->{NAME}; - + Log3 $name, 4, "GardenaSmartBridge ($name) - Request: $data"; my $decode_json = eval { decode_json($data) } if ( length($data) > 0 ); @@ -702,6 +701,11 @@ sub ErrorHandling { . $param->{code}; } + if ( !defined( $hash->{helper}{session_id} ) ) { + readingsSingleUpdate( $hash, 'token', 'none', 1 ); + InternalTimer( gettimeofday() + 5, + "FHEM::GardenaSmartBridge::getToken", $hash ); + } readingsEndUpdate( $dhash, 1 ); Log3 $dname, 5, @@ -712,60 +716,70 @@ sub ErrorHandling { delete $dhash->{helper}{deviceAction} if ( defined( $dhash->{helper}{deviceAction} ) ); - readingsSingleUpdate( $hash, 'token', 'none', 1 ) - if ( !defined( $hash->{helper}{session_id} ) ); - - getToken($hash) - if ( !defined( $hash->{helper}{session_id} ) ); return; } - elsif (defined ($decode_json->{message}) - && $decode_json->{message} eq 'Unauthorized') { - Log3 $name, 3, - "GardenaSmartBridge ($name) - Unauthorized -> fetch new token "; - getToken($hash); - return; + elsif ( defined( $decode_json->{message} ) + && $decode_json->{message} eq 'Unauthorized' ) + { + Log3 $name, 3, + "GardenaSmartBridge ($name) - Unauthorized -> fetch new token "; + + getToken($hash); + + return; } - if (defined($hash->{helper}{debug_device}) - && $hash->{helper}{debug_device} ne 'none' - ){ - Log3 $name, 4, "GardenaSmartBridge DEBUG Device"; - delete $hash->{helper}{debug_device}; - my @device_spec = ("name", "id", "category"); - my $devJson=$decode_json->{devices}; - my $output = '.:{ DEBUG OUTPUT for '.$devJson->{name}.' }:. \n'; - for my $spec (@device_spec) { - $output .= "$spec : $devJson->{$spec} \n"; - } - #settings - $output .= '\n=== Settings \n'; - my $i = 0; - for my $dev_settings ( @ { $devJson->{settings} } ) { - $output .= "[".$i++."]id: $dev_settings->{id} \n"; - $output .= "name: $dev_settings->{name} "; - if (ref ($dev_settings->{value}) eq 'ARRAY' - || ref ($dev_settings->{value}) eq 'HASH'){ - $output .= 'N/A \n'; - } else { - $output .= "value: $dev_settings->{value} \n"; + if ( defined( $hash->{helper}{debug_device} ) + && $hash->{helper}{debug_device} ne 'none' ) + { + Log3 $name, 4, "GardenaSmartBridge DEBUG Device"; + delete $hash->{helper}{debug_device}; + + my @device_spec = ( "name", "id", "category" ); + my $devJson = $decode_json->{devices}; + my $output = '.:{ DEBUG OUTPUT for ' . $devJson->{name} . ' }:. \n'; + + for my $spec (@device_spec) { + $output .= "$spec : $devJson->{$spec} \n"; } - } - $output .= '\n=== Abilities \n'; - $i = 0; - for my $dev_settings ( @ { $devJson->{abilities} } ) { - $output .= "[".$i++."]id: $dev_settings->{id} \n"; - $output .= "name: $dev_settings->{name} "; - if (ref ($dev_settings->{value}) eq 'ARRAY' - || ref ($dev_settings->{value}) eq 'HASH'){ - $output .= 'N/A \n'; - } else { - $output .= "value: $dev_settings->{value} \n"; + + #settings + $output .= '\n=== Settings \n'; + my $i = 0; + for my $dev_settings ( @{ $devJson->{settings} } ) { + $output .= "[" . $i++ . "]id: $dev_settings->{id} \n"; + $output .= "name: $dev_settings->{name} "; + if ( ref( $dev_settings->{value} ) eq 'ARRAY' + || ref( $dev_settings->{value} ) eq 'HASH' ) + { + $output .= 'N/A \n'; + } + else { + $output .= "value: $dev_settings->{value} \n"; + } } - } - $hash->{helper}{debug_device_output} = $output; - asyncOutput($param->{cl}, $hash->{helper}{debug_device_output}); - return; + + $output .= '\n=== Abilities \n'; + $i = 0; + + for my $dev_settings ( @{ $devJson->{abilities} } ) { + $output .= "[" . $i++ . "]id: $dev_settings->{id} \n"; + $output .= "name: $dev_settings->{name} "; + + if ( ref( $dev_settings->{value} ) eq 'ARRAY' + || ref( $dev_settings->{value} ) eq 'HASH' ) + { + $output .= 'N/A \n'; + } + else { + $output .= "value: $dev_settings->{value} \n"; + } + } + + $hash->{helper}{debug_device_output} = $output; + asyncOutput( $param->{cl}, $hash->{helper}{debug_device_output} ); + + return; } readingsSingleUpdate( $hash, 'state', 'Connected', 1 ) if ( defined( $hash->{helper}{locations_id} ) ); @@ -796,16 +810,20 @@ sub ResponseProcessing { # print Dumper $decode_json; - if ( defined( $decode_json->{data} ) && $decode_json->{data} - && ref($decode_json->{data}) eq 'HASH' - && !defined( $hash->{helper}->{user_id})) { + if ( defined( $decode_json->{data} ) + && $decode_json->{data} + && ref( $decode_json->{data} ) eq 'HASH' + && !defined( $hash->{helper}->{user_id} ) ) + { - $hash->{helper}{session_id} = $decode_json->{data}{id}; - $hash->{helper}{user_id} = $decode_json->{data}{attributes}->{user_id}; - $hash->{helper}{refresh_token} = $decode_json->{data}{attributes}->{refresh_token}; - $hash->{helper}{token_expired} = gettimeofday() + $decode_json->{data}{attributes}->{expires_in}; + $hash->{helper}{session_id} = $decode_json->{data}{id}; + $hash->{helper}{user_id} = $decode_json->{data}{attributes}->{user_id}; + $hash->{helper}{refresh_token} = + $decode_json->{data}{attributes}->{refresh_token}; + $hash->{helper}{token_expired} = + gettimeofday() + $decode_json->{data}{attributes}->{expires_in}; - InternalTimer($hash->{helper}{token_expired}, + InternalTimer( $hash->{helper}{token_expired}, "FHEM::GardenaSmartBridge::getToken", $hash ); Write( $hash, undef, undef, undef ); @@ -838,27 +856,76 @@ sub ResponseProcessing { && ref( $decode_json->{devices} ) eq 'ARRAY' && scalar( @{ $decode_json->{devices} } ) > 0 ) { - my @buffer = split( '"devices":\[', $json ); - my ( $json, $tail ) = ParseJSON( $hash, $buffer[1] ); + require SubProcess; - while ($json) { + my $subprocess = + SubProcess->new( { onRun => \&ResponseSubprocessing } ); + $subprocess->{buffer} = $buffer[1]; - Log3 $name, 5, - "GardenaSmartBridge ($name) - Decoding JSON message. Length: " - . length($json) - . " Content: " - . $json; - Log3 $name, 5, - "GardenaSmartBridge ($name) - Vor Sub: Laenge JSON: " - . length($json) - . " Content: " - . $json - . " Tail: " - . $tail; + my $pid = $subprocess->run(); - if ( defined($tail) and $tail ) { + if ( !defined($pid) ) { + Log3( $name, 1, +qq{GardenaSmartBridge ($name) - Cannot execute parse json asynchronously} + ); + + CleanSubprocess($hash); + readingsSingleUpdate( $hash, 'state', + 'Cannot execute parse json asynchronously', 1 ); + return; + } + + Log3( $name, 4, +qq{GardenaSmartBridge ($name) - execute parse json asynchronously (PID="$pid")} + ); + + $hash->{".fhem"}{subprocess} = $subprocess; + + InternalTimer( gettimeofday() + 1, + "FHEM::GardenaSmartBridge::PollChild", $hash ); + } + + Log3 $name, 3, "GardenaSmartBridge ($name) - no Match for processing data"; + + return; +} + +sub PollChild { + my $hash = shift; + + my $name = $hash->{NAME}; + + if ( defined( $hash->{".fhem"}{subprocess} ) ) { + my $subprocess = $hash->{".fhem"}{subprocess}; + my $response = $subprocess->readFromChild(); + + if ( !defined($response) ) { + Log3( $name, 5, +qq{GardenaSmartBridge ($name) - still waiting ($subprocess->{lasterror}).} + ); + + InternalTimer( gettimeofday() + 1, + "FHEM::GardenaSmartBridge::PollChild", $hash ); + return; + } + else { + Log3( $name, 4, +qq{GardenaSmartBridge ($name) - got result from asynchronous parsing} + ); + + my $decode_json; + + $subprocess->wait(); + Log3( $name, 4, + qq{GardenaSmartBridge ($name) - asynchronous finished.} ); + + CleanSubprocess($hash); + + for my $json ( @{$response} ) { + + ################# $decode_json = eval { decode_json($json) }; if ($@) { Log3 $name, 5, @@ -871,26 +938,76 @@ sub ResponseProcessing { if ( defined( $decode_json->{category} ) && $decode_json->{category} eq 'gateway' ); } + } + } +} - ( $json, $tail ) = ParseJSON( $hash, $tail ); +# ResponseSubprocessin muss in eine async ausgelagert werden +###################################### +# Begin Childprozess +###################################### +sub ResponseSubprocessing { + my $subprocess = shift; + my $buffer = $subprocess->{buffer}; + my $response = []; - Log3 $name, 5, - "GardenaSmartBridge ($name) - Nach Sub: Laenge JSON: " - . length($json) - . " Content: " - . $json - . " Tail: " - . $tail; + my ( $json, $tail ) = ParseJSON($buffer); + + while ($json) { + if ( defined($tail) and $tail ) { + push @{$response}, $json; } - return; + ( $json, $tail ) = ParseJSON($tail); } - Log3 $name, 3, "GardenaSmartBridge ($name) - no Match for processing data"; + $subprocess->writeToParent($response); return; } +sub ParseJSON { + my $buffer = shift; + + my $open = 0; + my $close = 0; + my $msg = ''; + my $tail = ''; + + if ($buffer) { + for my $c ( split //, $buffer ) { + if ( $open == $close && $open > 0 ) { + $tail .= $c; + } + else { + + if ( $c eq '{' ) { + + $open++; + + } + elsif ( $c eq '}' ) { + + $close++; + } + + $msg .= $c; + } + } + + if ( $open != $close ) { + + $tail = $msg; + $msg = ''; + } + } + + return ( $msg, $tail ); +} +###################################### +# End Childprozess +###################################### + sub WriteReadings { my $hash = shift; my $decode_json = shift; @@ -940,8 +1057,9 @@ sub WriteReadings { $decode_json->{abilities}[0]{properties}[$properties] {name} . '-' . $t, $v - ) - if ($decode_json->{abilities}[0]{properties}[$properties]{name} !~ /ethernet_status|wifi_status/ ); + ) + if ( $decode_json->{abilities}[0]{properties}[$properties] + {name} !~ /ethernet_status|wifi_status/ ); if ( ( $decode_json->{abilities}[0]{properties} @@ -968,8 +1086,8 @@ sub WriteReadings { [$properties]{name} eq 'wifi_status' ) { readingsBulkUpdateIfChanged( $hash, - 'wifi_status-ssid', $v->{ssid} ) - if (ref($v->{ssid}) ne 'HASH'); + 'wifi_status-ssid', $v->{ssid} ) + if ( ref( $v->{ssid} ) ne 'HASH' ); readingsBulkUpdateIfChanged( $hash, 'wifi_status-mac', $v->{mac} ); readingsBulkUpdateIfChanged( $hash, @@ -1002,25 +1120,23 @@ sub getDevices { my $hash = shift; my $name = $hash->{NAME}; - RemoveInternalTimer($hash, "FHEM::GardenaSmartBridge::getDevices"); + RemoveInternalTimer( $hash, "FHEM::GardenaSmartBridge::getDevices" ); if ( not IsDisabled($name) ) { delete $hash->{helper}{deviceList}; my @list; @list = devspec2array('TYPE=GardenaSmartDevice'); - for my $gardenaDev (@list){ - push( @{ $hash->{helper}{deviceList} }, $gardenaDev ); + for my $gardenaDev (@list) { + push( @{ $hash->{helper}{deviceList} }, $gardenaDev ); } - if ( AttrVal( $name, 'gardenaAccountEmail', 'none' ) ne 'none' - && ( - defined( ReadPassword( $hash, $name ) ) - )) + if ( AttrVal( $name, 'gardenaAccountEmail', 'none' ) ne 'none' + && ( defined( ReadPassword( $hash, $name ) ) ) ) { - Write( $hash, undef, undef, undef ); - Log3 $name, 4, - "GardenaSmartBridge ($name) - fetch device list and device states"; - } # fi gardenaAccountEmail + Write( $hash, undef, undef, undef ); + Log3 $name, 4, +"GardenaSmartBridge ($name) - fetch device list and device states"; + } # fi gardenaAccountEmail } else { readingsSingleUpdate( $hash, 'state', 'disabled', 1 ); @@ -1044,27 +1160,29 @@ sub getToken { readingsSingleUpdate( $hash, 'state', 'get token', 1 ); delete $hash->{helper}{session_id} - if ( defined( $hash->{helper}{session_id} ) - && $hash->{helper}{session_id} ); + if ( exists( $hash->{helper}{session_id} ) ); delete $hash->{helper}{user_id} - if ( defined( $hash->{helper}{user_id} ) && $hash->{helper}{user_id} ); + if ( exists( $hash->{helper}{user_id} ) ); delete $hash->{helper}{locations_id} - if ( defined( $hash->{helper}{locations_id} ) - && $hash->{helper}{locations_id} ); + if ( exists( $hash->{helper}{locations_id} ) ); Write( - $hash, - '"data": {"type":"token", "attributes":{"username": "' - . AttrVal( $name, 'gardenaAccountEmail', 'none' ) - . '","password": "' - . ReadPassword( $hash, $name ) . '", "client_id":"smartgarden-jwt-client"}}', - undef, - undef - ); + $hash, + '"data": {"type":"token", "attributes":{"username": "' + . AttrVal( $name, 'gardenaAccountEmail', 'none' ) + . '","password": "' + . ReadPassword( $hash, $name ) + . '", "client_id":"smartgarden-jwt-client"}}', + undef, + undef + ); - Log3 $name, 4, '"data": {"type":"token", "attributes":{"username": "' - .AttrVal( $name, 'gardenaAccountEmail', 'none' ) . '","password": "' - .ReadPassword( $hash, $name ) . '", "client_id":"smartgarden-jwt-client"}}'; + Log3 $name, 4, + '"data": {"type":"token", "attributes":{"username": "' + . AttrVal( $name, 'gardenaAccountEmail', 'none' ) + . '","password": "' + . ReadPassword( $hash, $name ) + . '", "client_id":"smartgarden-jwt-client"}}'; Log3 $name, 3, "GardenaSmartBridge ($name) - send credentials to fetch Token and locationId"; @@ -1115,7 +1233,7 @@ sub ReadPassword { Log3 $name, 3, "GardenaSmartBridge ($name) - unable to read password from file: $err"; - return undef; + return; } @@ -1141,7 +1259,7 @@ sub ReadPassword { else { Log3 $name, 3, "GardenaSmartBridge ($name) - No password in file"; - return undef; + return; } return; @@ -1159,59 +1277,6 @@ sub Rename { return; } -sub ParseJSON { - my $hash = shift; - my $buffer = shift; - - my $name = $hash->{NAME}; - my $open = 0; - my $close = 0; - my $msg = ''; - my $tail = ''; - - if ($buffer) { - for my $c ( split //, $buffer ) { - if ( $open == $close && $open > 0 ) { - $tail .= $c; - Log3 $name, 5, - "GardenaSmartBridge ($name) - $open == $close and $open > 0"; - - } - elsif ( ( $open == $close ) && ( $c ne '{' ) ) { - - Log3 $name, 5, -"GardenaSmartBridge ($name) - Garbage character before message: " - . $c; - - } - else { - - if ( $c eq '{' ) { - - $open++; - - } - elsif ( $c eq '}' ) { - - $close++; - } - - $msg .= $c; - } - } - - if ( $open != $close ) { - - $tail = $msg; - $msg = ''; - } - } - - Log3 $name, 5, - "GardenaSmartBridge ($name) - return msg: $msg and tail: $tail"; - return ( $msg, $tail ); -} - sub createHttpValueStrings { my ( $hash, $payload, $deviceId, $abilities, $service_id ) = @_; @@ -1220,17 +1285,17 @@ sub createHttpValueStrings { my $uri = ''; my $method = 'POST'; $header .= "\r\nAuthorization: Bearer $session_id" - if ( defined($hash->{helper}{session_id}) ); + if ( defined( $hash->{helper}{session_id} ) ); $header .= "\r\nAuthorization-Provider: husqvarna" - if ( defined($hash->{helper}{session_id}) ); + if ( defined( $hash->{helper}{session_id} ) ); # $header .= "\r\nx-api-key: $session_id" # if ( defined( $hash->{helper}{session_id} ) ); $payload = '{' . $payload . '}' if ( defined($payload) ); - $payload = '{}' if ( !defined($payload) ); + $payload = '{}' if ( !defined($payload) ); if ( $payload eq '{}' ) { - $method = 'GET' if (defined( $hash->{helper}{session_id} ) ); + $method = 'GET' if ( defined( $hash->{helper}{session_id} ) ); $payload = ''; $uri .= '/locations?locatioId=null&user_id=' . $hash->{helper}{user_id} if ( exists( $hash->{helper}{user_id} ) @@ -1243,8 +1308,10 @@ sub createHttpValueStrings { && defined( $hash->{helper}{locations_id} ) ); } - $uri = '/devices/'.InternalVal($hash->{helper}{debug_device}, 'DEVICEID', 0 ) if ( defined ($hash->{helper}{debug_device}) - && defined( $hash->{helper}{locations_id} ) ); + $uri = + '/devices/' . InternalVal( $hash->{helper}{debug_device}, 'DEVICEID', 0 ) + if ( defined( $hash->{helper}{debug_device} ) + && defined( $hash->{helper}{locations_id} ) ); $uri = '/auth/token' if ( !defined( $hash->{helper}{session_id} ) ); if ( defined( $hash->{helper}{locations_id} ) ) { @@ -1252,17 +1319,13 @@ sub createHttpValueStrings { $method = 'PUT'; my $dhash = $modules{GardenaSmartDevice}{defptr}{$deviceId}; - - $uri .= - '/devices/' - . $deviceId - . '/settings/' - . $service_id + + $uri .= '/devices/' . $deviceId . '/settings/' . $service_id if ( defined($abilities) && defined($payload) && $abilities =~ /.*_settings/ ); - } # park until next schedules or override + } # park until next schedules or override elsif (defined($abilities) && defined($payload) && $abilities eq 'mower_timer' ) @@ -1285,7 +1348,7 @@ sub createHttpValueStrings { my $valve_id; if ( $payload =~ m#watering_timer_(\d)# ) { - $method = 'PUT'; + $method = 'PUT'; $valve_id = $1; } $uri .= @@ -1293,7 +1356,11 @@ sub createHttpValueStrings { . $deviceId . '/abilities/' . $abilities - . ( defined($valve_id) ? '/properties/watering_timer_'. $valve_id : '/command') + . ( + defined($valve_id) + ? '/properties/watering_timer_' . $valve_id + : '/command' + ); } elsif (defined($abilities) @@ -1507,9 +1574,9 @@ sub DeletePassword { ], "release_status": "stable", "license": "GPL_2", - "version": "v2.4.6", + "version": "v2.4.7", "author": [ - "Marko Oldenburg " + "Marko Oldenburg " ], "x_fhem_maintainer": [ "CoolTux" diff --git a/FHEM/74_GardenaSmartDevice.pm b/FHEM/74_GardenaSmartDevice.pm index 801e015..d9fdd13 100644 --- a/FHEM/74_GardenaSmartDevice.pm +++ b/FHEM/74_GardenaSmartDevice.pm @@ -1,8 +1,8 @@ ############################################################################### # -# Developed with Kate +# Developed with VSCodium and richterger perl plugin. # -# (c) 2017-2021 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) +# (c) 2017-2022 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) # All rights reserved # # Special thanks goes to comitters: @@ -164,7 +164,7 @@ BEGIN { #-- Export to main context with different name GP_Export( qw( - Initialize + Initialize ) ); @@ -204,22 +204,23 @@ sub Define { my $deviceId = $aArg->[2]; my $category = $aArg->[3]; - $hash->{DEVICEID} = $deviceId; - $hash->{VERSION} = version->parse($VERSION)->normal; - $hash->{helper}{STARTINGPOINTID} = ''; - $hash->{helper}{schedules_paused_until_id} = ''; - $hash->{helper}{eco_mode_id} = ''; - $hash->{helper}{button_config_time_id} = ''; - $hash->{helper}{winter_mode_id} = ''; - - $hash->{helper}{_id} = ''; + $hash->{DEVICEID} = $deviceId; + $hash->{VERSION} = version->parse($VERSION)->normal; + $hash->{helper}{STARTINGPOINTID} = ''; + $hash->{helper}{schedules_paused_until_id} = ''; + $hash->{helper}{eco_mode_id} = ''; + $hash->{helper}{button_config_time_id} = ''; + $hash->{helper}{winter_mode_id} = ''; + + $hash->{helper}{_id} = ''; + # IrrigationControl valve control max 6 - $hash->{helper}{schedules_paused_until_1_id} = ''; - $hash->{helper}{schedules_paused_until_2_id} = ''; - $hash->{helper}{schedules_paused_until_3_id} = ''; - $hash->{helper}{schedules_paused_until_4_id} = ''; - $hash->{helper}{schedules_paused_until_5_id} = ''; - $hash->{helper}{schedules_paused_until_6_id} = ''; + $hash->{helper}{schedules_paused_until_1_id} = ''; + $hash->{helper}{schedules_paused_until_2_id} = ''; + $hash->{helper}{schedules_paused_until_3_id} = ''; + $hash->{helper}{schedules_paused_until_4_id} = ''; + $hash->{helper}{schedules_paused_until_5_id} = ''; + $hash->{helper}{schedules_paused_until_6_id} = ''; CommandAttr( undef, "$name IODev $modules{GardenaSmartBridge}{defptr}{BRIDGE}->{NAME}" ) @@ -283,16 +284,18 @@ sub Attr { } sub Set { - my $hash = shift // return; - my $aArg = shift // return; + my $hash = shift // return; + my $aArg = shift // return; - my $name = shift @$aArg; - my $cmd = shift @$aArg // return qq{"set $name" needs at least one argument}; + my $name = shift @$aArg; + my $cmd = shift @$aArg + // return qq{"set $name" needs at least one argument}; my $payload; my $abilities; my $service_id; - my $mainboard_version = ReadingsVal( $name, 'mower_type-mainboard_version', 0.0 ); + my $mainboard_version = + ReadingsVal( $name, 'mower_type-mainboard_version', 0.0 ); #set default abilitie ... overwrite in cmd to change $abilities = 'mower' @@ -305,51 +308,62 @@ sub Set { $abilities = 'manual_watering' if ( AttrVal( $name, 'model', 'unknown' ) eq 'electronic_pressure_pump' ); - ### mower + ### mower # service_id (eco, parkuntilfurhternotice, startpoints) if ( lc $cmd eq 'parkuntilfurthernotice' ) { $payload = '"name":"park_until_further_notice"'; if ( $mainboard_version > 10.30 ) { - $payload = ' "settings":{"name":"schedules_paused_until","value":"2038-01-18T00:00:00.000Z","device":"'.$hash->{DEVICEID}.'"}'; - $abilities = 'mower_settings' ; - $service_id = $hash->{helper}{schedules_paused_until_id}; + $payload = +' "settings":{"name":"schedules_paused_until","value":"2038-01-18T00:00:00.000Z","device":"' + . $hash->{DEVICEID} . '"}'; + $abilities = 'mower_settings'; + $service_id = $hash->{helper}{schedules_paused_until_id}; } } - elsif ( lc $cmd eq 'parkuntilnexttimer' ) { + elsif ( lc $cmd eq 'parkuntilnexttimer' ) { $payload = '"name":"park_until_next_timer"'; - if ( $mainboard_version > 10.30 ){ - $payload = '"properties":{"name":"mower_timer","value":0}' ; - $abilities = 'mower_timer'; + if ( $mainboard_version > 10.30 ) { + $payload = '"properties":{"name":"mower_timer","value":0}'; + $abilities = 'mower_timer'; } } elsif ( lc $cmd eq 'startresumeschedule' ) { $payload = '"name":"start_resume_schedule"'; if ( $mainboard_version > 10.30 ) { - $payload = ' "settings":{"name":"schedules_paused_until","value":"","device":"'.$hash->{DEVICEID}.'"}'; - $abilities = 'mower_settings' ; - $service_id = $hash->{helper}{schedules_paused_until_id}; + $payload = +' "settings":{"name":"schedules_paused_until","value":"","device":"' + . $hash->{DEVICEID} . '"}'; + $abilities = 'mower_settings'; + $service_id = $hash->{helper}{schedules_paused_until_id}; } } elsif ( lc $cmd eq 'startoverridetimer' ) { $payload = '"name":"start_override_timer","parameters":{"duration":' . $aArg->[0] * 60 . '}'; - if ( $mainboard_version > 10.30 ){ - $payload = '"properties":{"name":"mower_timer","value":'.$aArg->[0] * 60 .'}'; - $abilities = 'mower_timer'; + if ( $mainboard_version > 10.30 ) { + $payload = '"properties":{"name":"mower_timer","value":' + . $aArg->[0] * 60 . '}'; + $abilities = 'mower_timer'; } } elsif ( lc $cmd eq 'startpoint' ) { my $err; - ( $err, $payload, $abilities ) = SetPredefinedStartPoints( $hash, $aArg ); + ( $err, $payload, $abilities ) = + SetPredefinedStartPoints( $hash, $aArg ); $service_id = $hash->{helper}{STARTINGPOINTID}; return $err if ( defined($err) ); } elsif ( lc $cmd eq 'eco' ) { - $payload = '"settings": {"name": "eco_mode", "value": '.$aArg->[0].', "device": "'.$hash->{DEVICEID}.'"}'; - $abilities = 'mower_settings' if ( $mainboard_version > 10.30 ); + $payload = + '"settings": {"name": "eco_mode", "value": ' + . $aArg->[0] + . ', "device": "' + . $hash->{DEVICEID} . '"}'; + $abilities = 'mower_settings' if ( $mainboard_version > 10.30 ); $service_id = $hash->{helper}{eco_mode_id}; - #$abilities['service_id'] = $hash->{helper}{SCHEDULESID} if ( $mainboard_version > 10.30 ); + +#$abilities['service_id'] = $hash->{helper}{SCHEDULESID} if ( $mainboard_version > 10.30 ); } ### electronic_pressure_pump elsif ( lc $cmd eq 'pumptimer' ) { @@ -365,16 +379,15 @@ sub Set { . $aArg->[0] * 60 . ',"valve_id":1}}'; } - elsif ( lc $cmd eq 'manualbuttontime'){ - $service_id = $hash->{helper}{button_config_time_id}; - $payload= - '"properties":{"name":"button_config_time",' - .'"value":' - . $aArg->[0] * 60 - . ',"timestamp":"2021-05-26T19:06:23.680Z"' - . ',"at_bound":null,"unit":"seconds","ability":"' - . $service_id - .'"}'; + elsif ( lc $cmd eq 'manualbuttontime' ) { + $service_id = $hash->{helper}{button_config_time_id}; + $payload = + '"properties":{"name":"button_config_time",' + . '"value":' + . $aArg->[0] * 60 + . ',"timestamp":"2021-05-26T19:06:23.680Z"' + . ',"at_bound":null,"unit":"seconds","ability":"' + . $service_id . '"}'; $abilities = 'watering_button_config'; } elsif ( $cmd =~ m{\AcancelOverride}xms ) { @@ -393,26 +406,40 @@ sub Set { . ',"valve_id":' . $valve_id . '}}'; } - elsif ( $cmd =~ /.*Schedule/ ){ - my $duration = (( defined($aArg->[0]) ? ( ((Time::Piece->new)+(ONE_HOUR * $aArg->[0]) - (Time::Piece->new)->tzoffset )->datetime ).'.000Z' : '2038-01-18T00:00:00.000Z')); - - $abilities = 'wateringcomputer_settings'; - $service_id = $hash->{helper}->{'schedules_paused_until_id'}; - $payload = '"settings":{"name":"schedules_paused_until"' - . ', "value":"' - . ($cmd eq 'resumeSchedule' ? '' : $duration ) - . '","device":"' - . $hash->{DEVICEID} - . '"}'; + elsif ( $cmd =~ /.*Schedule/ ) { + my $duration = ( + ( + defined( $aArg->[0] ) + ? ( + ( + ( Time::Piece->new ) + + ( ONE_HOUR * $aArg->[0] ) - + ( Time::Piece->new )->tzoffset + )->datetime + ) + . '.000Z' + : '2038-01-18T00:00:00.000Z' + ) + ); + + $abilities = 'wateringcomputer_settings'; + $service_id = $hash->{helper}->{'schedules_paused_until_id'}; + $payload = + '"settings":{"name":"schedules_paused_until"' + . ', "value":"' + . ( $cmd eq 'resumeSchedule' ? '' : $duration ) + . '","device":"' + . $hash->{DEVICEID} . '"}'; } elsif ( lc $cmd eq 'on' || lc $cmd eq 'off' || lc $cmd eq 'on-for-timer' ) { my $val = ( - scalar(!@$aArg == 0) && ref($aArg) eq 'ARRAY' + scalar( !@$aArg == 0 ) && ref($aArg) eq 'ARRAY' ? $aArg->[0] * 60 : lc $cmd ); - $payload = '"properties":{"name":"power_timer", "value":"' . $val . '"}'; + $payload = + '"properties":{"name":"power_timer", "value":"' . $val . '"}'; } ### Watering ic24 elsif ( $cmd =~ m{\AmanualDurationValve\d\z}xms ) { @@ -430,34 +457,51 @@ sub Set { . ',"valve_id":' . $valve_id . '}}'; } - elsif ( $cmd eq 'closeAllValves' ){ - $payload = '"name":"close_all_valves","parameters":{}'; + elsif ( $cmd eq 'closeAllValves' ) { + $payload = '"name":"close_all_valves","parameters":{}'; } - elsif ( $cmd =~ /.*ScheduleValve/ ){ - my $valve_id = $aArg->[0]; - my $duration = (( defined($aArg->[1]) ? ( ((Time::Piece->new)+(ONE_HOUR * $aArg->[1]) - (Time::Piece->new)->tzoffset )->datetime ).'.000Z' : '2038-01-18T00:00:00.000Z')); - - $abilities = 'irrigation_settings'; - $service_id = $hash->{helper}->{'schedules_paused_until_'.$valve_id.'_id'}; - $payload = '"settings":{"name":"schedules_paused_until_' - . $valve_id - . '", "value":"' - . ($cmd eq 'resumeScheduleValve' ? '' : $duration ) - . '","device":"' - . $hash->{DEVICEID} - . '"}'; + elsif ( $cmd =~ /.*ScheduleValve/ ) { + my $valve_id = $aArg->[0]; + my $duration = ( + ( + defined( $aArg->[1] ) + ? ( + ( + ( Time::Piece->new ) + + ( ONE_HOUR * $aArg->[1] ) - + ( Time::Piece->new )->tzoffset + )->datetime + ) + . '.000Z' + : '2038-01-18T00:00:00.000Z' + ) + ); + + $abilities = 'irrigation_settings'; + $service_id = + $hash->{helper}->{ 'schedules_paused_until_' . $valve_id . '_id' }; + $payload = + '"settings":{"name":"schedules_paused_until_' + . $valve_id + . '", "value":"' + . ( $cmd eq 'resumeScheduleValve' ? '' : $duration ) + . '","device":"' + . $hash->{DEVICEID} . '"}'; } ### Sensors elsif ( lc $cmd eq 'refresh' ) { my $sensname = $aArg->[0]; if ( lc $sensname eq 'temperature' ) { - if ( ReadingsVal( $name, 'device_info-category', 'sensor' ) eq 'sensor') { - $payload = '"name":"measure_ambient_temperature"'; - $abilities = 'ambient_temperature'; - } else { - $payload = '"name":"measure_soil_temperature"'; - $abilities = 'soil_temperature'; + if ( ReadingsVal( $name, 'device_info-category', 'sensor' ) eq + 'sensor' ) + { + $payload = '"name":"measure_ambient_temperature"'; + $abilities = 'ambient_temperature'; + } + else { + $payload = '"name":"measure_soil_temperature"'; + $abilities = 'soil_temperature'; } } elsif ( lc $sensname eq 'light' ) { @@ -471,13 +515,13 @@ sub Set { } } ## winter sleep - elsif ( lc $cmd eq 'winter_mode') { - $payload = '"settings":{"name":"winter_mode","value":"' - . $aArg->[0] - .'","device":"' - . $hash->{DEVICEID} - .'"}'; - $abilities = 'winter_settings'; + elsif ( lc $cmd eq 'winter_mode' ) { + $payload = + '"settings":{"name":"winter_mode","value":"' + . $aArg->[0] + . '","device":"' + . $hash->{DEVICEID} . '"}'; + $abilities = 'winter_settings'; $service_id = $hash->{helper}->{'winter_mode_id'}; } else { @@ -488,7 +532,8 @@ sub Set { 'parkUntilFurtherNotice:noArg parkUntilNextTimer:noArg startResumeSchedule:noArg startOverrideTimer:slider,0,1,240 startpoint' if ( AttrVal( $name, 'model', 'unknown' ) eq 'mower' ); - $list .= 'manualOverride:slider,1,1,59 cancelOverride:noArg resumeSchedule:noArg stopSchedule manualButtonTime:slider,0,2,100' + $list .= +'manualOverride:slider,1,1,59 cancelOverride:noArg resumeSchedule:noArg stopSchedule manualButtonTime:slider,0,2,100' if ( AttrVal( $name, 'model', 'unknown' ) eq 'watering_computer' ); $list .= @@ -497,13 +542,16 @@ sub Set { $list .= 'refresh:temperature,humidity' if ( AttrVal( $name, 'model', 'unknown' ) eq 'sensor' ); + # add light for old sensors $list .= ',light' - if ( AttrVal( $name, 'model', 'unknown' ) eq 'sensor' - && ReadingsVal($name, 'device_info-category', 'unknown') eq 'sensor' ); + if ( AttrVal( $name, 'model', 'unknown' ) eq 'sensor' + && ReadingsVal( $name, 'device_info-category', 'unknown' ) eq + 'sensor' ); $list .= 'on:noArg off:noArg on-for-timer:slider,0,1,720' if ( AttrVal( $name, 'model', 'unknown' ) eq 'power' ); + # all devices has abilitie to fall a sleep $list .= ' winter_mode:awake,hibernate'; return "Unknown argument $cmd, choose one of $list"; @@ -584,25 +632,30 @@ sub WriteReadings { for my $propertie ( @{ $decode_json->{abilities}[$abilities]{properties} } ) { - if ( exists($decode_json->{abilities}[$abilities]{name}) - && ( - $decode_json->{abilities}[$abilities]{name} eq 'watering' ) - ) { - if ( $propertie->{name} eq 'button_config_time' ) - { - if ( $hash->{helper}{$propertie->{name}.'_id'} ne - $decode_json->{abilities}[$abilities]{id} ) - { - $hash->{helper}{$propertie->{name}.'_id'} = - $decode_json->{abilities}[$abilities]{id}; - } - readingsBulkUpdateIfChanged( - $hash, - 'manualButtonTime', - (RigReadingsValue( $hash, $propertie->{value} / 60) ) - ); - next; - } + if ( + exists( $decode_json->{abilities}[$abilities]{name} ) + && ( $decode_json->{abilities}[$abilities]{name} eq + 'watering' ) + ) + { + if ( $propertie->{name} eq 'button_config_time' ) { + if ( $hash->{helper}{ $propertie->{name} . '_id' } ne + $decode_json->{abilities}[$abilities]{id} ) + { + $hash->{helper}{ $propertie->{name} . '_id' } = + $decode_json->{abilities}[$abilities]{id}; + } + readingsBulkUpdateIfChanged( + $hash, + 'manualButtonTime', + ( + RigReadingsValue( + $hash, $propertie->{value} / 60 + ) + ) + ); + next; + } } readingsBulkUpdateIfChanged( @@ -653,21 +706,22 @@ sub WriteReadings { || $decode_json->{abilities}[$abilities]{name} . '-' . $propertie->{name} eq 'light-light' ) ); - + readingsBulkUpdateIfChanged( $hash, $decode_json->{abilities}[$abilities]{name} . '-' - . $propertie->{name} + . $propertie->{name} . '_timestamp', - Time::Piece->strptime(RigReadingsValue( $hash, $propertie->{timestamp} ), "%Y-%m-%d %H:%M:%S")->strftime('%s') - + Time::Piece->strptime( + RigReadingsValue( $hash, $propertie->{timestamp} ), + "%Y-%m-%d %H:%M:%S" )->strftime('%s') + ) if ( - defined( $propertie->{value} ) + defined( $propertie->{value} ) && ( $decode_json->{abilities}[$abilities]{name} . '-' - . $propertie->{name} eq 'mower_timer-mower_timer' - ) - ); + . $propertie->{name} eq 'mower_timer-mower_timer' ) + ); readingsBulkUpdateIfChanged( $hash, @@ -707,31 +761,33 @@ sub WriteReadings { } while ( $abilities >= 0 ); do { - #Log3 $name, 1, "Settings pro Device : ".$decode_json->{settings}[$settings]{name}; - #Log3 $name, 1, " - KEIN ARRAY" if ( ref( $decode_json->{settings}[$settings]{value} ) ne "ARRAY"); - #Log3 $name, 1, " - IST ARRAY" if ( ref( $decode_json->{settings}[$settings]{value} ) eq "ARRAY"); +#Log3 $name, 1, "Settings pro Device : ".$decode_json->{settings}[$settings]{name}; +#Log3 $name, 1, " - KEIN ARRAY" if ( ref( $decode_json->{settings}[$settings]{value} ) ne "ARRAY"); +#Log3 $name, 1, " - IST ARRAY" if ( ref( $decode_json->{settings}[$settings]{value} ) eq "ARRAY"); - if ( exists($decode_json->{settings}[$settings]{name}) - && ( - $decode_json->{settings}[$settings]{name} =~ /schedules_paused_until_?\d?$/ - || $decode_json->{settings}[$settings]{name} eq 'eco_mode' - || $decode_json->{settings}[$settings]{name} eq 'winter_mode' ) - ) - { - if ( $hash->{helper}{$decode_json->{settings}[$settings]{name}.'_id'} ne + if ( + exists( $decode_json->{settings}[$settings]{name} ) + && ( $decode_json->{settings}[$settings]{name} =~ + /schedules_paused_until_?\d?$/ + || $decode_json->{settings}[$settings]{name} eq 'eco_mode' + || $decode_json->{settings}[$settings]{name} eq 'winter_mode' ) + ) + { + if ( $hash->{helper} + { $decode_json->{settings}[$settings]{name} . '_id' } ne $decode_json->{settings}[$settings]{id} ) { - $hash->{helper}{$decode_json->{settings}[$settings]{name}.'_id'} = + $hash->{helper} + { $decode_json->{settings}[$settings]{name} . '_id' } = $decode_json->{settings}[$settings]{id}; } + # save winter mode as reading - readingsBulkUpdateIfChanged( - $hash, - 'winter_mode', - $decode_json->{settings}[$settings]{value} - ) if ($decode_json->{settings}[$settings]{name} eq 'winter_mode'); + readingsBulkUpdateIfChanged( $hash, 'winter_mode', + $decode_json->{settings}[$settings]{value} ) + if ( $decode_json->{settings}[$settings]{name} eq 'winter_mode' ); } - + if ( ref( $decode_json->{settings}[$settings]{value} ) eq "ARRAY" && $decode_json->{settings}[$settings]{name} eq 'starting_points' ) { @@ -763,36 +819,50 @@ sub WriteReadings { $settings--; } while ( $settings >= 0 ); - - my $online_state = ReadingsVal($name , 'device_info-connection_status', 'unknown'); - + my $online_state = + ReadingsVal( $name, 'device_info-connection_status', 'unknown' ); + readingsBulkUpdate( $hash, 'state', - $online_state eq 'online' ? - ReadingsVal( $name, 'mower-status', 'readingsValError') : 'offline' - ) + $online_state eq 'online' + ? ReadingsVal( $name, 'mower-status', 'readingsValError' ) + : 'offline' ) if ( AttrVal( $name, 'model', 'unknown' ) eq 'mower' ); readingsBulkUpdate( $hash, 'state', ( - ReadingsVal( $name, 'watering-watering_timer_1_duration', 0 ) - =~ m{\A[1-9]([0-9]+)?\z}xms + ReadingsVal( $name, 'watering-watering_timer_1_duration', 0 ) =~ + m{\A[1-9]([0-9]+)?\z}xms ? RigReadingsValue( $hash, 'open' ) : RigReadingsValue( $hash, 'closed' ) ) ) if ( AttrVal( $name, 'model', 'unknown' ) eq 'watering_computer' ); - if ( AttrVal( $name, 'model', 'unknown' ) eq 'sensor' ) { - my $state_string = ( ReadingsVal($name, 'device_info-category', 'unknown') eq 'sensor') ? 'T: ' .ReadingsVal( $name, 'ambient_temperature-temperature', 'readingsValError' ) . '°C, ' : 'T: ' .ReadingsVal( $name, 'soil_temperature-temperature', 'readingsValError' ) . '°C, ' ; - $state_string .= 'H: '. ReadingsVal( $name, 'humidity-humidity', 'readingsValError' ). '%'; - $state_string .= ', L: ' . ReadingsVal( $name, 'light-light', 'readingsValError' ) . 'lux' if (ReadingsVal($name, 'device_info-category', 'unknown') eq 'sensor'); - - # if ( $online_state eq 'offline') { - # readingsBulkUpdate( $hash, 'humidity-humidity', '-1' ); - # readingsBulkUpdate( $hash, 'ambient_temperature-temperature', '-1' ) if (ReadingsVal($name, 'device_info-category', 'unknown') eq 'sensor'); - # readingsBulkUpdate( $hash, 'light-light', '-1' ) if (ReadingsVal($name, 'device_info-category', 'unknown') eq 'sensor'); - # } - readingsBulkUpdate($hash, 'state', $online_state eq 'online' ? $state_string : 'offline' ) + my $state_string = + ( ReadingsVal( $name, 'device_info-category', 'unknown' ) eq + 'sensor' ) + ? 'T: ' + . ReadingsVal( $name, 'ambient_temperature-temperature', + 'readingsValError' ) + . '°C, ' + : 'T: ' + . ReadingsVal( $name, 'soil_temperature-temperature', + 'readingsValError' ) + . '°C, '; + $state_string .= 'H: ' + . ReadingsVal( $name, 'humidity-humidity', 'readingsValError' ) . '%'; + $state_string .= ', L: ' + . ReadingsVal( $name, 'light-light', 'readingsValError' ) . 'lux' + if ( ReadingsVal( $name, 'device_info-category', 'unknown' ) eq + 'sensor' ); + +# if ( $online_state eq 'offline') { +# readingsBulkUpdate( $hash, 'humidity-humidity', '-1' ); +# readingsBulkUpdate( $hash, 'ambient_temperature-temperature', '-1' ) if (ReadingsVal($name, 'device_info-category', 'unknown') eq 'sensor'); +# readingsBulkUpdate( $hash, 'light-light', '-1' ) if (ReadingsVal($name, 'device_info-category', 'unknown') eq 'sensor'); +# } + readingsBulkUpdate( $hash, 'state', + $online_state eq 'online' ? $state_string : 'offline' ); } readingsBulkUpdate( @@ -977,7 +1047,7 @@ sub Zulu2LocalString { return ( sprintf( "%04d-%02d-%02d %02d:%02d:%s", - $lyear, $lmonth, $lday, + $lyear, $lmonth, $lday, $lhour, $datemin, substr( $rest, 0, 2 ) ) ); @@ -998,10 +1068,10 @@ sub Zulu2LocalString { } sub SetPredefinedStartPoints { - my $hash = shift; - my $aArg = shift; + my $hash = shift; + my $aArg = shift; - my ($startpoint_state,$startpoint_num,@morestartpoints) = @{$aArg}; + my ( $startpoint_state, $startpoint_num, @morestartpoints ) = @{$aArg}; my $name = $hash->{NAME}; my $payload; @@ -1049,6 +1119,7 @@ sub SetPredefinedStartPoints { $payload = '"settings": ' . encode_json($decode_json_settings); $abilities = 'mower_settings'; + #$abilities['service_id'] = $hash->{helper}{STARTINGPOINTID}; } else { @@ -1406,7 +1477,7 @@ sub SetPredefinedStartPoints { "license": "GPL_2", "version": "v2.4.2", "author": [ - "Marko Oldenburg " + "Marko Oldenburg " ], "x_fhem_maintainer": [ "CoolTux" diff --git a/controls_GardenaSmartDevice.txt b/controls_GardenaSmartDevice.txt index 94b7649..9a5ca74 100644 --- a/controls_GardenaSmartDevice.txt +++ b/controls_GardenaSmartDevice.txt @@ -1,2 +1,2 @@ -UPD 2021-09-27_10:50:10 48067 FHEM/73_GardenaSmartBridge.pm -UPD 2021-09-27_10:50:10 56217 FHEM/74_GardenaSmartDevice.pm +UPD 2022-01-31_19:35:20 49370 FHEM/73_GardenaSmartBridge.pm +UPD 2022-01-31_19:35:42 56993 FHEM/74_GardenaSmartDevice.pm -- 2.45.2 From 8e470ccbb6537087b1bab1e1d379a0f145495735 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Tue, 1 Feb 2022 09:26:31 +0100 Subject: [PATCH 02/13] Subject line (try to keep under 50 characters) Undefined subroutine &FHEM::GardenaSmartBridge::CleanSubprocess called [Ticket: none] --- FHEM/73_GardenaSmartBridge.pm | 9 +++++++++ controls_GardenaSmartDevice.txt | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/FHEM/73_GardenaSmartBridge.pm b/FHEM/73_GardenaSmartBridge.pm index 4a80358..a161d5b 100644 --- a/FHEM/73_GardenaSmartBridge.pm +++ b/FHEM/73_GardenaSmartBridge.pm @@ -1008,6 +1008,15 @@ sub ParseJSON { # End Childprozess ###################################### +sub CleanSubprocess { + my $hash = shift; + + my $name = $hash->{NAME}; + + delete( $hash->{".fhem"}{subprocess} ); + Log3( $name, 4, qq{GardenaSmartBridge ($name) - clean Subprocess} ); +} + sub WriteReadings { my $hash = shift; my $decode_json = shift; diff --git a/controls_GardenaSmartDevice.txt b/controls_GardenaSmartDevice.txt index 9a5ca74..2b02a72 100644 --- a/controls_GardenaSmartDevice.txt +++ b/controls_GardenaSmartDevice.txt @@ -1,2 +1,2 @@ -UPD 2022-01-31_19:35:20 49370 FHEM/73_GardenaSmartBridge.pm +UPD 2022-02-01_09:23:35 49566 FHEM/73_GardenaSmartBridge.pm UPD 2022-01-31_19:35:42 56993 FHEM/74_GardenaSmartDevice.pm -- 2.45.2 From bd06f262482a0cc2aae7157bee7ec5d38ffb0350 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Tue, 1 Feb 2022 09:54:42 +0100 Subject: [PATCH 03/13] no array reference found. will be check [Ticket: no] --- FHEM/73_GardenaSmartBridge.pm | 37 ++++++++++++++++++++------------- controls_GardenaSmartDevice.txt | 2 +- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/FHEM/73_GardenaSmartBridge.pm b/FHEM/73_GardenaSmartBridge.pm index a161d5b..fa9134d 100644 --- a/FHEM/73_GardenaSmartBridge.pm +++ b/FHEM/73_GardenaSmartBridge.pm @@ -62,7 +62,7 @@ use warnings; use POSIX; use FHEM::Meta; -#use Data::Dumper; +use Data::Dumper; use HttpUtils; @@ -923,21 +923,28 @@ qq{GardenaSmartBridge ($name) - got result from asynchronous parsing} CleanSubprocess($hash); - for my $json ( @{$response} ) { + if ( ref( @{$response} ) eq 'ARRAY' ) { + for my $json ( @{$response} ) { - ################# - $decode_json = eval { decode_json($json) }; - if ($@) { - Log3 $name, 5, + ################# + $decode_json = eval { decode_json($json) }; + if ($@) { + Log3 $name, 5, "GardenaSmartBridge ($name) - JSON error while request: $@"; - } + } - Dispatch( $hash, $json, undef ) - if ( $decode_json->{category} ne 'gateway' ); - WriteReadings( $hash, $decode_json ) - if ( defined( $decode_json->{category} ) - && $decode_json->{category} eq 'gateway' ); + Dispatch( $hash, $json, undef ) + if ( $decode_json->{category} ne 'gateway' ); + WriteReadings( $hash, $decode_json ) + if ( defined( $decode_json->{category} ) + && $decode_json->{category} eq 'gateway' ); + } } + + Log3 $name, 3, +"GardenaSmartBridge ($name) - It looks like so is no Array reference at response"; + Log3 $name, 3, + "GardenaSmartBridge ($name) - Response ist: " . Dumper $response; } } } @@ -949,19 +956,19 @@ qq{GardenaSmartBridge ($name) - got result from asynchronous parsing} sub ResponseSubprocessing { my $subprocess = shift; my $buffer = $subprocess->{buffer}; - my $response = []; + my @response = (); my ( $json, $tail ) = ParseJSON($buffer); while ($json) { if ( defined($tail) and $tail ) { - push @{$response}, $json; + push @response, $json; } ( $json, $tail ) = ParseJSON($tail); } - $subprocess->writeToParent($response); + $subprocess->writeToParent( \@response ); return; } diff --git a/controls_GardenaSmartDevice.txt b/controls_GardenaSmartDevice.txt index 2b02a72..f791c4a 100644 --- a/controls_GardenaSmartDevice.txt +++ b/controls_GardenaSmartDevice.txt @@ -1,2 +1,2 @@ -UPD 2022-02-01_09:23:35 49566 FHEM/73_GardenaSmartBridge.pm +UPD 2022-02-01_09:54:04 49897 FHEM/73_GardenaSmartBridge.pm UPD 2022-01-31_19:35:42 56993 FHEM/74_GardenaSmartDevice.pm -- 2.45.2 From ddbe14517995d93ad45087dc97a075f3cea4544a Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Tue, 1 Feb 2022 10:59:08 +0100 Subject: [PATCH 04/13] Subject line (try to keep under 50 characters) Multi-line description of commit, feel free to be detailed. [Ticket: X] --- FHEM/73_GardenaSmartBridge.pm | 2 +- controls_GardenaSmartDevice.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/FHEM/73_GardenaSmartBridge.pm b/FHEM/73_GardenaSmartBridge.pm index fa9134d..a402c06 100644 --- a/FHEM/73_GardenaSmartBridge.pm +++ b/FHEM/73_GardenaSmartBridge.pm @@ -923,7 +923,7 @@ qq{GardenaSmartBridge ($name) - got result from asynchronous parsing} CleanSubprocess($hash); - if ( ref( @{$response} ) eq 'ARRAY' ) { + if ( ref($response) eq 'ARRAY' ) { for my $json ( @{$response} ) { ################# diff --git a/controls_GardenaSmartDevice.txt b/controls_GardenaSmartDevice.txt index f791c4a..03b8b81 100644 --- a/controls_GardenaSmartDevice.txt +++ b/controls_GardenaSmartDevice.txt @@ -1,2 +1,2 @@ -UPD 2022-02-01_09:54:04 49897 FHEM/73_GardenaSmartBridge.pm +UPD 2022-02-01_10:58:50 49892 FHEM/73_GardenaSmartBridge.pm UPD 2022-01-31_19:35:42 56993 FHEM/74_GardenaSmartDevice.pm -- 2.45.2 From 5d245d5a3dc59c9731ebec7be7bc8744053f3cb2 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Tue, 1 Feb 2022 11:53:08 +0100 Subject: [PATCH 05/13] Subject line (try to keep under 50 characters) Multi-line description of commit, feel free to be detailed. [Ticket: X] --- FHEM/73_GardenaSmartBridge.pm | 10 +++++----- controls_GardenaSmartDevice.txt | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/FHEM/73_GardenaSmartBridge.pm b/FHEM/73_GardenaSmartBridge.pm index a402c06..b4351ba 100644 --- a/FHEM/73_GardenaSmartBridge.pm +++ b/FHEM/73_GardenaSmartBridge.pm @@ -899,9 +899,9 @@ sub PollChild { if ( defined( $hash->{".fhem"}{subprocess} ) ) { my $subprocess = $hash->{".fhem"}{subprocess}; - my $response = $subprocess->readFromChild(); + my @response = $subprocess->readFromChild(); - if ( !defined($response) ) { + if ( !defined(@response) ) { Log3( $name, 5, qq{GardenaSmartBridge ($name) - still waiting ($subprocess->{lasterror}).} ); @@ -923,8 +923,8 @@ qq{GardenaSmartBridge ($name) - got result from asynchronous parsing} CleanSubprocess($hash); - if ( ref($response) eq 'ARRAY' ) { - for my $json ( @{$response} ) { + if ( scalar(@response) > 0 ) { + for my $json (@response) { ################# $decode_json = eval { decode_json($json) }; @@ -968,7 +968,7 @@ sub ResponseSubprocessing { ( $json, $tail ) = ParseJSON($tail); } - $subprocess->writeToParent( \@response ); + $subprocess->writeToParent(@response); return; } diff --git a/controls_GardenaSmartDevice.txt b/controls_GardenaSmartDevice.txt index 03b8b81..54905ea 100644 --- a/controls_GardenaSmartDevice.txt +++ b/controls_GardenaSmartDevice.txt @@ -1,2 +1,2 @@ -UPD 2022-02-01_10:58:50 49892 FHEM/73_GardenaSmartBridge.pm +UPD 2022-02-01_11:52:56 49880 FHEM/73_GardenaSmartBridge.pm UPD 2022-01-31_19:35:42 56993 FHEM/74_GardenaSmartDevice.pm -- 2.45.2 From f3f2688292f4d97aa9318e7b575d4a7e33cb4f53 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Tue, 1 Feb 2022 12:42:32 +0100 Subject: [PATCH 06/13] Subject line (try to keep under 50 characters) Multi-line description of commit, feel free to be detailed. [Ticket: X] --- FHEM/73_GardenaSmartBridge.pm | 5 ++++- controls_GardenaSmartDevice.txt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/FHEM/73_GardenaSmartBridge.pm b/FHEM/73_GardenaSmartBridge.pm index b4351ba..6e3b977 100644 --- a/FHEM/73_GardenaSmartBridge.pm +++ b/FHEM/73_GardenaSmartBridge.pm @@ -901,7 +901,10 @@ sub PollChild { my $subprocess = $hash->{".fhem"}{subprocess}; my @response = $subprocess->readFromChild(); - if ( !defined(@response) ) { + Log3 $name, 3, + "GardenaSmartBridge ($name) - Response ist: " . Dumper $response; + + if ( scalar(@response) == 0 ) { Log3( $name, 5, qq{GardenaSmartBridge ($name) - still waiting ($subprocess->{lasterror}).} ); diff --git a/controls_GardenaSmartDevice.txt b/controls_GardenaSmartDevice.txt index 54905ea..8f94b7c 100644 --- a/controls_GardenaSmartDevice.txt +++ b/controls_GardenaSmartDevice.txt @@ -1,2 +1,2 @@ -UPD 2022-02-01_11:52:56 49880 FHEM/73_GardenaSmartBridge.pm +UPD 2022-02-01_12:42:22 49983 FHEM/73_GardenaSmartBridge.pm UPD 2022-01-31_19:35:42 56993 FHEM/74_GardenaSmartDevice.pm -- 2.45.2 From 157e9fc58cb0fce8e6d42aa4cb53b67534270033 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Tue, 1 Feb 2022 12:53:37 +0100 Subject: [PATCH 07/13] Subject line (try to keep under 50 characters) Multi-line description of commit, feel free to be detailed. [Ticket: X] --- FHEM/73_GardenaSmartBridge.pm | 4 ++-- controls_GardenaSmartDevice.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/FHEM/73_GardenaSmartBridge.pm b/FHEM/73_GardenaSmartBridge.pm index 6e3b977..860aaea 100644 --- a/FHEM/73_GardenaSmartBridge.pm +++ b/FHEM/73_GardenaSmartBridge.pm @@ -902,7 +902,7 @@ sub PollChild { my @response = $subprocess->readFromChild(); Log3 $name, 3, - "GardenaSmartBridge ($name) - Response ist: " . Dumper $response; + "GardenaSmartBridge ($name) - Response ist: " . Dumper @response; if ( scalar(@response) == 0 ) { Log3( $name, 5, @@ -947,7 +947,7 @@ qq{GardenaSmartBridge ($name) - got result from asynchronous parsing} Log3 $name, 3, "GardenaSmartBridge ($name) - It looks like so is no Array reference at response"; Log3 $name, 3, - "GardenaSmartBridge ($name) - Response ist: " . Dumper $response; + "GardenaSmartBridge ($name) - Response ist: " . Dumper @response; } } } diff --git a/controls_GardenaSmartDevice.txt b/controls_GardenaSmartDevice.txt index 8f94b7c..f3bc55f 100644 --- a/controls_GardenaSmartDevice.txt +++ b/controls_GardenaSmartDevice.txt @@ -1,2 +1,2 @@ -UPD 2022-02-01_12:42:22 49983 FHEM/73_GardenaSmartBridge.pm +UPD 2022-02-01_12:53:28 49983 FHEM/73_GardenaSmartBridge.pm UPD 2022-01-31_19:35:42 56993 FHEM/74_GardenaSmartDevice.pm -- 2.45.2 From 673445e3396e25b80a7f9c6fa6a17a0b02ed5978 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Tue, 1 Feb 2022 13:05:53 +0100 Subject: [PATCH 08/13] Subject line (try to keep under 50 characters) Multi-line description of commit, feel free to be detailed. [Ticket: X] --- FHEM/73_GardenaSmartBridge.pm | 5 +++++ controls_GardenaSmartDevice.txt | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/FHEM/73_GardenaSmartBridge.pm b/FHEM/73_GardenaSmartBridge.pm index 860aaea..1191829 100644 --- a/FHEM/73_GardenaSmartBridge.pm +++ b/FHEM/73_GardenaSmartBridge.pm @@ -966,11 +966,16 @@ sub ResponseSubprocessing { while ($json) { if ( defined($tail) and $tail ) { push @response, $json; + Log3 'Gardena Subprocess', 2, + "GardenaSmartBridge (Gardena) - JSON ist: $json"; } ( $json, $tail ) = ParseJSON($tail); } + Log3 'Gardena Subprocess', 2, + "GardenaSmartBridge (Gardena) - Response ist: " . Dumper @response; + $subprocess->writeToParent(@response); return; diff --git a/controls_GardenaSmartDevice.txt b/controls_GardenaSmartDevice.txt index f3bc55f..63b02a0 100644 --- a/controls_GardenaSmartDevice.txt +++ b/controls_GardenaSmartDevice.txt @@ -1,2 +1,2 @@ -UPD 2022-02-01_12:53:28 49983 FHEM/73_GardenaSmartBridge.pm +UPD 2022-02-01_13:05:43 50198 FHEM/73_GardenaSmartBridge.pm UPD 2022-01-31_19:35:42 56993 FHEM/74_GardenaSmartDevice.pm -- 2.45.2 From b61458a45eae0d1365c17ccac9f4b7130bdbf1e0 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Tue, 1 Feb 2022 17:01:49 +0100 Subject: [PATCH 09/13] code clean up after add run parseJSON function ansynchron [Ticket: no] --- FHEM/73_GardenaSmartBridge.pm | 149 ++++++++++++++------------------ FHEM/74_GardenaSmartDevice.pm | 36 +++----- controls_GardenaSmartDevice.txt | 4 +- 3 files changed, 75 insertions(+), 114 deletions(-) diff --git a/FHEM/73_GardenaSmartBridge.pm b/FHEM/73_GardenaSmartBridge.pm index 1191829..797807d 100644 --- a/FHEM/73_GardenaSmartBridge.pm +++ b/FHEM/73_GardenaSmartBridge.pm @@ -62,16 +62,15 @@ use warnings; use POSIX; use FHEM::Meta; -use Data::Dumper; - use HttpUtils; my $missingModul = ''; -eval "use Encode qw(encode encode_utf8 decode_utf8);1" +eval { use Encode qw /encode_utf8 decode_utf8/; 1 } or $missingModul .= "Encode "; # eval "use JSON;1" || $missingModul .= 'JSON '; -eval "use IO::Socket::SSL;1" or $missingModul .= 'IO::Socket::SSL '; +eval { use IO::Socket::SSL; 1 } + or $missingModul .= 'IO::Socket::SSL '; # try to use JSON::MaybeXS wrapper # for chance of better performance + open code @@ -79,15 +78,11 @@ 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' @@ -96,10 +91,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 ... @@ -107,10 +99,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 ... @@ -118,10 +107,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 ... @@ -129,20 +115,17 @@ 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; - } - } - } - } -} + }; + }; + }; + }; +}; ## Import der FHEM Funktionen #-- Run before package compilation @@ -808,8 +791,6 @@ sub ResponseProcessing { } } - # print Dumper $decode_json; - if ( defined( $decode_json->{data} ) && $decode_json->{data} && ref( $decode_json->{data} ) eq 'HASH' @@ -892,6 +873,42 @@ qq{GardenaSmartBridge ($name) - execute parse json asynchronously (PID="$pid")} return; } +sub ResponseProcessingFinalFromSubProcessing { + my $hash = shift; + my $response = shift; + + my $name = $hash->{NAME}; + + my @response = split '\|,', $response; + + Log3( $name, 4, + qq{GardenaSmartBridge ($name) - got result from asynchronous parsing} ); + + my $decode_json; + + Log3( $name, 4, qq{GardenaSmartBridge ($name) - asynchronous finished.} ); + + if ( scalar(@response) > 0 ) { + for my $json (@response) { + + ################# + $decode_json = eval { decode_json($json) }; + if ($@) { + Log3 $name, 5, + "GardenaSmartBridge ($name) - JSON error while request: $@"; + } + + Dispatch( $hash, $json, undef ) + if ( $decode_json->{category} ne 'gateway' ); + WriteReadings( $hash, $decode_json ) + if ( defined( $decode_json->{category} ) + && $decode_json->{category} eq 'gateway' ); + } + } + + return; +} + sub PollChild { my $hash = shift; @@ -899,57 +916,24 @@ sub PollChild { if ( defined( $hash->{".fhem"}{subprocess} ) ) { my $subprocess = $hash->{".fhem"}{subprocess}; - my @response = $subprocess->readFromChild(); - - Log3 $name, 3, - "GardenaSmartBridge ($name) - Response ist: " . Dumper @response; - - if ( scalar(@response) == 0 ) { - Log3( $name, 5, -qq{GardenaSmartBridge ($name) - still waiting ($subprocess->{lasterror}).} - ); - - InternalTimer( gettimeofday() + 1, - "FHEM::GardenaSmartBridge::PollChild", $hash ); - return; - } - else { - Log3( $name, 4, -qq{GardenaSmartBridge ($name) - got result from asynchronous parsing} - ); - - my $decode_json; + my $response = $subprocess->readFromChild(); + if ( defined($response) ) { + ResponseProcessingFinalFromSubProcessing( $hash, $response ); $subprocess->wait(); - Log3( $name, 4, - qq{GardenaSmartBridge ($name) - asynchronous finished.} ); - CleanSubprocess($hash); - - if ( scalar(@response) > 0 ) { - for my $json (@response) { - - ################# - $decode_json = eval { decode_json($json) }; - if ($@) { - Log3 $name, 5, -"GardenaSmartBridge ($name) - JSON error while request: $@"; - } - - Dispatch( $hash, $json, undef ) - if ( $decode_json->{category} ne 'gateway' ); - WriteReadings( $hash, $decode_json ) - if ( defined( $decode_json->{category} ) - && $decode_json->{category} eq 'gateway' ); - } - } - - Log3 $name, 3, -"GardenaSmartBridge ($name) - It looks like so is no Array reference at response"; - Log3 $name, 3, - "GardenaSmartBridge ($name) - Response ist: " . Dumper @response; } + + Log3( $name, 5, +qq{GardenaSmartBridge ($name) - still waiting ($subprocess->{lasterror}).} + ); + + InternalTimer( gettimeofday() + 1, + "FHEM::GardenaSmartBridge::PollChild", $hash ); + return; } + + return; } # ResponseSubprocessin muss in eine async ausgelagert werden @@ -966,17 +950,12 @@ sub ResponseSubprocessing { while ($json) { if ( defined($tail) and $tail ) { push @response, $json; - Log3 'Gardena Subprocess', 2, - "GardenaSmartBridge (Gardena) - JSON ist: $json"; } ( $json, $tail ) = ParseJSON($tail); } - Log3 'Gardena Subprocess', 2, - "GardenaSmartBridge (Gardena) - Response ist: " . Dumper @response; - - $subprocess->writeToParent(@response); + $subprocess->writeToParent( join '|', @response ); return; } @@ -1036,8 +1015,6 @@ sub WriteReadings { my $hash = shift; my $decode_json = shift; - # print Dumper $decode_json; - my $name = $hash->{NAME}; if ( defined( $decode_json->{id} ) diff --git a/FHEM/74_GardenaSmartDevice.pm b/FHEM/74_GardenaSmartDevice.pm index d9fdd13..39fa1bd 100644 --- a/FHEM/74_GardenaSmartDevice.pm +++ b/FHEM/74_GardenaSmartDevice.pm @@ -72,15 +72,11 @@ 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' @@ -89,10 +85,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 ... @@ -100,10 +93,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 ... @@ -111,10 +101,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 ... @@ -122,20 +109,17 @@ 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; - } - } - } - } -} + }; + }; + }; + }; +}; ## Import der FHEM Funktionen #-- Run before package compilation diff --git a/controls_GardenaSmartDevice.txt b/controls_GardenaSmartDevice.txt index 63b02a0..5279fc7 100644 --- a/controls_GardenaSmartDevice.txt +++ b/controls_GardenaSmartDevice.txt @@ -1,2 +1,2 @@ -UPD 2022-02-01_13:05:43 50198 FHEM/73_GardenaSmartBridge.pm -UPD 2022-01-31_19:35:42 56993 FHEM/74_GardenaSmartDevice.pm +UPD 2022-02-01_16:59:23 49503 FHEM/73_GardenaSmartBridge.pm +UPD 2022-02-01_16:37:05 56817 FHEM/74_GardenaSmartDevice.pm -- 2.45.2 From 13e7e24911b3bb4c013b707952a436374900263f Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Tue, 1 Feb 2022 18:42:33 +0100 Subject: [PATCH 10/13] change version number, ready for testing [Ticket: no] --- FHEM/73_GardenaSmartBridge.pm | 4 +++- FHEM/74_GardenaSmartDevice.pm | 2 +- controls_GardenaSmartDevice.txt | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/FHEM/73_GardenaSmartBridge.pm b/FHEM/73_GardenaSmartBridge.pm index 797807d..19297c3 100644 --- a/FHEM/73_GardenaSmartBridge.pm +++ b/FHEM/73_GardenaSmartBridge.pm @@ -866,6 +866,8 @@ qq{GardenaSmartBridge ($name) - execute parse json asynchronously (PID="$pid")} InternalTimer( gettimeofday() + 1, "FHEM::GardenaSmartBridge::PollChild", $hash ); + + return; } Log3 $name, 3, "GardenaSmartBridge ($name) - no Match for processing data"; @@ -924,7 +926,7 @@ sub PollChild { CleanSubprocess($hash); } - Log3( $name, 5, + Log3( $name, 4, qq{GardenaSmartBridge ($name) - still waiting ($subprocess->{lasterror}).} ); diff --git a/FHEM/74_GardenaSmartDevice.pm b/FHEM/74_GardenaSmartDevice.pm index 39fa1bd..93817a9 100644 --- a/FHEM/74_GardenaSmartDevice.pm +++ b/FHEM/74_GardenaSmartDevice.pm @@ -1459,7 +1459,7 @@ sub SetPredefinedStartPoints { ], "release_status": "stable", "license": "GPL_2", - "version": "v2.4.2", + "version": "v2.4.3", "author": [ "Marko Oldenburg " ], diff --git a/controls_GardenaSmartDevice.txt b/controls_GardenaSmartDevice.txt index 5279fc7..9c8d9bc 100644 --- a/controls_GardenaSmartDevice.txt +++ b/controls_GardenaSmartDevice.txt @@ -1,2 +1,2 @@ -UPD 2022-02-01_16:59:23 49503 FHEM/73_GardenaSmartBridge.pm -UPD 2022-02-01_16:37:05 56817 FHEM/74_GardenaSmartDevice.pm +UPD 2022-02-01_18:41:32 49520 FHEM/73_GardenaSmartBridge.pm +UPD 2022-02-01_18:41:58 56817 FHEM/74_GardenaSmartDevice.pm -- 2.45.2 From 65df7eb47b665c852deeded6ca6fa21cb966a153 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Tue, 8 Feb 2022 11:56:46 +0100 Subject: [PATCH 11/13] chage state to hibernate [Ticket: no] --- FHEM/74_GardenaSmartDevice.pm | 30 +++++++++++++++++++++++++----- controls_GardenaSmartDevice.txt | 2 +- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/FHEM/74_GardenaSmartDevice.pm b/FHEM/74_GardenaSmartDevice.pm index 93817a9..09fc772 100644 --- a/FHEM/74_GardenaSmartDevice.pm +++ b/FHEM/74_GardenaSmartDevice.pm @@ -744,6 +744,8 @@ sub WriteReadings { $abilities--; } while ( $abilities >= 0 ); + my $winter_mode; + do { #Log3 $name, 1, "Settings pro Device : ".$decode_json->{settings}[$settings]{name}; #Log3 $name, 1, " - KEIN ARRAY" if ( ref( $decode_json->{settings}[$settings]{value} ) ne "ARRAY"); @@ -770,6 +772,8 @@ sub WriteReadings { readingsBulkUpdateIfChanged( $hash, 'winter_mode', $decode_json->{settings}[$settings]{value} ) if ( $decode_json->{settings}[$settings]{name} eq 'winter_mode' ); + + # $winter_mode = } if ( ref( $decode_json->{settings}[$settings]{value} ) eq "ARRAY" @@ -803,6 +807,25 @@ sub WriteReadings { $settings--; } while ( $settings >= 0 ); + if ( ReadingsVal( $name, 'winter_mode', 'awake' ) ne 'hibernate' ) { + setState(); + } + else { + readingsBulkUpdate( $hash, 'state', + RigReadingsValue( $hash, 'hibernate' ) ); + } + + readingsEndUpdate( $hash, 1 ); + + Log3 $name, 4, "GardenaSmartDevice ($name) - readings was written"; + + return; +} + +sub setState { + my $hash = shift; + my $name = $hash->{NAME}; + my $online_state = ReadingsVal( $name, 'device_info-connection_status', 'unknown' ); @@ -864,10 +887,6 @@ sub WriteReadings { ReadingsVal( $name, 'power-power_timer', 'no info from power-timer' ) ) if ( AttrVal( $name, 'model', 'unknown' ) eq 'power' ); - readingsEndUpdate( $hash, 1 ); - - Log3 $name, 4, "GardenaSmartDevice ($name) - readings was written"; - return; } @@ -977,7 +996,8 @@ sub ReadingLangGerman { 'closed' => 'geschlossen', 'included' => 'inbegriffen', 'active' => 'aktiv', - 'inactive' => 'nicht aktiv' + 'inactive' => 'nicht aktiv', + 'hibernate' => 'Winterschlaf', ); if ( diff --git a/controls_GardenaSmartDevice.txt b/controls_GardenaSmartDevice.txt index 9c8d9bc..3fbc6ef 100644 --- a/controls_GardenaSmartDevice.txt +++ b/controls_GardenaSmartDevice.txt @@ -1,2 +1,2 @@ UPD 2022-02-01_18:41:32 49520 FHEM/73_GardenaSmartBridge.pm -UPD 2022-02-01_18:41:58 56817 FHEM/74_GardenaSmartDevice.pm +UPD 2022-02-08_11:55:50 57225 FHEM/74_GardenaSmartDevice.pm -- 2.45.2 From 85c7b3fa0a8226edaea2816e47cfab845192f33d Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Wed, 9 Feb 2022 10:29:40 +0100 Subject: [PATCH 12/13] change condition to grep wintermode [Ticket: no] --- FHEM/74_GardenaSmartDevice.pm | 12 +++++++----- controls_GardenaSmartDevice.txt | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/FHEM/74_GardenaSmartDevice.pm b/FHEM/74_GardenaSmartDevice.pm index 09fc772..5abf0bb 100644 --- a/FHEM/74_GardenaSmartDevice.pm +++ b/FHEM/74_GardenaSmartDevice.pm @@ -769,11 +769,13 @@ sub WriteReadings { } # save winter mode as reading - readingsBulkUpdateIfChanged( $hash, 'winter_mode', - $decode_json->{settings}[$settings]{value} ) - if ( $decode_json->{settings}[$settings]{name} eq 'winter_mode' ); - # $winter_mode = + if ( $decode_json->{settings}[$settings]{name} eq 'winter_mode' ) { + readingsBulkUpdateIfChanged( $hash, 'winter_mode', + $decode_json->{settings}[$settings]{value} ); + + $winter_mode = $decode_json->{settings}[$settings]{value}; + } } if ( ref( $decode_json->{settings}[$settings]{value} ) eq "ARRAY" @@ -807,7 +809,7 @@ sub WriteReadings { $settings--; } while ( $settings >= 0 ); - if ( ReadingsVal( $name, 'winter_mode', 'awake' ) ne 'hibernate' ) { + if ( $winter_mode ne 'hibernate' ) { setState(); } else { diff --git a/controls_GardenaSmartDevice.txt b/controls_GardenaSmartDevice.txt index 3fbc6ef..2cb0604 100644 --- a/controls_GardenaSmartDevice.txt +++ b/controls_GardenaSmartDevice.txt @@ -1,2 +1,2 @@ UPD 2022-02-01_18:41:32 49520 FHEM/73_GardenaSmartBridge.pm -UPD 2022-02-08_11:55:50 57225 FHEM/74_GardenaSmartDevice.pm +UPD 2022-02-09_10:29:06 57262 FHEM/74_GardenaSmartDevice.pm -- 2.45.2 From b211fe2b56802a0482093f44dab3054e240c37a2 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Wed, 9 Feb 2022 13:51:13 +0100 Subject: [PATCH 13/13] Subject line (try to keep under 50 characters) Multi-line description of commit, feel free to be detailed. [Ticket: X] --- FHEM/74_GardenaSmartDevice.pm | 2 +- controls_GardenaSmartDevice.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/FHEM/74_GardenaSmartDevice.pm b/FHEM/74_GardenaSmartDevice.pm index 5abf0bb..9fe5332 100644 --- a/FHEM/74_GardenaSmartDevice.pm +++ b/FHEM/74_GardenaSmartDevice.pm @@ -810,7 +810,7 @@ sub WriteReadings { } while ( $settings >= 0 ); if ( $winter_mode ne 'hibernate' ) { - setState(); + setState($hash); } else { readingsBulkUpdate( $hash, 'state', diff --git a/controls_GardenaSmartDevice.txt b/controls_GardenaSmartDevice.txt index 2cb0604..0dd4e74 100644 --- a/controls_GardenaSmartDevice.txt +++ b/controls_GardenaSmartDevice.txt @@ -1,2 +1,2 @@ UPD 2022-02-01_18:41:32 49520 FHEM/73_GardenaSmartBridge.pm -UPD 2022-02-09_10:29:06 57262 FHEM/74_GardenaSmartDevice.pm +UPD 2022-02-09_13:50:50 57267 FHEM/74_GardenaSmartDevice.pm -- 2.45.2