mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[linky] Fix data refresh (login / logout) (#9358)
Fix #9313 Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
parent
30485c6a5b
commit
4e54b5b9b5
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user