mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-25 16:05:19 +00:00
38_netatmo: fixed login problems by adapting to latest auth changes
git-svn-id: https://svn.fhem.de/fhem/trunk@28259 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
908af9d52f
commit
89868a683d
@ -1,5 +1,6 @@
|
|||||||
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
||||||
# Do not insert empty lines here, update check depends on it.
|
# Do not insert empty lines here, update check depends on it.
|
||||||
|
- bugfix: 38_netatmo: fixed login problems by adapting to latest auth changes
|
||||||
- feature: 76_SolarForecast: new get ftuiFramefiles command
|
- feature: 76_SolarForecast: new get ftuiFramefiles command
|
||||||
- feature: 76_SolarForecast: plantConfig: check module update in repo
|
- feature: 76_SolarForecast: plantConfig: check module update in repo
|
||||||
- feature: 76_SolarForecast: graphicHeaderOwnspec can show set-commands and
|
- feature: 76_SolarForecast: graphicHeaderOwnspec can show set-commands and
|
||||||
|
@ -389,8 +389,8 @@ my %sleep_readings = ( 'asleepduration' => { name => "Manual Sleep", reading =>
|
|||||||
'hr_zone_1' => { name => "HR Zone 1", reading => "heartrateZoneModerate", unit => "s", },
|
'hr_zone_1' => { name => "HR Zone 1", reading => "heartrateZoneModerate", unit => "s", },
|
||||||
'hr_zone_2' => { name => "HR Zone 2", reading => "heartrateZoneIntense", unit => "s", },
|
'hr_zone_2' => { name => "HR Zone 2", reading => "heartrateZoneIntense", unit => "s", },
|
||||||
'hr_zone_3' => { name => "HR Zone 3", reading => "heartrateZonePeak", unit => "s", },
|
'hr_zone_3' => { name => "HR Zone 3", reading => "heartrateZonePeak", unit => "s", },
|
||||||
'device_startdate' => { name => "Start", reading => "deviceStartDate", unit => "m", },
|
'device_startdate' => { name => "Start", reading => "deviceStartDate", unit => 0, },
|
||||||
'device_enddate' => { name => "End", reading => "deviceEndDate", unit => "m", },
|
'device_enddate' => { name => "End", reading => "deviceEndDate", unit => 0, },
|
||||||
);
|
);
|
||||||
|
|
||||||
my %alarm_sound = ( 0 => "Unknown",
|
my %alarm_sound = ( 0 => "Unknown",
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# Release 27 / 2023-07-14
|
# Release 29 / 2023-12-06
|
||||||
|
|
||||||
package main;
|
package main;
|
||||||
|
|
||||||
@ -449,7 +449,9 @@ netatmo_Define($$)
|
|||||||
$hash->{helper}{password} = $password;
|
$hash->{helper}{password} = $password;
|
||||||
$hash->{helper}{client_id} = $client_id;
|
$hash->{helper}{client_id} = $client_id;
|
||||||
$hash->{helper}{client_secret} = $client_secret;
|
$hash->{helper}{client_secret} = $client_secret;
|
||||||
$hash->{helper}{refresh_token} = $refresh_token;
|
$hash->{refresh_token} = $refresh_token;
|
||||||
|
$hash->{helper}{refresh_token} = $hash->{refresh_token};
|
||||||
|
$hash->{helper}{refresh_token} = $refresh_token if(!$hash->{helper}{refresh_token});
|
||||||
|
|
||||||
$hash->{helper}{INTERVAL} = 60*60 if( !$hash->{helper}{INTERVAL} );
|
$hash->{helper}{INTERVAL} = 60*60 if( !$hash->{helper}{INTERVAL} );
|
||||||
$attr{$name}{room} = "netatmo" if( !defined($attr{$name}{room}) && defined($name));
|
$attr{$name}{room} = "netatmo" if( !defined($attr{$name}{room}) && defined($name));
|
||||||
@ -509,6 +511,7 @@ sub netatmo_InitWait($) {
|
|||||||
|
|
||||||
RemoveInternalTimer($hash);
|
RemoveInternalTimer($hash);
|
||||||
|
|
||||||
|
return undef if(IsDisabled($name) || !defined($name));
|
||||||
|
|
||||||
if( $init_done ) {
|
if( $init_done ) {
|
||||||
netatmo_connect($hash) if( $hash->{SUBTYPE} eq "ACCOUNT" );
|
netatmo_connect($hash) if( $hash->{SUBTYPE} eq "ACCOUNT" );
|
||||||
@ -755,7 +758,7 @@ netatmo_getAuth($)
|
|||||||
my $webhookurl = AttrVal($name,"webhookURL",'https://webhook.local');
|
my $webhookurl = AttrVal($name,"webhookURL",'https://webhook.local');
|
||||||
|
|
||||||
my $callurl = "https://".$hash->{helper}{apiserver}."/oauth2/authorize";
|
my $callurl = "https://".$hash->{helper}{apiserver}."/oauth2/authorize";
|
||||||
$callurl .= "?client_id=".$hash->{helper}{client_id}."&redirect_uri=".$webhookurl."&scope=read_station read_thermostat write_thermostat read_camera write_camera access_camera read_presence write_presence access_presence read_homecoach read_doorbell access_doorbell read_smokedetector&state=auth".int(rand(100));
|
$callurl .= "?client_id=".$hash->{helper}{client_id}."&redirect_uri=".$webhookurl."&scope=read_thermostat write_thermostat read_camera write_camera access_camera read_doorbell access_doorbell read_presence write_presence access_presence read_homecoach read_carbonmonoxidedetector read_smokedetector read_station&state=auth".int(rand(100));
|
||||||
return $callurl;
|
return $callurl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -765,6 +768,8 @@ netatmo_getToken($)
|
|||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
|
return undef if(IsDisabled($name) || !defined($name));
|
||||||
|
|
||||||
return Log3 $name, 1, "$name: No refresh token was found! (getToken)\nYou will need to generate one at https://dev.netatmo.com/apps/" if(!defined($hash->{helper}{refresh_token}));
|
return Log3 $name, 1, "$name: No refresh token was found! (getToken)\nYou will need to generate one at https://dev.netatmo.com/apps/" if(!defined($hash->{helper}{refresh_token}));
|
||||||
return undef;
|
return undef;
|
||||||
|
|
||||||
@ -777,7 +782,7 @@ netatmo_getToken($)
|
|||||||
url => "https://".$hash->{helper}{apiserver}."/oauth2/token",
|
url => "https://".$hash->{helper}{apiserver}."/oauth2/token",
|
||||||
timeout => 5,
|
timeout => 5,
|
||||||
noshutdown => 1,
|
noshutdown => 1,
|
||||||
data => {grant_type => 'authorization_code', client_id => $hash->{helper}{client_id}, client_secret=> $hash->{helper}{client_secret}, code => $hash->{helper}{access_code}, redirect_uri => $webhookurl, scope => 'read_station read_thermostat write_thermostat read_camera write_camera access_camera read_presence write_presence access_presence read_homecoach read_smokedetector'},
|
data => {grant_type => 'authorization_code', client_id => $hash->{helper}{client_id}, client_secret=> $hash->{helper}{client_secret}, code => $hash->{helper}{access_code}, redirect_uri => $webhookurl, scope => 'read_thermostat write_thermostat read_camera write_camera access_camera read_doorbell access_doorbell read_presence write_presence access_presence read_homecoach read_carbonmonoxidedetector read_smokedetector read_station'},
|
||||||
});
|
});
|
||||||
|
|
||||||
netatmo_dispatch( {hash=>$hash,type=>'token'},$err,$data );
|
netatmo_dispatch( {hash=>$hash,type=>'token'},$err,$data );
|
||||||
@ -790,19 +795,19 @@ netatmo_getAppToken($)
|
|||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
|
return undef if(IsDisabled($name) || !defined($name));
|
||||||
|
|
||||||
return Log3 $name, 1, "$name: No username was found! (getAppToken)" if(!defined($hash->{helper}{username}));
|
return Log3 $name, 1, "$name: No username was found! (getAppToken)" if(!defined($hash->{helper}{username}));
|
||||||
return Log3 $name, 1, "$name: No password was found! (getAppToken)" if(!defined($hash->{helper}{password}));
|
return Log3 $name, 1, "$name: No password was found! (getAppToken)" if(!defined($hash->{helper}{password}));
|
||||||
|
|
||||||
my $auth = "QXV0aG9yaXphdGlvbjogQmFzaWMgYm1GZlkyeHBaVzUwWDJsdmN6bzFObU5qTmpSaU56azBOak5oT1RrMU9HSTNOREF4TkRjeVpEbGxNREUxT0E9PQ==";
|
|
||||||
$auth = decode_base64($auth);
|
|
||||||
|
|
||||||
my($err,$data) = HttpUtils_BlockingGet({
|
my($err,$data) = HttpUtils_BlockingGet({
|
||||||
url => "https://app.netatmo.net/oauth2/token",
|
url => "https://app.netatmo.net/oauth2/token",
|
||||||
method => "POST",
|
method => "POST",
|
||||||
timeout => 5,
|
timeout => 5,
|
||||||
noshutdown => 1,
|
noshutdown => 1,
|
||||||
header => "$auth",
|
header => "Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\nUser-Agent: NetatmoSecurity/5.0.13 (com.netatmo.camera; build:809; iOS 13.5.0) Alamofire/5.6.4",
|
||||||
data => {app_identifier=>'com.netatmo.camera', grant_type => 'password', password => netatmo_decrypt($hash->{helper}{password}), scope => 'write_camera read_camera access_camera read_presence write_presence access_presence read_station read_smokedetector', username => netatmo_decrypt($hash->{helper}{username})},
|
data => {grant_type => 'password', client_secret => '8ab584d62ca2a77e37ccc6b2c7e4f29e', username => netatmo_decrypt($hash->{helper}{username}), password => netatmo_decrypt($hash->{helper}{password}), scope => 'security_scopes read_station', client_id => 'na_client_ios_welcome'},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -890,16 +895,14 @@ netatmo_refreshAppToken($;$)
|
|||||||
delete($hash->{csrf_token});
|
delete($hash->{csrf_token});
|
||||||
Log3 $name, 3, "$name: refreshing app token";
|
Log3 $name, 3, "$name: refreshing app token";
|
||||||
|
|
||||||
my $auth = "QXV0aG9yaXphdGlvbjogQmFzaWMgYm1GZlkyeHBaVzUwWDJsdmN6bzFObU5qTmpSaU56azBOak5oT1RrMU9HSTNOREF4TkRjeVpEbGxNREUxT0E9PQ==";
|
|
||||||
$auth = decode_base64($auth);
|
|
||||||
|
|
||||||
if( $nonblocking ) {
|
if( $nonblocking ) {
|
||||||
HttpUtils_NonblockingGet({
|
HttpUtils_NonblockingGet({
|
||||||
url => "https://app.netatmo.net/oauth2/token",
|
url => "https://app.netatmo.net/oauth2/token",
|
||||||
timeout => 30,
|
timeout => 30,
|
||||||
noshutdown => 1,
|
noshutdown => 1,
|
||||||
header => "$auth",
|
header => "Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\nUser-Agent: NetatmoSecurity/5.0.13 (com.netatmo.camera; build:809; iOS 13.5.0) Alamofire/5.6.4",
|
||||||
data => {grant_type => 'refresh_token', refresh_token => $hash->{refresh_token_app}},
|
data => {refresh_token => $hash->{refresh_token_app}, scope => 'security_scopes read_station', grant_type => 'refresh_token', client_id => 'na_client_ios_welcome', client_secret => '8ab584d62ca2a77e37ccc6b2c7e4f29e'},
|
||||||
hash => $hash,
|
hash => $hash,
|
||||||
type => 'apptoken',
|
type => 'apptoken',
|
||||||
callback => \&netatmo_dispatch,
|
callback => \&netatmo_dispatch,
|
||||||
@ -909,8 +912,8 @@ netatmo_refreshAppToken($;$)
|
|||||||
url => "https://app.netatmo.net/oauth2/token",
|
url => "https://app.netatmo.net/oauth2/token",
|
||||||
timeout => 5,
|
timeout => 5,
|
||||||
noshutdown => 1,
|
noshutdown => 1,
|
||||||
header => "$auth",
|
header => "Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\nUser-Agent: NetatmoSecurity/5.0.13 (com.netatmo.camera; build:809; iOS 13.5.0) Alamofire/5.6.4",
|
||||||
data => {grant_type => 'refresh_token', refresh_token => $hash->{refresh_token_app}},
|
data => {refresh_token => $hash->{refresh_token_app}, scope => 'security_scopes read_station', grant_type => 'refresh_token', client_id => 'na_client_ios_welcome', client_secret => '8ab584d62ca2a77e37ccc6b2c7e4f29e'},
|
||||||
});
|
});
|
||||||
|
|
||||||
netatmo_dispatch( {hash=>$hash,type=>'apptoken'},$err,$data );
|
netatmo_dispatch( {hash=>$hash,type=>'apptoken'},$err,$data );
|
||||||
@ -1035,6 +1038,9 @@ sub
|
|||||||
netatmo_connect($)
|
netatmo_connect($)
|
||||||
{
|
{
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
|
return undef if(IsDisabled($name) || !defined($name));
|
||||||
|
|
||||||
netatmo_getToken($hash);
|
netatmo_getToken($hash);
|
||||||
#netatmo_getAppToken($hash);
|
#netatmo_getAppToken($hash);
|
||||||
@ -1257,6 +1263,8 @@ netatmo_initDevice($)
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return undef if(defined($hash->{IODev}->{NAME}) && IsDisabled($hash->{IODev}->{NAME}) || !defined($name));
|
||||||
|
|
||||||
my $device;
|
my $device;
|
||||||
if( $hash->{Module} ) {
|
if( $hash->{Module} ) {
|
||||||
$device = netatmo_getDeviceDetail( $hash, $hash->{Module} );
|
$device = netatmo_getDeviceDetail( $hash, $hash->{Module} );
|
||||||
@ -3300,17 +3308,29 @@ netatmo_parseToken($$)
|
|||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
my $had_token = $hash->{access_token};
|
my $had_token = $hash->{access_token};
|
||||||
|
my $old_refresh = $hash->{refresh_token};
|
||||||
|
if( $json->{access_token} ) {
|
||||||
|
|
||||||
$hash->{access_token} = $json->{access_token};
|
$hash->{access_token} = $json->{access_token};
|
||||||
$hash->{refresh_token} = $json->{refresh_token};
|
$hash->{refresh_token} = $json->{refresh_token};
|
||||||
|
$hash->{helper}{refresh_token} = $json->{refresh_token};
|
||||||
|
my $new_refresh = $json->{refresh_token};
|
||||||
|
|
||||||
if( $hash->{access_token} ) {
|
|
||||||
$hash->{STATE} = "Connected";
|
$hash->{STATE} = "Connected";
|
||||||
$hash->{network} = "ok";
|
$hash->{network} = "ok";
|
||||||
|
|
||||||
$hash->{expires_at} = int(gettimeofday());
|
$hash->{expires_at} = int(gettimeofday());
|
||||||
$hash->{expires_at} += int($json->{expires_in}*0.8);
|
$hash->{expires_at} += int($json->{expires_in}*0.8);
|
||||||
|
|
||||||
|
if($old_refresh ne $hash->{refresh_token}){
|
||||||
|
if($hash->{DEF} =~ /ACCOUNT/){
|
||||||
|
my @defarray = split(/ /, $hash->{DEF});
|
||||||
|
pop(@defarray);
|
||||||
|
push(@defarray, $json->{refresh_token});
|
||||||
|
$hash->{DEF} = join(' ', @defarray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
netatmo_getDevices($hash) if( !$had_token );
|
netatmo_getDevices($hash) if( !$had_token );
|
||||||
|
|
||||||
InternalTimer($hash->{expires_at}, "netatmo_refreshTokenTimer", $hash);
|
InternalTimer($hash->{expires_at}, "netatmo_refreshTokenTimer", $hash);
|
||||||
@ -6713,7 +6733,7 @@ sub netatmo_weatherIcon()
|
|||||||
Notes:
|
Notes:
|
||||||
<ul>
|
<ul>
|
||||||
<li>JSON has to be installed on the FHEM host.</li>
|
<li>JSON has to be installed on the FHEM host.</li>
|
||||||
<li>You need to create an app <u><a href="https://dev.netatmo.com/dev/createanapp">here</a></u> to get your <i>client_id / client_secret</i>.<br />Request the full access scope including cameras and thermostats and generate a refresh token.</li>
|
<li>You need to create an app <u><a href="https://dev.netatmo.com/apps/">here</a></u> to get your <i>client_id / client_secret</i>.<br />Request the full access scope including cameras and thermostats and generate a refresh token on the dev.netatmo.com page.</li>
|
||||||
</ul><br>
|
</ul><br>
|
||||||
|
|
||||||
<a name="netatmo_Define"></a>
|
<a name="netatmo_Define"></a>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user