diff --git a/bundles/org.openhab.binding.awattar/README.md b/bundles/org.openhab.binding.awattar/README.md
index ffa74f8528a74..104342a007f10 100644
--- a/bundles/org.openhab.binding.awattar/README.md
+++ b/bundles/org.openhab.binding.awattar/README.md
@@ -26,12 +26,12 @@ Auto discovery is not supported.
### aWATTar Bridge
-| Parameter | Description |
-|-------------|-------------------------------------------------------------------------------------------------------------------------------|
-| vatPercent | Percentage of the value added tax to apply to net prices. Optional, defaults to 19. |
-| basePrice | The net(!) base price you have to pay for every kWh. Optional, but you most probably want to set it based on you delivery contract. |
-| timeZone | The time zone the hour definitions of the things below refer to. Default is `CET`, as it corresponds to the aWATTar API. It is strongly recommended not to change this. However, if you do so, be aware that the prices delivered by the API will not cover a whole calendar day in this timezone. **Advanced** |
-| country | The country prices should be received for. Use `DE` for Germany or `AT` for Austria. `DE` is the default. |
+| Parameter | Description |
+| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| vatPercent | Percentage of the value added tax to apply to net prices. Optional, defaults to 19. |
+| basePrice | The net(!) base price you have to pay for every kWh. Optional, but you most probably want to set it based on you delivery contract. |
+| timeZone | The time zone the hour definitions of the things below refer to. Default is `CET`, as it corresponds to the aWATTar API. It is strongly recommended not to change this. However, if you do so, be aware that the prices delivered by the API will not cover a whole calendar day in this timezone. **Advanced** |
+| country | The country prices should be received for. Use `DE` for Germany or `AT` for Austria. `DE` is the default. |
### Prices Thing
@@ -39,12 +39,13 @@ The prices thing does not need any configuration.
### Bestprice Thing
-| Parameter | Description |
-|-------------|-------------------------------------------------------------------------------------------------------------------------------|
-| rangeStart | First hour of the time range the binding should search for the best prices. Default: `0` |
-| rangeDuration | The duration of the time range the binding should search for best prices. Default: `24` |
-| length | number of best price hours to find within the range. This value has to be at least `1` and below `rangeDuration` Default: `1` |
-| consecutive | if `true`, the thing identifies the cheapest consecutive range of `length` hours within the lookup range. Otherwise, the thing contains the cheapest `length` hours within the lookup range. Default: `true` |
+| Parameter | Description |
+| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| rangeStart | First hour of the time range the binding should search for the best prices. Default: `0` |
+| rangeDuration | The duration of the time range the binding should search for best prices. Default: `24` |
+| length | number of best price hours to find within the range. This value has to be at least `1` and below `rangeDuration` Default: `1` |
+| consecutive | if `true`, the thing identifies the cheapest consecutive range of `length` hours within the lookup range. Otherwise, the thing contains the cheapest `length` hours within the lookup range. Default: `true` |
+| inverted | if `true`, the worst prices will be searched instead of the best. Does currently not work in combination with 'consecutive'. Default: `false` |
#### Limitations
@@ -59,31 +60,31 @@ Also, due to the time the aWATTar API delivers the data for the next day, it doe
For every hour, the `prices` thing provides the following prices:
-| channel | type | description |
-|----------|--------|------------------------------|
-| market-net | Number | This net market price per kWh. This is directly taken from the price the aWATTar API delivers. |
-| market-gross | Number | The market price including VAT, using the defined VAT percentage. |
-| total-net | Number | Sum of net market price and configured base price |
-| total-gross | Number | Sum of market and base price with VAT applied. Most probably this is the final price you will have to pay for one kWh in a certain hour |
+| channel | type | description |
+| ------------ | ------ | --------------------------------------------------------------------------------------------------------------------------------------- |
+| market-net | Number | This net market price per kWh. This is directly taken from the price the aWATTar API delivers. |
+| market-gross | Number | The market price including VAT, using the defined VAT percentage. |
+| total-net | Number | Sum of net market price and configured base price |
+| total-gross | Number | Sum of market and base price with VAT applied. Most probably this is the final price you will have to pay for one kWh in a certain hour |
All prices are available in each of the following channel groups:
-| channel group | description |
-|----------|--------------------------------|
-| current | The prices for the current hour |
-| today00, today01, today02 ... today23 | Hourly prices for today. `today00` provides the price from 0:00 to 1:00, `today01` from 1:00 to 02:00 and so on. As long as the API is working, this data should always be available |
-| tomorrow00, tomorrow01, ... tomorrow23 | Hourly prices for the next day. They should be available starting at 14:00. |
+| channel group | description |
+| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| current | The prices for the current hour |
+| today00, today01, today02 ... today23 | Hourly prices for today. `today00` provides the price from 0:00 to 1:00, `today01` from 1:00 to 02:00 and so on. As long as the API is working, this data should always be available |
+| tomorrow00, tomorrow01, ... tomorrow23 | Hourly prices for the next day. They should be available starting at 14:00. |
### Bestprice Thing
-| channel | type | description |
-|----------|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| active | Switch | `ON` if the current time is within the bestprice period, `OFF` otherwise. If `consecutive` was set to `false`, this channel may change between `ON` and `OFF` multiple times within the bestprice period. |
-| start | DateTime | The exact start time of the bestprice range. If `consecutive` was `false`, it is the start time of the first hour found. |
-| end | DateTime | The exact end time of the bestprice range. If `consecutive` was `false`, it is the end time of the last hour found. |
-| countdown | Number:Time | The time in minutes until start of the bestprice range. If start time passed. the channel will be set to `UNDEFINED` until the values for the next day are available. |
-| remaining | Number:Time | The time in minutes until end of the bestprice range. If start time passed. the channel will be set to `UNDEFINED` until the values for the next day are available. |
-| hours | String | A comma separated list of hours this bestprice period contains. |
+| channel | type | description |
+| --------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| active | Switch | `ON` if the current time is within the bestprice period, `OFF` otherwise. If `consecutive` was set to `false`, this channel may change between `ON` and `OFF` multiple times within the bestprice period. |
+| start | DateTime | The exact start time of the bestprice range. If `consecutive` was `false`, it is the start time of the first hour found. |
+| end | DateTime | The exact end time of the bestprice range. If `consecutive` was `false`, it is the end time of the last hour found. |
+| countdown | Number:Time | The time in minutes until start of the bestprice range. If start time passed. the channel will be set to `UNDEFINED` until the values for the next day are available. |
+| remaining | Number:Time | The time in minutes until end of the bestprice range. If start time passed. the channel will be set to `UNDEFINED` until the values for the next day are available. |
+| hours | String | A comma separated list of hours this bestprice period contains. |
## Full Example
@@ -93,7 +94,7 @@ awattar.things:
```java
Bridge awattar:bridge:bridge1 "aWATTar Bridge" [ country="DE", vatPercent="19", basePrice="17.22"] {
- Thing prices price1 "aWATTar Price" []
+ Thing prices price1 "aWATTar Price" []
// The car should be loaded for 4 hours during the night
Thing bestprice carloader "Car Loader" [ rangeStart="22", rangeDuration="8", length="4", consecutive="true" ]
// In the cheapest hour of the night the garden should be watered
diff --git a/bundles/org.openhab.binding.awattar/src/main/java/org/openhab/binding/awattar/internal/AwattarBestpriceConfiguration.java b/bundles/org.openhab.binding.awattar/src/main/java/org/openhab/binding/awattar/internal/AwattarBestPriceConfiguration.java
similarity index 91%
rename from bundles/org.openhab.binding.awattar/src/main/java/org/openhab/binding/awattar/internal/AwattarBestpriceConfiguration.java
rename to bundles/org.openhab.binding.awattar/src/main/java/org/openhab/binding/awattar/internal/AwattarBestPriceConfiguration.java
index 8ab8d82a353e9..7af03bbb53821 100644
--- a/bundles/org.openhab.binding.awattar/src/main/java/org/openhab/binding/awattar/internal/AwattarBestpriceConfiguration.java
+++ b/bundles/org.openhab.binding.awattar/src/main/java/org/openhab/binding/awattar/internal/AwattarBestPriceConfiguration.java
@@ -20,11 +20,12 @@
* @author Wolfgang Klimt - initial contribution
*/
@NonNullByDefault
-public class AwattarBestpriceConfiguration {
+public class AwattarBestPriceConfiguration {
public int rangeStart = 0;
public int rangeDuration = 24;
public int length = 1;
public boolean consecutive = true;
+ public boolean inverted = false;
@Override
public String toString() {
diff --git a/bundles/org.openhab.binding.awattar/src/main/java/org/openhab/binding/awattar/internal/handler/AwattarBestpriceHandler.java b/bundles/org.openhab.binding.awattar/src/main/java/org/openhab/binding/awattar/internal/handler/AwattarBestPriceHandler.java
similarity index 92%
rename from bundles/org.openhab.binding.awattar/src/main/java/org/openhab/binding/awattar/internal/handler/AwattarBestpriceHandler.java
rename to bundles/org.openhab.binding.awattar/src/main/java/org/openhab/binding/awattar/internal/handler/AwattarBestPriceHandler.java
index 4c92b523411ee..ca0e911942ba7 100644
--- a/bundles/org.openhab.binding.awattar/src/main/java/org/openhab/binding/awattar/internal/handler/AwattarBestpriceHandler.java
+++ b/bundles/org.openhab.binding.awattar/src/main/java/org/openhab/binding/awattar/internal/handler/AwattarBestPriceHandler.java
@@ -28,6 +28,7 @@
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.SortedSet;
@@ -36,8 +37,8 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.awattar.internal.AwattarBestPriceConfiguration;
import org.openhab.binding.awattar.internal.AwattarBestPriceResult;
-import org.openhab.binding.awattar.internal.AwattarBestpriceConfiguration;
import org.openhab.binding.awattar.internal.AwattarConsecutiveBestPriceResult;
import org.openhab.binding.awattar.internal.AwattarNonConsecutiveBestPriceResult;
import org.openhab.binding.awattar.internal.AwattarPrice;
@@ -60,28 +61,28 @@
import org.slf4j.LoggerFactory;
/**
- * The {@link AwattarBestpriceHandler} is responsible for computing the best prices for a given configuration.
+ * The {@link AwattarBestPriceHandler} is responsible for computing the best prices for a given configuration.
*
* @author Wolfgang Klimt - Initial contribution
*/
@NonNullByDefault
-public class AwattarBestpriceHandler extends BaseThingHandler {
+public class AwattarBestPriceHandler extends BaseThingHandler {
private static final int THING_REFRESH_INTERVAL = 60;
- private final Logger logger = LoggerFactory.getLogger(AwattarBestpriceHandler.class);
+ private final Logger logger = LoggerFactory.getLogger(AwattarBestPriceHandler.class);
private @Nullable ScheduledFuture> thingRefresher;
private final TimeZoneProvider timeZoneProvider;
- public AwattarBestpriceHandler(Thing thing, TimeZoneProvider timeZoneProvider) {
+ public AwattarBestPriceHandler(Thing thing, TimeZoneProvider timeZoneProvider) {
super(thing);
this.timeZoneProvider = timeZoneProvider;
}
@Override
public void initialize() {
- AwattarBestpriceConfiguration config = getConfigAs(AwattarBestpriceConfiguration.class);
+ AwattarBestPriceConfiguration config = getConfigAs(AwattarBestPriceConfiguration.class);
if (config.length >= config.rangeDuration) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/error.length.value");
@@ -137,7 +138,7 @@ public void refreshChannel(ChannelUID channelUID) {
updateState(channelUID, state);
return;
}
- AwattarBestpriceConfiguration config = getConfigAs(AwattarBestpriceConfiguration.class);
+ AwattarBestPriceConfiguration config = getConfigAs(AwattarBestPriceConfiguration.class);
TimeRange timerange = getRange(config.rangeStart, config.rangeDuration, bridgeHandler.getTimeZone());
if (!(bridgeHandler.containsPriceFor(timerange.start()) && bridgeHandler.containsPriceFor(timerange.end()))) {
updateState(channelUID, state);
@@ -162,15 +163,20 @@ public void refreshChannel(ChannelUID channelUID) {
result = res;
} else {
range.sort(Comparator.naturalOrder());
+
+ // sort in descending order when inverted
+ if (config.inverted) {
+ Collections.reverse(range);
+ }
+
AwattarNonConsecutiveBestPriceResult res = new AwattarNonConsecutiveBestPriceResult(
bridgeHandler.getTimeZone());
- int ct = 0;
- for (AwattarPrice price : range) {
- res.addMember(price);
- if (++ct >= config.length) {
- break;
- }
+
+ // take up to config.length prices
+ for (int i = 0; i < Math.min(config.length, range.size()); i++) {
+ res.addMember(range.get(i));
}
+
result = res;
}
String channelId = channelUID.getIdWithoutGroup();
diff --git a/bundles/org.openhab.binding.awattar/src/main/java/org/openhab/binding/awattar/internal/handler/AwattarHandlerFactory.java b/bundles/org.openhab.binding.awattar/src/main/java/org/openhab/binding/awattar/internal/handler/AwattarHandlerFactory.java
index c232edfcc72ff..50ca43afc91d2 100644
--- a/bundles/org.openhab.binding.awattar/src/main/java/org/openhab/binding/awattar/internal/handler/AwattarHandlerFactory.java
+++ b/bundles/org.openhab.binding.awattar/src/main/java/org/openhab/binding/awattar/internal/handler/AwattarHandlerFactory.java
@@ -36,7 +36,8 @@
import org.slf4j.LoggerFactory;
/**
- * The {@link AwattarHandlerFactory} is responsible for creating things and thing
+ * The {@link AwattarHandlerFactory} is responsible for creating things and
+ * thing
* handlers.
*
* @author Wolfgang Klimt - Initial contribution
@@ -72,7 +73,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
} else if (THING_TYPE_PRICE.equals(thingTypeUID)) {
return new AwattarPriceHandler(thing, timeZoneProvider);
} else if (THING_TYPE_BESTPRICE.equals(thingTypeUID)) {
- return new AwattarBestpriceHandler(thing, timeZoneProvider);
+ return new AwattarBestPriceHandler(thing, timeZoneProvider);
}
logger.warn("Unknown thing type {}, not creating handler!", thingTypeUID);
diff --git a/bundles/org.openhab.binding.awattar/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.binding.awattar/src/main/resources/OH-INF/config/config.xml
index 619864cc07008..10445470f9285 100644
--- a/bundles/org.openhab.binding.awattar/src/main/resources/OH-INF/config/config.xml
+++ b/bundles/org.openhab.binding.awattar/src/main/resources/OH-INF/config/config.xml
@@ -47,6 +47,11 @@
Do the hours need to be consecutive?true
+
+
+ Should the highest prices be returned?
+ false
+
diff --git a/bundles/org.openhab.binding.awattar/src/main/resources/OH-INF/i18n/awattar.properties b/bundles/org.openhab.binding.awattar/src/main/resources/OH-INF/i18n/awattar.properties
index 3fc96bad710c5..6df6886f3af94 100644
--- a/bundles/org.openhab.binding.awattar/src/main/resources/OH-INF/i18n/awattar.properties
+++ b/bundles/org.openhab.binding.awattar/src/main/resources/OH-INF/i18n/awattar.properties
@@ -28,6 +28,8 @@ thing-type.config.awattar.bestprice.length.label = Length
thing-type.config.awattar.bestprice.length.description = The number of hours the bestprice period should last
thing-type.config.awattar.bestprice.consecutive.label = Consecutive
thing-type.config.awattar.bestprice.consecutive.description = Do the hours need to be consecutive?
+thing-type.config.awattar.bestprice.inverted.label = Inverted
+thing-type.config.awattar.bestprice.inverted.description = Invert the search for the highest price
# channel types
channel-type.awattar.price.label = ct/kWh
diff --git a/bundles/org.openhab.binding.awattar/src/main/resources/OH-INF/i18n/awattar_de.properties b/bundles/org.openhab.binding.awattar/src/main/resources/OH-INF/i18n/awattar_de.properties
index 2888dab20781e..24e6563806ae4 100644
--- a/bundles/org.openhab.binding.awattar/src/main/resources/OH-INF/i18n/awattar_de.properties
+++ b/bundles/org.openhab.binding.awattar/src/main/resources/OH-INF/i18n/awattar_de.properties
@@ -28,6 +28,8 @@ thing-type.config.awattar.bestprice.length.label = Länge
thing-type.config.awattar.bestprice.length.description = Die Anzahl der zu findenden günstigen Stunden
thing-type.config.awattar.bestprice.consecutive.label = Durchgehend
thing-type.config.awattar.bestprice.consecutive.description = Wird ein einzelner durchgehender Zeitraum gesucht?
+thing-type.config.awattar.bestprice.inverted.label = Invertiert
+thing-type.config.awattar.bestprice.inverted.description = Wird nach den teuersten Stunden gesucht?
# channel types
channel-type.awattar.price.label = ct/kWh
diff --git a/bundles/org.openhab.binding.awattar/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.awattar/src/main/resources/OH-INF/thing/thing-types.xml
index 4b659c087b22e..837435424b7f6 100644
--- a/bundles/org.openhab.binding.awattar/src/main/resources/OH-INF/thing/thing-types.xml
+++ b/bundles/org.openhab.binding.awattar/src/main/resources/OH-INF/thing/thing-types.xml
@@ -278,6 +278,13 @@
+
+ Switch
+
+ Return highest prices?
+
+
+
Switch
diff --git a/bundles/org.openhab.binding.awattar/src/test/java/org/openhab/binding/awattar/internal/handler/AwattarBridgeHandlerTest.java b/bundles/org.openhab.binding.awattar/src/test/java/org/openhab/binding/awattar/internal/handler/AwattarBridgeHandlerTest.java
index a0e8d079c0897..b4d5ace5b8004 100644
--- a/bundles/org.openhab.binding.awattar/src/test/java/org/openhab/binding/awattar/internal/handler/AwattarBridgeHandlerTest.java
+++ b/bundles/org.openhab.binding.awattar/src/test/java/org/openhab/binding/awattar/internal/handler/AwattarBridgeHandlerTest.java
@@ -177,7 +177,7 @@ public void testBestpriceHandler(int length, boolean consecutive, String channel
Map config = Map.of("length", length, "consecutive", consecutive);
when(bestpriceMock.getConfiguration()).thenReturn(new Configuration(config));
- AwattarBestpriceHandler handler = new AwattarBestpriceHandler(bestpriceMock, timeZoneProviderMock) {
+ AwattarBestPriceHandler handler = new AwattarBestPriceHandler(bestpriceMock, timeZoneProviderMock) {
@Override
protected TimeRange getRange(int start, int duration, ZoneId zoneId) {
return new TimeRange(1718402400000L, 1718488800000L);