Compare commits
268 Commits
Author | SHA1 | Date | |
---|---|---|---|
2111939863 | |||
c9a3cc9e1d | |||
b399fcd524 | |||
89bbb4bb10 | |||
801a1a468f | |||
eddcb708ba | |||
c7073b24b4 | |||
fe97f0b203 | |||
eebe13bb7b | |||
a6174d9982 | |||
aea73bb010 | |||
4cb9f2e50b | |||
b61c32a850 | |||
8c49aaa079 | |||
1f54fc7601 | |||
3dd4796e14 | |||
7b188e3e41 | |||
c2863d9998 | |||
76a7eeb4e5 | |||
388ae1635e | |||
d660366aea | |||
8b9ce793cd | |||
71b435d90b | |||
c86cae74e6 | |||
8ce2980356 | |||
0d29721111 | |||
ade45510ac | |||
8a32c9f215 | |||
78b5731bbf | |||
0ee95be7be | |||
bae27c39c1 | |||
47804c996b | |||
6a7083f6ea | |||
ada7e2875c | |||
658f40e979 | |||
1c7097e476 | |||
e363b45862 | |||
11c5e6650d | |||
4b998d19ab | |||
7f6c7bc265 | |||
e108afda5a | |||
a13c42f08c | |||
df33172650 | |||
f3d153726b | |||
33a10d3756 | |||
abcccefeb4 | |||
f61e9d327b | |||
42afa2133e | |||
6aba15caca | |||
1abf586f71 | |||
f02da0c428 | |||
ebb342d83f | |||
fd4ac49f59 | |||
73d7c50db0 | |||
f5ec4f699a | |||
f2400a3949 | |||
63443d75b4 | |||
5e87026852 | |||
c6ee46489b | |||
97540ef9c4 | |||
0c75c89cf0 | |||
93d0ef26c7 | |||
9b49c75317 | |||
5e10125a09 | |||
9e389681f0 | |||
5b8bd75c55 | |||
f77f49b7f1 | |||
43d9356d8c | |||
41c226536f | |||
ec88be0b06 | |||
8ce72c5ddc | |||
9643a9074f | |||
6f1eebcf48 | |||
c084fabc92 | |||
188f5d3838 | |||
9d70fa238a | |||
740effe531 | |||
426fb7c06a | |||
782ad5f0a9 | |||
41ef5cd10a | |||
6d684ade92 | |||
bc4b6eecf5 | |||
e8c2bd5183 | |||
967ec86ea1 | |||
0086f52d74 | |||
54b378d094 | |||
200751b72b | |||
7cefd1c7e3 | |||
ee0c7fa4ba | |||
ae3bf5f68a | |||
929bd705d5 | |||
9b1170a978 | |||
2a5872002f | |||
1b7670f8c5 | |||
768a5a6d7a | |||
2eefd813df | |||
197dba15f1 | |||
8dd9771033 | |||
a4a75ab016 | |||
2cbe907db4 | |||
af3dee00a2 | |||
c9b1e470cb | |||
458edffa85 | |||
930e42835b | |||
d3020ded2c | |||
97f55e6122 | |||
9f9722ce9c | |||
6ce4b352b4 | |||
b3d39a6e58 | |||
3780befa7a | |||
c68f35c2e3 | |||
830e5426d6 | |||
bbf9919ad3 | |||
ab2e990ffb | |||
df99f04e6e | |||
91ff06ea79 | |||
0c3db5e445 | |||
9ffde3bd2c | |||
3326b134a8 | |||
f8b4df8f4f | |||
5bf618a9d2 | |||
9a85c9c20d | |||
86b679ba97 | |||
a4865cae47 | |||
b6a179a0ea | |||
4666020263 | |||
576569ea2d | |||
ae4e1b9990 | |||
c07f757c4a | |||
6faccfe564 | |||
9505316291 | |||
c76fd125ec | |||
3b28a20b33 | |||
8002d2a1d3 | |||
6b475415cc | |||
40074a3db6 | |||
234607cb8d | |||
9ad11bff63 | |||
0849705c62 | |||
6490c2f1be | |||
d863cbeff0 | |||
d04ea31ef0 | |||
33fddad023 | |||
b620f87eb1 | |||
97b4147072 | |||
bd3d354786 | |||
b230baa776 | |||
4e6ca5f8ed | |||
d6e6847955 | |||
c551f4855f | |||
15c791e1bf | |||
af2f803be5 | |||
91fd570896 | |||
0e876c319c | |||
122983580f | |||
948f68515c | |||
528e8d5a08 | |||
b7adf6af6d | |||
a8646efe0d | |||
480946f9be | |||
c3620aa017 | |||
43bf81053b | |||
b4f5cef061 | |||
58333bef34 | |||
0beab4ec1d | |||
4860b7e0ee | |||
bf6734f44b | |||
a1fad78c3b | |||
bfbf2cced4 | |||
78e9906e6b | |||
8d03f20b57 | |||
83b9a4347c | |||
b197fbd082 | |||
29869e9b08 | |||
d61e06e0e9 | |||
6b87b19f0d | |||
c87d8e9302 | |||
8afc912ed5 | |||
b06c9acda3 | |||
a56dfe6a2d | |||
17b4182abe | |||
9f19ed8817 | |||
cea5741fb8 | |||
5661ef3e59 | |||
40c7318992 | |||
9bdeb2ac19 | |||
e64f8fd0a4 | |||
a193c6f814 | |||
d1b04b6a74 | |||
7113e9974e | |||
7c074adbb9 | |||
462311836f | |||
c553b8ef8f | |||
1d75b5cc77 | |||
f2c840bedc | |||
b6c5f42acc | |||
65cbeba975 | |||
1498f73b10 | |||
8ae1510a71 | |||
b211fe2b56 | |||
85c7b3fa0a | |||
65df7eb47b | |||
13e7e24911 | |||
b61458a45e | |||
673445e339 | |||
157e9fc58c | |||
f3f2688292 | |||
5d245d5a3d | |||
ddbe145179 | |||
bd06f26248 | |||
8e470ccbb6 | |||
7c01c1c790 | |||
7b30b50cf1 | |||
32eec48ce6 | |||
5545ac1370 | |||
d186f3e6c8 | |||
eec264b014 | |||
ef1aabfcb0 | |||
c3882d4af3 | |||
43b4c15a9d | |||
908fe4fc24 | |||
b423fc73fc | |||
9abd0a9173 | |||
2af38efe42 | |||
8ddb1a8233 | |||
23be875b9f | |||
5294e3fea5 | |||
12c4a0d5ba | |||
a856bb574a | |||
4e52ea8215 | |||
70c54892d8 | |||
b49d7f643b | |||
cf93bbdba6 | |||
9d3ddb088b | |||
48e526a627 | |||
113dec6551 | |||
71ef5799c2 | |||
49ef217d12 | |||
65f031e1c2 | |||
10718f1355 | |||
b0638c525e | |||
0adf1d8a3b | |||
a0d8125d32 | |||
b6866dd44a | |||
6f0aee2a69 | |||
acb482e37f | |||
0ec53ea1b3 | |||
08bb518e9a | |||
33eb0ed012 | |||
70af6fd6a3 | |||
44a251f7f7 | |||
0aa3e543a8 | |||
97b8a6edab | |||
a7d374596d | |||
cf0772f6ae | |||
fe23d695e4 | |||
9a6241b608 | |||
065eebb858 | |||
1f3465a12d | |||
e3674c401d | |||
1dde30c52c | |||
5fb14e80a8 | |||
c9f212a641 | |||
9e20c40b37 | |||
e9d37309b4 | |||
613e14b4f9 | |||
6e5f2d98b3 | |||
249f996db7 |
3972
CHANGELOG.md
Normal file
3972
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
||||
###############################################################################
|
||||
#
|
||||
# Developed with Kate
|
||||
# Developed with VSCodium and richterger perl plugin.
|
||||
#
|
||||
# (c) 2017-2021 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net)
|
||||
# (c) 2017-2022 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net)
|
||||
# All rights reserved
|
||||
#
|
||||
# Special thanks goes to comitters:
|
||||
@ -57,7 +57,6 @@
|
||||
package FHEM::GardenaSmartBridge;
|
||||
use GPUtils qw(GP_Import GP_Export);
|
||||
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use POSIX;
|
||||
@ -66,11 +65,12 @@ use FHEM::Meta;
|
||||
use HttpUtils;
|
||||
|
||||
my $missingModul = '';
|
||||
eval "use Encode qw(encode encode_utf8 decode_utf8);1"
|
||||
eval { use Encode qw /encode_utf8 decode_utf8/; 1 }
|
||||
or $missingModul .= "Encode ";
|
||||
|
||||
# eval "use JSON;1" || $missingModul .= 'JSON ';
|
||||
eval "use IO::Socket::SSL;1" or $missingModul .= 'IO::Socket::SSL ';
|
||||
eval { use IO::Socket::SSL; 1 }
|
||||
or $missingModul .= 'IO::Socket::SSL ';
|
||||
|
||||
# try to use JSON::MaybeXS wrapper
|
||||
# for chance of better performance + open code
|
||||
@ -78,15 +78,11 @@ eval {
|
||||
require JSON::MaybeXS;
|
||||
import JSON::MaybeXS qw( decode_json encode_json );
|
||||
1;
|
||||
};
|
||||
|
||||
if ($@) {
|
||||
$@ = undef;
|
||||
} or do {
|
||||
|
||||
# try to use JSON wrapper
|
||||
# for chance of better performance
|
||||
eval {
|
||||
|
||||
# JSON preference order
|
||||
local $ENV{PERL_JSON_BACKEND} =
|
||||
'Cpanel::JSON::XS,JSON::XS,JSON::PP,JSON::backportPP'
|
||||
@ -95,10 +91,7 @@ if ($@) {
|
||||
require JSON;
|
||||
import JSON qw( decode_json encode_json );
|
||||
1;
|
||||
};
|
||||
|
||||
if ($@) {
|
||||
$@ = undef;
|
||||
} or do {
|
||||
|
||||
# In rare cases, Cpanel::JSON::XS may
|
||||
# be installed but JSON|JSON::MaybeXS not ...
|
||||
@ -106,10 +99,7 @@ if ($@) {
|
||||
require Cpanel::JSON::XS;
|
||||
import Cpanel::JSON::XS qw(decode_json encode_json);
|
||||
1;
|
||||
};
|
||||
|
||||
if ($@) {
|
||||
$@ = undef;
|
||||
} or do {
|
||||
|
||||
# In rare cases, JSON::XS may
|
||||
# be installed but JSON not ...
|
||||
@ -117,10 +107,7 @@ if ($@) {
|
||||
require JSON::XS;
|
||||
import JSON::XS qw(decode_json encode_json);
|
||||
1;
|
||||
};
|
||||
|
||||
if ($@) {
|
||||
$@ = undef;
|
||||
} or do {
|
||||
|
||||
# Fallback to built-in JSON which SHOULD
|
||||
# be available since 5.014 ...
|
||||
@ -128,20 +115,17 @@ if ($@) {
|
||||
require JSON::PP;
|
||||
import JSON::PP qw(decode_json encode_json);
|
||||
1;
|
||||
};
|
||||
|
||||
if ($@) {
|
||||
$@ = undef;
|
||||
} or do {
|
||||
|
||||
# Fallback to JSON::backportPP in really rare cases
|
||||
require JSON::backportPP;
|
||||
import JSON::backportPP qw(decode_json encode_json);
|
||||
1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
## Import der FHEM Funktionen
|
||||
#-- Run before package compilation
|
||||
@ -181,8 +165,8 @@ BEGIN {
|
||||
#-- Export to main context with different name
|
||||
GP_Export(
|
||||
qw(
|
||||
Initialize
|
||||
)
|
||||
Initialize
|
||||
)
|
||||
);
|
||||
|
||||
sub Initialize {
|
||||
@ -205,6 +189,7 @@ sub Initialize {
|
||||
$hash->{AttrFn} = \&Attr;
|
||||
$hash->{AttrList} =
|
||||
'debugJSON:0,1 '
|
||||
. 'debugDEVICE:0,1 '
|
||||
. 'disable:1 '
|
||||
. 'interval '
|
||||
. 'disabledForIntervals '
|
||||
@ -234,9 +219,7 @@ sub Define {
|
||||
my $name = shift @$aArg;
|
||||
$hash->{BRIDGE} = 1;
|
||||
$hash->{URL} =
|
||||
AttrVal( $name, 'gardenaBaseURL',
|
||||
'https://smart.gardena.com' )
|
||||
. '/v1';
|
||||
AttrVal( $name, 'gardenaBaseURL', 'https://smart.gardena.com' ) . '/v1';
|
||||
$hash->{VERSION} = version->parse($VERSION)->normal;
|
||||
$hash->{INTERVAL} = 60;
|
||||
$hash->{NOTIFYDEV} = "global,$name";
|
||||
@ -258,7 +241,7 @@ sub Undef {
|
||||
my $hash = shift;
|
||||
my $name = shift;
|
||||
|
||||
RemoveInternalTimer($hash);
|
||||
RemoveInternalTimer( $hash, "FHEM::GardenaSmartBridge::getDevices" );
|
||||
delete $modules{GardenaSmartBridge}{defptr}{BRIDGE}
|
||||
if ( defined( $modules{GardenaSmartBridge}{defptr}{BRIDGE} ) );
|
||||
|
||||
@ -279,7 +262,8 @@ sub Attr {
|
||||
|
||||
if ( $attrName eq 'disable' ) {
|
||||
if ( $cmd eq 'set' && $attrVal eq '1' ) {
|
||||
RemoveInternalTimer($hash);
|
||||
RemoveInternalTimer( $hash,
|
||||
"FHEM::GardenaSmartBridge::getDevices" );
|
||||
readingsSingleUpdate( $hash, 'state', 'inactive', 1 );
|
||||
Log3 $name, 3, "GardenaSmartBridge ($name) - disabled";
|
||||
}
|
||||
@ -304,13 +288,15 @@ sub Attr {
|
||||
if ( $cmd eq 'set' ) {
|
||||
return 'Interval must be greater than 0'
|
||||
if ( $attrVal == 0 );
|
||||
RemoveInternalTimer($hash);
|
||||
RemoveInternalTimer( $hash,
|
||||
"FHEM::GardenaSmartBridge::getDevices" );
|
||||
$hash->{INTERVAL} = $attrVal;
|
||||
Log3 $name, 3,
|
||||
"GardenaSmartBridge ($name) - set interval: $attrVal";
|
||||
}
|
||||
elsif ( $cmd eq 'del' ) {
|
||||
RemoveInternalTimer($hash);
|
||||
RemoveInternalTimer( $hash,
|
||||
"FHEM::GardenaSmartBridge::getDevices" );
|
||||
$hash->{INTERVAL} = 60;
|
||||
Log3 $name, 3,
|
||||
"GardenaSmartBridge ($name) - delete User interval and set default: 60";
|
||||
@ -352,25 +338,21 @@ sub Notify {
|
||||
@{$events} or grep /^DEFINED.$name$/,
|
||||
@{$events} or grep /^MODIFIED.$name$/,
|
||||
@{$events} or grep /^ATTR.$name.gardenaAccountEmail.+/,
|
||||
@{$events} or grep /^DELETEATTR.$name.disable$/,
|
||||
@{$events}
|
||||
)
|
||||
)
|
||||
|
||||
|| (
|
||||
$devtype eq 'GardenaSmartBridge'
|
||||
&& (
|
||||
grep /^gardenaAccountPassword.+/,
|
||||
@{$events}
|
||||
)
|
||||
)
|
||||
|| ( $devtype eq 'GardenaSmartBridge'
|
||||
&& ( grep /^gardenaAccountPassword.+/, @{$events} ) )
|
||||
&& $init_done
|
||||
);
|
||||
|
||||
getDevices($hash)
|
||||
if (
|
||||
$devtype eq 'Global'
|
||||
&& (
|
||||
grep /^DELETEATTR.$name.disable$/,
|
||||
@{$events} or grep /^ATTR.$name.disable.0$/,
|
||||
grep /^ATTR.$name.disable.0$/,
|
||||
@{$events} or grep /^DELETEATTR.$name.interval$/,
|
||||
@{$events} or grep /^ATTR.$name.interval.[0-9]+/,
|
||||
@{$events}
|
||||
@ -387,7 +369,6 @@ sub Notify {
|
||||
)
|
||||
)
|
||||
{
|
||||
|
||||
InternalTimer( gettimeofday() + $hash->{INTERVAL},
|
||||
"FHEM::GardenaSmartBridge::getDevices", $hash );
|
||||
Log3 $name, 4,
|
||||
@ -396,6 +377,7 @@ sub Notify {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub Get {
|
||||
my $hash = shift // return;
|
||||
my $aArg = shift // return;
|
||||
@ -407,15 +389,16 @@ sub Get {
|
||||
if ( lc $cmd eq 'debug_devices_list' ) {
|
||||
my $device = shift @$aArg;
|
||||
$hash->{helper}{debug_device} = $device;
|
||||
Write($hash, undef, undef, undef, undef);
|
||||
return undef;
|
||||
} else {
|
||||
Write( $hash, undef, undef, undef, undef );
|
||||
return;
|
||||
}
|
||||
else {
|
||||
my $list = "";
|
||||
$list .= " debug_devices_list:"
|
||||
.join( ',', @{ $hash->{helper}{deviceList} })
|
||||
if ( AttrVal( $name, "debugJSON", "none") ne "none"
|
||||
&& exists($hash->{helper}{deviceList}) );
|
||||
return "Unknown argument $cmd,choose one of $list";
|
||||
$list .=
|
||||
" debug_devices_list:" . join( ',', @{ $hash->{helper}{deviceList} } )
|
||||
if ( AttrVal( $name, "debugDEVICE", "none" ) ne "none"
|
||||
&& exists( $hash->{helper}{deviceList} ) );
|
||||
return "Unknown argument $cmd,choose one of $list";
|
||||
}
|
||||
}
|
||||
|
||||
@ -424,13 +407,13 @@ sub Set {
|
||||
my $aArg = shift // return;
|
||||
|
||||
my $name = shift @$aArg // return;
|
||||
my $cmd = shift @$aArg // return qq{"set $name" needs at least one argument};
|
||||
|
||||
my $cmd = shift @$aArg
|
||||
// return qq{"set $name" needs at least one argument};
|
||||
|
||||
# Das Argument für das Passwort, also das Passwort an sich darf keine = enthalten!!!
|
||||
|
||||
if ( lc $cmd eq 'getdevicesstate' ) {
|
||||
getDevices($hash);
|
||||
|
||||
}
|
||||
elsif ( lc $cmd eq 'gettoken' ) {
|
||||
return "please set Attribut gardenaAccountEmail first"
|
||||
@ -454,6 +437,15 @@ sub Set {
|
||||
|
||||
DeletePassword($hash);
|
||||
}
|
||||
elsif ( lc $cmd eq 'debughelper' ) {
|
||||
return "usage: $cmd" if ( scalar( @{$aArg} ) != 2 );
|
||||
my $new_helper = $aArg->[0];
|
||||
my $new_helper_value = $aArg->[1];
|
||||
Log3( $name, 5,
|
||||
"[DEBUG] - GardenaSmartBridge ($name) - override helper $new_helper with $new_helper_value"
|
||||
);
|
||||
$hash->{helper}{$new_helper} = $new_helper_value;
|
||||
}
|
||||
else {
|
||||
|
||||
my $list = "getDevicesState:noArg getToken:noArg"
|
||||
@ -475,20 +467,22 @@ sub Write {
|
||||
my ( $session_id, $header, $uri, $method );
|
||||
|
||||
( $payload, $session_id, $header, $uri, $method, $deviceId, $service_id ) =
|
||||
createHttpValueStrings( $hash, $payload, $deviceId, $abilities, $service_id );
|
||||
createHttpValueStrings( $hash, $payload, $deviceId, $abilities,
|
||||
$service_id );
|
||||
|
||||
HttpUtils_NonblockingGet(
|
||||
{
|
||||
url => $hash->{URL} . $uri,
|
||||
timeout => 15,
|
||||
hash => $hash,
|
||||
device_id => $deviceId,
|
||||
data => $payload,
|
||||
method => $method,
|
||||
header => $header,
|
||||
doTrigger => 1,
|
||||
cl => $hash->{CL},
|
||||
callback => \&ErrorHandling
|
||||
url => $hash->{URL} . $uri,
|
||||
timeout => 15,
|
||||
incrementalTimeout => 1,
|
||||
hash => $hash,
|
||||
device_id => $deviceId,
|
||||
data => $payload,
|
||||
method => $method,
|
||||
header => $header,
|
||||
doTrigger => 1,
|
||||
cl => $hash->{CL},
|
||||
callback => \&ErrorHandling
|
||||
}
|
||||
);
|
||||
|
||||
@ -496,8 +490,8 @@ sub Write {
|
||||
"GardenaSmartBridge ($name) - Send with URL: $hash->{URL}$uri, HEADER: secret!, DATA: secret!, METHOD: $method"
|
||||
);
|
||||
|
||||
# Log3($name, 3,
|
||||
# "GardenaSmartBridge ($name) - Send with URL: $hash->{URL}$uri, HEADER: $header, DATA: $payload, METHOD: $method");
|
||||
# Log3($name, 3,
|
||||
# "GardenaSmartBridge ($name) - Send with URL: $hash->{URL}$uri, HEADER: $header, DATA: $payload, METHOD: $method");
|
||||
|
||||
return;
|
||||
}
|
||||
@ -515,10 +509,10 @@ sub ErrorHandling {
|
||||
if ( defined( $param->{'device_id'} ) );
|
||||
|
||||
my $dname = $dhash->{NAME};
|
||||
|
||||
|
||||
Log3 $name, 4, "GardenaSmartBridge ($name) - Request: $data";
|
||||
|
||||
my $decode_json = eval { decode_json($data) };
|
||||
|
||||
my $decode_json = eval { decode_json($data) } if ( length($data) > 0 );
|
||||
if ($@) {
|
||||
Log3 $name, 3, "GardenaSmartBridge ($name) - JSON error while request";
|
||||
}
|
||||
@ -534,7 +528,6 @@ sub ErrorHandling {
|
||||
1 );
|
||||
|
||||
if ( $err =~ /timed out/ ) {
|
||||
|
||||
Log3 $dname, 5,
|
||||
"GardenaSmartBridge ($dname) - RequestERROR: connect to gardena cloud is timed out. check network";
|
||||
}
|
||||
@ -620,7 +613,7 @@ sub ErrorHandling {
|
||||
}
|
||||
|
||||
if (
|
||||
$data =~ /Error/
|
||||
$data =~ /Error/ && $data !~ /lastLonaErrorCode/
|
||||
|| ( defined($decode_json)
|
||||
&& ref($decode_json) eq 'HASH'
|
||||
&& defined( $decode_json->{errors} ) )
|
||||
@ -698,6 +691,11 @@ sub ErrorHandling {
|
||||
. $param->{code};
|
||||
}
|
||||
|
||||
if ( !defined( $hash->{helper}{session_id} ) ) {
|
||||
readingsSingleUpdate( $hash, 'token', 'none', 1 );
|
||||
InternalTimer( gettimeofday() + 5,
|
||||
"FHEM::GardenaSmartBridge::getToken", $hash );
|
||||
}
|
||||
readingsEndUpdate( $dhash, 1 );
|
||||
|
||||
Log3 $dname, 5,
|
||||
@ -710,30 +708,59 @@ sub ErrorHandling {
|
||||
|
||||
return;
|
||||
}
|
||||
if (defined($hash->{helper}{debug_device})){
|
||||
Log3 $name, 5, "GardenaSmartBridge DEBUG Device";
|
||||
my @device_spec = ("name", "id", "category");
|
||||
my $devJson=$decode_json->{devices};
|
||||
my $output = '.:{ DEBUG OUTPUT for '.$devJson->{name}.' }:. \n';
|
||||
for my $spec (@device_spec) {
|
||||
$output .= "$spec : $devJson->{$spec} \n";
|
||||
}
|
||||
#settings
|
||||
$output .= '\n=== Settings \n';
|
||||
my $i = 0;
|
||||
for my $dev_settings ( @ { $devJson->{settings} } ) {
|
||||
$output .= "[".$i++."]id: $dev_settings->{id} \n";
|
||||
$output .= "name: $dev_settings->{name} ";
|
||||
if (ref ($dev_settings->{value}) eq 'ARRAY'
|
||||
|| ref ($dev_settings->{value}) eq 'HASH'){
|
||||
$output .= 'N/A \n';
|
||||
} else {
|
||||
$output .= "value: $dev_settings->{value} \n";
|
||||
elsif ( defined( $decode_json->{message} )
|
||||
&& $decode_json->{message} eq 'Unauthorized' )
|
||||
{
|
||||
Log3 $name, 3,
|
||||
"GardenaSmartBridge ($name) - Unauthorized -> fetch new token ";
|
||||
|
||||
getToken($hash);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( defined( $hash->{helper}{debug_device} )
|
||||
&& $hash->{helper}{debug_device} ne 'none' )
|
||||
{
|
||||
Log3 $name, 4, "GardenaSmartBridge DEBUG Device";
|
||||
delete $hash->{helper}{debug_device};
|
||||
|
||||
my @device_spec = ( "name", "id", "category" );
|
||||
my $devJson = $decode_json->{devices};
|
||||
my $output = '.:{ DEBUG OUTPUT for ' . $devJson->{name} . ' }:. \n';
|
||||
|
||||
for my $spec (@device_spec) {
|
||||
$output .= "$spec : $devJson->{$spec} \n";
|
||||
}
|
||||
}
|
||||
$hash->{helper}{debug_device_output} = $output;
|
||||
asyncOutput($param->{cl}, $hash->{helper}{debug_device_output});
|
||||
return;
|
||||
|
||||
#settings
|
||||
$output .= '\n=== Settings \n';
|
||||
my $i = 0;
|
||||
for my $dev_settings ( @{ $devJson->{settings} } ) {
|
||||
$output .= "[" . $i++ . "]id: $dev_settings->{id} \n";
|
||||
$output .= "name: $dev_settings->{name} \n";
|
||||
if ( ref( $dev_settings->{value} ) eq 'ARRAY'
|
||||
|| ref( $dev_settings->{value} ) eq 'HASH' )
|
||||
{
|
||||
$output .= 'N/A \n';
|
||||
}
|
||||
else {
|
||||
$output .= "value: $dev_settings->{value} \n";
|
||||
}
|
||||
}
|
||||
|
||||
$output .= '\n=== Abilities \n';
|
||||
$i = 0;
|
||||
|
||||
for my $dev_settings ( @{ $devJson->{abilities} } ) {
|
||||
$output .= "[" . $i++ . "]id: $dev_settings->{id} \n";
|
||||
$output .= "name: $dev_settings->{name} \n";
|
||||
}
|
||||
|
||||
$hash->{helper}{debug_device_output} = $output;
|
||||
asyncOutput( $param->{cl}, $hash->{helper}{debug_device_output} );
|
||||
|
||||
return;
|
||||
}
|
||||
readingsSingleUpdate( $hash, 'state', 'Connected', 1 )
|
||||
if ( defined( $hash->{helper}{locations_id} ) );
|
||||
@ -762,15 +789,21 @@ sub ResponseProcessing {
|
||||
}
|
||||
}
|
||||
|
||||
# print Dumper $decode_json;
|
||||
if ( defined( $decode_json->{data} )
|
||||
&& $decode_json->{data}
|
||||
&& ref( $decode_json->{data} ) eq 'HASH'
|
||||
&& !defined( $hash->{helper}->{user_id} ) )
|
||||
{
|
||||
|
||||
if ( defined( $decode_json->{data} ) && $decode_json->{data}
|
||||
&& ref($decode_json->{data}) eq 'HASH'
|
||||
&& !defined( $hash->{helper}->{user_id})) {
|
||||
$hash->{helper}{session_id} = $decode_json->{data}{id};
|
||||
$hash->{helper}{user_id} = $decode_json->{data}{attributes}->{user_id};
|
||||
$hash->{helper}{refresh_token} =
|
||||
$decode_json->{data}{attributes}->{refresh_token};
|
||||
$hash->{helper}{token_expired} =
|
||||
gettimeofday() + $decode_json->{data}{attributes}->{expires_in};
|
||||
|
||||
$hash->{helper}{session_id} = $decode_json->{data}{id};
|
||||
$hash->{helper}{user_id} = $decode_json->{data}{attributes}->{user_id};
|
||||
$hash->{helper}{refresh_token} = $decode_json->{data}{attributes}->{refresh_token};
|
||||
InternalTimer( $hash->{helper}{token_expired},
|
||||
"FHEM::GardenaSmartBridge::getToken", $hash );
|
||||
|
||||
Write( $hash, undef, undef, undef );
|
||||
Log3 $name, 3, "GardenaSmartBridge ($name) - fetch locations id";
|
||||
@ -802,51 +835,36 @@ sub ResponseProcessing {
|
||||
&& ref( $decode_json->{devices} ) eq 'ARRAY'
|
||||
&& scalar( @{ $decode_json->{devices} } ) > 0 )
|
||||
{
|
||||
|
||||
my @buffer = split( '"devices":\[', $json );
|
||||
|
||||
my ( $json, $tail ) = ParseJSON( $hash, $buffer[1] );
|
||||
require SubProcess;
|
||||
|
||||
while ($json) {
|
||||
my $subprocess =
|
||||
SubProcess->new( { onRun => \&ResponseSubprocessing } );
|
||||
$subprocess->{buffer} = $buffer[1];
|
||||
|
||||
Log3 $name, 5,
|
||||
"GardenaSmartBridge ($name) - Decoding JSON message. Length: "
|
||||
. length($json)
|
||||
. " Content: "
|
||||
. $json;
|
||||
Log3 $name, 5,
|
||||
"GardenaSmartBridge ($name) - Vor Sub: Laenge JSON: "
|
||||
. length($json)
|
||||
. " Content: "
|
||||
. $json
|
||||
. " Tail: "
|
||||
. $tail;
|
||||
my $pid = $subprocess->run();
|
||||
|
||||
if ( defined($tail) and $tail ) {
|
||||
$decode_json = eval { decode_json($json) };
|
||||
if ($@) {
|
||||
Log3 $name, 5,
|
||||
"GardenaSmartBridge ($name) - JSON error while request: $@";
|
||||
}
|
||||
if ( !defined($pid) ) {
|
||||
Log3( $name, 1,
|
||||
qq{GardenaSmartBridge ($name) - Cannot execute parse json asynchronously}
|
||||
);
|
||||
|
||||
Dispatch( $hash, $json, undef )
|
||||
if ( $decode_json->{category} ne 'gateway' );
|
||||
WriteReadings( $hash, $decode_json )
|
||||
if ( defined( $decode_json->{category} )
|
||||
&& $decode_json->{category} eq 'gateway' );
|
||||
}
|
||||
|
||||
( $json, $tail ) = ParseJSON( $hash, $tail );
|
||||
|
||||
Log3 $name, 5,
|
||||
"GardenaSmartBridge ($name) - Nach Sub: Laenge JSON: "
|
||||
. length($json)
|
||||
. " Content: "
|
||||
. $json
|
||||
. " Tail: "
|
||||
. $tail;
|
||||
CleanSubprocess($hash);
|
||||
readingsSingleUpdate( $hash, 'state',
|
||||
'Cannot execute parse json asynchronously', 1 );
|
||||
return;
|
||||
}
|
||||
|
||||
Log3( $name, 4,
|
||||
qq{GardenaSmartBridge ($name) - execute parse json asynchronously (PID="$pid")}
|
||||
);
|
||||
|
||||
$hash->{".fhem"}{subprocess} = $subprocess;
|
||||
|
||||
InternalTimer( gettimeofday() + 1,
|
||||
"FHEM::GardenaSmartBridge::PollChild", $hash );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -855,12 +873,148 @@ sub ResponseProcessing {
|
||||
return;
|
||||
}
|
||||
|
||||
sub ResponseProcessingFinalFromSubProcessing {
|
||||
my $hash = shift;
|
||||
my $response = shift;
|
||||
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
my @response = split '\|,', $response;
|
||||
|
||||
Log3( $name, 4,
|
||||
qq{GardenaSmartBridge ($name) - got result from asynchronous parsing} );
|
||||
|
||||
my $decode_json;
|
||||
|
||||
Log3( $name, 4, qq{GardenaSmartBridge ($name) - asynchronous finished.} );
|
||||
|
||||
if ( scalar(@response) > 0 ) {
|
||||
for my $json (@response) {
|
||||
|
||||
#################
|
||||
$decode_json = eval { decode_json($json) };
|
||||
if ($@) {
|
||||
Log3 $name, 5,
|
||||
"GardenaSmartBridge ($name) - JSON error while request: $@";
|
||||
}
|
||||
|
||||
Dispatch( $hash, $json, undef )
|
||||
if ( $decode_json->{category} ne 'gateway' );
|
||||
WriteReadings( $hash, $decode_json )
|
||||
if ( defined( $decode_json->{category} )
|
||||
&& $decode_json->{category} eq 'gateway' );
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub PollChild {
|
||||
my $hash = shift;
|
||||
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
if ( defined( $hash->{".fhem"}{subprocess} ) ) {
|
||||
my $subprocess = $hash->{".fhem"}{subprocess};
|
||||
my $response = $subprocess->readFromChild();
|
||||
|
||||
if ( defined($response) ) {
|
||||
ResponseProcessingFinalFromSubProcessing( $hash, $response );
|
||||
$subprocess->wait();
|
||||
CleanSubprocess($hash);
|
||||
}
|
||||
|
||||
Log3( $name, 4,
|
||||
qq{GardenaSmartBridge ($name) - still waiting ($subprocess->{lasterror}).}
|
||||
);
|
||||
|
||||
InternalTimer( gettimeofday() + 1,
|
||||
"FHEM::GardenaSmartBridge::PollChild", $hash );
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# ResponseSubprocessin muss in eine async ausgelagert werden
|
||||
######################################
|
||||
# Begin Childprozess
|
||||
######################################
|
||||
sub ResponseSubprocessing {
|
||||
my $subprocess = shift;
|
||||
my $buffer = $subprocess->{buffer};
|
||||
my @response = ();
|
||||
|
||||
my ( $json, $tail ) = ParseJSON($buffer);
|
||||
|
||||
while ($json) {
|
||||
if ( defined($tail) and $tail ) {
|
||||
push @response, $json;
|
||||
}
|
||||
|
||||
( $json, $tail ) = ParseJSON($tail);
|
||||
}
|
||||
|
||||
$subprocess->writeToParent( join '|', @response );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub ParseJSON {
|
||||
my $buffer = shift;
|
||||
|
||||
my $open = 0;
|
||||
my $close = 0;
|
||||
my $msg = '';
|
||||
my $tail = '';
|
||||
|
||||
if ($buffer) {
|
||||
for my $c ( split //, $buffer ) {
|
||||
if ( $open == $close && $open > 0 ) {
|
||||
$tail .= $c;
|
||||
}
|
||||
else {
|
||||
|
||||
if ( $c eq '{' ) {
|
||||
|
||||
$open++;
|
||||
|
||||
}
|
||||
elsif ( $c eq '}' ) {
|
||||
|
||||
$close++;
|
||||
}
|
||||
|
||||
$msg .= $c;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $open != $close ) {
|
||||
|
||||
$tail = $msg;
|
||||
$msg = '';
|
||||
}
|
||||
}
|
||||
|
||||
return ( $msg, $tail );
|
||||
}
|
||||
######################################
|
||||
# End Childprozess
|
||||
######################################
|
||||
|
||||
sub CleanSubprocess {
|
||||
my $hash = shift;
|
||||
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
delete( $hash->{".fhem"}{subprocess} );
|
||||
Log3( $name, 4, qq{GardenaSmartBridge ($name) - clean Subprocess} );
|
||||
}
|
||||
|
||||
sub WriteReadings {
|
||||
my $hash = shift;
|
||||
my $decode_json = shift;
|
||||
|
||||
# print Dumper $decode_json;
|
||||
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
if ( defined( $decode_json->{id} )
|
||||
@ -904,8 +1058,9 @@ sub WriteReadings {
|
||||
$decode_json->{abilities}[0]{properties}[$properties]
|
||||
{name} . '-' . $t,
|
||||
$v
|
||||
)
|
||||
if ($decode_json->{abilities}[0]{properties}[$properties]{name} !~ /ethernet_status|wifi_status/ );
|
||||
)
|
||||
if ( $decode_json->{abilities}[0]{properties}[$properties]
|
||||
{name} !~ /ethernet_status|wifi_status/ );
|
||||
if (
|
||||
(
|
||||
$decode_json->{abilities}[0]{properties}
|
||||
@ -931,10 +1086,9 @@ sub WriteReadings {
|
||||
elsif ( $decode_json->{abilities}[0]{properties}
|
||||
[$properties]{name} eq 'wifi_status' )
|
||||
{
|
||||
#TODO: read valies if bridge connected to wifi
|
||||
readingsBulkUpdateIfChanged( $hash,
|
||||
'wifi_status-ssid', $v->{ssid} )
|
||||
if (ref($v->{ssid}) ne 'HASH');
|
||||
'wifi_status-ssid', $v->{ssid} )
|
||||
if ( ref( $v->{ssid} ) ne 'HASH' );
|
||||
readingsBulkUpdateIfChanged( $hash,
|
||||
'wifi_status-mac', $v->{mac} );
|
||||
readingsBulkUpdateIfChanged( $hash,
|
||||
@ -967,23 +1121,25 @@ sub getDevices {
|
||||
my $hash = shift;
|
||||
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
RemoveInternalTimer($hash);
|
||||
RemoveInternalTimer( $hash, "FHEM::GardenaSmartBridge::getDevices" );
|
||||
|
||||
if ( not IsDisabled($name) ) {
|
||||
|
||||
delete $hash->{helper}{deviceList};
|
||||
my @list;
|
||||
@list = devspec2array('TYPE=GardenaSmartDevice');
|
||||
for my $gardenaDev (@list){
|
||||
push( @{ $hash->{helper}{deviceList} }, $gardenaDev );
|
||||
for my $gardenaDev (@list) {
|
||||
push( @{ $hash->{helper}{deviceList} }, $gardenaDev );
|
||||
}
|
||||
Write( $hash, undef, undef, undef );
|
||||
Log3 $name, 4,
|
||||
"GardenaSmartBridge ($name) - fetch device list and device states";
|
||||
if ( AttrVal( $name, 'gardenaAccountEmail', 'none' ) ne 'none'
|
||||
&& ( defined( ReadPassword( $hash, $name ) ) ) )
|
||||
{
|
||||
Write( $hash, undef, undef, undef );
|
||||
Log3 $name, 4,
|
||||
"GardenaSmartBridge ($name) - fetch device list and device states";
|
||||
} # fi gardenaAccountEmail
|
||||
}
|
||||
else {
|
||||
|
||||
readingsSingleUpdate( $hash, 'state', 'disabled', 1 );
|
||||
Log3 $name, 3, "GardenaSmartBridge ($name) - device is disabled";
|
||||
}
|
||||
@ -1005,36 +1161,29 @@ sub getToken {
|
||||
readingsSingleUpdate( $hash, 'state', 'get token', 1 );
|
||||
|
||||
delete $hash->{helper}{session_id}
|
||||
if ( defined( $hash->{helper}{session_id} )
|
||||
&& $hash->{helper}{session_id} );
|
||||
if ( exists( $hash->{helper}{session_id} ) );
|
||||
delete $hash->{helper}{user_id}
|
||||
if ( defined( $hash->{helper}{user_id} ) && $hash->{helper}{user_id} );
|
||||
if ( exists( $hash->{helper}{user_id} ) );
|
||||
delete $hash->{helper}{locations_id}
|
||||
if ( defined( $hash->{helper}{locations_id} )
|
||||
&& $hash->{helper}{locations_id} );
|
||||
if ( exists( $hash->{helper}{locations_id} ) );
|
||||
|
||||
# Write(
|
||||
# $hash,
|
||||
# '"sessions": {"email": "'
|
||||
# . AttrVal( $name, 'gardenaAccountEmail', 'none' )
|
||||
# . '","password": "'
|
||||
# . ReadPassword( $hash, $name ) . '"}',
|
||||
# undef,
|
||||
# undef
|
||||
# );
|
||||
|
||||
Write(
|
||||
$hash,
|
||||
'"data": {"type":"token", "attributes":{"username": "'
|
||||
. AttrVal( $name, 'gardenaAccountEmail', 'none' )
|
||||
. '","password": "'
|
||||
. ReadPassword( $hash, $name ) . '", "client_id":"smartgarden-jwt-client"}}',
|
||||
undef,
|
||||
undef
|
||||
);
|
||||
$hash,
|
||||
'"data": {"type":"token", "attributes":{"username": "'
|
||||
. AttrVal( $name, 'gardenaAccountEmail', 'none' )
|
||||
. '","password": "'
|
||||
. ReadPassword( $hash, $name )
|
||||
. '", "client_id":"smartgarden-jwt-client"}}',
|
||||
undef,
|
||||
undef
|
||||
);
|
||||
|
||||
Log3 $name, 4, '"data": {"type":"token", "attributes":{"username": "' . AttrVal( $name, 'gardenaAccountEmail', 'none' ) . '","password": "'
|
||||
. ReadPassword( $hash, $name ) . '", "client_id":"smartgarden-jwt-client"}}';
|
||||
Log3 $name, 4,
|
||||
'"data": {"type":"token", "attributes":{"username": "'
|
||||
. AttrVal( $name, 'gardenaAccountEmail', 'none' )
|
||||
. '","password": "'
|
||||
. ReadPassword( $hash, $name )
|
||||
. '", "client_id":"smartgarden-jwt-client"}}';
|
||||
Log3 $name, 3,
|
||||
"GardenaSmartBridge ($name) - send credentials to fetch Token and locationId";
|
||||
|
||||
@ -1085,7 +1234,7 @@ sub ReadPassword {
|
||||
|
||||
Log3 $name, 3,
|
||||
"GardenaSmartBridge ($name) - unable to read password from file: $err";
|
||||
return undef;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
@ -1111,7 +1260,7 @@ sub ReadPassword {
|
||||
else {
|
||||
|
||||
Log3 $name, 3, "GardenaSmartBridge ($name) - No password in file";
|
||||
return undef;
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
@ -1129,59 +1278,6 @@ sub Rename {
|
||||
return;
|
||||
}
|
||||
|
||||
sub ParseJSON {
|
||||
my $hash = shift;
|
||||
my $buffer = shift;
|
||||
|
||||
my $name = $hash->{NAME};
|
||||
my $open = 0;
|
||||
my $close = 0;
|
||||
my $msg = '';
|
||||
my $tail = '';
|
||||
|
||||
if ($buffer) {
|
||||
for my $c ( split //, $buffer ) {
|
||||
if ( $open == $close && $open > 0 ) {
|
||||
$tail .= $c;
|
||||
Log3 $name, 5,
|
||||
"GardenaSmartBridge ($name) - $open == $close and $open > 0";
|
||||
|
||||
}
|
||||
elsif ( ( $open == $close ) && ( $c ne '{' ) ) {
|
||||
|
||||
Log3 $name, 5,
|
||||
"GardenaSmartBridge ($name) - Garbage character before message: "
|
||||
. $c;
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
if ( $c eq '{' ) {
|
||||
|
||||
$open++;
|
||||
|
||||
}
|
||||
elsif ( $c eq '}' ) {
|
||||
|
||||
$close++;
|
||||
}
|
||||
|
||||
$msg .= $c;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $open != $close ) {
|
||||
|
||||
$tail = $msg;
|
||||
$msg = '';
|
||||
}
|
||||
}
|
||||
|
||||
Log3 $name, 5,
|
||||
"GardenaSmartBridge ($name) - return msg: $msg and tail: $tail";
|
||||
return ( $msg, $tail );
|
||||
}
|
||||
|
||||
sub createHttpValueStrings {
|
||||
my ( $hash, $payload, $deviceId, $abilities, $service_id ) = @_;
|
||||
|
||||
@ -1190,30 +1286,33 @@ sub createHttpValueStrings {
|
||||
my $uri = '';
|
||||
my $method = 'POST';
|
||||
$header .= "\r\nAuthorization: Bearer $session_id"
|
||||
if ( defined($hash->{helper}{session_id}) );
|
||||
if ( defined( $hash->{helper}{session_id} ) );
|
||||
$header .= "\r\nAuthorization-Provider: husqvarna"
|
||||
if ( defined($hash->{helper}{session_id}) );
|
||||
if ( defined( $hash->{helper}{session_id} ) );
|
||||
|
||||
# $header .= "\r\nx-api-key: $session_id"
|
||||
# if ( defined( $hash->{helper}{session_id} ) );
|
||||
$payload = '{' . $payload . '}' if ( defined($payload) );
|
||||
$payload = '{}' if ( !defined($payload) );
|
||||
$payload = '{}' if ( !defined($payload) );
|
||||
|
||||
if ( $payload eq '{}' ) {
|
||||
$method = 'GET';
|
||||
$method = 'GET' if ( defined( $hash->{helper}{session_id} ) );
|
||||
$payload = '';
|
||||
$uri .= '/locations?locatioId=null&user_id=' . $hash->{helper}{user_id}
|
||||
if ( exists( $hash->{helper}{user_id} )
|
||||
&& !defined( $hash->{helper}{locations_id} ) );
|
||||
readingsSingleUpdate( $hash, 'state', 'fetch locationId', 1 )
|
||||
if ( !defined( $hash->{helper}{locations_id} ) );
|
||||
$uri .= '/auth/token' if ( !defined( $hash->{helper}{session_id} ) );
|
||||
if ( exists( $hash->{helper}{user_id} )
|
||||
&& !defined( $hash->{helper}{locations_id} ) );
|
||||
$uri .= '/devices'
|
||||
if (!defined($abilities)
|
||||
&& defined( $hash->{helper}{locations_id} ) );
|
||||
}
|
||||
|
||||
$uri = '/devices/'.InternalVal($hash->{helper}{debug_device}, 'DEVICEID', 0 ) if ( exists ($hash->{helper}{debug_device}));
|
||||
$uri =
|
||||
'/devices/' . InternalVal( $hash->{helper}{debug_device}, 'DEVICEID', 0 )
|
||||
if ( defined( $hash->{helper}{debug_device} )
|
||||
&& defined( $hash->{helper}{locations_id} ) );
|
||||
$uri = '/auth/token' if ( !defined( $hash->{helper}{session_id} ) );
|
||||
|
||||
if ( defined( $hash->{helper}{locations_id} ) ) {
|
||||
@ -1221,17 +1320,13 @@ sub createHttpValueStrings {
|
||||
|
||||
$method = 'PUT';
|
||||
my $dhash = $modules{GardenaSmartDevice}{defptr}{$deviceId};
|
||||
|
||||
$uri .=
|
||||
'/devices/'
|
||||
. $deviceId
|
||||
. '/settings/'
|
||||
. $service_id
|
||||
|
||||
$uri .= '/devices/' . $deviceId . '/settings/' . $service_id
|
||||
if ( defined($abilities)
|
||||
&& defined($payload)
|
||||
&& $abilities =~ /.*_settings/ );
|
||||
|
||||
} # park until next schedules or override
|
||||
} # park until next schedules or override
|
||||
elsif (defined($abilities)
|
||||
&& defined($payload)
|
||||
&& $abilities eq 'mower_timer' )
|
||||
@ -1254,7 +1349,7 @@ sub createHttpValueStrings {
|
||||
my $valve_id;
|
||||
|
||||
if ( $payload =~ m#watering_timer_(\d)# ) {
|
||||
$method = 'PUT';
|
||||
$method = 'PUT';
|
||||
$valve_id = $1;
|
||||
}
|
||||
$uri .=
|
||||
@ -1262,7 +1357,11 @@ sub createHttpValueStrings {
|
||||
. $deviceId
|
||||
. '/abilities/'
|
||||
. $abilities
|
||||
. ( defined($valve_id) ? '/properties/watering_timer_'. $valve_id : '/command')
|
||||
. (
|
||||
defined($valve_id)
|
||||
? '/properties/watering_timer_' . $valve_id
|
||||
: '/command'
|
||||
);
|
||||
|
||||
}
|
||||
elsif (defined($abilities)
|
||||
@ -1279,6 +1378,19 @@ sub createHttpValueStrings {
|
||||
. $abilities
|
||||
. '/properties/manual_watering_timer';
|
||||
|
||||
}
|
||||
elsif (defined($abilities)
|
||||
&& defined($payload)
|
||||
&& $abilities eq 'watering_button_config' )
|
||||
{
|
||||
$method = 'PUT';
|
||||
|
||||
$uri .=
|
||||
'/devices/'
|
||||
. $deviceId
|
||||
. '/abilities/watering'
|
||||
. '/properties/button_config_time';
|
||||
|
||||
}
|
||||
elsif (defined($abilities)
|
||||
&& defined($payload)
|
||||
@ -1463,9 +1575,9 @@ sub DeletePassword {
|
||||
],
|
||||
"release_status": "stable",
|
||||
"license": "GPL_2",
|
||||
"version": "v2.4.0",
|
||||
"version": "v2.6.0",
|
||||
"author": [
|
||||
"Marko Oldenburg <leongaultier@gmail.com>"
|
||||
"Marko Oldenburg <fhemdevelopment@cooltux.net>"
|
||||
],
|
||||
"x_fhem_maintainer": [
|
||||
"CoolTux"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,2 +1,2 @@
|
||||
UPD 2021-05-22_04:53:56 46135 FHEM/73_GardenaSmartBridge.pm
|
||||
UPD 2021-05-22_04:54:14 51644 FHEM/74_GardenaSmartDevice.pm
|
||||
UPD 2023-01-10_09:49:28 49646 FHEM/73_GardenaSmartBridge.pm
|
||||
UPD 2023-01-10_09:49:45 126305 FHEM/74_GardenaSmartDevice.pm
|
||||
|
36
hooks/commit-msg
Executable file
36
hooks/commit-msg
Executable file
@ -0,0 +1,36 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message.
|
||||
# Called by "git commit" with one argument, the name of the file
|
||||
# that has the commit message. The hook should exit with non-zero
|
||||
# status after issuing an appropriate message if it wants to stop the
|
||||
# commit. The hook is allowed to edit the commit message file.
|
||||
#
|
||||
# To enable this hook, rename this file to "commit-msg".
|
||||
|
||||
# Uncomment the below to add a Signed-off-by line to the message.
|
||||
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
|
||||
# hook is more suited to it.
|
||||
#
|
||||
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
||||
|
||||
# This example catches duplicate Signed-off-by lines.
|
||||
|
||||
commit_msg=$(cat "${1:?Missing commit message file}")
|
||||
|
||||
test "" = "$(grep '^Signed-off-by: ' "$1" |
|
||||
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
|
||||
echo >&2 Duplicate Signed-off-by lines.
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ! echo "$commit_msg" | grep -Eq "^(build|chore|ci|docs|feat|feat!|fix|perf|refactor|revert|style|test)(\(.+\))?: .*$" ; then
|
||||
|
||||
echo "Invalid commit message"
|
||||
|
||||
exit 1
|
||||
|
||||
fi
|
||||
|
||||
echo "Commit message is valid!"
|
18
hooks/post-commit
Executable file
18
hooks/post-commit
Executable file
@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
set -eu
|
||||
|
||||
# destination of the final changelog file
|
||||
OUTPUT_FILE=CHANGELOG.md
|
||||
|
||||
# generate the changelog
|
||||
git --no-pager log --no-merges --format="### %s%d%n>%aD%n%n>Author: %aN (%aE)%n%n>Commiter: %cN (%cE)%n%n%b%n%N%n" > $OUTPUT_FILE
|
||||
|
||||
# prevent recursion!
|
||||
# since a 'commit --amend' will trigger the post-commit script again
|
||||
# we have to check if the changelog file has changed or not
|
||||
res=$(git status --porcelain | grep -c ".\$OUTPUT_FILE$")
|
||||
if [ "$res" -gt 0 ]; then
|
||||
git add $OUTPUT_FILE
|
||||
git commit --amend
|
||||
echo "Populated Changelog in $OUTPUT_FILE"
|
||||
fi
|
Reference in New Issue
Block a user