public class LinkyHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(LinkyHandler.class);
- private static final int REFRESH_FIRST_HOUR_OF_DAY = 5;
- private static final int REFRESH_INTERVAL_IN_MIN = 360;
+ private static final int REFRESH_FIRST_HOUR_OF_DAY = 1;
+ private static final int REFRESH_INTERVAL_IN_MIN = 120;
private final HttpClient httpClient;
private final Gson gson;
this.cachedDailyData = new ExpiringDayCache<>("daily cache", REFRESH_FIRST_HOUR_OF_DAY, () -> {
LocalDate today = LocalDate.now();
- return getConsumptionData(today.minusDays(15), today);
+ Consumption consumption = getConsumptionData(today.minusDays(15), today);
+ if (consumption != null) {
+ logData(consumption.aggregats.days, "Day", false, DateTimeFormatter.ISO_LOCAL_DATE, false);
+ logData(consumption.aggregats.weeks, "Week", true, DateTimeFormatter.ISO_LOCAL_DATE_TIME, false);
+ consumption = getConsumptionAfterChecks(consumption);
+ }
+ return consumption;
});
this.cachedPowerData = new ExpiringDayCache<>("power cache", REFRESH_FIRST_HOUR_OF_DAY, () -> {
LocalDate to = LocalDate.now().plusDays(1);
LocalDate from = to.minusDays(2);
- return getPowerData(from, to);
+ Consumption consumption = getPowerData(from, to);
+ if (consumption != null) {
+ try {
+ checkData(consumption);
+ } catch (LinkyException e) {
+ logger.debug("Power data: {}", e.getMessage());
+ return null;
+ }
+ }
+ return consumption;
});
this.cachedMonthlyData = new ExpiringDayCache<>("monthly cache", REFRESH_FIRST_HOUR_OF_DAY, () -> {
LocalDate today = LocalDate.now();
- return getConsumptionData(today.withDayOfMonth(1).minusMonths(1), today);
+ Consumption consumption = getConsumptionData(today.withDayOfMonth(1).minusMonths(1), today);
+ if (consumption != null) {
+ logData(consumption.aggregats.months, "Month", true, DateTimeFormatter.ISO_LOCAL_DATE_TIME, false);
+ consumption = getConsumptionAfterChecks(consumption);
+ }
+ return consumption;
});
this.cachedYearlyData = new ExpiringDayCache<>("yearly cache", REFRESH_FIRST_HOUR_OF_DAY, () -> {
LocalDate today = LocalDate.now();
- return getConsumptionData(LocalDate.of(today.getYear() - 1, 1, 1), today);
+ Consumption consumption = getConsumptionData(LocalDate.of(today.getYear() - 1, 1, 1), today);
+ if (consumption != null) {
+ logData(consumption.aggregats.years, "Year", true, DateTimeFormatter.ISO_LOCAL_DATE_TIME, false);
+ consumption = getConsumptionAfterChecks(consumption);
+ }
+ return consumption;
});
}
if (isLinked(PEAK_POWER) || isLinked(PEAK_TIMESTAMP)) {
cachedPowerData.getValue().ifPresent(values -> {
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));
- }
+ updateVAChannel(PEAK_POWER, days.datas.get(0));
+ updateState(PEAK_TIMESTAMP, new DateTimeType(days.periodes.get(0).dateDebut));
});
}
}
* Request new dayly/weekly data and updates channels
*/
private synchronized void updateDailyData() {
- if (isLinked(YESTERDAY) || isLinked(THIS_WEEK)) {
+ if (isLinked(YESTERDAY)) {
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);
- double thisWeek = 0.00;
-
- for (int i = maxValue; i >= 0; i--) {
- int weekNumber = days.periodes.get(i).dateDebut.get(weekFields.weekOfWeekBasedYear());
- if (weekNumber == thisWeekNumber) {
- Double value = days.datas.get(i);
- thisWeek += !value.isNaN() ? value : 0;
- } else {
- break;
- }
- }
-
- updateKwhChannel(YESTERDAY, yesterday);
- updateKwhChannel(THIS_WEEK, thisWeek);
+ updateKwhChannel(YESTERDAY, days.datas.get(days.datas.size() - 1));
});
}
}
* Request new weekly data and updates channels
*/
private synchronized void updateWeeklyData() {
- if (isLinked(LAST_WEEK)) {
+ if (isLinked(LAST_WEEK) || isLinked(THIS_WEEK)) {
cachedDailyData.getValue().ifPresent(values -> {
+ Aggregate days = values.aggregats.days;
+ int idxLast = days.periodes.get(days.periodes.size() - 1).dateDebut.get(weekFields.dayOfWeek()) == 7 ? 2
+ : 1;
Aggregate weeks = values.aggregats.weeks;
- if (weeks.datas.size() > 1) {
- updateKwhChannel(LAST_WEEK, weeks.datas.get(1));
+ if (weeks.datas.size() > idxLast) {
+ updateKwhChannel(LAST_WEEK, weeks.datas.get(idxLast));
+ }
+ if (weeks.datas.size() > (idxLast + 1)) {
+ updateKwhChannel(THIS_WEEK, weeks.datas.get(idxLast + 1));
} else {
- logger.debug("Weekly data are without last week data");
- updateKwhChannel(LAST_WEEK, Double.NaN);
+ updateKwhChannel(THIS_WEEK, 0.0);
}
});
}
if (isLinked(LAST_MONTH) || isLinked(THIS_MONTH)) {
cachedMonthlyData.getValue().ifPresent(values -> {
Aggregate months = values.aggregats.months;
- if (months.datas.size() == 0) {
- logger.debug("Monthly data are without any data");
- updateKwhChannel(LAST_MONTH, Double.NaN);
- updateKwhChannel(THIS_MONTH, Double.NaN);
+ updateKwhChannel(LAST_MONTH, months.datas.get(0));
+ if (months.datas.size() > 1) {
+ updateKwhChannel(THIS_MONTH, months.datas.get(1));
} 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);
- }
+ updateKwhChannel(THIS_MONTH, 0.0);
}
});
}
if (isLinked(LAST_YEAR) || isLinked(THIS_YEAR)) {
cachedYearlyData.getValue().ifPresent(values -> {
Aggregate years = values.aggregats.years;
- if (years.datas.size() == 0) {
- logger.debug("Yearly data are without any data");
- updateKwhChannel(LAST_YEAR, Double.NaN);
- updateKwhChannel(THIS_YEAR, Double.NaN);
+ updateKwhChannel(LAST_YEAR, years.datas.get(0));
+ if (years.datas.size() > 1) {
+ updateKwhChannel(THIS_YEAR, years.datas.get(1));
} 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);
- }
+ updateKwhChannel(THIS_YEAR, 0.0);
}
});
}
List<String> report = new ArrayList<>();
if (startDay.getYear() == endDay.getYear() && startDay.getMonthValue() == endDay.getMonthValue()) {
// All values in the same month
- Consumption result = getConsumptionData(startDay, endDay);
+ Consumption result = getConsumptionData(startDay, endDay.plusDays(1));
if (result != null) {
Aggregate days = result.aggregats.days;
- for (int i = 0; i < days.datas.size(); i++) {
+ int size = (days.datas == null || days.periodes == null) ? 0
+ : (days.datas.size() <= days.periodes.size() ? days.datas.size() : days.periodes.size());
+ for (int i = 0; i < size; i++) {
double consumption = days.datas.get(i);
String line = days.periodes.get(i).dateDebut.format(DateTimeFormatter.ISO_LOCAL_DATE) + separator;
if (consumption >= 0) {
EnedisHttpApi api = this.enedisApi;
if (api != null) {
try {
- return api.getEnergyData(userId, prmId, from, to);
+ Consumption consumption = api.getEnergyData(userId, prmId, from, to);
+ updateStatus(ThingStatus.ONLINE);
+ return consumption;
} catch (LinkyException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, e.getMessage());
}
EnedisHttpApi api = this.enedisApi;
if (api != null) {
try {
- return api.getPowerData(userId, prmId, from, to);
+ Consumption consumption = api.getPowerData(userId, prmId, from, to);
+ updateStatus(ThingStatus.ONLINE);
+ return consumption;
} catch (LinkyException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, e.getMessage());
}
boolean connectedBefore = isConnected();
switch (channelUID.getId()) {
case YESTERDAY:
- case THIS_WEEK:
updateDailyData();
break;
case LAST_WEEK:
+ case THIS_WEEK:
updateWeeklyData();
break;
case LAST_MONTH:
logger.debug("The Linky binding is read-only and can not handle command {}", command);
}
}
+
+ private @Nullable Consumption getConsumptionAfterChecks(Consumption consumption) {
+ try {
+ checkData(consumption);
+ } catch (LinkyException e) {
+ logger.debug("Consumption data: {}", e.getMessage());
+ return null;
+ }
+ if (!isDataLastDayAvailable(consumption)) {
+ logger.debug("Data including yesterday are not yet available");
+ return null;
+ }
+ return consumption;
+ }
+
+ public void checkData(Consumption consumption) throws LinkyException {
+ if (consumption.aggregats.days.periodes.size() == 0) {
+ throw new LinkyException("invalid consumptions data: no day period");
+ }
+ if (consumption.aggregats.days.periodes.size() != consumption.aggregats.days.datas.size()) {
+ throw new LinkyException("invalid consumptions data: not one data for each day period");
+ }
+ if (consumption.aggregats.weeks.periodes.size() == 0) {
+ throw new LinkyException("invalid consumptions data: no week period");
+ }
+ if (consumption.aggregats.weeks.periodes.size() != consumption.aggregats.weeks.datas.size()) {
+ throw new LinkyException("invalid consumptions data: not one data for each week period");
+ }
+ if (consumption.aggregats.months.periodes.size() == 0) {
+ throw new LinkyException("invalid consumptions data: no month period");
+ }
+ if (consumption.aggregats.months.periodes.size() != consumption.aggregats.months.datas.size()) {
+ throw new LinkyException("invalid consumptions data: not one data for each month period");
+ }
+ if (consumption.aggregats.years.periodes.size() == 0) {
+ throw new LinkyException("invalid consumptions data: no year period");
+ }
+ if (consumption.aggregats.years.periodes.size() != consumption.aggregats.years.datas.size()) {
+ throw new LinkyException("invalid consumptions data: not one data for each year period");
+ }
+ }
+
+ private boolean isDataLastDayAvailable(Consumption consumption) {
+ Aggregate days = consumption.aggregats.days;
+ logData(days, "Last day", false, DateTimeFormatter.ISO_LOCAL_DATE, true);
+ return days.datas != null && days.datas.size() > 0 && !days.datas.get(days.datas.size() - 1).isNaN();
+ }
+
+ private void logData(Aggregate aggregate, String title, boolean withDateFin, DateTimeFormatter dateTimeFormatter,
+ boolean onlyLast) {
+ if (logger.isDebugEnabled()) {
+ int size = (aggregate.datas == null || aggregate.periodes == null) ? 0
+ : (aggregate.datas.size() <= aggregate.periodes.size() ? aggregate.datas.size()
+ : aggregate.periodes.size());
+ if (onlyLast) {
+ if (size > 0) {
+ logData(aggregate, size - 1, title, withDateFin, dateTimeFormatter);
+ }
+ } else {
+ for (int i = 0; i < size; i++) {
+ logData(aggregate, i, title, withDateFin, dateTimeFormatter);
+ }
+ }
+ }
+ }
+
+ private void logData(Aggregate aggregate, int index, String title, boolean withDateFin,
+ DateTimeFormatter dateTimeFormatter) {
+ if (withDateFin) {
+ logger.debug("{} {} {} value {}", title, aggregate.periodes.get(index).dateDebut.format(dateTimeFormatter),
+ aggregate.periodes.get(index).dateFin.format(dateTimeFormatter), aggregate.datas.get(index));
+ } else {
+ logger.debug("{} {} value {}", title, aggregate.periodes.get(index).dateDebut.format(dateTimeFormatter),
+ aggregate.datas.get(index));
+ }
+ }
}