diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml
index c5b6913a0540..9555fa7c8b84 100644
--- a/bom/openhab-addons/pom.xml
+++ b/bom/openhab-addons/pom.xml
@@ -751,13 +751,11 @@
org.openhab.binding.lifx
${project.version}
-
+
org.openhab.addons.bundles
org.openhab.binding.linuxinput
diff --git a/bundles/org.openhab.binding.linky/src/main/feature/feature.xml.bak b/bundles/org.openhab.binding.linky/src/main/feature/feature.xml
similarity index 100%
rename from bundles/org.openhab.binding.linky/src/main/feature/feature.xml.bak
rename to bundles/org.openhab.binding.linky/src/main/feature/feature.xml
diff --git a/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/LinkyConfiguration.java b/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/LinkyConfiguration.java
index 5c5029c58f82..f14e2b378a3a 100644
--- a/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/LinkyConfiguration.java
+++ b/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/LinkyConfiguration.java
@@ -12,15 +12,22 @@
*/
package org.openhab.binding.linky.internal;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
/**
* The {@link LinkyConfiguration} is the class used to match the
* thing configuration.
*
* @author Gaƫl L'hopital - Initial contribution
*/
+@NonNullByDefault
public class LinkyConfiguration {
public static final String INTERNAL_AUTH_ID = "internalAuthId";
- public String username;
- public String password;
- public String internalAuthId;
+ public String username = "";
+ public String password = "";
+ public String internalAuthId = "";
+
+ public boolean seemsValid() {
+ return !username.isBlank() && !password.isBlank() && !internalAuthId.isBlank();
+ }
}
diff --git a/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/LinkyHandlerFactory.java b/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/LinkyHandlerFactory.java
index d0edaa6a9259..1f2e28bdd5eb 100644
--- a/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/LinkyHandlerFactory.java
+++ b/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/LinkyHandlerFactory.java
@@ -47,9 +47,10 @@
@NonNullByDefault
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.linky")
public class LinkyHandlerFactory extends BaseThingHandlerFactory {
+ private static final DateTimeFormatter LINKY_FORMATTER = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX");
+
private final Logger logger = LoggerFactory.getLogger(LinkyHandlerFactory.class);
- private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX");
private final LocaleProvider localeProvider;
private final Gson gson;
private final HttpClient httpClient;
@@ -60,7 +61,7 @@ public LinkyHandlerFactory(final @Reference LocaleProvider localeProvider,
this.localeProvider = localeProvider;
this.gson = new GsonBuilder().registerTypeAdapter(ZonedDateTime.class,
(JsonDeserializer) (json, type, jsonDeserializationContext) -> ZonedDateTime
- .parse(json.getAsJsonPrimitive().getAsString(), formatter))
+ .parse(json.getAsJsonPrimitive().getAsString(), LINKY_FORMATTER))
.create();
this.httpClient = httpClientFactory.createHttpClient(LinkyBindingConstants.BINDING_ID);
}
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 fb4fad25cb1b..47f964df666a 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
@@ -64,18 +64,19 @@ public class EnedisHttpApi {
private final Logger logger = LoggerFactory.getLogger(EnedisHttpApi.class);
private final Gson gson;
private final HttpClient httpClient;
- private final LinkyConfiguration config;
private boolean connected = false;
+ private final CookieStore cookieStore;
+ private final LinkyConfiguration config;
public EnedisHttpApi(LinkyConfiguration config, Gson gson, HttpClient httpClient) {
this.gson = gson;
this.httpClient = httpClient;
this.config = config;
+ this.cookieStore = httpClient.getCookieStore();
+ addCookie(LinkyConfiguration.INTERNAL_AUTH_ID, config.internalAuthId);
}
public void initialize() throws LinkyException {
- addCookie(LinkyConfiguration.INTERNAL_AUTH_ID, config.internalAuthId);
-
logger.debug("Starting login process for user : {}", config.username);
try {
@@ -109,31 +110,39 @@ public void initialize() throws LinkyException {
logger.debug(
"Step 3 : auth1 - retrieve the template, thanks to cookie internalAuthId, user is already set");
- result = httpClient.POST(url).send();
+ result = httpClient.POST(url).header("X-NoSession", "true").header("X-Password", "anonymous")
+ .header("X-Requested-With", "XMLHttpRequest").header("X-Username", "anonymous").send();
if (result.getStatus() != 200) {
throw new LinkyException("Connection failed step 3 - auth1 : " + result.getContentAsString());
}
AuthData authData = gson.fromJson(result.getContentAsString(), AuthData.class);
- if (authData.callbacks.size() < 2 || authData.callbacks.get(0).input.size() == 0
- || authData.callbacks.get(1).input.size() == 0 || !config.username
+ if (authData == null || authData.callbacks.size() < 2 || authData.callbacks.get(0).input.isEmpty()
+ || authData.callbacks.get(1).input.isEmpty() || !config.username
.equals(Objects.requireNonNull(authData.callbacks.get(0).input.get(0)).valueAsString())) {
throw new LinkyException("Authentication error, the authentication_cookie is probably wrong");
}
authData.callbacks.get(1).input.get(0).value = config.password;
- url = "https://mon-compte.enedis.fr/auth/json/authenticate?realm=/enedis&spEntityID=SP-ODW-PROD&goto=/auth/SSOPOST/metaAlias/enedis/providerIDP?ReqID%"
+ url = URL_MON_COMPTE
+ + "/auth/json/authenticate?realm=/enedis&spEntityID=SP-ODW-PROD&goto=/auth/SSOPOST/metaAlias/enedis/providerIDP?ReqID%"
+ reqId
+ "%26index%3Dnull%26acsURL%3Dhttps://apps.lincs.enedis.fr/saml/SSO%26spEntityID%3DSP-ODW-PROD%26binding%3Durn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST&AMAuthCookie=";
logger.debug("Step 3 : auth2 - send the auth data");
result = httpClient.POST(url).header(HttpHeader.CONTENT_TYPE, "application/json")
+ .header("X-NoSession", "true").header("X-Password", "anonymous")
+ .header("X-Requested-With", "XMLHttpRequest").header("X-Username", "anonymous")
.content(new StringContentProvider(gson.toJson(authData))).send();
if (result.getStatus() != 200) {
throw new LinkyException("Connection failed step 3 - auth2 : " + result.getContentAsString());
}
AuthResult authResult = gson.fromJson(result.getContentAsString(), AuthResult.class);
+ if (authResult == null) {
+ throw new LinkyException("Invalid authentication result data");
+ }
+
logger.debug("Add the tokenId cookie");
addCookie("enedisExt", authResult.tokenId);
@@ -155,18 +164,17 @@ public void initialize() throws LinkyException {
}
}
- public String getLocation(ContentResponse response) {
+ private String getLocation(ContentResponse response) {
return response.getHeaders().get(HttpHeader.LOCATION);
}
- public void disconnect() throws LinkyException {
+ private 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));
location = getLocation(httpClient.GET(location));
- CookieStore cookieStore = httpClient.getCookieStore();
cookieStore.removeAll();
connected = false;
} catch (InterruptedException | ExecutionException | TimeoutException e) {
@@ -184,7 +192,6 @@ public void dispose() throws LinkyException {
}
private void addCookie(String key, String value) {
- CookieStore cookieStore = httpClient.getCookieStore();
HttpCookie cookie = new HttpCookie(key, value);
cookie.setDomain(".enedis.fr");
cookie.setPath("/");
@@ -220,6 +227,9 @@ public PrmInfo getPrmInfo() throws LinkyException {
}
try {
PrmInfo[] prms = gson.fromJson(data, PrmInfo[].class);
+ if (prms == null || prms.length < 1) {
+ throw new LinkyException("Invalid prms data received");
+ }
return prms[0];
} catch (JsonSyntaxException e) {
logger.debug("invalid JSON response not matching PrmInfo[].class: {}", data);
@@ -259,6 +269,9 @@ private Consumption getMeasures(String userId, String prmId, LocalDate from, Loc
logger.trace("getData returned {}", data);
try {
ConsumptionReport report = gson.fromJson(data, ConsumptionReport.class);
+ if (report == null) {
+ throw new LinkyException("No report data received");
+ }
return report.firstLevel.consumptions;
} catch (JsonSyntaxException e) {
logger.debug("invalid JSON response not matching ConsumptionReport.class: {}", data);
diff --git a/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/api/ExpiringDayCache.java b/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/api/ExpiringDayCache.java
index 577120659736..59ec78d57eb8 100644
--- a/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/api/ExpiringDayCache.java
+++ b/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/api/ExpiringDayCache.java
@@ -77,24 +77,6 @@ public synchronized Optional getValue() {
return Optional.ofNullable(cachedValue);
}
- /**
- * Puts a new value into the cache.
- *
- * @param value the new value
- */
- public final synchronized void putValue(@Nullable V value) {
- this.value = value;
- expiresAt = calcNextExpiresAt();
- }
-
- /**
- * Invalidates the value in the cache.
- */
- public final synchronized void invalidateValue() {
- value = null;
- expiresAt = calcAlreadyExpired();
- }
-
/**
* Refreshes and returns the value in the cache.
*
diff --git a/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/dto/AuthData.java b/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/dto/AuthData.java
index 4ee6f93b1e38..bc8407fca4df 100644
--- a/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/dto/AuthData.java
+++ b/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/dto/AuthData.java
@@ -12,7 +12,6 @@
*/
package org.openhab.binding.linky.internal.dto;
-import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -31,22 +30,19 @@ public class NameValuePair {
public @Nullable Object value;
public @Nullable String valueAsString() {
- if (value instanceof String) {
- return (String) value;
- }
- return null;
+ return (value instanceof String) ? (String) value : null;
}
}
public @Nullable String type;
- public List output = new ArrayList<>();
- public List input = new ArrayList<>();
+ public List output = List.of();
+ public List input = List.of();
}
public @Nullable String authId;
public @Nullable String template;
public @Nullable String stage;
public @Nullable String header;
- public List callbacks = new ArrayList<>();
+ public List callbacks = List.of();
}
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 7f4cc7273999..724bd5dd0584 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
@@ -64,11 +64,11 @@
@NonNullByDefault
public class LinkyHandler extends BaseThingHandler {
- private final Logger logger = LoggerFactory.getLogger(LinkyHandler.class);
-
private static final int REFRESH_FIRST_HOUR_OF_DAY = 1;
private static final int REFRESH_INTERVAL_IN_MIN = 120;
+ private final Logger logger = LoggerFactory.getLogger(LinkyHandler.class);
+
private final HttpClient httpClient;
private final Gson gson;
private final WeekFields weekFields;
@@ -146,12 +146,11 @@ public void initialize() {
updateStatus(ThingStatus.UNKNOWN);
LinkyConfiguration config = getConfigAs(LinkyConfiguration.class);
- enedisApi = new EnedisHttpApi(config, gson, httpClient);
-
- scheduler.submit(() -> {
- try {
- EnedisHttpApi api = this.enedisApi;
- if (api != null) {
+ if (config.seemsValid()) {
+ enedisApi = new EnedisHttpApi(config, gson, httpClient);
+ scheduler.submit(() -> {
+ try {
+ EnedisHttpApi api = this.enedisApi;
api.initialize();
updateStatus(ThingStatus.ONLINE);
@@ -179,13 +178,14 @@ public void initialize() {
refreshJob = scheduler.scheduleWithFixedDelay(this::updateData,
ChronoUnit.MINUTES.between(now, nextDayFirstTimeUpdate) % REFRESH_INTERVAL_IN_MIN + 1,
REFRESH_INTERVAL_IN_MIN, TimeUnit.MINUTES);
- } else {
- throw new LinkyException("Enedis Api is not initialized");
+ } catch (LinkyException e) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
- } catch (LinkyException e) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
- }
- });
+ });
+ } else {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+ "Username, password and authId are mandatory");
+ }
}
/**
@@ -470,7 +470,7 @@ public synchronized void handleCommand(ChannelUID channelUID, Command command) {
return consumption;
}
- public void checkData(Consumption consumption) throws LinkyException {
+ private void checkData(Consumption consumption) throws LinkyException {
if (consumption.aggregats.days.periodes.size() == 0) {
throw new LinkyException("invalid consumptions data: no day period");
}
diff --git a/bundles/pom.xml b/bundles/pom.xml
index da42a13657c7..7be12335f1cd 100644
--- a/bundles/pom.xml
+++ b/bundles/pom.xml
@@ -185,9 +185,7 @@
org.openhab.binding.lgtvserial
org.openhab.binding.lgwebos
org.openhab.binding.lifx
-
+ org.openhab.binding.linky
org.openhab.binding.linuxinput
org.openhab.binding.lirc
org.openhab.binding.logreader