Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
be340b36d4 | |||
265f0d4ffa | |||
f0697c82f7 | |||
0826afa7d9 | |||
c671e48e6f | |||
c9ae34f0c4 | |||
b4c5586ce7 | |||
602ee3f512 | |||
78905b02d4 | |||
fecb5a1fa0 |
170
98_TadoAPI.pm
170
98_TadoAPI.pm
@ -1,5 +1,5 @@
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
# $Id: 98_TadoAPI.pm 107 2025-03-10 06:15:20Z psycho160 $
|
# $Id: 98_TadoAPI.pm 107 2025-04-07 06:15:20Z psycho160 $
|
||||||
#
|
#
|
||||||
# FILE: 98_TadoAPI.pm
|
# FILE: 98_TadoAPI.pm
|
||||||
# - for oauth2 (2025)
|
# - for oauth2 (2025)
|
||||||
@ -58,17 +58,17 @@ my %gets = (
|
|||||||
"getZoneDevices" => "noArg",
|
"getZoneDevices" => "noArg",
|
||||||
"getZoneInfo" => "noArg",
|
"getZoneInfo" => "noArg",
|
||||||
"getGeo" => "",
|
"getGeo" => "",
|
||||||
|
|
||||||
"getDeviceCode" => "noArg",
|
"getDeviceCode" => "noArg",
|
||||||
"getMobileDevices" => "noArg"
|
"getMobileDevices" => "noArg"
|
||||||
);
|
);
|
||||||
|
|
||||||
sub TadoAPI_Initialize {
|
sub TadoAPI_Initialize {
|
||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
my $TYPE = "TadoAPI";
|
|
||||||
|
|
||||||
$hash->{DefFn} = \&TadoAPI_Define;
|
$hash->{DefFn} = \&TadoAPI_Define;
|
||||||
$hash->{InitFn} = \&TadoAPI_Init;
|
$hash->{InitFn} = \&TadoAPI_Init;
|
||||||
|
$hash->{UndefFn} = \&TadoAPI_Undefine;
|
||||||
|
$hash->{DeleteFn} = \&TadoAPI_Delete;
|
||||||
$hash->{SetFn} = \&TadoAPI_Set;
|
$hash->{SetFn} = \&TadoAPI_Set;
|
||||||
$hash->{GetFn} = \&TadoAPI_Get;
|
$hash->{GetFn} = \&TadoAPI_Get;
|
||||||
$hash->{AttrList} = ""
|
$hash->{AttrList} = ""
|
||||||
@ -87,9 +87,8 @@ sub TadoAPI_Init {
|
|||||||
my $def = shift;
|
my $def = shift;
|
||||||
|
|
||||||
my @args = split( "[ \t][ \t]*", $def );
|
my @args = split( "[ \t][ \t]*", $def );
|
||||||
|
|
||||||
my $u =
|
my $u = "wrong syntax: define <name> TadoAPI <device_code>";
|
||||||
"wrong syntax: define <name> TadoAPI <username>";
|
|
||||||
return $u if ( int(@args) < 2 );
|
return $u if ( int(@args) < 2 );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -103,17 +102,19 @@ sub TadoAPI_Define {
|
|||||||
my $type = shift @a;
|
my $type = shift @a;
|
||||||
my $tokenFileName = $tokenFile . "_" . $name;
|
my $tokenFileName = $tokenFile . "_" . $name;
|
||||||
|
|
||||||
my ( $user, $homeID ) = @a;
|
my ( $dev_code ) = @a;
|
||||||
Log3 $name, 3, "TadoAPI_Define $name: called ";
|
Log3 $name, 3, "TadoAPI_Define $name: called ";
|
||||||
$hash->{STATE} = "defined";
|
|
||||||
|
my $u = "wrong define syntax: define <name> TadoAPI";
|
||||||
|
return $u if ( int(@a) > 1 );
|
||||||
|
|
||||||
|
defined $dev_code ? ($hash->{STATE} = "defined") : ($hash->{DEF} = "no_device_code_set");
|
||||||
|
|
||||||
# Initialize the device
|
# Initialize the device
|
||||||
return $@ unless ( FHEM::Meta::SetInternals($hash) );
|
return $@ unless ( FHEM::Meta::SetInternals($hash) );
|
||||||
|
|
||||||
$hash->{TOKEN_FILE} = $tokenFileName;
|
$hash->{TOKEN_FILE} = $tokenFileName;
|
||||||
$hash->{TADO_USER} = $user;
|
$hash->{TADO_DEV_CODE} = $dev_code;
|
||||||
|
|
||||||
my @args = ($homeID);
|
|
||||||
|
|
||||||
if ($main::init_done) {
|
if ($main::init_done) {
|
||||||
|
|
||||||
@ -121,26 +122,22 @@ sub TadoAPI_Define {
|
|||||||
return TadoAPI_Catch($@) if $@;
|
return TadoAPI_Catch($@) if $@;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( defined($user) ) {
|
if ( defined($dev_code) && $dev_code ne "no_device_code_set" ) {
|
||||||
TadoAPI_CheckStatus($hash);
|
TadoAPI_CheckStatus($hash);
|
||||||
TadoAPI_LoadToken($hash);
|
TadoAPI_NewTokenRequest($hash);
|
||||||
|
|
||||||
# start the status update timer
|
# start the status update timer
|
||||||
RemoveInternalTimer($hash);
|
RemoveInternalTimer($hash);
|
||||||
InternalTimer( gettimeofday() + 15, "TadoAPI_Update", $hash, 0 );
|
InternalTimer( gettimeofday() + 15, "TadoAPI_Update", $hash, 0 );
|
||||||
|
|
||||||
if ( defined($homeID) && $homeID ne "" ) {
|
my $id = TadoAPI_GetHomeId($hash);
|
||||||
$attr{$name}{homeID} = $homeID;
|
if ( defined($id) && $id ne "" ) {
|
||||||
}
|
$attr{$name}{homeID} = $id;
|
||||||
else {
|
|
||||||
my $id = TadoAPI_GetHomeId($hash);
|
|
||||||
if ( defined($id) && $id ne "" ) {
|
|
||||||
$attr{$name}{homeID} = $id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$hash->{STATE} = "no device_code set";
|
$hash->{STATE} = "no_device_code_set";
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -317,16 +314,6 @@ sub TadoAPI_Get {
|
|||||||
last;
|
last;
|
||||||
};
|
};
|
||||||
|
|
||||||
# only for testing
|
|
||||||
$cmd eq "getXTest" and do {
|
|
||||||
Log3 $name, 5, "TadoAPI $name" . ": " . "processing ($cmd)";
|
|
||||||
my $zoneName = TadoAPI_GetZoneNameById( $hash, $value );
|
|
||||||
$zoneName = "wrong Zone ID" unless $zoneName;
|
|
||||||
$message = "Name: " . $zoneName;
|
|
||||||
Log3 $name, 3, "TadoAPI $name" . ": " . "$cmd finished\n";
|
|
||||||
last;
|
|
||||||
};
|
|
||||||
|
|
||||||
$cmd eq "getZoneDevices" and do {
|
$cmd eq "getZoneDevices" and do {
|
||||||
Log3 $name, 3, "TadoAPI $name" . ": " . "processing ($cmd)";
|
Log3 $name, 3, "TadoAPI $name" . ": " . "processing ($cmd)";
|
||||||
my @devArr = TadoAPI_GetTadoDevices($hash);
|
my @devArr = TadoAPI_GetTadoDevices($hash);
|
||||||
@ -399,13 +386,19 @@ sub TadoAPI_Catch {
|
|||||||
sub TadoAPI_Undefine {
|
sub TadoAPI_Undefine {
|
||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
my $name = shift;
|
my $name = shift;
|
||||||
|
|
||||||
RemoveInternalTimer($hash);
|
RemoveInternalTimer($hash);
|
||||||
|
|
||||||
#todo remove tokenfile
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub TadoAPI_Delete {
|
||||||
|
my ( $hash, $name ) = @_;
|
||||||
|
RemoveInternalTimer($hash);
|
||||||
|
# Löschen von Token-File
|
||||||
|
unlink($tokenFile . "_" . $name);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sub TadoAPI_CheckStatus {
|
sub TadoAPI_CheckStatus {
|
||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -468,8 +461,8 @@ sub TadoAPI_LoadToken {
|
|||||||
sub TadoAPI_RegisterNewDevice {
|
sub TadoAPI_RegisterNewDevice {
|
||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my $device_code = $hash->{TADO_USER};
|
|
||||||
my $tokenFileName = $tokenFile . "_" . $name;
|
my $tokenFileName = $tokenFile . "_" . $name;
|
||||||
|
|
||||||
|
|
||||||
my $data = {
|
my $data = {
|
||||||
client_id => $client_id,
|
client_id => $client_id,
|
||||||
@ -497,18 +490,19 @@ sub TadoAPI_RegisterNewDevice {
|
|||||||
. " - $err";
|
. " - $err";
|
||||||
}
|
}
|
||||||
elsif ( $returnData ne "" ) {
|
elsif ( $returnData ne "" ) {
|
||||||
Log3 $name, 5, "url " . $param->{url} . " - returned: $returnData";
|
Log3 $name, 5, "Device registration URL: " . $param->{url} . " - returned: $returnData";
|
||||||
my $decoded_data = eval { decode_json($returnData) };
|
my $decoded_data = eval { decode_json($returnData) };
|
||||||
if ($@) {
|
if ($@) {
|
||||||
Log3 $name, 3, "TadoAPI $name" . ": "
|
Log3 $name, 3, "TadoAPI $name" . ": "
|
||||||
. "RegisterNewDevice: decode_json failed, invalid json. error: $@ ";
|
. "RegisterNewDevice: decode_json failed, invalid json. error: $@ ";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log3 $name, 5,
|
Log3 $name, 3,
|
||||||
"TadoAPI $name" . ": "
|
"TadoAPI $name" . ": "
|
||||||
. "New Device - Please go to "
|
. "New Device - Please go to URL: "
|
||||||
. $decoded_data->{'verification_uri_complete'};
|
. $decoded_data->{'verification_uri_complete'};
|
||||||
$hash->{STATE} = "reachable";
|
|
||||||
|
$hash->{STATE} = "OK";
|
||||||
|
|
||||||
return ($decoded_data->{'verification_uri_complete'}, $decoded_data->{'device_code'});
|
return ($decoded_data->{'verification_uri_complete'}, $decoded_data->{'device_code'});
|
||||||
}
|
}
|
||||||
@ -516,6 +510,94 @@ sub TadoAPI_RegisterNewDevice {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub TadoAPI_NewTokenRequest {
|
||||||
|
my $hash = shift;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
my $device_code = $hash->{TADO_DEV_CODE};
|
||||||
|
my $tokenFileName = $tokenFile . "_" . $name;
|
||||||
|
my $Token = undef;
|
||||||
|
|
||||||
|
Log3 $name, 5, "TadoAPI $name" . ": " . "calling NewTokenRequest()";
|
||||||
|
|
||||||
|
# Check if 'refresh_token' exists or a new token is needed
|
||||||
|
my $TOKENFILE;
|
||||||
|
eval {
|
||||||
|
open( $TOKENFILE, q{<}, $tokenFileName ) or do {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
$Token = decode_json(<$TOKENFILE>) };
|
||||||
|
close($TOKENFILE);
|
||||||
|
|
||||||
|
if (exists $Token->{'refresh_token'}) {
|
||||||
|
Log3 $name, 3, "TadoAPI $name" . ": " . "Refresh token exists - OK\n";
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
Log3 $name, 3, "TadoAPI $name" . ": " . "No Refresh token - NewTokenRequest start\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
my $data = {
|
||||||
|
client_id => $client_id,
|
||||||
|
device_code => $device_code,
|
||||||
|
grant_type => 'urn:ietf:params:oauth:grant-type:device_code'
|
||||||
|
};
|
||||||
|
|
||||||
|
my $param = {
|
||||||
|
url => $AuthURL,
|
||||||
|
method => 'POST',
|
||||||
|
timeout => 5,
|
||||||
|
hash => $hash,
|
||||||
|
data => $data
|
||||||
|
};
|
||||||
|
|
||||||
|
#Log3 $name, 5, 'Blocking GET: ' . Dumper($param);
|
||||||
|
Log3 $name, $reqDebug, "TadoAPI $name" . ": " . "Request NEW Token from: $AuthURL";
|
||||||
|
my ( $err, $returnData ) = HttpUtils_BlockingGet($param);
|
||||||
|
|
||||||
|
if ( $err ne "" ) {
|
||||||
|
Log3 $name, 3,
|
||||||
|
"TadoAPI $name" . ": "
|
||||||
|
. "NewTokenRequest: Error while requesting "
|
||||||
|
. $param->{url}
|
||||||
|
. " - $err";
|
||||||
|
}
|
||||||
|
elsif ( $returnData ne "" ) {
|
||||||
|
Log3 $name, 5, "url " . $param->{url} . " returned: $returnData";
|
||||||
|
my $decoded_data = eval { decode_json($returnData) };
|
||||||
|
if ($@) {
|
||||||
|
Log3 $name, 3, "TadoAPI $name" . ": "
|
||||||
|
. "NewTokenRequest: decode_json failed, invalid json. error: $@ ";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#write token data in file
|
||||||
|
open( my $TOKENFILE, q{>}, $tokenFileName ) or do {
|
||||||
|
$apiStatus = 0;
|
||||||
|
$hash->{STATE} = "Token error";
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
print $TOKENFILE $returnData . "\n";
|
||||||
|
close($TOKENFILE);
|
||||||
|
|
||||||
|
# token lifetime management
|
||||||
|
if ( defined($decoded_data->{'expires_in'}) ){
|
||||||
|
$hash->{TOKEN_LIFETIME} = gettimeofday() + $decoded_data->{'expires_in'};
|
||||||
|
}
|
||||||
|
$hash->{TOKEN_LIFETIME_HR} = localtime( $hash->{TOKEN_LIFETIME} );
|
||||||
|
Log3 $name, 5,
|
||||||
|
"TadoAPI $name" . ": "
|
||||||
|
. "Retrived new authentication token successfully. Valid until "
|
||||||
|
. localtime( $hash->{TOKEN_LIFETIME} );
|
||||||
|
$hash->{STATE} = "reachable";
|
||||||
|
# refresh FHEM device
|
||||||
|
TadoAPI_UpdateFn($hash);
|
||||||
|
return $decoded_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sub TadoAPI_TokenRefresh {
|
sub TadoAPI_TokenRefresh {
|
||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
@ -534,6 +616,8 @@ sub TadoAPI_TokenRefresh {
|
|||||||
$Token = decode_json(<$TOKENFILE>) };
|
$Token = decode_json(<$TOKENFILE>) };
|
||||||
close($TOKENFILE);
|
close($TOKENFILE);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
my $data = {
|
my $data = {
|
||||||
client_id => $client_id,
|
client_id => $client_id,
|
||||||
scope => $scope,
|
scope => $scope,
|
||||||
@ -579,9 +663,9 @@ sub TadoAPI_TokenRefresh {
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
#write token data in file
|
#write token data in file
|
||||||
open( my $TOKENFILE, q{>}, $tokenFileName ) or do {
|
open( $TOKENFILE, q{>}, $tokenFileName ) or do {
|
||||||
$apiStatus = 0;
|
$apiStatus = 0;
|
||||||
$hash->{STATE} = "Token error";
|
$hash->{STATE} = "Token open error";
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
print $TOKENFILE $returnData . "\n";
|
print $TOKENFILE $returnData . "\n";
|
||||||
@ -871,7 +955,7 @@ sub TadoAPI_callback {
|
|||||||
|
|
||||||
my $hash = $param->{hash};
|
my $hash = $param->{hash};
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
print Dumper($param);
|
|
||||||
$param->{code} = 0 unless defined $param->{code};
|
$param->{code} = 0 unless defined $param->{code};
|
||||||
|
|
||||||
if ( $param->{code} == 405 || $param->{code} == 400 ) {
|
if ( $param->{code} == 405 || $param->{code} == 400 ) {
|
||||||
|
@ -40,13 +40,10 @@ Für Fragen / Anliegen bin ich im FHEM-Forum (https://forum.fhem.de/index.php/to
|
|||||||
|
|
||||||
In FHEM wird das Modul mit folgenden Schritten definiert:
|
In FHEM wird das Modul mit folgenden Schritten definiert:
|
||||||
|
|
||||||
Wenn man noch keinen `device_code` hat
|
Wenn man noch keinen `device_code` hat (Standard)
|
||||||
|
|
||||||
* `define <name> TadoAPI`
|
* `define <name> TadoAPI`
|
||||||
|
|
||||||
sonst kann man ihn gleich mitgeben mit:
|
|
||||||
|
|
||||||
`define <name> TadoAPI [<device_code>] [<homeID>]`
|
|
||||||
|
|
||||||
### Wichtig: Device einrichten
|
### Wichtig: Device einrichten
|
||||||
|
|
||||||
@ -57,6 +54,9 @@ Danach muss man das FHEM Device bei tado registrieren. ->
|
|||||||
* `device_code` beim DEF in FHEM einfügen
|
* `device_code` beim DEF in FHEM einfügen
|
||||||
* Fertig
|
* Fertig
|
||||||
|
|
||||||
|
Optional: Wenn man schon einen Device Code hat, kann man ihn gleich mitgeben mit:
|
||||||
|
|
||||||
|
`define <name> TadoAPI <device_code>`
|
||||||
|
|
||||||
<img src="https://git.wolfmajer.at/Public/FHEM-Tado/raw/branch/master/doc/define.png" width="500" />
|
<img src="https://git.wolfmajer.at/Public/FHEM-Tado/raw/branch/master/doc/define.png" width="500" />
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user