[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
9 changed files with 62 additions and 21 deletions

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