diff --git a/98_TadoAPI.pm b/98_TadoAPI.pm index ea29d11..25ec09f 100644 --- a/98_TadoAPI.pm +++ b/98_TadoAPI.pm @@ -71,7 +71,7 @@ my %gets = ( "getZoneDevices" => "noArg", "getZoneInfo" => "noArg", "getGeo" => "", - #"getXTest" => "noArg", + "getXTest" => "", "getMobileDevices" => "noArg" ); @@ -107,6 +107,7 @@ sub TadoAPI_Define($$) my @a = split( "[ \t]+", $def ); my $name = shift @a; my $type = shift @a; + my $tokenFileName = $tokenFile."_".$name; return "Invalid number of arguments: " . "define TadoAPI []" @@ -120,6 +121,7 @@ sub TadoAPI_Define($$) return $@ unless ( FHEM::Meta::SetInternals($hash) ); $hash->{TADO_USER} = $user; + $hash->{TOKEN_FILE} = $tokenFileName; if ( defined($homeID) && $homeID ne "" ) { $attr{$name}{homeID} = $homeID; @@ -176,11 +178,12 @@ sub TadoAPI_Set(@) { } elsif( $cmd eq 'setZoneOverlay' ) { Log3 $name, 3, "TadoAPI $name" . ": " . "processing ($cmd)" if $debug; - return "Need at least two parameters (ID, Setting)" if(@a < 4); - if( $a[3] > 10 ) { - TadoAPI_SetZoneOverlay($hash, $value, $a[3]); - } else { - TadoAPI_SetZoneOverlay($hash, $value, "off"); + return "Need at least two parameters (ZoneID, Setting)" if(@a < 4); + + if( $a[3] eq "off" ) { + TadoAPI_SetZoneOverlayById($hash, $value, "off"); + } elsif ($a[3] > 1) { + TadoAPI_SetZoneOverlayById($hash, $value, $a[3]); } Log3 $name, 3, "TadoAPI $name" . ": " . "$cmd finished\n"; return undef; @@ -188,10 +191,10 @@ sub TadoAPI_Set(@) { } elsif( $cmd eq 'setAllOverlays' ) { Log3 $name, 3, "TadoAPI $name" . ": " . "processing ($cmd)" if $debug; return "Need at least one parameter (Setting)" if(@a < 3); - if( $value > 1 ) { - TadoAPI_SetAllOverlays($hash, $value); - } else { + if( $value eq "off" ) { TadoAPI_SetAllOverlays($hash, "off"); + } elsif ($value > 1) { + TadoAPI_SetAllOverlays($hash, $value); } Log3 $name, 3, "TadoAPI $name" . ": " . "$cmd finished\n"; return undef; @@ -200,7 +203,7 @@ sub TadoAPI_Set(@) { Log3 $name, 3, "TadoAPI: set $name: processing ($cmd)"; RemoveInternalTimer($hash); InternalTimer( gettimeofday() + 10, "TadoAPI_Update", $hash, 0 ); - TadoAPI_Connect($hash); + TadoAPI_LoadToken($hash); return undef; } elsif( $cmd eq 'update' ) { @@ -242,7 +245,6 @@ sub TadoAPI_Get(@) { my $value = $a[2]; my $name = $hash->{NAME}; my $homeID = $attr{$name}{homeID}; - my $mobileID = $attr{$name}{mobileID}; my $message = undef; #debug @@ -282,14 +284,13 @@ sub TadoAPI_Get(@) { $cmd eq "getXTest" and do { Log3 $name, 3, "TadoAPI $name" . ": " . "processing ($cmd)" if $debug; - TadoAPI_UpdateFn($hash); + TadoAPI_ZoneRequest($hash); Log3 $name, 3, "TadoAPI $name" . ": " . "$cmd finished\n"; last; }; $cmd eq "getZoneDevices" and do { Log3 $name, 3, "TadoAPI $name" . ": " . "processing ($cmd)" if $debug; - TadoAPI_Connect($hash); my @devArr = TadoAPI_RequestTadoDevices($hash); my $devicecount = 0; $message = "Tado-Device(s):\n"; @@ -387,54 +388,51 @@ sub TadoAPI_Status(@){ return undef; } -sub TadoAPI_Connect(@) { +sub TadoAPI_LoadToken(@){ my ($hash) = @_; - my $name = $hash->{NAME}; + my $name = $hash->{NAME}; my $tokenFileName = $tokenFile."_".$name; my $tokenLifeTime = $hash->{TOKEN_LIFETIME}; $tokenLifeTime = 0 if(!defined $tokenLifeTime || $tokenLifeTime eq ''); - + #debug $debug = $attr{$name}{debug}; - #load existing token, or try to refresh old one - Log3 $name, 3, "TadoAPI $name" . ": " . "Loading Token Data from file: $tokenFileName." if $debug; - TadoAPI_Status($hash); + my $Token = undef; + if($apiStatus){ eval { open(TOKENFILE, '<', $tokenFileName) or die("ERROR: $!"); - $TokenData = decode_json()}; + $Token = decode_json()}; if($@ || $tokenLifeTime < gettimeofday()){ Log3 $name, 3, "TadoAPI $name" . ": " . "Error while loading: $@" if $debug && $@; Log3 $name, 3, "TadoAPI $name" . ": " . "Token expired, requesting new one" if $debug && $tokenLifeTime < gettimeofday(); - TadoAPI_requestNewToken($hash); + TadoAPI_NewTokenRequest($hash); }else{ Log3 $name, 3, "TadoAPI $name" . ": " . "Token expires at " . localtime($tokenLifeTime) if $debug; # if token is about to expire, refresh him - if (($tokenLifeTime-60) < gettimeofday()){ + if (($tokenLifeTime-15) < gettimeofday()){ Log3 $name, 3, "TadoAPI $name" . ": " . "Token will expire soon, refreshing" if $debug; - TadoAPI_refreshToken($hash); + TadoAPI_TokenRefresh($hash); } - } close(TOKENFILE); + return $Token; } - - return undef; +return undef; } -sub TadoAPI_requestNewToken(@) { +sub TadoAPI_NewTokenRequest(@) { my ($hash) = @_; my $name = $hash->{NAME}; my $username = $hash->{TADO_USER}; my $password = TadoAPI_readPassword($name); - my $tokenFileName = $tokenFile."_".$name; - Log3 $name, 3, "TadoAPI $name" . ": " . "Requesting new Token (TadoAPI_requestNewToken)" if $debug; + Log3 $name, 3, "TadoAPI $name" . ": " . "calling TadoAPI_NewTokenRequest()" if $debug; $data = { client_id => $client_id, @@ -445,42 +443,29 @@ sub TadoAPI_requestNewToken(@) { grant_type=>'password' }; - my $req = POST($AuthURL,$data); - my $ua = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 5,); - my $res = $ua->request($req); + my $request = { + url => $AuthURL, + method => 'POST', + timeout => 5, + callback => \&Tado_StoreTokenCallback, + refreshToken => 0, + hash => $hash, + data => $data + }; - if($res->is_success){ - $TokenData = decode_json($res->content); - - #write token data in file - open(TOKENFILE,">$tokenFileName") or die("ERROR: $!"); - print TOKENFILE $res->content."\n"; - close(TOKENFILE); + HttpUtils_NonblockingGet($request); +} - # token time management - $hash->{TOKEN_LIFETIME} = gettimeofday() + $TokenData->{'expires_in'}; - - Log3 $name, 3, "TadoAPI $name" . ": " . "Retrived new authentication token successfully. Valid until " . localtime($hash->{TOKEN_LIFETIME}) if $debug; - - #return to apistatus - $hash->{STATE}="reachable"; - return 1; - }else{ - Log3 $name, 3, "TadoAPI $name" . ": " . "Error in token retrival [Authentication Error]"; - print $Response->status_line."\n" if $debug; - #apiStatus down - $hash->{STATE}="error"; - return 0; - } - return undef; - } - -sub TadoAPI_refreshToken(@) { +sub TadoAPI_TokenRefresh(@) { my ($hash) = @_; my $name = $hash->{NAME}; - my $tokenFileName = $tokenFile."_".$name; - Log3 $name, 3, "TadoAPI $name" . ": " . "calling TadoAPI_refreshToken()" if $debug; + Log3 $name, 3, "TadoAPI $name" . ": " . "calling TokenRefresh()" if $debug; + + # load token + eval { + open(TOKENFILE, '<', $hash->{TOKEN_FILE}) or die("ERROR: $!"); + $TokenData = decode_json()}; $data = { client_id => $client_id, @@ -489,38 +474,68 @@ sub TadoAPI_refreshToken(@) { grant_type=>'refresh_token', refresh_token => $TokenData->{'refresh_token'} }; - - $Request = POST($AuthURL,$data); - $UserAgent = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 3,); - $Response = $UserAgent->request($Request); - $header = HTTP::Headers->new("Content-Type"=>"application/json;charset=UTF-8"); - if($Response->is_success){ - Log3 $name, 3, "TadoAPI $name" . ": " . "refreshed authentication token successfully." if $debug; - $TokenData = decode_json($Response->content); - Log3 $name, 3, "TadoAPI $name" . ": " . "writting refreshed Token Data to file $tokenFileName" if $debug; + my $request = { + url => $AuthURL, + method => 'POST', + timeout => 5, + callback => \&Tado_StoreTokenCallback, + hash => $hash, + refreshToken => 1, + data => $data + }; + + HttpUtils_NonblockingGet($request); +} + +sub Tado_StoreTokenCallback($) +{ + my ($param, $err, $data) = @_; + my $hash = $param->{hash}; + my $name = $hash->{NAME}; + my $tokenFileName = $hash->{TOKEN_FILE}; + + if($err ne "") + { + Log3 $name, 3, "TadoAPI $name" . ": " . "Error in token retrival while requesting ".$param->{url}." - $err"; + $hash->{STATE}="error"; + } + + elsif($data ne "") + { + Log3 $name, 3, "url ".$param->{url}." returned: $data" if $debug; + my $json_data =""; + + eval{ + $json_data = decode_json($data); + }; + # todo error handling + + if ($param->{refreshToken} == 1 && exists($json_data->{error})) + { + # do if refresh sub was not successful (maybe token expired) + Log3 $name, 3, "TadoAPI $name" . ": " . "Token expired, requesting new one"; + TadoAPI_NewTokenRequest($hash); + } else + { + eval{ + $TokenData = decode_json($data); + }; + # todo error handling + + #write token data in file open(TOKENFILE,">$tokenFileName") or die("ERROR: $!"); - print TOKENFILE $Response->content."\n"; - close(TOKENFILE); - #Log3 $name, 3, "TadoAPI $name" . ": " . "refreshed Token successful written" if $debug; - return 1; - }else{ - Log3 $name, 3, "TadoAPI $name" . ": " . "token expired, requesting new token"; - Log3 $name, 3, "TadoAPI $name" . ": " . $Response->status_line if $debug; - Log3 $name, 3, "TadoAPI $name" . ": " . "response code: " . $Response->code if $debug; - #if token is expired and connection up, request new one - if($Response->code == 500){ - Log3 $name, 3, "TadoAPI $name" . ": " . "error: not connected - response: 500" if $debug; - $apiStatus = 0; - $hash->{STATE}="error"; - } - else{ - TadoAPI_requestNewToken($hash); - } - return 0; - } - return undef; + print TOKENFILE $data . "\n"; + close(TOKENFILE); + + # token lifetime management + $hash->{TOKEN_LIFETIME} = gettimeofday() + $TokenData->{'expires_in'}; + $hash->{TOKEN_LIFETIME_HR} = localtime($hash->{TOKEN_LIFETIME}); + Log3 $name, 3, "TadoAPI $name" . ": " . "Retrived new authentication token successfully. Valid until " . localtime($hash->{TOKEN_LIFETIME}); #if $debug; + $hash->{STATE}="reachable"; } + } +} sub TadoAPI_Update(@){ my ($hash) = @_; @@ -548,37 +563,26 @@ sub TadoAPI_Update(@){ ######################## tado methods ######################## ############################################################## -sub TadoAPI_SetZoneOverlay(@){ + +sub TadoAPI_SetZoneOverlayById(@){ my ($hash, $zoneID, $setting) = @_; my $name = $hash->{NAME}; my $homeID = $attr{$name}{homeID}; my $URL = $QueryURL . qq{/$homeID/zones/$zoneID/overlay}; + my $TokenData = TadoAPI_LoadToken($hash); + + if(defined($TokenData)){ + my $method = ""; + my $myjson =""; - Log3 $name, 3, "TadoAPI $name" . ": SetOverlay for Zone $zoneID (Setting: " . $setting . ") - " . "query-URL: $URL" if $debug; - - if($apiStatus == 1){ - TadoAPI_Connect($hash); - my $zoneName = TadoAPI_GetZoneNameById($hash, $zoneID); - - $header = HTTP::Headers->new("Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}"); - - $UserAgent = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 5,); - $UserAgent->default_headers($header); - - my $req = undef; - my $res = undef; - my $message = ""; + Log3 $name, 3, "TadoAPI $name" . ": SetOverlay for Zone $zoneID (Setting: " . $setting . ") - " . "query-URL: $URL" if $debug; if ($setting eq "off"){ - # Delete overlay - $req = HTTP::Request->new( 'DELETE', $URL ); - $req->content_type('application/json'); - Log3 $name, 3, "TadoAPI $name" . ": " . "Deleting Overlay (off)" if $debug; - $message = "no overlay"; + $method = "DELETE"; + Log3 $name, 3, "TadoAPI $name" . ": " . "Deleting Overlay for Zone $zoneID"; }elsif($setting > 10){ - $req = HTTP::Request->new( 'PUT', $URL ); - $req->content_type('application/json'); - my $message = { + $method = "PUT"; + $myjson = { setting => { type => "HEATING", power => "ON", @@ -590,58 +594,73 @@ sub TadoAPI_SetZoneOverlay(@){ type => "MANUAL" }, }; - my $myjson = encode_json($message); - #print Dumper($myjson); - $req->content($myjson); + $myjson = encode_json($myjson); + } - $message = "MANUAL"; - } - $UserAgent->default_headers($header); - $res = $UserAgent->request($req); + my $request = { + url => $URL, + header => { "Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}" }, + method => $method, + timeout => 3, + callback => \&Tado_UpdateZoneOverlayCallback, + hash => $hash, + setting => $setting, + zoneID => $zoneID, + data => $myjson + }; + + #Log3 $name, 3, 'NonBlocking Request: ' . Dumper($request); + + HttpUtils_NonblockingGet($request); - if($res->is_success){ - print "\n Retriving State:\n" if $debug; - Log3 $name, 3, "TadoAPI $name" . ": " . "Retriving state:\n" . $res->content if $debug; - Log3 $name, 3, "TadoAPI $name" . ": " . "Set Overlay for Zone $zoneID to: $setting"; - }else{ - Log3 $name, 3, "TadoAPI $name" . ": " . "Error in SetOverlay()"; - Log3 $name, 3, "TadoAPI $name" . ": " . "Status (setOverlay): " . $res->status_line if $debug; - } - # finaly update readings - TadoAPI_GetZoneReadingsById($hash, $zoneID); } } +sub Tado_UpdateZoneOverlayCallback($) +{ + my ($param, $err, $data) = @_; + my $hash = $param->{hash}; + my $name = $hash->{NAME}; + my $zoneID = $param->{zoneID}; + my $setting = $param->{setting}; + + if($err ne "") + { + Log3 $name, 3, "Error in UpdateZoneOverlayCallback while requesting ".$param->{url}." - $err"; + return undef; + } + + elsif($data ne "") + { + Log3 $name, 3, "url ".$param->{url}." returned: $data" if $debug; + Log3 $name, 3, "TadoAPI $name" . ": " . "Set Overlay for Zone $zoneID to: $setting"; + + } + # finaly update readings + TadoAPI_GetZoneReadingsById($hash, $zoneID); + +} + sub TadoAPI_SetAllOverlays(@){ my ($hash, $setting) = @_; my $name = $hash->{NAME}; my $homeID = $attr{$name}{homeID}; - + if($apiStatus == 1){ - TadoAPI_Connect($hash); - my $zonecount = TadoAPI_RequestZones($hash); - - my $header = HTTP::Headers->new("Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}"); - my $ua = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 5,); - $ua->default_headers($header); - - my $req = undef; - my $res = undef; + my $zonecount = TadoAPI_ZoneRequest($hash); my $message = ""; + my $method = ""; + my $myjson =""; for (my $i=1; $i <= $zonecount; $i++) { my $URL = $QueryURL . qq{/$homeID/zones/$i/overlay}; if ($setting eq "off"){ - # Delete overlay - $req = HTTP::Request->new( 'DELETE', $URL ); - $req->content_type('application/json'); - Log3 $name, 3, "TadoAPI $name" . ": " . "Deleting Overlay (off)" if $debug; - $message = "no overlay"; + $method = "DELETE"; + Log3 $name, 3, "TadoAPI $name" . ": " . "Deleting Overlay for Zone $i"; }elsif($setting > 10){ - $req = HTTP::Request->new( 'PUT', $URL ); - $req->content_type('application/json'); - $message = { + $method = "PUT"; + $myjson = { setting => { type => "HEATING", power => "ON", @@ -653,23 +672,21 @@ sub TadoAPI_SetAllOverlays(@){ type => "MANUAL" }, }; - my $myjson = encode_json($message); - #print Dumper($myjson); - $req->content($myjson); + $myjson = encode_json($myjson); + } - $message = "MANUAL"; - } - $ua->default_headers($header); - $res = $ua->request($req); - - if($res->is_success){ - print "\n Retriving State:\n" if $debug; - Log3 $name, 3, "TadoAPI $name" . ": " . "Retriving state:\n" . $res->content if $debug; - Log3 $name, 3, "TadoAPI $name" . ": " . "Set Overlay for Zone $i to: $setting"; - }else{ - Log3 $name, 3, "TadoAPI $name" . ": " . "Error in SetOverlay()"; - Log3 $name, 3, "TadoAPI $name" . ": " . "Status (setOverlay): " . $res->status_line if $debug; - } + my $request = { + url => $URL, + header => { "Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}" }, + method => $method, + timeout => 3, + callback => \&Tado_UpdateZoneOverlayCallback, + hash => $hash, + setting => $setting, + zoneID => $i, + data => $myjson + }; + HttpUtils_NonblockingGet($request); } # finaly update readings @@ -681,11 +698,11 @@ sub TadoAPI_UpdateFn(@){ my ($hash) = @_; my $name = $hash->{NAME}; - TadoAPI_Connect($hash); + TadoAPI_Status($hash); # zone specific updates if($apiStatus == 1){ - my @zones = TadoAPI_RequestZones($hash); + my @zones = TadoAPI_ZoneRequest($hash); my @devices = TadoAPI_RequestTadoDevices($hash); my $zonecount = @zones; @@ -737,11 +754,12 @@ sub TadoAPI_GetGeoById(@){ my $name = $hash->{NAME}; my $homeID = $attr{$name}{homeID}; my $URL=$QueryURL.qq{/$homeID/mobileDevices/$mobileID/settings}; + my $TokenData = TadoAPI_LoadToken($hash); - Log3 $name, 3, "TadoAPI $name" . ": " . "query-URL: $URL" if $debug; - TadoAPI_Connect($hash); + if(defined($TokenData)){ - if($apiStatus == 1){ + Log3 $name, 3, "TadoAPI $name" . ": " . "query-URL: $URL" if $debug; + my $header = HTTP::Headers->new("Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}"); my $ua = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 5,); $ua->default_headers($header); @@ -770,10 +788,9 @@ sub TadoAPI_GetZoneInfo(@) { my $name = $hash->{NAME}; my $homeID = $attr{$name}{homeID}; my $URL=$QueryURL.qq{/$homeID/zones/1/state}; + my $TokenData = TadoAPI_LoadToken($hash); - if($apiStatus == 1){ - TadoAPI_Connect($hash); - + if(defined($TokenData)){ $header = HTTP::Headers->new("Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}"); $UserAgent = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 5,); $UserAgent->default_headers($header); @@ -813,6 +830,7 @@ sub TadoAPI_GetZoneInfo(@) { Log3 $name, 3, "TadoAPI $name" . ": " . "GetZoneInfo: [Authentication Error]". $res->status_line; } + # todo remove static mobile id my $mobileID = $attr{$name}{mobileID}; $URL=$QueryURL.qq{/$homeID/mobileDevices/$mobileID/settings}; @@ -843,60 +861,16 @@ sub TadoAPI_GetZoneInfo(@) { return undef; } -sub TadoAPI_SetGeo(@){ - my ($hash, $geo) = @_; - my $name = $hash->{NAME}; - my $homeID = $attr{$name}{homeID}; - my $mobileID = $attr{$name}{mobileID}; - my $URL=$QueryURL.qq{/$homeID/mobileDevices/$mobileID/settings}; - - Log3 $name, 3, "TadoAPI $name" . ": " . "homeID: $homeID" if $debug; - Log3 $name, 3, "TadoAPI $name" . ": " . "geo: $geo" if $debug; - Log3 $name, 3, "TadoAPI $name" . ": " . "query-URL: $URL" if $debug; - - - if($apiStatus == 1){ - TadoAPI_Connect($hash); - - $header = HTTP::Headers->new("Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}"); - - $UserAgent = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 5,); - $UserAgent->default_headers($header); - - $Request = HTTP::Request->new('PUT',$URL); - $Request->content_type('application/json'); - - if($geo){ - $Request->content('{"geoTrackingEnabled":"true"}'); - }else{ - $Request->content('{"geoTrackingEnabled":"false"}'); - } - - $Response = $UserAgent->request($Request); - - if($Response->is_success){ - print "\n Retriving State:\n" if $debug; - Log3 $name, 3, "TadoAPI $name" . ": " . "Retriving state:\n" . $Response->content if $debug; - Log3 $name, 3, "TadoAPI $name" . ": " . "Set geo setting for $mobileID to: $geo"; - }else{ - Log3 $name, 3, "TadoAPI $name" . ": " . "Error in setGeo()"; - Log3 $name, 3, "TadoAPI $name" . ": " . "Status: " . $Response->status_line if $debug; - } - } -} - sub TadoAPI_SetGeoById(@){ my ($hash, $mobID, $geo) = @_; my $name = $hash->{NAME}; my $homeID = $attr{$name}{homeID}; my $URL=$QueryURL.qq{/$homeID/mobileDevices/$mobID/settings}; - - TadoAPI_Connect($hash); - - if($apiStatus == 1){ - + my $TokenData = TadoAPI_LoadToken($hash); + + if(defined($TokenData)){ my $header = HTTP::Headers->new("Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}"); - my $ua = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 5,); + my $ua = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 3,); $ua->default_headers($header); my $req = HTTP::Request->new('PUT',$URL); @@ -929,12 +903,11 @@ sub TadoAPI_RequestHome(@) { my ($hash) = @_; my $name = $hash->{NAME}; my $URL=qq{https://my.tado.com/api/v2/me}; + my $TokenData = TadoAPI_LoadToken($hash); - if($apiStatus == 1){ - TadoAPI_Connect($hash); - + if(defined($TokenData)){ my $header = HTTP::Headers->new("Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}"); - my $ua = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 5,); + my $ua = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 3,); $ua->default_headers($header); my $req = GET($URL); @@ -966,12 +939,11 @@ sub TadoAPI_RequestTadoDevices(@) { my $name = $hash->{NAME}; my $homeID = $attr{$name}{homeID}; my $URL=$QueryURL.qq{/$homeID/zones}; + my $TokenData = TadoAPI_LoadToken($hash); - if($apiStatus == 1){ - TadoAPI_Connect($hash); - + if(defined($TokenData)){ my $header = HTTP::Headers->new("Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}"); - my $ua = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 5,); + my $ua = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 3,); $ua->default_headers($header); my $req = GET($URL); @@ -999,46 +971,50 @@ sub TadoAPI_RequestTadoDevices(@) { return undef; } -sub TadoAPI_RequestZones(@) { +sub TadoAPI_ZoneRequest(@) { # returns array with state of all zones my ($hash) = @_; my $name = $hash->{NAME}; my $homeID = $attr{$name}{homeID}; + my @zones = (); + my $TokenData = TadoAPI_LoadToken($hash); - if($apiStatus == 1){ - TadoAPI_Connect($hash); - - my $header = HTTP::Headers->new("Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}"); - my $ua = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 5,); - $ua->default_headers($header); - - my @zones = (); - + if(defined($TokenData)) + { for (my $i=1; $i <= TadoAPI_GetZoneCount($hash); $i++) { my $URL=$QueryURL.qq{/$homeID/zones/$i/state}; + my $param = { + url => $URL, + header => {"Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}"}, + method => 'GET', + timeout => 2, + hash => $hash, + zoneID => $i + }; - my $req = GET($URL); - my $res = $UserAgent->request($req); - - if($res->is_success){ - Log3 $name, 3, "TadoAPI $name" . ": " . "RequestZones: Zone $i Status:\n" . $res->content if $debug; - my $data = $res->content; - # validate response from api - my $decoded_data = eval { decode_json($data) }; - if ($@) - { - Log3 $name, 3, "TadoAPI $name" . ": " . "RequestZones: Zone $i decode_json failed, invalid json. error:$@\n"; - }else{ - # returns a json object with zone i - push @zones, $decoded_data; + Log3 $name, 3, 'Blocking GET: ' . Dumper($param) if $debug; + my ($err, $data) = HttpUtils_BlockingGet($param); + + if($err ne "") + { + Log3 $name, 3, "TadoAPI $name" . ": " . "ZoneRequest: Error while requesting ".$param->{url}." - $err"; } - }else{ - Log3 $name, 3, "TadoAPI $name" . ": " . "RequestZones: [Authentication Error]". $res->status_line; + elsif($data ne "") + { + Log3 $name, 3, "url ".$param->{url}." returned: $data" if $debug; + + # An dieser Stelle die Antwort parsen / verarbeiten mit $data + my $decoded_data = eval { decode_json($data) }; + if ($@){ + Log3 $name, 3, "TadoAPI $name" . ": " . "RequestZones: Zone $i decode_json failed, invalid json. error:$@\n"; + }else{ + # pushes zone i to array + push @zones, $decoded_data; + } } } - return @zones; + return @zones; } -return undef; } sub TadoAPI_RequestMobileDevices(@) { @@ -1046,13 +1022,12 @@ sub TadoAPI_RequestMobileDevices(@) { my $name = $hash->{NAME}; my $homeID = $attr{$name}{homeID}; my $URL=$QueryURL . qq{/$homeID/mobileDevices}; + my $TokenData = TadoAPI_LoadToken($hash); - if($apiStatus == 1){ - TadoAPI_Connect($hash); + if(defined($TokenData)){ my @devices = (); - my $header = HTTP::Headers->new("Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}"); - my $ua = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 5,); + my $ua = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 3,); $ua->default_headers($header); my $req = GET($URL); @@ -1098,9 +1073,10 @@ sub TadoAPI_GetZoneCount(@) { my $homeID = $attr{$name}{homeID}; my $URL=$QueryURL.qq{/$homeID/zones}; my $zonecount = 0; + my $TokenData = TadoAPI_LoadToken($hash); $header = HTTP::Headers->new("Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}"); - $UserAgent = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 5,); + $UserAgent = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 3,); $UserAgent->default_headers($header); $Request = GET($URL); @@ -1123,9 +1099,10 @@ sub TadoAPI_GetZoneNameById(@) { my $name = $hash->{NAME}; my $homeID = $attr{$name}{homeID}; my $URL=$QueryURL.qq{/$homeID/zones}; + my $TokenData = TadoAPI_LoadToken($hash); $header = HTTP::Headers->new("Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}"); - $UserAgent = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 5,); + $UserAgent = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 3,); $UserAgent->default_headers($header); $Request = GET($URL); @@ -1150,9 +1127,10 @@ sub TadoAPI_GetZoneTemperatureById(@){ my $URL=$QueryURL.qq{/$homeID/zones/$zoneID/state}; my $temperature = 0; my $humidity = 0; + my $TokenData = TadoAPI_LoadToken($hash); $header = HTTP::Headers->new("Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}"); - $UserAgent = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 5,); + $UserAgent = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 3,); $UserAgent->default_headers($header); $Request = GET($URL); @@ -1180,9 +1158,10 @@ sub TadoAPI_GetZoneReadingsById(@){ my $desiredTemp = 0; my $currentHeatingPower = 0; my $overlay = 0; + my $TokenData = TadoAPI_LoadToken($hash); my $header = HTTP::Headers->new("Content-Type"=>"application/json;charset=UTF-8","Authorization" => "$TokenData->{'token_type'} $TokenData->{'access_token'}"); - my $ua = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 5,); + my $ua = LWP::UserAgent::Paranoid->new(ssl_opts => { verify_hostname => 1 },protocols_allowed => ['https','http'],request_timeout => 3,); $ua->default_headers($header); my $req = GET($URL);