]> git.basschouten.com Git - openhab-addons.git/commitdiff
[netatmo] Compatibility with OpenHAB 3 (Update to newer Swagger version and code...
authorSven Strohschein <novanic@gmx.de>
Sun, 4 Oct 2020 10:07:23 +0000 (12:07 +0200)
committerGitHub <noreply@github.com>
Sun, 4 Oct 2020 10:07:23 +0000 (12:07 +0200)
Swagger upgrade for the Netatmo binding (required to use the OAS 3 Swagger annotations, the old annotations dependencies were removed with OpenHAB 3)
- Swagger-Codegen updated to the latest version (to generate the OAS 3 Swagger annotations)
- Retrofit replaced by the default code generation (Retrofit 1 code generation is broken with newer swagger-codegen versions and an update to Retrofit 2 is also incompatible and would require more dependencies)
- NULL handling for collections introduced (newer versions of the Swagger codegen return NULL for empty collections instead of an empty collection ...)
- The binding is now working completely again (compiles and starts), but there are still some TODOs

Signed-off-by: Sven Strohschein <sven.strohschein@gmail.com>
sven.strohschein@gmail.com>

21 files changed:
bundles/org.openhab.binding.netatmo/NOTICE
bundles/org.openhab.binding.netatmo/pom.xml
bundles/org.openhab.binding.netatmo/src/main/feature/feature.xml [new file with mode: 0644]
bundles/org.openhab.binding.netatmo/src/main/feature/feature.xml.bak.xml [deleted file]
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/APIUtils.java [new file with mode: 0644]
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/camera/CameraHandler.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/discovery/NetatmoModuleDiscoveryService.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/MeasurableChannels.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/NetatmoBridgeHandler.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/NetatmoDeviceHandler.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/homecoach/NAHealthyHomeCoachHandler.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAMainHandler.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule1Handler.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule2Handler.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule3Handler.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/station/NAModule4Handler.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/thermostat/NAPlugHandler.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/thermostat/NATherm1Handler.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomeHomeHandler.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/welcome/NAWelcomePersonHandler.java
bundles/pom.xml

index 41d3f500d0473f28f0e6183c34049b846f26ef13..33e1210cf574da90fee6c1b96e36b7c5b4203114 100644 (file)
@@ -19,6 +19,11 @@ commons-codec
 * Project; https://commons.apache.org/proper/commons-codec
 * Source:  https://commons.apache.org/proper/commons-codec
 
+gson-fire
+* License: Apache 2.0 License
+* Project: http://gsonfire.io
+* Source:  https://github.com/julman99/gson-fire
+
 json
 * License: JSON License
 * Project: https://www.json.org
@@ -43,8 +48,3 @@ netatmo-swagger-decl
 * License: MIT License
 * Project: https://dev.netatmo.com
 * Source:  https://github.com/cbornet/netatmo-swagger-decl
-
-retrofit
-* License: Apache 2.0 License
-* Project: https://square.github.io/retrofit
-* Source:  https://github.com/square/retrofit
index 63bfd013c8cdcbf775af4129a4382ecaac0334e6..62686d0ac6ecb7e01c78a8826a6269bcbf8e6eca 100644 (file)
@@ -15,7 +15,7 @@
   <name>openHAB Add-ons :: Bundles :: Netatmo Binding</name>
 
   <properties>
-    <dep.noembedding>com.squareup.okhttp.okhttp,com.squareup.okio.okio-1.3.0,com.squareup.retrofit.retrofit,org.apache.oltu.oauth2.client,org.apache.oltu.oauth2.common</dep.noembedding>
+    <bnd.importpackage>!android.*,!com.android.org.*,!org.apache.harmony.*,!sun.*,!org.apache.oltu.*</bnd.importpackage>
   </properties>
 
   <dependencies>
       <scope>compile</scope>
     </dependency>
     <dependency>
-      <groupId>org.openhab.osgiify</groupId>
-      <artifactId>com.squareup.okhttp.okhttp</artifactId>
-      <version>2.3.0</version>
+      <groupId>com.squareup.okhttp</groupId>
+      <artifactId>okhttp</artifactId>
+      <version>2.7.5</version>
       <scope>compile</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>com.google.android</groupId>
+          <artifactId>*</artifactId>
+        </exclusion>
+      </exclusions>
     </dependency>
     <dependency>
-      <groupId>org.openhab.osgiify</groupId>
-      <artifactId>com.squareup.okio.okio-1.3.0</artifactId>
-      <version>1.3.0</version>
+      <groupId>com.squareup.okhttp</groupId>
+      <artifactId>logging-interceptor</artifactId>
+      <version>2.7.5</version>
       <scope>compile</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>com.google.android</groupId>
+          <artifactId>*</artifactId>
+        </exclusion>
+      </exclusions>
     </dependency>
     <dependency>
-      <groupId>org.openhab.osgiify</groupId>
-      <artifactId>com.squareup.retrofit.retrofit</artifactId>
-      <version>1.9.0</version>
+      <groupId>com.squareup.okio</groupId>
+      <artifactId>okio</artifactId>
+      <version>1.6.0</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>io.gsonfire</groupId>
+      <artifactId>gson-fire</artifactId>
+      <version>1.8.4</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <version>1.0.0</version>
       <scope>compile</scope>
     </dependency>
+    <dependency>
+      <groupId>commons-codec</groupId>
+      <artifactId>commons-codec</artifactId>
+      <version>1.8</version>
+      <scope>compile</scope>
+    </dependency>
   </dependencies>
 
   <build>
     <plugins>
       <plugin>
-        <groupId>io.swagger</groupId>
+        <groupId>io.swagger.codegen.v3</groupId>
         <artifactId>swagger-codegen-maven-plugin</artifactId>
-        <version>2.1.6</version>
+        <version>3.0.21</version>
         <executions>
           <execution>
             <goals>
             <configuration>
               <inputSpec>https://raw.githubusercontent.com/cbornet/netatmo-swagger-decl/35e27745fb0d432bc6c8b5ec7a83ed2a09944cea/spec/swagger.yaml</inputSpec>
               <language>java</language>
-              <library>retrofit</library>
+              <generateApiTests>false</generateApiTests>
+              <generateModelTests>false</generateModelTests>
               <configOptions>
                 <sourceFolder>src/main/java</sourceFolder>
+                <java8>true</java8>
+                <dateLibrary>java8-localdatetime</dateLibrary>
+                <useRuntimeException>true</useRuntimeException>
               </configOptions>
             </configuration>
           </execution>
diff --git a/bundles/org.openhab.binding.netatmo/src/main/feature/feature.xml b/bundles/org.openhab.binding.netatmo/src/main/feature/feature.xml
new file mode 100644 (file)
index 0000000..21b41c9
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<features name="org.openhab.binding.netatmo-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
+       <repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
+
+       <feature name="openhab-binding-netatmo" description="Netatmo Binding" version="${project.version}">
+               <feature>openhab-runtime-base</feature>
+               <bundle dependency="true">mvn:org.openhab.osgiify/org.json.json/20131018</bundle>
+               <bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.netatmo/${project.version}</bundle>
+       </feature>
+</features>
diff --git a/bundles/org.openhab.binding.netatmo/src/main/feature/feature.xml.bak.xml b/bundles/org.openhab.binding.netatmo/src/main/feature/feature.xml.bak.xml
deleted file mode 100644 (file)
index fb52bfe..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<features name="org.openhab.binding.netatmo-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
-       <repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
-
-       <feature name="openhab-binding-netatmo" description="Netatmo Binding" version="${project.version}">
-               <feature>openhab-runtime-base</feature>
-               <bundle dependency="true">mvn:org.openhab.osgiify/org.json.json/20131018</bundle>
-               <bundle dependency="true">mvn:org.openhab.osgiify/com.squareup.okhttp.okhttp/2.3.0</bundle>
-               <bundle dependency="true">mvn:org.openhab.osgiify/com.squareup.okio.okio-1.3.0/1.3.0</bundle>
-               <bundle dependency="true">mvn:org.openhab.osgiify/com.squareup.retrofit.retrofit/1.9.0</bundle>
-               <bundle dependency="true">mvn:org.apache.oltu.oauth2/org.apache.oltu.oauth2.client/1.0.0</bundle>
-               <bundle dependency="true">mvn:org.apache.oltu.oauth2/org.apache.oltu.oauth2.common/1.0.0</bundle>
-               <bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.netatmo/${project.version}</bundle>
-       </feature>
-</features>
diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/APIUtils.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/APIUtils.java
new file mode 100644 (file)
index 0000000..378adcc
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.netatmo.internal;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * {@link APIUtils} provides util methods for the usage of the generated API classes.
+ *
+ * @author Sven Strohschein - Initial contribution
+ */
+@NonNullByDefault
+public final class APIUtils {
+
+    private APIUtils() {
+    }
+
+    public static <T> Stream<T> nonNullStream(Collection<T> collection) {
+        return Optional.ofNullable(collection).stream().flatMap(Collection::stream);
+    }
+
+    public static <T> List<T> nonNullList(List<T> list) {
+        return Optional.ofNullable(list).orElse(Collections.emptyList());
+    }
+}
index 46230c7d8090015f8471273a19c40d8ae63cea6c..ecc0ac32de8e416af4df7fc8db701f94b828420e 100644 (file)
@@ -19,7 +19,6 @@ import java.io.IOException;
 import java.util.Optional;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.openhab.binding.netatmo.internal.ChannelTypeUtils;
@@ -53,10 +52,11 @@ public abstract class CameraHandler extends NetatmoModuleHandler<NAWelcomeCamera
 
     private final Logger logger = LoggerFactory.getLogger(CameraHandler.class);
 
-    private @Nullable CameraAddress cameraAddress;
+    private Optional<CameraAddress> cameraAddress;
 
     protected CameraHandler(Thing thing, final TimeZoneProvider timeZoneProvider) {
         super(thing, timeZoneProvider);
+        cameraAddress = Optional.empty();
     }
 
     @Override
@@ -114,7 +114,7 @@ public abstract class CameraHandler extends NetatmoModuleHandler<NAWelcomeCamera
     }
 
     protected State getIsLocalState() {
-        return getModule().map(m -> toOnOffType(m.getIsLocal())).orElse(UnDefType.UNDEF);
+        return getModule().map(m -> toOnOffType(m.isIsLocal())).orElse(UnDefType.UNDEF);
     }
 
     protected State getLivePictureURLState() {
@@ -181,7 +181,7 @@ public abstract class CameraHandler extends NetatmoModuleHandler<NAWelcomeCamera
     }
 
     private boolean isLocal() {
-        return getModule().map(NAWelcomeCamera::getIsLocal).orElse(false);
+        return getModule().map(NAWelcomeCamera::isIsLocal).orElse(false);
     }
 
     private void switchVideoSurveillance(boolean isOn) {
@@ -201,20 +201,20 @@ public abstract class CameraHandler extends NetatmoModuleHandler<NAWelcomeCamera
 
     protected Optional<String> getLocalCameraURL() {
         Optional<String> vpnURLOptional = getVpnUrl();
-        CameraAddress address = cameraAddress;
+        Optional<CameraAddress> address = cameraAddress;
         if (vpnURLOptional.isPresent()) {
             final String vpnURL = vpnURLOptional.get();
 
             // The local address is (re-)requested when it wasn't already determined or when the vpn address was
             // changed.
-            if (address == null || address.isVpnURLChanged(vpnURL)) {
+            if (!address.isPresent() || address.get().isVpnURLChanged(vpnURL)) {
                 Optional<JSONObject> json = executeGETRequestJSON(vpnURL + PING_URL_PATH);
                 address = json.map(j -> j.optString("local_url", null))
-                        .map(localURL -> new CameraAddress(vpnURL, localURL)).orElse(null);
+                        .map(localURL -> new CameraAddress(vpnURL, localURL));
                 cameraAddress = address;
             }
         }
-        return Optional.ofNullable(address).map(CameraAddress::getLocalURL);
+        return address.map(CameraAddress::getLocalURL);
     }
 
     private Optional<JSONObject> executeGETRequestJSON(String url) {
index a8224d794514dff9941b86b24a1b355dc03bb9d0..ee23eeddead3918b1ebaa9542cfab234a353c106 100644 (file)
  */
 package org.openhab.binding.netatmo.internal.discovery;
 
+import static org.openhab.binding.netatmo.internal.APIUtils.*;
 import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -71,28 +73,28 @@ public class NetatmoModuleDiscoveryService extends AbstractDiscoveryService impl
     public void startScan() {
         if (netatmoBridgeHandler.configuration.readStation) {
             netatmoBridgeHandler.getStationsDataBody(null).ifPresent(dataBody -> {
-                dataBody.getDevices().forEach(station -> {
+                nonNullList(dataBody.getDevices()).forEach(station -> {
                     discoverWeatherStation(station);
                 });
             });
         }
         if (netatmoBridgeHandler.configuration.readHealthyHomeCoach) {
             netatmoBridgeHandler.getHomecoachDataBody(null).ifPresent(dataBody -> {
-                dataBody.getDevices().forEach(homecoach -> {
+                nonNullList(dataBody.getDevices()).forEach(homecoach -> {
                     discoverHomeCoach(homecoach);
                 });
             });
         }
         if (netatmoBridgeHandler.configuration.readThermostat) {
             netatmoBridgeHandler.getThermostatsDataBody(null).ifPresent(dataBody -> {
-                dataBody.getDevices().forEach(plug -> {
+                nonNullList(dataBody.getDevices()).forEach(plug -> {
                     discoverThermostat(plug);
                 });
             });
         }
         if (netatmoBridgeHandler.configuration.readWelcome || netatmoBridgeHandler.configuration.readPresence) {
             netatmoBridgeHandler.getWelcomeDataBody(null).ifPresent(dataBody -> {
-                dataBody.getHomes().forEach(home -> {
+                nonNullList(dataBody.getHomes()).forEach(home -> {
                     discoverWelcomeHome(home);
                 });
             });
@@ -123,7 +125,7 @@ public class NetatmoModuleDiscoveryService extends AbstractDiscoveryService impl
 
     private void discoverThermostat(NAPlug plug) {
         onDeviceAddedInternal(plug.getId(), null, plug.getType(), plug.getStationName(), plug.getFirmware());
-        plug.getModules().forEach(thermostat -> {
+        nonNullList(plug.getModules()).forEach(thermostat -> {
             onDeviceAddedInternal(thermostat.getId(), plug.getId(), thermostat.getType(), thermostat.getModuleName(),
                     thermostat.getFirmware());
         });
@@ -135,11 +137,11 @@ public class NetatmoModuleDiscoveryService extends AbstractDiscoveryService impl
     }
 
     private void discoverWeatherStation(NAMain station) {
-        final boolean isFavorite = station.getFavorite() != null && station.getFavorite();
+        final boolean isFavorite = station.isFavorite() != null && station.isFavorite();
         final String weatherStationName = createWeatherStationName(station, isFavorite);
 
         onDeviceAddedInternal(station.getId(), null, station.getType(), weatherStationName, station.getFirmware());
-        station.getModules().forEach(module -> {
+        nonNullList(station.getModules()).forEach(module -> {
             onDeviceAddedInternal(module.getId(), station.getId(), module.getType(),
                     createWeatherModuleName(station, module, isFavorite), module.getFirmware());
         });
@@ -148,15 +150,16 @@ public class NetatmoModuleDiscoveryService extends AbstractDiscoveryService impl
     private void discoverWelcomeHome(NAWelcomeHome home) {
         // I observed that Thermostat homes are also reported here by Netatmo API
         // So I ignore homes that have an empty list of cameras
-        if (!home.getCameras().isEmpty()) {
+        List<NAWelcomeCamera> cameras = nonNullList(home.getCameras());
+        if (!cameras.isEmpty()) {
             onDeviceAddedInternal(home.getId(), null, WELCOME_HOME_THING_TYPE.getId(), home.getName(), null);
             // Discover Cameras
-            home.getCameras().forEach(camera -> {
+            cameras.forEach(camera -> {
                 onDeviceAddedInternal(camera.getId(), home.getId(), camera.getType(), camera.getName(), null);
             });
 
             // Discover Known Persons
-            home.getPersons().stream().filter(person -> person.getPseudo() != null).forEach(person -> {
+            nonNullStream(home.getPersons()).filter(person -> person.getPseudo() != null).forEach(person -> {
                 onDeviceAddedInternal(person.getId(), home.getId(), WELCOME_PERSON_THING_TYPE.getId(),
                         person.getPseudo(), null);
             });
index eead1771168454efeed181fad5ee71161f18215a..1df657b79546fd49cab4caf0041f7bd51b04d930 100644 (file)
@@ -12,6 +12,7 @@
  */
 package org.openhab.binding.netatmo.internal.handler;
 
+import static org.openhab.binding.netatmo.internal.APIUtils.*;
 import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.MEASURABLE_CHANNELS;
 
 import java.util.ArrayList;
@@ -24,7 +25,7 @@ import org.openhab.binding.netatmo.internal.ChannelTypeUtils;
 import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.types.State;
 
-import io.swagger.client.CollectionFormats.CSVParams;
+import io.swagger.client.model.NAMeasureBodyElem;
 import io.swagger.client.model.NAMeasureResponse;
 
 /**
@@ -64,10 +65,11 @@ public class MeasurableChannels {
         int index = measuredChannels.indexOf(channelId);
         NAMeasureResponse theMeasures = measures;
         if (index != -1 && theMeasures != null) {
-            if (!theMeasures.getBody().isEmpty()) {
-                List<List<Float>> valueList = theMeasures.getBody().get(0).getValue();
+            List<NAMeasureBodyElem> body = nonNullList(theMeasures.getBody());
+            if (!body.isEmpty()) {
+                List<List<Float>> valueList = nonNullList(body.get(0).getValue());
                 if (!valueList.isEmpty()) {
-                    List<Float> values = valueList.get(0);
+                    List<Float> values = nonNullList(valueList.get(0));
                     if (values.size() >= index) {
                         Float value = values.get(index);
                         return Optional.of(ChannelTypeUtils.toDecimalType(value));
@@ -78,9 +80,9 @@ public class MeasurableChannels {
         return Optional.empty();
     }
 
-    public Optional<CSVParams> getAsCsv() {
+    public Optional<List<String>> getMeasuredChannels() {
         if (!measuredChannels.isEmpty()) {
-            return Optional.of(new CSVParams(measuredChannels));
+            return Optional.of(measuredChannels);
         }
         return Optional.empty();
     }
index 23043ba77e38bbf6383bff203210d1f9147d030e..1cdfc31efe0acc83c55bcdda06e670456e81db96 100644 (file)
@@ -14,11 +14,13 @@ package org.openhab.binding.netatmo.internal.handler;
 
 import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
 
+import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -26,7 +28,13 @@ import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Stream;
 
+import org.apache.oltu.oauth2.client.OAuthClient;
+import org.apache.oltu.oauth2.client.URLConnectionClient;
 import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
+import org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse;
+import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+import org.apache.oltu.oauth2.common.message.types.GrantType;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.netatmo.internal.config.NetatmoBridgeConfiguration;
@@ -44,25 +52,20 @@ import org.openhab.core.types.Command;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.squareup.okhttp.OkHttpClient;
-
 import io.swagger.client.ApiClient;
-import io.swagger.client.CollectionFormats.CSVParams;
+import io.swagger.client.ApiException;
 import io.swagger.client.api.HealthyhomecoachApi;
 import io.swagger.client.api.PartnerApi;
 import io.swagger.client.api.StationApi;
 import io.swagger.client.api.ThermostatApi;
 import io.swagger.client.api.WelcomeApi;
+import io.swagger.client.auth.Authentication;
 import io.swagger.client.auth.OAuth;
-import io.swagger.client.auth.OAuthFlow;
 import io.swagger.client.model.NAHealthyHomeCoachDataBody;
 import io.swagger.client.model.NAMeasureBodyElem;
 import io.swagger.client.model.NAStationDataBody;
 import io.swagger.client.model.NAThermostatDataBody;
 import io.swagger.client.model.NAWelcomeHomeData;
-import retrofit.RestAdapter.LogLevel;
-import retrofit.RetrofitError;
-import retrofit.RetrofitError.Kind;
 
 /**
  * {@link NetatmoBridgeHandler} is the handler for a Netatmo API and connects it
@@ -79,25 +82,34 @@ public class NetatmoBridgeHandler extends BaseBridgeHandler {
 
     public NetatmoBridgeConfiguration configuration = new NetatmoBridgeConfiguration();
     private @Nullable ScheduledFuture<?> refreshJob;
-    private @Nullable APIMap apiMap;
+    private @Nullable APICreator apiCreator;
     private @Nullable WelcomeWebHookServlet webHookServlet;
     private List<NetatmoDataListener> dataListeners = new CopyOnWriteArrayList<>();
 
-    private class APIMap extends HashMap<Class<?>, Object> {
-        private static final long serialVersionUID = -2024031764691952343L;
-        private ApiClient apiClient;
+    private static class APICreator {
+
+        private final ApiClient apiClient;
+        private final Map<Class<?>, Object> apiMap;
 
-        public APIMap(ApiClient apiClient) {
+        private APICreator(ApiClient apiClient) {
             super();
             this.apiClient = apiClient;
+            apiMap = new HashMap<>();
         }
 
-        public Object get(Class<?> apiClass) {
-            if (!super.containsKey(apiClass)) {
-                Object api = apiClient.createService(apiClass);
-                super.put(apiClass, api);
+        @SuppressWarnings("unchecked")
+        public <T> T getAPI(Class<T> apiClass) {
+            T api = (T) apiMap.get(apiClass);
+            if (api == null) {
+                try {
+                    api = apiClass.getDeclaredConstructor(ApiClient.class).newInstance(apiClient);
+                } catch (InstantiationException | IllegalAccessException | InvocationTargetException
+                        | NoSuchMethodException e) {
+                    throw new RuntimeException("Error on executing API class constructor!", e);
+                }
+                apiMap.put(apiClass, api);
             }
-            return super.get(apiClass);
+            return api;
         }
     }
 
@@ -136,37 +148,29 @@ public class NetatmoBridgeHandler extends BaseBridgeHandler {
                 // I use a connection to Netatmo API using PartnerAPI to ensure that API is reachable
                 getPartnerApi().partnerdevices();
                 connectionSucceed();
-            } catch (RetrofitError e) {
-                if (e.getKind() == Kind.NETWORK) {
-                    logger.warn("Network error while connecting to Netatmo API, will retry in {} s",
-                            configuration.reconnectInterval);
-                    updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
-                            "Netatmo Access Failed, will retry in " + configuration.reconnectInterval + " seconds.");
-                } else {
-                    switch (e.getResponse().getStatus()) {
-                        case 404: // If no partner station has been associated - likely to happen - we'll have this
-                                  // error
-                                  // but it means connection to API is OK
-                            connectionSucceed();
-                            break;
-                        case 403: // Forbidden Access maybe too many requests ? Let's wait next cycle
-                            logger.warn("Error 403 while connecting to Netatmo API, will retry in {} s",
-                                    configuration.reconnectInterval);
-                            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
-                                    "Netatmo Access Forbidden, will retry in " + configuration.reconnectInterval
-                                            + " seconds.");
-                            break;
-                        default:
-                            if (logger.isDebugEnabled()) {
-                                // we also attach the stack trace
-                                logger.error("Unable to connect Netatmo API : {}", e.getMessage(), e);
-                            } else {
-                                logger.error("Unable to connect Netatmo API : {}", e.getMessage());
-                            }
-                            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
-                                    "Unable to connect Netatmo API : " + e.getLocalizedMessage());
-                            return;
-                    }
+            } catch (ApiException e) {
+                switch (e.getCode()) {
+                    case 404: // If no partner station has been associated - likely to happen - we'll have this
+                              // error
+                              // but it means connection to API is OK
+                        connectionSucceed();
+                        break;
+                    case 403: // Forbidden Access maybe too many requests ? Let's wait next cycle
+                        logger.warn("Error 403 while connecting to Netatmo API, will retry in {} s",
+                                configuration.reconnectInterval);
+                        updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+                                "Netatmo Access Forbidden, will retry in " + configuration.reconnectInterval
+                                        + " seconds.");
+                        break;
+                    default:
+                        if (logger.isDebugEnabled()) {
+                            // we also attach the stack trace
+                            logger.error("Unable to connect Netatmo API : {}", e.getMessage(), e);
+                        } else {
+                            logger.error("Unable to connect Netatmo API : {}", e.getMessage());
+                        }
+                        updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+                                "Unable to connect Netatmo API : " + e.getLocalizedMessage());
                 }
             } catch (RuntimeException e) {
                 logger.warn("Unable to connect Netatmo API : {}", e.getMessage(), e);
@@ -177,22 +181,31 @@ public class NetatmoBridgeHandler extends BaseBridgeHandler {
         }, 2, configuration.reconnectInterval, TimeUnit.SECONDS);
     }
 
-    private void initializeApiClient() throws RetrofitError {
-        ApiClient apiClient = new ApiClient();
+    private void initializeApiClient() {
+        try {
+            ApiClient apiClient = new ApiClient();
 
-        OAuth auth = new OAuth(new OkHttpClient(),
-                OAuthClientRequest.tokenLocation("https://api.netatmo.net/oauth2/token"));
-        auth.setFlow(OAuthFlow.password);
-        auth.setAuthenticationRequestBuilder(OAuthClientRequest.authorizationLocation(""));
+            OAuthClientRequest oAuthRequest = OAuthClientRequest.tokenLocation("https://api.netatmo.net/oauth2/token")
+                    .setClientId(configuration.clientId).setClientSecret(configuration.clientSecret)
+                    .setUsername(configuration.username).setPassword(configuration.password).setScope(getApiScope())
+                    .setGrantType(GrantType.PASSWORD).buildBodyMessage();
 
-        apiClient.getApiAuthorizations().put("password_oauth", auth);
-        apiClient.getTokenEndPoint().setClientId(configuration.clientId).setClientSecret(configuration.clientSecret)
-                .setUsername(configuration.username).setPassword(configuration.password).setScope(getApiScope());
+            OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
 
-        apiClient.configureFromOkclient(new OkHttpClient());
-        apiClient.getAdapterBuilder().setLogLevel(logger.isDebugEnabled() ? LogLevel.FULL : LogLevel.NONE);
+            OAuthJSONAccessTokenResponse accessTokenResponse = oAuthClient.accessToken(oAuthRequest,
+                    OAuthJSONAccessTokenResponse.class);
+            String accessToken = accessTokenResponse.getAccessToken();
 
-        apiMap = new APIMap(apiClient);
+            for (Authentication authentication : apiClient.getAuthentications().values()) {
+                if (authentication instanceof OAuth) {
+                    ((OAuth) authentication).setAccessToken(accessToken);
+                }
+            }
+
+            apiCreator = new APICreator(apiClient);
+        } catch (OAuthSystemException | OAuthProblemException e) {
+            throw new RuntimeException("Error on trying to get an access token!", e);
+        }
     }
 
     private String getApiScope() {
@@ -231,28 +244,23 @@ public class NetatmoBridgeHandler extends BaseBridgeHandler {
     }
 
     public @Nullable PartnerApi getPartnerApi() {
-        APIMap map = apiMap;
-        return map != null ? (PartnerApi) map.get(PartnerApi.class) : null;
+        return apiCreator != null ? apiCreator.getAPI(PartnerApi.class) : null;
     }
 
     public Optional<StationApi> getStationApi() {
-        APIMap map = apiMap;
-        return map != null ? Optional.of((StationApi) map.get(StationApi.class)) : Optional.empty();
+        return apiCreator != null ? Optional.of(apiCreator.getAPI(StationApi.class)) : Optional.empty();
     }
 
     public Optional<HealthyhomecoachApi> getHomeCoachApi() {
-        APIMap map = apiMap;
-        return map != null ? Optional.of((HealthyhomecoachApi) map.get(HealthyhomecoachApi.class)) : Optional.empty();
+        return apiCreator != null ? Optional.of(apiCreator.getAPI(HealthyhomecoachApi.class)) : Optional.empty();
     }
 
     public Optional<ThermostatApi> getThermostatApi() {
-        APIMap map = apiMap;
-        return map != null ? Optional.of((ThermostatApi) map.get(ThermostatApi.class)) : Optional.empty();
+        return apiCreator != null ? Optional.of(apiCreator.getAPI(ThermostatApi.class)) : Optional.empty();
     }
 
     public Optional<WelcomeApi> getWelcomeApi() {
-        APIMap map = apiMap;
-        return map != null ? Optional.of((WelcomeApi) map.get(WelcomeApi.class)) : Optional.empty();
+        return apiCreator != null ? Optional.of(apiCreator.getAPI(WelcomeApi.class)) : Optional.empty();
     }
 
     @Override
@@ -283,8 +291,8 @@ public class NetatmoBridgeHandler extends BaseBridgeHandler {
 
     public List<Float> getStationMeasureResponses(String equipmentId, @Nullable String moduleId, String scale,
             List<String> types) {
-        List<NAMeasureBodyElem> data = getStationApi().map(api -> api
-                .getmeasure(equipmentId, scale, new CSVParams(types), moduleId, null, "last", 1, true, false).getBody())
+        List<NAMeasureBodyElem> data = getStationApi()
+                .map(api -> api.getmeasure(equipmentId, scale, types, moduleId, null, "last", 1, true, false).getBody())
                 .orElse(null);
         updateStatus(ThingStatus.ONLINE);
         NAMeasureBodyElem element = (data != null && data.size() > 0) ? data.get(0) : null;
index b68c43126a254068270656d43b99d09a4edfa3e4..1d18b47bb19405037f850242d1fb5e6f29a61275 100644 (file)
@@ -39,8 +39,8 @@ import org.openhab.core.types.UnDefType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import io.swagger.client.ApiException;
 import io.swagger.client.model.NAPlace;
-import retrofit.RetrofitError;
 
 /**
  * {@link NetatmoDeviceHandler} is the handler for a given
@@ -125,7 +125,7 @@ public abstract class NetatmoDeviceHandler<DEVICE> extends AbstractNetatmoThingH
                     Optional<DEVICE> newDeviceReading = Optional.empty();
                     try {
                         newDeviceReading = updateReadings();
-                    } catch (RetrofitError e) {
+                    } catch (ApiException e) {
                         if (logger.isDebugEnabled()) {
                             // we also attach the stack trace
                             logger.error("Unable to connect Netatmo API : {}", e.getMessage(), e);
index aa9b5fc2327c7ccc7f93a458bb091119654c5a46..f0cd32bb124bb4b5bc8af776288ad5a39725b7ca 100644 (file)
@@ -12,6 +12,7 @@
  */
 package org.openhab.binding.netatmo.internal.homecoach;
 
+import static org.openhab.binding.netatmo.internal.APIUtils.*;
 import static org.openhab.binding.netatmo.internal.ChannelTypeUtils.*;
 import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
 
@@ -43,7 +44,7 @@ public class NAHealthyHomeCoachHandler extends NetatmoDeviceHandler<NAHealthyHom
     @Override
     protected Optional<NAHealthyHomeCoach> updateReadings() {
         return getBridgeHandler().flatMap(handler -> handler.getHomecoachDataBody(getId()))
-                .map(dataBody -> dataBody.getDevices().stream()
+                .map(dataBody -> nonNullStream(dataBody.getDevices())
                         .filter(device -> device.getId().equalsIgnoreCase(getId())).findFirst().orElse(null));
     }
 
@@ -58,7 +59,7 @@ public class NAHealthyHomeCoachHandler extends NetatmoDeviceHandler<NAHealthyHom
         if (dashboardData != null) {
             switch (channelId) {
                 case CHANNEL_CO2:
-                    return toQuantityType(dashboardData.getCO2(), API_CO2_UNIT);
+                    return toQuantityType(dashboardData.getCo2(), API_CO2_UNIT);
                 case CHANNEL_TEMPERATURE:
                     return toQuantityType(dashboardData.getTemperature(), API_TEMPERATURE_UNIT);
                 case CHANNEL_HEALTH_INDEX:
index c5a7892e2d51270899e0afe897e4e7ce1903eb5d..c319d00dfc628efa9489aa59a46d80cb2831289e 100644 (file)
@@ -12,6 +12,7 @@
  */
 package org.openhab.binding.netatmo.internal.station;
 
+import static org.openhab.binding.netatmo.internal.APIUtils.*;
 import static org.openhab.binding.netatmo.internal.ChannelTypeUtils.*;
 import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
 
@@ -51,10 +52,10 @@ public class NAMainHandler extends NetatmoDeviceHandler<NAMain> {
     @Override
     protected Optional<NAMain> updateReadings() {
         Optional<NAMain> result = getBridgeHandler().flatMap(handler -> handler.getStationsDataBody(getId()))
-                .map(dataBody -> dataBody.getDevices().stream()
+                .map(dataBody -> nonNullStream(dataBody.getDevices())
                         .filter(device -> device.getId().equalsIgnoreCase(getId())).findFirst().orElse(null));
         result.ifPresent(device -> {
-            device.getModules().forEach(child -> childs.put(child.getId(), child));
+            nonNullList(device.getModules()).forEach(child -> childs.put(child.getId(), child));
         });
 
         updateMeasurements();
@@ -166,7 +167,7 @@ public class NAMainHandler extends NetatmoDeviceHandler<NAMain> {
         if (dashboardData != null) {
             switch (channelId) {
                 case CHANNEL_CO2:
-                    return toQuantityType(dashboardData.getCO2(), API_CO2_UNIT);
+                    return toQuantityType(dashboardData.getCo2(), API_CO2_UNIT);
                 case CHANNEL_TEMPERATURE:
                     return toQuantityType(dashboardData.getTemperature(), API_TEMPERATURE_UNIT);
                 case CHANNEL_MIN_TEMP:
@@ -288,7 +289,7 @@ public class NAMainHandler extends NetatmoDeviceHandler<NAMain> {
         boolean result = false;
         Optional<NAMain> device = getDevice();
         if (device.isPresent()) {
-            Boolean reachable = device.get().getReachable();
+            Boolean reachable = device.get().isReachable();
             result = reachable != null ? reachable.booleanValue() : false;
         }
         return result;
index af10763195cb141c824aef854a6d177172c4ee17..dc65566858ec32957f8a62b467521aa9d7f0207a 100644 (file)
@@ -177,7 +177,7 @@ public class NAModule1Handler extends NetatmoModuleHandler<NAStationModule> {
         boolean result = false;
         Optional<NAStationModule> module = getModule();
         if (module.isPresent()) {
-            Boolean reachable = module.get().getReachable();
+            Boolean reachable = module.get().isReachable();
             result = reachable != null ? reachable.booleanValue() : false;
         }
         return result;
index 6071c01b6c08225805776e6836bf162da07702fc..43acf2563fb2a027615becc72403fe7bdb3e01a0 100644 (file)
@@ -73,7 +73,7 @@ public class NAModule2Handler extends NetatmoModuleHandler<NAStationModule> {
         boolean result = false;
         Optional<NAStationModule> module = getModule();
         if (module.isPresent()) {
-            Boolean reachable = module.get().getReachable();
+            Boolean reachable = module.get().isReachable();
             result = reachable != null ? reachable.booleanValue() : false;
         }
         return result;
index 06ca88cde2770df64aee8d5f6cae5942a9fca571..ddce844e979ac058e8695dae1d4a2159e430b133 100644 (file)
@@ -96,7 +96,7 @@ public class NAModule3Handler extends NetatmoModuleHandler<NAStationModule> {
         boolean result = false;
         Optional<NAStationModule> module = getModule();
         if (module.isPresent()) {
-            Boolean reachable = module.get().getReachable();
+            Boolean reachable = module.get().isReachable();
             result = reachable != null ? reachable.booleanValue() : false;
         }
         return result;
index 7d20bcc77123a061c625354facf7701399d24e20..a9bdeb2ac7bb1dff162c2530fc98dd31c0ec9aa8 100644 (file)
@@ -123,7 +123,7 @@ public class NAModule4Handler extends NetatmoModuleHandler<NAStationModule> {
                 case CHANNEL_TEMP_TREND:
                     return toStringType(dashboardData.getTempTrend());
                 case CHANNEL_CO2:
-                    return toQuantityType(dashboardData.getCO2(), API_CO2_UNIT);
+                    return toQuantityType(dashboardData.getCo2(), API_CO2_UNIT);
                 case CHANNEL_TEMPERATURE:
                     return toQuantityType(dashboardData.getTemperature(), API_TEMPERATURE_UNIT);
                 case CHANNEL_DATE_MIN_TEMP:
@@ -204,7 +204,7 @@ public class NAModule4Handler extends NetatmoModuleHandler<NAStationModule> {
         boolean result = false;
         Optional<NAStationModule> module = getModule();
         if (module.isPresent()) {
-            Boolean reachable = module.get().getReachable();
+            Boolean reachable = module.get().isReachable();
             result = reachable != null ? reachable.booleanValue() : false;
         }
         return result;
index 757f02b10458258bb005f25e63dc6ac03837f811..4c4e4514e3ed913c334f7c90d43ef91a95c2c1d0 100644 (file)
@@ -12,6 +12,7 @@
  */
 package org.openhab.binding.netatmo.internal.thermostat;
 
+import static org.openhab.binding.netatmo.internal.APIUtils.*;
 import static org.openhab.binding.netatmo.internal.ChannelTypeUtils.*;
 import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
 
@@ -47,10 +48,10 @@ public class NAPlugHandler extends NetatmoDeviceHandler<NAPlug> {
     @Override
     protected Optional<NAPlug> updateReadings() {
         Optional<NAPlug> result = getBridgeHandler().flatMap(handler -> handler.getThermostatsDataBody(getId()))
-                .map(dataBody -> dataBody.getDevices().stream()
+                .map(dataBody -> nonNullStream(dataBody.getDevices())
                         .filter(device -> device.getId().equalsIgnoreCase(getId())).findFirst().orElse(null));
         result.ifPresent(device -> {
-            device.getModules().forEach(child -> childs.put(child.getId(), child));
+            nonNullList(device.getModules()).forEach(child -> childs.put(child.getId(), child));
         });
         return result;
     }
index 9399a135b51398333987cffb0c42ddf84064c402..2f8c91c7accba18719f96277b0b094f36422dabb 100644 (file)
@@ -12,6 +12,7 @@
  */
 package org.openhab.binding.netatmo.internal.thermostat;
 
+import static org.openhab.binding.netatmo.internal.APIUtils.*;
 import static org.openhab.binding.netatmo.internal.ChannelTypeUtils.*;
 import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
 
@@ -80,7 +81,7 @@ public class NATherm1Handler extends NetatmoModuleHandler<NAThermostat> {
     @Override
     public void updateChannels(Object moduleObject) {
         if (isRefreshRequired()) {
-            measurableChannels.getAsCsv().ifPresent(csvParams -> {
+            measurableChannels.getMeasuredChannels().ifPresent(csvParams -> {
                 getApi().ifPresent(api -> {
                     NAMeasureResponse measures = api.getmeasure(getParentId(), "max", csvParams, getId(), null, null, 1,
                             true, true);
@@ -96,7 +97,7 @@ public class NATherm1Handler extends NetatmoModuleHandler<NAThermostat> {
 
     private void updateStateDescription(NAThermostat thermostat) {
         List<StateOption> options = new ArrayList<>();
-        for (NAThermProgram planning : thermostat.getThermProgramList()) {
+        for (NAThermProgram planning : nonNullList(thermostat.getThermProgramList())) {
             options.add(new StateOption(planning.getProgramId(), planning.getName()));
         }
         stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_PLANNING), options);
@@ -125,7 +126,7 @@ public class NATherm1Handler extends NetatmoModuleHandler<NAThermostat> {
                     if (setpoint != null) {
                         Integer endTime = setpoint.getSetpointEndtime();
                         if (endTime == null) {
-                            endTime = getNextProgramTime(thermostat.get().getThermProgramList());
+                            endTime = getNextProgramTime(nonNullList(thermostat.get().getThermProgramList()));
                         }
                         return toDateTimeType(endTime, timeZoneProvider.getTimeZone());
                     }
@@ -138,8 +139,8 @@ public class NATherm1Handler extends NetatmoModuleHandler<NAThermostat> {
             case CHANNEL_PLANNING: {
                 String currentPlanning = "-";
                 if (thermostat.isPresent()) {
-                    for (NAThermProgram program : thermostat.get().getThermProgramList()) {
-                        if (program.getSelected() == Boolean.TRUE) {
+                    for (NAThermProgram program : nonNullList(thermostat.get().getThermProgramList())) {
+                        if (program.isSelected() == Boolean.TRUE) {
                             currentPlanning = program.getProgramId();
                         }
                     }
@@ -164,8 +165,8 @@ public class NATherm1Handler extends NetatmoModuleHandler<NAThermostat> {
             if (setPoint != null) {
                 String currentMode = setPoint.getSetpointMode();
 
-                NAThermProgram currentProgram = thermostat.get().getThermProgramList().stream()
-                        .filter(p -> p.getSelected() != null && p.getSelected()).findFirst().get();
+                NAThermProgram currentProgram = nonNullStream(thermostat.get().getThermProgramList())
+                        .filter(p -> p.isSelected() != null && p.isSelected()).findFirst().get();
                 switch (currentMode) {
                     case CHANNEL_SETPOINT_MODE_MANUAL:
                         return toDecimalType(setPoint.getSetpointTemp());
@@ -177,7 +178,7 @@ public class NATherm1Handler extends NetatmoModuleHandler<NAThermostat> {
                         return toDecimalType(zone1.getTemp());
                     case CHANNEL_SETPOINT_MODE_PROGRAM:
                         NATimeTableItem currentProgramMode = getCurrentProgramMode(
-                                thermostat.get().getThermProgramList());
+                                nonNullList(thermostat.get().getThermProgramList()));
                         if (currentProgramMode != null) {
                             NAZone zone2 = getZone(currentProgram.getZones(), currentProgramMode.getId());
                             return toDecimalType(zone2.getTemp());
@@ -192,7 +193,7 @@ public class NATherm1Handler extends NetatmoModuleHandler<NAThermostat> {
     }
 
     private NAZone getZone(List<NAZone> zones, int searchedId) {
-        return zones.stream().filter(z -> z.getId() == searchedId).findFirst().get();
+        return nonNullStream(zones).filter(z -> z.getId() == searchedId).findFirst().get();
     }
 
     private long getNetatmoProgramBaseTime() {
@@ -210,10 +211,10 @@ public class NATherm1Handler extends NetatmoModuleHandler<NAThermostat> {
         long diff = (now.getTimeInMillis() - getNetatmoProgramBaseTime()) / 1000 / 60;
 
         Optional<NAThermProgram> currentProgram = thermProgramList.stream()
-                .filter(p -> p.getSelected() != null && p.getSelected()).findFirst();
+                .filter(p -> p.isSelected() != null && p.isSelected()).findFirst();
 
         if (currentProgram.isPresent()) {
-            Stream<NATimeTableItem> pastPrograms = currentProgram.get().getTimetable().stream()
+            Stream<NATimeTableItem> pastPrograms = nonNullStream(currentProgram.get().getTimetable())
                     .filter(t -> t.getMOffset() < diff);
             Optional<NATimeTableItem> program = pastPrograms.reduce((first, second) -> second);
             if (program.isPresent()) {
@@ -231,12 +232,13 @@ public class NATherm1Handler extends NetatmoModuleHandler<NAThermostat> {
         int result = -1;
 
         for (NAThermProgram thermProgram : thermProgramList) {
-            if (thermProgram.getSelected() != null && thermProgram.getSelected()) {
+            if (thermProgram.isSelected() != null && thermProgram.isSelected()) {
                 // By default we'll use the first slot of next week - this case will be true if
                 // we are in the last schedule of the week so below loop will not exit by break
-                int next = thermProgram.getTimetable().get(0).getMOffset() + (7 * 24 * 60);
+                List<NATimeTableItem> timetable = thermProgram.getTimetable();
+                int next = timetable.get(0).getMOffset() + (7 * 24 * 60);
 
-                for (NATimeTableItem timeTable : thermProgram.getTimetable()) {
+                for (NATimeTableItem timeTable : timetable) {
                     if (timeTable.getMOffset() > diff) {
                         next = timeTable.getMOffset();
                         break;
index 9a269e75a540762e0ec1bc63c45bbfc45ad264bc..7b3b926a5b0226677bad560f3c759f344f81a3ef 100644 (file)
@@ -12,6 +12,7 @@
  */
 package org.openhab.binding.netatmo.internal.welcome;
 
+import static org.openhab.binding.netatmo.internal.APIUtils.*;
 import static org.openhab.binding.netatmo.internal.ChannelTypeUtils.*;
 import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
 
@@ -68,29 +69,30 @@ public class NAWelcomeHomeHandler extends NetatmoDeviceHandler<NAWelcomeHome> {
     @Override
     protected Optional<NAWelcomeHome> updateReadings() {
         Optional<NAWelcomeHome> result = getBridgeHandler().flatMap(handler -> handler.getWelcomeDataBody(getId()))
-                .map(dataBody -> dataBody.getHomes().stream().filter(device -> device.getId().equalsIgnoreCase(getId()))
-                        .findFirst().orElse(null));
+                .map(dataBody -> nonNullStream(dataBody.getHomes())
+                        .filter(device -> device.getId().equalsIgnoreCase(getId())).findFirst().orElse(null));
         // data time stamp is updated to now as WelcomeDataBody does not provide any information according to this need
         dataTimeStamp = (int) (Calendar.getInstance().getTimeInMillis() / 1000);
         result.ifPresent(home -> {
-            home.getCameras().forEach(camera -> childs.put(camera.getId(), camera));
+            nonNullList(home.getCameras()).forEach(camera -> childs.put(camera.getId(), camera));
 
             // Check how many persons are at home
             iPersons = 0;
             iUnknowns = 0;
 
             logger.debug("welcome home '{}' calculate Persons at home count", getId());
-            home.getPersons().forEach(person -> {
-                iPersons += person.getOutOfSight() ? 0 : 1;
+            nonNullList(home.getPersons()).forEach(person -> {
+                iPersons += person.isOutOfSight() ? 0 : 1;
                 if (person.getPseudo() != null) {
                     childs.put(person.getId(), person);
                 } else {
-                    iUnknowns += person.getOutOfSight() ? 0 : 1;
+                    iUnknowns += person.isOutOfSight() ? 0 : 1;
                 }
             });
 
             NAWelcomeEvent previousLastEvent = lastEvent;
-            lastEvent = home.getEvents().stream().max(Comparator.comparingInt(NAWelcomeEvent::getTime)).orElse(null);
+            lastEvent = nonNullStream(home.getEvents()).max(Comparator.comparingInt(NAWelcomeEvent::getTime))
+                    .orElse(null);
             isNewLastEvent = previousLastEvent != null && !previousLastEvent.equals(lastEvent);
         });
         return result;
@@ -150,7 +152,7 @@ public class NAWelcomeHomeHandler extends NetatmoDeviceHandler<NAWelcomeHome> {
                 return lastEvt.map(e -> e.getVideoId() != null ? toStringType(e.getVideoStatus()) : UnDefType.UNDEF)
                         .orElse(UnDefType.UNDEF);
             case CHANNEL_WELCOME_EVENT_ISARRIVAL:
-                return lastEvt.map(e -> toOnOffType(e.getIsArrival())).orElse(UnDefType.UNDEF);
+                return lastEvt.map(e -> toOnOffType(e.isIsArrival())).orElse(UnDefType.UNDEF);
             case CHANNEL_WELCOME_EVENT_MESSAGE:
                 return findEventMessage().map(m -> (State) new StringType(m.replace("<b>", "").replace("</b>", "")))
                         .orElse(UnDefType.UNDEF);
@@ -192,7 +194,7 @@ public class NAWelcomeHomeHandler extends NetatmoDeviceHandler<NAWelcomeHome> {
             }
         }
 
-        event.getEventList().forEach(subEvent -> {
+        nonNullList(event.getEventList()).forEach(subEvent -> {
             String detectedObjectType = subEvent.getType().name();
             detectedObjectTypes.add(detectedObjectType);
         });
@@ -258,7 +260,7 @@ public class NAWelcomeHomeHandler extends NetatmoDeviceHandler<NAWelcomeHome> {
 
     private Optional<NAWelcomeSubEvent> findFirstSubEvent(NAWelcomeEvent event) {
         return Optional.ofNullable(event).map(NAWelcomeEvent::getEventList)
-                .flatMap(subEvents -> subEvents.stream().findFirst());
+                .flatMap(subEvents -> nonNullStream(subEvents).findFirst());
     }
 
     private Optional<NAWelcomeEvent> getLastEvent() {
index fd2ba848848a8f2e4de5f5a55f5929725d48d1f9..3026a8752d04a22bb63a248492983f1dcee8506f 100644 (file)
  */
 package org.openhab.binding.netatmo.internal.welcome;
 
+import static org.openhab.binding.netatmo.internal.APIUtils.*;
 import static org.openhab.binding.netatmo.internal.ChannelTypeUtils.*;
 import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
 
-import java.util.List;
 import java.util.Optional;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -58,8 +58,7 @@ public class NAWelcomePersonHandler extends NetatmoModuleHandler<NAWelcomePerson
                 NAWelcomeEventResponse eventResponse = api.getlasteventof(getParentId(), getId(), 10);
 
                 // Search the last event for this person
-                List<NAWelcomeEvent> rawEventList = eventResponse.getBody().getEventsList();
-                rawEventList.forEach(event -> {
+                nonNullList(eventResponse.getBody().getEventsList()).forEach(event -> {
                     if (event.getPersonId() != null && event.getPersonId().equalsIgnoreCase(getId())
                             && (lastEvent == null || lastEvent.getTime() < event.getTime())) {
                         lastEvent = event;
@@ -81,8 +80,7 @@ public class NAWelcomePersonHandler extends NetatmoModuleHandler<NAWelcomePerson
                 return getModule().map(m -> toDateTimeType(m.getLastSeen(), timeZoneProvider.getTimeZone()))
                         .orElse(UnDefType.UNDEF);
             case CHANNEL_WELCOME_PERSON_ATHOME:
-                return getModule()
-                        .map(m -> m.getOutOfSight() != null ? toOnOffType(!m.getOutOfSight()) : UnDefType.UNDEF)
+                return getModule().map(m -> m.isOutOfSight() != null ? toOnOffType(!m.isOutOfSight()) : UnDefType.UNDEF)
                         .orElse(UnDefType.UNDEF);
             case CHANNEL_WELCOME_PERSON_AVATAR_URL:
                 return toStringType(getAvatarURL());
index 84131e525de7aaee566821a3a83006eaccd41c01..61f5045e81399f14d7be19f330e2509e08a2e40c 100644 (file)
     <module>org.openhab.binding.neeo</module>
     <module>org.openhab.binding.neohub</module>
     <module>org.openhab.binding.nest</module>
+    <module>org.openhab.binding.netatmo</module>
     <module>org.openhab.binding.network</module>
     <module>org.openhab.binding.networkupstools</module>
     <module>org.openhab.binding.nibeheatpump</module>