Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 12 commits into from
Jan 15, 2024
73 changes: 39 additions & 34 deletions bundles/org.openhab.binding.tibber/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,43 +19,47 @@ The channels (i.e. measurements) associated with the Binding:

Tibber Default:

| Channel ID | Description | Read-only |
|--------------------|---------------------------------------------------------|-----------|
| Current Total | Current Total Price (energy + tax) | True |
| Starts At | Current Price Timestamp | True |
| Current Level | Current Price Level | True |
| Daily Cost | Daily Cost (last/previous day) | True |
| Daily Consumption | Daily Consumption (last/previous day) | True |
| Daily From | Timestamp (daily from) | True |
| Daily To | Timestamp (daily to) | True |
| Hourly Cost | Hourly Cost (last/previous hour) | True |
| Hourly Consumption | Hourly Consumption (last/previous hour) | True |
| Hourly From | Timestamp (hourly from) | True |
| Hourly To | Timestamp (hourly to) | True |
| Tomorrow prices | JSON array of tomorrow's prices. See below for example. | True |
| Today prices | JSON array of today's prices. See below for example. | True |
| Channel ID | Description | Read-only | Forecast |
|----------------------|---------------------------------------------------------|-----------|----------|
| current_total | Current Total Price (energy + tax) | True | yes |
| current_startsAt | Current Price Timestamp | True | no |
| current_level | Current Price Level | True | no |
| daily_cost | Daily Cost (last/previous day) | True | no |
| daily_consumption | Daily Consumption (last/previous day) | True | no |
| daily_from | Timestamp (daily from) | True | no |
| daily_to | Timestamp (daily to) | True | no |
| hourly_cost | Hourly Cost (last/previous hour) | True | no |
| hourly_consumption | Hourly Consumption (last/previous hour) | True | no |
| hourly_from | Timestamp (hourly from) | True | no |
| hourly_to | Timestamp (hourly to) | True | no |
| 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 | no |

Tibber Pulse (optional):

| Channel ID | Description | Read-only |
|-------------------------|------------------------------------------|-----------|
| Timestamp | Timestamp for live measurements | True |
| Power | Live Power Consumption | True |
| Last Meter Consumption | Last Recorded Meter Consumption | True |
| Accumulated Consumption | Accumulated Consumption since Midnight | True |
| Accumulated Cost | Accumulated Cost since Midnight | True |
| Accumulated Reward | Accumulated Reward since Midnight | True |
| Currency | Currency of Cost | True |
| Min Power | Min Power Consumption since Midnight | True |
| Average Power | Average Power Consumption since Midnight | True |
| Max Power | Max Power Consumption since Midnight | True |
| Voltage 1-3 | Voltage per Phase | True |
| Current 1-3 | Current per Phase | True |
| Power Production | Live Power Production | True |
| Accumulated Production | Accumulated Production since Midnight | True |
| Last Meter Production | Last Recorded Meter Production | True |
| Min Power Production | Min Power Production since Midnight | True |
| Max Power Production | Max Power Production since Midnight | True |
| Channel ID | Description | Read-only |
|-----------------------------|------------------------------------------|-----------|
| live_timestamp | Timestamp for live measurements | True |
| live_power | Live Power Consumption | True |
| live_lastMeterConsumption | Last Recorded Meter Consumption | True |
| live_accumulatedConsumption | Accumulated Consumption since Midnight | True |
| live_accumulatedCost | Accumulated Cost since Midnight | True |
| live_accumulatedReward | Accumulated Reward since Midnight | True |
| live_currency | Currency of Cost | True |
| live_minPower | Min Power Consumption since Midnight | True |
| live_averagePower | Average Power Consumption since Midnight | True |
| live_maxPower | Max Power Consumption since Midnight | True |
| live_voltage1 | Voltage Phase 1 | True |
| live_voltage2 | Voltage Phase 2 | True |
| live_voltage3 | Voltage Phase 3 | True |
| live_current1 | Current Phase 1 | True |
| live_current2 | Current Phase 2 | True |
| live_current3 | Current Phase 3 | 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

Expand Down Expand Up @@ -102,6 +106,7 @@ Tibber API will be auto discovered if provided input is correct.

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

```json
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
import java.math.BigDecimal;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.format.DateTimeParseException;
import java.util.Properties;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledFuture;
Expand Down Expand Up @@ -52,6 +55,7 @@
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.TimeSeries;
import org.osgi.framework.FrameworkUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -203,7 +207,10 @@ public void getURLInput(String url) throws IOException {
.getAsJsonObject("home").getAsJsonObject("currentSubscription").getAsJsonObject("priceInfo")
.getAsJsonArray("today");
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,
"Error communicating with Tibber API: " + e.getMessage());
}
Expand Down Expand Up @@ -267,6 +274,29 @@ public void getURLInput(String url) throws IOException {
}
}

/**
* 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) {
if (pollingJob == null) {
pollingJob = scheduler.scheduleWithFixedDelay(() -> {
Expand Down