mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[solarforecast] Avoid past data updates (#16996)
Signed-off-by: Bernd Weymann <bernd.weymann@gmail.com>
This commit is contained in:
parent
1793afc871
commit
c108049be8
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user