rewrite parts of Bridge Modul and add Support for predefined start points
This commit is contained in:
		@@ -2,7 +2,7 @@
 | 
			
		||||
# 
 | 
			
		||||
# Developed with Kate
 | 
			
		||||
#
 | 
			
		||||
#  (c) 2017 Copyright: Marko Oldenburg (leongaultier at gmail dot com)
 | 
			
		||||
#  (c) 2017-2018 Copyright: Marko Oldenburg (leongaultier at gmail dot com)
 | 
			
		||||
#  All rights reserved
 | 
			
		||||
#
 | 
			
		||||
#   Special thanks goes to comitters:
 | 
			
		||||
@@ -68,7 +68,7 @@ eval "use JSON;1" or $missingModul .= "JSON ";
 | 
			
		||||
eval "use IO::Socket::SSL;1" or $missingModul .= "IO::Socket::SSL ";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
my $version = "0.4.1";
 | 
			
		||||
my $version = "1.0.0";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -88,9 +88,10 @@ sub GardenaSmartBridge_WriteReadings($$);
 | 
			
		||||
sub GardenaSmartBridge_ParseJSON($$);
 | 
			
		||||
sub GardenaSmartBridge_getDevices($);
 | 
			
		||||
sub GardenaSmartBridge_getToken($);
 | 
			
		||||
#sub GardenaSmartBridge_InternalTimerGetDeviceData($);
 | 
			
		||||
sub GardenaSmartBridge_createHttpValueStrings($@);
 | 
			
		||||
sub GardenaSmartBridge_Notify($$);
 | 
			
		||||
sub GardenaSmartBridge_StorePassword($$);
 | 
			
		||||
sub GardenaSmartBridge_ReadPassword($);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -117,6 +118,7 @@ sub GardenaSmartBridge_Initialize($) {
 | 
			
		||||
                          "disable:1 ".
 | 
			
		||||
                          "interval ".
 | 
			
		||||
                          "disabledForIntervals ".
 | 
			
		||||
                          "gardenaAccountEmail ".
 | 
			
		||||
                          $readingFnAttributes;
 | 
			
		||||
    
 | 
			
		||||
    foreach my $d(sort keys %{$modules{GardenaSmartBridge}{defptr}}) {
 | 
			
		||||
@@ -133,34 +135,25 @@ sub GardenaSmartBridge_Define($$) {
 | 
			
		||||
    my @a = split( "[ \t][ \t]*", $def );
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    return "too few parameters: define <NAME> GardenaSmartBridge <Email> <Passwort>" if( @a != 4 ) ;
 | 
			
		||||
    return "too few parameters: define <NAME> GardenaSmartBridge" if( @a < 2 or @a > 4 );
 | 
			
		||||
    return "Cannot define Gardena Bridge device. Perl modul ${missingModul}is missing." if ( $missingModul );
 | 
			
		||||
    
 | 
			
		||||
    my $name                = $a[0];
 | 
			
		||||
    my $user                = $a[2];
 | 
			
		||||
    my $pass                = $a[3];
 | 
			
		||||
    $hash->{BRIDGE}         = 1;
 | 
			
		||||
    $hash->{URL}            = 'https://sg-api.dss.husqvarnagroup.net/sg-1';
 | 
			
		||||
    $hash->{VERSION}        = $version;
 | 
			
		||||
    $hash->{INTERVAL}       = 300;
 | 
			
		||||
    $hash->{NOTIFYDEV}      = "global,$name";
 | 
			
		||||
 | 
			
		||||
    my $username            = GardenaSmartBridge_encrypt($user);
 | 
			
		||||
    my $password            = GardenaSmartBridge_encrypt($pass);
 | 
			
		||||
    Log3 $name, 3, "GardenaSmartBridge ($name) - encrypt $user/$pass to $username/$password" if($user ne $username || $pass ne $password);
 | 
			
		||||
    $hash->{DEF} = "$username $password";
 | 
			
		||||
 | 
			
		||||
    $hash->{helper}{username} = $username;
 | 
			
		||||
    $hash->{helper}{password} = $password;
 | 
			
		||||
    CommandAttr(undef,$name.' room GardenaSmart') if( AttrVal($name,'room','none') eq 'none' );
 | 
			
		||||
    
 | 
			
		||||
    CommandDefMod(undef,$name.' '.$hash->{TYPE}) if(@a > 2);      # fix new define
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    $attr{$name}{room} = "GardenaSmart" if( !defined( $attr{$name}{room} ) );
 | 
			
		||||
    
 | 
			
		||||
    readingsSingleUpdate($hash,'state','initialized',1);
 | 
			
		||||
    readingsSingleUpdate($hash,'token','none',1);
 | 
			
		||||
    Log3 $name, 3, "GardenaSmartBridge ($name) - defined GardenaSmartBridge and crypt your credentials";
 | 
			
		||||
    readingsSingleUpdate($hash,'state','initialized',1);
 | 
			
		||||
    
 | 
			
		||||
    Log3 $name, 3, "GardenaSmartBridge ($name) - defined GardenaSmartBridge";
 | 
			
		||||
 | 
			
		||||
    $modules{GardenaSmartBridge}{defptr}{BRIDGE} = $hash;
 | 
			
		||||
 | 
			
		||||
@@ -172,7 +165,10 @@ sub GardenaSmartBridge_Undef($$) {
 | 
			
		||||
    my ( $hash, $arg ) = @_;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd";
 | 
			
		||||
    
 | 
			
		||||
    RemoveInternalTimer($hash);
 | 
			
		||||
    setKeyValue($index,undef);
 | 
			
		||||
    delete $modules{GardenaSmartBridge}{defptr}{BRIDGE} if( defined($modules{GardenaSmartBridge}{defptr}{BRIDGE}) );
 | 
			
		||||
 | 
			
		||||
    return undef;
 | 
			
		||||
@@ -248,12 +244,14 @@ sub GardenaSmartBridge_Notify($$) {
 | 
			
		||||
                                                    and (grep /^INITIALIZED$/,@{$events}
 | 
			
		||||
                                                        or grep /^DEFINED.$name$/,@{$events}
 | 
			
		||||
                                                        or grep /^MODIFIED.$name$/,@{$events}
 | 
			
		||||
                                                        or grep /^ATTR.$name.gardenaAccountEmail.+/,@{$events}
 | 
			
		||||
                                                    )
 | 
			
		||||
                                                )
 | 
			
		||||
                                                
 | 
			
		||||
                                            or 
 | 
			
		||||
                                                ($devtype eq 'GardenaSmartBridge'
 | 
			
		||||
                                                    and ReadingsVal('$devname','token','') eq 'none')
 | 
			
		||||
                                                    and (grep /^gardenaAccountPassword.+/,@{$events}
 | 
			
		||||
                                                    or ReadingsVal('$devname','token','') eq 'none') )
 | 
			
		||||
                                            );
 | 
			
		||||
 | 
			
		||||
    GardenaSmartBridge_getDevices($hash) if ( $devtype eq 'Global'
 | 
			
		||||
@@ -276,49 +274,36 @@ sub GardenaSmartBridge_Notify($$) {
 | 
			
		||||
sub GardenaSmartBridge_Set($@) {
 | 
			
		||||
    
 | 
			
		||||
    my ($hash, $name, $cmd, @args) = @_;
 | 
			
		||||
    my ($arg, @params) = @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 <password>" if( @args != 1 );
 | 
			
		||||
        
 | 
			
		||||
        my $passwd = join(' ',@args);
 | 
			
		||||
        GardenaSmartBridge_StorePassword($hash,$passwd);
 | 
			
		||||
    
 | 
			
		||||
    } else {
 | 
			
		||||
    
 | 
			
		||||
        my $list = "getDevicesState:noArg getToken:noArg";
 | 
			
		||||
        my $list    = "getDevicesState:noArg getToken:noArg" if( defined(GardenaSmartBridge_ReadPassword($hash)) );
 | 
			
		||||
        $list       .= " gardenaAccountPassword" if( not defined(GardenaSmartBridge_ReadPassword($hash)) );
 | 
			
		||||
        return "Unknown argument $cmd, choose one of $list";
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return undef;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# sub GardenaSmartBridge_InternalTimerGetDeviceData($) {
 | 
			
		||||
# 
 | 
			
		||||
#     my $hash    = shift;
 | 
			
		||||
#     my $name    = $hash->{NAME};
 | 
			
		||||
#     
 | 
			
		||||
#     
 | 
			
		||||
#     #RemoveInternalTimer($hash);
 | 
			
		||||
#     
 | 
			
		||||
#     if( not IsDisabled($name) ) {
 | 
			
		||||
#     
 | 
			
		||||
#         GardenaSmartBridge_getDevices($hash);
 | 
			
		||||
#         Log3 $name, 4, "GardenaSmartBridge ($name) - set internal timer function for recall InternalTimerGetDeviceData sub";
 | 
			
		||||
#         
 | 
			
		||||
#     } else {
 | 
			
		||||
#     
 | 
			
		||||
#         readingsSingleUpdate($hash,'state','disabled',1);
 | 
			
		||||
#         Log3 $name, 3, "GardenaSmartBridge ($name) - device is disabled";
 | 
			
		||||
#     }
 | 
			
		||||
#     
 | 
			
		||||
#     InternalTimer( gettimeofday()+$hash->{INTERVAL},"GardenaSmartBridge_InternalTimerGetDeviceData", $hash);
 | 
			
		||||
# }
 | 
			
		||||
 | 
			
		||||
sub GardenaSmartBridge_Write($@) {
 | 
			
		||||
 | 
			
		||||
    my ($hash,$payload,$deviceId,$abilities)  = @_;
 | 
			
		||||
@@ -396,7 +381,7 @@ sub GardenaSmartBridge_ErrorHandling($$$) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if( $data eq "" and exists( $param->{code} ) && $param->{code} != 200 ) {
 | 
			
		||||
    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" );
 | 
			
		||||
@@ -528,7 +513,7 @@ sub GardenaSmartBridge_ResponseProcessing($$) {
 | 
			
		||||
            GardenaSmartBridge_WriteReadings($hash,$location);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        Log3 $name, 3, "GardenaSmartBridge ($name) - processed locations id. ID ist " . $hash->{helper}{locations_id};
 | 
			
		||||
        Log3 $name, 3, "GardenaSmartBridge ($name) - processed locations id. ID is " . $hash->{helper}{locations_id};
 | 
			
		||||
        GardenaSmartBridge_Write($hash,undef,undef,undef);
 | 
			
		||||
        
 | 
			
		||||
        return;
 | 
			
		||||
@@ -605,6 +590,8 @@ sub GardenaSmartBridge_getDevices($) {
 | 
			
		||||
    my $name    = $hash->{NAME};
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    RemoveInternalTimer($hash);
 | 
			
		||||
    
 | 
			
		||||
    if( not IsDisabled($name) ) {
 | 
			
		||||
 | 
			
		||||
        GardenaSmartBridge_Write($hash,undef,undef,undef);
 | 
			
		||||
@@ -621,51 +608,90 @@ sub GardenaSmartBridge_getToken($) {
 | 
			
		||||
    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(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} );
 | 
			
		||||
        
 | 
			
		||||
    GardenaSmartBridge_Write($hash,'"sessions": {"email": "'.GardenaSmartBridge_decrypt($hash->{helper}{username}).'","password": "'.GardenaSmartBridge_decrypt($hash->{helper}{password}).'"}',undef,undef);
 | 
			
		||||
    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";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub GardenaSmartBridge_encrypt($) {
 | 
			
		||||
sub GardenaSmartBridge_StorePassword($$) {
 | 
			
		||||
    
 | 
			
		||||
    my ($decoded) = @_;
 | 
			
		||||
    my $key = getUniqueId();
 | 
			
		||||
    my $encoded;
 | 
			
		||||
    my ($hash, $password) = @_;
 | 
			
		||||
    my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd";
 | 
			
		||||
    my $key = getUniqueId().$index;
 | 
			
		||||
    my $enc_pwd = "";
 | 
			
		||||
 | 
			
		||||
    return $decoded if( $decoded =~ /crypt:/ );
 | 
			
		||||
    
 | 
			
		||||
    for my $char (split //, $decoded) {
 | 
			
		||||
        my $encode = chop($key);
 | 
			
		||||
        $encoded .= sprintf("%.2x",ord($char)^ord($encode));
 | 
			
		||||
        $key = $encode.$key;
 | 
			
		||||
    if(eval "use Digest::MD5;1") {
 | 
			
		||||
    
 | 
			
		||||
        $key = Digest::MD5::md5_hex(unpack "H*", $key);
 | 
			
		||||
        $key .= Digest::MD5::md5_hex($key);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return 'crypt:'.$encoded;
 | 
			
		||||
    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));
 | 
			
		||||
 | 
			
		||||
    return "password successfully saved";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub GardenaSmartBridge_decrypt($) {
 | 
			
		||||
sub GardenaSmartBridge_ReadPassword($) {
 | 
			
		||||
    
 | 
			
		||||
    my ($encoded) = @_;
 | 
			
		||||
    my $key = getUniqueId();
 | 
			
		||||
    my $decoded;
 | 
			
		||||
    my ($hash) = @_;
 | 
			
		||||
    my $name = $hash->{NAME};
 | 
			
		||||
    my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd";
 | 
			
		||||
    my $key = getUniqueId().$index;
 | 
			
		||||
    my ($password, $err);
 | 
			
		||||
 | 
			
		||||
    return $encoded if( $encoded !~ /crypt:/ );
 | 
			
		||||
    
 | 
			
		||||
    $encoded = $1 if( $encoded =~ /crypt:(.*)/ );
 | 
			
		||||
    Log3 $name, 4, "GardenaSmartBridge ($name) - Read password from file";
 | 
			
		||||
    
 | 
			
		||||
    ($err, $password) = getKeyValue($index);
 | 
			
		||||
 | 
			
		||||
    if ( defined($err) ) {
 | 
			
		||||
    
 | 
			
		||||
        Log3 $name, 3, "GardenaSmartBridge ($name) - unable to read password from file: $err";
 | 
			
		||||
        return undef;
 | 
			
		||||
        
 | 
			
		||||
    for my $char (map { pack('C', hex($_)) } ($encoded =~ /(..)/g)) {
 | 
			
		||||
        my $decode = chop($key);
 | 
			
		||||
        $decoded .= chr(ord($char)^ord($decode));
 | 
			
		||||
        $key = $decode.$key;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return $decoded;
 | 
			
		||||
    if ( defined($password) ) {
 | 
			
		||||
        if ( eval "use Digest::MD5;1" ) {
 | 
			
		||||
        
 | 
			
		||||
            $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;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return $dec_pwd;
 | 
			
		||||
        
 | 
			
		||||
    } else {
 | 
			
		||||
    
 | 
			
		||||
        Log3 $name, 3, "GardenaSmartBridge ($name) - No password in file";
 | 
			
		||||
        return undef;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub GardenaSmartBridge_ParseJSON($$) {
 | 
			
		||||
@@ -681,11 +707,11 @@ sub GardenaSmartBridge_ParseJSON($$) {
 | 
			
		||||
    
 | 
			
		||||
    if($buffer) {
 | 
			
		||||
        foreach my $c (split //, $buffer) {
 | 
			
		||||
            if($open == $close && $open > 0) {
 | 
			
		||||
            if($open == $close and $open > 0) {
 | 
			
		||||
                $tail .= $c;
 | 
			
		||||
                Log3 $name, 5, "GardenaSmartBridge ($name) - $open == $close && $open > 0";
 | 
			
		||||
                Log3 $name, 5, "GardenaSmartBridge ($name) - $open == $close and $open > 0";
 | 
			
		||||
                
 | 
			
		||||
            } elsif(($open == $close) && ($c ne '{')) {
 | 
			
		||||
            } elsif(($open == $close) and ($c ne '{')) {
 | 
			
		||||
            
 | 
			
		||||
                Log3 $name, 5, "GardenaSmartBridge ($name) - Garbage character before message: " . $c;
 | 
			
		||||
        
 | 
			
		||||
@@ -738,7 +764,16 @@ sub GardenaSmartBridge_createHttpValueStrings($@) {
 | 
			
		||||
    $uri                            .= '/sessions'                                                          if( not defined($hash->{helper}{session_id}));
 | 
			
		||||
    
 | 
			
		||||
    if( defined($hash->{helper}{locations_id}) ) {
 | 
			
		||||
        $uri                            .= '/devices/' . $deviceId . '/abilities/' . $abilities . '/command'    if( defined($abilities) and defined($payload) );
 | 
			
		||||
        #$uri                            .= '/devices/' . $deviceId . '/abilities/' . $abilities . '/command'    if( defined($abilities) and defined($payload) );
 | 
			
		||||
        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');      
 | 
			
		||||
        } else {
 | 
			
		||||
            $uri                            .= '/devices/' . $deviceId . '/abilities/' . $abilities . '/command'    if( defined($abilities) and defined($payload) and $abilities ne 'mower_settings');        
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $uri                            .= '?locationId=' . $hash->{helper}{locations_id};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,12 +2,13 @@
 | 
			
		||||
# 
 | 
			
		||||
# Developed with Kate
 | 
			
		||||
#
 | 
			
		||||
#  (c) 2017 Copyright: Marko Oldenburg (leongaultier at gmail dot com)
 | 
			
		||||
#  (c) 2017-2018 Copyright: Marko Oldenburg (leongaultier at gmail dot com)
 | 
			
		||||
#  All rights reserved
 | 
			
		||||
#
 | 
			
		||||
#   Special thanks goes to comitters:
 | 
			
		||||
#       - Michael (mbrak)       Thanks for Commandref
 | 
			
		||||
#       - Matthias (Kenneth)    Thanks for Wiki entry
 | 
			
		||||
#       - BioS                  Thanks for predefined start points Code
 | 
			
		||||
#
 | 
			
		||||
#
 | 
			
		||||
#  This script is free software; you can redistribute it and/or modify
 | 
			
		||||
@@ -65,7 +66,7 @@ use Time::Local;
 | 
			
		||||
eval "use JSON;1" or $missingModul .= "JSON ";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
my $version = "0.4.1";
 | 
			
		||||
my $version = "1.0.0";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -81,6 +82,7 @@ sub GardenaSmartDevice_Parse($$);
 | 
			
		||||
sub GardenaSmartDevice_ReadingLangGerman($$);
 | 
			
		||||
sub GardenaSmartDevice_RigRadingsValue($$);
 | 
			
		||||
sub GardenaSmartDevice_Zulu2LocalString($);
 | 
			
		||||
sub GardenaSmartDevice_SetPredefinedStartPoints($@);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -111,25 +113,26 @@ sub GardenaSmartDevice_Initialize($) {
 | 
			
		||||
 | 
			
		||||
sub GardenaSmartDevice_Define($$) {
 | 
			
		||||
 | 
			
		||||
    my ( $hash, $def ) = @_;
 | 
			
		||||
    my @a = split( "[ \t]+", $def );
 | 
			
		||||
    my ( $hash, $def )                  = @_;
 | 
			
		||||
    my @a                               = split( "[ \t]+", $def );
 | 
			
		||||
 | 
			
		||||
    return "too few parameters: define <NAME> GardenaSmartDevice <device_Id> <model>" 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];
 | 
			
		||||
    my $name                            = $a[0];
 | 
			
		||||
    my $deviceId                        = $a[2];
 | 
			
		||||
    my $category                        = $a[3];
 | 
			
		||||
    
 | 
			
		||||
    $hash->{DEVICEID}   = $deviceId;
 | 
			
		||||
    $hash->{VERSION}    = $version;
 | 
			
		||||
    $hash->{DEVICEID}                   = $deviceId;
 | 
			
		||||
    $hash->{VERSION}                    = $version;
 | 
			
		||||
    $hash->{helper}{STARTINGPOINTID}    = '';
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    CommandAttr(undef,"$name IODev $modules{GardenaSmartBridge}{defptr}{BRIDGE}->{NAME}") if(AttrVal($name,'IODev','none') eq 'none');
 | 
			
		||||
 | 
			
		||||
    my $iodev           = AttrVal($name,'IODev','none');
 | 
			
		||||
    my $iodev                           = AttrVal($name,'IODev','none');
 | 
			
		||||
    
 | 
			
		||||
    AssignIoPort($hash,$iodev) if( !$hash->{IODev} );
 | 
			
		||||
    
 | 
			
		||||
@@ -144,11 +147,13 @@ sub GardenaSmartDevice_Define($$) {
 | 
			
		||||
    my $d = $modules{GardenaSmartDevice}{defptr}{$deviceId};
 | 
			
		||||
    
 | 
			
		||||
    return "GardenaSmartDevice device $name on GardenaSmartBridge $iodev already defined."
 | 
			
		||||
    if( defined($d) && $d->{IODev} == $hash->{IODev} && $d->{NAME} ne $name );
 | 
			
		||||
    if( defined($d) and $d->{IODev} == $hash->{IODev} and $d->{NAME} ne $name );
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    $attr{$name}{room}          = "GardenaSmart"    if( not defined( $attr{$name}{room} ) );
 | 
			
		||||
    $attr{$name}{model}         = $category         if( not defined( $attr{$name}{model} ) );
 | 
			
		||||
    #$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);
 | 
			
		||||
@@ -182,7 +187,7 @@ sub GardenaSmartDevice_Attr(@) {
 | 
			
		||||
sub GardenaSmartDevice_Set($@) {
 | 
			
		||||
    
 | 
			
		||||
    my ($hash, $name, $cmd, @args) = @_;
 | 
			
		||||
    my ($arg, @params) = @args;
 | 
			
		||||
    #my ($arg, @params) = @args;
 | 
			
		||||
    
 | 
			
		||||
    my $payload;
 | 
			
		||||
    my $abilities;
 | 
			
		||||
@@ -206,6 +211,12 @@ sub GardenaSmartDevice_Set($@) {
 | 
			
		||||
        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' ) {
 | 
			
		||||
    
 | 
			
		||||
@@ -233,32 +244,17 @@ sub GardenaSmartDevice_Set($@) {
 | 
			
		||||
            $abilities  = 'humidity';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    } elsif( lc $cmd eq '' ) {
 | 
			
		||||
    
 | 
			
		||||
    } elsif( lc $cmd eq '' ) {
 | 
			
		||||
    
 | 
			
		||||
    } elsif( lc $cmd eq '' ) {
 | 
			
		||||
    
 | 
			
		||||
    } elsif( lc $cmd eq '' ) {
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    } elsif( lc $cmd eq '' ) {
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    } elsif( lc $cmd eq '' ) {
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    } else {
 | 
			
		||||
    
 | 
			
		||||
        my $list    = '';
 | 
			
		||||
        $list       .= 'parkUntilFurtherNotice:noArg parkUntilNextTimer:noArg startResumeSchedule:noArg startOverrideTimer:slider,0,60,1440' if( AttrVal($name,'model','unknown') eq 'mower' );
 | 
			
		||||
        $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       .= 'refresh:temperature,light' if( AttrVal($name,'model','unknown') eq 'sensor' );
 | 
			
		||||
        
 | 
			
		||||
        return "Unknown argument $cmd, choose one of $list";
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    $abilities  = 'mower' if( AttrVal($name,'model','unknown') eq 'mower' );
 | 
			
		||||
    $abilities  = 'mower' if( AttrVal($name,'model','unknown') eq 'mower' ) and $abilities ne 'mower_settings';
 | 
			
		||||
    $abilities  = 'outlet' if( AttrVal($name,'model','unknown') eq 'watering_computer' );
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
@@ -310,10 +306,11 @@ sub GardenaSmartDevice_Parse($$) {
 | 
			
		||||
 | 
			
		||||
sub GardenaSmartDevice_WriteReadings($$) {
 | 
			
		||||
 | 
			
		||||
    my ($hash,$decode_json)     = @_;
 | 
			
		||||
    my ($hash,$decode_json) = @_;
 | 
			
		||||
    
 | 
			
		||||
    my $name                    = $hash->{NAME};
 | 
			
		||||
    my $abilities               = scalar (@{$decode_json->{abilities}});
 | 
			
		||||
    my $name                = $hash->{NAME};
 | 
			
		||||
    my $abilities           = scalar (@{$decode_json->{abilities}});
 | 
			
		||||
    my $settings            = scalar (@{$decode_json->{settings}});
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    readingsBeginUpdate($hash);
 | 
			
		||||
@@ -346,6 +343,27 @@ sub GardenaSmartDevice_WriteReadings($$) {
 | 
			
		||||
    } while ($abilities >= 0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        
 | 
			
		||||
        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};
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            $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}}) {
 | 
			
		||||
                $startpoint_cnt++;
 | 
			
		||||
                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' );
 | 
			
		||||
    
 | 
			
		||||
@@ -509,6 +527,52 @@ sub GardenaSmartDevice_Zulu2LocalString($) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub GardenaSmartDevice_SetPredefinedStartPoints($@) {
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            return "startpoint usage: set ".$hash->{NAME}." startpoint disable 1 [enable 2] [disable 3]",undef,undef;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    return undef,$payload,$abilities;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -654,8 +718,13 @@ sub GardenaSmartDevice_Zulu2LocalString($) {
 | 
			
		||||
    <ul>
 | 
			
		||||
        <li>parkUntilFurtherNotice</li>
 | 
			
		||||
        <li>parkUntilNextTimer</li>
 | 
			
		||||
        <li>startOverrideTimer - 0 to 59 Minutes</li>
 | 
			
		||||
        <li>startOverrideTimer - (in minutes, 60 = 1h, 1440 = 24h, 4320 = 72h)</li>
 | 
			
		||||
        <li>startResumeSchedule</li>
 | 
			
		||||
        <li>startpoint enable|disable 1|2|3 - enables or disables one or more predefined start points</li>
 | 
			
		||||
        <ul>
 | 
			
		||||
            <li>set NAME startpoint enable 1</li>
 | 
			
		||||
            <li>set NAME startpoint disable 3 enable 1</li>
 | 
			
		||||
        </ul>
 | 
			
		||||
    </ul>
 | 
			
		||||
</ul>
 | 
			
		||||
 | 
			
		||||
@@ -793,8 +862,13 @@ sub GardenaSmartDevice_Zulu2LocalString($) {
 | 
			
		||||
    <ul>
 | 
			
		||||
        <li>parkUntilFurtherNotice - Parken des Mähers unter Umgehung des Zeitplans</li>
 | 
			
		||||
        <li>parkUntilNextTimer - Parken bis zum nächsten Zeitplan</li>
 | 
			
		||||
        <li>startOverrideTimer - Manuelles mähen (0 bis 59 Minuten)</li>
 | 
			
		||||
        <li>startOverrideTimer - Manuelles mähen (in Minuten, 60 = 1h, 1440 = 24h, 4320 = 72h)</li>
 | 
			
		||||
        <li>startResumeSchedule - Weiterführung des Zeitplans</li>
 | 
			
		||||
        <li>startpoint enable|disable 1|2|3 - Aktiviert oder deaktiviert einen vordefinierten Startbereich</li>
 | 
			
		||||
        <ul>
 | 
			
		||||
            <li>set NAME startpoint enable 1</li>
 | 
			
		||||
            <li>set NAME startpoint disable 3 enable 1</li>
 | 
			
		||||
        </ul>
 | 
			
		||||
    </ul>
 | 
			
		||||
</ul>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user