]> git.basschouten.com Git - openhab-addons.git/commitdiff
[solarforecast] Avoid past data updates (#16996)
authorBernd Weymann <bernd.weymann@gmail.com>
Thu, 22 Aug 2024 20:54:30 +0000 (22:54 +0200)
committerGitHub <noreply@github.com>
Thu, 22 Aug 2024 20:54:30 +0000 (22:54 +0200)
Signed-off-by: Bernd Weymann <bernd.weymann@gmail.com>
bundles/org.openhab.binding.solarforecast/src/main/java/org/openhab/binding/solarforecast/internal/forecastsolar/ForecastSolarObject.java
bundles/org.openhab.binding.solarforecast/src/main/java/org/openhab/binding/solarforecast/internal/solcast/SolcastObject.java
bundles/org.openhab.binding.solarforecast/src/test/java/org/openhab/binding/solarforecast/ForecastSolarTest.java
bundles/org.openhab.binding.solarforecast/src/test/java/org/openhab/binding/solarforecast/SolcastTest.java

index de15a50c063697a9977bfbf1a1129ff3942046dd..fa0f79cca56fea4990c2fc7b6381a4ea3a7f01aa 100644 (file)
@@ -46,6 +46,7 @@ import org.slf4j.LoggerFactory;
  * The {@link ForecastSolarObject} holds complete data for forecast
  *
  * @author Bernd Weymann - Initial contribution
+ * @author Bernd Weymann - TimeSeries delivers only future values, otherwise past values are overwritten
  */
 @NonNullByDefault
 public class ForecastSolarObject implements SolarForecast {
@@ -157,8 +158,12 @@ public class ForecastSolarObject implements SolarForecast {
     @Override
     public TimeSeries getEnergyTimeSeries(QueryMode mode) {
         TimeSeries ts = new TimeSeries(Policy.REPLACE);
+        Instant now = Instant.now(Utils.getClock());
         wattHourMap.forEach((timestamp, energy) -> {
-            ts.add(timestamp.toInstant(), Utils.getEnergyState(energy / 1000.0));
+            Instant entryTimestamp = timestamp.toInstant();
+            if (Utils.isAfterOrEqual(entryTimestamp, now)) {
+                ts.add(entryTimestamp, Utils.getEnergyState(energy / 1000.0));
+            }
         });
         return ts;
     }
@@ -206,8 +211,12 @@ public class ForecastSolarObject implements SolarForecast {
     @Override
     public TimeSeries getPowerTimeSeries(QueryMode mode) {
         TimeSeries ts = new TimeSeries(Policy.REPLACE);
+        Instant now = Instant.now(Utils.getClock());
         wattMap.forEach((timestamp, power) -> {
-            ts.add(timestamp.toInstant(), Utils.getPowerState(power / 1000.0));
+            Instant entryTimestamp = timestamp.toInstant();
+            if (Utils.isAfterOrEqual(entryTimestamp, now)) {
+                ts.add(entryTimestamp, Utils.getPowerState(power / 1000.0));
+            }
         });
         return ts;
     }
index 667c0e77ff958a999548353bc3021e5c51e05386..1055e6e6b1ad7a8ab2039a4556c07624da53c474 100644 (file)
@@ -46,6 +46,7 @@ import org.slf4j.LoggerFactory;
  * The {@link SolcastObject} holds complete data for forecast
  *
  * @author Bernd Weymann - Initial contribution
+ * @author Bernd Weymann - TimeSeries delivers only future values, otherwise past values are overwritten
  */
 @NonNullByDefault
 public class SolcastObject implements SolarForecast {
@@ -214,8 +215,12 @@ public class SolcastObject implements SolarForecast {
     public TimeSeries getEnergyTimeSeries(QueryMode mode) {
         TreeMap<ZonedDateTime, Double> dtm = getDataMap(mode);
         TimeSeries ts = new TimeSeries(Policy.REPLACE);
+        Instant now = Instant.now(Utils.getClock());
         dtm.forEach((timestamp, energy) -> {
-            ts.add(timestamp.toInstant(), Utils.getEnergyState(getActualEnergyValue(timestamp, mode)));
+            Instant entryTimestamp = timestamp.toInstant();
+            if (Utils.isAfterOrEqual(entryTimestamp, now)) {
+                ts.add(entryTimestamp, Utils.getEnergyState(getActualEnergyValue(timestamp, mode)));
+            }
         });
         return ts;
     }
@@ -264,8 +269,12 @@ public class SolcastObject implements SolarForecast {
     public TimeSeries getPowerTimeSeries(QueryMode mode) {
         TreeMap<ZonedDateTime, Double> dtm = getDataMap(mode);
         TimeSeries ts = new TimeSeries(Policy.REPLACE);
+        Instant now = Instant.now(Utils.getClock());
         dtm.forEach((timestamp, power) -> {
-            ts.add(timestamp.toInstant(), Utils.getPowerState(power));
+            Instant entryTimestamp = timestamp.toInstant();
+            if (Utils.isAfterOrEqual(entryTimestamp, now)) {
+                ts.add(entryTimestamp, Utils.getPowerState(power));
+            }
         });
         return ts;
     }
index e81c7ca1eef711bb349c862df3c347c6176a6f12..fd491b3f6999102991f1e3f3f0e69746924eaea3 100644 (file)
@@ -29,6 +29,7 @@ import javax.measure.quantity.Energy;
 import javax.measure.quantity.Power;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.openhab.binding.solarforecast.internal.SolarForecastBindingConstants;
 import org.openhab.binding.solarforecast.internal.SolarForecastException;
@@ -68,6 +69,14 @@ class ForecastSolarTest {
     public static final String NO_GORECAST_INDICATOR = "No forecast data";
     public static final String DAY_MISSING_INDICATOR = "not available in forecast";
 
+    @BeforeAll
+    static void setFixedTime() {
+        // Instant matching the date of test resources
+        String fixedInstant = "2022-07-17T15:00:00Z";
+        Clock fixedClock = Clock.fixed(Instant.parse(fixedInstant), TEST_ZONE);
+        Utils.setClock(fixedClock);
+    }
+
     @Test
     void testForecastObject() {
         String content = FileReader.readFileInString("src/test/resources/forecastsolar/result.json");
@@ -345,16 +354,19 @@ class ForecastSolarTest {
         ForecastSolarObject fo = new ForecastSolarObject("fs-test", content, queryDateTime.toInstant());
 
         TimeSeries powerSeries = fo.getPowerTimeSeries(QueryMode.Average);
-        assertEquals(36, powerSeries.size()); // 18 values each day for 2 days
+        Instant now = Instant.now(Utils.getClock());
+        assertEquals(24, powerSeries.size());
         powerSeries.getStates().forEachOrdered(entry -> {
+            assertTrue(Utils.isAfterOrEqual(entry.timestamp(), now));
             State s = entry.state();
             assertTrue(s instanceof QuantityType<?>);
             assertEquals("kW", ((QuantityType<?>) s).getUnit().toString());
         });
 
         TimeSeries energySeries = fo.getEnergyTimeSeries(QueryMode.Average);
-        assertEquals(36, energySeries.size());
+        assertEquals(24, energySeries.size());
         energySeries.getStates().forEachOrdered(entry -> {
+            assertTrue(Utils.isAfterOrEqual(entry.timestamp(), now));
             State s = entry.state();
             assertTrue(s instanceof QuantityType<?>);
             assertEquals("kWh", ((QuantityType<?>) s).getUnit().toString());
@@ -363,10 +375,6 @@ class ForecastSolarTest {
 
     @Test
     void testPowerTimeSeries() {
-        // Instant matching the date of test resources
-        String fixedInstant = "2022-07-17T15:00:00Z";
-        Clock fixedClock = Clock.fixed(Instant.parse(fixedInstant), TEST_ZONE);
-        Utils.setClock(fixedClock);
         ForecastSolarBridgeHandler fsbh = new ForecastSolarBridgeHandler(
                 new BridgeImpl(SolarForecastBindingConstants.FORECAST_SOLAR_SITE, "bridge"),
                 Optional.of(PointType.valueOf("1,2")));
@@ -398,10 +406,6 @@ class ForecastSolarTest {
 
     @Test
     void testCommonForecastStartEnd() {
-        // Instant matching the date of test resources
-        String fixedInstant = "2022-07-17T15:00:00Z";
-        Clock fixedClock = Clock.fixed(Instant.parse(fixedInstant), TEST_ZONE);
-        Utils.setClock(fixedClock);
         ForecastSolarBridgeHandler fsbh = new ForecastSolarBridgeHandler(
                 new BridgeImpl(SolarForecastBindingConstants.FORECAST_SOLAR_SITE, "bridge"),
                 Optional.of(PointType.valueOf("1,2")));
@@ -447,10 +451,6 @@ class ForecastSolarTest {
 
     @Test
     void testActions() {
-        // Instant matching the date of test resources
-        String fixedInstant = "2022-07-17T15:00:00Z";
-        Clock fixedClock = Clock.fixed(Instant.parse(fixedInstant), TEST_ZONE);
-        Utils.setClock(fixedClock);
         ForecastSolarBridgeHandler fsbh = new ForecastSolarBridgeHandler(
                 new BridgeImpl(SolarForecastBindingConstants.FORECAST_SOLAR_SITE, "bridge"),
                 Optional.of(PointType.valueOf("1,2")));
@@ -486,10 +486,6 @@ class ForecastSolarTest {
 
     @Test
     void testEnergyTimeSeries() {
-        // Instant matching the date of test resources
-        String fixedInstant = "2022-07-17T15:00:00Z";
-        Clock fixedClock = Clock.fixed(Instant.parse(fixedInstant), TEST_ZONE);
-        Utils.setClock(fixedClock);
         ForecastSolarBridgeHandler fsbh = new ForecastSolarBridgeHandler(
                 new BridgeImpl(SolarForecastBindingConstants.FORECAST_SOLAR_SITE, "bridge"),
                 Optional.of(PointType.valueOf("1,2")));
@@ -521,10 +517,6 @@ class ForecastSolarTest {
 
     @Test
     void testCalmDown() {
-        // Instant matching the date of test resources
-        String fixedInstant = "2022-07-17T15:00:00Z";
-        Clock fixedClock = Clock.fixed(Instant.parse(fixedInstant), TEST_ZONE);
-        Utils.setClock(fixedClock);
         ForecastSolarBridgeHandler fsbh = new ForecastSolarBridgeHandler(
                 new BridgeImpl(SolarForecastBindingConstants.FORECAST_SOLAR_SITE, "bridge"),
                 Optional.of(PointType.valueOf("1,2")));
@@ -555,8 +547,8 @@ class ForecastSolarTest {
         assertEquals(ThingStatusDetail.COMMUNICATION_ERROR, cm.getStatus().getStatusDetail(), "Offline");
 
         // forward Clock to get ONLINE again
-        fixedInstant = "2022-07-17T16:15:00Z";
-        fixedClock = Clock.fixed(Instant.parse(fixedInstant), ZoneId.of("UTC"));
+        String fixedInstant = "2022-07-17T16:15:00Z";
+        Clock fixedClock = Clock.fixed(Instant.parse(fixedInstant), ZoneId.of("UTC"));
         Utils.setClock(fixedClock);
         fsbh.handleCommand(
                 new ChannelUID("solarforecast:fs-site:bridge:" + SolarForecastBindingConstants.CHANNEL_ENERGY_ACTUAL),
index a6606d54f37da84d89a1efce6405883d13f5ba1f..01763ae3e967b7e13714cc00662ce8befde4e4c8 100644 (file)
@@ -14,6 +14,7 @@ package org.openhab.binding.solarforecast;
 
 import static org.junit.jupiter.api.Assertions.*;
 
+import java.time.Clock;
 import java.time.Instant;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
@@ -28,6 +29,7 @@ import javax.measure.quantity.Energy;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.json.JSONObject;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.openhab.binding.solarforecast.internal.SolarForecastBindingConstants;
 import org.openhab.binding.solarforecast.internal.SolarForecastException;
@@ -38,6 +40,7 @@ import org.openhab.binding.solarforecast.internal.solcast.SolcastObject.QueryMod
 import org.openhab.binding.solarforecast.internal.solcast.handler.SolcastBridgeHandler;
 import org.openhab.binding.solarforecast.internal.solcast.handler.SolcastPlaneHandler;
 import org.openhab.binding.solarforecast.internal.solcast.handler.SolcastPlaneMock;
+import org.openhab.binding.solarforecast.internal.utils.Utils;
 import org.openhab.core.library.types.QuantityType;
 import org.openhab.core.library.unit.Units;
 import org.openhab.core.thing.internal.BridgeImpl;
@@ -59,6 +62,21 @@ class SolcastTest {
     public static final String TOO_LATE_INDICATOR = "too late";
     public static final String DAY_MISSING_INDICATOR = "not available in forecast";
 
+    @BeforeAll
+    static void setFixedTimeJul17() {
+        // Instant matching the date of test resources
+        Instant fixedInstant = Instant.parse("2022-07-17T21:00:00Z");
+        Clock fixedClock = Clock.fixed(fixedInstant, TEST_ZONE);
+        Utils.setClock(fixedClock);
+    }
+
+    static void setFixedTimeJul18() {
+        // Instant matching the date of test resources
+        Instant fixedInstant = Instant.parse("2022-07-18T14:23:00Z");
+        Clock fixedClock = Clock.fixed(fixedInstant, TEST_ZONE);
+        Utils.setClock(fixedClock);
+    }
+
     /**
      * "2022-07-18T00:00+02:00[Europe/Berlin]": 0,
      * "2022-07-18T00:30+02:00[Europe/Berlin]": 0,
@@ -497,16 +515,18 @@ class SolcastTest {
 
     @Test
     void testPowerTimeSeries() {
+        setFixedTimeJul18();
+        Instant now = Instant.now(Utils.getClock());
         String content = FileReader.readFileInString("src/test/resources/solcast/estimated-actuals.json");
-        ZonedDateTime now = LocalDateTime.of(2022, 7, 18, 16, 23).atZone(TEST_ZONE);
-        SolcastObject sco = new SolcastObject("sc-test", content, now.toInstant(), TIMEZONEPROVIDER);
+        SolcastObject sco = new SolcastObject("sc-test", content, now, TIMEZONEPROVIDER);
         content = FileReader.readFileInString("src/test/resources/solcast/forecasts.json");
         sco.join(content);
 
         TimeSeries powerSeries = sco.getPowerTimeSeries(QueryMode.Average);
         List<QuantityType<?>> estimateL = new ArrayList<>();
-        assertEquals(672, powerSeries.size());
+        assertEquals(302, powerSeries.size());
         powerSeries.getStates().forEachOrdered(entry -> {
+            assertTrue(entry.timestamp().isAfter(Instant.now(Utils.getClock())));
             State s = entry.state();
             assertTrue(s instanceof QuantityType<?>);
             assertEquals("kW", ((QuantityType<?>) s).getUnit().toString());
@@ -519,8 +539,9 @@ class SolcastTest {
 
         TimeSeries powerSeries10 = sco.getPowerTimeSeries(QueryMode.Pessimistic);
         List<QuantityType<?>> estimate10 = new ArrayList<>();
-        assertEquals(672, powerSeries10.size());
+        assertEquals(302, powerSeries10.size());
         powerSeries10.getStates().forEachOrdered(entry -> {
+            assertTrue(entry.timestamp().isAfter(Instant.now(Utils.getClock())));
             State s = entry.state();
             assertTrue(s instanceof QuantityType<?>);
             assertEquals("kW", ((QuantityType<?>) s).getUnit().toString());
@@ -533,8 +554,9 @@ class SolcastTest {
 
         TimeSeries powerSeries90 = sco.getPowerTimeSeries(QueryMode.Optimistic);
         List<QuantityType<?>> estimate90 = new ArrayList<>();
-        assertEquals(672, powerSeries90.size());
+        assertEquals(302, powerSeries90.size());
         powerSeries90.getStates().forEachOrdered(entry -> {
+            assertTrue(entry.timestamp().isAfter(Instant.now(Utils.getClock())));
             State s = entry.state();
             assertTrue(s instanceof QuantityType<?>);
             assertEquals("kW", ((QuantityType<?>) s).getUnit().toString());
@@ -555,16 +577,18 @@ class SolcastTest {
 
     @Test
     void testEnergyTimeSeries() {
+        setFixedTimeJul18();
+        Instant now = Instant.now(Utils.getClock());
         String content = FileReader.readFileInString("src/test/resources/solcast/estimated-actuals.json");
-        ZonedDateTime now = LocalDateTime.of(2022, 7, 18, 16, 23).atZone(TEST_ZONE);
-        SolcastObject sco = new SolcastObject("sc-test", content, now.toInstant(), TIMEZONEPROVIDER);
+        SolcastObject sco = new SolcastObject("sc-test", content, now, TIMEZONEPROVIDER);
         content = FileReader.readFileInString("src/test/resources/solcast/forecasts.json");
         sco.join(content);
 
         TimeSeries energySeries = sco.getEnergyTimeSeries(QueryMode.Average);
         List<QuantityType<?>> estimateL = new ArrayList<>();
-        assertEquals(672, energySeries.size()); // 18 values each day for 2 days
+        assertEquals(302, energySeries.size()); // 48 values each day for next 7 days
         energySeries.getStates().forEachOrdered(entry -> {
+            assertTrue(Utils.isAfterOrEqual(entry.timestamp(), now));
             State s = entry.state();
             assertTrue(s instanceof QuantityType<?>);
             assertEquals("kWh", ((QuantityType<?>) s).getUnit().toString());
@@ -577,8 +601,9 @@ class SolcastTest {
 
         TimeSeries energySeries10 = sco.getEnergyTimeSeries(QueryMode.Pessimistic);
         List<QuantityType<?>> estimate10 = new ArrayList<>();
-        assertEquals(672, energySeries10.size()); // 18 values each day for 2 days
+        assertEquals(302, energySeries10.size()); // 48 values each day for next 7 days
         energySeries10.getStates().forEachOrdered(entry -> {
+            assertTrue(Utils.isAfterOrEqual(entry.timestamp(), now));
             State s = entry.state();
             assertTrue(s instanceof QuantityType<?>);
             assertEquals("kWh", ((QuantityType<?>) s).getUnit().toString());
@@ -591,8 +616,9 @@ class SolcastTest {
 
         TimeSeries energySeries90 = sco.getEnergyTimeSeries(QueryMode.Optimistic);
         List<QuantityType<?>> estimate90 = new ArrayList<>();
-        assertEquals(672, energySeries90.size()); // 18 values each day for 2 days
+        assertEquals(302, energySeries90.size()); // 48 values each day for next 7 days
         energySeries90.getStates().forEachOrdered(entry -> {
+            assertTrue(Utils.isAfterOrEqual(entry.timestamp(), now));
             State s = entry.state();
             assertTrue(s instanceof QuantityType<?>);
             assertEquals("kWh", ((QuantityType<?>) s).getUnit().toString());
@@ -613,6 +639,7 @@ class SolcastTest {
 
     @Test
     void testCombinedPowerTimeSeries() {
+        setFixedTimeJul18();
         BridgeImpl bi = new BridgeImpl(SolarForecastBindingConstants.SOLCAST_SITE, "bridge");
         SolcastBridgeHandler scbh = new SolcastBridgeHandler(bi, new TimeZP());
         bi.setHandler(scbh);
@@ -632,8 +659,8 @@ class SolcastTest {
 
         TimeSeries ts1 = cm.getTimeSeries("solarforecast:sc-site:bridge:average#power-estimate");
         TimeSeries ts2 = cm2.getTimeSeries("solarforecast:sc-plane:thing:average#power-estimate");
-        assertEquals(336, ts1.size(), "TimeSeries size");
-        assertEquals(336, ts2.size(), "TimeSeries size");
+        assertEquals(302, ts1.size(), "TimeSeries size");
+        assertEquals(302, ts2.size(), "TimeSeries size");
         Iterator<TimeSeries.Entry> iter1 = ts1.getStates().iterator();
         Iterator<TimeSeries.Entry> iter2 = ts2.getStates().iterator();
         while (iter1.hasNext()) {
@@ -651,6 +678,7 @@ class SolcastTest {
 
     @Test
     void testCombinedEnergyTimeSeries() {
+        setFixedTimeJul18();
         BridgeImpl bi = new BridgeImpl(SolarForecastBindingConstants.SOLCAST_SITE, "bridge");
         SolcastBridgeHandler scbh = new SolcastBridgeHandler(bi, new TimeZP());
         bi.setHandler(scbh);
@@ -672,8 +700,8 @@ class SolcastTest {
 
         TimeSeries ts1 = cm.getTimeSeries("solarforecast:sc-site:bridge:average#energy-estimate");
         TimeSeries ts2 = cm2.getTimeSeries("solarforecast:sc-plane:thing:average#energy-estimate");
-        assertEquals(336, ts1.size(), "TimeSeries size");
-        assertEquals(336, ts2.size(), "TimeSeries size");
+        assertEquals(302, ts1.size(), "TimeSeries size");
+        assertEquals(302, ts2.size(), "TimeSeries size");
 
         Iterator<TimeSeries.Entry> iter1 = ts1.getStates().iterator();
         Iterator<TimeSeries.Entry> iter2 = ts2.getStates().iterator();
@@ -692,6 +720,7 @@ class SolcastTest {
 
     @Test
     void testSingleEnergyTimeSeries() {
+        setFixedTimeJul18();
         BridgeImpl bi = new BridgeImpl(SolarForecastBindingConstants.SOLCAST_SITE, "bridge");
         SolcastBridgeHandler scbh = new SolcastBridgeHandler(bi, new TimeZP());
         bi.setHandler(scbh);
@@ -707,7 +736,7 @@ class SolcastTest {
         scbh.getData();
 
         TimeSeries ts1 = cm.getTimeSeries("solarforecast:sc-site:bridge:average#energy-estimate");
-        assertEquals(336, ts1.size(), "TimeSeries size");
+        assertEquals(302, ts1.size(), "TimeSeries size");
         Iterator<TimeSeries.Entry> iter1 = ts1.getStates().iterator();
         while (iter1.hasNext()) {
             TimeSeries.Entry e1 = iter1.next();