@@ -158,6 +158,8 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
158
158
159
159
private String localToken = "" ;
160
160
161
+ private String accessToken = "" ;
162
+
161
163
private Map <String , SomfyTahomaDevice > devicePlaces = new HashMap <>();
162
164
163
165
private ExpiringCache <List <SomfyTahomaDevice >> cachedDevices = new ExpiringCache <>(Duration .ofSeconds (30 ),
@@ -261,62 +263,29 @@ public synchronized void login() {
261
263
cloudFallback = false ;
262
264
263
265
try {
264
- String urlParameters = "" ;
266
+ lastLoginTimestamp = Instant . now () ;
265
267
266
- // if cozytouch, must use oauth server
267
268
if (thingConfig .getCloudPortal ().equalsIgnoreCase (COZYTOUCH_PORTAL )) {
268
- logger .debug ("CozyTouch Oauth2 authentication flow" );
269
- urlParameters = "jwt=" + loginCozytouch ();
269
+ if (!loginCozyTouch ()) {
270
+ return ;
271
+ }
270
272
} else {
271
- urlParameters = "userId=" + urlEncode (thingConfig .getEmail ()) + "&userPassword="
272
- + urlEncode (thingConfig .getPassword ());
273
+ loginOAUTH ();
273
274
}
274
275
275
- ContentResponse response = sendRequestBuilder ("login" , HttpMethod .POST )
276
- .content (new StringContentProvider (urlParameters ),
277
- "application/x-www-form-urlencoded; charset=UTF-8" )
278
- .send ();
279
-
280
- if (logger .isTraceEnabled ()) {
281
- logger .trace ("Login response: {}" , response .getContentAsString ());
276
+ if (thingConfig .isDevMode ()) {
277
+ initializeLocalMode ();
282
278
}
283
279
284
- SomfyTahomaLoginResponse data = gson .fromJson (response .getContentAsString (),
285
- SomfyTahomaLoginResponse .class );
286
-
287
- lastLoginTimestamp = Instant .now ();
288
-
289
- if (data == null ) {
290
- updateStatus (ThingStatus .OFFLINE , ThingStatusDetail .COMMUNICATION_ERROR ,
291
- "Received invalid data (login)" );
292
- } else if (!data .getErrorCode ().isEmpty ()) {
293
- updateStatus (ThingStatus .OFFLINE , ThingStatusDetail .COMMUNICATION_ERROR , data .getError ());
294
- if (data .getError ().startsWith (TOO_MANY_REQUESTS )) {
295
- setTooManyRequests ();
296
- }
280
+ String id = registerEvents ();
281
+ if (id != null && !UNAUTHORIZED .equals (id )) {
282
+ eventsId = id ;
283
+ logger .debug ("Events id: {}" , eventsId );
284
+ updateStatus (ThingStatus .ONLINE , ThingStatusDetail .NONE ,
285
+ isDevModeReady () ? "LAN mode" : cloudFallback ? "Cloud mode fallback" : "Cloud mode" );
297
286
} else {
298
- if (thingConfig .isDevMode ()) {
299
- initializeLocalMode ();
300
- }
301
-
302
- String id = registerEvents ();
303
- if (id != null && !UNAUTHORIZED .equals (id )) {
304
- eventsId = id ;
305
- logger .debug ("Events id: {}" , eventsId );
306
- updateStatus (ThingStatus .ONLINE , ThingStatusDetail .NONE ,
307
- isDevModeReady () ? "LAN mode" : cloudFallback ? "Cloud mode fallback" : "Cloud mode" );
308
- } else {
309
- logger .debug ("Events id error: {}" , id );
310
- if (!thingConfig .isDevMode ()) {
311
- updateStatus (ThingStatus .OFFLINE , ThingStatusDetail .COMMUNICATION_ERROR ,
312
- "unable to register events" );
313
- } else {
314
- updateStatus (ThingStatus .OFFLINE , ThingStatusDetail .COMMUNICATION_ERROR ,
315
- "LAN mode is not properly configured" );
316
- logger .debug ("Forcing the gateway discovery" );
317
- discoverGateway ();
318
- }
319
- }
287
+ logger .debug ("Events id error: {}" , id );
288
+ updateStatus (ThingStatus .OFFLINE , ThingStatusDetail .COMMUNICATION_ERROR , "unable to register events" );
320
289
}
321
290
} catch (JsonSyntaxException e ) {
322
291
logger .debug ("Received invalid data (login)" , e );
@@ -339,6 +308,33 @@ public synchronized void login() {
339
308
}
340
309
}
341
310
311
+ private boolean loginCozyTouch ()
312
+ throws ExecutionException , InterruptedException , TimeoutException , JsonSyntaxException {
313
+ logger .debug ("CozyTouch Oauth2 authentication flow" );
314
+ String urlParameters = "jwt=" + getCozytouchJWT ();
315
+ ContentResponse response = sendRequestBuilder ("login" , HttpMethod .POST )
316
+ .content (new StringContentProvider (urlParameters ), "application/x-www-form-urlencoded; charset=UTF-8" )
317
+ .send ();
318
+
319
+ if (logger .isTraceEnabled ()) {
320
+ logger .trace ("Login response: {}" , response .getContentAsString ());
321
+ }
322
+
323
+ SomfyTahomaLoginResponse data = gson .fromJson (response .getContentAsString (), SomfyTahomaLoginResponse .class );
324
+
325
+ if (data == null ) {
326
+ updateStatus (ThingStatus .OFFLINE , ThingStatusDetail .COMMUNICATION_ERROR , "Received invalid data (login)" );
327
+ return false ;
328
+ } else if (!data .getErrorCode ().isEmpty ()) {
329
+ updateStatus (ThingStatus .OFFLINE , ThingStatusDetail .COMMUNICATION_ERROR , data .getError ());
330
+ if (data .getError ().startsWith (TOO_MANY_REQUESTS )) {
331
+ setTooManyRequests ();
332
+ }
333
+ return false ;
334
+ }
335
+ return true ;
336
+ }
337
+
342
338
public boolean isDevModeReady () {
343
339
return thingConfig .isDevMode () && !localToken .isEmpty () && !cloudFallback ;
344
340
}
@@ -507,6 +503,7 @@ private void cleanup() {
507
503
508
504
// Clean access data
509
505
localToken = "" ;
506
+ accessToken = "" ;
510
507
}
511
508
512
509
@ Override
@@ -852,10 +849,16 @@ private boolean isLocalRequest(String subUrl) {
852
849
}
853
850
854
851
private Request sendRequestBuilderCloud (String subUrl , HttpMethod method ) {
855
- return httpClient .newRequest (getApiFullUrl (subUrl )).method (method )
852
+ Request request = httpClient .newRequest (getApiFullUrl (subUrl )).method (method )
856
853
.header (HttpHeader .ACCEPT_LANGUAGE , "en-US,en" ).header (HttpHeader .ACCEPT_ENCODING , "gzip, deflate" )
857
854
.header ("X-Requested-With" , "XMLHttpRequest" ).timeout (TAHOMA_TIMEOUT , TimeUnit .SECONDS )
858
855
.agent (TAHOMA_AGENT );
856
+
857
+ if (!thingConfig .getCloudPortal ().equalsIgnoreCase (COZYTOUCH_PORTAL )) {
858
+ // user OAuth token if not cozytouch
859
+ request = request .header (HttpHeader .AUTHORIZATION , "Bearer " + accessToken );
860
+ }
861
+ return request ;
859
862
}
860
863
861
864
private Request sendRequestBuilderLocal (String subUrl , HttpMethod method ) {
@@ -872,7 +875,7 @@ private Request sendRequestBuilderLocal(String subUrl, HttpMethod method) {
872
875
* @throws InterruptedException
873
876
* @throws JsonSyntaxException
874
877
*/
875
- private String loginCozytouch ()
878
+ private String getCozytouchJWT ()
876
879
throws InterruptedException , TimeoutException , ExecutionException , JsonSyntaxException {
877
880
String authBaseUrl = "https://" + COZYTOUCH_OAUTH2_URL ;
878
881
@@ -920,6 +923,42 @@ private String loginCozytouch()
920
923
}
921
924
}
922
925
926
+ private void loginOAUTH () throws InterruptedException , TimeoutException , ExecutionException , JsonSyntaxException {
927
+ String authBaseUrl = "https://" + SOMFY_OAUTH2_URL ;
928
+
929
+ String urlParameters = "client_id=" + SOMFY_OAUTH2_CLIENT_ID + "&client_secret=" + SOMFY_OAUTH2_CLIENT_SECRET
930
+ + "&grant_type=password&username=" + urlEncode (thingConfig .getEmail ()) + "&password="
931
+ + urlEncode (thingConfig .getPassword ());
932
+
933
+ ContentResponse response = httpClient .newRequest (authBaseUrl ).method (HttpMethod .POST )
934
+ .header (HttpHeader .ACCEPT_LANGUAGE , "en-US,en" ).header (HttpHeader .ACCEPT_ENCODING , "gzip, deflate" )
935
+ .header ("X-Requested-With" , "XMLHttpRequest" ).timeout (TAHOMA_TIMEOUT , TimeUnit .SECONDS )
936
+ .agent (TAHOMA_AGENT )
937
+ .content (new StringContentProvider (urlParameters ), "application/x-www-form-urlencoded; charset=UTF-8" )
938
+ .send ();
939
+
940
+ if (response .getStatus () != 200 ) {
941
+ // Login error
942
+ if (response .getHeaders ().getField (HttpHeader .CONTENT_TYPE ).getValue ()
943
+ .equalsIgnoreCase (MediaType .APPLICATION_JSON )) {
944
+ try {
945
+ SomfyTahomaOauth2Error error = gson .fromJson (response .getContentAsString (),
946
+ SomfyTahomaOauth2Error .class );
947
+ throw new ExecutionException (error .getErrorDescription (), null );
948
+ } catch (JsonSyntaxException e ) {
949
+ }
950
+ }
951
+ throw new ExecutionException ("Unknown error while attempting to log in." , null );
952
+ }
953
+
954
+ SomfyTahomaOauth2Reponse oauth2response = gson .fromJson (response .getContentAsString (),
955
+ SomfyTahomaOauth2Reponse .class );
956
+
957
+ logger .debug ("OAuth2 Access Token: {}" , oauth2response .getAccessToken ());
958
+
959
+ accessToken = oauth2response .getAccessToken ();
960
+ }
961
+
923
962
private String getApiFullUrl (String subUrl ) {
924
963
return isLocalRequest (subUrl )
925
964
? "https://" + thingConfig .getIp () + ":8443/enduser-mobile-web/1/enduserAPI/" + subUrl
@@ -1036,6 +1075,7 @@ private boolean reLogin() {
1036
1075
logger .debug ("Doing relogin" );
1037
1076
reLoginNeeded = true ;
1038
1077
localToken = "" ;
1078
+ accessToken = "" ;
1039
1079
login ();
1040
1080
return ThingStatus .OFFLINE != thing .getStatus ();
1041
1081
}
0 commit comments