From 00971df97ec34f96e49ed01901a3eba9a892edaf Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Fri, 22 Nov 2024 10:14:22 +0100 Subject: [PATCH 01/13] riemann sums Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 819 ++++++++++++++++-- .../extensions/PersistenceExtensionsTest.java | 209 ++++- .../extensions/TestPersistenceService.java | 149 +++- 3 files changed, 1113 insertions(+), 64 deletions(-) diff --git a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java index cb3d1f8cad0..44d0457714d 100644 --- a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java +++ b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java @@ -34,6 +34,7 @@ import org.openhab.core.library.items.NumberItem; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.unit.Units; import org.openhab.core.persistence.FilterCriteria; import org.openhab.core.persistence.FilterCriteria.Ordering; import org.openhab.core.persistence.HistoricItem; @@ -66,6 +67,7 @@ * @author Mark Herwege - lastChange and nextChange methods * @author Mark Herwege - handle persisted GroupItem with QuantityType * @author Mark Herwege - add median methods + * @author Mark Herwege - add Riemann sum methods */ @Component(immediate = true) @NonNullByDefault @@ -74,6 +76,13 @@ public class PersistenceExtensions { private static @Nullable PersistenceServiceRegistry registry; private static @Nullable TimeZoneProvider timeZoneProvider; + public static enum RiemannType { + left, + midpoint, + right, + trapezoidal + } + @Activate public PersistenceExtensions(@Reference PersistenceServiceRegistry registry, @Reference TimeZoneProvider timeZoneProvider) { @@ -1136,6 +1145,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable /** * Gets the variance of the state of the given {@link Item} since a certain point in time. + * A left approximation type is used for the Riemann sum. * The default {@link PersistenceService} is used. * * @param item the {@link Item} to get the variance for @@ -1145,11 +1155,27 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * if there is no persisted state for the given item at the given timestamp */ public static @Nullable State varianceSince(Item item, ZonedDateTime timestamp) { - return internalVarianceBetween(item, timestamp, null, null); + return internalVarianceBetween(item, timestamp, null, RiemannType.left, null); + } + + /** + * Gets the variance of the state of the given {@link Item} since a certain point in time. + * The default {@link PersistenceService} is used. + * + * @param item the {@link Item} to get the variance for + * @param timestamp the point in time from which to compute the variance + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @return the variance between then and now, or null if timestamp is in the future, if + * there is no default persistence service available, or it is not a {@link QueryablePersistenceService}, or + * if there is no persisted state for the given item at the given timestamp + */ + public static @Nullable State varianceSince(Item item, ZonedDateTime timestamp, RiemannType type) { + return internalVarianceBetween(item, timestamp, null, type, null); } /** * Gets the variance of the state of the given {@link Item} until a certain point in time. + * A left approximation type is used for the Riemann sum. * The default {@link PersistenceService} is used. * * @param item the {@link Item} to get the variance for @@ -1159,7 +1185,42 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * if there is no persisted state for the given item at the given timestamp */ public static @Nullable State varianceUntil(Item item, ZonedDateTime timestamp) { - return internalVarianceBetween(item, null, timestamp, null); + return internalVarianceBetween(item, null, timestamp, RiemannType.left, null); + } + + /** + * Gets the variance of the state of the given {@link Item} until a certain point in time. + * The default {@link PersistenceService} is used. + * + * @param item the {@link Item} to get the variance for + * @param timestamp the point in time to which to compute the variance + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @return the variance between now and then, or null if timestamp is in the past, if + * there is no default persistence service available, or it is not a {@link QueryablePersistenceService}, or + * if there is no persisted state for the given item at the given timestamp + */ + public static @Nullable State varianceUntil(Item item, ZonedDateTime timestamp, RiemannType type) { + return internalVarianceBetween(item, null, timestamp, type, null); + } + + /** + * Gets the variance of the state of the given {@link Item} between two points in time. + * A left approximation type is used for the Riemann sum. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the {@link Item} to get the variance for + * @param begin the point in time from which to compute + * @param end the end time for the computation + * @param serviceId the name of the {@link PersistenceService} to use + * @return the variance between both points of time, or null if begin is after + * end, if the persistence service given by + * serviceId is not available, or it is not a {@link QueryablePersistenceService}, or it is not + * a {@link QueryablePersistenceService}, or if there is no persisted state for the + * given item between begin and end + */ + public static @Nullable State varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end, + @Nullable String serviceId) { + return internalVarianceBetween(item, begin, end, RiemannType.left, serviceId); } /** @@ -1169,17 +1230,19 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * @param item the {@link Item} to get the variance for * @param begin the point in time from which to compute the variance * @param end the end time for the computation + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums * @return the variance between both points of time, or null if begin is after * end, if there is no default persistence service available, or it is not a * {@link QueryablePersistenceService}, or if there is no persisted state for the * given item between begin and end */ - public static @Nullable State varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return internalVarianceBetween(item, begin, end, null); + public static @Nullable State varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end, RiemannType type) { + return internalVarianceBetween(item, begin, end, type, null); } /** * Gets the variance of the state of the given {@link Item} since a certain point in time. + * A left approximation type is used for the Riemann sum. * The {@link PersistenceService} identified by the serviceId is used. * * @param item the {@link Item} to get the variance for @@ -1191,11 +1254,30 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State varianceSince(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalVarianceBetween(item, timestamp, null, serviceId); + return internalVarianceBetween(item, timestamp, null, RiemannType.left, serviceId); + } + + /** + * Gets the variance of the state of the given {@link Item} since a certain point in time. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the {@link Item} to get the variance for + * @param timestamp the point in time from which to compute the variance + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param serviceId the name of the {@link PersistenceService} to use + * @return the variance between then and now, or null if timestamp is in the future, if + * the persistence service given by serviceId is not available, or it is not a + * {@link QueryablePersistenceService}, or if there is no persisted state for the given item at + * the given timestamp + */ + public static @Nullable State varianceSince(Item item, ZonedDateTime timestamp, RiemannType type, + @Nullable String serviceId) { + return internalVarianceBetween(item, timestamp, null, type, serviceId); } /** * Gets the variance of the state of the given {@link Item} until a certain point in time. + * A left approximation type is used for the Riemann sum. * The {@link PersistenceService} identified by the serviceId is used. * * @param item the {@link Item} to get the variance for @@ -1207,7 +1289,42 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State varianceUntil(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalVarianceBetween(item, null, timestamp, serviceId); + return internalVarianceBetween(item, null, timestamp, RiemannType.left, serviceId); + } + + /** + * Gets the variance of the state of the given {@link Item} until a certain point in time. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the {@link Item} to get the variance for + * @param timestamp the point in time to which to compute the variance + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param serviceId the name of the {@link PersistenceService} to use + * @return the variance between now and then, or null if timestamp is in the past, if the + * persistence service given by serviceId is not available, or it is not a + * {@link QueryablePersistenceService}, or if there is no persisted state for the given item at + * the given timestamp + */ + public static @Nullable State varianceUntil(Item item, ZonedDateTime timestamp, RiemannType type, + @Nullable String serviceId) { + return internalVarianceBetween(item, null, timestamp, type, serviceId); + } + + /** + * Gets the variance of the state of the given {@link Item} between two certain point in time. + * A left approximation type is used for the Riemann sum. + * The default {@link PersistenceService} is used. + * + * @param item the {@link Item} to get the variance for + * @param begin the point in time from which to compute the variance + * @param end the end time for the computation + * @return the variance between both points of time, or null if begin is after + * end, if there is no default persistence service available, or it is not a + * {@link QueryablePersistenceService}, or if there is no persisted state for the + * given item between begin and end + */ + public static @Nullable State varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { + return internalVarianceBetween(item, begin, end, RiemannType.left, null); } /** @@ -1217,6 +1334,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * @param item the {@link Item} to get the variance for * @param begin the point in time from which to compute * @param end the end time for the computation + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums * @param serviceId the name of the {@link PersistenceService} to use * @return the variance between both points of time, or null if begin is after * end, if the persistence service given by @@ -1224,13 +1342,13 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * a {@link QueryablePersistenceService}, or if there is no persisted state for the * given item between begin and end */ - public static @Nullable State varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end, + public static @Nullable State varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end, RiemannType type, @Nullable String serviceId) { - return internalVarianceBetween(item, begin, end, serviceId); + return internalVarianceBetween(item, begin, end, type, serviceId); } private static @Nullable State internalVarianceBetween(Item item, @Nullable ZonedDateTime begin, - @Nullable ZonedDateTime end, @Nullable String serviceId) { + @Nullable ZonedDateTime end, RiemannType type, @Nullable String serviceId) { String effectiveServiceId = serviceId == null ? getDefaultServiceId() : serviceId; if (effectiveServiceId == null) { return null; @@ -1239,7 +1357,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable if (result == null) { return null; } - State averageState = internalAverageBetween(item, begin, end, effectiveServiceId); + State averageState = internalAverageBetween(item, begin, end, type, effectiveServiceId); if (averageState != null) { DecimalType dt = averageState.as(DecimalType.class); @@ -1274,6 +1392,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable /** * Gets the standard deviation of the state of the given {@link Item} since a certain point in time. + * A left approximation type is used for the Riemann sum. * The default {@link PersistenceService} is used. * * Note: If you need variance and standard deviation at the same time do not query both as it is a costly @@ -1287,11 +1406,31 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State deviationSince(Item item, ZonedDateTime timestamp) { - return internalDeviationBetween(item, timestamp, null, null); + return internalDeviationBetween(item, timestamp, null, RiemannType.left, null); + } + + /** + * Gets the standard deviation of the state of the given {@link Item} since a certain point in time. + * The default {@link PersistenceService} is used. + * + * Note: If you need variance and standard deviation at the same time do not query both as it is a costly + * operation. Get the variance only, it is the squared deviation. + * + * @param item the {@link Item} to get the standard deviation for + * @param timestamp the point in time from which to compute the standard deviation + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @return the standard deviation between then and now, or null if timestamp is in the + * future, if there is no default persistence service available, or it is not a + * {@link QueryablePersistenceService}, or if there is no persisted state for the given item at + * the given timestamp + */ + public static @Nullable State deviationSince(Item item, ZonedDateTime timestamp, RiemannType type) { + return internalDeviationBetween(item, timestamp, null, type, null); } /** * Gets the standard deviation of the state of the given {@link Item} until a certain point in time. + * A left approximation type is used for the Riemann sum. * The default {@link PersistenceService} is used. * * Note: If you need variance and standard deviation at the same time do not query both as it is a costly @@ -1305,11 +1444,31 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State deviationUntil(Item item, ZonedDateTime timestamp) { - return internalDeviationBetween(item, timestamp, null, null); + return internalDeviationBetween(item, timestamp, null, RiemannType.left, null); + } + + /** + * Gets the standard deviation of the state of the given {@link Item} until a certain point in time. + * The default {@link PersistenceService} is used. + * + * Note: If you need variance and standard deviation at the same time do not query both as it is a costly + * operation. Get the variance only, it is the squared deviation. + * + * @param item the {@link Item} to get the standard deviation for + * @param timestamp the point in time to which to compute the standard deviation + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @return the standard deviation between now and then, or null if timestamp is in the + * past, if there is no default persistence service available, or it is not a + * {@link QueryablePersistenceService}, or if there is no persisted state for the given item at + * the given timestamp + */ + public static @Nullable State deviationUntil(Item item, ZonedDateTime timestamp, RiemannType type) { + return internalDeviationBetween(item, timestamp, null, type, null); } /** * Gets the standard deviation of the state of the given {@link Item} between two points in time. + * A left approximation type is used for the Riemann sum. * The default {@link PersistenceService} is used. * * Note: If you need variance and standard deviation at the same time do not query both as it is a costly @@ -1324,11 +1483,33 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * given item between begin and end */ public static @Nullable State deviationBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return internalDeviationBetween(item, begin, end, null); + return internalDeviationBetween(item, begin, end, RiemannType.left, null); + } + + /** + * Gets the standard deviation of the state of the given {@link Item} between two points in time. + * The default {@link PersistenceService} is used. + * + * Note: If you need variance and standard deviation at the same time do not query both as it is a costly + * operation. Get the variance only, it is the squared deviation. + * + * @param item the {@link Item} to get the standard deviation for + * @param begin the point in time from which to compute + * @param end the end time for the computation + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @return the standard deviation between both points of time, or null if begin is after + * end, if there is no default persistence service available, or it is not a + * {@link QueryablePersistenceService}, or if there is no persisted state for the + * given item between begin and end + */ + public static @Nullable State deviationBetween(Item item, ZonedDateTime begin, ZonedDateTime end, + RiemannType type) { + return internalDeviationBetween(item, begin, end, type, null); } /** * Gets the standard deviation of the state of the given {@link Item} since a certain point in time. + * A left approximation type is used for the Riemann sum. * The {@link PersistenceService} identified by the serviceId is used. * * Note: If you need variance and standard deviation at the same time do not query both as it is a costly @@ -1343,11 +1524,33 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State deviationSince(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalDeviationBetween(item, timestamp, null, serviceId); + return internalDeviationBetween(item, timestamp, null, RiemannType.left, serviceId); + } + + /** + * Gets the standard deviation of the state of the given {@link Item} since a certain point in time. + * The {@link PersistenceService} identified by the serviceId is used. + * + * Note: If you need variance and standard deviation at the same time do not query both as it is a costly + * operation. Get the variance only, it is the squared deviation. + * + * @param item the {@link Item} to get the standard deviation for + * @param timestamp the point in time from which to compute the standard deviation + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param serviceId the name of the {@link PersistenceService} to use + * @return the standard deviation between then and now, or null if timestamp is in the + * future, if the persistence service given by serviceId is not available, or it is not a + * {@link QueryablePersistenceService}, or if there is no persisted state for the given item at + * the given timestamp + */ + public static @Nullable State deviationSince(Item item, ZonedDateTime timestamp, RiemannType type, + @Nullable String serviceId) { + return internalDeviationBetween(item, timestamp, null, type, serviceId); } /** * Gets the standard deviation of the state of the given {@link Item} until a certain point in time. + * A left approximation type is used for the Riemann sum. * The {@link PersistenceService} identified by the serviceId is used. * * Note: If you need variance and standard deviation at the same time do not query both as it is a costly @@ -1362,11 +1565,33 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State deviationUntil(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalDeviationBetween(item, null, timestamp, serviceId); + return internalDeviationBetween(item, null, timestamp, RiemannType.left, serviceId); + } + + /** + * Gets the standard deviation of the state of the given {@link Item} until a certain point in time. + * The {@link PersistenceService} identified by the serviceId is used. + * + * Note: If you need variance and standard deviation at the same time do not query both as it is a costly + * operation. Get the variance only, it is the squared deviation. + * + * @param item the {@link Item} to get the standard deviation for + * @param timestamp the point in time to which to compute the standard deviation + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param serviceId the name of the {@link PersistenceService} to use + * @return the standard deviation between now and then, or null if timestamp is in the + * past, if the persistence service given by serviceId is not available, or it is not a + * {@link QueryablePersistenceService}, or if there is no persisted state for the given item at + * the given timestamp + */ + public static @Nullable State deviationUntil(Item item, ZonedDateTime timestamp, RiemannType type, + @Nullable String serviceId) { + return internalDeviationBetween(item, null, timestamp, type, serviceId); } /** * Gets the standard deviation of the state of the given {@link Item} between two points in time. + * A left approximation type is used for the Riemann sum. * The {@link PersistenceService} identified by the serviceId is used. * * Note: If you need variance and standard deviation at the same time do not query both as it is a costly @@ -1384,16 +1609,39 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable */ public static @Nullable State deviationBetween(Item item, ZonedDateTime begin, ZonedDateTime end, @Nullable String serviceId) { - return internalDeviationBetween(item, begin, end, serviceId); + return internalDeviationBetween(item, begin, end, RiemannType.left, serviceId); + } + + /** + * Gets the standard deviation of the state of the given {@link Item} between two points in time. + * The {@link PersistenceService} identified by the serviceId is used. + * + * Note: If you need variance and standard deviation at the same time do not query both as it is a costly + * operation. Get the variance only, it is the squared deviation. + * + * @param item the {@link Item} to get the standard deviation for + * @param begin the point in time from which to compute + * @param end the end time for the computation + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param serviceId the name of the {@link PersistenceService} to use + * @return the standard deviation between both points of time, or null if begin is after + * end, if the persistence service given by + * serviceId is not available, or it is not a {@link QueryablePersistenceService}, or it is not + * a {@link QueryablePersistenceService}, or if there is no persisted state for the + * given item between begin and end + */ + public static @Nullable State deviationBetween(Item item, ZonedDateTime begin, ZonedDateTime end, RiemannType type, + @Nullable String serviceId) { + return internalDeviationBetween(item, begin, end, type, serviceId); } private static @Nullable State internalDeviationBetween(Item item, @Nullable ZonedDateTime begin, - @Nullable ZonedDateTime end, @Nullable String serviceId) { + @Nullable ZonedDateTime end, RiemannType type, @Nullable String serviceId) { String effectiveServiceId = serviceId == null ? getDefaultServiceId() : serviceId; if (effectiveServiceId == null) { return null; } - State variance = internalVarianceBetween(item, begin, end, effectiveServiceId); + State variance = internalVarianceBetween(item, begin, end, type, effectiveServiceId); if (variance != null) { DecimalType dt = variance.as(DecimalType.class); @@ -1415,6 +1663,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable /** * Gets the average value of the state of a given {@link Item} since a certain point in time. + * A left approximation type is used for the Riemann sum. * The default {@link PersistenceService} is used. * * @param item the {@link Item} to get the average value for @@ -1424,11 +1673,27 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}. The current state is included in the calculation. */ public static @Nullable State averageSince(Item item, ZonedDateTime timestamp) { - return internalAverageBetween(item, timestamp, null, null); + return internalAverageBetween(item, timestamp, null, RiemannType.left, null); + } + + /** + * Gets the average value of the state of a given {@link Item} since a certain point in time. + * The default {@link PersistenceService} is used. + * + * @param item the {@link Item} to get the average value for + * @param timestamp the point in time from which to search for the average value + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @return the average value since timestamp or null if no + * previous states could be found or if the default persistence service does not refer to an available + * {@link QueryablePersistenceService}. The current state is included in the calculation. + */ + public static @Nullable State averageSince(Item item, ZonedDateTime timestamp, RiemannType type) { + return internalAverageBetween(item, timestamp, null, type, null); } /** * Gets the average value of the state of a given {@link Item} until a certain point in time. + * A left approximation type is used for the Riemann sum. * The default {@link PersistenceService} is used. * * @param item the {@link Item} to get the average value for @@ -1438,11 +1703,27 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}. The current state is included in the calculation. */ public static @Nullable State averageUntil(Item item, ZonedDateTime timestamp) { - return internalAverageBetween(item, null, timestamp, null); + return internalAverageBetween(item, null, timestamp, RiemannType.left, null); + } + + /** + * Gets the average value of the state of a given {@link Item} until a certain point in time. + * The default {@link PersistenceService} is used. + * + * @param item the {@link Item} to get the average value for + * @param timestamp the point in time to which to search for the average value + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @return the average value until timestamp or null if no + * future states could be found or if the default persistence service does not refer to an available + * {@link QueryablePersistenceService}. The current state is included in the calculation. + */ + public static @Nullable State averageUntil(Item item, ZonedDateTime timestamp, RiemannType type) { + return internalAverageBetween(item, null, timestamp, type, null); } /** * Gets the average value of the state of a given {@link Item} between two certain points in time. + * A left approximation type is used for the Riemann sum. * The default {@link PersistenceService} is used. * * @param item the {@link Item} to get the average value for @@ -1453,11 +1734,28 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}. */ public static @Nullable State averageBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return internalAverageBetween(item, begin, end, null); + return internalAverageBetween(item, begin, end, RiemannType.left, null); + } + + /** + * Gets the average value of the state of a given {@link Item} between two certain points in time. + * The default {@link PersistenceService} is used. + * + * @param item the {@link Item} to get the average value for + * @param begin the point in time from which to start the summation + * @param end the point in time to which to start the summation + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @return the average value between begin and end or null if no + * states could be found or if the default persistence service does not refer to an available + * {@link QueryablePersistenceService}. + */ + public static @Nullable State averageBetween(Item item, ZonedDateTime begin, ZonedDateTime end, RiemannType type) { + return internalAverageBetween(item, begin, end, type, null); } /** * Gets the average value of the state of a given {@link Item} since a certain point in time. + * A left approximation type is used for the Riemann sum. * The {@link PersistenceService} identified by the serviceId is used. * * @param item the {@link Item} to get the average value for @@ -1469,11 +1767,30 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * calculation. */ public static @Nullable State averageSince(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalAverageBetween(item, timestamp, null, serviceId); + return internalAverageBetween(item, timestamp, null, RiemannType.left, serviceId); + } + + /** + * Gets the average value of the state of a given {@link Item} since a certain point in time. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the {@link Item} to get the average value for + * @param timestamp the point in time from which to search for the average value + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param serviceId the name of the {@link PersistenceService} to use + * @return the average value since timestamp, or null if no + * previous states could be found or if the persistence service given by serviceId does not + * refer to an available {@link QueryablePersistenceService}. The current state is included in the + * calculation. + */ + public static @Nullable State averageSince(Item item, ZonedDateTime timestamp, RiemannType type, + @Nullable String serviceId) { + return internalAverageBetween(item, timestamp, null, type, serviceId); } /** * Gets the average value of the state of a given {@link Item} until a certain point in time. + * A left approximation type is used for the Riemann sum. * The {@link PersistenceService} identified by the serviceId is used. * * @param item the {@link Item} to get the average value for @@ -1485,11 +1802,30 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * calculation. */ public static @Nullable State averageUntil(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalAverageBetween(item, null, timestamp, serviceId); + return internalAverageBetween(item, null, timestamp, RiemannType.left, serviceId); + } + + /** + * Gets the average value of the state of a given {@link Item} until a certain point in time. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the {@link Item} to get the average value for + * @param timestamp the point in time to which to search for the average value + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param serviceId the name of the {@link PersistenceService} to use + * @return the average value until timestamp, or null if no + * future states could be found or if the persistence service given by serviceId does not + * refer to an available {@link QueryablePersistenceService}. The current state is included in the + * calculation. + */ + public static @Nullable State averageUntil(Item item, ZonedDateTime timestamp, RiemannType type, + @Nullable String serviceId) { + return internalAverageBetween(item, null, timestamp, type, serviceId); } /** * Gets the average value of the state of a given {@link Item} between two certain points in time. + * A left approximation type is used for the Riemann sum. * The {@link PersistenceService} identified by the serviceId is used. * * @param item the {@link Item} to get the average value for @@ -1502,11 +1838,29 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable */ public static @Nullable State averageBetween(Item item, ZonedDateTime begin, ZonedDateTime end, @Nullable String serviceId) { - return internalAverageBetween(item, begin, end, serviceId); + return internalAverageBetween(item, begin, end, RiemannType.left, serviceId); + } + + /** + * Gets the average value of the state of a given {@link Item} between two certain points in time. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the {@link Item} to get the average value for + * @param begin the point in time from which to start the summation + * @param end the point in time to which to start the summation + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param serviceId the name of the {@link PersistenceService} to use + * @return the average value between begin and end, or null if no + * states could be found or if the persistence service given by serviceId does not + * refer to an available {@link QueryablePersistenceService} + */ + public static @Nullable State averageBetween(Item item, ZonedDateTime begin, ZonedDateTime end, RiemannType type, + @Nullable String serviceId) { + return internalAverageBetween(item, begin, end, type, serviceId); } private static @Nullable State internalAverageBetween(Item item, @Nullable ZonedDateTime begin, - @Nullable ZonedDateTime end, @Nullable String serviceId) { + @Nullable ZonedDateTime end, RiemannType type, @Nullable String serviceId) { String effectiveServiceId = serviceId == null ? getDefaultServiceId() : serviceId; if (effectiveServiceId == null) { return null; @@ -1525,46 +1879,397 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable return null; } Iterator it = result.iterator(); + // Remove initial part of history that does not have any values persisted + if (beginTime.isBefore(now)) { + if (it.hasNext()) { + beginTime = it.next().getTimestamp(); + } + it = result.iterator(); + } - BigDecimal sum = BigDecimal.ZERO; + Item baseItem = item instanceof GroupItem groupItem ? groupItem.getBaseItem() : item; + Unit unit = baseItem instanceof NumberItem numberItem ? numberItem.getUnit() : null; + + BigDecimal sum = riemannSum(beginTime, endTime, it, unit, type); + BigDecimal totalDuration = BigDecimal.valueOf(Duration.between(beginTime, endTime).toMillis()); + if (totalDuration.signum() == 0) { + return null; + } + BigDecimal average = sum.divide(totalDuration, MathContext.DECIMAL64); + if (unit != null) { + return new QuantityType<>(average, unit); + } + return new DecimalType(average); + } + + /** + * Gets the Riemann sum of the states of a given {@link Item} since a certain point in time. + * This can be used as an approximation for integrating the curve represented by discrete values. + * A left approximation type is used for the Riemann sum. + * The time dimension in the result is in seconds, therefore if you do not use QuantityType results, you may have to + * multiply or divide to get the result in the expected scale. + * The default {@link PersistenceService} is used. + * + * @param item the {@link Item} to get the riemannSum value for + * @param timestamp the point in time from which to search for the riemannSum value + * @return the Riemann sum since timestamp or null if no + * previous states could be found or if the default persistence service does not refer to an available + * {@link QueryablePersistenceService}. The current state is included in the calculation. + */ + public static @Nullable State riemannSumSince(Item item, ZonedDateTime timestamp) { + return internalRiemannSumBetween(item, timestamp, null, RiemannType.left, null); + } + + /** + * Gets the Riemann sum of the states of a given {@link Item} since a certain point in time. + * This can be used as an approximation for integrating the curve represented by discrete values. + * The time dimension in the result is in seconds, therefore if you do not use QuantityType results, you may have to + * multiply or divide to get the result in the expected scale. + * The default {@link PersistenceService} is used. + * + * @param item the {@link Item} to get the riemannSum value for + * @param timestamp the point in time from which to search for the riemannSum value + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @return the Riemann sum since timestamp or null if no + * previous states could be found or if the default persistence service does not refer to an available + * {@link QueryablePersistenceService}. The current state is included in the calculation. + */ + public static @Nullable State riemannSumSince(Item item, ZonedDateTime timestamp, RiemannType type) { + return internalRiemannSumBetween(item, timestamp, null, type, null); + } + + /** + * Gets the Riemann sum of the states of a given {@link Item} until a certain point in time. + * This can be used as an approximation for integrating the curve represented by discrete values. + * A left approximation type is used for the Riemann sum. + * The time dimension in the result is in seconds, therefore if you do not use QuantityType results, you may have to + * multiply or divide to get the result in the expected scale. + * The default {@link PersistenceService} is used. + * + * @param item the {@link Item} to get the riemannSum value for + * @param timestamp the point in time to which to search for the riemannSum value + * @return the Riemann sum until timestamp or null if no + * future states could be found or if the default persistence service does not refer to an available + * {@link QueryablePersistenceService}. The current state is included in the calculation. + */ + public static @Nullable State riemannSumUntil(Item item, ZonedDateTime timestamp) { + return internalRiemannSumBetween(item, null, timestamp, RiemannType.left, null); + } + + /** + * Gets the Riemann sum of the states of a given {@link Item} until a certain point in time. + * This can be used as an approximation for integrating the curve represented by discrete values. + * The time dimension in the result is in seconds, therefore if you do not use QuantityType results, you may have to + * multiply or divide to get the result in the expected scale. + * The default {@link PersistenceService} is used. + * + * @param item the {@link Item} to get the riemannSum value for + * @param timestamp the point in time to which to search for the riemannSum value + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @return the Riemann sum until timestamp or null if no + * future states could be found or if the default persistence service does not refer to an available + * {@link QueryablePersistenceService}. The current state is included in the calculation. + */ + public static @Nullable State riemannSumUntil(Item item, ZonedDateTime timestamp, RiemannType type) { + return internalRiemannSumBetween(item, null, timestamp, type, null); + } + + /** + * Gets the Riemann sum of the states of a given {@link Item} between two certain points in time. + * This can be used as an approximation for integrating the curve represented by discrete values. + * A left approximation type is used for the Riemann sum. + * The time dimension in the result is in seconds, therefore if you do not use QuantityType results, you may have to + * multiply or divide to get the result in the expected scale. + * The default {@link PersistenceService} is used. + * + * @param item the {@link Item} to get the riemannSum value for + * @param begin the point in time from which to start the summation + * @param end the point in time to which to start the summation + * @return the Riemann sum between begin and end or null if no + * states could be found or if the default persistence service does not refer to an available + * {@link QueryablePersistenceService}. + */ + public static @Nullable State riemannSumBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { + return internalRiemannSumBetween(item, begin, end, RiemannType.left, null); + } + + /** + * Gets the Riemann sum of the states of a given {@link Item} between two certain points in time. + * This can be used as an approximation for integrating the curve represented by discrete values. + * The time dimension in the result is in seconds, therefore if you do not use QuantityType results, you may have to + * multiply or divide to get the result in the expected scale. + * The default {@link PersistenceService} is used. + * + * @param item the {@link Item} to get the riemannSum value for + * @param begin the point in time from which to start the summation + * @param end the point in time to which to start the summation + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @return the Riemann sum between begin and end or null if no + * states could be found or if the default persistence service does not refer to an available + * {@link QueryablePersistenceService}. + */ + public static @Nullable State riemannSumBetween(Item item, ZonedDateTime begin, ZonedDateTime end, + RiemannType type) { + return internalRiemannSumBetween(item, begin, end, type, null); + } + + /** + * Gets the Riemann sum of the states of a given {@link Item} since a certain point in time. + * This can be used as an approximation for integrating the curve represented by discrete values. + * A left approximation type is used for the Riemann sum. + * The time dimension in the result is in seconds, therefore if you do not use QuantityType results, you may have to + * multiply or divide to get the result in the expected scale. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the {@link Item} to get the riemannSum value for + * @param timestamp the point in time from which to search for the riemannSum value + * @param serviceId the name of the {@link PersistenceService} to use + * @return the Riemann sum since timestamp, or null if no + * previous states could be found or if the persistence service given by serviceId does not + * refer to an available {@link QueryablePersistenceService}. The current state is included in the + * calculation. + */ + public static @Nullable State riemannSumSince(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { + return internalRiemannSumBetween(item, timestamp, null, RiemannType.left, serviceId); + } + + /** + * Gets the Riemann sum of the states of a given {@link Item} since a certain point in time. + * This can be used as an approximation for integrating the curve represented by discrete values. + * The time dimension in the result is in seconds, therefore if you do not use QuantityType results, you may have to + * multiply or divide to get the result in the expected scale. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the {@link Item} to get the riemannSum value for + * @param timestamp the point in time from which to search for the riemannSum value + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param serviceId the name of the {@link PersistenceService} to use + * @return the Riemann sum since timestamp, or null if no + * previous states could be found or if the persistence service given by serviceId does not + * refer to an available {@link QueryablePersistenceService}. The current state is included in the + * calculation. + */ + public static @Nullable State riemannSumSince(Item item, ZonedDateTime timestamp, RiemannType type, + @Nullable String serviceId) { + return internalRiemannSumBetween(item, timestamp, null, type, serviceId); + } + + /** + * Gets the Riemann sum of the states of a given {@link Item} until a certain point in time. + * This can be used as an approximation for integrating the curve represented by discrete values. + * A left approximation type is used for the Riemann sum. + * The time dimension in the result is in seconds, therefore if you do not use QuantityType results, you may have to + * multiply or divide to get the result in the expected scale. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the {@link Item} to get the riemannSum value for + * @param timestamp the point in time to which to search for the riemannSum value + * @param serviceId the name of the {@link PersistenceService} to use + * @return the Riemann sum until timestamp, or null if no + * future states could be found or if the persistence service given by serviceId does not + * refer to an available {@link QueryablePersistenceService}. The current state is included in the + * calculation. + */ + public static @Nullable State riemannSumUntil(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { + return internalRiemannSumBetween(item, null, timestamp, RiemannType.left, serviceId); + } + + /** + * Gets the Riemann sum of the states of a given {@link Item} until a certain point in time. + * This can be used as an approximation for integrating the curve represented by discrete values. + * The time dimension in the result is in seconds, therefore if you do not use QuantityType results, you may have to + * multiply or divide to get the result in the expected scale. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the {@link Item} to get the riemannSum value for + * @param timestamp the point in time to which to search for the riemannSum value + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param serviceId the name of the {@link PersistenceService} to use + * @return the Riemann sum until timestamp, or null if no + * future states could be found or if the persistence service given by serviceId does not + * refer to an available {@link QueryablePersistenceService}. The current state is included in the + * calculation. + */ + public static @Nullable State riemannSumUntil(Item item, ZonedDateTime timestamp, RiemannType type, + @Nullable String serviceId) { + return internalRiemannSumBetween(item, null, timestamp, type, serviceId); + } + + /** + * Gets the Riemann sum of the states of a given {@link Item} between two certain points in time. + * This can be used as an approximation for integrating the curve represented by discrete values. + * A left approximation type is used for the Riemann sum. + * The time dimension in the result is in seconds, therefore if you do not use QuantityType results, you may have to + * multiply or divide to get the result in the expected scale. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the {@link Item} to get the riemannSum value for + * @param begin the point in time from which to start the summation + * @param end the point in time to which to start the summation + * @param serviceId the name of the {@link PersistenceService} to use + * @return the Riemann sum between begin and end, or null if no + * states could be found or if the persistence service given by serviceId does not + * refer to an available {@link QueryablePersistenceService} + */ + public static @Nullable State riemannSumBetween(Item item, ZonedDateTime begin, ZonedDateTime end, + @Nullable String serviceId) { + return internalRiemannSumBetween(item, begin, end, RiemannType.left, serviceId); + } - HistoricItem lastItem = null; - ZonedDateTime firstTimestamp = null; + /** + * Gets the Riemann sum of the states of a given {@link Item} between two certain points in time. + * This can be used as an approximation for integrating the curve represented by discrete values. + * The time dimension in the result is in seconds, therefore if you do not use QuantityType results, you may have to + * multiply or divide to get the result in the expected scale. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the {@link Item} to get the riemannSum value for + * @param begin the point in time from which to start the summation + * @param end the point in time to which to start the summation + * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param serviceId the name of the {@link PersistenceService} to use + * @return the Riemann sum between begin and end, or null if no + * states could be found or if the persistence service given by serviceId does not + * refer to an available {@link QueryablePersistenceService} + */ + public static @Nullable State riemannSumBetween(Item item, ZonedDateTime begin, ZonedDateTime end, RiemannType type, + @Nullable String serviceId) { + return internalRiemannSumBetween(item, begin, end, type, serviceId); + } + + private static @Nullable State internalRiemannSumBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end, RiemannType type, @Nullable String serviceId) { + String effectiveServiceId = serviceId == null ? getDefaultServiceId() : serviceId; + if (effectiveServiceId == null) { + return null; + } + ZonedDateTime now = ZonedDateTime.now(); + ZonedDateTime beginTime = Objects.requireNonNullElse(begin, now); + ZonedDateTime endTime = Objects.requireNonNullElse(end, now); + + Iterable result = getAllStatesBetweenWithBoundaries(item, begin, end, effectiveServiceId); + if (result == null) { + return null; + } + Iterator it = result.iterator(); + // Remove initial part of history that does not have any values persisted + if (beginTime.isBefore(now)) { + if (it.hasNext()) { + beginTime = it.next().getTimestamp(); + } + it = result.iterator(); + } Item baseItem = item instanceof GroupItem groupItem ? groupItem.getBaseItem() : item; Unit unit = baseItem instanceof NumberItem numberItem ? numberItem.getUnit() : null; - while (it.hasNext()) { - HistoricItem thisItem = it.next(); - if (lastItem != null) { - DecimalType dtState = getPersistedValue(lastItem, unit); - if (dtState != null) { - BigDecimal value = dtState.toBigDecimal(); - BigDecimal weight = BigDecimal - .valueOf(Duration.between(lastItem.getTimestamp(), thisItem.getTimestamp()).toMillis()); - sum = sum.add(value.multiply(weight)); - } - } + BigDecimal sum = riemannSum(beginTime, endTime, it, unit, type).scaleByPowerOfTen(-3); + if (unit != null) { + return new QuantityType<>(sum, unit.multiply(Units.SECOND)); + } + return new DecimalType(sum); + } + + private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Iterator it, + @Nullable Unit unit, RiemannType type) { + BigDecimal sum = BigDecimal.ZERO; + HistoricItem prevItem = null; + HistoricItem currentItem = null; + Duration prevDuration = null; - if (firstTimestamp == null) { - firstTimestamp = thisItem.getTimestamp(); + if (it.hasNext() && (type == RiemannType.midpoint)) { + currentItem = it.next(); + prevDuration = Duration.between(begin, currentItem.getTimestamp()); + } + + while (it.hasNext()) { + HistoricItem nextItem = it.next(); + BigDecimal weight = BigDecimal.ZERO; + BigDecimal value = BigDecimal.ZERO; + DecimalType prevState; + DecimalType currentState; + DecimalType nextState; + switch (type) { + case left: + if (prevItem != null) { + prevState = getPersistedValue(prevItem, unit); + if (prevState != null) { + value = prevState.toBigDecimal(); + weight = BigDecimal.valueOf( + Duration.between(prevItem.getTimestamp(), nextItem.getTimestamp()).toMillis()); + } + } + prevItem = nextItem; + break; + case right: + nextState = getPersistedValue(nextItem, unit); + if (nextState != null) { + value = nextState.toBigDecimal(); + if (prevItem == null) { + weight = BigDecimal.valueOf(Duration.between(begin, nextItem.getTimestamp()).toMillis()); + } else { + weight = BigDecimal.valueOf( + Duration.between(prevItem.getTimestamp(), nextItem.getTimestamp()).toMillis()); + } + } + prevItem = nextItem; + break; + case trapezoidal: + if (prevItem != null) { + prevState = getPersistedValue(prevItem, unit); + nextState = getPersistedValue(nextItem, unit); + if (prevState != null && nextState != null) { + value = prevState.toBigDecimal().add(nextState.toBigDecimal()) + .divide(BigDecimal.valueOf(2)); + weight = BigDecimal.valueOf( + Duration.between(prevItem.getTimestamp(), nextItem.getTimestamp()).toMillis()); + } + } + prevItem = nextItem; + break; + case midpoint: + if (currentItem != null) { + currentState = getPersistedValue(currentItem, unit); + if (currentState != null && prevDuration != null) { + value = currentState.toBigDecimal(); + Duration nextDuration = Duration.between(currentItem.getTimestamp(), + nextItem.getTimestamp()); + weight = prevDuration.isZero() || nextDuration.isZero() ? BigDecimal.ZERO + : BigDecimal.valueOf(prevDuration.plus(nextDuration).dividedBy(2).toMillis()); + if (!nextDuration.isZero()) { + prevDuration = nextDuration; + } + } + } + prevItem = currentItem; + currentItem = nextItem; + break; } - lastItem = thisItem; + sum = sum.add(value.multiply(weight)); } - if (firstTimestamp != null) { - BigDecimal totalDuration = BigDecimal.valueOf(Duration.between(firstTimestamp, endTime).toMillis()); - if (totalDuration.signum() == 0) { - return null; + if (prevItem != null && type == RiemannType.left) { + DecimalType dtState = getPersistedValue(prevItem, unit); + if (dtState != null) { + BigDecimal value = dtState.toBigDecimal(); + BigDecimal weight = BigDecimal.valueOf(Duration.between(prevItem.getTimestamp(), end).toMillis()); + sum = sum.add(value.multiply(weight)); } - BigDecimal average = sum.divide(totalDuration, MathContext.DECIMAL64); - if (unit != null) { - return new QuantityType<>(average, unit); + } + if (prevItem != null && currentItem != null && type == RiemannType.midpoint) { + DecimalType dtState = getPersistedValue(currentItem, unit); + if (dtState != null && prevDuration != null && !prevDuration.isZero()) { + BigDecimal value = dtState.toBigDecimal(); + Duration nextDuration = Duration.between(currentItem.getTimestamp(), end); + if (!nextDuration.isZero()) { + BigDecimal weight = BigDecimal.valueOf(prevDuration.plus(nextDuration).dividedBy(2).toMillis()); + sum = sum.add(value.multiply(weight)); + } } - return new DecimalType(average); } - return null; + return sum; + } /** @@ -1703,6 +2408,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable /** * Gets the sum of the state of a given item since a certain point in time. + * This method does not calculate a Riemann sum and therefore cannot be used as an approximation for the integral + * value. * The default persistence service is used. * * @param item the item for which we will sum its persisted state values since timestamp @@ -1716,6 +2423,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable /** * Gets the sum of the state of a given item until a certain point in time. + * This method does not calculate a Riemann sum and therefore cannot be used as an approximation for the integral + * value. * The default persistence service is used. * * @param item the item for which we will sum its persisted state values to timestamp @@ -1729,6 +2438,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable /** * Gets the sum of the state of a given item between two certain points in time. + * This method does not calculate a Riemann sum and therefore cannot be used as an approximation for the integral + * value. * The default persistence service is used. * * @param item the item for which we will sum its persisted state values between begin and @@ -1745,6 +2456,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable /** * Gets the sum of the state of a given item since a certain point in time. + * This method does not calculate a Riemann sum and therefore cannot be used as an approximation for the integral + * value. * The {@link PersistenceService} identified by the serviceId is used. * * @param item the item for which we will sum its persisted state values since timestamp @@ -1759,6 +2472,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable /** * Gets the sum of the state of a given item until a certain point in time. + * This method does not calculate a Riemann sum and therefore cannot be used as an approximation for the integral + * value. * The {@link PersistenceService} identified by the serviceId is used. * * @param item the item for which we will sum its persisted state values to timestamp @@ -1773,6 +2488,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable /** * Gets the sum of the state of a given item between two certain points in time. + * This method does not calculate a Riemann sum and therefore cannot be used as an approximation for the integral + * value. * The {@link PersistenceService} identified by the serviceId is used. * * @param item the item for which we will sum its persisted state values between begin and diff --git a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java index cfcf66326ff..f0a0eb724cc 100644 --- a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java +++ b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java @@ -52,6 +52,7 @@ import org.openhab.core.persistence.HistoricItem; import org.openhab.core.persistence.PersistenceService; import org.openhab.core.persistence.PersistenceServiceRegistry; +import org.openhab.core.persistence.extensions.PersistenceExtensions.RiemannType; import org.openhab.core.types.State; /** @@ -64,6 +65,7 @@ * @author Mark Herwege - lastChange and nextChange methods * @author Mark Herwege - handle persisted GroupItem with QuantityType * @author Mark Herwege - add median methods + * @author Mark Herwege - add Riemann sum methods */ @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) @@ -1483,6 +1485,211 @@ public void testDeviationBetweenGroupQuantityType() { assertNull(deviation); } + @Test + public void testRiemannSumSinceDecimalType() { + for (RiemannType type : RiemannType.values()) { + ZonedDateTime start = ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + double expected = riemannSum(BEFORE_START, null, type); + State sum = PersistenceExtensions.riemannSumSince(numberItem, start, type, SERVICE_ID); + assertNotNull(sum); + DecimalType dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertEquals(expected, dt.doubleValue(), HISTORIC_END * 1.0); // Allow max 1s difference between method and + // test + + start = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, null, type); + sum = PersistenceExtensions.riemannSumSince(numberItem, start, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertEquals(expected, dt.doubleValue(), HISTORIC_END * 1.0); // Allow max 1s difference between method and + // test value + + // default persistence service + sum = PersistenceExtensions.riemannSumSince(numberItem, start, type); + assertNull(sum); + } + } + + @Test + public void testRiemannSumUntilDecimalType() { + for (RiemannType type : RiemannType.values()) { + ZonedDateTime end = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + double expected = riemannSum(null, FUTURE_INTERMEDIATE_VALUE_3, type); + State sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type, SERVICE_ID); + assertNotNull(sum); + DecimalType dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertEquals(expected, dt.doubleValue(), HISTORIC_END * 1.0); // Allow max 1s difference between method and + // test value + // default persistence service + sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type); + assertNull(sum); + } + } + + @Test + public void testRiemannSumBetweenDecimalType() { + for (RiemannType type : RiemannType.values()) { + ZonedDateTime beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, + ZoneId.systemDefault()); + ZonedDateTime endStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, + ZoneId.systemDefault()); + double expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2, type); + State sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + DecimalType dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertEquals(expected, dt.doubleValue(), 0.01); + + beginStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4, type); + + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + + beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, FUTURE_INTERMEDIATE_VALUE_3, type); + + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + + // default persistence service + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type); + assertNull(sum); + } + } + + @Test + public void testRiemannSumBetweenQuantityType() { + for (RiemannType type : RiemannType.values()) { + ZonedDateTime beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, + ZoneId.systemDefault()); + ZonedDateTime endStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, + ZoneId.systemDefault()); + double expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2, type); + State RiemannSum = PersistenceExtensions.riemannSumBetween(quantityItem, beginStored, endStored, type, + SERVICE_ID); + + assertNotNull(RiemannSum); + QuantityType qt = RiemannSum.as(QuantityType.class); + assertNotNull(qt); + assertThat(qt.doubleValue(), is(closeTo(expected, 0.01))); + assertEquals(SIUnits.CELSIUS.multiply(Units.SECOND), qt.getUnit()); + + beginStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4, type); + + RiemannSum = PersistenceExtensions.riemannSumBetween(quantityItem, beginStored, endStored, type, + SERVICE_ID); + assertNotNull(RiemannSum); + qt = RiemannSum.as(QuantityType.class); + assertNotNull(qt); + assertThat(qt.doubleValue(), is(closeTo(expected, 0.01))); + assertEquals(SIUnits.CELSIUS.multiply(Units.SECOND), qt.getUnit()); + + beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, FUTURE_INTERMEDIATE_VALUE_3, type); + + RiemannSum = PersistenceExtensions.riemannSumBetween(quantityItem, beginStored, endStored, type, + SERVICE_ID); + assertNotNull(RiemannSum); + qt = RiemannSum.as(QuantityType.class); + assertNotNull(qt); + assertThat(qt.doubleValue(), is(closeTo(expected, 0.01))); + assertEquals(SIUnits.CELSIUS.multiply(Units.SECOND), qt.getUnit()); + + // default persistence service + RiemannSum = PersistenceExtensions.riemannSumBetween(quantityItem, beginStored, endStored, type); + assertNull(RiemannSum); + } + } + + @Test + public void testRiemannSumSinceDecimalTypeIrregularTimespans() { + RiemannType type = RiemannType.left; + + ZonedDateTime now = ZonedDateTime.now(); + int historicHours = 27; + int futureHours = 0; + + createTestCachedValuesPersistenceService(now, historicHours, futureHours); + + State sum = PersistenceExtensions.riemannSumSince(numberItem, now.minusHours(historicHours), type, + TestCachedValuesPersistenceService.ID); + assertNotNull(sum); + DecimalType dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(100.0 * 3600 + 50.0 * 3600, 0.01))); + + sum = PersistenceExtensions.riemannSumSince(numberItem, now.minusHours(historicHours).plusHours(3), type, + TestCachedValuesPersistenceService.ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(50.0 * 3600, 0.01))); + + sum = PersistenceExtensions.riemannSumSince(numberItem, now.minusMinutes(30), type, + TestCachedValuesPersistenceService.ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(0, 0.01))); + } + + @Test + public void testRiemannSumUntilDecimalTypeIrregularTimespans() { + RiemannType type = RiemannType.left; + + ZonedDateTime now = ZonedDateTime.now(); + int historicHours = 0; + int futureHours = 27; + + createTestCachedValuesPersistenceService(now, historicHours, futureHours); + + State sum = PersistenceExtensions.riemannSumUntil(numberItem, now.plusHours(futureHours), type, + TestCachedValuesPersistenceService.ID); + assertNotNull(sum); + DecimalType dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(100.0 * 3600 + 50.0 * 3600, 0.01))); + + sum = PersistenceExtensions.riemannSumUntil(numberItem, now.plusHours(futureHours).minusHours(2), type, + TestCachedValuesPersistenceService.ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(50.0 * 3600, 0.01))); + + sum = PersistenceExtensions.riemannSumUntil(numberItem, now.plusMinutes(30), type, + TestCachedValuesPersistenceService.ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(0, 0.01))); + } + + @Test + public void testRiemannSumBetweenZeroDuration() { + ZonedDateTime now = ZonedDateTime.now(); + State sum = PersistenceExtensions.riemannSumBetween(numberItem, now, now, SERVICE_ID); + assertNotNull(sum); + DecimalType dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(0, 0.01))); + } + @Test public void testAverageSinceDecimalType() { ZonedDateTime start = ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); @@ -1556,7 +1763,7 @@ public void testAverageBetweenDecimalType() { assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); // default persistence service - average = PersistenceExtensions.averageBetween(quantityItem, beginStored, endStored); + average = PersistenceExtensions.averageBetween(numberItem, beginStored, endStored); assertNull(average); } diff --git a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java index 1a734703c4e..7998ecf8a83 100644 --- a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java +++ b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java @@ -41,6 +41,7 @@ import org.openhab.core.persistence.HistoricItem; import org.openhab.core.persistence.PersistenceItemInfo; import org.openhab.core.persistence.QueryablePersistenceService; +import org.openhab.core.persistence.extensions.PersistenceExtensions.RiemannType; import org.openhab.core.persistence.strategy.PersistenceStrategy; import org.openhab.core.types.State; @@ -49,6 +50,7 @@ * * @author Kai Kreuzer - Initial contribution * @author Mark Herwege - Allow future values + * @author Mark Herwege - Adapt test expected value logic for Riemann sums */ @NonNullByDefault public class TestPersistenceService implements QueryablePersistenceService { @@ -176,6 +178,7 @@ public String getName() { } final int year = i; results.add(new HistoricItem() { + @Override public ZonedDateTime getTimestamp() { return ZonedDateTime.of(year, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); @@ -201,6 +204,7 @@ public String getName() { if (filter.getOrdering() == Ordering.DESCENDING) { Collections.reverse(results); } + Stream stream = results.stream(); if (filter.getPageNumber() > 0) { stream = stream.skip(filter.getPageSize() * filter.getPageNumber()); @@ -247,6 +251,137 @@ static DecimalType value(long year) { } } + static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, RiemannType type) { + ZonedDateTime now = ZonedDateTime.now(); + int begin = beginYear != null ? (beginYear < HISTORIC_START ? HISTORIC_START : beginYear) : now.getYear() + 1; + int end = endYear != null ? endYear : now.getYear(); + double sum = 0; + int index = begin; + long duration = 0; + switch (type) { + case left: + if (beginYear == null) { + duration = Duration + .between(now, ZonedDateTime.of(now.getYear() + 1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) + .toSeconds(); + } + while (index < end) { + int bucketStart = index; + double value = value(index).doubleValue(); + while ((index < end - 1) && (value(index).longValue() == value(index + 1).longValue())) { + index++; + } + index++; + duration += Duration + .between(ZonedDateTime.of(bucketStart, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(index, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) + .toSeconds(); + if (endYear == null && index == end) { + duration += Duration + .between(ZonedDateTime.of(now.getYear(), 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), now) + .toSeconds(); + } + sum += value * duration; + duration = 0; + } + break; + case right: + if (beginYear == null) { + duration = Duration + .between(now, ZonedDateTime.of(now.getYear() + 1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) + .toSeconds(); + } + while (index < end) { + int bucketStart = index; + while ((index < end - 1) && (value(index).longValue() == value(index + 1).longValue())) { + index++; + } + index++; + double value = value(index).doubleValue(); + duration += Duration + .between(ZonedDateTime.of(bucketStart, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(index, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) + .toSeconds(); + if (endYear == null && index == end) { + duration += Duration + .between(ZonedDateTime.of(now.getYear(), 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), now) + .toSeconds(); + } + sum += value * duration; + duration = 0; + } + break; + case trapezoidal: + if (beginYear == null) { + duration = Duration + .between(now, ZonedDateTime.of(now.getYear() + 1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) + .toSeconds(); + } + while (index < end) { + int bucketStart = index; + double value = value(index).doubleValue(); + while ((index < end - 1) && (value(index).longValue() == value(index + 1).longValue())) { + index++; + } + index++; + value = (value + value(index).doubleValue()) / 2.0; + duration += Duration + .between(ZonedDateTime.of(bucketStart, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(index, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) + .toSeconds(); + if (endYear == null && index == end) { + duration += Duration + .between(ZonedDateTime.of(now.getYear(), 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), now) + .toSeconds(); + } + sum += value * duration; + duration = 0; + } + break; + case midpoint: + int nextIndex = begin; + long nextDuration = 0; + if (beginYear == null) { + duration = Duration + .between(now, ZonedDateTime.of(now.getYear() + 1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) + .toSeconds(); + } + while (index < end - 1 && nextIndex < end) { + int bucketStart = index; + while ((index < end - 1) && (value(index).longValue() == value(index + 1).longValue())) { + index++; + } + index++; + double value = value(index).doubleValue(); + duration += Duration + .between(ZonedDateTime.of(bucketStart, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(index, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) + .toSeconds(); + bucketStart = index; + nextIndex = index; + while ((nextIndex < end - 1) + && (value(nextIndex).longValue() == value(nextIndex + 1).longValue())) { + nextIndex++; + } + nextIndex++; + if (endYear == null && nextIndex == end) { + nextDuration = Duration + .between(ZonedDateTime.of(now.getYear(), 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), now) + .toSeconds(); + } + nextDuration += Duration + .between(ZonedDateTime.of(bucketStart, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(nextIndex, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) + .toSeconds(); + sum += value * (duration + nextDuration) / 2.0; + duration = 0; + nextDuration = 0; + } + break; + } + return sum; + } + static double average(@Nullable Integer beginYear, @Nullable Integer endYear) { ZonedDateTime now = ZonedDateTime.now(); ZonedDateTime beginDate = beginYear != null @@ -255,18 +390,8 @@ static double average(@Nullable Integer beginYear, @Nullable Integer endYear) { : now; ZonedDateTime endDate = endYear != null ? ZonedDateTime.of(endYear, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()) : now; - int begin = beginYear != null ? beginYear : now.getYear() + 1; - int end = endYear != null ? endYear : now.getYear(); - long sum = LongStream.range(begin, end).map(y -> value(y).longValue() * Duration - .between(ZonedDateTime.of(Long.valueOf(y).intValue(), 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(Long.valueOf(y + 1).intValue(), 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) - .toMillis()).sum(); - sum += beginYear == null ? value(now.getYear()).longValue() * Duration - .between(now, ZonedDateTime.of(now.getYear() + 1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())).toMillis() - : 0; - sum += endYear == null ? value(now.getYear()).longValue() * Duration - .between(ZonedDateTime.of(now.getYear(), 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), now).toMillis() : 0; - long duration = Duration.between(beginDate, endDate).toMillis(); + double sum = riemannSum(beginYear, endYear, RiemannType.left); + long duration = Duration.between(beginDate, endDate).toSeconds(); return 1.0 * sum / duration; } From efc65b053b314eb59766ff2e28f646446b2c1366 Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Fri, 22 Nov 2024 11:32:16 +0100 Subject: [PATCH 02/13] spotless Signed-off-by: Mark Herwege --- .../core/persistence/extensions/PersistenceExtensions.java | 1 - 1 file changed, 1 deletion(-) diff --git a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java index 44d0457714d..5e6cf95ae3c 100644 --- a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java +++ b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java @@ -2269,7 +2269,6 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite } return sum; - } /** From 1007ee48c199cd22e8fc6663d3300c96dc6a49f1 Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Fri, 22 Nov 2024 11:58:35 +0100 Subject: [PATCH 03/13] fix test Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensionsTest.java | 358 ++++++++++++++---- 1 file changed, 292 insertions(+), 66 deletions(-) diff --git a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java index f0a0eb724cc..688f949e827 100644 --- a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java +++ b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java @@ -1487,86 +1487,312 @@ public void testDeviationBetweenGroupQuantityType() { @Test public void testRiemannSumSinceDecimalType() { - for (RiemannType type : RiemannType.values()) { - ZonedDateTime start = ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - double expected = riemannSum(BEFORE_START, null, type); - State sum = PersistenceExtensions.riemannSumSince(numberItem, start, type, SERVICE_ID); - assertNotNull(sum); - DecimalType dt = sum.as(DecimalType.class); - assertNotNull(dt); - assertEquals(expected, dt.doubleValue(), HISTORIC_END * 1.0); // Allow max 1s difference between method and - // test - - start = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, null, type); - sum = PersistenceExtensions.riemannSumSince(numberItem, start, type, SERVICE_ID); - assertNotNull(sum); - dt = sum.as(DecimalType.class); - assertNotNull(dt); - assertEquals(expected, dt.doubleValue(), HISTORIC_END * 1.0); // Allow max 1s difference between method and - // test value + RiemannType type = RiemannType.left; - // default persistence service - sum = PersistenceExtensions.riemannSumSince(numberItem, start, type); - assertNull(sum); - } + ZonedDateTime start = ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + double expected = riemannSum(BEFORE_START, null, type); + State sum = PersistenceExtensions.riemannSumSince(numberItem, start, type, SERVICE_ID); + assertNotNull(sum); + DecimalType dt = sum.as(DecimalType.class); + assertNotNull(dt); + // Allow max 5s difference between method and test, required as both expected and method tested retrieve + // now + assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); + start = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, null, type); + sum = PersistenceExtensions.riemannSumSince(numberItem, start, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + // Allow max 5s difference between method and test, required as both expected and method tested retrieve + // now + assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); + + // default persistence service + sum = PersistenceExtensions.riemannSumSince(numberItem, start, type); + assertNull(sum); + + type = RiemannType.right; + + start = ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(BEFORE_START, null, type); + sum = PersistenceExtensions.riemannSumSince(numberItem, start, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + // Allow max 5s difference between method and test, required as both expected and method tested retrieve + // now + assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); + start = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, null, type); + sum = PersistenceExtensions.riemannSumSince(numberItem, start, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + // Allow max 5s difference between method and test, required as both expected and method tested retrieve + // now + assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); + + // default persistence service + sum = PersistenceExtensions.riemannSumSince(numberItem, start, type); + assertNull(sum); + + type = RiemannType.trapezoidal; + + start = ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(BEFORE_START, null, type); + sum = PersistenceExtensions.riemannSumSince(numberItem, start, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + // Allow max 5s difference between method and test, required as both expected and method tested retrieve + // now + assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); + start = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, null, type); + sum = PersistenceExtensions.riemannSumSince(numberItem, start, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + // Allow max 5s difference between method and test, required as both expected and method tested retrieve + // now + assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); + + // default persistence service + sum = PersistenceExtensions.riemannSumSince(numberItem, start, type); + assertNull(sum); + + type = RiemannType.midpoint; + + start = ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(BEFORE_START, null, type); + sum = PersistenceExtensions.riemannSumSince(numberItem, start, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + // Allow max 5s difference between method and test, required as both expected and method tested retrieve + // now + assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); + start = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, null, type); + sum = PersistenceExtensions.riemannSumSince(numberItem, start, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + // Allow max 1 min difference between method and test, required as both expected and method tested retrieve + // now + assertEquals(expected, dt.doubleValue(), HISTORIC_END * 60.0); + + // default persistence service + sum = PersistenceExtensions.riemannSumSince(numberItem, start, type); + assertNull(sum); } @Test public void testRiemannSumUntilDecimalType() { - for (RiemannType type : RiemannType.values()) { - ZonedDateTime end = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - double expected = riemannSum(null, FUTURE_INTERMEDIATE_VALUE_3, type); - State sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type, SERVICE_ID); - assertNotNull(sum); - DecimalType dt = sum.as(DecimalType.class); - assertNotNull(dt); - assertEquals(expected, dt.doubleValue(), HISTORIC_END * 1.0); // Allow max 1s difference between method and - // test value - // default persistence service - sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type); - assertNull(sum); - } + RiemannType type = RiemannType.left; + + ZonedDateTime end = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + double expected = riemannSum(null, FUTURE_INTERMEDIATE_VALUE_3, type); + State sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type, SERVICE_ID); + assertNotNull(sum); + DecimalType dt = sum.as(DecimalType.class); + assertNotNull(dt); + // Allow max 5s difference between method and test, required as both expected and method tested retrieve + // now + assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); + // default persistence service + sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type); + assertNull(sum); + + type = RiemannType.right; + + end = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(null, FUTURE_INTERMEDIATE_VALUE_3, type); + sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + // Allow max 5s difference between method and test, required as both expected and method tested retrieve + // now + assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); + // default persistence service + sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type); + assertNull(sum); + + type = RiemannType.trapezoidal; + + end = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(null, FUTURE_INTERMEDIATE_VALUE_3, type); + sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + // Allow max 5s difference between method and test, required as both expected and method tested retrieve + // now + assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); + // default persistence service + sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type); + assertNull(sum); + + type = RiemannType.midpoint; + + end = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(null, FUTURE_INTERMEDIATE_VALUE_3, type); + sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + // Allow max 5s difference between method and test, required as both expected and method tested retrieve + // now + assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); + // default persistence service + sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type); + assertNull(sum); } @Test public void testRiemannSumBetweenDecimalType() { - for (RiemannType type : RiemannType.values()) { - ZonedDateTime beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, - ZoneId.systemDefault()); - ZonedDateTime endStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, - ZoneId.systemDefault()); - double expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2, type); - State sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); - assertNotNull(sum); - DecimalType dt = sum.as(DecimalType.class); - assertNotNull(dt); - assertEquals(expected, dt.doubleValue(), 0.01); + RiemannType type = RiemannType.left; - beginStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - expected = riemannSum(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4, type); + ZonedDateTime beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, + ZoneId.systemDefault()); + ZonedDateTime endStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, + ZoneId.systemDefault()); + double expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2, type); + State sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + DecimalType dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertEquals(expected, dt.doubleValue(), 0.01); - sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); - assertNotNull(sum); - dt = sum.as(DecimalType.class); - assertNotNull(dt); - assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + beginStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4, type); - beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, FUTURE_INTERMEDIATE_VALUE_3, type); + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); - sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); - assertNotNull(sum); - dt = sum.as(DecimalType.class); - assertNotNull(dt); - assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, FUTURE_INTERMEDIATE_VALUE_3, type); - // default persistence service - sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type); - assertNull(sum); - } + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + + // default persistence service + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type); + assertNull(sum); + + type = RiemannType.right; + + beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + endStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2, type); + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertEquals(expected, dt.doubleValue(), 0.01); + + beginStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4, type); + + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + + beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, FUTURE_INTERMEDIATE_VALUE_3, type); + + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + + // default persistence service + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type); + assertNull(sum); + + type = RiemannType.trapezoidal; + + beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + endStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2, type); + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertEquals(expected, dt.doubleValue(), 0.01); + + beginStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4, type); + + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + + beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, FUTURE_INTERMEDIATE_VALUE_3, type); + + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + + // default persistence service + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type); + assertNull(sum); + type = RiemannType.midpoint; + + beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + endStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2, type); + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertEquals(expected, dt.doubleValue(), 0.01); + + beginStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4, type); + + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + + beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, FUTURE_INTERMEDIATE_VALUE_3, type); + + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + + // default persistence service + sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type); + assertNull(sum); } @Test From f87dd774f85bf746dd753a87ef1b46b0bdd3de76 Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Fri, 22 Nov 2024 18:07:32 +0100 Subject: [PATCH 04/13] test logging Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensionsTest.java | 47 ++++++++++++++----- .../extensions/TestPersistenceService.java | 24 +++++++--- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java index 688f949e827..15e8f47f2c4 100644 --- a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java +++ b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java @@ -54,6 +54,7 @@ import org.openhab.core.persistence.PersistenceServiceRegistry; import org.openhab.core.persistence.extensions.PersistenceExtensions.RiemannType; import org.openhab.core.types.State; +import org.slf4j.LoggerFactory; /** * @author Kai Kreuzer - Initial contribution @@ -1495,8 +1496,10 @@ public void testRiemannSumSinceDecimalType() { assertNotNull(sum); DecimalType dt = sum.as(DecimalType.class); assertNotNull(dt); + LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann since left expected {}, sum {}", + expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve - // now + // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); start = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, null, type); @@ -1504,8 +1507,10 @@ public void testRiemannSumSinceDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); + LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann since left expected {}, sum {}", + expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve - // now + // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); // default persistence service @@ -1520,8 +1525,10 @@ public void testRiemannSumSinceDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); + LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann since right expected {}, sum {}", + expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve - // now + // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); start = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, null, type); @@ -1529,8 +1536,10 @@ public void testRiemannSumSinceDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); + LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann since right expected {}, sum {}", + expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve - // now + // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); // default persistence service @@ -1545,6 +1554,8 @@ public void testRiemannSumSinceDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); + LoggerFactory.getLogger(PersistenceExtensionsTest.class) + .info("Test Riemann since trapezoidal expected {}, sum {}", expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve // now assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); @@ -1554,8 +1565,10 @@ public void testRiemannSumSinceDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); + LoggerFactory.getLogger(PersistenceExtensionsTest.class) + .info("Test Riemann since trapezoidal expected {}, sum {}", expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve - // now + // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); // default persistence service @@ -1570,8 +1583,10 @@ public void testRiemannSumSinceDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); + LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann since midpoint expected {}, sum {}", + expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve - // now + // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); start = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, null, type); @@ -1579,8 +1594,10 @@ public void testRiemannSumSinceDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); + LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann since midpoint expected {}, sum {}", + expected, sum); // Allow max 1 min difference between method and test, required as both expected and method tested retrieve - // now + // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 60.0); // default persistence service @@ -1598,8 +1615,10 @@ public void testRiemannSumUntilDecimalType() { assertNotNull(sum); DecimalType dt = sum.as(DecimalType.class); assertNotNull(dt); + LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann until left expected {}, sum {}", + expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve - // now + // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); // default persistence service sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type); @@ -1613,8 +1632,10 @@ public void testRiemannSumUntilDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); + LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann until right expected {}, sum {}", + expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve - // now + // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); // default persistence service sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type); @@ -1628,8 +1649,10 @@ public void testRiemannSumUntilDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); + LoggerFactory.getLogger(PersistenceExtensionsTest.class) + .info("Test Riemann until trapezoidal expected {}, sum {}", expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve - // now + // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); // default persistence service sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type); @@ -1643,8 +1666,10 @@ public void testRiemannSumUntilDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); + LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann until midpoint expected {}, sum {}", + expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve - // now + // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); // default persistence service sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type); diff --git a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java index 7998ecf8a83..68a2afdb794 100644 --- a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java +++ b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java @@ -44,6 +44,7 @@ import org.openhab.core.persistence.extensions.PersistenceExtensions.RiemannType; import org.openhab.core.persistence.strategy.PersistenceStrategy; import org.openhab.core.types.State; +import org.slf4j.LoggerFactory; /** * A simple persistence service used for unit tests @@ -258,6 +259,7 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, double sum = 0; int index = begin; long duration = 0; + long totalDuration = 0; switch (type) { case left: if (beginYear == null) { @@ -282,6 +284,7 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, .toSeconds(); } sum += value * duration; + totalDuration += duration; duration = 0; } break; @@ -308,6 +311,7 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, .toSeconds(); } sum += value * duration; + totalDuration += duration; duration = 0; } break; @@ -335,12 +339,15 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, .toSeconds(); } sum += value * duration; + totalDuration += duration; duration = 0; } + LoggerFactory.getLogger(TestPersistenceService.class).info("Test Riemann now {}", now); + LoggerFactory.getLogger(TestPersistenceService.class).info("Test Riemann trapezoidal total duration {}", + totalDuration); break; case midpoint: int nextIndex = begin; - long nextDuration = 0; if (beginYear == null) { duration = Duration .between(now, ZonedDateTime.of(now.getYear() + 1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) @@ -364,19 +371,22 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, nextIndex++; } nextIndex++; + long nextDuration = Duration + .between(ZonedDateTime.of(bucketStart, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(nextIndex, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) + .toSeconds(); if (endYear == null && nextIndex == end) { - nextDuration = Duration + nextDuration += Duration .between(ZonedDateTime.of(now.getYear(), 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), now) .toSeconds(); } - nextDuration += Duration - .between(ZonedDateTime.of(bucketStart, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(nextIndex, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) - .toSeconds(); sum += value * (duration + nextDuration) / 2.0; + totalDuration += (duration + nextDuration) / 2; duration = 0; - nextDuration = 0; } + LoggerFactory.getLogger(TestPersistenceService.class).info("Test Riemann now {}", now); + LoggerFactory.getLogger(TestPersistenceService.class).info("Test Riemann midpoint total duration {}", + totalDuration); break; } return sum; From 4e03495fca2bbcc23d6e00be5165f41c7239a22f Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Sat, 23 Nov 2024 18:14:17 +0100 Subject: [PATCH 05/13] more logging Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java index 5e6cf95ae3c..e21d12c7a4d 100644 --- a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java +++ b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java @@ -2180,6 +2180,8 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite if (it.hasNext() && (type == RiemannType.midpoint)) { currentItem = it.next(); prevDuration = Duration.between(begin, currentItem.getTimestamp()); + LoggerFactory.getLogger(PersistenceExtensions.class).info("Riemann midpoint init, state = {}", + getPersistedValue(currentItem, unit)); } while (it.hasNext()) { @@ -2239,6 +2241,8 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite if (!nextDuration.isZero()) { prevDuration = nextDuration; } + LoggerFactory.getLogger(PersistenceExtensions.class) + .info("Riemann midpoint, state = {}, weight = {}", currentState, weight); } } prevItem = currentItem; @@ -2246,6 +2250,9 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite break; } sum = sum.add(value.multiply(weight)); + if (type == RiemannType.midpoint) { + LoggerFactory.getLogger(PersistenceExtensions.class).info("Riemann midpoint, sum = {}", sum); + } } if (prevItem != null && type == RiemannType.left) { @@ -2261,10 +2268,14 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite if (dtState != null && prevDuration != null && !prevDuration.isZero()) { BigDecimal value = dtState.toBigDecimal(); Duration nextDuration = Duration.between(currentItem.getTimestamp(), end); + BigDecimal weight = BigDecimal.ZERO; if (!nextDuration.isZero()) { - BigDecimal weight = BigDecimal.valueOf(prevDuration.plus(nextDuration).dividedBy(2).toMillis()); + weight = BigDecimal.valueOf(prevDuration.plus(nextDuration).dividedBy(2).toMillis()); sum = sum.add(value.multiply(weight)); } + LoggerFactory.getLogger(PersistenceExtensions.class) + .info("Riemann midpoint end, state = {}, weight = {}", dtState, weight); + LoggerFactory.getLogger(PersistenceExtensions.class).info("Riemann midpoint end, sum = {}", sum); } } From 8ab147d74ec397a23a9b771c7420d72ca64a9b89 Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Sat, 23 Nov 2024 18:42:56 +0100 Subject: [PATCH 06/13] fix Riemann midpoint calculation Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 38 +++++++------------ 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java index e21d12c7a4d..a00d8e5164e 100644 --- a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java +++ b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java @@ -2174,14 +2174,13 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite @Nullable Unit unit, RiemannType type) { BigDecimal sum = BigDecimal.ZERO; HistoricItem prevItem = null; - HistoricItem currentItem = null; Duration prevDuration = null; if (it.hasNext() && (type == RiemannType.midpoint)) { - currentItem = it.next(); - prevDuration = Duration.between(begin, currentItem.getTimestamp()); + prevItem = it.next(); + prevDuration = Duration.between(begin, prevItem.getTimestamp()); LoggerFactory.getLogger(PersistenceExtensions.class).info("Riemann midpoint init, state = {}", - getPersistedValue(currentItem, unit)); + getPersistedValue(prevItem, unit)); } while (it.hasNext()) { @@ -2230,23 +2229,27 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite prevItem = nextItem; break; case midpoint: - if (currentItem != null) { - currentState = getPersistedValue(currentItem, unit); + if (prevItem != null) { + currentState = getPersistedValue(prevItem, unit); if (currentState != null && prevDuration != null) { value = currentState.toBigDecimal(); - Duration nextDuration = Duration.between(currentItem.getTimestamp(), - nextItem.getTimestamp()); + Duration nextDuration = Duration.between(prevItem.getTimestamp(), nextItem.getTimestamp()); weight = prevDuration.isZero() || nextDuration.isZero() ? BigDecimal.ZERO : BigDecimal.valueOf(prevDuration.plus(nextDuration).dividedBy(2).toMillis()); if (!nextDuration.isZero()) { prevDuration = nextDuration; + LoggerFactory.getLogger(PersistenceExtensions.class) + .info("Riemann midpoint nextDuration 0"); } LoggerFactory.getLogger(PersistenceExtensions.class) .info("Riemann midpoint, state = {}, weight = {}", currentState, weight); + } else { + LoggerFactory.getLogger(PersistenceExtensions.class).info( + "Riemann midpoint skip, state = {}, prevDuration = {}", currentState, prevDuration); + } } - prevItem = currentItem; - currentItem = nextItem; + prevItem = nextItem; break; } sum = sum.add(value.multiply(weight)); @@ -2263,21 +2266,6 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite sum = sum.add(value.multiply(weight)); } } - if (prevItem != null && currentItem != null && type == RiemannType.midpoint) { - DecimalType dtState = getPersistedValue(currentItem, unit); - if (dtState != null && prevDuration != null && !prevDuration.isZero()) { - BigDecimal value = dtState.toBigDecimal(); - Duration nextDuration = Duration.between(currentItem.getTimestamp(), end); - BigDecimal weight = BigDecimal.ZERO; - if (!nextDuration.isZero()) { - weight = BigDecimal.valueOf(prevDuration.plus(nextDuration).dividedBy(2).toMillis()); - sum = sum.add(value.multiply(weight)); - } - LoggerFactory.getLogger(PersistenceExtensions.class) - .info("Riemann midpoint end, state = {}, weight = {}", dtState, weight); - LoggerFactory.getLogger(PersistenceExtensions.class).info("Riemann midpoint end, sum = {}", sum); - } - } return sum; } From 13a18242c942fe02d2073dcf77dd85a968febb77 Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Sat, 23 Nov 2024 18:46:59 +0100 Subject: [PATCH 07/13] remove extra logging Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 13 ---------- .../extensions/PersistenceExtensionsTest.java | 25 ------------------- .../extensions/TestPersistenceService.java | 7 ------ 3 files changed, 45 deletions(-) diff --git a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java index a00d8e5164e..3bab210240b 100644 --- a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java +++ b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java @@ -2179,8 +2179,6 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite if (it.hasNext() && (type == RiemannType.midpoint)) { prevItem = it.next(); prevDuration = Duration.between(begin, prevItem.getTimestamp()); - LoggerFactory.getLogger(PersistenceExtensions.class).info("Riemann midpoint init, state = {}", - getPersistedValue(prevItem, unit)); } while (it.hasNext()) { @@ -2238,24 +2236,13 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite : BigDecimal.valueOf(prevDuration.plus(nextDuration).dividedBy(2).toMillis()); if (!nextDuration.isZero()) { prevDuration = nextDuration; - LoggerFactory.getLogger(PersistenceExtensions.class) - .info("Riemann midpoint nextDuration 0"); } - LoggerFactory.getLogger(PersistenceExtensions.class) - .info("Riemann midpoint, state = {}, weight = {}", currentState, weight); - } else { - LoggerFactory.getLogger(PersistenceExtensions.class).info( - "Riemann midpoint skip, state = {}, prevDuration = {}", currentState, prevDuration); - } } prevItem = nextItem; break; } sum = sum.add(value.multiply(weight)); - if (type == RiemannType.midpoint) { - LoggerFactory.getLogger(PersistenceExtensions.class).info("Riemann midpoint, sum = {}", sum); - } } if (prevItem != null && type == RiemannType.left) { diff --git a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java index 15e8f47f2c4..5b6c7f1c0ed 100644 --- a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java +++ b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java @@ -54,7 +54,6 @@ import org.openhab.core.persistence.PersistenceServiceRegistry; import org.openhab.core.persistence.extensions.PersistenceExtensions.RiemannType; import org.openhab.core.types.State; -import org.slf4j.LoggerFactory; /** * @author Kai Kreuzer - Initial contribution @@ -1496,8 +1495,6 @@ public void testRiemannSumSinceDecimalType() { assertNotNull(sum); DecimalType dt = sum.as(DecimalType.class); assertNotNull(dt); - LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann since left expected {}, sum {}", - expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); @@ -1507,8 +1504,6 @@ public void testRiemannSumSinceDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); - LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann since left expected {}, sum {}", - expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); @@ -1525,8 +1520,6 @@ public void testRiemannSumSinceDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); - LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann since right expected {}, sum {}", - expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); @@ -1536,8 +1529,6 @@ public void testRiemannSumSinceDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); - LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann since right expected {}, sum {}", - expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); @@ -1554,8 +1545,6 @@ public void testRiemannSumSinceDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); - LoggerFactory.getLogger(PersistenceExtensionsTest.class) - .info("Test Riemann since trapezoidal expected {}, sum {}", expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve // now assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); @@ -1565,8 +1554,6 @@ public void testRiemannSumSinceDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); - LoggerFactory.getLogger(PersistenceExtensionsTest.class) - .info("Test Riemann since trapezoidal expected {}, sum {}", expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); @@ -1583,8 +1570,6 @@ public void testRiemannSumSinceDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); - LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann since midpoint expected {}, sum {}", - expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); @@ -1594,8 +1579,6 @@ public void testRiemannSumSinceDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); - LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann since midpoint expected {}, sum {}", - expected, sum); // Allow max 1 min difference between method and test, required as both expected and method tested retrieve // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 60.0); @@ -1615,8 +1598,6 @@ public void testRiemannSumUntilDecimalType() { assertNotNull(sum); DecimalType dt = sum.as(DecimalType.class); assertNotNull(dt); - LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann until left expected {}, sum {}", - expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); @@ -1632,8 +1613,6 @@ public void testRiemannSumUntilDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); - LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann until right expected {}, sum {}", - expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); @@ -1649,8 +1628,6 @@ public void testRiemannSumUntilDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); - LoggerFactory.getLogger(PersistenceExtensionsTest.class) - .info("Test Riemann until trapezoidal expected {}, sum {}", expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); @@ -1666,8 +1643,6 @@ public void testRiemannSumUntilDecimalType() { assertNotNull(sum); dt = sum.as(DecimalType.class); assertNotNull(dt); - LoggerFactory.getLogger(PersistenceExtensionsTest.class).info("Test Riemann until midpoint expected {}, sum {}", - expected, sum); // Allow max 5s difference between method and test, required as both expected and method tested retrieve // now from system assertEquals(expected, dt.doubleValue(), HISTORIC_END * 5.0); diff --git a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java index 68a2afdb794..800cf900f21 100644 --- a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java +++ b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java @@ -44,7 +44,6 @@ import org.openhab.core.persistence.extensions.PersistenceExtensions.RiemannType; import org.openhab.core.persistence.strategy.PersistenceStrategy; import org.openhab.core.types.State; -import org.slf4j.LoggerFactory; /** * A simple persistence service used for unit tests @@ -342,9 +341,6 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, totalDuration += duration; duration = 0; } - LoggerFactory.getLogger(TestPersistenceService.class).info("Test Riemann now {}", now); - LoggerFactory.getLogger(TestPersistenceService.class).info("Test Riemann trapezoidal total duration {}", - totalDuration); break; case midpoint: int nextIndex = begin; @@ -384,9 +380,6 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, totalDuration += (duration + nextDuration) / 2; duration = 0; } - LoggerFactory.getLogger(TestPersistenceService.class).info("Test Riemann now {}", now); - LoggerFactory.getLogger(TestPersistenceService.class).info("Test Riemann midpoint total duration {}", - totalDuration); break; } return sum; From 4b86ac237e08bfbc8602f646299f4bbf615c788f Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Sat, 23 Nov 2024 22:27:50 +0100 Subject: [PATCH 08/13] midpoint first and last bucket improvements Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 46 +++++++++++++------ .../extensions/PersistenceExtensionsTest.java | 1 + .../extensions/TestPersistenceService.java | 27 +++++++---- 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java index 3bab210240b..98f145511ab 100644 --- a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java +++ b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java @@ -2174,20 +2174,24 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite @Nullable Unit unit, RiemannType type) { BigDecimal sum = BigDecimal.ZERO; HistoricItem prevItem = null; - Duration prevDuration = null; - - if (it.hasNext() && (type == RiemannType.midpoint)) { + HistoricItem nextItem = null; + DecimalType prevState = null; + DecimalType nextState = null; + Duration prevDuration = Duration.ZERO; + Duration nextDuration = Duration.ZERO; + + boolean midpointStartBucket = true; // The start and end buckets for the midpoint calculation should be + // considered for the full length, this flag is used to find the start + // bucket + if ((type == RiemannType.midpoint) && it.hasNext()) { prevItem = it.next(); - prevDuration = Duration.between(begin, prevItem.getTimestamp()); + prevState = getPersistedValue(prevItem, unit); } while (it.hasNext()) { - HistoricItem nextItem = it.next(); + nextItem = it.next(); BigDecimal weight = BigDecimal.ZERO; BigDecimal value = BigDecimal.ZERO; - DecimalType prevState; - DecimalType currentState; - DecimalType nextState; switch (type) { case left: if (prevItem != null) { @@ -2228,15 +2232,28 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite break; case midpoint: if (prevItem != null) { - currentState = getPersistedValue(prevItem, unit); - if (currentState != null && prevDuration != null) { + DecimalType currentState = getPersistedValue(prevItem, unit); + if (currentState != null) { value = currentState.toBigDecimal(); - Duration nextDuration = Duration.between(prevItem.getTimestamp(), nextItem.getTimestamp()); + if (midpointStartBucket && !prevDuration.isZero() && prevState != null) { + // Add half of the start bucket with the start value (left approximation) + sum = sum.add(prevState.toBigDecimal() + .multiply(BigDecimal.valueOf(prevDuration.dividedBy(2).toMillis()))); + midpointStartBucket = false; + LoggerFactory.getLogger(PersistenceExtensions.class).info( + "Start sum {}, value {}, duration {}", sum, prevState.doubleValue(), + prevDuration.dividedBy(2).toSeconds()); + } + nextDuration = Duration.between(prevItem.getTimestamp(), nextItem.getTimestamp()); weight = prevDuration.isZero() || nextDuration.isZero() ? BigDecimal.ZERO : BigDecimal.valueOf(prevDuration.plus(nextDuration).dividedBy(2).toMillis()); + LoggerFactory.getLogger(PersistenceExtensions.class).info( + "... sum {}, value {}, duration {}", sum.add(value.multiply(weight)), value, + prevDuration.plus(nextDuration).dividedBy(2).toSeconds()); if (!nextDuration.isZero()) { prevDuration = nextDuration; } + prevState = currentState; } } prevItem = nextItem; @@ -2245,12 +2262,15 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite sum = sum.add(value.multiply(weight)); } - if (prevItem != null && type == RiemannType.left) { + if ((type == RiemannType.midpoint) && (prevItem != null)) { + // Add half of the end bucket with the end value (right approximation) DecimalType dtState = getPersistedValue(prevItem, unit); if (dtState != null) { BigDecimal value = dtState.toBigDecimal(); - BigDecimal weight = BigDecimal.valueOf(Duration.between(prevItem.getTimestamp(), end).toMillis()); + BigDecimal weight = BigDecimal.valueOf(prevDuration.dividedBy(2).toMillis()); sum = sum.add(value.multiply(weight)); + LoggerFactory.getLogger(PersistenceExtensions.class).info("End sum {}, value {}, duration {}", sum, + value, prevDuration.dividedBy(2).toSeconds()); } } diff --git a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java index 5b6c7f1c0ed..03848cd0832 100644 --- a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java +++ b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java @@ -1759,6 +1759,7 @@ public void testRiemannSumBetweenDecimalType() { // default persistence service sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type); assertNull(sum); + type = RiemannType.midpoint; beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); diff --git a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java index 800cf900f21..ae82849f217 100644 --- a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java +++ b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java @@ -44,6 +44,7 @@ import org.openhab.core.persistence.extensions.PersistenceExtensions.RiemannType; import org.openhab.core.persistence.strategy.PersistenceStrategy; import org.openhab.core.types.State; +import org.slf4j.LoggerFactory; /** * A simple persistence service used for unit tests @@ -258,7 +259,7 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, double sum = 0; int index = begin; long duration = 0; - long totalDuration = 0; + long nextDuration = 0; switch (type) { case left: if (beginYear == null) { @@ -283,7 +284,6 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, .toSeconds(); } sum += value * duration; - totalDuration += duration; duration = 0; } break; @@ -310,7 +310,6 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, .toSeconds(); } sum += value * duration; - totalDuration += duration; duration = 0; } break; @@ -338,15 +337,15 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, .toSeconds(); } sum += value * duration; - totalDuration += duration; duration = 0; } break; case midpoint: int nextIndex = begin; + boolean startBucket = true; + double startValue = value(begin).doubleValue(); if (beginYear == null) { - duration = Duration - .between(now, ZonedDateTime.of(now.getYear() + 1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) + duration = Duration.between(now, ZonedDateTime.of(begin, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) .toSeconds(); } while (index < end - 1 && nextIndex < end) { @@ -360,6 +359,12 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, .between(ZonedDateTime.of(bucketStart, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), ZonedDateTime.of(index, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) .toSeconds(); + if (startBucket) { + sum += startValue * duration / 2.0; + LoggerFactory.getLogger(TestPersistenceService.class) + .info("Start sum {}, value {}, duration {}", sum, startValue, duration / 2.0); + startBucket = false; + } bucketStart = index; nextIndex = index; while ((nextIndex < end - 1) @@ -367,7 +372,7 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, nextIndex++; } nextIndex++; - long nextDuration = Duration + nextDuration = Duration .between(ZonedDateTime.of(bucketStart, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), ZonedDateTime.of(nextIndex, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) .toSeconds(); @@ -377,9 +382,15 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, .toSeconds(); } sum += value * (duration + nextDuration) / 2.0; - totalDuration += (duration + nextDuration) / 2; + LoggerFactory.getLogger(TestPersistenceService.class).info("... sum {}, value {}, duration {}", + sum, value, (duration + nextDuration) / 2.0); duration = 0; } + double endValue = value(end).doubleValue(); + long endDuration = nextDuration; + sum += endValue * endDuration / 2.0; + LoggerFactory.getLogger(TestPersistenceService.class).info("End sum {}, value {}, duration {}", sum, + endValue, endDuration / 2.0); break; } return sum; From 3272222e59219caa8fb35d6b0a0f64fcd6d7b99f Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Sat, 23 Nov 2024 22:43:04 +0100 Subject: [PATCH 09/13] remove extra logging Signed-off-by: Mark Herwege --- .../persistence/extensions/PersistenceExtensions.java | 8 -------- .../persistence/extensions/TestPersistenceService.java | 7 ------- 2 files changed, 15 deletions(-) diff --git a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java index 98f145511ab..9a2429a3777 100644 --- a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java +++ b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java @@ -2240,16 +2240,10 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite sum = sum.add(prevState.toBigDecimal() .multiply(BigDecimal.valueOf(prevDuration.dividedBy(2).toMillis()))); midpointStartBucket = false; - LoggerFactory.getLogger(PersistenceExtensions.class).info( - "Start sum {}, value {}, duration {}", sum, prevState.doubleValue(), - prevDuration.dividedBy(2).toSeconds()); } nextDuration = Duration.between(prevItem.getTimestamp(), nextItem.getTimestamp()); weight = prevDuration.isZero() || nextDuration.isZero() ? BigDecimal.ZERO : BigDecimal.valueOf(prevDuration.plus(nextDuration).dividedBy(2).toMillis()); - LoggerFactory.getLogger(PersistenceExtensions.class).info( - "... sum {}, value {}, duration {}", sum.add(value.multiply(weight)), value, - prevDuration.plus(nextDuration).dividedBy(2).toSeconds()); if (!nextDuration.isZero()) { prevDuration = nextDuration; } @@ -2269,8 +2263,6 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite BigDecimal value = dtState.toBigDecimal(); BigDecimal weight = BigDecimal.valueOf(prevDuration.dividedBy(2).toMillis()); sum = sum.add(value.multiply(weight)); - LoggerFactory.getLogger(PersistenceExtensions.class).info("End sum {}, value {}, duration {}", sum, - value, prevDuration.dividedBy(2).toSeconds()); } } diff --git a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java index ae82849f217..ca2b5a8d39e 100644 --- a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java +++ b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java @@ -44,7 +44,6 @@ import org.openhab.core.persistence.extensions.PersistenceExtensions.RiemannType; import org.openhab.core.persistence.strategy.PersistenceStrategy; import org.openhab.core.types.State; -import org.slf4j.LoggerFactory; /** * A simple persistence service used for unit tests @@ -361,8 +360,6 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, .toSeconds(); if (startBucket) { sum += startValue * duration / 2.0; - LoggerFactory.getLogger(TestPersistenceService.class) - .info("Start sum {}, value {}, duration {}", sum, startValue, duration / 2.0); startBucket = false; } bucketStart = index; @@ -382,15 +379,11 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, .toSeconds(); } sum += value * (duration + nextDuration) / 2.0; - LoggerFactory.getLogger(TestPersistenceService.class).info("... sum {}, value {}, duration {}", - sum, value, (duration + nextDuration) / 2.0); duration = 0; } double endValue = value(end).doubleValue(); long endDuration = nextDuration; sum += endValue * endDuration / 2.0; - LoggerFactory.getLogger(TestPersistenceService.class).info("End sum {}, value {}, duration {}", sum, - endValue, endDuration / 2.0); break; } return sum; From 4c9dd597cd71518fe391ac7fdaeaedb12dd36de3 Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Mon, 25 Nov 2024 09:11:38 +0100 Subject: [PATCH 10/13] RiemannType constants uppercase Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 116 +++++++++--------- .../extensions/PersistenceExtensionsTest.java | 28 ++--- .../extensions/TestPersistenceService.java | 10 +- 3 files changed, 77 insertions(+), 77 deletions(-) diff --git a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java index 9a2429a3777..5ee8603ba4c 100644 --- a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java +++ b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java @@ -77,10 +77,10 @@ public class PersistenceExtensions { private static @Nullable TimeZoneProvider timeZoneProvider; public static enum RiemannType { - left, - midpoint, - right, - trapezoidal + LEFT, + MIDPOINT, + RIGHT, + TRAPEZOIDAL } @Activate @@ -1155,7 +1155,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * if there is no persisted state for the given item at the given timestamp */ public static @Nullable State varianceSince(Item item, ZonedDateTime timestamp) { - return internalVarianceBetween(item, timestamp, null, RiemannType.left, null); + return internalVarianceBetween(item, timestamp, null, RiemannType.LEFT, null); } /** @@ -1164,7 +1164,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * * @param item the {@link Item} to get the variance for * @param timestamp the point in time from which to compute the variance - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @return the variance between then and now, or null if timestamp is in the future, if * there is no default persistence service available, or it is not a {@link QueryablePersistenceService}, or * if there is no persisted state for the given item at the given timestamp @@ -1185,7 +1185,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * if there is no persisted state for the given item at the given timestamp */ public static @Nullable State varianceUntil(Item item, ZonedDateTime timestamp) { - return internalVarianceBetween(item, null, timestamp, RiemannType.left, null); + return internalVarianceBetween(item, null, timestamp, RiemannType.LEFT, null); } /** @@ -1194,7 +1194,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * * @param item the {@link Item} to get the variance for * @param timestamp the point in time to which to compute the variance - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @return the variance between now and then, or null if timestamp is in the past, if * there is no default persistence service available, or it is not a {@link QueryablePersistenceService}, or * if there is no persisted state for the given item at the given timestamp @@ -1220,7 +1220,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable */ public static @Nullable State varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end, @Nullable String serviceId) { - return internalVarianceBetween(item, begin, end, RiemannType.left, serviceId); + return internalVarianceBetween(item, begin, end, RiemannType.LEFT, serviceId); } /** @@ -1230,7 +1230,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * @param item the {@link Item} to get the variance for * @param begin the point in time from which to compute the variance * @param end the end time for the computation - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @return the variance between both points of time, or null if begin is after * end, if there is no default persistence service available, or it is not a * {@link QueryablePersistenceService}, or if there is no persisted state for the @@ -1254,7 +1254,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State varianceSince(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalVarianceBetween(item, timestamp, null, RiemannType.left, serviceId); + return internalVarianceBetween(item, timestamp, null, RiemannType.LEFT, serviceId); } /** @@ -1263,7 +1263,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * * @param item the {@link Item} to get the variance for * @param timestamp the point in time from which to compute the variance - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @param serviceId the name of the {@link PersistenceService} to use * @return the variance between then and now, or null if timestamp is in the future, if * the persistence service given by serviceId is not available, or it is not a @@ -1289,7 +1289,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State varianceUntil(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalVarianceBetween(item, null, timestamp, RiemannType.left, serviceId); + return internalVarianceBetween(item, null, timestamp, RiemannType.LEFT, serviceId); } /** @@ -1298,7 +1298,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * * @param item the {@link Item} to get the variance for * @param timestamp the point in time to which to compute the variance - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @param serviceId the name of the {@link PersistenceService} to use * @return the variance between now and then, or null if timestamp is in the past, if the * persistence service given by serviceId is not available, or it is not a @@ -1324,7 +1324,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * given item between begin and end */ public static @Nullable State varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return internalVarianceBetween(item, begin, end, RiemannType.left, null); + return internalVarianceBetween(item, begin, end, RiemannType.LEFT, null); } /** @@ -1334,7 +1334,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * @param item the {@link Item} to get the variance for * @param begin the point in time from which to compute * @param end the end time for the computation - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @param serviceId the name of the {@link PersistenceService} to use * @return the variance between both points of time, or null if begin is after * end, if the persistence service given by @@ -1406,7 +1406,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State deviationSince(Item item, ZonedDateTime timestamp) { - return internalDeviationBetween(item, timestamp, null, RiemannType.left, null); + return internalDeviationBetween(item, timestamp, null, RiemannType.LEFT, null); } /** @@ -1418,7 +1418,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * * @param item the {@link Item} to get the standard deviation for * @param timestamp the point in time from which to compute the standard deviation - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @return the standard deviation between then and now, or null if timestamp is in the * future, if there is no default persistence service available, or it is not a * {@link QueryablePersistenceService}, or if there is no persisted state for the given item at @@ -1444,7 +1444,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State deviationUntil(Item item, ZonedDateTime timestamp) { - return internalDeviationBetween(item, timestamp, null, RiemannType.left, null); + return internalDeviationBetween(item, timestamp, null, RiemannType.LEFT, null); } /** @@ -1456,7 +1456,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * * @param item the {@link Item} to get the standard deviation for * @param timestamp the point in time to which to compute the standard deviation - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @return the standard deviation between now and then, or null if timestamp is in the * past, if there is no default persistence service available, or it is not a * {@link QueryablePersistenceService}, or if there is no persisted state for the given item at @@ -1483,7 +1483,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * given item between begin and end */ public static @Nullable State deviationBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return internalDeviationBetween(item, begin, end, RiemannType.left, null); + return internalDeviationBetween(item, begin, end, RiemannType.LEFT, null); } /** @@ -1496,7 +1496,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * @param item the {@link Item} to get the standard deviation for * @param begin the point in time from which to compute * @param end the end time for the computation - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @return the standard deviation between both points of time, or null if begin is after * end, if there is no default persistence service available, or it is not a * {@link QueryablePersistenceService}, or if there is no persisted state for the @@ -1524,7 +1524,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State deviationSince(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalDeviationBetween(item, timestamp, null, RiemannType.left, serviceId); + return internalDeviationBetween(item, timestamp, null, RiemannType.LEFT, serviceId); } /** @@ -1536,7 +1536,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * * @param item the {@link Item} to get the standard deviation for * @param timestamp the point in time from which to compute the standard deviation - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @param serviceId the name of the {@link PersistenceService} to use * @return the standard deviation between then and now, or null if timestamp is in the * future, if the persistence service given by serviceId is not available, or it is not a @@ -1565,7 +1565,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State deviationUntil(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalDeviationBetween(item, null, timestamp, RiemannType.left, serviceId); + return internalDeviationBetween(item, null, timestamp, RiemannType.LEFT, serviceId); } /** @@ -1577,7 +1577,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * * @param item the {@link Item} to get the standard deviation for * @param timestamp the point in time to which to compute the standard deviation - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @param serviceId the name of the {@link PersistenceService} to use * @return the standard deviation between now and then, or null if timestamp is in the * past, if the persistence service given by serviceId is not available, or it is not a @@ -1609,7 +1609,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable */ public static @Nullable State deviationBetween(Item item, ZonedDateTime begin, ZonedDateTime end, @Nullable String serviceId) { - return internalDeviationBetween(item, begin, end, RiemannType.left, serviceId); + return internalDeviationBetween(item, begin, end, RiemannType.LEFT, serviceId); } /** @@ -1622,7 +1622,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * @param item the {@link Item} to get the standard deviation for * @param begin the point in time from which to compute * @param end the end time for the computation - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @param serviceId the name of the {@link PersistenceService} to use * @return the standard deviation between both points of time, or null if begin is after * end, if the persistence service given by @@ -1673,7 +1673,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}. The current state is included in the calculation. */ public static @Nullable State averageSince(Item item, ZonedDateTime timestamp) { - return internalAverageBetween(item, timestamp, null, RiemannType.left, null); + return internalAverageBetween(item, timestamp, null, RiemannType.LEFT, null); } /** @@ -1682,7 +1682,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * * @param item the {@link Item} to get the average value for * @param timestamp the point in time from which to search for the average value - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @return the average value since timestamp or null if no * previous states could be found or if the default persistence service does not refer to an available * {@link QueryablePersistenceService}. The current state is included in the calculation. @@ -1703,7 +1703,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}. The current state is included in the calculation. */ public static @Nullable State averageUntil(Item item, ZonedDateTime timestamp) { - return internalAverageBetween(item, null, timestamp, RiemannType.left, null); + return internalAverageBetween(item, null, timestamp, RiemannType.LEFT, null); } /** @@ -1712,7 +1712,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * * @param item the {@link Item} to get the average value for * @param timestamp the point in time to which to search for the average value - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @return the average value until timestamp or null if no * future states could be found or if the default persistence service does not refer to an available * {@link QueryablePersistenceService}. The current state is included in the calculation. @@ -1734,7 +1734,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}. */ public static @Nullable State averageBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return internalAverageBetween(item, begin, end, RiemannType.left, null); + return internalAverageBetween(item, begin, end, RiemannType.LEFT, null); } /** @@ -1744,7 +1744,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * @param item the {@link Item} to get the average value for * @param begin the point in time from which to start the summation * @param end the point in time to which to start the summation - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @return the average value between begin and end or null if no * states could be found or if the default persistence service does not refer to an available * {@link QueryablePersistenceService}. @@ -1767,7 +1767,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * calculation. */ public static @Nullable State averageSince(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalAverageBetween(item, timestamp, null, RiemannType.left, serviceId); + return internalAverageBetween(item, timestamp, null, RiemannType.LEFT, serviceId); } /** @@ -1776,7 +1776,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * * @param item the {@link Item} to get the average value for * @param timestamp the point in time from which to search for the average value - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @param serviceId the name of the {@link PersistenceService} to use * @return the average value since timestamp, or null if no * previous states could be found or if the persistence service given by serviceId does not @@ -1802,7 +1802,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * calculation. */ public static @Nullable State averageUntil(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalAverageBetween(item, null, timestamp, RiemannType.left, serviceId); + return internalAverageBetween(item, null, timestamp, RiemannType.LEFT, serviceId); } /** @@ -1811,7 +1811,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * * @param item the {@link Item} to get the average value for * @param timestamp the point in time to which to search for the average value - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @param serviceId the name of the {@link PersistenceService} to use * @return the average value until timestamp, or null if no * future states could be found or if the persistence service given by serviceId does not @@ -1838,7 +1838,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable */ public static @Nullable State averageBetween(Item item, ZonedDateTime begin, ZonedDateTime end, @Nullable String serviceId) { - return internalAverageBetween(item, begin, end, RiemannType.left, serviceId); + return internalAverageBetween(item, begin, end, RiemannType.LEFT, serviceId); } /** @@ -1848,7 +1848,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * @param item the {@link Item} to get the average value for * @param begin the point in time from which to start the summation * @param end the point in time to which to start the summation - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @param serviceId the name of the {@link PersistenceService} to use * @return the average value between begin and end, or null if no * states could be found or if the persistence service given by serviceId does not @@ -1917,7 +1917,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}. The current state is included in the calculation. */ public static @Nullable State riemannSumSince(Item item, ZonedDateTime timestamp) { - return internalRiemannSumBetween(item, timestamp, null, RiemannType.left, null); + return internalRiemannSumBetween(item, timestamp, null, RiemannType.LEFT, null); } /** @@ -1929,7 +1929,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * * @param item the {@link Item} to get the riemannSum value for * @param timestamp the point in time from which to search for the riemannSum value - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @return the Riemann sum since timestamp or null if no * previous states could be found or if the default persistence service does not refer to an available * {@link QueryablePersistenceService}. The current state is included in the calculation. @@ -1953,7 +1953,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}. The current state is included in the calculation. */ public static @Nullable State riemannSumUntil(Item item, ZonedDateTime timestamp) { - return internalRiemannSumBetween(item, null, timestamp, RiemannType.left, null); + return internalRiemannSumBetween(item, null, timestamp, RiemannType.LEFT, null); } /** @@ -1965,7 +1965,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * * @param item the {@link Item} to get the riemannSum value for * @param timestamp the point in time to which to search for the riemannSum value - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @return the Riemann sum until timestamp or null if no * future states could be found or if the default persistence service does not refer to an available * {@link QueryablePersistenceService}. The current state is included in the calculation. @@ -1990,7 +1990,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}. */ public static @Nullable State riemannSumBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return internalRiemannSumBetween(item, begin, end, RiemannType.left, null); + return internalRiemannSumBetween(item, begin, end, RiemannType.LEFT, null); } /** @@ -2003,7 +2003,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * @param item the {@link Item} to get the riemannSum value for * @param begin the point in time from which to start the summation * @param end the point in time to which to start the summation - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @return the Riemann sum between begin and end or null if no * states could be found or if the default persistence service does not refer to an available * {@link QueryablePersistenceService}. @@ -2030,7 +2030,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * calculation. */ public static @Nullable State riemannSumSince(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalRiemannSumBetween(item, timestamp, null, RiemannType.left, serviceId); + return internalRiemannSumBetween(item, timestamp, null, RiemannType.LEFT, serviceId); } /** @@ -2042,7 +2042,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * * @param item the {@link Item} to get the riemannSum value for * @param timestamp the point in time from which to search for the riemannSum value - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @param serviceId the name of the {@link PersistenceService} to use * @return the Riemann sum since timestamp, or null if no * previous states could be found or if the persistence service given by serviceId does not @@ -2071,7 +2071,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * calculation. */ public static @Nullable State riemannSumUntil(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalRiemannSumBetween(item, null, timestamp, RiemannType.left, serviceId); + return internalRiemannSumBetween(item, null, timestamp, RiemannType.LEFT, serviceId); } /** @@ -2083,7 +2083,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * * @param item the {@link Item} to get the riemannSum value for * @param timestamp the point in time to which to search for the riemannSum value - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @param serviceId the name of the {@link PersistenceService} to use * @return the Riemann sum until timestamp, or null if no * future states could be found or if the persistence service given by serviceId does not @@ -2113,7 +2113,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable */ public static @Nullable State riemannSumBetween(Item item, ZonedDateTime begin, ZonedDateTime end, @Nullable String serviceId) { - return internalRiemannSumBetween(item, begin, end, RiemannType.left, serviceId); + return internalRiemannSumBetween(item, begin, end, RiemannType.LEFT, serviceId); } /** @@ -2126,7 +2126,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * @param item the {@link Item} to get the riemannSum value for * @param begin the point in time from which to start the summation * @param end the point in time to which to start the summation - * @param type left, right, midpoint or trapezoidal representing approximation types for Riemann sums + * @param type LEFT, RIGHT, MIDPOINT or TRAPEZOIDAL representing approximation types for Riemann sums * @param serviceId the name of the {@link PersistenceService} to use * @return the Riemann sum between begin and end, or null if no * states could be found or if the persistence service given by serviceId does not @@ -2183,7 +2183,7 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite boolean midpointStartBucket = true; // The start and end buckets for the midpoint calculation should be // considered for the full length, this flag is used to find the start // bucket - if ((type == RiemannType.midpoint) && it.hasNext()) { + if ((type == RiemannType.MIDPOINT) && it.hasNext()) { prevItem = it.next(); prevState = getPersistedValue(prevItem, unit); } @@ -2193,7 +2193,7 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite BigDecimal weight = BigDecimal.ZERO; BigDecimal value = BigDecimal.ZERO; switch (type) { - case left: + case LEFT: if (prevItem != null) { prevState = getPersistedValue(prevItem, unit); if (prevState != null) { @@ -2204,7 +2204,7 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite } prevItem = nextItem; break; - case right: + case RIGHT: nextState = getPersistedValue(nextItem, unit); if (nextState != null) { value = nextState.toBigDecimal(); @@ -2217,7 +2217,7 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite } prevItem = nextItem; break; - case trapezoidal: + case TRAPEZOIDAL: if (prevItem != null) { prevState = getPersistedValue(prevItem, unit); nextState = getPersistedValue(nextItem, unit); @@ -2230,7 +2230,7 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite } prevItem = nextItem; break; - case midpoint: + case MIDPOINT: if (prevItem != null) { DecimalType currentState = getPersistedValue(prevItem, unit); if (currentState != null) { @@ -2256,7 +2256,7 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite sum = sum.add(value.multiply(weight)); } - if ((type == RiemannType.midpoint) && (prevItem != null)) { + if ((type == RiemannType.MIDPOINT) && (prevItem != null)) { // Add half of the end bucket with the end value (right approximation) DecimalType dtState = getPersistedValue(prevItem, unit); if (dtState != null) { diff --git a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java index 03848cd0832..ba4a5bc39a9 100644 --- a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java +++ b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java @@ -1487,7 +1487,7 @@ public void testDeviationBetweenGroupQuantityType() { @Test public void testRiemannSumSinceDecimalType() { - RiemannType type = RiemannType.left; + RiemannType type = RiemannType.LEFT; ZonedDateTime start = ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); double expected = riemannSum(BEFORE_START, null, type); @@ -1512,7 +1512,7 @@ public void testRiemannSumSinceDecimalType() { sum = PersistenceExtensions.riemannSumSince(numberItem, start, type); assertNull(sum); - type = RiemannType.right; + type = RiemannType.RIGHT; start = ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); expected = riemannSum(BEFORE_START, null, type); @@ -1537,7 +1537,7 @@ public void testRiemannSumSinceDecimalType() { sum = PersistenceExtensions.riemannSumSince(numberItem, start, type); assertNull(sum); - type = RiemannType.trapezoidal; + type = RiemannType.TRAPEZOIDAL; start = ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); expected = riemannSum(BEFORE_START, null, type); @@ -1562,7 +1562,7 @@ public void testRiemannSumSinceDecimalType() { sum = PersistenceExtensions.riemannSumSince(numberItem, start, type); assertNull(sum); - type = RiemannType.midpoint; + type = RiemannType.MIDPOINT; start = ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); expected = riemannSum(BEFORE_START, null, type); @@ -1590,7 +1590,7 @@ public void testRiemannSumSinceDecimalType() { @Test public void testRiemannSumUntilDecimalType() { - RiemannType type = RiemannType.left; + RiemannType type = RiemannType.LEFT; ZonedDateTime end = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); double expected = riemannSum(null, FUTURE_INTERMEDIATE_VALUE_3, type); @@ -1605,7 +1605,7 @@ public void testRiemannSumUntilDecimalType() { sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type); assertNull(sum); - type = RiemannType.right; + type = RiemannType.RIGHT; end = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); expected = riemannSum(null, FUTURE_INTERMEDIATE_VALUE_3, type); @@ -1620,7 +1620,7 @@ public void testRiemannSumUntilDecimalType() { sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type); assertNull(sum); - type = RiemannType.trapezoidal; + type = RiemannType.TRAPEZOIDAL; end = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); expected = riemannSum(null, FUTURE_INTERMEDIATE_VALUE_3, type); @@ -1635,7 +1635,7 @@ public void testRiemannSumUntilDecimalType() { sum = PersistenceExtensions.riemannSumUntil(numberItem, end, type); assertNull(sum); - type = RiemannType.midpoint; + type = RiemannType.MIDPOINT; end = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); expected = riemannSum(null, FUTURE_INTERMEDIATE_VALUE_3, type); @@ -1653,7 +1653,7 @@ public void testRiemannSumUntilDecimalType() { @Test public void testRiemannSumBetweenDecimalType() { - RiemannType type = RiemannType.left; + RiemannType type = RiemannType.LEFT; ZonedDateTime beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); @@ -1690,7 +1690,7 @@ public void testRiemannSumBetweenDecimalType() { sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type); assertNull(sum); - type = RiemannType.right; + type = RiemannType.RIGHT; beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); endStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); @@ -1725,7 +1725,7 @@ public void testRiemannSumBetweenDecimalType() { sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type); assertNull(sum); - type = RiemannType.trapezoidal; + type = RiemannType.TRAPEZOIDAL; beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); endStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); @@ -1760,7 +1760,7 @@ public void testRiemannSumBetweenDecimalType() { sum = PersistenceExtensions.riemannSumBetween(numberItem, beginStored, endStored, type); assertNull(sum); - type = RiemannType.midpoint; + type = RiemannType.MIDPOINT; beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); endStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); @@ -1845,7 +1845,7 @@ public void testRiemannSumBetweenQuantityType() { @Test public void testRiemannSumSinceDecimalTypeIrregularTimespans() { - RiemannType type = RiemannType.left; + RiemannType type = RiemannType.LEFT; ZonedDateTime now = ZonedDateTime.now(); int historicHours = 27; @@ -1877,7 +1877,7 @@ public void testRiemannSumSinceDecimalTypeIrregularTimespans() { @Test public void testRiemannSumUntilDecimalTypeIrregularTimespans() { - RiemannType type = RiemannType.left; + RiemannType type = RiemannType.LEFT; ZonedDateTime now = ZonedDateTime.now(); int historicHours = 0; diff --git a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java index ca2b5a8d39e..3a49461ba2d 100644 --- a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java +++ b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java @@ -260,7 +260,7 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, long duration = 0; long nextDuration = 0; switch (type) { - case left: + case LEFT: if (beginYear == null) { duration = Duration .between(now, ZonedDateTime.of(now.getYear() + 1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) @@ -286,7 +286,7 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, duration = 0; } break; - case right: + case RIGHT: if (beginYear == null) { duration = Duration .between(now, ZonedDateTime.of(now.getYear() + 1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) @@ -312,7 +312,7 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, duration = 0; } break; - case trapezoidal: + case TRAPEZOIDAL: if (beginYear == null) { duration = Duration .between(now, ZonedDateTime.of(now.getYear() + 1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) @@ -339,7 +339,7 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, duration = 0; } break; - case midpoint: + case MIDPOINT: int nextIndex = begin; boolean startBucket = true; double startValue = value(begin).doubleValue(); @@ -397,7 +397,7 @@ static double average(@Nullable Integer beginYear, @Nullable Integer endYear) { : now; ZonedDateTime endDate = endYear != null ? ZonedDateTime.of(endYear, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()) : now; - double sum = riemannSum(beginYear, endYear, RiemannType.left); + double sum = riemannSum(beginYear, endYear, RiemannType.LEFT); long duration = Duration.between(beginDate, endDate).toSeconds(); return 1.0 * sum / duration; } From d2ca5aabc7b24486c7b1f20a41d6d8b62fb90f3c Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Sat, 30 Nov 2024 12:20:16 +0100 Subject: [PATCH 11/13] allow RiemannType null in method call Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 124 +++++++++--------- 1 file changed, 64 insertions(+), 60 deletions(-) diff --git a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java index 5ee8603ba4c..e2f385b488c 100644 --- a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java +++ b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java @@ -1155,7 +1155,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * if there is no persisted state for the given item at the given timestamp */ public static @Nullable State varianceSince(Item item, ZonedDateTime timestamp) { - return internalVarianceBetween(item, timestamp, null, RiemannType.LEFT, null); + return internalVarianceBetween(item, timestamp, null, null, null); } /** @@ -1169,7 +1169,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * there is no default persistence service available, or it is not a {@link QueryablePersistenceService}, or * if there is no persisted state for the given item at the given timestamp */ - public static @Nullable State varianceSince(Item item, ZonedDateTime timestamp, RiemannType type) { + public static @Nullable State varianceSince(Item item, ZonedDateTime timestamp, @Nullable RiemannType type) { return internalVarianceBetween(item, timestamp, null, type, null); } @@ -1185,7 +1185,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * if there is no persisted state for the given item at the given timestamp */ public static @Nullable State varianceUntil(Item item, ZonedDateTime timestamp) { - return internalVarianceBetween(item, null, timestamp, RiemannType.LEFT, null); + return internalVarianceBetween(item, null, timestamp, null, null); } /** @@ -1199,7 +1199,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * there is no default persistence service available, or it is not a {@link QueryablePersistenceService}, or * if there is no persisted state for the given item at the given timestamp */ - public static @Nullable State varianceUntil(Item item, ZonedDateTime timestamp, RiemannType type) { + public static @Nullable State varianceUntil(Item item, ZonedDateTime timestamp, @Nullable RiemannType type) { return internalVarianceBetween(item, null, timestamp, type, null); } @@ -1220,7 +1220,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable */ public static @Nullable State varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end, @Nullable String serviceId) { - return internalVarianceBetween(item, begin, end, RiemannType.LEFT, serviceId); + return internalVarianceBetween(item, begin, end, null, serviceId); } /** @@ -1236,7 +1236,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}, or if there is no persisted state for the * given item between begin and end */ - public static @Nullable State varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end, RiemannType type) { + public static @Nullable State varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end, + @Nullable RiemannType type) { return internalVarianceBetween(item, begin, end, type, null); } @@ -1254,7 +1255,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State varianceSince(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalVarianceBetween(item, timestamp, null, RiemannType.LEFT, serviceId); + return internalVarianceBetween(item, timestamp, null, null, serviceId); } /** @@ -1270,7 +1271,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}, or if there is no persisted state for the given item at * the given timestamp */ - public static @Nullable State varianceSince(Item item, ZonedDateTime timestamp, RiemannType type, + public static @Nullable State varianceSince(Item item, ZonedDateTime timestamp, @Nullable RiemannType type, @Nullable String serviceId) { return internalVarianceBetween(item, timestamp, null, type, serviceId); } @@ -1289,7 +1290,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State varianceUntil(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalVarianceBetween(item, null, timestamp, RiemannType.LEFT, serviceId); + return internalVarianceBetween(item, null, timestamp, null, serviceId); } /** @@ -1305,7 +1306,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}, or if there is no persisted state for the given item at * the given timestamp */ - public static @Nullable State varianceUntil(Item item, ZonedDateTime timestamp, RiemannType type, + public static @Nullable State varianceUntil(Item item, ZonedDateTime timestamp, @Nullable RiemannType type, @Nullable String serviceId) { return internalVarianceBetween(item, null, timestamp, type, serviceId); } @@ -1324,7 +1325,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * given item between begin and end */ public static @Nullable State varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return internalVarianceBetween(item, begin, end, RiemannType.LEFT, null); + return internalVarianceBetween(item, begin, end, null, null); } /** @@ -1342,13 +1343,13 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * a {@link QueryablePersistenceService}, or if there is no persisted state for the * given item between begin and end */ - public static @Nullable State varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end, RiemannType type, - @Nullable String serviceId) { + public static @Nullable State varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end, + @Nullable RiemannType type, @Nullable String serviceId) { return internalVarianceBetween(item, begin, end, type, serviceId); } private static @Nullable State internalVarianceBetween(Item item, @Nullable ZonedDateTime begin, - @Nullable ZonedDateTime end, RiemannType type, @Nullable String serviceId) { + @Nullable ZonedDateTime end, @Nullable RiemannType type, @Nullable String serviceId) { String effectiveServiceId = serviceId == null ? getDefaultServiceId() : serviceId; if (effectiveServiceId == null) { return null; @@ -1406,7 +1407,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State deviationSince(Item item, ZonedDateTime timestamp) { - return internalDeviationBetween(item, timestamp, null, RiemannType.LEFT, null); + return internalDeviationBetween(item, timestamp, null, null, null); } /** @@ -1424,7 +1425,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}, or if there is no persisted state for the given item at * the given timestamp */ - public static @Nullable State deviationSince(Item item, ZonedDateTime timestamp, RiemannType type) { + public static @Nullable State deviationSince(Item item, ZonedDateTime timestamp, @Nullable RiemannType type) { return internalDeviationBetween(item, timestamp, null, type, null); } @@ -1444,7 +1445,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State deviationUntil(Item item, ZonedDateTime timestamp) { - return internalDeviationBetween(item, timestamp, null, RiemannType.LEFT, null); + return internalDeviationBetween(item, timestamp, null, null, null); } /** @@ -1462,7 +1463,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}, or if there is no persisted state for the given item at * the given timestamp */ - public static @Nullable State deviationUntil(Item item, ZonedDateTime timestamp, RiemannType type) { + public static @Nullable State deviationUntil(Item item, ZonedDateTime timestamp, @Nullable RiemannType type) { return internalDeviationBetween(item, timestamp, null, type, null); } @@ -1483,7 +1484,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * given item between begin and end */ public static @Nullable State deviationBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return internalDeviationBetween(item, begin, end, RiemannType.LEFT, null); + return internalDeviationBetween(item, begin, end, null, null); } /** @@ -1503,7 +1504,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * given item between begin and end */ public static @Nullable State deviationBetween(Item item, ZonedDateTime begin, ZonedDateTime end, - RiemannType type) { + @Nullable RiemannType type) { return internalDeviationBetween(item, begin, end, type, null); } @@ -1524,7 +1525,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State deviationSince(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalDeviationBetween(item, timestamp, null, RiemannType.LEFT, serviceId); + return internalDeviationBetween(item, timestamp, null, null, serviceId); } /** @@ -1543,7 +1544,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}, or if there is no persisted state for the given item at * the given timestamp */ - public static @Nullable State deviationSince(Item item, ZonedDateTime timestamp, RiemannType type, + public static @Nullable State deviationSince(Item item, ZonedDateTime timestamp, @Nullable RiemannType type, @Nullable String serviceId) { return internalDeviationBetween(item, timestamp, null, type, serviceId); } @@ -1565,7 +1566,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * the given timestamp */ public static @Nullable State deviationUntil(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalDeviationBetween(item, null, timestamp, RiemannType.LEFT, serviceId); + return internalDeviationBetween(item, null, timestamp, null, serviceId); } /** @@ -1584,7 +1585,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}, or if there is no persisted state for the given item at * the given timestamp */ - public static @Nullable State deviationUntil(Item item, ZonedDateTime timestamp, RiemannType type, + public static @Nullable State deviationUntil(Item item, ZonedDateTime timestamp, @Nullable RiemannType type, @Nullable String serviceId) { return internalDeviationBetween(item, null, timestamp, type, serviceId); } @@ -1609,7 +1610,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable */ public static @Nullable State deviationBetween(Item item, ZonedDateTime begin, ZonedDateTime end, @Nullable String serviceId) { - return internalDeviationBetween(item, begin, end, RiemannType.LEFT, serviceId); + return internalDeviationBetween(item, begin, end, null, serviceId); } /** @@ -1630,13 +1631,13 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * a {@link QueryablePersistenceService}, or if there is no persisted state for the * given item between begin and end */ - public static @Nullable State deviationBetween(Item item, ZonedDateTime begin, ZonedDateTime end, RiemannType type, - @Nullable String serviceId) { + public static @Nullable State deviationBetween(Item item, ZonedDateTime begin, ZonedDateTime end, + @Nullable RiemannType type, @Nullable String serviceId) { return internalDeviationBetween(item, begin, end, type, serviceId); } private static @Nullable State internalDeviationBetween(Item item, @Nullable ZonedDateTime begin, - @Nullable ZonedDateTime end, RiemannType type, @Nullable String serviceId) { + @Nullable ZonedDateTime end, @Nullable RiemannType type, @Nullable String serviceId) { String effectiveServiceId = serviceId == null ? getDefaultServiceId() : serviceId; if (effectiveServiceId == null) { return null; @@ -1673,7 +1674,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}. The current state is included in the calculation. */ public static @Nullable State averageSince(Item item, ZonedDateTime timestamp) { - return internalAverageBetween(item, timestamp, null, RiemannType.LEFT, null); + return internalAverageBetween(item, timestamp, null, null, null); } /** @@ -1687,7 +1688,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * previous states could be found or if the default persistence service does not refer to an available * {@link QueryablePersistenceService}. The current state is included in the calculation. */ - public static @Nullable State averageSince(Item item, ZonedDateTime timestamp, RiemannType type) { + public static @Nullable State averageSince(Item item, ZonedDateTime timestamp, @Nullable RiemannType type) { return internalAverageBetween(item, timestamp, null, type, null); } @@ -1703,7 +1704,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}. The current state is included in the calculation. */ public static @Nullable State averageUntil(Item item, ZonedDateTime timestamp) { - return internalAverageBetween(item, null, timestamp, RiemannType.LEFT, null); + return internalAverageBetween(item, null, timestamp, null, null); } /** @@ -1717,7 +1718,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * future states could be found or if the default persistence service does not refer to an available * {@link QueryablePersistenceService}. The current state is included in the calculation. */ - public static @Nullable State averageUntil(Item item, ZonedDateTime timestamp, RiemannType type) { + public static @Nullable State averageUntil(Item item, ZonedDateTime timestamp, @Nullable RiemannType type) { return internalAverageBetween(item, null, timestamp, type, null); } @@ -1734,7 +1735,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}. */ public static @Nullable State averageBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return internalAverageBetween(item, begin, end, RiemannType.LEFT, null); + return internalAverageBetween(item, begin, end, null, null); } /** @@ -1749,7 +1750,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * states could be found or if the default persistence service does not refer to an available * {@link QueryablePersistenceService}. */ - public static @Nullable State averageBetween(Item item, ZonedDateTime begin, ZonedDateTime end, RiemannType type) { + public static @Nullable State averageBetween(Item item, ZonedDateTime begin, ZonedDateTime end, + @Nullable RiemannType type) { return internalAverageBetween(item, begin, end, type, null); } @@ -1767,7 +1769,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * calculation. */ public static @Nullable State averageSince(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalAverageBetween(item, timestamp, null, RiemannType.LEFT, serviceId); + return internalAverageBetween(item, timestamp, null, null, serviceId); } /** @@ -1783,7 +1785,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * refer to an available {@link QueryablePersistenceService}. The current state is included in the * calculation. */ - public static @Nullable State averageSince(Item item, ZonedDateTime timestamp, RiemannType type, + public static @Nullable State averageSince(Item item, ZonedDateTime timestamp, @Nullable RiemannType type, @Nullable String serviceId) { return internalAverageBetween(item, timestamp, null, type, serviceId); } @@ -1802,7 +1804,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * calculation. */ public static @Nullable State averageUntil(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalAverageBetween(item, null, timestamp, RiemannType.LEFT, serviceId); + return internalAverageBetween(item, null, timestamp, null, serviceId); } /** @@ -1818,7 +1820,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * refer to an available {@link QueryablePersistenceService}. The current state is included in the * calculation. */ - public static @Nullable State averageUntil(Item item, ZonedDateTime timestamp, RiemannType type, + public static @Nullable State averageUntil(Item item, ZonedDateTime timestamp, @Nullable RiemannType type, @Nullable String serviceId) { return internalAverageBetween(item, null, timestamp, type, serviceId); } @@ -1838,7 +1840,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable */ public static @Nullable State averageBetween(Item item, ZonedDateTime begin, ZonedDateTime end, @Nullable String serviceId) { - return internalAverageBetween(item, begin, end, RiemannType.LEFT, serviceId); + return internalAverageBetween(item, begin, end, null, serviceId); } /** @@ -1854,13 +1856,13 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * states could be found or if the persistence service given by serviceId does not * refer to an available {@link QueryablePersistenceService} */ - public static @Nullable State averageBetween(Item item, ZonedDateTime begin, ZonedDateTime end, RiemannType type, - @Nullable String serviceId) { + public static @Nullable State averageBetween(Item item, ZonedDateTime begin, ZonedDateTime end, + @Nullable RiemannType type, @Nullable String serviceId) { return internalAverageBetween(item, begin, end, type, serviceId); } private static @Nullable State internalAverageBetween(Item item, @Nullable ZonedDateTime begin, - @Nullable ZonedDateTime end, RiemannType type, @Nullable String serviceId) { + @Nullable ZonedDateTime end, @Nullable RiemannType type, @Nullable String serviceId) { String effectiveServiceId = serviceId == null ? getDefaultServiceId() : serviceId; if (effectiveServiceId == null) { return null; @@ -1917,7 +1919,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}. The current state is included in the calculation. */ public static @Nullable State riemannSumSince(Item item, ZonedDateTime timestamp) { - return internalRiemannSumBetween(item, timestamp, null, RiemannType.LEFT, null); + return internalRiemannSumBetween(item, timestamp, null, null, null); } /** @@ -1934,7 +1936,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * previous states could be found or if the default persistence service does not refer to an available * {@link QueryablePersistenceService}. The current state is included in the calculation. */ - public static @Nullable State riemannSumSince(Item item, ZonedDateTime timestamp, RiemannType type) { + public static @Nullable State riemannSumSince(Item item, ZonedDateTime timestamp, @Nullable RiemannType type) { return internalRiemannSumBetween(item, timestamp, null, type, null); } @@ -1953,7 +1955,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}. The current state is included in the calculation. */ public static @Nullable State riemannSumUntil(Item item, ZonedDateTime timestamp) { - return internalRiemannSumBetween(item, null, timestamp, RiemannType.LEFT, null); + return internalRiemannSumBetween(item, null, timestamp, null, null); } /** @@ -1970,7 +1972,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * future states could be found or if the default persistence service does not refer to an available * {@link QueryablePersistenceService}. The current state is included in the calculation. */ - public static @Nullable State riemannSumUntil(Item item, ZonedDateTime timestamp, RiemannType type) { + public static @Nullable State riemannSumUntil(Item item, ZonedDateTime timestamp, @Nullable RiemannType type) { return internalRiemannSumBetween(item, null, timestamp, type, null); } @@ -1990,7 +1992,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}. */ public static @Nullable State riemannSumBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return internalRiemannSumBetween(item, begin, end, RiemannType.LEFT, null); + return internalRiemannSumBetween(item, begin, end, null, null); } /** @@ -2009,7 +2011,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * {@link QueryablePersistenceService}. */ public static @Nullable State riemannSumBetween(Item item, ZonedDateTime begin, ZonedDateTime end, - RiemannType type) { + @Nullable RiemannType type) { return internalRiemannSumBetween(item, begin, end, type, null); } @@ -2030,7 +2032,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * calculation. */ public static @Nullable State riemannSumSince(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalRiemannSumBetween(item, timestamp, null, RiemannType.LEFT, serviceId); + return internalRiemannSumBetween(item, timestamp, null, null, serviceId); } /** @@ -2049,7 +2051,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * refer to an available {@link QueryablePersistenceService}. The current state is included in the * calculation. */ - public static @Nullable State riemannSumSince(Item item, ZonedDateTime timestamp, RiemannType type, + public static @Nullable State riemannSumSince(Item item, ZonedDateTime timestamp, @Nullable RiemannType type, @Nullable String serviceId) { return internalRiemannSumBetween(item, timestamp, null, type, serviceId); } @@ -2071,7 +2073,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * calculation. */ public static @Nullable State riemannSumUntil(Item item, ZonedDateTime timestamp, @Nullable String serviceId) { - return internalRiemannSumBetween(item, null, timestamp, RiemannType.LEFT, serviceId); + return internalRiemannSumBetween(item, null, timestamp, null, serviceId); } /** @@ -2090,7 +2092,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * refer to an available {@link QueryablePersistenceService}. The current state is included in the * calculation. */ - public static @Nullable State riemannSumUntil(Item item, ZonedDateTime timestamp, RiemannType type, + public static @Nullable State riemannSumUntil(Item item, ZonedDateTime timestamp, @Nullable RiemannType type, @Nullable String serviceId) { return internalRiemannSumBetween(item, null, timestamp, type, serviceId); } @@ -2113,7 +2115,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable */ public static @Nullable State riemannSumBetween(Item item, ZonedDateTime begin, ZonedDateTime end, @Nullable String serviceId) { - return internalRiemannSumBetween(item, begin, end, RiemannType.LEFT, serviceId); + return internalRiemannSumBetween(item, begin, end, null, serviceId); } /** @@ -2132,13 +2134,13 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable * states could be found or if the persistence service given by serviceId does not * refer to an available {@link QueryablePersistenceService} */ - public static @Nullable State riemannSumBetween(Item item, ZonedDateTime begin, ZonedDateTime end, RiemannType type, - @Nullable String serviceId) { + public static @Nullable State riemannSumBetween(Item item, ZonedDateTime begin, ZonedDateTime end, + @Nullable RiemannType type, @Nullable String serviceId) { return internalRiemannSumBetween(item, begin, end, type, serviceId); } private static @Nullable State internalRiemannSumBetween(Item item, @Nullable ZonedDateTime begin, - @Nullable ZonedDateTime end, RiemannType type, @Nullable String serviceId) { + @Nullable ZonedDateTime end, @Nullable RiemannType type, @Nullable String serviceId) { String effectiveServiceId = serviceId == null ? getDefaultServiceId() : serviceId; if (effectiveServiceId == null) { return null; @@ -2171,7 +2173,9 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable } private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Iterator it, - @Nullable Unit unit, RiemannType type) { + @Nullable Unit unit, @Nullable RiemannType type) { + RiemannType riemannType = type == null ? RiemannType.LEFT : type; + BigDecimal sum = BigDecimal.ZERO; HistoricItem prevItem = null; HistoricItem nextItem = null; @@ -2183,7 +2187,7 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite boolean midpointStartBucket = true; // The start and end buckets for the midpoint calculation should be // considered for the full length, this flag is used to find the start // bucket - if ((type == RiemannType.MIDPOINT) && it.hasNext()) { + if ((riemannType == RiemannType.MIDPOINT) && it.hasNext()) { prevItem = it.next(); prevState = getPersistedValue(prevItem, unit); } @@ -2192,7 +2196,7 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite nextItem = it.next(); BigDecimal weight = BigDecimal.ZERO; BigDecimal value = BigDecimal.ZERO; - switch (type) { + switch (riemannType) { case LEFT: if (prevItem != null) { prevState = getPersistedValue(prevItem, unit); @@ -2256,7 +2260,7 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite sum = sum.add(value.multiply(weight)); } - if ((type == RiemannType.MIDPOINT) && (prevItem != null)) { + if ((riemannType == RiemannType.MIDPOINT) && (prevItem != null)) { // Add half of the end bucket with the end value (right approximation) DecimalType dtState = getPersistedValue(prevItem, unit); if (dtState != null) { From 2ec010a344b051a1b14ec56f7c460152ee93240e Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Fri, 24 Jan 2025 13:11:00 +0100 Subject: [PATCH 12/13] riemann sums on absolute unit values Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 3 +- .../extensions/PersistenceExtensionsTest.java | 37 +++++++++---------- .../extensions/TestPersistenceService.java | 37 +++++++++++++------ 3 files changed, 45 insertions(+), 32 deletions(-) diff --git a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java index e2f385b488c..ece38c2d230 100644 --- a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java +++ b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java @@ -2163,7 +2163,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable } Item baseItem = item instanceof GroupItem groupItem ? groupItem.getBaseItem() : item; - Unit unit = baseItem instanceof NumberItem numberItem ? numberItem.getUnit() : null; + Unit baseUnit = baseItem instanceof NumberItem numberItem ? numberItem.getUnit() : null; + Unit unit = baseUnit != null ? baseUnit.getSystemUnit() : null; BigDecimal sum = riemannSum(beginTime, endTime, it, unit, type).scaleByPowerOfTen(-3); if (unit != null) { diff --git a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java index ba4a5bc39a9..6fcfe4c17c4 100644 --- a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java +++ b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/PersistenceExtensionsTest.java @@ -1803,43 +1803,40 @@ public void testRiemannSumBetweenQuantityType() { ZoneId.systemDefault()); ZonedDateTime endStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - double expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2, type); - State RiemannSum = PersistenceExtensions.riemannSumBetween(quantityItem, beginStored, endStored, type, - SERVICE_ID); + double expected = riemannSumCelsius(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2, type); + State sum = PersistenceExtensions.riemannSumBetween(quantityItem, beginStored, endStored, type, SERVICE_ID); - assertNotNull(RiemannSum); - QuantityType qt = RiemannSum.as(QuantityType.class); + assertNotNull(sum); + QuantityType qt = sum.as(QuantityType.class); assertNotNull(qt); assertThat(qt.doubleValue(), is(closeTo(expected, 0.01))); - assertEquals(SIUnits.CELSIUS.multiply(Units.SECOND), qt.getUnit()); + assertEquals(Units.KELVIN.multiply(Units.SECOND), qt.getUnit()); beginStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - expected = riemannSum(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4, type); + expected = riemannSumCelsius(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4, type); - RiemannSum = PersistenceExtensions.riemannSumBetween(quantityItem, beginStored, endStored, type, - SERVICE_ID); - assertNotNull(RiemannSum); - qt = RiemannSum.as(QuantityType.class); + sum = PersistenceExtensions.riemannSumBetween(quantityItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + qt = sum.as(QuantityType.class); assertNotNull(qt); assertThat(qt.doubleValue(), is(closeTo(expected, 0.01))); - assertEquals(SIUnits.CELSIUS.multiply(Units.SECOND), qt.getUnit()); + assertEquals(Units.KELVIN.multiply(Units.SECOND), qt.getUnit()); beginStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - expected = riemannSum(HISTORIC_INTERMEDIATE_VALUE_1, FUTURE_INTERMEDIATE_VALUE_3, type); + expected = riemannSumCelsius(HISTORIC_INTERMEDIATE_VALUE_1, FUTURE_INTERMEDIATE_VALUE_3, type); - RiemannSum = PersistenceExtensions.riemannSumBetween(quantityItem, beginStored, endStored, type, - SERVICE_ID); - assertNotNull(RiemannSum); - qt = RiemannSum.as(QuantityType.class); + sum = PersistenceExtensions.riemannSumBetween(quantityItem, beginStored, endStored, type, SERVICE_ID); + assertNotNull(sum); + qt = sum.as(QuantityType.class); assertNotNull(qt); assertThat(qt.doubleValue(), is(closeTo(expected, 0.01))); - assertEquals(SIUnits.CELSIUS.multiply(Units.SECOND), qt.getUnit()); + assertEquals(Units.KELVIN.multiply(Units.SECOND), qt.getUnit()); // default persistence service - RiemannSum = PersistenceExtensions.riemannSumBetween(quantityItem, beginStored, endStored, type); - assertNull(RiemannSum); + sum = PersistenceExtensions.riemannSumBetween(quantityItem, beginStored, endStored, type); + assertNull(sum); } } diff --git a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java index 3a49461ba2d..7199b8fea8e 100644 --- a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java +++ b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestPersistenceService.java @@ -89,6 +89,8 @@ public class TestPersistenceService implements QueryablePersistenceService { static final int AFTER_END = 2110; static final DecimalType STATE = new DecimalType(HISTORIC_END); + static final double KELVIN_OFFSET = 273.15; + private final ItemRegistry itemRegistry; public TestPersistenceService(ItemRegistry itemRegistry) { @@ -238,20 +240,33 @@ static OnOffType switchValue(int hour) { } static DecimalType value(long year) { + return value(year, false); + } + + private static DecimalType value(long year, boolean kelvinOffset) { if (year < HISTORIC_START) { return DecimalType.ZERO; } else if (year <= HISTORIC_END) { - return new DecimalType(year); + return new DecimalType(year + (kelvinOffset ? KELVIN_OFFSET : 0)); } else if (year < FUTURE_START) { - return new DecimalType(HISTORIC_END); + return new DecimalType(HISTORIC_END + (kelvinOffset ? KELVIN_OFFSET : 0)); } else if (year <= FUTURE_END) { - return new DecimalType(year); + return new DecimalType(year + (kelvinOffset ? KELVIN_OFFSET : 0)); } else { - return new DecimalType(FUTURE_END); + return new DecimalType(FUTURE_END + (kelvinOffset ? KELVIN_OFFSET : 0)); } } static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, RiemannType type) { + return riemannSumInternal(beginYear, endYear, type, false); + } + + static double riemannSumCelsius(@Nullable Integer beginYear, @Nullable Integer endYear, RiemannType type) { + return riemannSumInternal(beginYear, endYear, type, true); + } + + private static double riemannSumInternal(@Nullable Integer beginYear, @Nullable Integer endYear, RiemannType type, + boolean kelvinOffset) { ZonedDateTime now = ZonedDateTime.now(); int begin = beginYear != null ? (beginYear < HISTORIC_START ? HISTORIC_START : beginYear) : now.getYear() + 1; int end = endYear != null ? endYear : now.getYear(); @@ -268,7 +283,7 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, } while (index < end) { int bucketStart = index; - double value = value(index).doubleValue(); + double value = value(index, kelvinOffset).doubleValue(); while ((index < end - 1) && (value(index).longValue() == value(index + 1).longValue())) { index++; } @@ -298,7 +313,7 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, index++; } index++; - double value = value(index).doubleValue(); + double value = value(index, kelvinOffset).doubleValue(); duration += Duration .between(ZonedDateTime.of(bucketStart, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), ZonedDateTime.of(index, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) @@ -320,12 +335,12 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, } while (index < end) { int bucketStart = index; - double value = value(index).doubleValue(); + double value = value(index, kelvinOffset).doubleValue(); while ((index < end - 1) && (value(index).longValue() == value(index + 1).longValue())) { index++; } index++; - value = (value + value(index).doubleValue()) / 2.0; + value = (value + value(index, kelvinOffset).doubleValue()) / 2.0; duration += Duration .between(ZonedDateTime.of(bucketStart, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), ZonedDateTime.of(index, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) @@ -342,7 +357,7 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, case MIDPOINT: int nextIndex = begin; boolean startBucket = true; - double startValue = value(begin).doubleValue(); + double startValue = value(begin, kelvinOffset).doubleValue(); if (beginYear == null) { duration = Duration.between(now, ZonedDateTime.of(begin, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) .toSeconds(); @@ -353,7 +368,7 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, index++; } index++; - double value = value(index).doubleValue(); + double value = value(index, kelvinOffset).doubleValue(); duration += Duration .between(ZonedDateTime.of(bucketStart, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), ZonedDateTime.of(index, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())) @@ -381,7 +396,7 @@ static double riemannSum(@Nullable Integer beginYear, @Nullable Integer endYear, sum += value * (duration + nextDuration) / 2.0; duration = 0; } - double endValue = value(end).doubleValue(); + double endValue = value(end, kelvinOffset).doubleValue(); long endDuration = nextDuration; sum += endValue * endDuration / 2.0; break; From e9057779ef5f772e7be05f3ecfb11b7d09b70bb0 Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Sat, 25 Jan 2025 14:26:59 +0100 Subject: [PATCH 13/13] simplify Signed-off-by: Mark Herwege --- .../core/persistence/extensions/PersistenceExtensions.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java index ece38c2d230..1926c872051 100644 --- a/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java +++ b/bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java @@ -2163,9 +2163,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable } Item baseItem = item instanceof GroupItem groupItem ? groupItem.getBaseItem() : item; - Unit baseUnit = baseItem instanceof NumberItem numberItem ? numberItem.getUnit() : null; - Unit unit = baseUnit != null ? baseUnit.getSystemUnit() : null; - + Unit unit = (baseItem instanceof NumberItem numberItem) + && (numberItem.getUnit() instanceof Unit numberItemUnit) ? numberItemUnit.getSystemUnit() : null; BigDecimal sum = riemannSum(beginTime, endTime, it, unit, type).scaleByPowerOfTen(-3); if (unit != null) { return new QuantityType<>(sum, unit.multiply(Units.SECOND));