98_vitoconnect: Refresh expired token in set action
git-svn-id: https://svn.fhem.de/fhem/trunk@30291 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
@@ -93,6 +93,7 @@ use FHEM::SynoModules::SMUtils qw (
|
|||||||
); # Hilfsroutinen Modul
|
); # Hilfsroutinen Modul
|
||||||
|
|
||||||
my %vNotesIntern = (
|
my %vNotesIntern = (
|
||||||
|
"0.9.1" => "11.09.2025 In case of set action when token is expired get new token and try again",
|
||||||
"0.9.0" => "09.03.2025 New api and iam URL (viessmann-climatesolutions.com)",
|
"0.9.0" => "09.03.2025 New api and iam URL (viessmann-climatesolutions.com)",
|
||||||
"0.8.7" => "09.03.2025 Fix return value when using SVN or Roger",
|
"0.8.7" => "09.03.2025 Fix return value when using SVN or Roger",
|
||||||
"0.8.6" => "24.02.2025 Adapt schedule data before sending",
|
"0.8.6" => "24.02.2025 Adapt schedule data before sending",
|
||||||
@@ -2946,7 +2947,7 @@ sub vitoconnect_getAccessTokenCallback {
|
|||||||
# neuen Access-Token anfragen
|
# neuen Access-Token anfragen
|
||||||
#####################################################################################################################
|
#####################################################################################################################
|
||||||
sub vitoconnect_getRefresh {
|
sub vitoconnect_getRefresh {
|
||||||
my ($hash) = @_;
|
my ($hash, $caller) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my $client_id = $hash->{apiKey};
|
my $client_id = $hash->{apiKey};
|
||||||
my $param = {
|
my $param = {
|
||||||
@@ -2960,6 +2961,7 @@ sub vitoconnect_getRefresh {
|
|||||||
sslargs => { SSL_verify_mode => 0 },
|
sslargs => { SSL_verify_mode => 0 },
|
||||||
method => "POST",
|
method => "POST",
|
||||||
timeout => $hash->{timeout},
|
timeout => $hash->{timeout},
|
||||||
|
caller => $caller, # <–– Kontext hier speichern!
|
||||||
callback => \&vitoconnect_getRefreshCallback
|
callback => \&vitoconnect_getRefreshCallback
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2976,6 +2978,7 @@ sub vitoconnect_getRefreshCallback {
|
|||||||
my ($param,$err,$response_body) = @_; # Übergabe-Parameter
|
my ($param,$err,$response_body) = @_; # Übergabe-Parameter
|
||||||
my $hash = $param->{hash};
|
my $hash = $param->{hash};
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
my $caller = $param->{caller} // 'update'; # Default: update
|
||||||
|
|
||||||
if ($err eq "") {
|
if ($err eq "") {
|
||||||
Log3($name,4,$name.". - getRefreshCallback went ok");
|
Log3($name,4,$name.". - getRefreshCallback went ok");
|
||||||
@@ -2983,7 +2986,9 @@ sub vitoconnect_getRefreshCallback {
|
|||||||
my $decode_json = eval {decode_json($response_body)};
|
my $decode_json = eval {decode_json($response_body)};
|
||||||
if ($@) { # Fehler aufgetreten
|
if ($@) { # Fehler aufgetreten
|
||||||
Log3($name,1,$name.", vitoconnect_getRefreshCallback: JSON error while request: ".$@);
|
Log3($name,1,$name.", vitoconnect_getRefreshCallback: JSON error while request: ".$@);
|
||||||
|
if ($caller ne 'action') {
|
||||||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
my $access_token = $decode_json->{"access_token"};
|
my $access_token = $decode_json->{"access_token"};
|
||||||
@@ -2992,18 +2997,34 @@ sub vitoconnect_getRefreshCallback {
|
|||||||
Log3($name,4,$name." - Access Token: ".substr($access_token,0,20)."...");
|
Log3($name,4,$name." - Access Token: ".substr($access_token,0,20)."...");
|
||||||
#vitoconnect_getGw($hash); # Abfrage Gateway-Serial
|
#vitoconnect_getGw($hash); # Abfrage Gateway-Serial
|
||||||
# directly call get resource to save API calls
|
# directly call get resource to save API calls
|
||||||
|
if ($caller eq 'action') {
|
||||||
|
vitoconnect_action(
|
||||||
|
$hash,
|
||||||
|
$hash->{".retry_feature"},
|
||||||
|
$hash->{".retry_data"},
|
||||||
|
$name,
|
||||||
|
$hash->{".retry_opt"},
|
||||||
|
@{ $hash->{".retry_args"} }
|
||||||
|
);
|
||||||
|
} else {
|
||||||
vitoconnect_getResource($hash);
|
vitoconnect_getResource($hash);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
Log3 $name, 1, "$name - Access Token: nicht definiert";
|
Log3 $name, 1, "$name - Access Token: nicht definiert";
|
||||||
Log3 $name, 5, "$name - Received response: $response_body\n";
|
Log3 $name, 5, "$name - Received response: $response_body\n";
|
||||||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash); # zurück zu getCode?
|
# zurück zu getCode?
|
||||||
|
if ($caller ne 'action') {
|
||||||
|
InternalTimer(gettimeofday() + $hash->{intervall}, "vitoconnect_GetUpdate", $hash);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log3 $name, 1, "$name - getRefresh: An error occured: $err";
|
Log3 $name, 1, "$name - getRefresh: An error occured: $err";
|
||||||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
if ($caller ne 'action') {
|
||||||
|
InternalTimer(gettimeofday() + $hash->{intervall}, "vitoconnect_GetUpdate", $hash);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -3791,37 +3812,62 @@ sub vitoconnect_getErrorCode {
|
|||||||
# Setzen von Daten
|
# Setzen von Daten
|
||||||
#####################################################################################################################
|
#####################################################################################################################
|
||||||
sub vitoconnect_action {
|
sub vitoconnect_action {
|
||||||
my ($hash,$feature,$data,$name,$opt,@args ) = @_; # Übergabe-Parameter
|
my ($hash, $feature, $data, $name, $opt, @args) = @_;
|
||||||
my $access_token = $hash->{".access_token"}; # Internal: .access_token
|
return delete $hash->{".action_retry_count"} if IsDisabled($name); # Modul deaktiviert → abbrechen
|
||||||
my $installation = AttrVal( $name, 'vitoconnect_installationID', 0 );
|
|
||||||
my $gw = AttrVal( $name, 'vitoconnect_serial', 0 );
|
my $access_token = $hash->{".access_token"};
|
||||||
my $dev = AttrVal($name,'vitoconnect_device',0);
|
my $installation = AttrVal($name, 'vitoconnect_installationID', 0);
|
||||||
|
my $gw = AttrVal($name, 'vitoconnect_serial', 0);
|
||||||
|
my $dev = AttrVal($name, 'vitoconnect_device', 0);
|
||||||
|
my $Text = join(' ', @args);
|
||||||
|
my $retry_count = $hash->{".action_retry_count"} // 0;
|
||||||
|
|
||||||
my $param = {
|
my $param = {
|
||||||
url => $iotURL_V2
|
url => $iotURL_V2."installations/$installation/gateways/$gw/devices/$dev/features/$feature",
|
||||||
."installations/".$installation."/gateways/".$gw."/"
|
|
||||||
."devices/".$dev."/features/".$feature,
|
|
||||||
hash => $hash,
|
hash => $hash,
|
||||||
header => "Authorization: Bearer ".$access_token."\r\n"
|
header => "Authorization: Bearer $access_token\r\nContent-Type: application/json",
|
||||||
. "Content-Type: application/json",
|
|
||||||
data => $data,
|
data => $data,
|
||||||
timeout => $hash->{timeout}, # Timeout von Internals = 15s
|
timeout => $hash->{timeout},
|
||||||
method => "POST",
|
method => "POST",
|
||||||
sslargs => { SSL_verify_mode => 0 },
|
sslargs => { SSL_verify_mode => 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
Log3($name,3,$name.", vitoconnect_action url=" .$param->{url}); # change back to 3
|
Log3($name,3,$name.", vitoconnect_action url=" .$param->{url}); # change back to 3
|
||||||
Log3($name,3,$name.", vitoconnect_action data=".$param->{data}); # change back to 3
|
Log3($name,3,$name.", vitoconnect_action data=".$param->{data}); # change back to 3
|
||||||
# https://wiki.fhem.de/wiki/HttpUtils#HttpUtils_BlockingGet
|
# https://wiki.fhem.de/wiki/HttpUtils#HttpUtils_BlockingGet
|
||||||
(my $err,my $msg) = HttpUtils_BlockingGet($param);
|
my ($err, $msg) = HttpUtils_BlockingGet($param);
|
||||||
my $decode_json = eval {decode_json($msg)};
|
my $decode_json = eval { decode_json($msg) };
|
||||||
|
|
||||||
Log3($name,3,$name.", vitoconnect_action call finished, err:" .$err);
|
if ((defined($err) && $err ne "") || (defined($decode_json->{statusCode}) && $decode_json->{statusCode} ne "")) {
|
||||||
my $Text = join(' ',@args); # Befehlsparameter in Text
|
$retry_count++;
|
||||||
if ( (defined($err) && $err ne "") || (defined($decode_json->{statusCode}) && $decode_json->{statusCode} ne "") ) { # Fehler bei Befehlsausführung
|
$hash->{".action_retry_count"} = $retry_count;
|
||||||
readingsSingleUpdate($hash,"Aktion_Status","Fehler: ".$opt." ".$Text,1); # Reading 'Aktion_Status' setzen
|
readingsSingleUpdate($hash, "Aktion_Status", "Fehler ($retry_count/20): $opt $Text", 1);
|
||||||
Log3($name,1,$name.",vitoconnect_action: set ".$name." ".$opt." ".@args.", Fehler bei Befehlsausfuehrung: ".$err." :: ".$msg);
|
# Log3($name, 2, "$name - RetryLoop Fehler: $err :: $msg");
|
||||||
|
Log3($name,1,$name.",vitoconnect_action: set ".$name." ".$opt." ".@args.", Fehler bei Befehlsausfuehrung ($retry_count/20): ".$err." :: ".$msg);
|
||||||
|
|
||||||
|
# Token abgelaufen?
|
||||||
|
if ($decode_json->{statusCode} eq "401" && $decode_json->{error} eq "EXPIRED TOKEN") {
|
||||||
|
# Token erneuern, aber ohne getResource
|
||||||
|
$hash->{".retry_feature"} = $feature;
|
||||||
|
$hash->{".retry_data"} = $data;
|
||||||
|
$hash->{".retry_opt"} = $opt;
|
||||||
|
$hash->{".retry_args"} = [@args];
|
||||||
|
$hash->{".action_retry_count"} = $retry_count;
|
||||||
|
vitoconnect_getRefresh($hash, 'action'); # Kontext 'action' → kein getResource
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else { # Befehl korrekt ausgeführt
|
|
||||||
|
# Wiederholen in 10 Sekunden
|
||||||
|
if ($retry_count < 20) {
|
||||||
|
InternalTimer(gettimeofday() + 10, "vitoconnect_action", [$hash, $feature, $data, $name, $opt, @args]);
|
||||||
|
} else {
|
||||||
|
Log3($name, 1, "$name - vitoconnect_action: Abbruch nach 20 Fehlversuchen");
|
||||||
|
readingsSingleUpdate($hash, "Aktion_Status", "Fehlgeschlagen: $opt $Text (nach 20 Versuchen)", 1);
|
||||||
|
delete $hash->{".action_retry_count"};
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
readingsSingleUpdate($hash,"Aktion_Status","OK: ".$opt." ".$Text,1); # Reading 'Aktion_Status' setzen
|
readingsSingleUpdate($hash,"Aktion_Status","OK: ".$opt." ".$Text,1); # Reading 'Aktion_Status' setzen
|
||||||
#Log3($name,1,$name.",vitoconnect_action: set name:".$name." opt:".$opt." text:".$Text.", korrekt ausgefuehrt: ".$err." :: ".$msg); # TODO: Wieder weg machen $err
|
#Log3($name,1,$name.",vitoconnect_action: set name:".$name." opt:".$opt." text:".$Text.", korrekt ausgefuehrt: ".$err." :: ".$msg); # TODO: Wieder weg machen $err
|
||||||
Log3($name,3,$name.",vitoconnect_action: set name:".$name." opt:".$opt." text:".$Text.", korrekt ausgefuehrt");
|
Log3($name,3,$name.",vitoconnect_action: set name:".$name." opt:".$opt." text:".$Text.", korrekt ausgefuehrt");
|
||||||
@@ -3849,7 +3895,7 @@ sub vitoconnect_action {
|
|||||||
|
|
||||||
|
|
||||||
Log3($name,4,$name.",vitoconnect_action: set feature:".$feature." data:".$data.", korrekt ausgefuehrt"); #4
|
Log3($name,4,$name.",vitoconnect_action: set feature:".$feature." data:".$data.", korrekt ausgefuehrt"); #4
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3883,7 +3929,7 @@ sub vitoconnect_errorHandling {
|
|||||||
);
|
);
|
||||||
if ( $items->{statusCode} eq "401" ) {
|
if ( $items->{statusCode} eq "401" ) {
|
||||||
# EXPIRED TOKEN
|
# EXPIRED TOKEN
|
||||||
vitoconnect_getRefresh($hash); # neuen Access-Token anfragen
|
vitoconnect_getRefresh($hash,'update'); # neuen Access-Token anfragen
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
elsif ( $items->{statusCode} eq "404" ) {
|
elsif ( $items->{statusCode} eq "404" ) {
|
||||||
|
|||||||
Reference in New Issue
Block a user