diff --git a/bundles/org.openhab.binding.solarforecast/src/main/java/org/openhab/binding/solarforecast/internal/forecastsolar/ForecastSolarObject.java b/bundles/org.openhab.binding.solarforecast/src/main/java/org/openhab/binding/solarforecast/internal/forecastsolar/ForecastSolarObject.java index de15a50c063..fa0f79cca56 100644 --- a/bundles/org.openhab.binding.solarforecast/src/main/java/org/openhab/binding/solarforecast/internal/forecastsolar/ForecastSolarObject.java +++ b/bundles/org.openhab.binding.solarforecast/src/main/java/org/openhab/binding/solarforecast/internal/forecastsolar/ForecastSolarObject.java @@ -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; } diff --git a/bundles/org.openhab.binding.solarforecast/src/main/java/org/openhab/binding/solarforecast/internal/solcast/SolcastObject.java b/bundles/org.openhab.binding.solarforecast/src/main/java/org/openhab/binding/solarforecast/internal/solcast/SolcastObject.java index 667c0e77ff9..1055e6e6b1a 100644 --- a/bundles/org.openhab.binding.solarforecast/src/main/java/org/openhab/binding/solarforecast/internal/solcast/SolcastObject.java +++ b/bundles/org.openhab.binding.solarforecast/src/main/java/org/openhab/binding/solarforecast/internal/solcast/SolcastObject.java @@ -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 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 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; } diff --git a/bundles/org.openhab.binding.solarforecast/src/test/java/org/openhab/binding/solarforecast/ForecastSolarTest.java b/bundles/org.openhab.binding.solarforecast/src/test/java/org/openhab/binding/solarforecast/ForecastSolarTest.java index e81c7ca1eef..fd491b3f699 100644 --- a/bundles/org.openhab.binding.solarforecast/src/test/java/org/openhab/binding/solarforecast/ForecastSolarTest.java +++ b/bundles/org.openhab.binding.solarforecast/src/test/java/org/openhab/binding/solarforecast/ForecastSolarTest.java @@ -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), diff --git a/bundles/org.openhab.binding.solarforecast/src/test/java/org/openhab/binding/solarforecast/SolcastTest.java b/bundles/org.openhab.binding.solarforecast/src/test/java/org/openhab/binding/solarforecast/SolcastTest.java index a6606d54f37..01763ae3e96 100644 --- a/bundles/org.openhab.binding.solarforecast/src/test/java/org/openhab/binding/solarforecast/SolcastTest.java +++ b/bundles/org.openhab.binding.solarforecast/src/test/java/org/openhab/binding/solarforecast/SolcastTest.java @@ -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> 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> 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> 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> 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> 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> 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 iter1 = ts1.getStates().iterator(); Iterator 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 iter1 = ts1.getStates().iterator(); Iterator 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 iter1 = ts1.getStates().iterator(); while (iter1.hasNext()) { TimeSeries.Entry e1 = iter1.next();