]> git.basschouten.com Git - openhab-addons.git/commitdiff
[linky] Fix data refresh (login / logout) (#9358)
authorlolodomo <lg.hc@free.fr>
Tue, 15 Dec 2020 21:38:52 +0000 (22:38 +0100)
committerGitHub <noreply@github.com>
Tue, 15 Dec 2020 21:38:52 +0000 (22:38 +0100)
Fix #9313

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/api/EnedisHttpApi.java
bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/handler/LinkyHandler.java

index 67aabcd0289a463cb26ac52b0928cb6e7b4edca4..50581eabf2d5b9390ad96046fe11bda602c25f3c 100644 (file)
@@ -45,6 +45,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
 
 /**
  * {@link EnedisHttpApi} wraps the Enedis Webservice.
@@ -149,7 +150,7 @@ public class EnedisHttpApi {
                 throw new LinkyException("Connection failed step 5");
             }
             connected = true;
-        } catch (InterruptedException | TimeoutException | ExecutionException e) {
+        } catch (InterruptedException | TimeoutException | ExecutionException | JsonSyntaxException e) {
             throw new LinkyException("Error opening connection with Enedis webservice", e);
         }
     }
@@ -160,6 +161,7 @@ public class EnedisHttpApi {
 
     public void disconnect() throws LinkyException {
         if (connected) {
+            logger.debug("Logout process");
             try { // Three times in a row to get disconnected
                 String location = getLocation(httpClient.GET(URL_APPS_LINCS + "/logout"));
                 location = getLocation(httpClient.GET(location));
@@ -173,6 +175,10 @@ public class EnedisHttpApi {
         }
     }
 
+    public boolean isConnected() {
+        return connected;
+    }
+
     public void dispose() throws LinkyException {
         disconnect();
     }
@@ -204,16 +210,40 @@ public class EnedisHttpApi {
     }
 
     public PrmInfo getPrmInfo() throws LinkyException {
+        if (!connected) {
+            initialize();
+        }
         final String prm_info_url = URL_APPS_LINCS + "/mes-mesures/api/private/v1/personnes/null/prms";
         String data = getData(prm_info_url);
-        PrmInfo[] prms = gson.fromJson(data, PrmInfo[].class);
-        return prms[0];
+        if (data.isEmpty()) {
+            throw new LinkyException(String.format("Requesting '%s' returned an empty response", prm_info_url));
+        }
+        try {
+            PrmInfo[] prms = gson.fromJson(data, PrmInfo[].class);
+            return prms[0];
+        } catch (JsonSyntaxException e) {
+            logger.debug("invalid JSON response not matching PrmInfo[].class: {}", data);
+            throw new LinkyException(String.format("Requesting '%s' returned an invalid JSON response : %s",
+                    prm_info_url, e.getMessage()), e);
+        }
     }
 
     public UserInfo getUserInfo() throws LinkyException {
+        if (!connected) {
+            initialize();
+        }
         final String user_info_url = URL_APPS_LINCS + "/userinfos";
         String data = getData(user_info_url);
-        return Objects.requireNonNull(gson.fromJson(data, UserInfo.class));
+        if (data.isEmpty()) {
+            throw new LinkyException(String.format("Requesting '%s' returned an empty response", user_info_url));
+        }
+        try {
+            return Objects.requireNonNull(gson.fromJson(data, UserInfo.class));
+        } catch (JsonSyntaxException e) {
+            logger.debug("invalid JSON response not matching UserInfo.class: {}", data);
+            throw new LinkyException(String.format("Requesting '%s' returned an invalid JSON response : %s",
+                    user_info_url, e.getMessage()), e);
+        }
     }
 
     private Consumption getMeasures(String userId, String prmId, LocalDate from, LocalDate to, String request)
@@ -223,15 +253,30 @@ public class EnedisHttpApi {
         String url = String.format(measure_url, userId, prmId, request, from.format(API_DATE_FORMAT),
                 to.format(API_DATE_FORMAT));
         String data = getData(url);
-        ConsumptionReport report = gson.fromJson(data, ConsumptionReport.class);
-        return report.firstLevel.consumptions;
+        if (data.isEmpty()) {
+            throw new LinkyException(String.format("Requesting '%s' returned an empty response", url));
+        }
+        try {
+            ConsumptionReport report = gson.fromJson(data, ConsumptionReport.class);
+            return report.firstLevel.consumptions;
+        } catch (JsonSyntaxException e) {
+            logger.debug("invalid JSON response not matching ConsumptionReport.class: {}", data);
+            throw new LinkyException(
+                    String.format("Requesting '%s' returned an invalid JSON response : %s", url, e.getMessage()), e);
+        }
     }
 
     public Consumption getEnergyData(String userId, String prmId, LocalDate from, LocalDate to) throws LinkyException {
+        if (!connected) {
+            initialize();
+        }
         return getMeasures(userId, prmId, from, to, "energie");
     }
 
     public Consumption getPowerData(String userId, String prmId, LocalDate from, LocalDate to) throws LinkyException {
+        if (!connected) {
+            initialize();
+        }
         return getMeasures(userId, prmId, from, to, "pmax");
     }
 }
index eb3782d7ead68c68be288b1d505cfcca2696d667..2da73b75370aaa87b31e278e9183f30539cc7cce 100644 (file)
@@ -127,19 +127,26 @@ public class LinkyHandler extends BaseThingHandler {
                     updateStatus(ThingStatus.ONLINE);
 
                     if (thing.getProperties().isEmpty()) {
-                        Map<String, String> properties = discoverAttributes();
+                        Map<String, String> properties = new HashMap<>();
+                        PrmInfo prmInfo = api.getPrmInfo();
+                        UserInfo userInfo = api.getUserInfo();
+                        properties.put(USER_ID, userInfo.userProperties.internId);
+                        properties.put(PUISSANCE, prmInfo.puissanceSouscrite + " kVA");
+                        properties.put(PRM_ID, prmInfo.prmId);
                         updateProperties(properties);
                     }
 
                     prmId = thing.getProperties().get(PRM_ID);
                     userId = thing.getProperties().get(USER_ID);
 
+                    updateData();
+
+                    disconnect();
+
                     final LocalDateTime now = LocalDateTime.now();
                     final LocalDateTime nextDayFirstTimeUpdate = now.plusDays(1).withHour(REFRESH_FIRST_HOUR_OF_DAY)
                             .truncatedTo(ChronoUnit.HOURS);
 
-                    updateData();
-
                     refreshJob = scheduler.scheduleWithFixedDelay(this::updateData,
                             ChronoUnit.MINUTES.between(now, nextDayFirstTimeUpdate) % REFRESH_INTERVAL_IN_MIN + 1,
                             REFRESH_INTERVAL_IN_MIN, TimeUnit.MINUTES);
@@ -152,36 +159,31 @@ public class LinkyHandler extends BaseThingHandler {
         });
     }
 
-    private Map<String, String> discoverAttributes() throws LinkyException {
-        Map<String, String> properties = new HashMap<>();
-        EnedisHttpApi api = this.enedisApi;
-        if (api != null) {
-            PrmInfo prmInfo = api.getPrmInfo();
-            UserInfo userInfo = api.getUserInfo();
-            properties.put(USER_ID, userInfo.userProperties.internId);
-            properties.put(PUISSANCE, prmInfo.puissanceSouscrite + " kVA");
-            properties.put(PRM_ID, prmInfo.prmId);
-        }
-
-        return properties;
-    }
-
     /**
      * Request new data and updates channels
      */
-    private void updateData() {
+    private synchronized void updateData() {
+        boolean connectedBefore = isConnected();
         updatePowerData();
         updateDailyData();
         updateWeeklyData();
         updateMonthlyData();
         updateYearlyData();
+        if (!connectedBefore && isConnected()) {
+            disconnect();
+        }
     }
 
     private synchronized void updatePowerData() {
         if (isLinked(PEAK_POWER) || isLinked(PEAK_TIMESTAMP)) {
             cachedPowerData.getValue().ifPresent(values -> {
-                updateVAChannel(PEAK_POWER, values.aggregats.days.datas.get(0));
-                updateState(PEAK_TIMESTAMP, new DateTimeType(values.aggregats.days.periodes.get(0).dateDebut));
+                Aggregate days = values.aggregats.days;
+                if (days.datas.size() == 0 || days.periodes.size() == 0) {
+                    logger.debug("Daily power data are without any period/data");
+                } else {
+                    updateVAChannel(PEAK_POWER, days.datas.get(0));
+                    updateState(PEAK_TIMESTAMP, new DateTimeType(days.periodes.get(0).dateDebut));
+                }
             });
         }
     }
@@ -193,6 +195,10 @@ public class LinkyHandler extends BaseThingHandler {
         if (isLinked(YESTERDAY) || isLinked(THIS_WEEK)) {
             cachedDailyData.getValue().ifPresent(values -> {
                 Aggregate days = values.aggregats.days;
+                if (days.periodes.size() > days.datas.size()) {
+                    logger.debug("Daily data are invalid: not a data for each period");
+                    return;
+                }
                 int maxValue = days.periodes.size() - 1;
                 int thisWeekNumber = days.periodes.get(maxValue).dateDebut.get(weekFields.weekOfWeekBasedYear());
                 double yesterday = days.datas.get(maxValue);
@@ -223,6 +229,9 @@ public class LinkyHandler extends BaseThingHandler {
                 Aggregate weeks = values.aggregats.weeks;
                 if (weeks.datas.size() > 1) {
                     updateKwhChannel(LAST_WEEK, weeks.datas.get(1));
+                } else {
+                    logger.debug("Weekly data are without last week data");
+                    updateKwhChannel(LAST_WEEK, Double.NaN);
                 }
             });
         }
@@ -235,11 +244,18 @@ public class LinkyHandler extends BaseThingHandler {
         if (isLinked(LAST_MONTH) || isLinked(THIS_MONTH)) {
             cachedMonthlyData.getValue().ifPresent(values -> {
                 Aggregate months = values.aggregats.months;
-                updateKwhChannel(LAST_MONTH, months.datas.get(0));
-                if (months.datas.size() > 1) {
-                    updateKwhChannel(THIS_MONTH, months.datas.get(1));
-                } else {
+                if (months.datas.size() == 0) {
+                    logger.debug("Monthly data are without any data");
+                    updateKwhChannel(LAST_MONTH, Double.NaN);
                     updateKwhChannel(THIS_MONTH, Double.NaN);
+                } else {
+                    updateKwhChannel(LAST_MONTH, months.datas.get(0));
+                    if (months.datas.size() > 1) {
+                        updateKwhChannel(THIS_MONTH, months.datas.get(1));
+                    } else {
+                        logger.debug("Monthly data are without current month data");
+                        updateKwhChannel(THIS_MONTH, Double.NaN);
+                    }
                 }
             });
         }
@@ -252,11 +268,18 @@ public class LinkyHandler extends BaseThingHandler {
         if (isLinked(LAST_YEAR) || isLinked(THIS_YEAR)) {
             cachedYearlyData.getValue().ifPresent(values -> {
                 Aggregate years = values.aggregats.years;
-                updateKwhChannel(LAST_YEAR, years.datas.get(0));
-                if (years.datas.size() > 1) {
-                    updateKwhChannel(THIS_YEAR, years.datas.get(1));
-                } else {
+                if (years.datas.size() == 0) {
+                    logger.debug("Yearly data are without any data");
+                    updateKwhChannel(LAST_YEAR, Double.NaN);
                     updateKwhChannel(THIS_YEAR, Double.NaN);
+                } else {
+                    updateKwhChannel(LAST_YEAR, years.datas.get(0));
+                    if (years.datas.size() > 1) {
+                        updateKwhChannel(THIS_YEAR, years.datas.get(1));
+                    } else {
+                        logger.debug("Yearly data are without current year data");
+                        updateKwhChannel(THIS_YEAR, Double.NaN);
+                    }
                 }
             });
         }
@@ -280,9 +303,15 @@ public class LinkyHandler extends BaseThingHandler {
      * @param endDay the end day of the report
      * @param separator the separator to be used betwwen the date and the value
      *
-     * @return the report as a string
+     * @return the report as a list of string
      */
-    public List<String> reportValues(LocalDate startDay, LocalDate endDay, @Nullable String separator) {
+    public synchronized List<String> reportValues(LocalDate startDay, LocalDate endDay, @Nullable String separator) {
+        List<String> report = buildReport(startDay, endDay, separator);
+        disconnect();
+        return report;
+    }
+
+    private List<String> buildReport(LocalDate startDay, LocalDate endDay, @Nullable String separator) {
         List<String> report = new ArrayList<>();
         if (startDay.getYear() == endDay.getYear() && startDay.getMonthValue() == endDay.getMonthValue()) {
             // All values in the same month
@@ -312,7 +341,7 @@ public class LinkyHandler extends BaseThingHandler {
                 if (last.isAfter(endDay)) {
                     last = endDay;
                 }
-                report.addAll(reportValues(first, last, separator));
+                report.addAll(buildReport(first, last, separator));
                 first = last.plusDays(1);
             } while (!first.isAfter(endDay));
         }
@@ -320,6 +349,8 @@ public class LinkyHandler extends BaseThingHandler {
     }
 
     private @Nullable Consumption getConsumptionData(LocalDate from, LocalDate to) {
+        logger.debug("getConsumptionData from {} to {}", from.format(DateTimeFormatter.ISO_LOCAL_DATE),
+                to.format(DateTimeFormatter.ISO_LOCAL_DATE));
         EnedisHttpApi api = this.enedisApi;
         if (api != null) {
             try {
@@ -332,6 +363,8 @@ public class LinkyHandler extends BaseThingHandler {
     }
 
     private @Nullable Consumption getPowerData(LocalDate from, LocalDate to) {
+        logger.debug("getPowerData from {} to {}", from.format(DateTimeFormatter.ISO_LOCAL_DATE),
+                to.format(DateTimeFormatter.ISO_LOCAL_DATE));
         EnedisHttpApi api = this.enedisApi;
         if (api != null) {
             try {
@@ -343,6 +376,21 @@ public class LinkyHandler extends BaseThingHandler {
         return null;
     }
 
+    private boolean isConnected() {
+        EnedisHttpApi api = this.enedisApi;
+        return api == null ? false : api.isConnected();
+    }
+
+    private void disconnect() {
+        EnedisHttpApi api = this.enedisApi;
+        if (api != null) {
+            try {
+                api.dispose();
+            } catch (LinkyException ignore) {
+            }
+        }
+    }
+
     @Override
     public void dispose() {
         logger.debug("Disposing the Linky handler.");
@@ -351,26 +399,23 @@ public class LinkyHandler extends BaseThingHandler {
             job.cancel(true);
             refreshJob = null;
         }
-        EnedisHttpApi api = this.enedisApi;
-        if (api != null) {
-            try {
-                api.dispose();
-                enedisApi = null;
-            } catch (LinkyException ignore) {
-            }
-        }
+        disconnect();
+        enedisApi = null;
     }
 
     @Override
-    public void handleCommand(ChannelUID channelUID, Command command) {
+    public synchronized void handleCommand(ChannelUID channelUID, Command command) {
         if (command instanceof RefreshType) {
             logger.debug("Refreshing channel {}", channelUID.getId());
+            boolean connectedBefore = isConnected();
             switch (channelUID.getId()) {
                 case YESTERDAY:
-                case LAST_WEEK:
                 case THIS_WEEK:
                     updateDailyData();
                     break;
+                case LAST_WEEK:
+                    updateWeeklyData();
+                    break;
                 case LAST_MONTH:
                 case THIS_MONTH:
                     updateMonthlyData();
@@ -379,9 +424,16 @@ public class LinkyHandler extends BaseThingHandler {
                 case THIS_YEAR:
                     updateYearlyData();
                     break;
+                case PEAK_POWER:
+                case PEAK_TIMESTAMP:
+                    updatePowerData();
+                    break;
                 default:
                     break;
             }
+            if (!connectedBefore && isConnected()) {
+                disconnect();
+            }
         } else {
             logger.debug("The Linky binding is read-only and can not handle command {}", command);
         }