mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
Merge 40202b1641
into adacdebb9f
This commit is contained in:
commit
9788bb2f18
@ -26,6 +26,7 @@ public class LinkyConfiguration {
|
|||||||
public String username = "";
|
public String username = "";
|
||||||
public String password = "";
|
public String password = "";
|
||||||
public String internalAuthId = "";
|
public String internalAuthId = "";
|
||||||
|
public String timezone = "";
|
||||||
|
|
||||||
public boolean seemsValid() {
|
public boolean seemsValid() {
|
||||||
return !username.isBlank() && !password.isBlank() && !internalAuthId.isBlank();
|
return !username.isBlank() && !password.isBlank() && !internalAuthId.isBlank();
|
||||||
|
@ -12,12 +12,16 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.linky.internal;
|
package org.openhab.binding.linky.internal;
|
||||||
|
|
||||||
|
import static java.time.temporal.ChronoField.*;
|
||||||
import static org.openhab.binding.linky.internal.LinkyBindingConstants.THING_TYPE_LINKY;
|
import static org.openhab.binding.linky.internal.LinkyBindingConstants.THING_TYPE_LINKY;
|
||||||
|
|
||||||
import java.security.KeyManagementException;
|
import java.security.KeyManagementException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeFormatterBuilder;
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
@ -28,6 +32,7 @@ import org.eclipse.jetty.client.HttpClient;
|
|||||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
import org.openhab.binding.linky.internal.handler.LinkyHandler;
|
import org.openhab.binding.linky.internal.handler.LinkyHandler;
|
||||||
import org.openhab.core.i18n.LocaleProvider;
|
import org.openhab.core.i18n.LocaleProvider;
|
||||||
|
import org.openhab.core.i18n.TimeZoneProvider;
|
||||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||||
import org.openhab.core.io.net.http.TrustAllTrustManager;
|
import org.openhab.core.io.net.http.TrustAllTrustManager;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
@ -55,21 +60,43 @@ import com.google.gson.JsonDeserializer;
|
|||||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.linky")
|
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.linky")
|
||||||
public class LinkyHandlerFactory extends BaseThingHandlerFactory {
|
public class LinkyHandlerFactory extends BaseThingHandlerFactory {
|
||||||
private static final DateTimeFormatter LINKY_FORMATTER = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX");
|
private static final DateTimeFormatter LINKY_FORMATTER = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX");
|
||||||
|
private static final DateTimeFormatter LINKY_LOCALDATE_FORMATTER = DateTimeFormatter.ofPattern("uuuu-MM-dd");
|
||||||
|
private static final DateTimeFormatter LINKY_LOCALDATETIME_FORMATTER = new DateTimeFormatterBuilder()
|
||||||
|
.appendPattern("uuuu-MM-dd'T'HH:mm").optionalStart().appendLiteral(':').appendValue(SECOND_OF_MINUTE, 2)
|
||||||
|
.optionalStart().appendFraction(NANO_OF_SECOND, 0, 9, true).toFormatter();
|
||||||
|
|
||||||
private static final int REQUEST_BUFFER_SIZE = 8000;
|
private static final int REQUEST_BUFFER_SIZE = 8000;
|
||||||
private static final int RESPONSE_BUFFER_SIZE = 200000;
|
private static final int RESPONSE_BUFFER_SIZE = 200000;
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(LinkyHandlerFactory.class);
|
private final Logger logger = LoggerFactory.getLogger(LinkyHandlerFactory.class);
|
||||||
private final Gson gson = new GsonBuilder().registerTypeAdapter(ZonedDateTime.class,
|
private final Gson gson = new GsonBuilder()
|
||||||
(JsonDeserializer<ZonedDateTime>) (json, type, jsonDeserializationContext) -> ZonedDateTime
|
.registerTypeAdapter(ZonedDateTime.class,
|
||||||
.parse(json.getAsJsonPrimitive().getAsString(), LINKY_FORMATTER))
|
(JsonDeserializer<ZonedDateTime>) (json, type, jsonDeserializationContext) -> ZonedDateTime
|
||||||
|
.parse(json.getAsJsonPrimitive().getAsString(), LINKY_FORMATTER))
|
||||||
|
.registerTypeAdapter(LocalDate.class,
|
||||||
|
(JsonDeserializer<LocalDate>) (json, type, jsonDeserializationContext) -> LocalDate
|
||||||
|
.parse(json.getAsJsonPrimitive().getAsString(), LINKY_LOCALDATE_FORMATTER))
|
||||||
|
.registerTypeAdapter(LocalDateTime.class,
|
||||||
|
(JsonDeserializer<LocalDateTime>) (json, type, jsonDeserializationContext) -> {
|
||||||
|
try {
|
||||||
|
return LocalDateTime.parse(json.getAsJsonPrimitive().getAsString(),
|
||||||
|
LINKY_LOCALDATETIME_FORMATTER);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return LocalDate.parse(json.getAsJsonPrimitive().getAsString(), LINKY_LOCALDATE_FORMATTER)
|
||||||
|
.atStartOfDay();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
.create();
|
.create();
|
||||||
private final LocaleProvider localeProvider;
|
private final LocaleProvider localeProvider;
|
||||||
private final HttpClient httpClient;
|
private final HttpClient httpClient;
|
||||||
|
private final TimeZoneProvider timeZoneProvider;
|
||||||
|
|
||||||
@Activate
|
@Activate
|
||||||
public LinkyHandlerFactory(final @Reference LocaleProvider localeProvider,
|
public LinkyHandlerFactory(final @Reference LocaleProvider localeProvider,
|
||||||
final @Reference HttpClientFactory httpClientFactory) {
|
final @Reference HttpClientFactory httpClientFactory, final @Reference TimeZoneProvider timeZoneProvider) {
|
||||||
this.localeProvider = localeProvider;
|
this.localeProvider = localeProvider;
|
||||||
|
this.timeZoneProvider = timeZoneProvider;
|
||||||
SslContextFactory sslContextFactory = new SslContextFactory.Client();
|
SslContextFactory sslContextFactory = new SslContextFactory.Client();
|
||||||
try {
|
try {
|
||||||
SSLContext sslContext = SSLContext.getInstance("SSL");
|
SSLContext sslContext = SSLContext.getInstance("SSL");
|
||||||
@ -114,7 +141,8 @@ public class LinkyHandlerFactory extends BaseThingHandlerFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||||
return supportsThingType(thing.getThingTypeUID()) ? new LinkyHandler(thing, localeProvider, gson, httpClient)
|
return supportsThingType(thing.getThingTypeUID())
|
||||||
|
? new LinkyHandler(thing, localeProvider, gson, httpClient, timeZoneProvider)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ import com.google.gson.JsonSyntaxException;
|
|||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class EnedisHttpApi {
|
public class EnedisHttpApi {
|
||||||
private static final DateTimeFormatter API_DATE_FORMAT = DateTimeFormatter.ofPattern("dd-MM-yyyy");
|
private static final DateTimeFormatter API_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||||
private static final String ENEDIS_DOMAIN = ".enedis.fr";
|
private static final String ENEDIS_DOMAIN = ".enedis.fr";
|
||||||
private static final String URL_APPS_LINCS = "https://alex.microapplications" + ENEDIS_DOMAIN;
|
private static final String URL_APPS_LINCS = "https://alex.microapplications" + ENEDIS_DOMAIN;
|
||||||
private static final String URL_MON_COMPTE = "https://mon-compte" + ENEDIS_DOMAIN;
|
private static final String URL_MON_COMPTE = "https://mon-compte" + ENEDIS_DOMAIN;
|
||||||
@ -70,10 +70,10 @@ public class EnedisHttpApi {
|
|||||||
private static final String URL_ENEDIS_AUTHENTICATE = URL_APPS_LINCS + "/authenticate?target=" + URL_COMPTE_PART;
|
private static final String URL_ENEDIS_AUTHENTICATE = URL_APPS_LINCS + "/authenticate?target=" + URL_COMPTE_PART;
|
||||||
private static final String USER_INFO_CONTRACT_URL = URL_APPS_LINCS + "/mon-compte-client/api/private/v1/userinfos";
|
private static final String USER_INFO_CONTRACT_URL = URL_APPS_LINCS + "/mon-compte-client/api/private/v1/userinfos";
|
||||||
private static final String USER_INFO_URL = URL_APPS_LINCS + "/userinfos";
|
private static final String USER_INFO_URL = URL_APPS_LINCS + "/userinfos";
|
||||||
private static final String PRM_INFO_BASE_URL = URL_APPS_LINCS + "/mes-mesures/api/private/v1/personnes/";
|
private static final String PRM_INFO_BASE_URL = URL_APPS_LINCS + "/mes-mesures-prm/api/private/v1/personnes/";
|
||||||
private static final String PRM_INFO_URL = URL_APPS_LINCS + "/mes-prms-part/api/private/v2/personnes/%s/prms";
|
private static final String PRM_INFO_URL = URL_APPS_LINCS + "/mes-prms-part/api/private/v2/personnes/%s/prms";
|
||||||
private static final String MEASURE_URL = PRM_INFO_BASE_URL
|
private static final String MEASURE_URL = PRM_INFO_BASE_URL
|
||||||
+ "%s/prms/%s/donnees-%s?dateDebut=%s&dateFin=%s&mesuretypecode=CONS";
|
+ "%s/prms/%s/donnees-energetiques?mesuresTypeCode=%s&mesuresCorrigees=false&typeDonnees=CONS&dateDebut=%s";
|
||||||
private static final URI COOKIE_URI = URI.create(URL_COMPTE_PART);
|
private static final URI COOKIE_URI = URI.create(URL_COMPTE_PART);
|
||||||
private static final Pattern REQ_PATTERN = Pattern.compile("ReqID%(.*?)%26");
|
private static final Pattern REQ_PATTERN = Pattern.compile("ReqID%(.*?)%26");
|
||||||
|
|
||||||
@ -289,17 +289,16 @@ public class EnedisHttpApi {
|
|||||||
|
|
||||||
private Consumption getMeasures(String userId, String prmId, LocalDate from, LocalDate to, String request)
|
private Consumption getMeasures(String userId, String prmId, LocalDate from, LocalDate to, String request)
|
||||||
throws LinkyException {
|
throws LinkyException {
|
||||||
String url = String.format(MEASURE_URL, userId, prmId, request, from.format(API_DATE_FORMAT),
|
String url = String.format(MEASURE_URL, userId, prmId, request, from.format(API_DATE_FORMAT));
|
||||||
to.format(API_DATE_FORMAT));
|
|
||||||
ConsumptionReport report = getData(url, ConsumptionReport.class);
|
ConsumptionReport report = getData(url, ConsumptionReport.class);
|
||||||
return report.firstLevel.consumptions;
|
return report.consumptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Consumption getEnergyData(String userId, String prmId, LocalDate from, LocalDate to) throws LinkyException {
|
public Consumption getEnergyData(String userId, String prmId, LocalDate from, LocalDate to) throws LinkyException {
|
||||||
return getMeasures(userId, prmId, from, to, "energie");
|
return getMeasures(userId, prmId, from, to, "ENERGIE");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Consumption getPowerData(String userId, String prmId, LocalDate from, LocalDate to) throws LinkyException {
|
public Consumption getPowerData(String userId, String prmId, LocalDate from, LocalDate to) throws LinkyException {
|
||||||
return getMeasures(userId, prmId, from, to, "pmax");
|
return getMeasures(userId, prmId, from, to, "PMAX");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.linky.internal.dto;
|
package org.openhab.binding.linky.internal.dto;
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
@ -22,28 +23,30 @@ import com.google.gson.annotations.SerializedName;
|
|||||||
* returned by API calls
|
* returned by API calls
|
||||||
*
|
*
|
||||||
* @author Gaël L'hopital - Initial contribution
|
* @author Gaël L'hopital - Initial contribution
|
||||||
|
* @author Laurent ARNAL - fix to handle new Dto format after enedis site modifications
|
||||||
*/
|
*/
|
||||||
public class ConsumptionReport {
|
public class ConsumptionReport {
|
||||||
public class Period {
|
|
||||||
public String grandeurPhysiqueEnum;
|
public class Data {
|
||||||
public ZonedDateTime dateDebut;
|
public LocalDateTime dateDebut;
|
||||||
public ZonedDateTime dateFin;
|
public LocalDateTime dateFin;
|
||||||
|
public Double valeur;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Aggregate {
|
public class Aggregate {
|
||||||
public List<String> labels;
|
@SerializedName("donnees")
|
||||||
public List<Period> periodes;
|
public List<Data> datas;
|
||||||
public List<Double> datas;
|
public String unite;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ChronoData {
|
public class ChronoData {
|
||||||
@SerializedName("JOUR")
|
@SerializedName("jour")
|
||||||
public Aggregate days;
|
public Aggregate days;
|
||||||
@SerializedName("SEMAINE")
|
@SerializedName("semaine")
|
||||||
public Aggregate weeks;
|
public Aggregate weeks;
|
||||||
@SerializedName("MOIS")
|
@SerializedName("mois")
|
||||||
public Aggregate months;
|
public Aggregate months;
|
||||||
@SerializedName("ANNEE")
|
@SerializedName("annee")
|
||||||
public Aggregate years;
|
public Aggregate years;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,14 +54,10 @@ public class ConsumptionReport {
|
|||||||
public ChronoData aggregats;
|
public ChronoData aggregats;
|
||||||
public String grandeurMetier;
|
public String grandeurMetier;
|
||||||
public String grandeurPhysique;
|
public String grandeurPhysique;
|
||||||
public String unite;
|
public LocalDate dateDebut;
|
||||||
|
public LocalDate dateFin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FirstLevel {
|
@SerializedName("cons")
|
||||||
@SerializedName("CONS")
|
public Consumption consumptions;
|
||||||
public Consumption consumptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SerializedName("1")
|
|
||||||
public FirstLevel firstLevel;
|
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import static org.openhab.binding.linky.internal.LinkyBindingConstants.*;
|
|||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
@ -38,7 +39,9 @@ import org.openhab.binding.linky.internal.dto.ConsumptionReport.Consumption;
|
|||||||
import org.openhab.binding.linky.internal.dto.PrmDetail;
|
import org.openhab.binding.linky.internal.dto.PrmDetail;
|
||||||
import org.openhab.binding.linky.internal.dto.PrmInfo;
|
import org.openhab.binding.linky.internal.dto.PrmInfo;
|
||||||
import org.openhab.binding.linky.internal.dto.UserInfo;
|
import org.openhab.binding.linky.internal.dto.UserInfo;
|
||||||
|
import org.openhab.core.config.core.Configuration;
|
||||||
import org.openhab.core.i18n.LocaleProvider;
|
import org.openhab.core.i18n.LocaleProvider;
|
||||||
|
import org.openhab.core.i18n.TimeZoneProvider;
|
||||||
import org.openhab.core.library.types.DateTimeType;
|
import org.openhab.core.library.types.DateTimeType;
|
||||||
import org.openhab.core.library.types.QuantityType;
|
import org.openhab.core.library.types.QuantityType;
|
||||||
import org.openhab.core.library.unit.MetricPrefix;
|
import org.openhab.core.library.unit.MetricPrefix;
|
||||||
@ -65,6 +68,9 @@ import com.google.gson.Gson;
|
|||||||
|
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class LinkyHandler extends BaseThingHandler {
|
public class LinkyHandler extends BaseThingHandler {
|
||||||
|
private final TimeZoneProvider timeZoneProvider;
|
||||||
|
private ZoneId zoneId = ZoneId.systemDefault();
|
||||||
|
|
||||||
private static final int REFRESH_FIRST_HOUR_OF_DAY = 1;
|
private static final int REFRESH_FIRST_HOUR_OF_DAY = 1;
|
||||||
private static final int REFRESH_INTERVAL_IN_MIN = 120;
|
private static final int REFRESH_INTERVAL_IN_MIN = 120;
|
||||||
|
|
||||||
@ -90,11 +96,13 @@ public class LinkyHandler extends BaseThingHandler {
|
|||||||
ALL
|
ALL
|
||||||
}
|
}
|
||||||
|
|
||||||
public LinkyHandler(Thing thing, LocaleProvider localeProvider, Gson gson, HttpClient httpClient) {
|
public LinkyHandler(Thing thing, LocaleProvider localeProvider, Gson gson, HttpClient httpClient,
|
||||||
|
TimeZoneProvider timeZoneProvider) {
|
||||||
super(thing);
|
super(thing);
|
||||||
this.gson = gson;
|
this.gson = gson;
|
||||||
this.httpClient = httpClient;
|
this.httpClient = httpClient;
|
||||||
this.weekFields = WeekFields.of(localeProvider.getLocale());
|
this.weekFields = WeekFields.of(localeProvider.getLocale());
|
||||||
|
this.timeZoneProvider = timeZoneProvider;
|
||||||
|
|
||||||
this.cachedDailyData = new ExpiringDayCache<>("daily cache", REFRESH_FIRST_HOUR_OF_DAY, () -> {
|
this.cachedDailyData = new ExpiringDayCache<>("daily cache", REFRESH_FIRST_HOUR_OF_DAY, () -> {
|
||||||
LocalDate today = LocalDate.now();
|
LocalDate today = LocalDate.now();
|
||||||
@ -150,6 +158,19 @@ public class LinkyHandler extends BaseThingHandler {
|
|||||||
logger.debug("Initializing Linky handler.");
|
logger.debug("Initializing Linky handler.");
|
||||||
updateStatus(ThingStatus.UNKNOWN);
|
updateStatus(ThingStatus.UNKNOWN);
|
||||||
|
|
||||||
|
// update the timezone if not set to default to openhab default timezone
|
||||||
|
Configuration thingConfig = getConfig();
|
||||||
|
|
||||||
|
String val = (String) thingConfig.get("timezone");
|
||||||
|
if (val == null || val.isBlank()) {
|
||||||
|
zoneId = this.timeZoneProvider.getTimeZone();
|
||||||
|
thingConfig.put("timezone", zoneId.getId());
|
||||||
|
} else {
|
||||||
|
zoneId = ZoneId.of(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateConfiguration(thingConfig);
|
||||||
|
|
||||||
LinkyConfiguration config = getConfigAs(LinkyConfiguration.class);
|
LinkyConfiguration config = getConfigAs(LinkyConfiguration.class);
|
||||||
if (config.seemsValid()) {
|
if (config.seemsValid()) {
|
||||||
enedisApi = new EnedisHttpApi(config, gson, httpClient);
|
enedisApi = new EnedisHttpApi(config, gson, httpClient);
|
||||||
@ -211,8 +232,9 @@ public class LinkyHandler extends BaseThingHandler {
|
|||||||
if (isLinked(PEAK_POWER) || isLinked(PEAK_TIMESTAMP)) {
|
if (isLinked(PEAK_POWER) || isLinked(PEAK_TIMESTAMP)) {
|
||||||
cachedPowerData.getValue().ifPresentOrElse(values -> {
|
cachedPowerData.getValue().ifPresentOrElse(values -> {
|
||||||
Aggregate days = values.aggregats.days;
|
Aggregate days = values.aggregats.days;
|
||||||
updatekVAChannel(PEAK_POWER, days.datas.get(days.datas.size() - 1));
|
updatekVAChannel(PEAK_POWER, days.datas.get(days.datas.size() - 1).valeur);
|
||||||
updateState(PEAK_TIMESTAMP, new DateTimeType(days.periodes.get(days.datas.size() - 1).dateDebut));
|
updateState(PEAK_TIMESTAMP,
|
||||||
|
new DateTimeType(days.datas.get(days.datas.size() - 1).dateDebut.atZone(zoneId)));
|
||||||
}, () -> {
|
}, () -> {
|
||||||
updateKwhChannel(PEAK_POWER, Double.NaN);
|
updateKwhChannel(PEAK_POWER, Double.NaN);
|
||||||
updateState(PEAK_TIMESTAMP, UnDefType.UNDEF);
|
updateState(PEAK_TIMESTAMP, UnDefType.UNDEF);
|
||||||
@ -224,9 +246,9 @@ public class LinkyHandler extends BaseThingHandler {
|
|||||||
double currentValue = 0.0;
|
double currentValue = 0.0;
|
||||||
double previousValue = 0.0;
|
double previousValue = 0.0;
|
||||||
if (!periods.datas.isEmpty()) {
|
if (!periods.datas.isEmpty()) {
|
||||||
currentValue = periods.datas.get(periods.datas.size() - 1);
|
currentValue = periods.datas.get(periods.datas.size() - 1).valeur;
|
||||||
if (periods.datas.size() > 1) {
|
if (periods.datas.size() > 1) {
|
||||||
previousValue = periods.datas.get(periods.datas.size() - 2);
|
previousValue = periods.datas.get(periods.datas.size() - 2).valeur;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateKwhChannel(currentChannel, currentValue);
|
updateKwhChannel(currentChannel, currentValue);
|
||||||
@ -240,7 +262,7 @@ public class LinkyHandler extends BaseThingHandler {
|
|||||||
if (isLinked(YESTERDAY) || isLinked(LAST_WEEK) || isLinked(THIS_WEEK)) {
|
if (isLinked(YESTERDAY) || isLinked(LAST_WEEK) || isLinked(THIS_WEEK)) {
|
||||||
cachedDailyData.getValue().ifPresentOrElse(values -> {
|
cachedDailyData.getValue().ifPresentOrElse(values -> {
|
||||||
Aggregate days = values.aggregats.days;
|
Aggregate days = values.aggregats.days;
|
||||||
updateKwhChannel(YESTERDAY, days.datas.get(days.datas.size() - 1));
|
updateKwhChannel(YESTERDAY, days.datas.get(days.datas.size() - 1).valeur);
|
||||||
setCurrentAndPrevious(values.aggregats.weeks, THIS_WEEK, LAST_WEEK);
|
setCurrentAndPrevious(values.aggregats.weeks, THIS_WEEK, LAST_WEEK);
|
||||||
}, () -> {
|
}, () -> {
|
||||||
updateKwhChannel(YESTERDAY, Double.NaN);
|
updateKwhChannel(YESTERDAY, Double.NaN);
|
||||||
@ -322,16 +344,15 @@ public class LinkyHandler extends BaseThingHandler {
|
|||||||
Consumption result = getConsumptionData(startDay, endDay.plusDays(1));
|
Consumption result = getConsumptionData(startDay, endDay.plusDays(1));
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
Aggregate days = result.aggregats.days;
|
Aggregate days = result.aggregats.days;
|
||||||
int size = (days.datas == null || days.periodes == null) ? 0
|
int size = (days.datas == null) ? 0 : days.datas.size();
|
||||||
: (days.datas.size() <= days.periodes.size() ? days.datas.size() : days.periodes.size());
|
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
double consumption = days.datas.get(i);
|
double consumption = days.datas.get(i).valeur;
|
||||||
LocalDate day = days.periodes.get(i).dateDebut.toLocalDate();
|
LocalDate day = days.datas.get(i).dateDebut.toLocalDate();
|
||||||
// Filter data in case it contains data from dates outside the requested period
|
// Filter data in case it contains data from dates outside the requested period
|
||||||
if (day.isBefore(startDay) || day.isAfter(endDay)) {
|
if (day.isBefore(startDay) || day.isAfter(endDay)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String line = days.periodes.get(i).dateDebut.format(DateTimeFormatter.ISO_LOCAL_DATE) + separator;
|
String line = days.datas.get(i).dateDebut.format(DateTimeFormatter.ISO_LOCAL_DATE) + separator;
|
||||||
if (consumption >= 0) {
|
if (consumption >= 0) {
|
||||||
line += String.valueOf(consumption);
|
line += String.valueOf(consumption);
|
||||||
}
|
}
|
||||||
@ -474,50 +495,36 @@ public class LinkyHandler extends BaseThingHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkData(Consumption consumption) throws LinkyException {
|
private void checkData(Consumption consumption) throws LinkyException {
|
||||||
if (consumption.aggregats.days.periodes.isEmpty()) {
|
if (consumption.aggregats.days.datas.isEmpty()) {
|
||||||
throw new LinkyException("Invalid consumptions data: no day period");
|
throw new LinkyException("Invalid consumptions data: no day period");
|
||||||
}
|
}
|
||||||
if (consumption.aggregats.days.periodes.size() != consumption.aggregats.days.datas.size()) {
|
if (consumption.aggregats.weeks != null && consumption.aggregats.weeks.datas.isEmpty()) {
|
||||||
throw new LinkyException("Invalid consumptions data: not any data for each day period");
|
|
||||||
}
|
|
||||||
if (consumption.aggregats.weeks.periodes.isEmpty()) {
|
|
||||||
throw new LinkyException("Invalid consumptions data: no week period");
|
throw new LinkyException("Invalid consumptions data: no week period");
|
||||||
}
|
}
|
||||||
if (consumption.aggregats.weeks.periodes.size() != consumption.aggregats.weeks.datas.size()) {
|
if (consumption.aggregats.months != null && consumption.aggregats.months.datas.isEmpty()) {
|
||||||
throw new LinkyException("Invalid consumptions data: not any data for each week period");
|
|
||||||
}
|
|
||||||
if (consumption.aggregats.months.periodes.isEmpty()) {
|
|
||||||
throw new LinkyException("Invalid consumptions data: no month period");
|
throw new LinkyException("Invalid consumptions data: no month period");
|
||||||
}
|
}
|
||||||
if (consumption.aggregats.months.periodes.size() != consumption.aggregats.months.datas.size()) {
|
if (consumption.aggregats.years != null && consumption.aggregats.years.datas.isEmpty()) {
|
||||||
throw new LinkyException("Invalid consumptions data: not any data for each month period");
|
|
||||||
}
|
|
||||||
if (consumption.aggregats.years.periodes.isEmpty()) {
|
|
||||||
throw new LinkyException("Invalid consumptions data: no year period");
|
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 any data for each year period");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isDataFirstDayAvailable(Consumption consumption) {
|
private boolean isDataFirstDayAvailable(Consumption consumption) {
|
||||||
Aggregate days = consumption.aggregats.days;
|
Aggregate days = consumption.aggregats.days;
|
||||||
logData(days, "First day", false, DateTimeFormatter.ISO_LOCAL_DATE, Target.FIRST);
|
logData(days, "First day", false, DateTimeFormatter.ISO_LOCAL_DATE, Target.FIRST);
|
||||||
return days.datas != null && !days.datas.isEmpty() && !days.datas.get(0).isNaN();
|
return days.datas != null && !days.datas.isEmpty() && !days.datas.get(0).valeur.isNaN();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isDataLastDayAvailable(Consumption consumption) {
|
private boolean isDataLastDayAvailable(Consumption consumption) {
|
||||||
Aggregate days = consumption.aggregats.days;
|
Aggregate days = consumption.aggregats.days;
|
||||||
logData(days, "Last day", false, DateTimeFormatter.ISO_LOCAL_DATE, Target.LAST);
|
logData(days, "Last day", false, DateTimeFormatter.ISO_LOCAL_DATE, Target.LAST);
|
||||||
return days.datas != null && !days.datas.isEmpty() && !days.datas.get(days.datas.size() - 1).isNaN();
|
return days.datas != null && !days.datas.isEmpty() && !days.datas.get(days.datas.size() - 1).valeur.isNaN();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logData(Aggregate aggregate, String title, boolean withDateFin, DateTimeFormatter dateTimeFormatter,
|
private void logData(Aggregate aggregate, String title, boolean withDateFin, DateTimeFormatter dateTimeFormatter,
|
||||||
Target target) {
|
Target target) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
int size = (aggregate.datas == null || aggregate.periodes == null) ? 0
|
int size = (aggregate.datas == null) ? 0 : aggregate.datas.size();
|
||||||
: (aggregate.datas.size() <= aggregate.periodes.size() ? aggregate.datas.size()
|
|
||||||
: aggregate.periodes.size());
|
|
||||||
if (target == Target.FIRST) {
|
if (target == Target.FIRST) {
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
logData(aggregate, 0, title, withDateFin, dateTimeFormatter);
|
logData(aggregate, 0, title, withDateFin, dateTimeFormatter);
|
||||||
@ -537,11 +544,11 @@ public class LinkyHandler extends BaseThingHandler {
|
|||||||
private void logData(Aggregate aggregate, int index, String title, boolean withDateFin,
|
private void logData(Aggregate aggregate, int index, String title, boolean withDateFin,
|
||||||
DateTimeFormatter dateTimeFormatter) {
|
DateTimeFormatter dateTimeFormatter) {
|
||||||
if (withDateFin) {
|
if (withDateFin) {
|
||||||
logger.debug("{} {} {} value {}", title, aggregate.periodes.get(index).dateDebut.format(dateTimeFormatter),
|
logger.debug("{} {} {} value {}", title, aggregate.datas.get(index).dateDebut.format(dateTimeFormatter),
|
||||||
aggregate.periodes.get(index).dateFin.format(dateTimeFormatter), aggregate.datas.get(index));
|
aggregate.datas.get(index).dateFin.format(dateTimeFormatter), aggregate.datas.get(index).valeur);
|
||||||
} else {
|
} else {
|
||||||
logger.debug("{} {} value {}", title, aggregate.periodes.get(index).dateDebut.format(dateTimeFormatter),
|
logger.debug("{} {} value {}", title, aggregate.datas.get(index).dateDebut.format(dateTimeFormatter),
|
||||||
aggregate.datas.get(index));
|
aggregate.datas.get(index).valeur);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ thing-type.config.linky.linky.internalAuthId.label = Auth ID
|
|||||||
thing-type.config.linky.linky.internalAuthId.description = Authentication ID delivered after the captcha (see documentation).
|
thing-type.config.linky.linky.internalAuthId.description = Authentication ID delivered after the captcha (see documentation).
|
||||||
thing-type.config.linky.linky.password.label = Password
|
thing-type.config.linky.linky.password.label = Password
|
||||||
thing-type.config.linky.linky.password.description = Your Enedis Password
|
thing-type.config.linky.linky.password.description = Your Enedis Password
|
||||||
|
thing-type.config.linky.linky.timezone.label = timezone
|
||||||
|
thing-type.config.linky.linky.timezone.description = The timezone associated with your Point of delivery. Will default to openHAB default timezone. You will need to change this if your Linky is located in a different timezone that your openHAB location. You can use an offset, or a label like Europe/Paris
|
||||||
thing-type.config.linky.linky.username.label = Username
|
thing-type.config.linky.linky.username.label = Username
|
||||||
thing-type.config.linky.linky.username.description = Your Enedis Username
|
thing-type.config.linky.linky.username.description = Your Enedis Username
|
||||||
|
|
||||||
@ -41,6 +43,6 @@ channel-type.linky.power.label = Yesterday Peak Power
|
|||||||
channel-type.linky.power.description = Maximum power usage yesterday
|
channel-type.linky.power.description = Maximum power usage yesterday
|
||||||
channel-type.linky.timestamp.label = Timestamp
|
channel-type.linky.timestamp.label = Timestamp
|
||||||
|
|
||||||
# Thing status descriptions
|
# thing status descriptions
|
||||||
|
|
||||||
offline.config-error-mandatory-settings = Username, password and authId are mandatory.
|
offline.config-error-mandatory-settings = Username, password and authId are mandatory.
|
||||||
|
@ -34,6 +34,16 @@
|
|||||||
<label>Auth ID</label>
|
<label>Auth ID</label>
|
||||||
<description>Authentication ID delivered after the captcha (see documentation).</description>
|
<description>Authentication ID delivered after the captcha (see documentation).</description>
|
||||||
</parameter>
|
</parameter>
|
||||||
|
<parameter name="timezone" type="text" required="false">
|
||||||
|
<label>timezone</label>
|
||||||
|
<description>The timezone associated with your Point of delivery.
|
||||||
|
Will default to openHAB default timezone.
|
||||||
|
You will
|
||||||
|
need to change this if your Linky is located in a different timezone that your openHAB location.
|
||||||
|
You can use an
|
||||||
|
offset, or a label like Europe/Paris</description>
|
||||||
|
</parameter>
|
||||||
|
|
||||||
</config-description>
|
</config-description>
|
||||||
</thing-type>
|
</thing-type>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user