2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-10 09:16:53 +00:00

GardenaSmart: all modules change to new API and code PBP conform

git-svn-id: https://svn.fhem.de/fhem/trunk@21791 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
LeonGaultier 2020-04-28 09:19:20 +00:00
parent b16f95a60d
commit 36f5c6cc04
3 changed files with 320 additions and 329 deletions

View File

@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # 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. # Do not insert empty lines here, update check depends on it.
- bugfix: GardenaSmart: all modules change to new API and code PBP conform
- feature: 37_echodevice.pm A1WAR447VT003J Yamaha MusicCast 20 - feature: 37_echodevice.pm A1WAR447VT003J Yamaha MusicCast 20
CHANGE: get status CHANGE: get status
- feature: 10_SOMFY: new attr autoStoreRollingCode - store rc in uniqueID - feature: 10_SOMFY: new attr autoStoreRollingCode - store rc in uniqueID

View File

@ -54,22 +54,23 @@
## ##
package FHEM::GardenaSmartBridge; package FHEM::GardenaSmartBridge;
use GPUtils qw(GP_Import) use GPUtils qw(GP_Import GP_Export);
; # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt
# use Data::Dumper; #only for Debugging
use strict; use strict;
use warnings; use warnings;
use POSIX; use POSIX;
use FHEM::Meta; use FHEM::Meta;
use Data::Dumper;
use HttpUtils; use HttpUtils;
our $VERSION = '1.6.9';
my $missingModul = ''; my $missingModul = '';
eval "use Encode qw(encode encode_utf8 decode_utf8);1" eval "use Encode qw(encode encode_utf8 decode_utf8);1"
or $missingModul .= "Encode "; or $missingModul .= "Encode ";
# eval "use JSON;1" or $missingModul .= 'JSON '; # eval "use JSON;1" || $missingModul .= 'JSON ';
eval "use IO::Socket::SSL;1" or $missingModul .= 'IO::Socket::SSL '; eval "use IO::Socket::SSL;1" or $missingModul .= 'IO::Socket::SSL ';
# try to use JSON::MaybeXS wrapper # try to use JSON::MaybeXS wrapper
@ -176,42 +177,30 @@ BEGIN {
); );
} }
# _Export - Export references to main context using a different naming schema
sub _Export {
no strict qw/refs/; ## no critic
my $pkg = caller(0);
my $main = $pkg;
$main =~ s/^(?:.+::)?([^:]+)$/main::$1\_/g;
foreach (@_) {
*{ $main . $_ } = *{ $pkg . '::' . $_ };
}
}
#-- Export to main context with different name #-- Export to main context with different name
_Export( GP_Export(
qw( qw(
Initialize Initialize
) )
); );
sub Initialize($) { sub Initialize {
my $hash = shift;
my ($hash) = @_;
# Provider # Provider
$hash->{WriteFn} = 'FHEM::GardenaSmartBridge::Write'; $hash->{WriteFn} = \&Write;
$hash->{Clients} = ':GardenaSmartDevice:'; $hash->{Clients} = ':GardenaSmartDevice:';
$hash->{MatchList} = { '1:GardenaSmartDevice' => '^{"id":".*' }; $hash->{MatchList} = { '1:GardenaSmartDevice' => '^{"id":".*' };
# Consumer # Consumer
$hash->{SetFn} = 'FHEM::GardenaSmartBridge::Set'; $hash->{SetFn} = \&Set;
$hash->{DefFn} = 'FHEM::GardenaSmartBridge::Define'; $hash->{DefFn} = \&Define;
$hash->{UndefFn} = 'FHEM::GardenaSmartBridge::Undef'; $hash->{UndefFn} = \&Undef;
$hash->{DeleteFn} = 'FHEM::GardenaSmartBridge::Delete'; $hash->{DeleteFn} = \&Delete;
$hash->{RenameFn} = 'FHEM::GardenaSmartBridge::Rename'; $hash->{RenameFn} = \&Rename;
$hash->{NotifyFn} = 'FHEM::GardenaSmartBridge::Notify'; $hash->{NotifyFn} = \&Notify;
$hash->{AttrFn} = 'FHEM::GardenaSmartBridge::Attr'; $hash->{AttrFn} = \&Attr;
$hash->{AttrList} = $hash->{AttrList} =
'debugJSON:0,1 ' 'debugJSON:0,1 '
. 'disable:1 ' . 'disable:1 '
@ -220,38 +209,33 @@ sub Initialize($) {
. 'gardenaAccountEmail ' . 'gardenaAccountEmail '
. 'gardenaBaseURL ' . 'gardenaBaseURL '
. $readingFnAttributes; . $readingFnAttributes;
$hash->{parseParams} = 1;
foreach my $d ( sort keys %{ $modules{GardenaSmartBridge}{defptr} } ) {
my $hash = $modules{GardenaSmartBridge}{defptr}{$d};
$hash->{VERSION} = $VERSION;
}
return FHEM::Meta::InitMod( __FILE__, $hash ); return FHEM::Meta::InitMod( __FILE__, $hash );
} }
sub Define($$) { sub Define {
my $hash = shift;
my ( $hash, $def ) = @_; my $a = shift;
my @a = split( '[ \t][ \t]*', $def );
return $@ unless ( FHEM::Meta::SetInternals($hash) ); return $@ unless ( FHEM::Meta::SetInternals($hash) );
use version 0.60; our $VERSION = FHEM::Meta::Get( $hash, 'version' );
return 'too few parameters: define <NAME> GardenaSmartBridge' return 'too few parameters: define <NAME> GardenaSmartBridge'
if ( @a != 2 ); if ( scalar( @{$a} ) != 2 );
return return
'Cannot define Gardena Bridge device. Perl modul ' 'Cannot define Gardena Bridge device. Perl modul '
. ${missingModul} . ${missingModul}
. ' is missing.' . ' is missing.'
if ($missingModul); if ($missingModul);
my $name = $a[0]; my $name = shift @$a;
$hash->{BRIDGE} = 1; $hash->{BRIDGE} = 1;
$hash->{URL} = $hash->{URL} =
AttrVal( $name, 'gardenaBaseURL', AttrVal( $name, 'gardenaBaseURL',
'https://sg-api.dss.husqvarnagroup.net' ) 'https://sg-api.dss.husqvarnagroup.net' )
. '/sg-1'; . '/sg-1';
$hash->{VERSION} = $VERSION; $hash->{VERSION} = version->parse($VERSION)->normal;
$hash->{INTERVAL} = 60; $hash->{INTERVAL} = 60;
$hash->{NOTIFYDEV} = "global,$name"; $hash->{NOTIFYDEV} = "global,$name";
@ -265,35 +249,34 @@ sub Define($$) {
$modules{GardenaSmartBridge}{defptr}{BRIDGE} = $hash; $modules{GardenaSmartBridge}{defptr}{BRIDGE} = $hash;
return undef; return;
} }
sub Undef($$) { sub Undef {
my $hash = shift;
my ( $hash, $name ) = @_; my $name = shift;
RemoveInternalTimer($hash); RemoveInternalTimer($hash);
delete $modules{GardenaSmartBridge}{defptr}{BRIDGE} delete $modules{GardenaSmartBridge}{defptr}{BRIDGE}
if ( defined( $modules{GardenaSmartBridge}{defptr}{BRIDGE} ) ); if ( defined( $modules{GardenaSmartBridge}{defptr}{BRIDGE} ) );
return undef; return;
} }
sub Delete($$) { sub Delete {
my $hash = shift;
my ( $hash, $name ) = @_; my $name = shift;
setKeyValue( $hash->{TYPE} . '_' . $name . '_passwd', undef ); setKeyValue( $hash->{TYPE} . '_' . $name . '_passwd', undef );
return undef; return;
} }
sub Attr(@) { sub Attr {
my ( $cmd, $name, $attrName, $attrVal ) = @_; my ( $cmd, $name, $attrName, $attrVal ) = @_;
my $hash = $defs{$name}; my $hash = $defs{$name};
if ( $attrName eq 'disable' ) { if ( $attrName eq 'disable' ) {
if ( $cmd eq 'set' and $attrVal eq '1' ) { if ( $cmd eq 'set' && $attrVal eq '1' ) {
RemoveInternalTimer($hash); RemoveInternalTimer($hash);
readingsSingleUpdate( $hash, 'state', 'inactive', 1 ); readingsSingleUpdate( $hash, 'state', 'inactive', 1 );
Log3 $name, 3, "GardenaSmartBridge ($name) - disabled"; Log3 $name, 3, "GardenaSmartBridge ($name) - disabled";
@ -307,7 +290,7 @@ sub Attr(@) {
if ( $cmd eq 'set' ) { if ( $cmd eq 'set' ) {
return return
"check disabledForIntervals Syntax HH:MM-HH:MM or 'HH:MM-HH:MM HH:MM-HH:MM ...'" "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?)+$/ ); if ( $attrVal !~ /^((\d{2}:\d{2})-(\d{2}:\d{2})\s?)+$/ );
Log3 $name, 3, "GardenaSmartBridge ($name) - disabledForIntervals"; Log3 $name, 3, "GardenaSmartBridge ($name) - disabledForIntervals";
} }
elsif ( $cmd eq 'del' ) { elsif ( $cmd eq 'del' ) {
@ -319,7 +302,7 @@ sub Attr(@) {
if ( $cmd eq 'set' ) { if ( $cmd eq 'set' ) {
RemoveInternalTimer($hash); RemoveInternalTimer($hash);
return 'Interval must be greater than 0' return 'Interval must be greater than 0'
unless ( $attrVal > 0 ); if ( $attrVal == 0 );
$hash->{INTERVAL} = $attrVal; $hash->{INTERVAL} = $attrVal;
Log3 $name, 3, Log3 $name, 3,
"GardenaSmartBridge ($name) - set interval: $attrVal"; "GardenaSmartBridge ($name) - set interval: $attrVal";
@ -342,12 +325,13 @@ sub Attr(@) {
} }
} }
return undef; return;
} }
sub Notify($$) { sub Notify {
my $hash = shift;
my $dev = shift;
my ( $hash, $dev ) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
return if ( IsDisabled($name) ); return if ( IsDisabled($name) );
@ -360,7 +344,7 @@ sub Notify($$) {
if ( if (
( (
$devtype eq 'Global' $devtype eq 'Global'
and ( && (
grep /^INITIALIZED$/, grep /^INITIALIZED$/,
@{$events} or grep /^REREADCFG$/, @{$events} or grep /^REREADCFG$/,
@{$events} or grep /^DEFINED.$name$/, @{$events} or grep /^DEFINED.$name$/,
@ -370,11 +354,11 @@ sub Notify($$) {
) )
) )
or ( || (
$devtype eq 'GardenaSmartBridge' $devtype eq 'GardenaSmartBridge'
and ( && (
grep /^gardenaAccountPassword.+/, grep /^gardenaAccountPassword.+/,
@{$events} or ReadingsVal( '$devname', 'token', '' ) eq 'none' @{$events} || ReadingsVal( '$devname', 'token', '' ) eq 'none'
) )
) )
); );
@ -382,19 +366,19 @@ sub Notify($$) {
getDevices($hash) getDevices($hash)
if ( if (
$devtype eq 'Global' $devtype eq 'Global'
and ( && (
grep /^DELETEATTR.$name.disable$/, grep /^DELETEATTR.$name.disable$/,
@{$events} or grep /^ATTR.$name.disable.0$/, @{$events} or grep /^ATTR.$name.disable.0$/,
@{$events} or grep /^DELETEATTR.$name.interval$/, @{$events} or grep /^DELETEATTR.$name.interval$/,
@{$events} or grep /^ATTR.$name.interval.[0-9]+/, @{$events} or grep /^ATTR.$name.interval.[0-9]+/,
@{$events} @{$events}
) )
and $init_done && $init_done
); );
if ( if (
$devtype eq 'GardenaSmartBridge' $devtype eq 'GardenaSmartBridge'
and ( && (
grep /^state:.Connected$/, grep /^state:.Connected$/,
@{$events} or grep /^lastRequestState:.request_error$/, @{$events} or grep /^lastRequestState:.request_error$/,
@{$events} @{$events}
@ -411,9 +395,12 @@ sub Notify($$) {
return; return;
} }
sub Set($@) { sub Set {
my $hash = shift;
my $a = shift;
my ( $hash, $name, $cmd, @args ) = @_; my $name = shift @$a;
my $cmd = shift @$a // return qq{"set $name" needs at least one argument};
if ( lc $cmd eq 'getdevicesstate' ) { if ( lc $cmd eq 'getdevicesstate' ) {
getDevices($hash); getDevices($hash);
@ -423,44 +410,39 @@ sub Set($@) {
return "please set Attribut gardenaAccountEmail first" return "please set Attribut gardenaAccountEmail first"
if ( AttrVal( $name, 'gardenaAccountEmail', 'none' ) eq 'none' ); if ( AttrVal( $name, 'gardenaAccountEmail', 'none' ) eq 'none' );
return "please set gardenaAccountPassword first" return "please set gardenaAccountPassword first"
if ( not defined( ReadPassword($hash,$name) ) ); if ( not defined( ReadPassword( $hash, $name ) ) );
return "token is up to date" return "token is up to date"
if ( defined( $hash->{helper}{session_id} ) ); if ( defined( $hash->{helper}{session_id} ) );
getToken($hash); getToken($hash);
} }
elsif ( lc $cmd eq 'gardenaaccountpassword' ) { elsif ( lc $cmd eq 'gardenaaccountpassword' ) {
return "please set Attribut gardenaAccountEmail first" return "please set Attribut gardenaAccountEmail first"
if ( AttrVal( $name, 'gardenaAccountEmail', 'none' ) eq 'none' ); if ( AttrVal( $name, 'gardenaAccountEmail', 'none' ) eq 'none' );
return "usage: $cmd <password>" if ( @args != 1 ); return "usage: $cmd <password>" if ( scalar( @{$a} ) != 0 );
my $passwd = join( ' ', @args );
StorePassword( $hash, $name, $passwd );
StorePassword( $hash, $name, $a->[0] );
} }
elsif ( lc $cmd eq 'deleteaccountpassword' ) { elsif ( lc $cmd eq 'deleteaccountpassword' ) {
return "usage: $cmd <password>" if ( @args != 0 ); return "usage: $cmd <password>" if ( scalar( @{$a} ) != 0 );
DeletePassword($hash); DeletePassword($hash);
} }
else { else {
my $list = "getDevicesState:noArg getToken:noArg" my $list = "getDevicesState:noArg getToken:noArg"
if ( defined( ReadPassword($hash,$name) ) ); if ( defined( ReadPassword( $hash, $name ) ) );
$list .= " gardenaAccountPassword" $list .= " gardenaAccountPassword"
if ( not defined( ReadPassword($hash,$name) ) ); if ( not defined( ReadPassword( $hash, $name ) ) );
$list .= " deleteAccountPassword:noArg" $list .= " deleteAccountPassword:noArg"
if ( defined( ReadPassword($hash,$name) ) ); if ( defined( ReadPassword( $hash, $name ) ) );
return "Unknown argument $cmd, choose one of $list"; return "Unknown argument $cmd, choose one of $list";
} }
return undef; return;
} }
sub Write($@) { sub Write {
my ( $hash, $payload, $deviceId, $abilities ) = @_; my ( $hash, $payload, $deviceId, $abilities ) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
@ -489,18 +471,21 @@ sub Write($@) {
# Log3($name, 3, # Log3($name, 3,
# "GardenaSmartBridge ($name) - Send with URL: $hash->{URL}$uri, HEADER: $header, DATA: $payload, METHOD: $method"); # "GardenaSmartBridge ($name) - Send with URL: $hash->{URL}$uri, HEADER: $header, DATA: $payload, METHOD: $method");
return;
} }
sub ErrorHandling($$$) { sub ErrorHandling {
my $param = shift;
my ( $param, $err, $data ) = @_; my $err = shift;
my $data = shift;
my $hash = $param->{hash}; my $hash = $param->{hash};
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $dhash = $hash; my $dhash = $hash;
$dhash = $modules{GardenaSmartDevice}{defptr}{ $param->{'device_id'} } $dhash = $modules{GardenaSmartDevice}{defptr}{ $param->{'device_id'} }
unless ( not defined( $param->{'device_id'} ) ); if ( defined( $param->{'device_id'} ) );
my $dname = $dhash->{NAME}; my $dname = $dhash->{NAME};
@ -526,7 +511,7 @@ sub ErrorHandling($$$) {
} }
elsif ($err =~ /Keine Route zum Zielrechner/ elsif ($err =~ /Keine Route zum Zielrechner/
or $err =~ /no route to target/ ) || $err =~ /no route to target/ )
{ {
Log3 $dname, 5, Log3 $dname, 5,
@ -551,7 +536,7 @@ sub ErrorHandling($$$) {
} }
} }
if ( $data eq "" and exists( $param->{code} ) and $param->{code} != 200 ) { if ( $data eq "" && exists( $param->{code} ) && $param->{code} != 200 ) {
readingsBeginUpdate($dhash); readingsBeginUpdate($dhash);
readingsBulkUpdate( $dhash, "state", $param->{code}, 1 ) readingsBulkUpdate( $dhash, "state", $param->{code}, 1 )
@ -560,7 +545,7 @@ sub ErrorHandling($$$) {
readingsBulkUpdateIfChanged( $dhash, "lastRequestState", readingsBulkUpdateIfChanged( $dhash, "lastRequestState",
"request_error", 1 ); "request_error", 1 );
if ( $param->{code} == 401 and $hash eq $dhash ) { if ( $param->{code} == 401 && $hash eq $dhash ) {
if ( ReadingsVal( $dname, 'token', 'none' ) eq 'none' ) { if ( ReadingsVal( $dname, 'token', 'none' ) eq 'none' ) {
readingsBulkUpdate( $dhash, "state", "no token available", 1 ); readingsBulkUpdate( $dhash, "state", "no token available", 1 );
@ -572,9 +557,9 @@ sub ErrorHandling($$$) {
"GardenaSmartBridge ($dname) - RequestERROR: " . $param->{code}; "GardenaSmartBridge ($dname) - RequestERROR: " . $param->{code};
} }
elsif ( $param->{code} == 204 elsif ($param->{code} == 204
and $dhash ne $hash && $dhash ne $hash
and defined( $dhash->{helper}{deviceAction} ) ) && defined( $dhash->{helper}{deviceAction} ) )
{ {
readingsBulkUpdate( $dhash, "state", "the command is processed", readingsBulkUpdate( $dhash, "state", "the command is processed",
@ -607,9 +592,9 @@ sub ErrorHandling($$$) {
if ( if (
$data =~ /Error/ $data =~ /Error/
or ( defined($decode_json) || ( defined($decode_json)
and ref($decode_json) eq 'HASH' && ref($decode_json) eq 'HASH'
and defined( $decode_json->{errors} ) ) && defined( $decode_json->{errors} ) )
) )
{ {
readingsBeginUpdate($dhash); readingsBeginUpdate($dhash);
@ -621,7 +606,7 @@ sub ErrorHandling($$$) {
if ( $param->{code} == 400 ) { if ( $param->{code} == 400 ) {
if ($decode_json) { if ($decode_json) {
if ( ref( $decode_json->{errors} ) eq "ARRAY" if ( ref( $decode_json->{errors} ) eq "ARRAY"
and defined( $decode_json->{errors} ) ) && defined( $decode_json->{errors} ) )
{ {
readingsBulkUpdate( readingsBulkUpdate(
$dhash, $dhash,
@ -660,7 +645,7 @@ sub ErrorHandling($$$) {
} }
elsif ( $param->{code} == 404 ) { elsif ( $param->{code} == 404 ) {
if ( defined( $dhash->{helper}{deviceAction} ) and $dhash ne $hash ) if ( defined( $dhash->{helper}{deviceAction} ) && $dhash ne $hash )
{ {
readingsBulkUpdate( $dhash, "state", "device Id not found", 1 ); readingsBulkUpdate( $dhash, "state", "device Id not found", 1 );
readingsBulkUpdate( $dhash, "lastRequestState", readingsBulkUpdate( $dhash, "lastRequestState",
@ -701,11 +686,13 @@ sub ErrorHandling($$$) {
if ( defined( $hash->{helper}{locations_id} ) ); if ( defined( $hash->{helper}{locations_id} ) );
ResponseProcessing( $hash, $data ) ResponseProcessing( $hash, $data )
if ( ref($decode_json) eq 'HASH' ); if ( ref($decode_json) eq 'HASH' );
return;
} }
sub ResponseProcessing($$) { sub ResponseProcessing {
my $hash = shift;
my ( $hash, $json ) = @_; my $json = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
@ -722,7 +709,9 @@ sub ResponseProcessing($$) {
} }
} }
if ( defined( $decode_json->{sessions} ) and $decode_json->{sessions} ) { # print Dumper $decode_json;
if ( defined( $decode_json->{sessions} ) && $decode_json->{sessions} ) {
$hash->{helper}{session_id} = $decode_json->{sessions}{token}; $hash->{helper}{session_id} = $decode_json->{sessions}{token};
$hash->{helper}{user_id} = $decode_json->{sessions}{user_id}; $hash->{helper}{user_id} = $decode_json->{sessions}{user_id};
@ -734,13 +723,12 @@ sub ResponseProcessing($$) {
return; return;
} }
elsif ( not defined( $hash->{helper}{locations_id} ) elsif ( !defined( $hash->{helper}{locations_id} )
and defined( $decode_json->{locations} ) && defined( $decode_json->{locations} )
and ref( $decode_json->{locations} ) eq "ARRAY" && ref( $decode_json->{locations} ) eq 'ARRAY'
and scalar( @{ $decode_json->{locations} } ) > 0 ) && scalar( @{ $decode_json->{locations} } ) > 0 )
{ {
for my $location ( @{ $decode_json->{locations} } ) {
foreach my $location ( @{ $decode_json->{locations} } ) {
$hash->{helper}{locations_id} = $location->{id}; $hash->{helper}{locations_id} = $location->{id};
@ -753,11 +741,10 @@ sub ResponseProcessing($$) {
Write( $hash, undef, undef, undef ); Write( $hash, undef, undef, undef );
return; return;
} }
elsif ( defined( $decode_json->{devices} ) elsif (defined( $decode_json->{devices} )
and ref( $decode_json->{devices} ) eq "ARRAY" && ref( $decode_json->{devices} ) eq 'ARRAY'
and scalar( @{ $decode_json->{devices} } ) > 0 ) && scalar( @{ $decode_json->{devices} } ) > 0 )
{ {
my @buffer = split( '"devices":\[', $json ); my @buffer = split( '"devices":\[', $json );
@ -779,19 +766,18 @@ sub ResponseProcessing($$) {
. " Tail: " . " Tail: "
. $tail; . $tail;
unless ( not defined($tail) and not($tail) ) { if ( defined($tail) and $tail ) {
$decode_json = eval { decode_json($json) }; $decode_json = eval { decode_json($json) };
if ($@) { if ($@) {
Log3 $name, 3, Log3 $name, 5,
"GardenaSmartBridge ($name) - JSON error while request: $@"; "GardenaSmartBridge ($name) - JSON error while request: $@";
} }
Dispatch( $hash, $json, undef ) Dispatch( $hash, $json, undef )
unless ( $decode_json->{category} eq 'gateway' ); if ( $decode_json->{category} ne 'gateway' );
WriteReadings( $hash, $decode_json ) WriteReadings( $hash, $decode_json )
if ( defined( $decode_json->{category} ) if ( defined( $decode_json->{category} )
and $decode_json->{category} eq 'gateway' ); && $decode_json->{category} eq 'gateway' );
} }
( $json, $tail ) = ParseJSON( $hash, $tail ); ( $json, $tail ) = ParseJSON( $hash, $tail );
@ -809,17 +795,22 @@ sub ResponseProcessing($$) {
} }
Log3 $name, 3, "GardenaSmartBridge ($name) - no Match for processing data"; Log3 $name, 3, "GardenaSmartBridge ($name) - no Match for processing data";
return;
} }
sub WriteReadings($$) { sub WriteReadings {
my $hash = shift;
my $decode_json = shift;
# print Dumper $decode_json;
my ( $hash, $decode_json ) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
if ( defined( $decode_json->{id} ) if ( defined( $decode_json->{id} )
and $decode_json->{id} && $decode_json->{id}
and defined( $decode_json->{name} ) && defined( $decode_json->{name} )
and $decode_json->{name} ) && $decode_json->{name} )
{ {
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
if ( $decode_json->{id} eq $hash->{helper}{locations_id} ) { if ( $decode_json->{id} eq $hash->{helper}{locations_id} ) {
@ -839,9 +830,9 @@ sub WriteReadings($$) {
readingsBulkUpdateIfChanged( $hash, 'zones', readingsBulkUpdateIfChanged( $hash, 'zones',
scalar( @{ $decode_json->{zones} } ) ); scalar( @{ $decode_json->{zones} } ) );
} }
elsif ( $decode_json->{id} ne $hash->{helper}{locations_id} elsif ($decode_json->{id} ne $hash->{helper}{locations_id}
and ref( $decode_json->{abilities} ) eq 'ARRAY' && ref( $decode_json->{abilities} ) eq 'ARRAY'
and ref( $decode_json->{abilities}[0]{properties} ) eq 'ARRAY' ) && ref( $decode_json->{abilities}[0]{properties} ) eq 'ARRAY' )
{ {
my $properties = my $properties =
scalar( @{ $decode_json->{abilities}[0]{properties} } ); scalar( @{ $decode_json->{abilities}[0]{properties} } );
@ -861,20 +852,20 @@ sub WriteReadings($$) {
{name} . '-' . $t, {name} . '-' . $t,
$v $v
) )
unless ( if (
$decode_json->{abilities}[0]{properties}[$properties] $decode_json->{abilities}[0]{properties}[$properties]
{name} eq 'ethernet_status' {name} ne 'ethernet_status'
or $decode_json->{abilities}[0]{properties}[$properties] || $decode_json->{abilities}[0]{properties}
{name} eq 'wifi_status' ); [$properties]{name} ne 'wifi_status' );
if ( if (
( (
$decode_json->{abilities}[0]{properties} $decode_json->{abilities}[0]{properties}
[$properties]{name} eq 'ethernet_status' [$properties]{name} eq 'ethernet_status'
or $decode_json->{abilities}[0]{properties} || $decode_json->{abilities}[0]{properties}
[$properties]{name} eq 'wifi_status' [$properties]{name} eq 'wifi_status'
) )
and ref($v) eq 'HASH' && ref($v) eq 'HASH'
) )
{ {
if ( $decode_json->{abilities}[0]{properties} if ( $decode_json->{abilities}[0]{properties}
@ -914,15 +905,17 @@ sub WriteReadings($$) {
} }
Log3 $name, 4, "GardenaSmartBridge ($name) - readings would be written"; Log3 $name, 4, "GardenaSmartBridge ($name) - readings would be written";
return;
} }
#################################### ####################################
#################################### ####################################
#### my little helpers Sub's ####### #### my little helpers Sub's #######
sub getDevices($) { sub getDevices {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
RemoveInternalTimer($hash); RemoveInternalTimer($hash);
@ -938,11 +931,13 @@ sub getDevices($) {
readingsSingleUpdate( $hash, 'state', 'disabled', 1 ); readingsSingleUpdate( $hash, 'state', 'disabled', 1 );
Log3 $name, 3, "GardenaSmartBridge ($name) - device is disabled"; Log3 $name, 3, "GardenaSmartBridge ($name) - device is disabled";
} }
return;
} }
sub getToken($) { sub getToken {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
return readingsSingleUpdate( $hash, 'state', return readingsSingleUpdate( $hash, 'state',
@ -950,35 +945,39 @@ sub getToken($) {
if ( AttrVal( $name, 'gardenaAccountEmail', 'none' ) eq 'none' ); if ( AttrVal( $name, 'gardenaAccountEmail', 'none' ) eq 'none' );
return readingsSingleUpdate( $hash, 'state', return readingsSingleUpdate( $hash, 'state',
'please set gardena account password first', 1 ) 'please set gardena account password first', 1 )
if ( not defined( ReadPassword($hash,$name) ) ); if ( !defined( ReadPassword( $hash, $name ) ) );
readingsSingleUpdate( $hash, 'state', 'get token', 1 ); readingsSingleUpdate( $hash, 'state', 'get token', 1 );
delete $hash->{helper}{session_id} delete $hash->{helper}{session_id}
if ( defined( $hash->{helper}{session_id} ) if ( defined( $hash->{helper}{session_id} )
and $hash->{helper}{session_id} ); && $hash->{helper}{session_id} );
delete $hash->{helper}{user_id} delete $hash->{helper}{user_id}
if ( defined( $hash->{helper}{user_id} ) and $hash->{helper}{user_id} ); if ( defined( $hash->{helper}{user_id} ) && $hash->{helper}{user_id} );
delete $hash->{helper}{locations_id} delete $hash->{helper}{locations_id}
if ( defined( $hash->{helper}{locations_id} ) if ( defined( $hash->{helper}{locations_id} )
and $hash->{helper}{locations_id} ); && $hash->{helper}{locations_id} );
Write( Write(
$hash, $hash,
'"sessions": {"email": "' '"sessions": {"email": "'
. AttrVal( $name, 'gardenaAccountEmail', 'none' ) . AttrVal( $name, 'gardenaAccountEmail', 'none' )
. '","password": "' . '","password": "'
. ReadPassword($hash,$name) . '"}', . ReadPassword( $hash, $name ) . '"}',
undef, undef,
undef undef
); );
Log3 $name, 3, Log3 $name, 3,
"GardenaSmartBridge ($name) - send credentials to fetch Token and locationId"; "GardenaSmartBridge ($name) - send credentials to fetch Token and locationId";
return;
} }
sub StorePassword($@) { sub StorePassword {
my $hash = shift;
my $name = shift;
my $password = shift;
my ( $hash, $name, $password ) = @_;
my $index = $hash->{TYPE} . "_" . $name . "_passwd"; my $index = $hash->{TYPE} . "_" . $name . "_passwd";
my $key = getUniqueId() . $index; my $key = getUniqueId() . $index;
my $enc_pwd = ""; my $enc_pwd = "";
@ -1002,11 +1001,12 @@ sub StorePassword($@) {
return "password successfully saved"; return "password successfully saved";
} }
sub ReadPassword($$) { sub ReadPassword {
my $hash = shift;
my $name = shift;
my ( $hash, $name ) = @_; my $index = $hash->{TYPE} . "_" . $name . "_passwd";
my $index = $hash->{TYPE} . "_" . $name . "_passwd"; my $key = getUniqueId() . $index;
my $key = getUniqueId() . $index;
my ( $password, $err ); my ( $password, $err );
Log3 $name, 4, "GardenaSmartBridge ($name) - Read password from file"; Log3 $name, 4, "GardenaSmartBridge ($name) - Read password from file";
@ -1045,22 +1045,25 @@ sub ReadPassword($$) {
Log3 $name, 3, "GardenaSmartBridge ($name) - No password in file"; Log3 $name, 3, "GardenaSmartBridge ($name) - No password in file";
return undef; return undef;
} }
return;
} }
sub Rename(@) { sub Rename {
my $new = shift;
my $old = shift;
my ( $new, $old ) = @_;
my $hash = $defs{$new}; my $hash = $defs{$new};
StorePassword( $hash, $new, ReadPassword($hash,$old) ); StorePassword( $hash, $new, ReadPassword( $hash, $old ) );
setKeyValue( $hash->{TYPE} . "_" . $old . "_passwd", undef ); setKeyValue( $hash->{TYPE} . "_" . $old . "_passwd", undef );
return undef; return;
} }
sub ParseJSON($$) { sub ParseJSON {
my $hash = shift;
my ( $hash, $buffer ) = @_; my $buffer = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $open = 0; my $open = 0;
@ -1069,14 +1072,14 @@ sub ParseJSON($$) {
my $tail = ''; my $tail = '';
if ($buffer) { if ($buffer) {
foreach my $c ( split //, $buffer ) { for my $c ( split //, $buffer ) {
if ( $open == $close and $open > 0 ) { if ( $open == $close && $open > 0 ) {
$tail .= $c; $tail .= $c;
Log3 $name, 5, Log3 $name, 5,
"GardenaSmartBridge ($name) - $open == $close and $open > 0"; "GardenaSmartBridge ($name) - $open == $close and $open > 0";
} }
elsif ( ( $open == $close ) and ( $c ne '{' ) ) { elsif ( ( $open == $close ) && ( $c ne '{' ) ) {
Log3 $name, 5, Log3 $name, 5,
"GardenaSmartBridge ($name) - Garbage character before message: " "GardenaSmartBridge ($name) - Garbage character before message: "
@ -1111,9 +1114,9 @@ sub ParseJSON($$) {
return ( $msg, $tail ); return ( $msg, $tail );
} }
sub createHttpValueStrings($@) { sub createHttpValueStrings {
my ( $hash, $payload, $deviceId, $abilities ) = @_; my ( $hash, $payload, $deviceId, $abilities ) = @_;
my $session_id = $hash->{helper}{session_id}; my $session_id = $hash->{helper}{session_id};
my $header = "Content-Type: application/json"; my $header = "Content-Type: application/json";
my $uri = ''; my $uri = '';
@ -1121,25 +1124,25 @@ sub createHttpValueStrings($@) {
$header .= "\r\nX-Session: $session_id" $header .= "\r\nX-Session: $session_id"
if ( defined( $hash->{helper}{session_id} ) ); if ( defined( $hash->{helper}{session_id} ) );
$payload = '{' . $payload . '}' if ( defined($payload) ); $payload = '{' . $payload . '}' if ( defined($payload) );
$payload = '{}' if ( not defined($payload) ); $payload = '{}' if ( !defined($payload) );
if ( $payload eq '{}' ) { if ( $payload eq '{}' ) {
$method = 'GET'; $method = 'GET';
$uri .= '/locations/?user_id=' . $hash->{helper}{user_id} $uri .= '/locations/?user_id=' . $hash->{helper}{user_id}
if ( exists($hash->{helper}{user_id}) if ( exists( $hash->{helper}{user_id} )
and not defined( $hash->{helper}{locations_id} ) ); && !defined( $hash->{helper}{locations_id} ) );
readingsSingleUpdate( $hash, 'state', 'fetch locationId', 1 ) readingsSingleUpdate( $hash, 'state', 'fetch locationId', 1 )
if ( not defined( $hash->{helper}{locations_id} ) ); if ( !defined( $hash->{helper}{locations_id} ) );
$uri .= '/sessions' if ( not defined( $hash->{helper}{session_id} ) ); $uri .= '/sessions' if ( !defined( $hash->{helper}{session_id} ) );
$uri .= '/devices' $uri .= '/devices'
if ( not defined($abilities) if (!defined($abilities)
and defined( $hash->{helper}{locations_id} ) ); && defined( $hash->{helper}{locations_id} ) );
} }
$uri .= '/sessions' if ( not defined( $hash->{helper}{session_id} ) ); $uri .= '/sessions' if ( !defined( $hash->{helper}{session_id} ) );
if ( defined( $hash->{helper}{locations_id} ) ) { if ( defined( $hash->{helper}{locations_id} ) ) {
if ( defined($abilities) and $abilities eq 'mower_settings' ) { if ( defined($abilities) && $abilities eq 'mower_settings' ) {
$method = 'PUT'; $method = 'PUT';
my $dhash = $modules{GardenaSmartDevice}{defptr}{$deviceId}; my $dhash = $modules{GardenaSmartDevice}{defptr}{$deviceId};
@ -1148,14 +1151,14 @@ sub createHttpValueStrings($@) {
. $deviceId . $deviceId
. '/settings/' . '/settings/'
. $dhash->{helper}{STARTINGPOINTID} . $dhash->{helper}{STARTINGPOINTID}
if ( defined($abilities) if ( defined($abilities)
and defined($payload) && defined($payload)
and $abilities eq 'mower_settings' ); && $abilities eq 'mower_settings' );
} }
elsif ( defined($abilities) elsif (defined($abilities)
and defined($payload) && defined($payload)
and $abilities eq 'watering' ) && $abilities eq 'watering' )
{ {
my $valve_id; my $valve_id;
$method = 'PUT'; $method = 'PUT';
@ -1172,9 +1175,9 @@ sub createHttpValueStrings($@) {
. $valve_id; . $valve_id;
} }
elsif ( defined($abilities) elsif (defined($abilities)
and defined($payload) && defined($payload)
and $abilities eq 'manual_watering' ) && $abilities eq 'manual_watering' )
{ {
my $valve_id; my $valve_id;
$method = 'PUT'; $method = 'PUT';
@ -1187,9 +1190,9 @@ sub createHttpValueStrings($@) {
. '/properties/manual_watering_timer'; . '/properties/manual_watering_timer';
} }
elsif ( defined($abilities) elsif (defined($abilities)
and defined($payload) && defined($payload)
and $abilities eq 'power' ) && $abilities eq 'power' )
{ {
my $valve_id; my $valve_id;
$method = 'PUT'; $method = 'PUT';
@ -1205,7 +1208,7 @@ sub createHttpValueStrings($@) {
else { else {
$uri .= $uri .=
'/devices/' . $deviceId . '/abilities/' . $abilities . '/command' '/devices/' . $deviceId . '/abilities/' . $abilities . '/command'
if ( defined($abilities) and defined($payload) ); if ( defined($abilities) && defined($payload) );
} }
$uri .= '?locationId=' . $hash->{helper}{locations_id}; $uri .= '?locationId=' . $hash->{helper}{locations_id};
@ -1215,13 +1218,12 @@ sub createHttpValueStrings($@) {
$abilities ); $abilities );
} }
sub DeletePassword($) { sub DeletePassword {
my $hash = shift; my $hash = shift;
setKeyValue( $hash->{TYPE} . "_" . $hash->{NAME} . "_passwd", undef ); setKeyValue( $hash->{TYPE} . "_" . $hash->{NAME} . "_passwd", undef );
return undef; return;
} }
1; 1;
@ -1373,6 +1375,7 @@ sub DeletePassword($) {
], ],
"release_status": "stable", "release_status": "stable",
"license": "GPL_2", "license": "GPL_2",
"version": "v2.0.0",
"author": [ "author": [
"Marko Oldenburg <leongaultier@gmail.com>" "Marko Oldenburg <leongaultier@gmail.com>"
], ],

View File

@ -55,18 +55,13 @@
## unserer packagename ## unserer packagename
package FHEM::GardenaSmartDevice; package FHEM::GardenaSmartDevice;
use GPUtils qw(GP_Import GP_Export);
use GPUtils qw(GP_Import)
; # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt
my $missingModul = "";
use strict; use strict;
use warnings; use warnings;
use POSIX; use POSIX;
use FHEM::Meta; use FHEM::Meta;
use Time::Local; use Time::Local;
our $VERSION = '1.6.7';
# try to use JSON::MaybeXS wrapper # try to use JSON::MaybeXS wrapper
# for chance of better performance + open code # for chance of better performance + open code
@ -163,70 +158,51 @@ BEGIN {
); );
} }
# _Export - Export references to main context using a different naming schema
sub _Export {
no strict qw/refs/; ## no critic
my $pkg = caller(0);
my $main = $pkg;
$main =~ s/^(?:.+::)?([^:]+)$/main::$1\_/g;
foreach (@_) {
*{ $main . $_ } = *{ $pkg . '::' . $_ };
}
}
#-- Export to main context with different name #-- Export to main context with different name
_Export( GP_Export(
qw( qw(
Initialize Initialize
) )
); );
sub Initialize($) { sub Initialize {
my $hash = shift;
my ($hash) = @_;
$hash->{Match} = '^{"id":".*'; $hash->{Match} = '^{"id":".*';
$hash->{SetFn} = "FHEM::GardenaSmartDevice::Set"; $hash->{SetFn} = \&Set;
$hash->{DefFn} = "FHEM::GardenaSmartDevice::Define"; $hash->{DefFn} = \&Define;
$hash->{UndefFn} = "FHEM::GardenaSmartDevice::Undef"; $hash->{UndefFn} = \&Undef;
$hash->{ParseFn} = "FHEM::GardenaSmartDevice::Parse"; $hash->{ParseFn} = \&Parse;
$hash->{AttrFn} = "FHEM::GardenaSmartDevice::Attr"; $hash->{AttrFn} = \&Attr;
$hash->{AttrList} = $hash->{AttrList} =
"readingValueLanguage:de,en " "readingValueLanguage:de,en "
. "model:watering_computer,sensor,mower,ic24,power,electronic_pressure_pump " . "model:watering_computer,sensor,mower,ic24,power,electronic_pressure_pump "
. "IODev " . "IODev "
. $readingFnAttributes; . $readingFnAttributes;
$hash->{parseParams} = 1;
foreach my $d ( sort keys %{ $modules{GardenaSmartDevice}{defptr} } ) {
my $hash = $modules{GardenaSmartDevice}{defptr}{$d};
$hash->{VERSION} = $VERSION;
}
return FHEM::Meta::InitMod( __FILE__, $hash ); return FHEM::Meta::InitMod( __FILE__, $hash );
} }
sub Define($$) { sub Define {
my $hash = shift;
my ( $hash, $def ) = @_; my $a = shift;
my @a = split( "[ \t]+", $def );
return $@ unless ( FHEM::Meta::SetInternals($hash) ); return $@ unless ( FHEM::Meta::SetInternals($hash) );
use version 0.60; our $VERSION = FHEM::Meta::Get( $hash, 'version' );
return return
"too few parameters: define <NAME> GardenaSmartDevice <device_Id> <model>" "too few parameters: define <NAME> GardenaSmartDevice <device_Id> <model>"
if ( @a < 3 ); if ( scalar( @{$a} ) < 3 );
return
"Cannot define Gardena Bridge device. Perl modul $missingModul is missing."
if ($missingModul);
my $name = $a[0]; my $name = $a->[0];
my $deviceId = $a[2]; my $deviceId = $a->[2];
my $category = $a[3]; my $category = $a->[3];
$hash->{DEVICEID} = $deviceId; $hash->{DEVICEID} = $deviceId;
$hash->{VERSION} = $VERSION; $hash->{VERSION} = version->parse($VERSION)->normal;
$hash->{helper}{STARTINGPOINTID} = ''; $hash->{helper}{STARTINGPOINTID} = '';
CommandAttr( undef, CommandAttr( undef,
@ -251,9 +227,9 @@ sub Define($$) {
return return
"GardenaSmartDevice device $name on GardenaSmartBridge $iodev already defined." "GardenaSmartDevice device $name on GardenaSmartBridge $iodev already defined."
if ( defined($d) if ( defined($d)
and $d->{IODev} == $hash->{IODev} && $d->{IODev} == $hash->{IODev}
and $d->{NAME} ne $name ); && $d->{NAME} ne $name );
CommandAttr( undef, $name . ' room GardenaSmart' ) CommandAttr( undef, $name . ' room GardenaSmart' )
if ( AttrVal( $name, 'room', 'none' ) eq 'none' ); if ( AttrVal( $name, 'room', 'none' ) eq 'none' );
@ -267,100 +243,107 @@ sub Define($$) {
$modules{GardenaSmartDevice}{defptr}{$deviceId} = $hash; $modules{GardenaSmartDevice}{defptr}{$deviceId} = $hash;
return undef; return;
} }
sub Undef($$) { sub Undef {
my $hash = shift;
my $arg = shift;
my ( $hash, $arg ) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $deviceId = $hash->{DEVICEID}; my $deviceId = $hash->{DEVICEID};
delete $modules{GardenaSmartDevice}{defptr}{$deviceId}; delete $modules{GardenaSmartDevice}{defptr}{$deviceId};
return undef; return;
} }
sub Attr(@) { sub Attr {
my ( $cmd, $name, $attrName, $attrVal ) = @_; my ( $cmd, $name, $attrName, $attrVal ) = @_;
my $hash = $defs{$name}; my $hash = $defs{$name};
return undef; return;
} }
sub Set($@) { sub Set {
my $hash = shift;
my $a = shift;
my ( $hash, $name, $cmd, @args ) = @_; my $name = shift @$a;
my $cmd = shift @$a // return qq{"set $name" needs at least one argument};
my $payload; my $payload;
my $abilities = ''; my $abilities = '';
### mower ### mower
if ( lc $cmd eq 'parkuntilfurthernotice' ) { if ( lc $cmd eq 'parkuntilfurthernotice' ) {
$payload = '"name":"park_until_further_notice"'; $payload = '"name":"park_until_further_notice"';
} }
elsif ( lc $cmd eq 'parkuntilnexttimer' ) { elsif ( lc $cmd eq 'parkuntilnexttimer' ) {
$payload = '"name":"park_until_next_timer"'; $payload = '"name":"park_until_next_timer"';
} }
elsif ( lc $cmd eq 'startresumeschedule' ) { elsif ( lc $cmd eq 'startresumeschedule' ) {
$payload = '"name":"start_resume_schedule"'; $payload = '"name":"start_resume_schedule"';
} }
elsif ( lc $cmd eq 'startoverridetimer' ) { elsif ( lc $cmd eq 'startoverridetimer' ) {
my $duration = join( " ", @args );
$payload = '"name":"start_override_timer","parameters":{"duration":' $payload = '"name":"start_override_timer","parameters":{"duration":'
. $duration * 60 . '}'; . $a->[0] * 60 . '}';
} }
elsif ( lc $cmd eq 'startpoint' ) { elsif ( lc $cmd eq 'startpoint' ) {
my $err; my $err;
( $err, $payload, $abilities ) = ( $err, $payload, $abilities ) = SetPredefinedStartPoints( $hash, @$a );
SetPredefinedStartPoints( $hash, @args );
return $err if ( defined($err) ); return $err if ( defined($err) );
} }
### electronic_pressure_pump ### electronic_pressure_pump
elsif ( lc $cmd eq 'pumptimer' ) { elsif ( lc $cmd eq 'pumptimer' ) {
my $duration = join( " ", @args );
$payload = $payload =
'"name":"pump_manual_watering_timer","parameters":{"duration":' '"name":"pump_manual_watering_timer","parameters":{"duration":'
. $duration . '}'; . $a->[0] . '}';
} }
### watering_computer ### watering_computer
elsif ( lc $cmd eq 'manualoverride' ) { elsif ( lc $cmd eq 'manualoverride' ) {
$payload =
my $duration = join( " ", @args ); '"properties":{"name":"watering_timer_1'
$payload = '"name":"manual_override","parameters":{"duration":' . '","value":{"state":"manual","duration":'
. $duration . '}'; . $a->[0] * 60
. ',"valve_id":1}}';
} }
elsif ( lc $cmd eq 'canceloverride' ) { elsif ( $cmd =~ m{\AcancelOverride}xms ) {
$payload = '"name":"cancel_override"'; my $valve_id = 1;
if ( $cmd =~ m{\AcancelOverrideValve(\d)\z}xms ) {
$valve_id = $1;
}
$payload =
'"properties":{"name":"watering_timer_'
. $valve_id
. '","value":{"state":"idle","duration":'
. 0
. ',"valve_id":'
. $valve_id . '}}';
} }
elsif ( lc $cmd eq 'on' or lc $cmd eq 'off' or lc $cmd eq 'on-for-timer' ) { elsif ( lc $cmd eq 'on' || lc $cmd eq 'off' || lc $cmd eq 'on-for-timer' ) {
my $val = (
defined($a) && ref($a) eq 'ARRAY'
? $a->[0] * 60
: lc $cmd
);
my $val = ( defined( $args[0] ) ? join( " ", @args ) * 60 : lc $cmd );
$payload = '"properties":{"value":"' . $val . '"}'; $payload = '"properties":{"value":"' . $val . '"}';
} }
### Watering ic24 ### Watering ic24
elsif ( $cmd =~ /manualDurationValve/ ) { elsif ( $cmd =~ m{\AmanualDurationValve\d\z}xms ) {
my $valve_id; my $valve_id;
my $duration = join( " ", @args );
if ( $cmd =~ m#(\d)$# ) { if ( $cmd =~ m{\AmanualDurationValve(\d)\z}xms ) {
$valve_id = $1; $valve_id = $1;
} }
@ -368,14 +351,14 @@ sub Set($@) {
'"properties":{"name":"watering_timer_' '"properties":{"name":"watering_timer_'
. $valve_id . $valve_id
. '","value":{"state":"manual","duration":' . '","value":{"state":"manual","duration":'
. $duration * 60 . $a->[0] * 60
. ',"valve_id":' . ',"valve_id":'
. $valve_id . '}}'; . $valve_id . '}}';
} }
### Sensors ### Sensors
elsif ( lc $cmd eq 'refresh' ) { elsif ( lc $cmd eq 'refresh' ) {
my $sensname = join( " ", @args ); my $sensname = $a->[0];
if ( lc $sensname eq 'temperature' ) { if ( lc $sensname eq 'temperature' ) {
$payload = '"name":"measure_ambient_temperature"'; $payload = '"name":"measure_ambient_temperature"';
$abilities = 'ambient_temperature'; $abilities = 'ambient_temperature';
@ -395,18 +378,12 @@ sub Set($@) {
else { else {
my $list = ''; my $list = '';
$list .=
'parkUntilFurtherNotice:noArg parkUntilNextTimer:noArg startResumeSchedule:noArg startOverrideTimer:slider,0,1,60 startpoint'
if ( AttrVal( $name, 'model', 'unknown' ) eq 'mower' );
$list .= 'manualOverride:slider,0,1,59 cancelOverride:noArg' $list .= 'manualOverride:slider,1,1,59 cancelOverride:noArg'
if ( AttrVal( $name, 'model', 'unknown' ) eq 'watering_computer' ); if ( AttrVal( $name, 'model', 'unknown' ) eq 'watering_computer' );
# $list .= 'pumpTimer:slider,0,1,59'
# if ( AttrVal( $name, 'model', 'unknown' ) eq 'electronic_pressure_pump' );
$list .= $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' '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 cancelOverrideValve1:noArg cancelOverrideValve2:noArg cancelOverrideValve3:noArg cancelOverrideValve4:noArg cancelOverrideValve5:noArg cancelOverrideValve6:noArg'
if ( AttrVal( $name, 'model', 'unknown' ) eq 'ic24' ); if ( AttrVal( $name, 'model', 'unknown' ) eq 'ic24' );
$list .= 'refresh:temperature,light,humidity' $list .= 'refresh:temperature,light,humidity'
@ -420,11 +397,10 @@ sub Set($@) {
$abilities = 'mower' $abilities = 'mower'
if ( AttrVal( $name, 'model', 'unknown' ) eq 'mower' ) if ( AttrVal( $name, 'model', 'unknown' ) eq 'mower' )
and $abilities ne 'mower_settings'; && $abilities ne 'mower_settings';
$abilities = 'outlet'
if ( AttrVal( $name, 'model', 'unknown' ) eq 'watering_computer' );
$abilities = 'watering' $abilities = 'watering'
if ( AttrVal( $name, 'model', 'unknown' ) eq 'ic24' ); if ( AttrVal( $name, 'model', 'unknown' ) eq 'ic24'
|| AttrVal( $name, 'model', 'unknown' ) eq 'watering_computer' );
$abilities = 'power' $abilities = 'power'
if ( AttrVal( $name, 'model', 'unknown' ) eq 'power' ); if ( AttrVal( $name, 'model', 'unknown' ) eq 'power' );
$abilities = 'manual_watering' $abilities = 'manual_watering'
@ -437,12 +413,12 @@ sub Set($@) {
Log3 $name, 4, Log3 $name, 4,
"GardenaSmartBridge ($name) - IOWrite: $payload $hash->{DEVICEID} $abilities IODevHash=$hash->{IODev}"; "GardenaSmartBridge ($name) - IOWrite: $payload $hash->{DEVICEID} $abilities IODevHash=$hash->{IODev}";
return undef; return;
} }
sub Parse($$) { sub Parse {
my $io_hash = shift;
my ( $io_hash, $json ) = @_; my $json = shift;
my $name = $io_hash->{NAME}; my $name = $io_hash->{NAME};
@ -481,11 +457,13 @@ sub Parse($$) {
. " GardenaSmartDevice $decode_json->{id} $decode_json->{category}"; . " GardenaSmartDevice $decode_json->{id} $decode_json->{category}";
} }
} }
return;
} }
sub WriteReadings($$) { sub WriteReadings {
my $hash = shift;
my ( $hash, $decode_json ) = @_; my $decode_json = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $abilities = scalar( @{ $decode_json->{abilities} } ); my $abilities = scalar( @{ $decode_json->{abilities} } );
@ -497,11 +475,10 @@ sub WriteReadings($$) {
if ( if (
ref( $decode_json->{abilities}[$abilities]{properties} ) eq "ARRAY" ref( $decode_json->{abilities}[$abilities]{properties} ) eq "ARRAY"
and && scalar( @{ $decode_json->{abilities}[$abilities]{properties} } )
scalar( @{ $decode_json->{abilities}[$abilities]{properties} } ) > > 0 )
0 )
{ {
foreach my $propertie ( for my $propertie (
@{ $decode_json->{abilities}[$abilities]{properties} } ) @{ $decode_json->{abilities}[$abilities]{properties} } )
{ {
readingsBulkUpdateIfChanged( readingsBulkUpdateIfChanged(
@ -511,21 +488,21 @@ sub WriteReadings($$) {
RigRadingsValue( $hash, $propertie->{value} ) RigRadingsValue( $hash, $propertie->{value} )
) )
if ( defined( $propertie->{value} ) if ( defined( $propertie->{value} )
and $decode_json->{abilities}[$abilities]{name} . '-' && $decode_json->{abilities}[$abilities]{name} . '-'
. $propertie->{name} ne 'radio-quality' . $propertie->{name} ne 'radio-quality'
and $decode_json->{abilities}[$abilities]{name} . '-' && $decode_json->{abilities}[$abilities]{name} . '-'
. $propertie->{name} ne 'battery-level' . $propertie->{name} ne 'battery-level'
and $decode_json->{abilities}[$abilities]{name} . '-' && $decode_json->{abilities}[$abilities]{name} . '-'
. $propertie->{name} ne 'internal_temperature-temperature' . $propertie->{name} ne 'internal_temperature-temperature'
and $decode_json->{abilities}[$abilities]{name} . '-' && $decode_json->{abilities}[$abilities]{name} . '-'
. $propertie->{name} ne 'ambient_temperature-temperature' . $propertie->{name} ne 'ambient_temperature-temperature'
and $decode_json->{abilities}[$abilities]{name} . '-' && $decode_json->{abilities}[$abilities]{name} . '-'
. $propertie->{name} ne 'soil_temperature-temperature' . $propertie->{name} ne 'soil_temperature-temperature'
and $decode_json->{abilities}[$abilities]{name} . '-' && $decode_json->{abilities}[$abilities]{name} . '-'
. $propertie->{name} ne 'humidity-humidity' . $propertie->{name} ne 'humidity-humidity'
and $decode_json->{abilities}[$abilities]{name} . '-' && $decode_json->{abilities}[$abilities]{name} . '-'
. $propertie->{name} ne 'light-light' . $propertie->{name} ne 'light-light'
and ref( $propertie->{value} ) ne "HASH" ); && ref( $propertie->{value} ) ne "HASH" );
readingsBulkUpdate( readingsBulkUpdate(
$hash, $hash,
@ -535,21 +512,21 @@ sub WriteReadings($$) {
) )
if ( if (
defined( $propertie->{value} ) defined( $propertie->{value} )
and ( $decode_json->{abilities}[$abilities]{name} . '-' && ( $decode_json->{abilities}[$abilities]{name} . '-'
. $propertie->{name} eq 'radio-quality' . $propertie->{name} eq 'radio-quality'
or $decode_json->{abilities}[$abilities]{name} . '-' || $decode_json->{abilities}[$abilities]{name} . '-'
. $propertie->{name} eq 'battery-level' . $propertie->{name} eq 'battery-level'
or $decode_json->{abilities}[$abilities]{name} . '-' || $decode_json->{abilities}[$abilities]{name} . '-'
. $propertie->{name} eq . $propertie->{name} eq
'internal_temperature-temperature' 'internal_temperature-temperature'
or $decode_json->{abilities}[$abilities]{name} . '-' || $decode_json->{abilities}[$abilities]{name} . '-'
. $propertie->{name} eq . $propertie->{name} eq
'ambient_temperature-temperature' 'ambient_temperature-temperature'
or $decode_json->{abilities}[$abilities]{name} . '-' || $decode_json->{abilities}[$abilities]{name} . '-'
. $propertie->{name} eq 'soil_temperature-temperature' . $propertie->{name} eq 'soil_temperature-temperature'
or $decode_json->{abilities}[$abilities]{name} . '-' || $decode_json->{abilities}[$abilities]{name} . '-'
. $propertie->{name} eq 'humidity-humidity' . $propertie->{name} eq 'humidity-humidity'
or $decode_json->{abilities}[$abilities]{name} . '-' || $decode_json->{abilities}[$abilities]{name} . '-'
. $propertie->{name} eq 'light-light' ) . $propertie->{name} eq 'light-light' )
); );
@ -560,7 +537,7 @@ sub WriteReadings($$) {
join( ',', @{ $propertie->{value} } ) join( ',', @{ $propertie->{value} } )
) )
if ( defined( $propertie->{value} ) if ( defined( $propertie->{value} )
and $decode_json->{abilities}[$abilities]{name} . '-' && $decode_json->{abilities}[$abilities]{name} . '-'
. $propertie->{name} eq 'ic24-valves_connected' ); . $propertie->{name} eq 'ic24-valves_connected' );
readingsBulkUpdateIfChanged( readingsBulkUpdateIfChanged(
@ -570,7 +547,7 @@ sub WriteReadings($$) {
join( ',', @{ $propertie->{value} } ) join( ',', @{ $propertie->{value} } )
) )
if ( defined( $propertie->{value} ) if ( defined( $propertie->{value} )
and $decode_json->{abilities}[$abilities]{name} . '-' && $decode_json->{abilities}[$abilities]{name} . '-'
. $propertie->{name} eq 'ic24-valves_master_config' ); . $propertie->{name} eq 'ic24-valves_master_config' );
if ( ref( $propertie->{value} ) eq "HASH" ) { if ( ref( $propertie->{value} ) eq "HASH" ) {
@ -593,7 +570,7 @@ sub WriteReadings($$) {
do { do {
if ( ref( $decode_json->{settings}[$settings]{value} ) eq "ARRAY" if ( ref( $decode_json->{settings}[$settings]{value} ) eq "ARRAY"
and $decode_json->{settings}[$settings]{name} eq 'starting_points' ) && $decode_json->{settings}[$settings]{name} eq 'starting_points' )
{ {
#save the startingpointid needed to update the startingpoints #save the startingpointid needed to update the startingpoints
if ( $hash->{helper}{STARTINGPOINTID} ne if ( $hash->{helper}{STARTINGPOINTID} ne
@ -608,7 +585,7 @@ sub WriteReadings($$) {
. encode_json( $decode_json->{settings}[$settings]{value} ) . '}'; . encode_json( $decode_json->{settings}[$settings]{value} ) . '}';
my $startpoint_cnt = 0; my $startpoint_cnt = 0;
foreach my $startingpoint ( for my $startingpoint (
@{ $decode_json->{settings}[$settings]{value} } ) @{ $decode_json->{settings}[$settings]{value} } )
{ {
$startpoint_cnt++; $startpoint_cnt++;
@ -629,9 +606,9 @@ sub WriteReadings($$) {
readingsBulkUpdate( readingsBulkUpdate(
$hash, 'state', $hash, 'state',
( (
ReadingsVal( $name, 'outlet-valve_open', 0 ) == 1 ReadingsVal( $name, 'watering-watering_timer_1_state', 0 ) eq 'idle'
? RigRadingsValue( $hash, 'open' ) ? RigRadingsValue( $hash, 'closed' )
: RigRadingsValue( $hash, 'closed' ) : RigRadingsValue( $hash, 'open' )
) )
) if ( AttrVal( $name, 'model', 'unknown' ) eq 'watering_computer' ); ) if ( AttrVal( $name, 'model', 'unknown' ) eq 'watering_computer' );
@ -664,17 +641,19 @@ sub WriteReadings($$) {
readingsEndUpdate( $hash, 1 ); readingsEndUpdate( $hash, 1 );
Log3 $name, 4, "GardenaSmartDevice ($name) - readings was written}"; Log3 $name, 4, "GardenaSmartDevice ($name) - readings was written}";
return;
} }
################################## ##################################
################################## ##################################
#### my little helpers ########### #### my little helpers ###########
sub ReadingLangGerman($$) { sub ReadingLangGerman {
my $hash = shift;
my ( $hash, $readingValue ) = @_; my $readingValue = shift;
my $name = $hash->{NAME};
my $name = $hash->{NAME};
my %langGermanMapp = ( my %langGermanMapp = (
'ok_cutting' => 'mähen', 'ok_cutting' => 'mähen',
'paused' => 'pausiert', 'paused' => 'pausiert',
@ -777,9 +756,9 @@ sub ReadingLangGerman($$) {
if ( if (
defined( $langGermanMapp{$readingValue} ) defined( $langGermanMapp{$readingValue} )
and ( AttrVal( 'global', 'language', 'none' ) eq 'DE' && ( AttrVal( 'global', 'language', 'none' ) eq 'DE'
or AttrVal( $name, 'readingValueLanguage', 'none' ) eq 'de' ) || AttrVal( $name, 'readingValueLanguage', 'none' ) eq 'de' )
and AttrVal( $name, 'readingValueLanguage', 'none' ) ne 'en' && AttrVal( $name, 'readingValueLanguage', 'none' ) ne 'en'
) )
{ {
return $langGermanMapp{$readingValue}; return $langGermanMapp{$readingValue};
@ -787,11 +766,13 @@ sub ReadingLangGerman($$) {
else { else {
return $readingValue; return $readingValue;
} }
return;
} }
sub RigRadingsValue($$) { sub RigRadingsValue {
my $hash = shift;
my ( $hash, $readingValue ) = @_; my $readingValue = shift;
my $rigReadingValue; my $rigReadingValue;
@ -805,9 +786,9 @@ sub RigRadingsValue($$) {
return $rigReadingValue; return $rigReadingValue;
} }
sub Zulu2LocalString($) { sub Zulu2LocalString {
my $t = shift; my $t = shift;
my ( $datehour, $datemin, $rest ) = split( /:/, $t, 3 ); my ( $datehour, $datemin, $rest ) = split( /:/, $t, 3 );
my ( $year, $month, $day, $hour, $min ) = my ( $year, $month, $day, $hour, $min ) =
@ -840,18 +821,23 @@ sub Zulu2LocalString($) {
) )
); );
} }
return;
} }
sub SetPredefinedStartPoints($@) { sub SetPredefinedStartPoints {
my $hash = shift;
my $a = shift;
my ( $startpoint_state, $startpoint_num, @morestartpoints ) = @$a;
my ( $hash, $startpoint_state, $startpoint_num, @morestartpoints ) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $payload; my $payload;
my $abilities; my $abilities;
if ( defined($startpoint_state) and defined($startpoint_num) ) { if ( defined($startpoint_state) && defined($startpoint_num) ) {
if ( defined( $hash->{helper}{STARTINGPOINTS} ) if ( defined( $hash->{helper}{STARTINGPOINTS} )
and $hash->{helper}{STARTINGPOINTS} ne '' ) && $hash->{helper}{STARTINGPOINTS} ne '' )
{ {
# add needed parameters to saved settings config and change the value in request # add needed parameters to saved settings config and change the value in request
my $decode_json_settings = my $decode_json_settings =
@ -869,8 +855,8 @@ sub SetPredefinedStartPoints($@) {
#set more startpoints #set more startpoints
if ( if (
defined scalar(@morestartpoints) defined scalar(@morestartpoints)
and ( scalar(@morestartpoints) == 2 && ( scalar(@morestartpoints) == 2
or scalar(@morestartpoints) == 4 ) || scalar(@morestartpoints) == 4 )
) )
{ {
if ( scalar(@morestartpoints) == 2 ) { if ( scalar(@morestartpoints) == 2 ) {
@ -1221,6 +1207,7 @@ sub SetPredefinedStartPoints($@) {
], ],
"release_status": "stable", "release_status": "stable",
"license": "GPL_2", "license": "GPL_2",
"version": "v2.0.0",
"author": [ "author": [
"Marko Oldenburg <leongaultier@gmail.com>" "Marko Oldenburg <leongaultier@gmail.com>"
], ],