[tibber] Add time series support for Tibber prices (#16275)

Signed-off-by: Sönke Küper <soenkekueper@gmx.de>
This commit is contained in:
Sönke Küper 2024-01-15 18:46:50 +01:00 committed by GitHub
parent 601ab42207
commit deb423e22c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 35 deletions

View File

@ -19,43 +19,47 @@ The channels (i.e. measurements) associated with the Binding:
Tibber Default: Tibber Default:
| Channel ID | Description | Read-only | | Channel ID | Description | Read-only | Forecast |
|--------------------|---------------------------------------------------------|-----------| |----------------------|---------------------------------------------------------|-----------|----------|
| Current Total | Current Total Price (energy + tax) | True | | current_total | Current Total Price (energy + tax) | True | yes |
| Starts At | Current Price Timestamp | True | | current_startsAt | Current Price Timestamp | True | no |
| Current Level | Current Price Level | True | | current_level | Current Price Level | True | no |
| Daily Cost | Daily Cost (last/previous day) | True | | daily_cost | Daily Cost (last/previous day) | True | no |
| Daily Consumption | Daily Consumption (last/previous day) | True | | daily_consumption | Daily Consumption (last/previous day) | True | no |
| Daily From | Timestamp (daily from) | True | | daily_from | Timestamp (daily from) | True | no |
| Daily To | Timestamp (daily to) | True | | daily_to | Timestamp (daily to) | True | no |
| Hourly Cost | Hourly Cost (last/previous hour) | True | | hourly_cost | Hourly Cost (last/previous hour) | True | no |
| Hourly Consumption | Hourly Consumption (last/previous hour) | True | | hourly_consumption | Hourly Consumption (last/previous hour) | True | no |
| Hourly From | Timestamp (hourly from) | True | | hourly_from | Timestamp (hourly from) | True | no |
| Hourly To | Timestamp (hourly to) | True | | hourly_to | Timestamp (hourly to) | True | no |
| Tomorrow prices | JSON array of tomorrow's prices. See below for example. | True | | tomorrow_prices | JSON array of tomorrow's prices. See below for example. | True | no |
| Today prices | JSON array of today's prices. See below for example. | True | | today_prices | JSON array of today's prices. See below for example. | True | no |
Tibber Pulse (optional): Tibber Pulse (optional):
| Channel ID | Description | Read-only | | Channel ID | Description | Read-only |
|-------------------------|------------------------------------------|-----------| |-----------------------------|------------------------------------------|-----------|
| Timestamp | Timestamp for live measurements | True | | live_timestamp | Timestamp for live measurements | True |
| Power | Live Power Consumption | True | | live_power | Live Power Consumption | True |
| Last Meter Consumption | Last Recorded Meter Consumption | True | | live_lastMeterConsumption | Last Recorded Meter Consumption | True |
| Accumulated Consumption | Accumulated Consumption since Midnight | True | | live_accumulatedConsumption | Accumulated Consumption since Midnight | True |
| Accumulated Cost | Accumulated Cost since Midnight | True | | live_accumulatedCost | Accumulated Cost since Midnight | True |
| Accumulated Reward | Accumulated Reward since Midnight | True | | live_accumulatedReward | Accumulated Reward since Midnight | True |
| Currency | Currency of Cost | True | | live_currency | Currency of Cost | True |
| Min Power | Min Power Consumption since Midnight | True | | live_minPower | Min Power Consumption since Midnight | True |
| Average Power | Average Power Consumption since Midnight | True | | live_averagePower | Average Power Consumption since Midnight | True |
| Max Power | Max Power Consumption since Midnight | True | | live_maxPower | Max Power Consumption since Midnight | True |
| Voltage 1-3 | Voltage per Phase | True | | live_voltage1 | Voltage Phase 1 | True |
| Current 1-3 | Current per Phase | True | | live_voltage2 | Voltage Phase 2 | True |
| Power Production | Live Power Production | True | | live_voltage3 | Voltage Phase 3 | True |
| Accumulated Production | Accumulated Production since Midnight | True | | live_current1 | Current Phase 1 | True |
| Last Meter Production | Last Recorded Meter Production | True | | live_current2 | Current Phase 2 | True |
| Min Power Production | Min Power Production since Midnight | True | | live_current3 | Current Phase 3 | True |
| Max Power Production | Max Power Production since Midnight | True | | live_powerProduction | Live Power Production | True |
| live_accumulatedProduction | Accumulated Production since Midnight | True |
| live_lastMeterProduction | Last Recorded Meter Production | True |
| live_minPowerproduction | Min Power Production since Midnight | True |
| live_maxPowerproduction | Max Power Production since Midnight | True |
## Binding Configuration ## Binding Configuration
@ -102,6 +106,7 @@ Tibber API will be auto discovered if provided input is correct.
## Tomorrow and Today Prices ## Tomorrow and Today Prices
The today and tomorrow prices are served as forecast on the `current_total` channel and as JSON data on the channels `today_prices` and `tomorrow_prices`.
Example of tomorrow and today prices data structure - an array of tuples: Example of tomorrow and today prices data structure - an array of tuples:
```json ```json

View File

@ -19,6 +19,9 @@ import java.io.InputStream;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.format.DateTimeParseException;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
@ -52,6 +55,7 @@ import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.binding.BaseThingHandler; import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command; import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType; import org.openhab.core.types.RefreshType;
import org.openhab.core.types.TimeSeries;
import org.osgi.framework.FrameworkUtil; import org.osgi.framework.FrameworkUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -203,7 +207,10 @@ public class TibberHandler extends BaseThingHandler {
.getAsJsonObject("home").getAsJsonObject("currentSubscription").getAsJsonObject("priceInfo") .getAsJsonObject("home").getAsJsonObject("currentSubscription").getAsJsonObject("priceInfo")
.getAsJsonArray("today"); .getAsJsonArray("today");
updateState(TODAY_PRICES, new StringType(today.toString())); updateState(TODAY_PRICES, new StringType(today.toString()));
} catch (JsonSyntaxException e) {
TimeSeries timeSeries = buildTimeSeries(today, tomorrow);
sendTimeSeries(CURRENT_TOTAL, timeSeries);
} catch (JsonSyntaxException | DateTimeParseException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Error communicating with Tibber API: " + e.getMessage()); "Error communicating with Tibber API: " + e.getMessage());
} }
@ -267,6 +274,29 @@ public class TibberHandler extends BaseThingHandler {
} }
} }
/**
* Builds the {@link TimeSeries} that represents the future tibber prices.
*
* @param today The prices for today
* @param tomorrow The prices for tomorrow.
* @return The {@link TimeSeries} with future values.
*/
private TimeSeries buildTimeSeries(JsonArray today, JsonArray tomorrow) {
final TimeSeries timeSeries = new TimeSeries(TimeSeries.Policy.REPLACE);
mapTimeSeriesEntries(today, timeSeries);
mapTimeSeriesEntries(tomorrow, timeSeries);
return timeSeries;
}
private void mapTimeSeriesEntries(JsonArray prices, TimeSeries timeSeries) {
for (JsonElement entry : prices) {
JsonObject entryObject = entry.getAsJsonObject();
final Instant startsAt = ZonedDateTime.parse(entryObject.get("startsAt").getAsString()).toInstant();
final DecimalType value = new DecimalType(entryObject.get("total").getAsString());
timeSeries.add(startsAt, value);
}
}
public void startRefresh(int refresh) { public void startRefresh(int refresh) {
if (pollingJob == null) { if (pollingJob == null) {
pollingJob = scheduler.scheduleWithFixedDelay(() -> { pollingJob = scheduler.scheduleWithFixedDelay(() -> {