import static org.eclipse.jetty.http.HttpMethod.GET;
import static org.eclipse.jetty.http.HttpStatus.OK_200;
-import static org.openhab.binding.awattar.internal.AwattarBindingConstants.BINDING_ID;
+import static org.openhab.binding.awattar.internal.AwattarBindingConstants.*;
import java.time.Instant;
import java.time.LocalDate;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.function.Function;
+
+import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.awattar.internal.dto.AwattarApiData;
import org.openhab.binding.awattar.internal.dto.Datum;
import org.openhab.core.i18n.TimeZoneProvider;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.unit.CurrencyUnits;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
+import org.openhab.core.types.TimeSeries;
+import org.openhab.core.types.util.UnitUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
SortedSet<AwattarPrice> result = new TreeSet<>(Comparator.comparing(AwattarPrice::timerange));
AwattarApiData apiData = gson.fromJson(content, AwattarApiData.class);
if (apiData != null) {
+ TimeSeries netMarketSeries = new TimeSeries(TimeSeries.Policy.REPLACE);
+ TimeSeries netTotalSeries = new TimeSeries(TimeSeries.Policy.REPLACE);
+
+ Unit<?> priceUnit = getPriceUnit();
+
for (Datum d : apiData.data) {
- double netPrice = d.marketprice / 10.0;
- TimeRange timerange = new TimeRange(d.startTimestamp, d.endTimestamp);
- result.add(new AwattarPrice(netPrice, netPrice * vatFactor, netPrice + basePrice,
- (netPrice + basePrice) * vatFactor, timerange));
+ double netMarket = d.marketprice / 10.0;
+ double grossMarket = netMarket * vatFactor;
+ double netTotal = netMarket + basePrice;
+ double grossTotal = netTotal * vatFactor;
+ Instant timestamp = Instant.ofEpochMilli(d.startTimestamp);
+
+ netMarketSeries.add(timestamp, new QuantityType<>(netMarket / 100.0, priceUnit));
+ netTotalSeries.add(timestamp, new QuantityType<>(netTotal / 100.0, priceUnit));
+
+ result.add(new AwattarPrice(netMarket, grossMarket, netTotal, grossTotal,
+ new TimeRange(d.startTimestamp, d.endTimestamp)));
}
prices = result;
+
+ // update channels
+ sendTimeSeries(CHANNEL_MARKET_NET, netMarketSeries);
+ sendTimeSeries(CHANNEL_TOTAL_NET, netTotalSeries);
+
updateStatus(ThingStatus.ONLINE);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
}
}
+ private Unit<?> getPriceUnit() {
+ Unit<?> priceUnit = UnitUtils.parseUnit("EUR/kWh");
+ if (priceUnit == null) {
+ priceUnit = CurrencyUnits.BASE_ENERGY_PRICE;
+ logger.info("Using {} instead of EUR/kWh, because it is not available", priceUnit);
+ }
+ return priceUnit;
+ }
+
+ private void createAndSendTimeSeries(String channelId, Function<AwattarPrice, Double> valueFunction) {
+ SortedSet<AwattarPrice> prices = getPrices();
+ Unit<?> priceUnit = getPriceUnit();
+ if (prices == null) {
+ return;
+ }
+ TimeSeries timeSeries = new TimeSeries(TimeSeries.Policy.REPLACE);
+ prices.forEach(p -> {
+ timeSeries.add(Instant.ofEpochMilli(p.timerange().start()),
+ new QuantityType<>(valueFunction.apply(p) / 100.0, priceUnit));
+ });
+ sendTimeSeries(channelId, timeSeries);
+ }
+
/**
* Check if the data needs to be refreshed.
*
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
- refresh();
- } else {
- logger.debug("Binding {} only supports refresh command", BINDING_ID);
+ switch (channelUID.getId()) {
+ case CHANNEL_MARKET_NET -> createAndSendTimeSeries(CHANNEL_MARKET_NET, AwattarPrice::netPrice);
+ case CHANNEL_TOTAL_NET -> createAndSendTimeSeries(CHANNEL_TOTAL_NET, AwattarPrice::netTotal);
+ }
}
}
}
<bridge-type id="bridge">
<label>aWATTar Bridge</label>
<description>Provides price data from the aWATTar API.</description>
+
+ <channels>
+ <channel id="market-net" typeId="uom-price">
+ <label>Net Market Price</label>
+ <description>Price without VAT and network charge</description>
+ </channel>
+ <channel id="market-gross" typeId="uom-price">
+ <label>Gross Market Price</label>
+ <description>Price with VAT but without network charge</description>
+ </channel>
+ <channel id="total-net" typeId="uom-price">
+ <label>Net Total Price</label>
+ <description>Price with network charge but without VAT</description>
+ </channel>
+ <channel id="total-gross" typeId="uom-price">
+ <label>Gross Total Price</label>
+ <description>Price with network charge and VAT</description>
+ </channel>
+ </channels>
+
+ <properties>
+ <property name="thingTypeVersion">1</property>
+ </properties>
+
<config-description-ref uri="bridge-type:awattar:bridge"/>
</bridge-type>
<config-description-ref uri="thing-type:awattar:bestprice"/>
</thing-type>
+ <channel-type id="uom-price">
+ <item-type>Number:EnergyPrice</item-type>
+ <label>Price</label>
+ <state readOnly="true" pattern="%.3f %unit%"/>
+ </channel-type>
+
<channel-type id="price">
<item-type>Number</item-type>
<label>Price</label>