From 9b55bfba58cf06982c306e3f565286d3d9849101 Mon Sep 17 00:00:00 2001 From: lolodomo Date: Sun, 26 Nov 2023 23:34:45 +0100 Subject: [PATCH] [ecowatt] Add support for API version 5 (#15953) A new thing parameter to define the API version has been added. Its default value is 4 for backward compatibility even if this version is now deprecated. The documentation explains what to do to switch from a version to another. Signed-off-by: Laurent Garnier --- bundles/org.openhab.binding.ecowatt/README.md | 22 +++++++++++++------ .../configuration/EcowattConfiguration.java | 2 ++ .../internal/handler/EcowattHandler.java | 6 +++-- .../internal/restapi/EcowattDaySignals.java | 2 +- .../internal/restapi/EcowattRestApi.java | 11 ++++++---- .../resources/OH-INF/i18n/ecowatt.properties | 9 ++++++-- .../resources/OH-INF/thing/thing-types.xml | 20 +++++++++++++---- .../internal/EcowattApiResponseTest.java | 9 ++++++++ .../src/test/resources/ApiResponse.json | 2 +- 9 files changed, 62 insertions(+), 21 deletions(-) diff --git a/bundles/org.openhab.binding.ecowatt/README.md b/bundles/org.openhab.binding.ecowatt/README.md index 7a5b3d79356..23a41ce6948 100644 --- a/bundles/org.openhab.binding.ecowatt/README.md +++ b/bundles/org.openhab.binding.ecowatt/README.md @@ -17,11 +17,16 @@ You have to add the thing manually. You must create an account and an application on the RTE portal to obtain the OAuth2 credentials required to access the API. -1. Open this [page](https://data.rte-france.com/catalog/-/api/consumption/Ecowatt/v4.0), find the "Ecowatt" tile and click on the "Abonnez-vous à l'API" button. +1. Open this [page](https://data.rte-france.com/catalog/-/api/consumption/Ecowatt/v5.0), find the "Ecowatt" tile and click on the "Abonnez-vous à l'API" button. 1. Create an account by following the instructions (you will receive an email to validate your new account). 1. Once logged in, create an application by entering a name (for example "openHAB Integration"), choosing "Web Server" as type, entering any description of your choice and finally clicking on the "Valider" button. 1. You will then see your application details, in particular the "ID client" and "ID Secret" information which you will need later to set up your binding thing. +Note that you are subscribed to a particular version of the API. +When a new version of the API is released, you will have to subscribe to this new version and create a new application. +You will then get new information "ID client" and "ID Secret" and you will have to update your thing configuration in openHAB. +After changing version, you will have to wait for your authentication token to be renewed (max 2 hours) to get a successful response from the API. + ## Binding Configuration There are no overall binding configuration settings that need to be set. @@ -29,10 +34,13 @@ All settings are through thing configuration parameters. ## Thing Configuration -| Name | Type | Description | Required | -|-----------|---------|-----------------------------------------------------------------------|----------| -| idClient | text | ID client provided with the application you created in the RTE portal | yes | -| idSecret | text | ID secret provided with the application you created in the RTE portal | yes | +| Name | Type | Description | Required | Default | +|------------|---------|---------------------------------------------------------------------------|----------|---------| +| apiVersion | integer | The version of the Ecowatt tile to which you subscribed in the RTE portal | no | 4 | +| idClient | text | ID client provided with the application you created in the RTE portal | yes | | +| idSecret | text | ID secret provided with the application you created in the RTE portal | yes | | + +Take care to select the API version corresponding to the one to which you subscribed in the RTE portal. ## Channels @@ -42,14 +50,14 @@ All channels are read-only. |-------------------|--------|------------------------------------------------------------------| | todaySignal | Number | The signal relating to the forecast consumption level for today. Values are 1 for normal consumption (green), 2 for strained electrical system (orange) and 3 for very strained electrical system (red). | | tomorrowSignal | Number | The signal relating to the forecast consumption level for tomorrow. Values are 1 for normal consumption (green), 2 for strained electrical system (orange) and 3 for very strained electrical system (red). | -| currentHourSignal | Number | The signal relating to the forecast consumption level for the current hour. Values are 1 for normal consumption (green), 2 for strained electrical system (orange) and 3 for very strained electrical system (red). | +| currentHourSignal | Number | The signal relating to the forecast consumption level for the current hour. Values are 0 for normal consumption (green) and carbon-free production, 1 for normal consumption (green), 2 for strained electrical system (orange) and 3 for very strained electrical system (red). | ## Full Example example.things: ```java -Thing ecowatt:signals:signals "Ecowatt Signals" [ idClient="xxxxx", idSecret="yyyyy"] +Thing ecowatt:signals:signals "Ecowatt Signals" [ apiVersion=4, idClient="xxxxx", idSecret="yyyyy"] ``` example.items: diff --git a/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/configuration/EcowattConfiguration.java b/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/configuration/EcowattConfiguration.java index 61e037919dd..f9b8e3bbff8 100644 --- a/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/configuration/EcowattConfiguration.java +++ b/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/configuration/EcowattConfiguration.java @@ -18,10 +18,12 @@ import org.eclipse.jdt.annotation.NonNullByDefault; * The {@link EcowattConfiguration} class contains fields mapping thing configuration parameters. * * @author Laurent Garnier - Initial contribution + * @author Laurent Garnier - New parameter apiVersion */ @NonNullByDefault public class EcowattConfiguration { + public int apiVersion = 4; public String idClient = ""; public String idSecret = ""; } diff --git a/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/handler/EcowattHandler.java b/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/handler/EcowattHandler.java index 365d65c67e2..912e93a9e2b 100644 --- a/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/handler/EcowattHandler.java +++ b/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/handler/EcowattHandler.java @@ -54,6 +54,7 @@ import org.slf4j.LoggerFactory; * The {@link EcowattHandler} is responsible for updating the state of the channels * * @author Laurent Garnier - Initial contribution + * @author Laurent Garnier - Add support for API version 5 */ @NonNullByDefault public class EcowattHandler extends BaseThingHandler { @@ -100,7 +101,8 @@ public class EcowattHandler extends BaseThingHandler { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/offline.config-error-unset-parameters"); } else { - api = new EcowattRestApi(oAuthFactory, httpClient, thing.getUID().getAsString(), idClient, idSecret); + api = new EcowattRestApi(oAuthFactory, httpClient, thing.getUID().getAsString(), idClient, idSecret, + config.apiVersion); updateStatus(ThingStatus.UNKNOWN); scheduleNextUpdate(0, true); } @@ -264,7 +266,7 @@ public class EcowattHandler extends BaseThingHandler { int hour = dateTime.withZoneSameInstant(day.getZone()).getHour(); int value = signals.getHourSignal(hour); LoggerFactory.getLogger(EcowattHandler.class).debug("hour {} value {}", hour, value); - if (value >= 1 && value <= 3) { + if (value >= 0 && value <= 3) { return new DecimalType(value); } } diff --git a/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/restapi/EcowattDaySignals.java b/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/restapi/EcowattDaySignals.java index 10dbf317ca6..e27ed283f7b 100644 --- a/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/restapi/EcowattDaySignals.java +++ b/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/restapi/EcowattDaySignals.java @@ -58,6 +58,6 @@ public class EcowattDaySignals { } } } - return 0; + return -1; } } diff --git a/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/restapi/EcowattRestApi.java b/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/restapi/EcowattRestApi.java index 7da333721b3..37a68fabfd4 100644 --- a/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/restapi/EcowattRestApi.java +++ b/bundles/org.openhab.binding.ecowatt/src/main/java/org/openhab/binding/ecowatt/internal/restapi/EcowattRestApi.java @@ -46,23 +46,25 @@ import com.google.gson.JsonSyntaxException; * The {@link EcowattRestApi} is responsible for handling all communication with the Ecowatt REST API * * @author Laurent Garnier - Initial contribution + * @author Laurent Garnier - Add support for different API versions */ @NonNullByDefault public class EcowattRestApi { private static final String ECOWATT_API_TOKEN_URL = "https://digital.iservices.rte-france.com/token/oauth/"; - private static final String ECOWATT_API_GET_SIGNALS_URL = "https://digital.iservices.rte-france.com/open_api/ecowatt/v4/signals"; + private static final String ECOWATT_API_GET_SIGNALS_URL = "https://digital.iservices.rte-france.com/open_api/ecowatt/v%d/signals"; private final Logger logger = LoggerFactory.getLogger(EcowattRestApi.class); private final OAuthFactory oAuthFactory; private final HttpClient httpClient; private final Gson gson; + private final String apiUrl; private OAuthClientService authService; private String authServiceHandle; public EcowattRestApi(OAuthFactory oAuthFactory, HttpClient httpClient, String authServiceHandle, String idClient, - String idSecret) { + String idSecret, int apiVersion) { this.oAuthFactory = oAuthFactory; this.httpClient = httpClient; GsonBuilder gsonBuilder = new GsonBuilder(); @@ -73,13 +75,14 @@ public class EcowattRestApi { this.authService = oAuthFactory.createOAuthClientService(authServiceHandle, ECOWATT_API_TOKEN_URL, null, idClient, idSecret, null, true); this.authServiceHandle = authServiceHandle; + this.apiUrl = ECOWATT_API_GET_SIGNALS_URL.formatted(apiVersion); } public EcowattApiResponse getSignals() throws CommunicationException, EcowattApiLimitException { - logger.debug("API request signals"); + logger.debug("API request {}", apiUrl); String token = authenticate().getAccessToken(); - final Request request = httpClient.newRequest(ECOWATT_API_GET_SIGNALS_URL).method(HttpMethod.GET) + final Request request = httpClient.newRequest(apiUrl).method(HttpMethod.GET) .header(HttpHeader.AUTHORIZATION, "Bearer " + token).timeout(10, TimeUnit.SECONDS); ContentResponse response; diff --git a/bundles/org.openhab.binding.ecowatt/src/main/resources/OH-INF/i18n/ecowatt.properties b/bundles/org.openhab.binding.ecowatt/src/main/resources/OH-INF/i18n/ecowatt.properties index 690a2860198..832341843ce 100644 --- a/bundles/org.openhab.binding.ecowatt/src/main/resources/OH-INF/i18n/ecowatt.properties +++ b/bundles/org.openhab.binding.ecowatt/src/main/resources/OH-INF/i18n/ecowatt.properties @@ -8,7 +8,7 @@ addon.ecowatt.description = This binding uses the Ecowatt API to expose clear si thing-type.ecowatt.signals.label = Electricity Forecast thing-type.ecowatt.signals.description = The French electricity consumption forecasts thing-type.ecowatt.signals.channel.currentHourSignal.label = Current Hour Signal -thing-type.ecowatt.signals.channel.currentHourSignal.description = The signal relating to the forecast consumption level for the current hour. Values are 1 for normal consumption (green), 2 for strained electrical system (orange) and 3 for very strained electrical system (red). +thing-type.ecowatt.signals.channel.currentHourSignal.description = The signal relating to the forecast consumption level for the current hour. Values are 0 for normal consumption (green) and carbon-free production, 1 for normal consumption (green), 2 for strained electrical system (orange) and 3 for very strained electrical system (red). thing-type.ecowatt.signals.channel.inThreeDaysSignal.label = In Three Days Signal thing-type.ecowatt.signals.channel.inThreeDaysSignal.description = The signal relating to the forecast consumption level in three days. Values are 1 for normal consumption (green), 2 for strained electrical system (orange) and 3 for very strained electrical system (red). thing-type.ecowatt.signals.channel.inTwoDaysSignal.label = In Two Days Signal @@ -20,6 +20,10 @@ thing-type.ecowatt.signals.channel.tomorrowSignal.description = The signal relat # thing types config +thing-type.config.ecowatt.signals.apiVersion.label = API Version +thing-type.config.ecowatt.signals.apiVersion.description = The version of the Ecowatt tile to which you subscribed in the RTE portal. +thing-type.config.ecowatt.signals.apiVersion.option.4 = V4.0 (deprecated) +thing-type.config.ecowatt.signals.apiVersion.option.5 = V5.0 thing-type.config.ecowatt.signals.idClient.label = ID Client thing-type.config.ecowatt.signals.idClient.description = ID client provided with the application you created in the RTE portal. thing-type.config.ecowatt.signals.idSecret.label = ID Secret @@ -28,7 +32,8 @@ thing-type.config.ecowatt.signals.idSecret.description = ID secret provided with # channel types channel-type.ecowatt.signal.label = Consumption Signal -channel-type.ecowatt.signal.description = The signal relating to the forecast consumption level. Values are 1 for normal consumption (green), 2 for strained electrical system (orange) and 3 for very strained electrical system (red). +channel-type.ecowatt.signal.description = The signal relating to the forecast consumption level. Values are 0 for normal consumption (green) and carbon-free production, 1 for normal consumption (green), 2 for strained electrical system (orange) and 3 for very strained electrical system (red). +channel-type.ecowatt.signal.state.option.0 = Green + carbon-free production channel-type.ecowatt.signal.state.option.1 = Green channel-type.ecowatt.signal.state.option.2 = Orange channel-type.ecowatt.signal.state.option.3 = Red diff --git a/bundles/org.openhab.binding.ecowatt/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.ecowatt/src/main/resources/OH-INF/thing/thing-types.xml index b1d7b43504d..1dbd4ac7e61 100644 --- a/bundles/org.openhab.binding.ecowatt/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.ecowatt/src/main/resources/OH-INF/thing/thing-types.xml @@ -34,12 +34,22 @@ - The signal relating to the forecast consumption level for the current hour. Values are 1 for normal - consumption (green), 2 for strained electrical system (orange) and 3 for very strained electrical system (red). + The signal relating to the forecast consumption level for the current hour. Values are 0 for normal + consumption (green) and carbon-free production, 1 for normal consumption (green), 2 for strained electrical system + (orange) and 3 for very strained electrical system (red). + + + The version of the Ecowatt tile to which you subscribed in the RTE portal. + + + + + 4 + ID client provided with the application you created in the RTE portal. @@ -55,10 +65,12 @@ Number - The signal relating to the forecast consumption level. Values are 1 for normal consumption (green), 2 for - strained electrical system (orange) and 3 for very strained electrical system (red). + The signal relating to the forecast consumption level. Values are 0 for normal consumption (green) and + carbon-free production, 1 for normal consumption (green), 2 for strained electrical system (orange) and 3 for very + strained electrical system (red). + diff --git a/bundles/org.openhab.binding.ecowatt/src/test/java/org/openhab/binding/ecowatt/internal/EcowattApiResponseTest.java b/bundles/org.openhab.binding.ecowatt/src/test/java/org/openhab/binding/ecowatt/internal/EcowattApiResponseTest.java index f2dbba608b0..b3b614adad0 100644 --- a/bundles/org.openhab.binding.ecowatt/src/test/java/org/openhab/binding/ecowatt/internal/EcowattApiResponseTest.java +++ b/bundles/org.openhab.binding.ecowatt/src/test/java/org/openhab/binding/ecowatt/internal/EcowattApiResponseTest.java @@ -42,6 +42,7 @@ import com.google.gson.JsonDeserializer; @NonNullByDefault public class EcowattApiResponseTest { + private static final DecimalType STATE_ZERO = new DecimalType(0); private static final DecimalType STATE_ONE = new DecimalType(1); private static final DecimalType STATE_TWO = new DecimalType(2); private static final DecimalType STATE_THREE = new DecimalType(3); @@ -104,6 +105,10 @@ public class EcowattApiResponseTest { State expectedState; for (int h = 0; h < 24; h++) { switch (h) { + case 2: + case 3: + expectedState = STATE_ZERO; + break; case 7: case 11: case 19: @@ -155,6 +160,10 @@ public class EcowattApiResponseTest { case 2: expectedState = UnDefType.UNDEF; break; + case 5: + case 6: + expectedState = STATE_ZERO; + break; case 10: case 14: case 22: diff --git a/bundles/org.openhab.binding.ecowatt/src/test/resources/ApiResponse.json b/bundles/org.openhab.binding.ecowatt/src/test/resources/ApiResponse.json index c5ac41b7434..a7b65bc5fd7 100644 --- a/bundles/org.openhab.binding.ecowatt/src/test/resources/ApiResponse.json +++ b/bundles/org.openhab.binding.ecowatt/src/test/resources/ApiResponse.json @@ -1,4 +1,4 @@ {"signals":[{"GenerationFichier":"2022-09-18T22:00:00+02:00","jour":"2022-09-22T00:00:00+02:00","dvalue":1,"message":"Notre consommation est raisonnable.","values":[{"pas":0,"hvalue":1},{"pas":1,"hvalue":1},{"pas":2,"hvalue":1},{"pas":3,"hvalue":1},{"pas":4,"hvalue":1},{"pas":5,"hvalue":1},{"pas":6,"hvalue":1},{"pas":7,"hvalue":1},{"pas":8,"hvalue":1},{"pas":9,"hvalue":1},{"pas":10,"hvalue":1},{"pas":11,"hvalue":1},{"pas":12,"hvalue":1},{"pas":13,"hvalue":1},{"pas":14,"hvalue":1},{"pas":15,"hvalue":1},{"pas":16,"hvalue":1},{"pas":17,"hvalue":1},{"pas":18,"hvalue":1},{"pas":19,"hvalue":1},{"pas":20,"hvalue":1},{"pas":21,"hvalue":1},{"pas":22,"hvalue":1}]}, {"GenerationFichier":"2022-09-18T22:00:00+02:00","jour":"2022-09-20T00:00:00+02:00","dvalue":2,"message":"Notre consommation est raisonnable.","values":[{"pas":0,"hvalue":1},{"pas":1,"hvalue":1},{"pas":2,"hvalue":1},{"pas":3,"hvalue":1},{"pas":4,"hvalue":1},{"pas":5,"hvalue":1},{"pas":6,"hvalue":1},{"pas":7,"hvalue":1},{"pas":8,"hvalue":1},{"pas":9,"hvalue":1},{"pas":10,"hvalue":1},{"pas":11,"hvalue":1},{"pas":12,"hvalue":1},{"pas":13,"hvalue":1},{"pas":14,"hvalue":1},{"pas":15,"hvalue":1},{"pas":16,"hvalue":1},{"pas":17,"hvalue":1},{"pas":18,"hvalue":1},{"pas":19,"hvalue":1},{"pas":20,"hvalue":2},{"pas":21,"hvalue":1},{"pas":22,"hvalue":1},{"pas":23,"hvalue":1}]}, {"GenerationFichier":"2022-09-18T22:00:00+02:00","jour":"2022-09-21T00:00:00+02:00","dvalue":1,"message":"Notre consommation est raisonnable.","values":[{"pas":0,"hvalue":1},{"pas":1,"hvalue":1},{"pas":2,"hvalue":1},{"pas":3,"hvalue":1},{"pas":4,"hvalue":1},{"pas":5,"hvalue":1},{"pas":6,"hvalue":1},{"pas":7,"hvalue":1},{"pas":8,"hvalue":1},{"pas":9,"hvalue":1},{"pas":10,"hvalue":1},{"pas":11,"hvalue":1},{"pas":12,"hvalue":1},{"pas":13,"hvalue":1},{"pas":14,"hvalue":1},{"pas":15,"hvalue":1},{"pas":16,"hvalue":1},{"pas":17,"hvalue":1},{"pas":18,"hvalue":1},{"pas":19,"hvalue":1},{"pas":20,"hvalue":1},{"pas":21,"hvalue":1},{"pas":22,"hvalue":1},{"pas":23,"hvalue":1}]}, -{"GenerationFichier":"2022-09-18T22:00:00+02:00","jour":"2022-09-19T00:00:00+02:00","dvalue":3,"message":"Notre consommation est raisonnable.","values":[{"pas":0,"hvalue":1},{"pas":1,"hvalue":1},{"pas":2,"hvalue":1},{"pas":3,"hvalue":1},{"pas":4,"hvalue":1},{"pas":5,"hvalue":1},{"pas":6,"hvalue":1},{"pas":7,"hvalue":2},{"pas":8,"hvalue":3},{"pas":9,"hvalue":3},{"pas":10,"hvalue":3},{"pas":11,"hvalue":2},{"pas":12,"hvalue":1},{"pas":13,"hvalue":1},{"pas":14,"hvalue":1},{"pas":15,"hvalue":1},{"pas":16,"hvalue":1},{"pas":17,"hvalue":1},{"pas":18,"hvalue":1},{"pas":19,"hvalue":2},{"pas":20,"hvalue":3},{"pas":21,"hvalue":2},{"pas":22,"hvalue":1},{"pas":23,"hvalue":1}]}]} +{"GenerationFichier":"2022-09-18T22:00:00+02:00","jour":"2022-09-19T00:00:00+02:00","dvalue":3,"message":"Notre consommation est raisonnable.","values":[{"pas":0,"hvalue":1},{"pas":1,"hvalue":1},{"pas":2,"hvalue":0},{"pas":3,"hvalue":0},{"pas":4,"hvalue":1},{"pas":5,"hvalue":1},{"pas":6,"hvalue":1},{"pas":7,"hvalue":2},{"pas":8,"hvalue":3},{"pas":9,"hvalue":3},{"pas":10,"hvalue":3},{"pas":11,"hvalue":2},{"pas":12,"hvalue":1},{"pas":13,"hvalue":1},{"pas":14,"hvalue":1},{"pas":15,"hvalue":1},{"pas":16,"hvalue":1},{"pas":17,"hvalue":1},{"pas":18,"hvalue":1},{"pas":19,"hvalue":2},{"pas":20,"hvalue":3},{"pas":21,"hvalue":2},{"pas":22,"hvalue":1},{"pas":23,"hvalue":1}]}]}