From 4e0c1e7b30b808ed3f0bc583acdd4c199f0ee52d Mon Sep 17 00:00:00 2001 From: LeonGaultier Date: Mon, 15 Oct 2018 12:57:08 +0000 Subject: [PATCH] 73_GardenaSmartBridge/Device: fix typo oK to ok, change to package git-svn-id: https://svn.fhem.de/fhem/trunk@17536 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 2 + fhem/FHEM/73_GardenaSmartBridge.pm | 1261 ++++++++++++++++------------ fhem/FHEM/74_GardenaSmartDevice.pm | 1053 +++++++++++++---------- 3 files changed, 1357 insertions(+), 959 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index 7fd967cab..760d8d20f 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,7 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - bugfix: 73_GardenaSmartBridge/Device fix typo oK to ok, change to + package System - change: 93_DbRep: V8.2.3, check availability of DbLog-device at definition time of DbRep-device - change: 93_Log2Syslog: send BSD-format changed, commandref revised diff --git a/fhem/FHEM/73_GardenaSmartBridge.pm b/fhem/FHEM/73_GardenaSmartBridge.pm index a6d7f0399..1b9aaa53c 100644 --- a/fhem/FHEM/73_GardenaSmartBridge.pm +++ b/fhem/FHEM/73_GardenaSmartBridge.pm @@ -1,5 +1,5 @@ ############################################################################### -# +# # Developed with Kate # # (c) 2017-2018 Copyright: Marko Oldenburg (leongaultier at gmail dot com) @@ -38,7 +38,7 @@ # # if($@){ # Log3($SELF, 2, "$TYPE ($SELF) - error while request: $@"); -# +# # readingsSingleUpdate($hash, "state", "error", 1); # # return; @@ -49,115 +49,144 @@ # # apt-get install libio-socket-ssl-perl # http://www.dxsdata.com/de/2016/07/php-class-for-gardena-smart-system-api/ -# +# ## ## - - package main; - -my $missingModul = ""; - use strict; use warnings; -use HttpUtils; - -eval "use Encode qw(encode encode_utf8 decode_utf8);1" or $missingModul .= "Encode "; -eval "use JSON;1" or $missingModul .= "JSON "; -eval "use IO::Socket::SSL;1" or $missingModul .= "IO::Socket::SSL "; - - -my $version = "1.2.2"; - - - - -# Declare functions -sub GardenaSmartBridge_Attr(@); -sub GardenaSmartBridge_Define($$); -sub GardenaSmartBridge_Initialize($); -sub GardenaSmartBridge_Set($@); -sub GardenaSmartBridge_Write($@); -sub GardenaSmartBridge_Undef($$); -sub GardenaSmartBridge_Delete($$); -sub GardenaSmartBridge_ResponseProcessing($$); -sub GardenaSmartBridge_ErrorHandling($$$); -sub GardenaSmartBridge_WriteReadings($$); -sub GardenaSmartBridge_ParseJSON($$); -sub GardenaSmartBridge_getDevices($); -sub GardenaSmartBridge_getToken($); -sub GardenaSmartBridge_createHttpValueStrings($@); -sub GardenaSmartBridge_Notify($$); -sub GardenaSmartBridge_StorePassword($$); -sub GardenaSmartBridge_ReadPassword($); -sub GardenaSmartBridge_DeletePassword($); -sub GardenaSmartBridge_Rename(@); - - +my $version = "1.4.0"; +# # Declare functions +# sub Attr(@); +# sub Define($$); +# sub Initialize($); +# sub Set($@); +# sub Write($@); +# sub Undef($$); +# sub Delete($$); +# sub ResponseProcessing($$); +# sub ErrorHandling($$$); +# sub WriteReadings($$); +# sub ParseJSON($$); +# sub getDevices($); +# sub getToken($); +# sub createHttpValueStrings($@); +# sub Notify($$); +# sub StorePassword($$); +# sub ReadPassword($); +# sub DeletePassword($); +# sub Rename(@); sub GardenaSmartBridge_Initialize($) { my ($hash) = @_; - # Provider - $hash->{WriteFn} = "GardenaSmartBridge_Write"; - $hash->{Clients} = ":GardenaSmartDevice:"; - $hash->{MatchList} = { "1:GardenaSmartDevice" => '^{"id":".*' }; - - + $hash->{WriteFn} = "GardenaSmartBridge::Write"; + $hash->{Clients} = ":GardenaSmartDevice:"; + $hash->{MatchList} = { "1:GardenaSmartDevice" => '^{"id":".*' }; + # Consumer - $hash->{SetFn} = "GardenaSmartBridge_Set"; - $hash->{DefFn} = "GardenaSmartBridge_Define"; - $hash->{UndefFn} = "GardenaSmartBridge_Undef"; - $hash->{DeleteFn} = "GardenaSmartBridge_Delete"; - $hash->{RenameFn} = "GardenaSmartBridge_Rename"; - $hash->{NotifyFn} = "GardenaSmartBridge_Notify"; - - $hash->{AttrFn} = "GardenaSmartBridge_Attr"; - $hash->{AttrList} = "debugJSON:0,1 ". - "disable:1 ". - "interval ". - "disabledForIntervals ". - "gardenaAccountEmail ". - $readingFnAttributes; - - foreach my $d(sort keys %{$modules{GardenaSmartBridge}{defptr}}) { - + $hash->{SetFn} = "GardenaSmartBridge::Set"; + $hash->{DefFn} = "GardenaSmartBridge::Define"; + $hash->{UndefFn} = "GardenaSmartBridge::Undef"; + $hash->{DeleteFn} = "GardenaSmartBridge::Delete"; + $hash->{RenameFn} = "GardenaSmartBridge::Rename"; + $hash->{NotifyFn} = "GardenaSmartBridge::Notify"; + + $hash->{AttrFn} = "GardenaSmartBridge::Attr"; + $hash->{AttrList} = + "debugJSON:0,1 " + . "disable:1 " + . "interval " + . "disabledForIntervals " + . "gardenaAccountEmail " + . $readingFnAttributes; + + foreach my $d ( sort keys %{ $modules{GardenaSmartBridge}{defptr} } ) { + my $hash = $modules{GardenaSmartBridge}{defptr}{$d}; - $hash->{VERSION} = $version; + $hash->{VERSION} = $version; } } -sub GardenaSmartBridge_Define($$) { +package GardenaSmartBridge; +use GPUtils qw(:all) + ; # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt + +my $missingModul = ""; + +use strict; +use warnings; +use POSIX; + +use HttpUtils; + +eval "use Encode qw(encode encode_utf8 decode_utf8);1" + or $missingModul .= "Encode "; +eval "use JSON;1" or $missingModul .= "JSON "; +eval "use IO::Socket::SSL;1" or $missingModul .= "IO::Socket::SSL "; + +BEGIN { + GP_Import( + qw(readingsSingleUpdate + readingsBulkUpdate + readingsBulkUpdateIfChanged + readingsBeginUpdate + readingsEndUpdate + Log3 + CommandAttr + AttrVal + ReadingsVal + CommandDefMod + modules + setKeyValue + getKeyValue + getUniqueId + RemoveInternalTimer + InternalTimer + defs + init_done + IsDisabled + deviceEvents + HttpUtils_NonblockingGet + gettimeofday + Dispatch) + ); +} + +sub Define($$) { my ( $hash, $def ) = @_; - + my @a = split( "[ \t][ \t]*", $def ); - - return "too few parameters: define GardenaSmartBridge" if( @a < 2 or @a > 4 ); - return "Cannot define Gardena Bridge device. Perl modul ${missingModul}is missing." if ( $missingModul ); - - my $name = $a[0]; - $hash->{BRIDGE} = 1; - $hash->{URL} = 'https://sg-api.dss.husqvarnagroup.net/sg-1'; - $hash->{VERSION} = $version; - $hash->{INTERVAL} = 300; - $hash->{NOTIFYDEV} = "global,$name"; + return "too few parameters: define GardenaSmartBridge" + if ( @a < 2 or @a > 4 ); + return +"Cannot define Gardena Bridge device. Perl modul ${missingModul}is missing." + if ($missingModul); + my $name = $a[0]; + $hash->{BRIDGE} = 1; + $hash->{URL} = 'https://sg-api.dss.husqvarnagroup.net/sg-1'; + $hash->{VERSION} = $version; + $hash->{INTERVAL} = 300; + $hash->{NOTIFYDEV} = "global,$name"; - CommandAttr(undef,$name.' room GardenaSmart') if( AttrVal($name,'room','none') eq 'none' ); - - CommandDefMod(undef,$name.' '.$hash->{TYPE}) if(@a > 2); # fix new define + CommandAttr( undef, $name . ' room GardenaSmart' ) + if ( AttrVal( $name, 'room', 'none' ) eq 'none' ); + + CommandDefMod( undef, $name . ' ' . $hash->{TYPE} ) + if ( @a > 2 ); # fix new define + + readingsSingleUpdate( $hash, 'token', 'none', 1 ); + readingsSingleUpdate( $hash, 'state', 'initialized', 1 ); - readingsSingleUpdate($hash,'token','none',1); - readingsSingleUpdate($hash,'state','initialized',1); - Log3 $name, 3, "GardenaSmartBridge ($name) - defined GardenaSmartBridge"; $modules{GardenaSmartBridge}{defptr}{BRIDGE} = $hash; @@ -165,683 +194,845 @@ sub GardenaSmartBridge_Define($$) { return undef; } -sub GardenaSmartBridge_Undef($$) { +sub Undef($$) { my ( $hash, $name ) = @_; - - + RemoveInternalTimer($hash); - delete $modules{GardenaSmartBridge}{defptr}{BRIDGE} if( defined($modules{GardenaSmartBridge}{defptr}{BRIDGE}) ); + delete $modules{GardenaSmartBridge}{defptr}{BRIDGE} + if ( defined( $modules{GardenaSmartBridge}{defptr}{BRIDGE} ) ); return undef; } -sub GardenaSmartBridge_Delete($$) { +sub Delete($$) { my ( $hash, $name ) = @_; - - setKeyValue($hash->{TYPE}."_".$name."_passwd",undef); + setKeyValue( $hash->{TYPE} . "_" . $name . "_passwd", undef ); return undef; } -sub GardenaSmartBridge_Attr(@) { +sub Attr(@) { my ( $cmd, $name, $attrName, $attrVal ) = @_; my $hash = $defs{$name}; - - if( $attrName eq "disable" ) { - if( $cmd eq "set" and $attrVal eq "1" ) { + if ( $attrName eq "disable" ) { + if ( $cmd eq "set" and $attrVal eq "1" ) { RemoveInternalTimer($hash); - readingsSingleUpdate ( $hash, "state", "inactive", 1 ); + readingsSingleUpdate( $hash, "state", "inactive", 1 ); Log3 $name, 3, "GardenaSmartBridge ($name) - disabled"; } - elsif( $cmd eq "del" ) { - readingsSingleUpdate ( $hash, "state", "active", 1 ); + elsif ( $cmd eq "del" ) { + readingsSingleUpdate( $hash, "state", "active", 1 ); Log3 $name, 3, "GardenaSmartBridge ($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 ...'" - unless($attrVal =~ /^((\d{2}:\d{2})-(\d{2}:\d{2})\s?)+$/); + + 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 ...'" + unless ( $attrVal =~ /^((\d{2}:\d{2})-(\d{2}:\d{2})\s?)+$/ ); Log3 $name, 3, "GardenaSmartBridge ($name) - disabledForIntervals"; } - elsif( $cmd eq "del" ) { - readingsSingleUpdate ( $hash, "state", "active", 1 ); + elsif ( $cmd eq "del" ) { + readingsSingleUpdate( $hash, "state", "active", 1 ); Log3 $name, 3, "GardenaSmartBridge ($name) - enabled"; } } - - elsif( $attrName eq "interval" ) { - if( $cmd eq "set" ) { + + elsif ( $attrName eq "interval" ) { + if ( $cmd eq "set" ) { RemoveInternalTimer($hash); return "Interval must be greater than 0" - unless($attrVal > 0); - $hash->{INTERVAL} = $attrVal; - Log3 $name, 3, "GardenaSmartBridge ($name) - set interval: $attrVal"; + unless ( $attrVal > 0 ); + $hash->{INTERVAL} = $attrVal; + Log3 $name, 3, + "GardenaSmartBridge ($name) - set interval: $attrVal"; } - elsif( $cmd eq "del" ) { + elsif ( $cmd eq "del" ) { RemoveInternalTimer($hash); - $hash->{INTERVAL} = 300; - Log3 $name, 3, "GardenaSmartBridge ($name) - delete User interval and set default: 300"; + $hash->{INTERVAL} = 300; + Log3 $name, 3, +"GardenaSmartBridge ($name) - delete User interval and set default: 300"; } } return undef; } -sub GardenaSmartBridge_Notify($$) { +sub Notify($$) { - my ($hash,$dev) = @_; + my ( $hash, $dev ) = @_; my $name = $hash->{NAME}; - return if (IsDisabled($name)); - + return if ( IsDisabled($name) ); + my $devname = $dev->{NAME}; my $devtype = $dev->{TYPE}; - my $events = deviceEvents($dev,1); - return if (!$events); + my $events = deviceEvents( $dev, 1 ); + return if ( !$events ); - #Log3 $name, 1, "GardenaSmartBridge ($name) - Im Notify: DEVTYPE: $devtype, DEVNAME: $devname EVENT: @{$events}"; - - - GardenaSmartBridge_getToken($hash) if ( - ($devtype eq 'Global' - and (grep /^INITIALIZED$/,@{$events} - or grep /^REREADCFG$/,@{$events} - or grep /^DEFINED.$name$/,@{$events} - or grep /^MODIFIED.$name$/,@{$events} - or grep /^ATTR.$name.gardenaAccountEmail.+/,@{$events} - ) - ) - - or - ($devtype eq 'GardenaSmartBridge' - and (grep /^gardenaAccountPassword.+/,@{$events} - or ReadingsVal('$devname','token','') eq 'none') ) - ); +#Log3 $name, 1, "GardenaSmartBridge ($name) - Im Notify: DEVTYPE: $devtype, DEVNAME: $devname EVENT: @{$events}"; - GardenaSmartBridge_getDevices($hash) if ( $devtype eq 'Global' - and (grep /^DELETEATTR.$name.disable$/,@{$events} - or grep /^ATTR.$name.disable.0$/,@{$events} - or grep /^DELETEATTR.$name.interval$/,@{$events} - or grep /^ATTR.$name.interval.[0-9]+/,@{$events} - ) - and $init_done ); + getToken($hash) + if ( + ( + $devtype eq 'Global' + and ( + grep /^INITIALIZED$/, + @{$events} or grep /^REREADCFG$/, + @{$events} or grep /^DEFINED.$name$/, + @{$events} or grep /^MODIFIED.$name$/, + @{$events} or grep /^ATTR.$name.gardenaAccountEmail.+/, + @{$events} + ) + ) - if( $devtype eq 'GardenaSmartBridge' and (grep /^state:.connected.to.cloud$/,@{$events} - or grep /^lastRequestState:.request_error$/,@{$events}) ) { - - InternalTimer( gettimeofday()+$hash->{INTERVAL},"GardenaSmartBridge_getDevices", $hash); - Log3 $name, 4, "GardenaSmartBridge ($name) - set internal timer function for recall GardenaSmartBridge_getDevices sub"; + or ( + $devtype eq 'GardenaSmartBridge' + and ( + grep /^gardenaAccountPassword.+/, + @{$events} or ReadingsVal( '$devname', 'token', '' ) eq 'none' + ) + ) + ); + + getDevices($hash) + if ( + $devtype eq 'Global' + and ( + grep /^DELETEATTR.$name.disable$/, + @{$events} or grep /^ATTR.$name.disable.0$/, + @{$events} or grep /^DELETEATTR.$name.interval$/, + @{$events} or grep /^ATTR.$name.interval.[0-9]+/, + @{$events} + ) + and $init_done + ); + + if ( + $devtype eq 'GardenaSmartBridge' + and ( + grep /^state:.connected.to.cloud$/, + @{$events} or grep /^lastRequestState:.request_error$/, + @{$events} + ) + ) + { + + InternalTimer( gettimeofday() + $hash->{INTERVAL}, + "GardenaSmartBridge::getDevices", $hash ); + Log3 $name, 4, +"GardenaSmartBridge ($name) - set internal timer function for recall getDevices sub"; } return; } -sub GardenaSmartBridge_Set($@) { - - my ($hash, $name, $cmd, @args) = @_; - #my ($arg, @params) = @args; - - - if( lc $cmd eq 'getdevicesstate' ) { - GardenaSmartBridge_getDevices($hash); - - } elsif( lc $cmd eq 'gettoken' ) { - return "please set Attribut gardenaAccountEmail first" if(AttrVal($name,'gardenaAccountEmail','none') eq 'none'); - return "please set gardenaAccountPassword first" if( not defined(GardenaSmartBridge_ReadPassword($hash)) ); - return "token is up to date" if( defined($hash->{helper}{session_id}) ); - - GardenaSmartBridge_getToken($hash); - - } elsif( lc $cmd eq 'gardenaaccountpassword' ) { - return "please set Attribut gardenaAccountEmail first" if(AttrVal($name,'gardenaAccountEmail','none') eq 'none'); - return "usage: $cmd " if( @args != 1 ); - - my $passwd = join(' ',@args); - GardenaSmartBridge_StorePassword($hash,$passwd); - - } elsif( lc $cmd eq 'deleteaccountpassword' ) { - return "usage: $cmd " if( @args != 0 ); +sub Set($@) { - GardenaSmartBridge_DeletePassword($hash); - - } else { - - my $list = "getDevicesState:noArg getToken:noArg" if( defined(GardenaSmartBridge_ReadPassword($hash)) ); - $list .= " gardenaAccountPassword" if( not defined(GardenaSmartBridge_ReadPassword($hash)) ); - $list .= " deleteAccountPassword:noArg" if( defined(GardenaSmartBridge_ReadPassword($hash)) ); + my ( $hash, $name, $cmd, @args ) = @_; + + #my ($arg, @params) = @args; + + if ( lc $cmd eq 'getdevicesstate' ) { + getDevices($hash); + + } + elsif ( lc $cmd eq 'gettoken' ) { + return "please set Attribut gardenaAccountEmail first" + if ( AttrVal( $name, 'gardenaAccountEmail', 'none' ) eq 'none' ); + return "please set gardenaAccountPassword first" + if ( not defined( ReadPassword($hash) ) ); + return "token is up to date" + if ( defined( $hash->{helper}{session_id} ) ); + + getToken($hash); + + } + elsif ( lc $cmd eq 'gardenaaccountpassword' ) { + return "please set Attribut gardenaAccountEmail first" + if ( AttrVal( $name, 'gardenaAccountEmail', 'none' ) eq 'none' ); + return "usage: $cmd " if ( @args != 1 ); + + my $passwd = join( ' ', @args ); + StorePassword( $hash, $passwd ); + + } + elsif ( lc $cmd eq 'deleteaccountpassword' ) { + return "usage: $cmd " if ( @args != 0 ); + + DeletePassword($hash); + + } + else { + + my $list = "getDevicesState:noArg getToken:noArg" + if ( defined( ReadPassword($hash) ) ); + $list .= " gardenaAccountPassword" + if ( not defined( ReadPassword($hash) ) ); + $list .= " deleteAccountPassword:noArg" + if ( defined( ReadPassword($hash) ) ); return "Unknown argument $cmd, choose one of $list"; } - + return undef; } -sub GardenaSmartBridge_Write($@) { +sub Write($@) { - my ($hash,$payload,$deviceId,$abilities) = @_; - my $name = $hash->{NAME}; - - my ($session_id,$header,$uri,$method); - + my ( $hash, $payload, $deviceId, $abilities ) = @_; + my $name = $hash->{NAME}; + + my ( $session_id, $header, $uri, $method ); + + ( $payload, $session_id, $header, $uri, $method, $deviceId, $abilities ) = + createHttpValueStrings( $hash, $payload, $deviceId, $abilities ); - - - ($payload,$session_id,$header,$uri,$method,$deviceId,$abilities) = GardenaSmartBridge_createHttpValueStrings($hash,$payload,$deviceId,$abilities); - HttpUtils_NonblockingGet( { - url => $hash->{URL} . $uri, - timeout => 15, - hash => $hash, - device_id => $deviceId, - data => $payload, - method => $method, - header => $header, - doTrigger => 1, - callback => \&GardenaSmartBridge_ErrorHandling + url => $hash->{URL} . $uri, + timeout => 15, + hash => $hash, + device_id => $deviceId, + data => $payload, + method => $method, + header => $header, + doTrigger => 1, + callback => \&ErrorHandling } ); - #Log3 $name, 4, "GardenaSmartBridge ($name) - Send with URL: $hash->{URL}$uri, HEADER: $header, DATA: $payload, METHOD: $method"; - Log3 $name, 4, "GardenaSmartBridge ($name) - Send with URL: $hash->{URL}$uri, HEADER: secret!, DATA: secret!, METHOD: $method"; +#Log3 $name, 4, "GardenaSmartBridge ($name) - Send with URL: $hash->{URL}$uri, HEADER: $header, DATA: $payload, METHOD: $method"; + Log3 $name, 4, +"GardenaSmartBridge ($name) - Send with URL: $hash->{URL}$uri, HEADER: secret!, DATA: secret!, METHOD: $method"; } -sub GardenaSmartBridge_ErrorHandling($$$) { +sub ErrorHandling($$$) { - my ($param,$err,$data) = @_; - - my $hash = $param->{hash}; - my $name = $hash->{NAME}; - my $dhash = $hash; - - $dhash = $modules{GardenaSmartDevice}{defptr}{$param->{'device_id'}} - unless( not defined( $param->{'device_id'}) ); - - my $dname = $dhash->{NAME}; + my ( $param, $err, $data ) = @_; + my $hash = $param->{hash}; + my $name = $hash->{NAME}; + my $dhash = $hash; - - - if( defined( $err ) ) { - if( $err ne "" ) { - - readingsBeginUpdate( $dhash ); - readingsBulkUpdate( $dhash, "state", "$err") if( ReadingsVal( $dname, "state", 1 ) ne "initialized" ); + $dhash = $modules{GardenaSmartDevice}{defptr}{ $param->{'device_id'} } + unless ( not defined( $param->{'device_id'} ) ); - readingsBulkUpdate( $dhash, "lastRequestState", "request_error", 1 ); - - if( $err =~ /timed out/ ) { - - Log3 $dname, 5, "GardenaSmartBridge ($dname) - RequestERROR: connect to gardena cloud is timed out. check network"; + my $dname = $dhash->{NAME}; + + if ( defined($err) ) { + if ( $err ne "" ) { + + readingsBeginUpdate($dhash); + readingsBulkUpdate( $dhash, "state", "$err" ) + if ( ReadingsVal( $dname, "state", 1 ) ne "initialized" ); + + readingsBulkUpdate( $dhash, "lastRequestState", "request_error", + 1 ); + + if ( $err =~ /timed out/ ) { + + Log3 $dname, 5, +"GardenaSmartBridge ($dname) - RequestERROR: connect to gardena cloud is timed out. check network"; } - - elsif( $err =~ /Keine Route zum Zielrechner/ or $err =~ /no route to target/ ) { - - Log3 $dname, 5, "GardenaSmartBridge ($dname) - RequestERROR: no route to target. bad network configuration or network is down"; - - } else { - Log3 $dname, 5, "GardenaSmartBridge ($dname) - RequestERROR: $err"; + elsif ($err =~ /Keine Route zum Zielrechner/ + or $err =~ /no route to target/ ) + { + + Log3 $dname, 5, +"GardenaSmartBridge ($dname) - RequestERROR: no route to target. bad network configuration or network is down"; + + } + else { + + Log3 $dname, 5, + "GardenaSmartBridge ($dname) - RequestERROR: $err"; } readingsEndUpdate( $dhash, 1 ); - Log3 $dname, 5, "GardenaSmartBridge ($dname) - RequestERROR: GardenaSmartBridge RequestErrorHandling: error while requesting gardena cloud: $err"; + Log3 $dname, 5, +"GardenaSmartBridge ($dname) - RequestERROR: GardenaSmartBridge RequestErrorHandling: error while requesting gardena cloud: $err"; + + delete $dhash->{helper}{deviceAction} + if ( defined( $dhash->{helper}{deviceAction} ) ); - delete $dhash->{helper}{deviceAction} if( defined($dhash->{helper}{deviceAction}) ); - return; } } - if( $data eq "" and exists( $param->{code} ) and $param->{code} != 200 ) { - - readingsBeginUpdate( $dhash ); - readingsBulkUpdate( $dhash, "state", $param->{code}, 1 ) if( ReadingsVal( $dname, "state", 1 ) ne "initialized" ); + if ( $data eq "" and exists( $param->{code} ) and $param->{code} != 200 ) { - readingsBulkUpdateIfChanged( $dhash, "lastRequestState", "request_error", 1 ); - - if( $param->{code} == 401 and $hash eq $dhash ) { - - if( ReadingsVal($dname,'token','none') eq 'none' ) { - readingsBulkUpdate( $dhash, "state", "no token available", 1); - readingsBulkUpdateIfChanged( $dhash, "lastRequestState", "no token available", 1 ); + readingsBeginUpdate($dhash); + readingsBulkUpdate( $dhash, "state", $param->{code}, 1 ) + if ( ReadingsVal( $dname, "state", 1 ) ne "initialized" ); + + readingsBulkUpdateIfChanged( $dhash, "lastRequestState", + "request_error", 1 ); + + if ( $param->{code} == 401 and $hash eq $dhash ) { + + if ( ReadingsVal( $dname, 'token', 'none' ) eq 'none' ) { + readingsBulkUpdate( $dhash, "state", "no token available", 1 ); + readingsBulkUpdateIfChanged( $dhash, "lastRequestState", + "no token available", 1 ); } - - Log3 $dname, 5, "GardenaSmartBridge ($dname) - RequestERROR: ".$param->{code}; - - } elsif( $param->{code} == 204 and $dhash ne $hash and defined($dhash->{helper}{deviceAction}) ) { - - readingsBulkUpdate( $dhash, "state", "the command is processed", 1); - InternalTimer( gettimeofday()+5,"GardenaSmartBridge_getDevices", $hash, 1 ); - - } elsif( $param->{code} != 200 ) { - Log3 $dname, 5, "GardenaSmartBridge ($dname) - RequestERROR: ".$param->{code}; + Log3 $dname, 5, + "GardenaSmartBridge ($dname) - RequestERROR: " . $param->{code}; + + } + elsif ( $param->{code} == 204 + and $dhash ne $hash + and defined( $dhash->{helper}{deviceAction} ) ) + { + + readingsBulkUpdate( $dhash, "state", "the command is processed", + 1 ); + InternalTimer( gettimeofday() + 5, "GardenaSmartBridge::getDevices", $hash, 1 ); + + } + elsif ( $param->{code} != 200 ) { + + Log3 $dname, 5, + "GardenaSmartBridge ($dname) - RequestERROR: " . $param->{code}; } readingsEndUpdate( $dhash, 1 ); - - Log3 $dname, 5, "GardenaSmartBridge ($dname) - RequestERROR: received http code ".$param->{code}." without any data after requesting gardena cloud"; - - delete $dhash->{helper}{deviceAction} if( defined($dhash->{helper}{deviceAction}) ); + + Log3 $dname, 5, + "GardenaSmartBridge ($dname) - RequestERROR: received http code " + . $param->{code} + . " without any data after requesting gardena cloud"; + + delete $dhash->{helper}{deviceAction} + if ( defined( $dhash->{helper}{deviceAction} ) ); return; } - if( ( ($data =~ /Error/ ) or defined(eval{decode_json($data)}->{errors}) ) and exists( $param->{code} ) ) { - readingsBeginUpdate( $dhash ); - readingsBulkUpdate( $dhash, "state", $param->{code}, 1 ) if( ReadingsVal( $dname, "state" ,0) ne "initialized" ); + if ( + ( + ( $data =~ /Error/ ) + or defined( eval { decode_json($data) }->{errors} ) + ) + and exists( $param->{code} ) + ) + { + readingsBeginUpdate($dhash); + readingsBulkUpdate( $dhash, "state", $param->{code}, 1 ) + if ( ReadingsVal( $dname, "state", 0 ) ne "initialized" ); readingsBulkUpdate( $dhash, "lastRequestState", "request_error", 1 ); - if( $param->{code} == 400 ) { - if( eval{decode_json($data)} ) { - if( ref(eval{decode_json($data)}->{errors}) eq "ARRAY" and defined(eval{decode_json($data)}->{errors}) ) { - readingsBulkUpdate( $dhash, "state", eval{decode_json($data)}->{errors}[0]{error} . ' ' . eval{decode_json($data)}->{errors}[0]{attribute}, 1); - readingsBulkUpdate( $dhash, "lastRequestState", eval{decode_json($data)}->{errors}[0]{error} . ' ' . eval{decode_json($data)}->{errors}[0]{attribute}, 1 ); - Log3 $dname, 5, "GardenaSmartBridge ($dname) - RequestERROR: " . eval{decode_json($data)}->{errors}[0]{error} . " " . eval{decode_json($data)}->{errors}[0]{attribute}; + if ( $param->{code} == 400 ) { + if ( eval { decode_json($data) } ) { + if ( ref( eval { decode_json($data) }->{errors} ) eq "ARRAY" + and defined( eval { decode_json($data) }->{errors} ) ) + { + readingsBulkUpdate( + $dhash, + "state", + eval { decode_json($data) }->{errors}[0]{error} . ' ' + . eval { decode_json($data) }->{errors}[0]{attribute}, + 1 + ); + readingsBulkUpdate( + $dhash, + "lastRequestState", + eval { decode_json($data) }->{errors}[0]{error} . ' ' + . eval { decode_json($data) }->{errors}[0]{attribute}, + 1 + ); + Log3 $dname, 5, + "GardenaSmartBridge ($dname) - RequestERROR: " + . eval { decode_json($data) }->{errors}[0]{error} . " " + . eval { decode_json($data) }->{errors}[0]{attribute}; } - } else { - readingsBulkUpdate( $dhash, "lastRequestState", "Error 400 Bad Request", 1 ); - Log3 $dname, 5, "GardenaSmartBridge ($dname) - RequestERROR: Error 400 Bad Request"; } - } elsif( $param->{code} == 503 ) { + else { + readingsBulkUpdate( $dhash, "lastRequestState", + "Error 400 Bad Request", 1 ); + Log3 $dname, 5, +"GardenaSmartBridge ($dname) - RequestERROR: Error 400 Bad Request"; + } + } + elsif ( $param->{code} == 503 ) { - Log3 $dname, 5, "GardenaSmartBridge ($dname) - RequestERROR: Error 503 Service Unavailable"; + Log3 $dname, 5, +"GardenaSmartBridge ($dname) - RequestERROR: Error 503 Service Unavailable"; readingsBulkUpdate( $dhash, "state", "Service Unavailable", 1 ); - readingsBulkUpdate( $dhash, "lastRequestState", "Error 503 Service Unavailable", 1 ); - - } elsif( $param->{code} == 404 ) { - if( defined($dhash->{helper}{deviceAction}) and $dhash ne $hash ) { - readingsBulkUpdate( $dhash, "state", "device Id not found", 1 ); - readingsBulkUpdate( $dhash, "lastRequestState", "device id not found", 1 ); - } - - Log3 $dname, 5, "GardenaSmartBridge ($dname) - RequestERROR: Error 404 Not Found"; - - } elsif( $param->{code} == 500 ) { - - Log3 $dname, 5, "GardenaSmartBridge ($dname) - RequestERROR: check the ???"; - - } else { + readingsBulkUpdate( $dhash, "lastRequestState", + "Error 503 Service Unavailable", 1 ); - Log3 $dname, 5, "GardenaSmartBridge ($dname) - RequestERROR: http error ".$param->{code}; + } + elsif ( $param->{code} == 404 ) { + if ( defined( $dhash->{helper}{deviceAction} ) and $dhash ne $hash ) + { + readingsBulkUpdate( $dhash, "state", "device Id not found", 1 ); + readingsBulkUpdate( $dhash, "lastRequestState", + "device id not found", 1 ); + } + + Log3 $dname, 5, + "GardenaSmartBridge ($dname) - RequestERROR: Error 404 Not Found"; + + } + elsif ( $param->{code} == 500 ) { + + Log3 $dname, 5, + "GardenaSmartBridge ($dname) - RequestERROR: check the ???"; + + } + else { + + Log3 $dname, 5, + "GardenaSmartBridge ($dname) - RequestERROR: http error " + . $param->{code}; } readingsEndUpdate( $dhash, 1 ); - - Log3 $dname, 5, "GardenaSmartBridge ($dname) - RequestERROR: received http code ".$param->{code}." receive Error after requesting gardena cloud"; - - delete $dhash->{helper}{deviceAction} if( defined($dhash->{helper}{deviceAction}) ); + + Log3 $dname, 5, + "GardenaSmartBridge ($dname) - RequestERROR: received http code " + . $param->{code} + . " receive Error after requesting gardena cloud"; + + delete $dhash->{helper}{deviceAction} + if ( defined( $dhash->{helper}{deviceAction} ) ); return; } - - - - readingsSingleUpdate($hash,'state','connected to cloud',1) if( defined($hash->{helper}{locations_id}) ); - GardenaSmartBridge_ResponseProcessing($hash,$data); + readingsSingleUpdate( $hash, 'state', 'connected to cloud', 1 ) + if ( defined( $hash->{helper}{locations_id} ) ); + ResponseProcessing( $hash, $data ); } -sub GardenaSmartBridge_ResponseProcessing($$) { +sub ResponseProcessing($$) { - my ($hash,$json) = @_; - - my $name = $hash->{NAME}; + my ( $hash, $json ) = @_; + my $name = $hash->{NAME}; - my $decode_json = eval{decode_json($json)}; - if($@){ - Log3 $name, 3, "GardenaSmartBridge ($name) - JSON error while request: $@"; - - if( AttrVal( $name, 'debugJSON', 0 ) == 1 ) { + my $decode_json = eval { decode_json($json) }; + if ($@) { + Log3 $name, 3, + "GardenaSmartBridge ($name) - JSON error while request: $@"; + + if ( AttrVal( $name, 'debugJSON', 0 ) == 1 ) { readingsBeginUpdate($hash); - readingsBulkUpdate($hash, 'JSON_ERROR', $@, 1); - readingsBulkUpdate($hash, 'JSON_ERROR_STRING', $json, 1); - readingsEndUpdate($hash, 1); + readingsBulkUpdate( $hash, 'JSON_ERROR', $@, 1 ); + readingsBulkUpdate( $hash, 'JSON_ERROR_STRING', $json, 1 ); + readingsEndUpdate( $hash, 1 ); } } - - - - if( defined($decode_json->{sessions}) and $decode_json->{sessions}) { - - $hash->{helper}{session_id} = $decode_json->{sessions}{token}; - $hash->{helper}{user_id} = $decode_json->{sessions}{user_id}; - - GardenaSmartBridge_Write($hash,undef,undef,undef); + + if ( defined( $decode_json->{sessions} ) and $decode_json->{sessions} ) { + + $hash->{helper}{session_id} = $decode_json->{sessions}{token}; + $hash->{helper}{user_id} = $decode_json->{sessions}{user_id}; + + Write( $hash, undef, undef, undef ); Log3 $name, 3, "GardenaSmartBridge ($name) - fetch locations id"; - readingsSingleUpdate($hash,'token',$hash->{helper}{session_id},1); - - return; - - } elsif( not defined($hash->{helper}{locations_id}) and defined($decode_json->{locations}) and ref($decode_json->{locations}) eq "ARRAY" and scalar(@{$decode_json->{locations}}) > 0) { - - foreach my $location ( @{$decode_json->{locations}} ) { - - $hash->{helper}{locations_id} = $location->{id}; + readingsSingleUpdate( $hash, 'token', $hash->{helper}{session_id}, 1 ); - GardenaSmartBridge_WriteReadings($hash,$location); + return; + + } + elsif ( not defined( $hash->{helper}{locations_id} ) + and defined( $decode_json->{locations} ) + and ref( $decode_json->{locations} ) eq "ARRAY" + and scalar( @{ $decode_json->{locations} } ) > 0 ) + { + + foreach my $location ( @{ $decode_json->{locations} } ) { + + $hash->{helper}{locations_id} = $location->{id}; + + WriteReadings( $hash, $location ); } - - Log3 $name, 3, "GardenaSmartBridge ($name) - processed locations id. ID is " . $hash->{helper}{locations_id}; - GardenaSmartBridge_Write($hash,undef,undef,undef); - + + Log3 $name, 3, + "GardenaSmartBridge ($name) - processed locations id. ID is " + . $hash->{helper}{locations_id}; + Write( $hash, undef, undef, undef ); + return; - - } elsif( defined($decode_json->{devices}) and ref($decode_json->{devices}) eq "ARRAY" and scalar(@{$decode_json->{devices}}) > 0) { - my @buffer = split('"devices":\[',$json); - - - my ($json,$tail) = GardenaSmartBridge_ParseJSON($hash, $buffer[1]); + } + elsif ( defined( $decode_json->{devices} ) + and ref( $decode_json->{devices} ) eq "ARRAY" + and scalar( @{ $decode_json->{devices} } ) > 0 ) + { + my @buffer = split( '"devices":\[', $json ); - while($json) { - - 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; - - - unless( not defined($tail) and not ($tail) ) { - - $decode_json = eval{decode_json($json)}; - if($@){ - Log3 $name, 3, "GardenaSmartBridge ($name) - JSON error while request: $@"; + my ( $json, $tail ) = ParseJSON( $hash, $buffer[1] ); + + while ($json) { + + 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; + + unless ( not defined($tail) and not($tail) ) { + + $decode_json = eval { decode_json($json) }; + if ($@) { + Log3 $name, 3, +"GardenaSmartBridge ($name) - JSON error while request: $@"; } - - Dispatch($hash,$json,undef) - unless( $decode_json->{category} eq 'gateway' ); + + Dispatch( $hash, $json, undef ) + unless ( $decode_json->{category} eq 'gateway' ); } - - ($json,$tail) = GardenaSmartBridge_ParseJSON($hash, $tail); - - Log3 $name, 5, "GardenaSmartBridge ($name) - Nach Sub: Laenge JSON: " . length($json) . " Content: " . $json . " Tail: " . $tail; + + ( $json, $tail ) = ParseJSON( $hash, $tail ); + + Log3 $name, 5, + "GardenaSmartBridge ($name) - Nach Sub: Laenge JSON: " + . length($json) + . " Content: " + . $json + . " Tail: " + . $tail; } return; } - Log3 $name, 3, "GardenaSmartBridge ($name) - no Match for processing data" + Log3 $name, 3, "GardenaSmartBridge ($name) - no Match for processing data"; } -sub GardenaSmartBridge_WriteReadings($$) { +sub WriteReadings($$) { - my ($hash,$decode_json) = @_; - my $name = $hash->{NAME}; + my ( $hash, $decode_json ) = @_; + my $name = $hash->{NAME}; - - if( defined($decode_json->{id}) and $decode_json->{id} and defined($decode_json->{name}) and $decode_json->{name} ) { + if ( defined( $decode_json->{id} ) + and $decode_json->{id} + and defined( $decode_json->{name} ) + and $decode_json->{name} ) + { readingsBeginUpdate($hash); - readingsBulkUpdateIfChanged($hash,'name',$decode_json->{name}); - readingsBulkUpdateIfChanged($hash,'authorized_user_ids',scalar(@{$decode_json->{authorized_user_ids}})); - readingsBulkUpdateIfChanged($hash,'devices',scalar(@{$decode_json->{devices}})); - - while( ( my ($t,$v) ) = each %{$decode_json->{geo_position}} ) { - $v = encode_utf8($v); - readingsBulkUpdateIfChanged($hash,$t,$v); + readingsBulkUpdateIfChanged( $hash, 'name', $decode_json->{name} ); + readingsBulkUpdateIfChanged( $hash, 'authorized_user_ids', + scalar( @{ $decode_json->{authorized_user_ids} } ) ); + readingsBulkUpdateIfChanged( $hash, 'devices', + scalar( @{ $decode_json->{devices} } ) ); + + while ( ( my ( $t, $v ) ) = each %{ $decode_json->{geo_position} } ) { + $v = encode_utf8($v); + readingsBulkUpdateIfChanged( $hash, $t, $v ); } - - readingsBulkUpdateIfChanged($hash,'zones',scalar(@{$decode_json->{zones}})); + + readingsBulkUpdateIfChanged( $hash, 'zones', + scalar( @{ $decode_json->{zones} } ) ); readingsEndUpdate( $hash, 1 ); } Log3 $name, 3, "GardenaSmartBridge ($name) - readings would be written"; } - #################################### #################################### #### my little helpers Sub's ####### -sub GardenaSmartBridge_getDevices($) { +sub getDevices($) { + + my $hash = shift; + my $name = $hash->{NAME}; - my $hash = shift; - my $name = $hash->{NAME}; - - RemoveInternalTimer($hash); - - if( not IsDisabled($name) ) { - GardenaSmartBridge_Write($hash,undef,undef,undef); - Log3 $name, 4, "GardenaSmartBridge ($name) - fetch device list and device states"; - } else { - - readingsSingleUpdate($hash,'state','disabled',1); + if ( not IsDisabled($name) ) { + + Write( $hash, undef, undef, undef ); + Log3 $name, 4, + "GardenaSmartBridge ($name) - fetch device list and device states"; + } + else { + + readingsSingleUpdate( $hash, 'state', 'disabled', 1 ); Log3 $name, 3, "GardenaSmartBridge ($name) - device is disabled"; } } -sub GardenaSmartBridge_getToken($) { +sub getToken($) { - my $hash = shift; - my $name = $hash->{NAME}; + my $hash = shift; + my $name = $hash->{NAME}; + return readingsSingleUpdate( $hash, 'state', + 'please set Attribut gardenaAccountEmail first', 1 ) + if ( AttrVal( $name, 'gardenaAccountEmail', 'none' ) eq 'none' ); + return readingsSingleUpdate( $hash, 'state', + 'please set gardena account password first', 1 ) + if ( not defined( ReadPassword($hash) ) ); + readingsSingleUpdate( $hash, 'state', 'get token', 1 ); - return readingsSingleUpdate($hash,'state','please set Attribut gardenaAccountEmail first',1) if(AttrVal($name,'gardenaAccountEmail','none') eq 'none'); - return readingsSingleUpdate($hash,'state','please set gardena account password first',1) if( not defined(GardenaSmartBridge_ReadPassword($hash)) ); - readingsSingleUpdate($hash,'state','get token',1); + delete $hash->{helper}{session_id} + if ( defined( $hash->{helper}{session_id} ) + and $hash->{helper}{session_id} ); + delete $hash->{helper}{user_id} + if ( defined( $hash->{helper}{user_id} ) and $hash->{helper}{user_id} ); + delete $hash->{helper}{locations_id} + if ( defined( $hash->{helper}{locations_id} ) + and $hash->{helper}{locations_id} ); - delete $hash->{helper}{session_id} if( defined($hash->{helper}{session_id}) and $hash->{helper}{session_id} ); - delete $hash->{helper}{user_id} if( defined($hash->{helper}{user_id}) and $hash->{helper}{user_id} ); - delete $hash->{helper}{locations_id} if( defined($hash->{helper}{locations_id}) and $hash->{helper}{locations_id} ); - - GardenaSmartBridge_Write($hash,'"sessions": {"email": "'.AttrVal($name,'gardenaAccountEmail','none').'","password": "'.GardenaSmartBridge_ReadPassword($hash).'"}',undef,undef); - - Log3 $name, 3, "GardenaSmartBridge ($name) - send credentials to fetch Token and locationId"; + Write( + $hash, + '"sessions": {"email": "' + . AttrVal( $name, 'gardenaAccountEmail', 'none' ) + . '","password": "' + . ReadPassword($hash) . '"}', + undef, + undef + ); + + Log3 $name, 3, +"GardenaSmartBridge ($name) - send credentials to fetch Token and locationId"; } -sub GardenaSmartBridge_StorePassword($$) { - - my ($hash, $password) = @_; - my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd"; - my $key = getUniqueId().$index; +sub StorePassword($$) { + + my ( $hash, $password ) = @_; + my $index = $hash->{TYPE} . "_" . $hash->{NAME} . "_passwd"; + my $key = getUniqueId() . $index; my $enc_pwd = ""; - - if(eval "use Digest::MD5;1") { - - $key = Digest::MD5::md5_hex(unpack "H*", $key); + if ( eval "use Digest::MD5;1" ) { + + $key = Digest::MD5::md5_hex( unpack "H*", $key ); $key .= Digest::MD5::md5_hex($key); } - - for my $char (split //, $password) { - - my $encode=chop($key); - $enc_pwd.=sprintf("%.2x",ord($char)^ord($encode)); - $key=$encode.$key; + + for my $char ( split //, $password ) { + + my $encode = chop($key); + $enc_pwd .= sprintf( "%.2x", ord($char) ^ ord($encode) ); + $key = $encode . $key; } - - my $err = setKeyValue($index, $enc_pwd); - return "error while saving the password - $err" if(defined($err)); + + my $err = setKeyValue( $index, $enc_pwd ); + return "error while saving the password - $err" if ( defined($err) ); return "password successfully saved"; } -sub GardenaSmartBridge_ReadPassword($) { - - my ($hash) = @_; - my $name = $hash->{NAME}; - my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd"; - my $key = getUniqueId().$index; - my ($password, $err); +sub ReadPassword($) { + + my ($hash) = @_; + my $name = $hash->{NAME}; + my $index = $hash->{TYPE} . "_" . $hash->{NAME} . "_passwd"; + my $key = getUniqueId() . $index; + my ( $password, $err ); - Log3 $name, 4, "GardenaSmartBridge ($name) - Read password from file"; - - ($err, $password) = getKeyValue($index); + + ( $err, $password ) = getKeyValue($index); if ( defined($err) ) { - - Log3 $name, 3, "GardenaSmartBridge ($name) - unable to read password from file: $err"; + + Log3 $name, 3, +"GardenaSmartBridge ($name) - unable to read password from file: $err"; return undef; - + } - + if ( defined($password) ) { if ( eval "use Digest::MD5;1" ) { - - $key = Digest::MD5::md5_hex(unpack "H*", $key); + + $key = Digest::MD5::md5_hex( unpack "H*", $key ); $key .= Digest::MD5::md5_hex($key); } - + my $dec_pwd = ''; - - for my $char (map { pack('C', hex($_)) } ($password =~ /(..)/g)) { - - my $decode=chop($key); - $dec_pwd.=chr(ord($char)^ord($decode)); - $key=$decode.$key; + + for my $char ( map { pack( 'C', hex($_) ) } ( $password =~ /(..)/g ) ) { + + my $decode = chop($key); + $dec_pwd .= chr( ord($char) ^ ord($decode) ); + $key = $decode . $key; } - + return $dec_pwd; - - } else { - + + } + else { + Log3 $name, 3, "GardenaSmartBridge ($name) - No password in file"; return undef; } } -sub GardenaSmartBridge_Rename(@) { +sub Rename(@) { - my ($new,$old) = @_; - my $hash = $defs{$new}; - + my ( $new, $old ) = @_; + my $hash = $defs{$new}; - GardenaSmartBridge_StorePassword($hash,GardenaSmartBridge_ReadPassword($hash)); - setKeyValue($hash->{TYPE}."_".$old."_passwd",undef); + StorePassword( $hash, ReadPassword($hash) ); + setKeyValue( $hash->{TYPE} . "_" . $old . "_passwd", undef ); return undef; } -sub GardenaSmartBridge_ParseJSON($$) { +sub ParseJSON($$) { - my ($hash, $buffer) = @_; - - my $name = $hash->{NAME}; - my $open = 0; - my $close = 0; - my $msg = ''; - my $tail = ''; - - - if($buffer) { - foreach my $c (split //, $buffer) { - if($open == $close and $open > 0) { + my ( $hash, $buffer ) = @_; + + my $name = $hash->{NAME}; + my $open = 0; + my $close = 0; + my $msg = ''; + my $tail = ''; + + if ($buffer) { + foreach my $c ( split //, $buffer ) { + if ( $open == $close and $open > 0 ) { $tail .= $c; - Log3 $name, 5, "GardenaSmartBridge ($name) - $open == $close and $open > 0"; - - } elsif(($open == $close) and ($c ne '{')) { - - Log3 $name, 5, "GardenaSmartBridge ($name) - Garbage character before message: " . $c; - - } else { - - if($c eq '{') { + Log3 $name, 5, + "GardenaSmartBridge ($name) - $open == $close and $open > 0"; + + } + elsif ( ( $open == $close ) and ( $c ne '{' ) ) { + + Log3 $name, 5, +"GardenaSmartBridge ($name) - Garbage character before message: " + . $c; + + } + else { + + if ( $c eq '{' ) { $open++; - - } elsif($c eq '}') { - + + } + elsif ( $c eq '}' ) { + $close++; } - + $msg .= $c; } } - - if($open != $close) { - + + if ( $open != $close ) { + $tail = $msg; - $msg = ''; + $msg = ''; } } - - Log3 $name, 5, "GardenaSmartBridge ($name) - return msg: $msg and tail: $tail"; - return ($msg,$tail); + + Log3 $name, 5, + "GardenaSmartBridge ($name) - return msg: $msg and tail: $tail"; + return ( $msg, $tail ); } -sub GardenaSmartBridge_createHttpValueStrings($@) { +sub createHttpValueStrings($@) { - my ($hash,$payload,$deviceId,$abilities) = @_; - my $session_id = $hash->{helper}{session_id}; - my $header = "Content-Type: application/json"; - my $uri = ''; - my $method = 'POST'; - $header .= "\r\nX-Session: $session_id" if( defined($hash->{helper}{session_id}) ); - $payload = '{' . $payload . '}' if( defined($payload) ); - $payload = '{}' if( not defined($payload) ); + my ( $hash, $payload, $deviceId, $abilities ) = @_; + my $session_id = $hash->{helper}{session_id}; + my $header = "Content-Type: application/json"; + my $uri = ''; + my $method = 'POST'; + $header .= "\r\nX-Session: $session_id" + if ( defined( $hash->{helper}{session_id} ) ); + $payload = '{' . $payload . '}' if ( defined($payload) ); + $payload = '{}' if ( not defined($payload) ); - - if( $payload eq '{}' ) { - $method = 'GET'; - $uri .= '/locations/?user_id=' . $hash->{helper}{user_id} if( not defined($hash->{helper}{locations_id}) ); - readingsSingleUpdate($hash,'state','fetch locationId',1) if( not defined($hash->{helper}{locations_id}) ); - $uri .= '/sessions' if( not defined($hash->{helper}{session_id})); - $uri .= '/devices' if( not defined($abilities) and defined($hash->{helper}{locations_id}) ); + if ( $payload eq '{}' ) { + $method = 'GET'; + $uri .= '/locations/?user_id=' . $hash->{helper}{user_id} + if ( not defined( $hash->{helper}{locations_id} ) ); + readingsSingleUpdate( $hash, 'state', 'fetch locationId', 1 ) + if ( not defined( $hash->{helper}{locations_id} ) ); + $uri .= '/sessions' if ( not defined( $hash->{helper}{session_id} ) ); + $uri .= '/devices' + if ( not defined($abilities) + and defined( $hash->{helper}{locations_id} ) ); } - - $uri .= '/sessions' if( not defined($hash->{helper}{session_id})); - - if( defined($hash->{helper}{locations_id}) ) { - if ( defined($abilities) and $abilities eq 'mower_settings') { - - $method = 'PUT'; + + $uri .= '/sessions' if ( not defined( $hash->{helper}{session_id} ) ); + + if ( defined( $hash->{helper}{locations_id} ) ) { + if ( defined($abilities) and $abilities eq 'mower_settings' ) { + + $method = 'PUT'; my $dhash = $modules{GardenaSmartDevice}{defptr}{$deviceId}; - $uri .= '/devices/' . $deviceId . '/settings/' . $dhash->{helper}{STARTINGPOINTID} if( defined($abilities) and defined($payload) and $abilities eq 'mower_settings'); - - } elsif( defined($abilities) and defined($payload) and $abilities eq 'watering') { - my $valve_id; - $method = 'PUT'; - - if( $payload =~ m#watering_timer_(\d)# ) { - $valve_id = $1; - } - $uri .= '/devices/' . $deviceId . '/abilities/' . $abilities . '/properties/watering_timer_' . $valve_id; + $uri .= + '/devices/' + . $deviceId + . '/settings/' + . $dhash->{helper}{STARTINGPOINTID} + if ( defined($abilities) + and defined($payload) + and $abilities eq 'mower_settings' ); - } else { - $uri .= '/devices/' . $deviceId . '/abilities/' . $abilities . '/command' if( defined($abilities) and defined($payload) ); } - - $uri .= '?locationId=' . $hash->{helper}{locations_id}; + elsif ( defined($abilities) + and defined($payload) + and $abilities eq 'watering' ) + { + my $valve_id; + $method = 'PUT'; + + if ( $payload =~ m#watering_timer_(\d)# ) { + $valve_id = $1; + } + $uri .= + '/devices/' + . $deviceId + . '/abilities/' + . $abilities + . '/properties/watering_timer_' + . $valve_id; + + } + else { + $uri .= + '/devices/' . $deviceId . '/abilities/' . $abilities . '/command' + if ( defined($abilities) and defined($payload) ); + } + + $uri .= '?locationId=' . $hash->{helper}{locations_id}; } - return ($payload,$session_id,$header,$uri,$method,$deviceId,$abilities); + return ( $payload, $session_id, $header, $uri, $method, $deviceId, + $abilities ); } -sub GardenaSmartBridge_DeletePassword($) { - - my $hash = shift; +sub DeletePassword($) { + my $hash = shift; #my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd"; - setKeyValue($hash->{TYPE}."_".$hash->{NAME}."_passwd",undef); + setKeyValue( $hash->{TYPE} . "_" . $hash->{NAME} . "_passwd", undef ); return undef; } - - - 1; - - - - - =pod =item device diff --git a/fhem/FHEM/74_GardenaSmartDevice.pm b/fhem/FHEM/74_GardenaSmartDevice.pm index be2f1db08..f9d58c71e 100644 --- a/fhem/FHEM/74_GardenaSmartDevice.pm +++ b/fhem/FHEM/74_GardenaSmartDevice.pm @@ -1,5 +1,5 @@ ############################################################################### -# +# # Developed with Kate # # (c) 2017-2018 Copyright: Marko Oldenburg (leongaultier at gmail dot com) @@ -38,7 +38,7 @@ # # if($@){ # Log3($SELF, 2, "$TYPE ($SELF) - error while request: $@"); -# +# # readingsSingleUpdate($hash, "state", "error", 1); # # return; @@ -49,356 +49,522 @@ # # apt-get install libio-socket-ssl-perl # http://www.dxsdata.com/de/2016/07/php-class-for-gardena-smart-system-api/ -# +# ## ## - - package main; +use strict; +use warnings; + +# # Declare functions +# sub GardenaSmartDevice_Attr(@); +# sub GardenaSmartDevice_Define($$); +# sub GardenaSmartDevice_Initialize($); +# sub GardenaSmartDevice_Set($@); +# sub GardenaSmartDevice_Undef($$); +# sub GardenaSmartDevice_WriteReadings($$); +# sub GardenaSmartDevice_Parse($$); +# sub GardenaSmartDevice_ReadingLangGerman($$); +# sub GardenaSmartDevice_RigRadingsValue($$); +# sub GardenaSmartDevice_Zulu2LocalString($); +# sub GardenaSmartDevice_SetPredefinedStartPoints($@); + +my $version = "1.4.0"; + +sub GardenaSmartDevice_Initialize($) { + + my ($hash) = @_; + + $hash->{Match} = '^{"id":".*'; + + $hash->{SetFn} = "GardenaSmartDevice::Set"; + $hash->{DefFn} = "GardenaSmartDevice::Define"; + $hash->{UndefFn} = "GardenaSmartDevice::Undef"; + $hash->{ParseFn} = "GardenaSmartDevice::Parse"; + + $hash->{AttrFn} = "GardenaSmartDevice::Attr"; + $hash->{AttrList} = + "readingValueLanguage:de,en " + . "model:watering_computer,sensor,mower,ic24 " + . "IODev " + . $readingFnAttributes; + + foreach my $d ( sort keys %{ $modules{GardenaSmartDevice}{defptr} } ) { + + my $hash = $modules{GardenaSmartDevice}{defptr}{$d}; + $hash->{VERSION} = $version; + } +} + +## unserer packagename +package GardenaSmartDevice; + +use GPUtils qw(:all) + ; # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt my $missingModul = ""; use strict; use warnings; +use POSIX; + use Time::Local; eval "use JSON;1" or $missingModul .= "JSON "; - -my $version = "1.2.2"; - - - - -# Declare functions -sub GardenaSmartDevice_Attr(@); -sub GardenaSmartDevice_Define($$); -sub GardenaSmartDevice_Initialize($); -sub GardenaSmartDevice_Set($@); -sub GardenaSmartDevice_Undef($$); -sub GardenaSmartDevice_WriteReadings($$); -sub GardenaSmartDevice_Parse($$); -sub GardenaSmartDevice_ReadingLangGerman($$); -sub GardenaSmartDevice_RigRadingsValue($$); -sub GardenaSmartDevice_Zulu2LocalString($); -sub GardenaSmartDevice_SetPredefinedStartPoints($@); - - - - -sub GardenaSmartDevice_Initialize($) { - - my ($hash) = @_; - - $hash->{Match} = '^{"id":".*'; - - $hash->{SetFn} = "GardenaSmartDevice_Set"; - $hash->{DefFn} = "GardenaSmartDevice_Define"; - $hash->{UndefFn} = "GardenaSmartDevice_Undef"; - $hash->{ParseFn} = "GardenaSmartDevice_Parse"; - - $hash->{AttrFn} = "GardenaSmartDevice_Attr"; - $hash->{AttrList} = "readingValueLanguage:de,en ". - "model:watering_computer,sensor,mower,ic24 ". - "IODev ". - $readingFnAttributes; - - foreach my $d(sort keys %{$modules{GardenaSmartDevice}{defptr}}) { - - my $hash = $modules{GardenaSmartDevice}{defptr}{$d}; - $hash->{VERSION} = $version; - } +## Import der FHEM Funktionen +BEGIN { + GP_Import( + qw(readingsSingleUpdate + readingsBulkUpdate + readingsBulkUpdateIfChanged + readingsBeginUpdate + readingsEndUpdate + Log3 + CommandAttr + AttrVal + ReadingsVal + AssignIoPort + modules + IOWrite + defs) + ); } -sub GardenaSmartDevice_Define($$) { +sub Define($$) { - my ( $hash, $def ) = @_; - my @a = split( "[ \t]+", $def ); + my ( $hash, $def ) = @_; + my @a = split( "[ \t]+", $def ); - return "too few parameters: define GardenaSmartDevice " if( @a < 3 ) ; - return "Cannot define Gardena Bridge device. Perl modul $missingModul is missing." if ( $missingModul ); + return + "too few parameters: define GardenaSmartDevice " + if ( @a < 3 ); + return +"Cannot define Gardena Bridge device. Perl modul $missingModul is missing." + if ($missingModul); - - my $name = $a[0]; - my $deviceId = $a[2]; - my $category = $a[3]; - - $hash->{DEVICEID} = $deviceId; - $hash->{VERSION} = $version; - $hash->{helper}{STARTINGPOINTID} = ''; + my $name = $a[0]; + my $deviceId = $a[2]; + my $category = $a[3]; - - - CommandAttr(undef,"$name IODev $modules{GardenaSmartBridge}{defptr}{BRIDGE}->{NAME}") if(AttrVal($name,'IODev','none') eq 'none'); + $hash->{DEVICEID} = $deviceId; + $hash->{VERSION} = $version; + $hash->{helper}{STARTINGPOINTID} = ''; - my $iodev = AttrVal($name,'IODev','none'); - - AssignIoPort($hash,$iodev) if( !$hash->{IODev} ); - - if(defined($hash->{IODev}->{NAME})) { - Log3 $name, 3, "GardenaSmartDevice ($name) - I/O device is " . $hash->{IODev}->{NAME}; - } else { + CommandAttr( undef, + "$name IODev $modules{GardenaSmartBridge}{defptr}{BRIDGE}->{NAME}" ) + if ( AttrVal( $name, 'IODev', 'none' ) eq 'none' ); + + my $iodev = AttrVal( $name, 'IODev', 'none' ); + + AssignIoPort( $hash, $iodev ) if ( !$hash->{IODev} ); + + if ( defined( $hash->{IODev}->{NAME} ) ) { + Log3 $name, 3, "GardenaSmartDevice ($name) - I/O device is " + . $hash->{IODev}->{NAME}; + } + else { Log3 $name, 1, "GardenaSmartDevice ($name) - no I/O device"; } - + $iodev = $hash->{IODev}->{NAME}; - + my $d = $modules{GardenaSmartDevice}{defptr}{$deviceId}; - - return "GardenaSmartDevice device $name on GardenaSmartBridge $iodev already defined." - if( defined($d) and $d->{IODev} == $hash->{IODev} and $d->{NAME} ne $name ); - - - #$attr{$name}{room} = "GardenaSmart" if( not defined( $attr{$name}{room} ) ); - CommandAttr(undef,$name.' room GardenaSmart') if( AttrVal($name,'room','none') eq 'none'); - #$attr{$name}{model} = $category if( not defined( $attr{$name}{model} ) ); - CommandAttr(undef,$name.' model '.$category) if( AttrVal($name,'model','none') eq 'none'); - - Log3 $name, 3, "GardenaSmartDevice ($name) - defined GardenaSmartDevice with DEVICEID: $deviceId"; - readingsSingleUpdate($hash,'state','initialized',1); - + + return +"GardenaSmartDevice device $name on GardenaSmartBridge $iodev already defined." + if ( defined($d) + and $d->{IODev} == $hash->{IODev} + and $d->{NAME} ne $name ); + +#$attr{$name}{room} = "GardenaSmart" if( not defined( $attr{$name}{room} ) ); + CommandAttr( undef, $name . ' room GardenaSmart' ) + if ( AttrVal( $name, 'room', 'none' ) eq 'none' ); + +#$attr{$name}{model} = $category if( not defined( $attr{$name}{model} ) ); + CommandAttr( undef, $name . ' model ' . $category ) + if ( AttrVal( $name, 'model', 'none' ) eq 'none' ); + + Log3 $name, 3, +"GardenaSmartDevice ($name) - defined GardenaSmartDevice with DEVICEID: $deviceId"; + readingsSingleUpdate( $hash, 'state', 'initialized', 1 ); + $modules{GardenaSmartDevice}{defptr}{$deviceId} = $hash; return undef; } -sub GardenaSmartDevice_Undef($$) { +sub Undef($$) { + + my ( $hash, $arg ) = @_; + my $name = $hash->{NAME}; + my $deviceId = $hash->{DEVICEID}; - my ( $hash, $arg ) = @_; - my $name = $hash->{NAME}; - my $deviceId = $hash->{DEVICEID}; - - delete $modules{GardenaSmartDevice}{defptr}{$deviceId}; return undef; } -sub GardenaSmartDevice_Attr(@) { +sub Attr(@) { my ( $cmd, $name, $attrName, $attrVal ) = @_; my $hash = $defs{$name}; - return undef; } -sub GardenaSmartDevice_Set($@) { - - my ($hash, $name, $cmd, @args) = @_; +sub Set($@) { + + my ( $hash, $name, $cmd, @args ) = @_; + #my ($arg, @params) = @args; - + my $payload; - my $abilities = ''; - - + my $abilities = ''; + ### mower - if( lc $cmd eq 'parkuntilfurthernotice' ) { + if ( lc $cmd eq 'parkuntilfurthernotice' ) { - $payload = '"name":"park_until_further_notice"'; - - } elsif( lc $cmd eq 'parkuntilnexttimer' ) { - - $payload = '"name":"park_until_next_timer"'; - - } elsif( lc $cmd eq 'startresumeschedule' ) { - - $payload = '"name":"start_resume_schedule"'; - - } elsif( lc $cmd eq 'startoverridetimer' ) { - - my $duration = join( " ", @args ); - $payload = '"name":"start_override_timer","parameters":{"duration":' . $duration . '}'; + $payload = '"name":"park_until_further_notice"'; - } elsif( lc $cmd eq 'startpoint' ) { + } + elsif ( lc $cmd eq 'parkuntilnexttimer' ) { + + $payload = '"name":"park_until_next_timer"'; + + } + elsif ( lc $cmd eq 'startresumeschedule' ) { + + $payload = '"name":"start_resume_schedule"'; + + } + elsif ( lc $cmd eq 'startoverridetimer' ) { + + my $duration = join( " ", @args ); + $payload = '"name":"start_override_timer","parameters":{"duration":' + . $duration . '}'; + + } + elsif ( lc $cmd eq 'startpoint' ) { my $err; - - ($err,$payload,$abilities) = GardenaSmartDevice_SetPredefinedStartPoints($hash,@args); - return $err if( defined($err) ); - ### watering_computer - } elsif( lc $cmd eq 'manualoverride' ) { - - my $duration = join( " ", @args ); - $payload = '"name":"manual_override","parameters":{"duration":' . $duration . '}'; - - } elsif( lc $cmd eq 'canceloverride' ) { - - $payload = '"name":"cancel_override"'; - - ### Watering ic24 - } elsif( $cmd =~ /manualDurationValve/ ) { - + ( $err, $payload, $abilities ) = + SetPredefinedStartPoints( $hash, @args ); + return $err if ( defined($err) ); + + ### watering_computer + } + elsif ( lc $cmd eq 'manualoverride' ) { + + my $duration = join( " ", @args ); + $payload = '"name":"manual_override","parameters":{"duration":' + . $duration . '}'; + + } + elsif ( lc $cmd eq 'canceloverride' ) { + + $payload = '"name":"cancel_override"'; + + ### Watering ic24 + } + elsif ( $cmd =~ /manualDurationValve/ ) { + my $valve_id; - my $duration = join( " ", @args ); - - if( $cmd =~ m#(\d)$# ) { - $valve_id = $1; + my $duration = join( " ", @args ); + + if ( $cmd =~ m#(\d)$# ) { + $valve_id = $1; } - $payload = '"properties":{"name":"watering_timer_' . $valve_id . '","value":{"state":"manual","duration":' . $duration . ',"valve_id":' . $valve_id . '}}'; - - ### Sensors - } elsif( lc $cmd eq 'refresh' ) { - - my $sensname = join( " ", @args ); - if( lc $sensname eq 'temperature' ) { - $payload = '"name":"measure_ambient_temperature"'; - $abilities = 'ambient_temperature'; - - } elsif( lc $sensname eq 'light' ) { - $payload = '"name":"measure_light"'; - $abilities = 'light'; - - } elsif( lc $sensname eq 'humidity' ) { - $payload = '"name":"measure_soil_humidity"'; - $abilities = 'humidity'; + $payload = + '"properties":{"name":"watering_timer_' + . $valve_id + . '","value":{"state":"manual","duration":' + . $duration + . ',"valve_id":' + . $valve_id . '}}'; + + ### Sensors + } + elsif ( lc $cmd eq 'refresh' ) { + + my $sensname = join( " ", @args ); + if ( lc $sensname eq 'temperature' ) { + $payload = '"name":"measure_ambient_temperature"'; + $abilities = 'ambient_temperature'; + + } + elsif ( lc $sensname eq 'light' ) { + $payload = '"name":"measure_light"'; + $abilities = 'light'; + + } + elsif ( lc $sensname eq 'humidity' ) { + $payload = '"name":"measure_soil_humidity"'; + $abilities = 'humidity'; } - } else { - - my $list = ''; - $list .= 'parkUntilFurtherNotice:noArg parkUntilNextTimer:noArg startResumeSchedule:noArg startOverrideTimer:slider,0,60,1440 startpoint' if( AttrVal($name,'model','unknown') eq 'mower' ); - $list .= 'manualOverride:slider,0,1,59 cancelOverride:noArg' if( AttrVal($name,'model','unknown') eq 'watering_computer' ); - $list .= 'manualDurationValve1:slider,1,1,59 manualDurationValve2:slider,1,1,59 manualDurationValve3:slider,1,1,59 manualDurationValve4:slider,1,1,59 manualDurationValve5:slider,1,1,59 manualDurationValve6:slider,1,1,59' if( AttrVal($name,'model','unknown') eq 'ic24' ); - $list .= 'refresh:temperature,light,humidity' if( AttrVal($name,'model','unknown') eq 'sensor' ); - + } + else { + + my $list = ''; + $list .= +'parkUntilFurtherNotice:noArg parkUntilNextTimer:noArg startResumeSchedule:noArg startOverrideTimer:slider,0,60,1440 startpoint' + if ( AttrVal( $name, 'model', 'unknown' ) eq 'mower' ); + $list .= 'manualOverride:slider,0,1,59 cancelOverride:noArg' + if ( AttrVal( $name, 'model', 'unknown' ) eq 'watering_computer' ); + $list .= +'manualDurationValve1:slider,1,1,59 manualDurationValve2:slider,1,1,59 manualDurationValve3:slider,1,1,59 manualDurationValve4:slider,1,1,59 manualDurationValve5:slider,1,1,59 manualDurationValve6:slider,1,1,59' + if ( AttrVal( $name, 'model', 'unknown' ) eq 'ic24' ); + $list .= 'refresh:temperature,light,humidity' + if ( AttrVal( $name, 'model', 'unknown' ) eq 'sensor' ); + return "Unknown argument $cmd, choose one of $list"; } - - $abilities = 'mower' if( AttrVal($name,'model','unknown') eq 'mower' ) and $abilities ne 'mower_settings'; - $abilities = 'outlet' if( AttrVal($name,'model','unknown') eq 'watering_computer' ); - $abilities = 'watering' if( AttrVal($name,'model','unknown') eq 'ic24' ); - - - $hash->{helper}{deviceAction} = $payload; - readingsSingleUpdate( $hash, "state", "send command to gardena cloud", 1); - - IOWrite($hash,$payload,$hash->{DEVICEID},$abilities); - Log3 $name, 4, "GardenaSmartBridge ($name) - IOWrite: $payload $hash->{DEVICEID} $abilities IODevHash=$hash->{IODev}"; - + + $abilities = 'mower' + if ( AttrVal( $name, 'model', 'unknown' ) eq 'mower' ) + and $abilities ne 'mower_settings'; + $abilities = 'outlet' + if ( AttrVal( $name, 'model', 'unknown' ) eq 'watering_computer' ); + $abilities = 'watering' + if ( AttrVal( $name, 'model', 'unknown' ) eq 'ic24' ); + + $hash->{helper}{deviceAction} = $payload; + readingsSingleUpdate( $hash, "state", "send command to gardena cloud", 1 ); + + IOWrite( $hash, $payload, $hash->{DEVICEID}, $abilities ); + Log3 $name, 4, +"GardenaSmartBridge ($name) - IOWrite: $payload $hash->{DEVICEID} $abilities IODevHash=$hash->{IODev}"; + return undef; } -sub GardenaSmartDevice_Parse($$) { +sub Parse($$) { - my ($io_hash,$json) = @_; - - my $name = $io_hash->{NAME}; - - - - my $decode_json = eval{decode_json($json)}; - if($@){ - Log3 $name, 3, "GardenaSmartBridge ($name) - JSON error while request: $@"; + my ( $io_hash, $json ) = @_; + + my $name = $io_hash->{NAME}; + + my $decode_json = eval { decode_json($json) }; + if ($@) { + Log3 $name, 3, + "GardenaSmartBridge ($name) - JSON error while request: $@"; } - + Log3 $name, 4, "GardenaSmartDevice ($name) - ParseFn was called"; Log3 $name, 4, "GardenaSmartDevice ($name) - JSON: $json"; - - if( defined($decode_json->{id}) ) { - - my $deviceId = $decode_json->{id}; + if ( defined( $decode_json->{id} ) ) { + + my $deviceId = $decode_json->{id}; + + if ( my $hash = $modules{GardenaSmartDevice}{defptr}{$deviceId} ) { + my $name = $hash->{NAME}; + + WriteReadings( $hash, $decode_json ); + Log3 $name, 4, + "GardenaSmartDevice ($name) - find logical device: $hash->{NAME}"; - if( my $hash = $modules{GardenaSmartDevice}{defptr}{$deviceId} ) { - my $name = $hash->{NAME}; - - GardenaSmartDevice_WriteReadings($hash,$decode_json); - Log3 $name, 4, "GardenaSmartDevice ($name) - find logical device: $hash->{NAME}"; - return $hash->{NAME}; - - } else { - - Log3 $name, 3, "GardenaSmartDevice ($name) - autocreate new device " . makeDeviceName($decode_json->{name}) . " with deviceId $decode_json->{id}, model $decode_json->{category}"; - return "UNDEFINED " . makeDeviceName($decode_json->{name}) . " GardenaSmartDevice $decode_json->{id} $decode_json->{category}"; + + } + else { + + Log3 $name, 3, + "GardenaSmartDevice ($name) - autocreate new device " + . makeDeviceName( $decode_json->{name} ) + . " with deviceId $decode_json->{id}, model $decode_json->{category}"; + return + "UNDEFINED " + . makeDeviceName( $decode_json->{name} ) + . " GardenaSmartDevice $decode_json->{id} $decode_json->{category}"; } } } -sub GardenaSmartDevice_WriteReadings($$) { +sub WriteReadings($$) { - my ($hash,$decode_json) = @_; - - my $name = $hash->{NAME}; - my $abilities = scalar (@{$decode_json->{abilities}}); - my $settings = scalar (@{$decode_json->{settings}}); + my ( $hash, $decode_json ) = @_; + + my $name = $hash->{NAME}; + my $abilities = scalar( @{ $decode_json->{abilities} } ); + my $settings = scalar( @{ $decode_json->{settings} } ); - readingsBeginUpdate($hash); - - do { - - if( ref($decode_json->{abilities}[$abilities]{properties}) eq "ARRAY" and scalar(@{$decode_json->{abilities}[$abilities]{properties}}) > 0 ) { - foreach my $propertie (@{$decode_json->{abilities}[$abilities]{properties}}) { - readingsBulkUpdateIfChanged($hash,$decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name},GardenaSmartDevice_RigRadingsValue($hash,$propertie->{value})) if( defined($propertie->{value}) - and $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} ne 'radio-quality' - and $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} ne 'battery-level' - and $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} ne 'internal_temperature-temperature' - and $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} ne 'ambient_temperature-temperature' - and $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} ne 'soil_temperature-temperature' - and $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} ne 'humidity-humidity' - and $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} ne 'light-light' - and ref($propertie->{value}) ne "HASH" ); - - readingsBulkUpdate($hash,$decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name},GardenaSmartDevice_RigRadingsValue($hash,$propertie->{value})) if( defined($propertie->{value}) - and ($decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} eq 'radio-quality' - or $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} eq 'battery-level' - or $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} eq 'internal_temperature-temperature' - or $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} eq 'ambient_temperature-temperature' - or $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} eq 'soil_temperature-temperature' - or $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} eq 'humidity-humidity' - or $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} eq 'light-light') ); - - readingsBulkUpdateIfChanged($hash,$decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name},join(',',@{$propertie->{value}})) if( defined($propertie->{value}) and $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} eq 'ic24-valves_connected' ); - - readingsBulkUpdateIfChanged($hash,$decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name},join(',',@{$propertie->{value}})) if( defined($propertie->{value}) and $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} eq 'ic24-valves_master_config' ); - if( ref($propertie->{value}) eq "HASH" ) { - while( my ($r,$v) = each %{$propertie->{value}} ) { - readingsBulkUpdate($hash,$decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name}.'_'.$r,GardenaSmartDevice_RigRadingsValue($hash,$v)); + do { + + if ( + ref( $decode_json->{abilities}[$abilities]{properties} ) eq "ARRAY" + and + scalar( @{ $decode_json->{abilities}[$abilities]{properties} } ) > + 0 ) + { + foreach my $propertie ( + @{ $decode_json->{abilities}[$abilities]{properties} } ) + { + readingsBulkUpdateIfChanged( + $hash, + $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name}, + RigRadingsValue( + $hash, $propertie->{value} + ) + ) + if ( defined( $propertie->{value} ) + and $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} ne 'radio-quality' + and $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} ne 'battery-level' + and $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} ne 'internal_temperature-temperature' + and $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} ne 'ambient_temperature-temperature' + and $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} ne 'soil_temperature-temperature' + and $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} ne 'humidity-humidity' + and $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} ne 'light-light' + and ref( $propertie->{value} ) ne "HASH" ); + + readingsBulkUpdate( + $hash, + $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name}, + RigRadingsValue( + $hash, $propertie->{value} + ) + ) + if ( + defined( $propertie->{value} ) + and ( $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} eq 'radio-quality' + or $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} eq 'battery-level' + or $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} eq + 'internal_temperature-temperature' + or $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} eq + 'ambient_temperature-temperature' + or $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} eq 'soil_temperature-temperature' + or $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} eq 'humidity-humidity' + or $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} eq 'light-light' ) + ); + + readingsBulkUpdateIfChanged( + $hash, + $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name}, + join( ',', @{ $propertie->{value} } ) + ) + if ( defined( $propertie->{value} ) + and $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} eq 'ic24-valves_connected' ); + + readingsBulkUpdateIfChanged( + $hash, + $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name}, + join( ',', @{ $propertie->{value} } ) + ) + if ( defined( $propertie->{value} ) + and $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} eq 'ic24-valves_master_config' ); + + if ( ref( $propertie->{value} ) eq "HASH" ) { + while ( my ( $r, $v ) = each %{ $propertie->{value} } ) { + readingsBulkUpdate( + $hash, + $decode_json->{abilities}[$abilities]{name} . '-' + . $propertie->{name} . '_' + . $r, + RigRadingsValue( $hash, $v ) + ); } } } } $abilities--; - } while ($abilities >= 0); - + } while ( $abilities >= 0 ); do { - - if( ref($decode_json->{settings}[$settings]{value}) eq "ARRAY" and $decode_json->{settings}[$settings]{name} eq 'starting_points' ) { + + if ( ref( $decode_json->{settings}[$settings]{value} ) eq "ARRAY" + and $decode_json->{settings}[$settings]{name} eq 'starting_points' ) + { #save the startingpointid needed to update the startingpoints - if ($hash->{helper}{STARTINGPOINTID} ne $decode_json->{settings}[$settings]{id}) { - $hash->{helper}{STARTINGPOINTID} = $decode_json->{settings}[$settings]{id}; + if ( $hash->{helper}{STARTINGPOINTID} ne + $decode_json->{settings}[$settings]{id} ) + { + $hash->{helper}{STARTINGPOINTID} = + $decode_json->{settings}[$settings]{id}; } - - $hash->{helper}{STARTINGPOINTS} = '{ "name": "starting_points", "value": '. encode_json($decode_json->{settings}[$settings]{value}) . '}'; + + $hash->{helper}{STARTINGPOINTS} = + '{ "name": "starting_points", "value": ' + . encode_json( $decode_json->{settings}[$settings]{value} ) . '}'; my $startpoint_cnt = 0; - - foreach my $startingpoint (@{$decode_json->{settings}[$settings]{value}}) { + + foreach my $startingpoint ( + @{ $decode_json->{settings}[$settings]{value} } ) + { $startpoint_cnt++; - readingsBulkUpdateIfChanged($hash,'startpoint-'.$startpoint_cnt.'-enabled',$startingpoint->{enabled}); + readingsBulkUpdateIfChanged( + $hash, + 'startpoint-' . $startpoint_cnt . '-enabled', + $startingpoint->{enabled} + ); } } $settings--; - } while ($settings >= 0); - - - readingsBulkUpdate($hash,'state',ReadingsVal($name,'mower-status','readingsValError')) if( AttrVal($name,'model','unknown') eq 'mower' ); - readingsBulkUpdate($hash,'state',(ReadingsVal($name,'outlet-valve_open','readingsValError') == 1 ? GardenaSmartDevice_RigRadingsValue($hash,'open') : GardenaSmartDevice_RigRadingsValue($hash,'closed'))) if( AttrVal($name,'model','unknown') eq 'watering_computer' ); - - readingsBulkUpdate($hash,'state','T: ' . ReadingsVal($name,'ambient_temperature-temperature','readingsValError') . '°C, H: ' . ReadingsVal($name,'humidity-humidity','readingsValError') . '%, L: ' . ReadingsVal($name,'light-light','readingsValError') . 'lux') if( AttrVal($name,'model','unknown') eq 'sensor' ); - - readingsBulkUpdate($hash,'state','scheduled watering next start: ' . (ReadingsVal($name,'scheduling-scheduled_watering_next_start','readingsValError'))) if( AttrVal($name,'model','unknown') eq 'ic24' ); + } while ( $settings >= 0 ); + + readingsBulkUpdate( $hash, 'state', + ReadingsVal( $name, 'mower-status', 'readingsValError' ) ) + if ( AttrVal( $name, 'model', 'unknown' ) eq 'mower' ); + readingsBulkUpdate( + $hash, 'state', + ( + ReadingsVal( $name, 'outlet-valve_open', 'readingsValError' ) == 1 + ? RigRadingsValue( $hash, 'open' ) + : RigRadingsValue( $hash, 'closed' ) + ) + ) if ( AttrVal( $name, 'model', 'unknown' ) eq 'watering_computer' ); + + readingsBulkUpdate( + $hash, 'state', + 'T: ' + . ReadingsVal( $name, 'ambient_temperature-temperature', + 'readingsValError' ) + . '°C, H: ' + . ReadingsVal( $name, 'humidity-humidity', 'readingsValError' ) + . '%, L: ' + . ReadingsVal( $name, 'light-light', 'readingsValError' ) . 'lux' + ) if ( AttrVal( $name, 'model', 'unknown' ) eq 'sensor' ); + + readingsBulkUpdate( + $hash, 'state', + 'scheduled watering next start: ' + . ( + ReadingsVal( + $name, 'scheduling-scheduled_watering_next_start', + 'readingsValError' + ) + ) + ) if ( AttrVal( $name, 'model', 'unknown' ) eq 'ic24' ); readingsEndUpdate( $hash, 1 ); - + Log3 $name, 4, "GardenaSmartDevice ($name) - readings was written}"; } @@ -406,206 +572,245 @@ sub GardenaSmartDevice_WriteReadings($$) { ################################## #### my little helpers ########### -sub GardenaSmartDevice_ReadingLangGerman($$) { +sub ReadingLangGerman($$) { + + my ( $hash, $readingValue ) = @_; + my $name = $hash->{NAME}; - my ($hash,$readingValue) = @_; - my $name = $hash->{NAME}; - - my %langGermanMapp = ( - 'ok_cutting' => 'mähen', - 'paused' => 'pausiert', - 'ok_searching' => 'suche Ladestation', - 'ok_charging' => 'lädt', - 'ok_leaving' => 'mähen', - 'wait_updating' => 'wird aktualisiert ...', - 'wait_power_up' => 'wird eingeschaltet ...', - 'parked_timer' => 'geparkt nach Zeitplan', - 'parked_park_selected' => 'geparkt', - 'off_disabled' => 'der Mäher ist ausgeschaltet', - 'off_hatch_open' => 'deaktiviert. Abdeckung ist offen oder PIN-Code erforderlich', - 'unknown' => 'unbekannter Status', - 'error' => 'Fehler', - 'error_at_power_up' => 'Neustart ...', - 'off_hatch_closed' => 'Deaktiviert. Manueller Start erforderlich', - 'ok_cutting_timer_overridden' => 'manuelles mähen', - 'parked_autotimer' => 'geparkt durch SensorControl', - 'parked_daily_limit_reached' => 'abgeschlossen', - 'no_message' => 'kein Fehler', - 'outside_working_area' => 'außerhalb des Arbeitsbereichs', - 'no_loop_signal' => 'kein Schleifensignal', - 'wrong_loop_signal' => 'falsches Schleifensignal', - 'loop_sensor_problem_front' => 'Problem Schleifensensor, vorne', - 'loop_sensor_problem_rear' => 'Problem Schleifensensor, hinten', - 'trapped' => 'eingeschlossen', - 'upside_down' => 'steht auf dem Kopf', - 'low_battery' => 'niedriger Batteriestand', - 'empty_battery' => 'Batterie leer', - 'no_drive' => 'fährt nicht', - 'lifted' => 'angehoben', - 'stuck_in_charging_station' => 'eingeklemmt in Ladestation', - 'charging_station_blocked' => 'Ladestation blockiert', - 'collision_sensor_problem_rear' => 'Problem Stoßsensor hinten', - 'collision_sensor_problem_front' => 'Problem Stoßsensor vorne', - 'wheel_motor_blocked_right' => 'Radmotor rechts blockiert', - 'wheel_motor_blocked_left' => 'Radmotor links blockiert', - 'wheel_drive_problem_right' => 'Problem Antrieb, rechts', - 'wheel_drive_problem_left' => 'Problem Antrieb, links', - 'cutting_system_blocked' => 'Schneidsystem blockiert', - 'invalid_sub_device_combination' => 'fehlerhafte Verbindung', - 'settings_restored' => 'Standardeinstellungen', - 'electronic_problem' => 'elektronisches Problem', - 'charging_system_problem' => 'Problem Ladesystem', - 'tilt_sensor_problem' => 'Kippsensor Problem', - 'wheel_motor_overloaded_right' => 'rechter Radmotor überlastet', - 'wheel_motor_overloaded_left' => 'linker Radmotor überlastet', - 'charging_current_too_high' => 'Ladestrom zu hoch', - 'temporary_problem' => 'vorübergehendes Problem', - 'guide_1_not_found' => 'SK 1 nicht gefunden', - 'guide_2_not_found' => 'SK 2 nicht gefunden', - 'guide_3_not_found' => 'SK 3 nicht gefunden', - 'difficult_finding_home' => 'Problem die Ladestation zu finden', - 'guide_calibration_accomplished' => 'Kalibrierung des Suchkabels beendet', - 'guide_calibration_failed' => 'Kalibrierung des Suchkabels fehlgeschlagen', - 'temporary_battery_problem' => 'kurzzeitiges Batterieproblem', - 'battery_problem' => 'Batterieproblem', - 'alarm_mower_switched_off' => 'Alarm! Mäher ausgeschalten', - 'alarm_mower_stopped' => 'Alarm! Mäher gestoppt', - 'alarm_mower_lifted' => 'Alarm! Mäher angehoben', - 'alarm_mower_tilted' => 'Alarm! Mäher gekippt', - 'connection_changed' => 'Verbindung geändert', - 'connection_not_changed' => 'Verbindung nicht geändert', - 'com_board_not_available' => 'COM Board nicht verfügbar', - 'slipped' => 'rutscht', - 'out_of_operation' => 'ausser Betrieb', - 'replace_now' => 'kritischer Batteriestand, wechseln Sie jetzt', - 'low' => 'niedrig', - 'ok' => 'oK', - 'no_source' => 'oK', - 'mower_charging' => 'Mäher wurde geladen', - 'completed_cutting_autotimer' => 'Sensor Control erreicht', - 'week_timer' => 'Wochentimer erreicht', - 'countdown_timer' => 'Stoppuhr Timer', - 'undefined' => 'unklar', - 'unknown' => 'unklar', - 'status_device_unreachable' => 'Gerät ist nicht in Reichweite', - 'status_device_alive' => 'Gerät ist in Reichweite', - 'bad' => 'schlecht', - 'poor' => 'schwach', - 'good' => 'gut', - 'undefined' => 'unklar', - 'idle' => 'nichts zu tun', - 'firmware_cancel' => 'Firmwareupload unterbrochen', - 'firmware_upload' => 'Firmwareupload', - 'unsupported' => 'nicht unterstützt', - 'up_to_date' => 'auf dem neusten Stand', - 'mower' => 'Mäher', - 'watering_computer' => 'Bewässerungscomputer', - 'no_frost' => 'kein Frost', - 'open' => 'offen', - 'closed' => 'geschlossen', - 'included' => 'inbegriffen', - 'active' => 'aktiv', - 'inactive' => 'nicht aktiv' + 'ok_cutting' => 'mähen', + 'paused' => 'pausiert', + 'ok_searching' => 'suche Ladestation', + 'ok_charging' => 'lädt', + 'ok_leaving' => 'mähen', + 'wait_updating' => 'wird aktualisiert ...', + 'wait_power_up' => 'wird eingeschaltet ...', + 'parked_timer' => 'geparkt nach Zeitplan', + 'parked_park_selected' => 'geparkt', + 'off_disabled' => 'der Mäher ist ausgeschaltet', + 'off_hatch_open' => + 'deaktiviert. Abdeckung ist offen oder PIN-Code erforderlich', + 'unknown' => 'unbekannter Status', + 'error' => 'Fehler', + 'error_at_power_up' => 'Neustart ...', + 'off_hatch_closed' => 'Deaktiviert. Manueller Start erforderlich', + 'ok_cutting_timer_overridden' => 'manuelles mähen', + 'parked_autotimer' => 'geparkt durch SensorControl', + 'parked_daily_limit_reached' => 'abgeschlossen', + 'no_message' => 'kein Fehler', + 'outside_working_area' => 'außerhalb des Arbeitsbereichs', + 'no_loop_signal' => 'kein Schleifensignal', + 'wrong_loop_signal' => 'falsches Schleifensignal', + 'loop_sensor_problem_front' => 'Problem Schleifensensor, vorne', + 'loop_sensor_problem_rear' => 'Problem Schleifensensor, hinten', + 'trapped' => 'eingeschlossen', + 'upside_down' => 'steht auf dem Kopf', + 'low_battery' => 'niedriger Batteriestand', + 'empty_battery' => 'Batterie leer', + 'no_drive' => 'fährt nicht', + 'lifted' => 'angehoben', + 'stuck_in_charging_station' => 'eingeklemmt in Ladestation', + 'charging_station_blocked' => 'Ladestation blockiert', + 'collision_sensor_problem_rear' => 'Problem Stoßsensor hinten', + 'collision_sensor_problem_front' => 'Problem Stoßsensor vorne', + 'wheel_motor_blocked_right' => 'Radmotor rechts blockiert', + 'wheel_motor_blocked_left' => 'Radmotor links blockiert', + 'wheel_drive_problem_right' => 'Problem Antrieb, rechts', + 'wheel_drive_problem_left' => 'Problem Antrieb, links', + 'cutting_system_blocked' => 'Schneidsystem blockiert', + 'invalid_sub_device_combination' => 'fehlerhafte Verbindung', + 'settings_restored' => 'Standardeinstellungen', + 'electronic_problem' => 'elektronisches Problem', + 'charging_system_problem' => 'Problem Ladesystem', + 'tilt_sensor_problem' => 'Kippsensor Problem', + 'wheel_motor_overloaded_right' => 'rechter Radmotor überlastet', + 'wheel_motor_overloaded_left' => 'linker Radmotor überlastet', + 'charging_current_too_high' => 'Ladestrom zu hoch', + 'temporary_problem' => 'vorübergehendes Problem', + 'guide_1_not_found' => 'SK 1 nicht gefunden', + 'guide_2_not_found' => 'SK 2 nicht gefunden', + 'guide_3_not_found' => 'SK 3 nicht gefunden', + 'difficult_finding_home' => 'Problem die Ladestation zu finden', + 'guide_calibration_accomplished' => + 'Kalibrierung des Suchkabels beendet', + 'guide_calibration_failed' => + 'Kalibrierung des Suchkabels fehlgeschlagen', + 'temporary_battery_problem' => 'kurzzeitiges Batterieproblem', + 'battery_problem' => 'Batterieproblem', + 'alarm_mower_switched_off' => 'Alarm! Mäher ausgeschalten', + 'alarm_mower_stopped' => 'Alarm! Mäher gestoppt', + 'alarm_mower_lifted' => 'Alarm! Mäher angehoben', + 'alarm_mower_tilted' => 'Alarm! Mäher gekippt', + 'connection_changed' => 'Verbindung geändert', + 'connection_not_changed' => 'Verbindung nicht geändert', + 'com_board_not_available' => 'COM Board nicht verfügbar', + 'slipped' => 'rutscht', + 'out_of_operation' => 'ausser Betrieb', + 'replace_now' => 'kritischer Batteriestand, wechseln Sie jetzt', + 'low' => 'niedrig', + 'ok' => 'ok', + 'no_source' => 'ok', + 'mower_charging' => 'Mäher wurde geladen', + 'completed_cutting_autotimer' => 'Sensor Control erreicht', + 'week_timer' => 'Wochentimer erreicht', + 'countdown_timer' => 'Stoppuhr Timer', + 'undefined' => 'unklar', + 'unknown' => 'unklar', + 'status_device_unreachable' => 'Gerät ist nicht in Reichweite', + 'status_device_alive' => 'Gerät ist in Reichweite', + 'bad' => 'schlecht', + 'poor' => 'schwach', + 'good' => 'gut', + 'undefined' => 'unklar', + 'idle' => 'nichts zu tun', + 'firmware_cancel' => 'Firmwareupload unterbrochen', + 'firmware_upload' => 'Firmwareupload', + 'unsupported' => 'nicht unterstützt', + 'up_to_date' => 'auf dem neusten Stand', + 'mower' => 'Mäher', + 'watering_computer' => 'Bewässerungscomputer', + 'no_frost' => 'kein Frost', + 'open' => 'offen', + 'closed' => 'geschlossen', + 'included' => 'inbegriffen', + 'active' => 'aktiv', + 'inactive' => 'nicht aktiv' ); - - if( defined($langGermanMapp{$readingValue}) and (AttrVal('global','language','none') eq 'DE' or AttrVal($name,'readingValueLanguage','none') eq 'de') and AttrVal($name,'readingValueLanguage','none') ne 'en') { + + if ( + defined( $langGermanMapp{$readingValue} ) + and ( AttrVal( 'global', 'language', 'none' ) eq 'DE' + or AttrVal( $name, 'readingValueLanguage', 'none' ) eq 'de' ) + and AttrVal( $name, 'readingValueLanguage', 'none' ) ne 'en' + ) + { return $langGermanMapp{$readingValue}; - } else { + } + else { return $readingValue; } } -sub GardenaSmartDevice_RigRadingsValue($$) { +sub RigRadingsValue($$) { - my ($hash,$readingValue) = @_; + my ( $hash, $readingValue ) = @_; my $rigReadingValue; - - - if( $readingValue =~ /^(\d+)-(\d\d)-(\d\d)T(\d\d)/ ) { - $rigReadingValue = GardenaSmartDevice_Zulu2LocalString($readingValue); - } else { - $rigReadingValue = GardenaSmartDevice_ReadingLangGerman($hash,$readingValue); + + if ( $readingValue =~ /^(\d+)-(\d\d)-(\d\d)T(\d\d)/ ) { + $rigReadingValue = Zulu2LocalString($readingValue); + } + else { + $rigReadingValue = + ReadingLangGerman( $hash, $readingValue ); } return $rigReadingValue; } -sub GardenaSmartDevice_Zulu2LocalString($) { +sub Zulu2LocalString($) { my $t = shift; - my ($datehour,$datemin,$rest) = split(/:/,$t,3); + my ( $datehour, $datemin, $rest ) = split( /:/, $t, 3 ); + my ( $year, $month, $day, $hour, $min ) = + $datehour =~ /(\d+)-(\d\d)-(\d\d)T(\d\d)/; + my $epoch = timegm( 0, 0, $hour, $day, $month - 1, $year ); - my ($year, $month, $day, $hour,$min) = $datehour =~ /(\d+)-(\d\d)-(\d\d)T(\d\d)/; - my $epoch = timegm (0,0,$hour,$day,$month-1,$year); + my ( $lyear, $lmonth, $lday, $lhour, $isdst ) = + ( localtime($epoch) )[ 5, 4, 3, 2, -1 ]; - my ($lyear,$lmonth,$lday,$lhour,$isdst) = (localtime($epoch))[5,4,3,2,-1]; + $lyear += 1900; # year is 1900 based + $lmonth++; # month number is zero based - $lyear += 1900; # year is 1900 based - $lmonth++; # month number is zero based - - if( defined($rest) ) { - return ( sprintf("%04d-%02d-%02d %02d:%02d:%s",$lyear,$lmonth,$lday,$lhour,$datemin,substr($rest,0,2))); - } elsif( $lyear < 2000 ) { + if ( defined($rest) ) { + return ( + sprintf( + "%04d-%02d-%02d %02d:%02d:%s", + $lyear, $lmonth, $lday, + $lhour, $datemin, substr( $rest, 0, 2 ) + ) + ); + } + elsif ( $lyear < 2000 ) { return "illegal year"; - } else { - return ( sprintf("%04d-%02d-%02d %02d:%02d",$lyear,$lmonth,$lday,$lhour,substr($datemin,0,2))); + } + else { + return ( + sprintf( + "%04d-%02d-%02d %02d:%02d", + $lyear, $lmonth, $lday, $lhour, substr( $datemin, 0, 2 ) + ) + ); } } -sub GardenaSmartDevice_SetPredefinedStartPoints($@) { +sub SetPredefinedStartPoints($@) { - my ($hash,$startpoint_state,$startpoint_num,@morestartpoints) = @_; - my $name = $hash->{NAME}; + my ( $hash, $startpoint_state, $startpoint_num, @morestartpoints ) = @_; + my $name = $hash->{NAME}; my $payload; my $abilities; - - if (defined($startpoint_state) and defined($startpoint_num) ) { - if (defined($hash->{helper}{STARTINGPOINTS}) and $hash->{helper}{STARTINGPOINTS} ne '') { - # add needed parameters to saved settings config and change the value in request - my $decode_json_settings = eval{decode_json($hash->{helper}{STARTINGPOINTS})}; - if($@){ - Log3 $name, 3, "GardenaSmartBridge ($name) - JSON error while setting startpoint: $@"; - } - - $decode_json_settings->{device} = $hash->{DEVICEID}; - my $setval = $startpoint_state eq 'disable' ? \0 : \1; - $decode_json_settings->{value}[$startpoint_num-1]{enabled} = $setval; - - #set more startpoints - if (defined scalar(@morestartpoints) and (scalar(@morestartpoints) == 2 or scalar(@morestartpoints) == 4 )) { - if (scalar(@morestartpoints) == 2) { - $setval = $morestartpoints[0] eq 'disable' ? \0 : \1; - $decode_json_settings->{value}[$morestartpoints[1]-1]{enabled} = $setval; - - } elsif (scalar(@morestartpoints) == 4) { - $setval = $morestartpoints[0] eq 'disable' ? \0 : \1; - $decode_json_settings->{value}[$morestartpoints[1]-1]{enabled} = $setval; - $setval = $morestartpoints[2] eq 'disable' ? \0 : \1; - $decode_json_settings->{value}[$morestartpoints[3]-1]{enabled} = $setval; - } - } - - $payload = '"settings": '. encode_json($decode_json_settings); - $abilities = 'mower_settings'; - } else { - return "startingpoints not loaded yet, please wait a couple of minutes",undef,undef; + if ( defined($startpoint_state) and defined($startpoint_num) ) { + if ( defined( $hash->{helper}{STARTINGPOINTS} ) + and $hash->{helper}{STARTINGPOINTS} ne '' ) + { +# add needed parameters to saved settings config and change the value in request + my $decode_json_settings = + eval { decode_json( $hash->{helper}{STARTINGPOINTS} ) }; + if ($@) { + Log3 $name, 3, +"GardenaSmartBridge ($name) - JSON error while setting startpoint: $@"; } - } else { - return "startpoint usage: set ".$hash->{NAME}." startpoint disable 1 [enable 2] [disable 3]",undef,undef; + + $decode_json_settings->{device} = $hash->{DEVICEID}; + my $setval = $startpoint_state eq 'disable' ? \0 : \1; + $decode_json_settings->{value}[ $startpoint_num - 1 ]{enabled} = + $setval; + + #set more startpoints + if ( + defined scalar(@morestartpoints) + and ( scalar(@morestartpoints) == 2 + or scalar(@morestartpoints) == 4 ) + ) + { + if ( scalar(@morestartpoints) == 2 ) { + $setval = $morestartpoints[0] eq 'disable' ? \0 : \1; + $decode_json_settings->{value}[ $morestartpoints[1] - 1 ] + {enabled} = $setval; + + } + elsif ( scalar(@morestartpoints) == 4 ) { + $setval = $morestartpoints[0] eq 'disable' ? \0 : \1; + $decode_json_settings->{value}[ $morestartpoints[1] - 1 ] + {enabled} = $setval; + $setval = $morestartpoints[2] eq 'disable' ? \0 : \1; + $decode_json_settings->{value}[ $morestartpoints[3] - 1 ] + {enabled} = $setval; + } + } + + $payload = '"settings": ' . encode_json($decode_json_settings); + $abilities = 'mower_settings'; } + else { + return + "startingpoints not loaded yet, please wait a couple of minutes", + undef, undef; + } + } + else { + return + "startpoint usage: set " + . $hash->{NAME} + . " startpoint disable 1 [enable 2] [disable 3]", undef, undef; + } - return undef,$payload,$abilities; + return undef, $payload, $abilities; } - - - - - 1; =pod