From: lolodomo Date: Tue, 15 Dec 2020 21:38:52 +0000 (+0100) Subject: [linky] Fix data refresh (login / logout) (#9358) X-Git-Url: https://git.basschouten.com/?a=commitdiff_plain;h=4e54b5b9b500b0d11a9fe763094b381528bf1ab6;p=openhab-addons.git [linky] Fix data refresh (login / logout) (#9358) Fix #9313 Signed-off-by: Laurent Garnier --- diff --git a/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/api/EnedisHttpApi.java b/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/api/EnedisHttpApi.java index 67aabcd028..50581eabf2 100644 --- a/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/api/EnedisHttpApi.java +++ b/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/api/EnedisHttpApi.java @@ -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"); } } diff --git a/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/handler/LinkyHandler.java b/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/handler/LinkyHandler.java index eb3782d7ea..2da73b7537 100644 --- a/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/handler/LinkyHandler.java +++ b/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/handler/LinkyHandler.java @@ -127,19 +127,26 @@ public class LinkyHandler extends BaseThingHandler { updateStatus(ThingStatus.ONLINE); if (thing.getProperties().isEmpty()) { - Map properties = discoverAttributes(); + Map 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 discoverAttributes() throws LinkyException { - Map 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 reportValues(LocalDate startDay, LocalDate endDay, @Nullable String separator) { + public synchronized List reportValues(LocalDate startDay, LocalDate endDay, @Nullable String separator) { + List report = buildReport(startDay, endDay, separator); + disconnect(); + return report; + } + + private List buildReport(LocalDate startDay, LocalDate endDay, @Nullable String separator) { List 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); }