[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 <lg.hc@free.fr>
This commit is contained in:
lolodomo 2023-11-26 23:34:45 +01:00 committed by GitHub
parent a4da986330
commit 9b55bfba58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 62 additions and 21 deletions

View File

@ -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:

View File

@ -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 = "";
}

View File

@ -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);
}
}

View File

@ -58,6 +58,6 @@ public class EcowattDaySignals {
}
}
}
return 0;
return -1;
}
}

View File

@ -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;

View File

@ -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

View File

@ -34,12 +34,22 @@
</channel>
<channel id="currentHourSignal" typeId="signal">
<label>Current Hour Signal</label>
<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).</description>
<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).</description>
</channel>
</channels>
<config-description>
<parameter name="apiVersion" type="integer" required="false">
<label>API Version</label>
<description>The version of the Ecowatt tile to which you subscribed in the RTE portal.</description>
<options>
<option value="4">V4.0 (deprecated)</option>
<option value="5">V5.0</option>
</options>
<default>4</default>
</parameter>
<parameter name="idClient" type="text" required="true">
<label>ID Client</label>
<description>ID client provided with the application you created in the RTE portal.</description>
@ -55,10 +65,12 @@
<channel-type id="signal">
<item-type>Number</item-type>
<label>Consumption Signal</label>
<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).</description>
<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).</description>
<state readOnly="true">
<options>
<option value="0">Green + carbon-free production</option>
<option value="1">Green</option>
<option value="2">Orange</option>
<option value="3">Red</option>

View File

@ -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:

View File

@ -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}]}]}