From 7a748140d48e410cb6dc6366a6def654400056e5 Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Wed, 10 Jan 2024 16:59:34 +0100 Subject: [PATCH 01/13] persistence extensions future and QuantityTypes Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 1617 +++++++++--- .../extensions/PersistenceExtensionsTest.java | 2181 +++++++++++++---- .../TestCachedValuesPersistenceService.java | 32 +- .../extensions/TestPersistenceService.java | 124 +- 4 files changed, 3065 insertions(+), 889 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 62909962d04..94b7efeaffd 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 @@ -15,6 +15,7 @@ import java.math.BigDecimal; import java.math.MathContext; import java.time.Duration; +import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Collection; @@ -22,16 +23,24 @@ import java.util.List; import java.util.stream.StreamSupport; +import javax.measure.Unit; + +import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.i18n.TimeZoneProvider; import org.openhab.core.items.Item; +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.persistence.FilterCriteria; import org.openhab.core.persistence.FilterCriteria.Ordering; import org.openhab.core.persistence.HistoricItem; +import org.openhab.core.persistence.ModifiablePersistenceService; import org.openhab.core.persistence.PersistenceService; import org.openhab.core.persistence.PersistenceServiceRegistry; import org.openhab.core.persistence.QueryablePersistenceService; import org.openhab.core.types.State; +import org.openhab.core.types.TimeSeries; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; @@ -48,15 +57,30 @@ * @author Jan N. Klug - Added sumSince * @author John Cocula - Added sumSince * @author Jan N. Klug - Added interval methods and refactoring + * @author Mark Herwege - Changed return types to State for some interval methods to also return unit + * @author Mark Herwege - Extended for future dates */ @Component(immediate = true) +@NonNullByDefault public class PersistenceExtensions { - private static PersistenceServiceRegistry registry; + private static @Nullable PersistenceServiceRegistry registry; + private static @Nullable TimeZoneProvider timeZoneProvider; @Activate - public PersistenceExtensions(@Reference PersistenceServiceRegistry registry) { + public PersistenceExtensions(@Reference PersistenceServiceRegistry registry, + @Reference TimeZoneProvider timeZoneProvider) { PersistenceExtensions.registry = registry; + PersistenceExtensions.timeZoneProvider = timeZoneProvider; + } + + /** + * Persists the state of a given item through the default persistence service. + * + * @param item the item to store + */ + public static void persist(Item item) { + internalPersist(item); } /** @@ -67,42 +91,137 @@ public PersistenceExtensions(@Reference PersistenceServiceRegistry registry) { * @param serviceId the name of the {@link PersistenceService} to use */ public static void persist(Item item, String serviceId) { + internalPersist(item, serviceId); + } + + private static void internalPersist(Item item) { + String serviceId = getDefaultServiceId(); + if (serviceId == null) { + return; + } + internalPersist(item, serviceId); + } + + private static void internalPersist(Item item, String serviceId) { PersistenceService service = getService(serviceId); if (service != null) { service.store(item); - } else { - LoggerFactory.getLogger(PersistenceExtensions.class) - .warn("There is no persistence service registered with the id '{}'", serviceId); + return; } + LoggerFactory.getLogger(PersistenceExtensions.class) + .warn("There is no persistence service registered with the id '{}'", serviceId); } /** - * Persists the state of a given item through the default persistence service. + * Persists a state at a given timestamp of an item through the default + * persistence service. * * @param item the item to store + * @param timestamp the date for the item state to be stored + * @param state the state to be stored */ - public static void persist(Item item) { - persist(item, getDefaultServiceId()); + public static void persist(Item item, ZonedDateTime timestamp, State state) { + internalPersist(item, timestamp, state); + } + + /** + * Persists a state at a given timestamp of an item through a + * {@link PersistenceService} identified by the serviceId. + * + * @param item the item + * @param timestamp the date for the item state to be stored + * @param state the state to be stored + * @param serviceId the name of the {@link PersistenceService} to use + */ + public static void persist(Item item, ZonedDateTime timestamp, State state, String serviceId) { + internalPersist(item, timestamp, state, serviceId); + } + + private static void internalPersist(Item item, ZonedDateTime timestamp, State state) { + String serviceId = getDefaultServiceId(); + if (serviceId == null) { + return; + } + internalPersist(item, timestamp, state, serviceId); + } + + private static void internalPersist(Item item, ZonedDateTime timestamp, State state, String serviceId) { + PersistenceService service = getService(serviceId); + if (service != null && service instanceof ModifiablePersistenceService modifiableService) { + modifiableService.store(item, timestamp, state, serviceId); + return; + } + LoggerFactory.getLogger(PersistenceExtensions.class) + .warn("There is no modifiable persistence service registered with the id '{}'", serviceId); + } + + /** + * Persists a timeSeries of an item through the default persistence service. + * + * @param item the item to store + * @param timeSeries the timeSeries of states to be stored + */ + public static void persist(Item item, TimeSeries timeSeries) { + internalPersist(item, timeSeries); + } + + /** + * Persists a timeSeries of an item through a {@link PersistenceService} identified by the + * serviceId. + * + * @param item the item + * @param timeSeries the timeSeries of states to be stored + * @param serviceId the name of the {@link PersistenceService} to use + */ + public static void persist(Item item, TimeSeries timeSeries, String serviceId) { + internalPersist(item, timeSeries, serviceId); + } + + private static void internalPersist(Item item, TimeSeries timeSeries) { + String serviceId = getDefaultServiceId(); + if (serviceId == null) { + return; + } + internalPersist(item, timeSeries, serviceId); + } + + private static void internalPersist(Item item, TimeSeries timeSeries, String serviceId) { + PersistenceService service = getService(serviceId); + ZoneId timeZone = timeZoneProvider != null ? timeZoneProvider.getTimeZone() : ZoneId.systemDefault(); + if (service != null && service instanceof ModifiablePersistenceService modifiableService) { + timeSeries.getStates() + .forEach(s -> modifiableService.store(item, s.timestamp().atZone(timeZone), s.state(), serviceId)); + return; + } + LoggerFactory.getLogger(PersistenceExtensions.class) + .warn("There is no modifiable persistence service registered with the id '{}'", serviceId); } /** * Retrieves the historic item for a given item at a certain point in time through the default * persistence service. * + * This method has been deprecated and {@link #persistedState(Item, ZonedDateTime)} should be used instead. + * * @param item the item for which to retrieve the historic item * @param timestamp the point in time for which the historic item should be retrieved * @return the historic item at the given point in time, or null if no historic item could be found, * the default persistence service is not available or does not refer to a * {@link QueryablePersistenceService} */ + @Deprecated public static @Nullable HistoricItem historicState(Item item, ZonedDateTime timestamp) { - return historicState(item, timestamp, getDefaultServiceId()); + LoggerFactory.getLogger(PersistenceExtensions.class).info( + "The historicState method has been deprecated and will be removed in a future version, use persistedState instead."); + return internalPersistedState(item, timestamp); } /** * Retrieves the historic item for a given item at a certain point in time through a * {@link PersistenceService} identified by the serviceId. * + * This method has been deprecated and {@link #persistedState(Item, ZonedDateTime, String)} should be used instead. + * * @param item the item for which to retrieve the historic item * @param timestamp the point in time for which the historic item should be retrieved * @param serviceId the name of the {@link PersistenceService} to use @@ -110,9 +229,55 @@ public static void persist(Item item) { * if the provided serviceId does not refer to an available * {@link QueryablePersistenceService} */ + @Deprecated public static @Nullable HistoricItem historicState(Item item, ZonedDateTime timestamp, String serviceId) { + LoggerFactory.getLogger(PersistenceExtensions.class).info( + "The historicState method has been deprecated and will be removed in a future version, use persistedState instead."); + return internalPersistedState(item, timestamp, serviceId); + } + + /** + * Retrieves the persisted item for a given item at a certain point in time through the default + * persistence service. + * + * @param item the item for which to retrieve the persisted item + * @param timestamp the point in time for which the persisted item should be retrieved + * @return the historic item at the given point in time, or null if no persisted item could be found, + * the default persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} + */ + public static @Nullable HistoricItem persistedState(Item item, ZonedDateTime timestamp) { + return internalPersistedState(item, timestamp); + } + + /** + * Retrieves the persisted item for a given item at a certain point in time through a + * {@link PersistenceService} identified by the serviceId. + * + * @param item the item for which to retrieve the persisted item + * @param timestamp the point in time for which the persisted item should be retrieved + * @param serviceId the name of the {@link PersistenceService} to use + * @return the persisted item at the given point in time, or null if no persisted item could be found + * or + * if the provided serviceId does not refer to an available + * {@link QueryablePersistenceService} + */ + public static @Nullable HistoricItem persistedState(Item item, ZonedDateTime timestamp, String serviceId) { + return internalPersistedState(item, timestamp, serviceId); + } + + private static @Nullable HistoricItem internalPersistedState(Item item, @Nullable ZonedDateTime timestamp) { + String serviceId = getDefaultServiceId(); + return serviceId != null ? internalPersistedState(item, timestamp, serviceId) : null; + } + + private static @Nullable HistoricItem internalPersistedState(Item item, @Nullable ZonedDateTime timestamp, + String serviceId) { + if (timestamp == null) { + return null; + } PersistenceService service = getService(serviceId); - if (service instanceof QueryablePersistenceService qService) { + if (service != null && service instanceof QueryablePersistenceService qService) { FilterCriteria filter = new FilterCriteria(); filter.setEndDate(timestamp); filter.setItemName(item.getName()); @@ -124,40 +289,82 @@ public static void persist(Item item) { } else { return null; } - } else { - LoggerFactory.getLogger(PersistenceExtensions.class) - .warn("There is no queryable persistence service registered with the id '{}'", serviceId); - return null; } + LoggerFactory.getLogger(PersistenceExtensions.class) + .warn("There is no queryable persistence service registered with the id '{}'", serviceId); + return null; } /** - * Query the last update time of a given item. The default persistence service is used. + * Query the last historic update time of a given item. The default persistence service is used. * - * @param item the item for which the last update time is to be returned - * @return point in time of the last update to item, or null if there are no previously + * @param item the item for which the last historic update time is to be returned + * @return point in time of the last historic update to item, or null if there are no + * historic * persisted updates or the default persistence service is not available or a * {@link QueryablePersistenceService} */ public static @Nullable ZonedDateTime lastUpdate(Item item) { - return lastUpdate(item, getDefaultServiceId()); + return internalAdjacentUpdate(item, false); } /** - * Query for the last update time of a given item. + * Query for the last historic update time of a given item. * - * @param item the item for which the last update time is to be returned + * @param item the item for which the last historic update time is to be returned * @param serviceId the name of the {@link PersistenceService} to use - * @return last time item was updated, or null if there are no previously + * @return point in time of the last historic update to item, or null if there are no + * historic * persisted updates or if persistence service given by serviceId does not refer to an * available {@link QueryablePersistenceService} */ public static @Nullable ZonedDateTime lastUpdate(Item item, String serviceId) { + return internalAdjacentUpdate(item, false, serviceId); + } + + /** + * Query the first future update time of a given item. The default persistence service is used. + * + * @param item the item for which the first future update time is to be returned + * @return point in time of the first future update to item, or null if there are no + * future + * persisted updates or the default persistence service is not available or a + * {@link QueryablePersistenceService} + */ + public static @Nullable ZonedDateTime nextUpdate(Item item) { + return internalAdjacentUpdate(item, true); + } + + /** + * Query for the first future update time of a given item. + * + * @param item the item for which the first future update time is to be returned + * @param serviceId the name of the {@link PersistenceService} to use + * @return point in time of the first future update to item, or null if there are no + * future + * persisted updates or if persistence service given by serviceId does not refer to an + * available {@link QueryablePersistenceService} + */ + public static @Nullable ZonedDateTime nextUpdate(Item item, String serviceId) { + return internalAdjacentUpdate(item, true, serviceId); + } + + private static @Nullable ZonedDateTime internalAdjacentUpdate(Item item, boolean forward) { + String serviceId = getDefaultServiceId(); + return serviceId != null ? internalAdjacentUpdate(item, forward, serviceId) : null; + } + + private static @Nullable ZonedDateTime internalAdjacentUpdate(Item item, boolean forward, String serviceId) { PersistenceService service = getService(serviceId); - if (service instanceof QueryablePersistenceService qService) { + if (service != null && service instanceof QueryablePersistenceService qService) { FilterCriteria filter = new FilterCriteria(); filter.setItemName(item.getName()); - filter.setOrdering(Ordering.DESCENDING); + if (forward) { + filter.setBeginDate(ZonedDateTime.now()); + } else { + filter.setEndDate(ZonedDateTime.now()); + } + filter.setOrdering(forward ? Ordering.ASCENDING : Ordering.DESCENDING); filter.setPageSize(1); Iterable result = qService.query(filter); if (result.iterator().hasNext()) { @@ -165,11 +372,10 @@ public static void persist(Item item) { } else { return null; } - } else { - LoggerFactory.getLogger(PersistenceExtensions.class) - .warn("There is no queryable persistence service registered with the id '{}'", serviceId); - return null; } + LoggerFactory.getLogger(PersistenceExtensions.class) + .warn("There is no queryable persistence service registered with the id '{}'", serviceId); + return null; } /** @@ -180,7 +386,7 @@ public static void persist(Item item) { * persistence service is not configured or does not refer to a {@link QueryablePersistenceService} */ public static @Nullable HistoricItem previousState(Item item) { - return previousState(item, false); + return internalAdjacentState(item, false, false); } /** @@ -192,7 +398,20 @@ public static void persist(Item item) { * persistence service is not configured or does not refer to a {@link QueryablePersistenceService} */ public static @Nullable HistoricItem previousState(Item item, boolean skipEqual) { - return previousState(item, skipEqual, getDefaultServiceId()); + return internalAdjacentState(item, skipEqual, false); + } + + /** + * Returns the previous state of a given item. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the item to get the previous state value for + * @param serviceId the name of the {@link PersistenceService} to use + * @return the previous state or null if no previous state could be found, or if the default + * persistence service is not configured or does not refer to a {@link QueryablePersistenceService} + */ + public static @Nullable HistoricItem previousState(Item item, String serviceId) { + return internalAdjacentState(item, false, false, serviceId); } /** @@ -207,11 +426,78 @@ public static void persist(Item item) { * serviceId is not available or does not refer to a {@link QueryablePersistenceService} */ public static @Nullable HistoricItem previousState(Item item, boolean skipEqual, String serviceId) { + return internalAdjacentState(item, skipEqual, false, serviceId); + + } + + /** + * Returns the next state of a given item. + * + * @param item the item to get the next state value for + * @return the next state or null if no next state could be found, or if the default + * persistence service is not configured or does not refer to a {@link QueryablePersistenceService} + */ + public static @Nullable HistoricItem nextState(Item item) { + return internalAdjacentState(item, false, true); + } + + /** + * Returns the next state of a given item. + * + * @param item the item to get the previous state value for + * @param skipEqual if true, skips equal state values and searches the first state not equal the current state + * @return the next state or null if no next state could be found, or if the default + * persistence service is not configured or does not refer to a {@link QueryablePersistenceService} + */ + public static @Nullable HistoricItem nextState(Item item, boolean skipEqual) { + return internalAdjacentState(item, skipEqual, true); + } + + /** + * Returns the next state of a given item. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the item to get the next state value for + * @param serviceId the name of the {@link PersistenceService} to use + * @return the next state or null if no next state could be found, or if the default + * persistence service is not configured or does not refer to a {@link QueryablePersistenceService} + */ + public static @Nullable HistoricItem nextState(Item item, String serviceId) { + return internalAdjacentState(item, false, true, serviceId); + } + + /** + * Returns the next state of a given item. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the item to get the next state value for + * @param skipEqual if true, skips equal state values and searches the first state not equal the + * current state + * @param serviceId the name of the {@link PersistenceService} to use + * @return the next state or null if no next state could be found, or if the given + * serviceId is not available or does not refer to a {@link QueryablePersistenceService} + */ + public static @Nullable HistoricItem nextState(Item item, boolean skipEqual, String serviceId) { + return internalAdjacentState(item, skipEqual, true, serviceId); + } + + private static @Nullable HistoricItem internalAdjacentState(Item item, boolean skipEqual, boolean forward) { + String serviceId = getDefaultServiceId(); + return serviceId != null ? internalAdjacentState(item, skipEqual, forward, serviceId) : null; + } + + private static @Nullable HistoricItem internalAdjacentState(Item item, boolean skipEqual, boolean forward, + String serviceId) { PersistenceService service = getService(serviceId); - if (service instanceof QueryablePersistenceService qService) { + if (service != null && service instanceof QueryablePersistenceService qService) { FilterCriteria filter = new FilterCriteria(); filter.setItemName(item.getName()); - filter.setOrdering(Ordering.DESCENDING); + if (forward) { + filter.setBeginDate(ZonedDateTime.now()); + } else { + filter.setEndDate(ZonedDateTime.now()); + } + filter.setOrdering(forward ? Ordering.ASCENDING : Ordering.DESCENDING); filter.setPageSize(skipEqual ? 1000 : 1); int startPage = 0; @@ -235,10 +521,9 @@ public static void persist(Item item) { items = null; } } - } else { - LoggerFactory.getLogger(PersistenceExtensions.class) - .warn("There is no queryable persistence service registered with the id '{}'", serviceId); } + LoggerFactory.getLogger(PersistenceExtensions.class) + .warn("There is no queryable persistence service registered with the id '{}'", serviceId); return null; } @@ -248,24 +533,40 @@ public static void persist(Item item) { * * @param item the item to check for state changes * @param timestamp the point in time to start the check - * @return true if item state has changed, false if it has not changed or if the default - * persistence service is not available or does not refer to a {@link QueryablePersistenceService} + * @return true if item state has changed, false if it has not changed, null + * if the default persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} + */ + public static @Nullable Boolean changedSince(Item item, ZonedDateTime timestamp) { + return internalChangedBetween(item, timestamp, null); + } + + /** + * Checks if the state of a given item will change by a certain point in time. + * The default persistence service is used. + * + * @param item the item to check for state changes + * @param timestamp the point in time to end the check + * @return true if item state will change, false if it will not change, null + * if the default persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} */ - public static boolean changedSince(Item item, ZonedDateTime timestamp) { - return changedSince(item, timestamp, getDefaultServiceId()); + public static @Nullable Boolean changedTill(Item item, ZonedDateTime timestamp) { + return internalChangedBetween(item, null, timestamp); } /** - * Checks if the state of a given item has changed between two points in time. + * Checks if the state of a given item changes between two points in time. * The default persistence service is used. * * @param item the item to check for state changes - * @return true if item state changed, false if either item has not been changed in - * the given interval or if the default persistence does not refer to a {@link QueryablePersistenceService}, - * or null if the default persistence service is not available + * @return true if item state changes, false if either item does not change in + * the given interval, null if the default persistence does not refer to a + * {@link QueryablePersistenceService}, or null if the default persistence service is not + * available */ - public static boolean changedBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return changedBetween(item, begin, end, getDefaultServiceId()); + public static @Nullable Boolean changedBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { + return internalChangedBetween(item, begin, end); } /** @@ -275,49 +576,75 @@ public static boolean changedBetween(Item item, ZonedDateTime begin, ZonedDateTi * @param item the item to check for state changes * @param timestamp the point in time to start the check * @param serviceId the name of the {@link PersistenceService} to use - * @return true if item state has changed, or false if it has not changed or if the - * provided serviceId does not refer to an available {@link QueryablePersistenceService} + * @return true if item state has changed, or false if it has not changed, + * null if the provided serviceId does not refer to an available + * {@link QueryablePersistenceService} + */ + public static @Nullable Boolean changedSince(Item item, ZonedDateTime timestamp, String serviceId) { + return internalChangedBetween(item, timestamp, null, serviceId); + } + + /** + * Checks if the state of a given item will change by a certain point in time. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the item to check for state changes + * @param timestamp the point in time to end the check + * @param serviceId the name of the {@link PersistenceService} to use + * @return true if item state will change, or false if it will not change, + * null if the provided serviceId does not refer to an available + * {@link QueryablePersistenceService} */ - public static boolean changedSince(Item item, ZonedDateTime timestamp, String serviceId) { - return internalChanged(item, timestamp, null, serviceId); + public static @Nullable Boolean changedTill(Item item, ZonedDateTime timestamp, String serviceId) { + return internalChangedBetween(item, null, timestamp, serviceId); } /** - * Checks if the state of a given item changed between two points in time. + * Checks if the state of a given item changes between two points in time. * The {@link PersistenceService} identified by the serviceId is used. * * @param item the item to check for state changes * @param begin the point in time to start the check * @param end the point in time to stop the check * @param serviceId the name of the {@link PersistenceService} to use - * @return true if item state changed or false if either the item has not changed - * in the given interval or if the given serviceId does not refer to a + * @return true if item state changed or false if either the item does not change + * in the given interval, null if the given serviceId does not refer to a * {@link QueryablePersistenceService} */ - public static boolean changedBetween(Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { - return internalChanged(item, begin, end, serviceId); + public static @Nullable Boolean changedBetween(Item item, ZonedDateTime begin, ZonedDateTime end, + String serviceId) { + return internalChangedBetween(item, begin, end, serviceId); } - private static boolean internalChanged(Item item, ZonedDateTime begin, @Nullable ZonedDateTime end, - String serviceId) { - Iterable result = getAllStatesBetween(item, begin, end, serviceId); - Iterator it = result.iterator(); - HistoricItem itemThen = historicState(item, begin, serviceId); - if (itemThen == null) { - // Can't get the state at the start time - // If we've got results more recent than this, it must have changed - return it.hasNext(); - } + private static @Nullable Boolean internalChangedBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end) { + String serviceId = getDefaultServiceId(); + return serviceId != null ? internalChangedBetween(item, begin, end, serviceId) : null; + } - State state = itemThen.getState(); - while (it.hasNext()) { - HistoricItem hItem = it.next(); - if (!hItem.getState().equals(state)) { - return true; + private static @Nullable Boolean internalChangedBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end, String serviceId) { + Iterable result = internalGetAllStatesBetween(item, begin, end, serviceId); + if (result != null) { + Iterator it = result.iterator(); + HistoricItem itemThen = internalPersistedState(item, begin, serviceId); + if (itemThen == null) { + // Can't get the state at the start time + // If we've got results more recent than this, it must have changed + return it.hasNext(); + } + + State state = itemThen.getState(); + while (it.hasNext()) { + HistoricItem hItem = it.next(); + if (!hItem.getState().equals(state)) { + return true; + } + state = hItem.getState(); } - state = hItem.getState(); + return false; } - return false; + return null; } /** @@ -327,12 +654,27 @@ private static boolean internalChanged(Item item, ZonedDateTime begin, @Nullable * @param item the item to check for state updates * @param timestamp the point in time to start the check * @return true if item state was updated, false if either item has not been updated since - * timestamp or if the default persistence does not refer to a + * timestamp, null if the default persistence does not refer to a + * {@link QueryablePersistenceService}, or null if the default persistence service is not + * available + */ + public static @Nullable Boolean updatedSince(Item item, ZonedDateTime timestamp) { + return internalUpdatedBetween(item, timestamp, null); + } + + /** + * Checks if the state of a given item will be updated till a certain point in time. + * The default persistence service is used. + * + * @param item the item to check for state updates + * @param timestamp the point in time to end the check + * @return true if item state is updated, false if either item is not updated till + * timestamp, null if the default persistence does not refer to a * {@link QueryablePersistenceService}, or null if the default persistence service is not * available */ - public static boolean updatedSince(Item item, ZonedDateTime timestamp) { - return updatedSince(item, timestamp, getDefaultServiceId()); + public static @Nullable Boolean updatedTill(Item item, ZonedDateTime timestamp) { + return internalUpdatedBetween(item, null, timestamp); } /** @@ -343,12 +685,12 @@ public static boolean updatedSince(Item item, ZonedDateTime timestamp) { * @param begin the point in time to start the check * @param end the point in time to stop the check * @return true if item state was updated, false if either item has not been updated in - * the given interval or if the default persistence does not refer to a + * the given interval, null if the default persistence does not refer to a * {@link QueryablePersistenceService}, or null if the default persistence service is not * available */ - public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return updatedBetween(item, begin, end, getDefaultServiceId()); + public static @Nullable Boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { + return internalUpdatedBetween(item, begin, end); } /** @@ -359,29 +701,58 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * @param timestamp the point in time to start the check * @param serviceId the name of the {@link PersistenceService} to use * @return true if item state was updated or false if either the item has not been updated - * since timestamp or if the given serviceId does not refer to a + * since timestamp, null if the given serviceId does not refer to a * {@link QueryablePersistenceService} */ - public static boolean updatedSince(Item item, ZonedDateTime timestamp, String serviceId) { - Iterable result = getAllStatesBetween(item, timestamp, null, serviceId); - return result.iterator().hasNext(); + public static @Nullable Boolean updatedSince(Item item, ZonedDateTime timestamp, String serviceId) { + return internalUpdatedBetween(item, timestamp, null, serviceId); } /** - * Checks if the state of a given item has been updated between two points in time. + * Checks if the state of a given item will be updated till a certain point in time. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the item to check for state changes + * @param timestamp the point in time to end the check + * @param serviceId the name of the {@link PersistenceService} to use + * @return true if item state was updated or false if either the item is not updated + * since timestamp, null if the given serviceId does not refer to a + * {@link QueryablePersistenceService} + */ + public static @Nullable Boolean updatedTill(Item item, ZonedDateTime timestamp, String serviceId) { + return internalUpdatedBetween(item, null, timestamp, serviceId); + } + + /** + * Checks if the state of a given item is updated between two points in time. * The {@link PersistenceService} identified by the serviceId is used. * * @param item the item to check for state changes * @param begin the point in time to start the check * @param end the point in time to stop the check * @param serviceId the name of the {@link PersistenceService} to use - * @return true if item state was updated or false if either the item has not been updated - * in the given interval or if the given serviceId does not refer to a + * @return true if item state was updated or false if either the item is not updated + * in the given interval, null if the given serviceId does not refer to a * {@link QueryablePersistenceService} */ - public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { - Iterable result = getAllStatesBetween(item, begin, end, serviceId); - return result.iterator().hasNext(); + public static @Nullable Boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTime end, + String serviceId) { + return internalUpdatedBetween(item, begin, end, serviceId); + } + + private static @Nullable Boolean internalUpdatedBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end) { + String serviceId = getDefaultServiceId(); + return serviceId != null ? internalUpdatedBetween(item, begin, end, serviceId) : null; + } + + private static @Nullable Boolean internalUpdatedBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end, String serviceId) { + Iterable result = internalGetAllStatesBetween(item, begin, end, serviceId); + if (result != null) { + return result.iterator().hasNext(); + } + return null; } /** @@ -395,22 +766,36 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * {@link QueryablePersistenceService} */ public static @Nullable HistoricItem maximumSince(Item item, ZonedDateTime timestamp) { - return maximumSince(item, timestamp, getDefaultServiceId()); + return internalMaximumBetween(item, timestamp, null); } /** - * Gets the historic item with the maximum value of the state of a given item since + * Gets the historic item with the maximum value of the state of a given item till * a certain point in time. The default persistence service is used. * * @param item the item to get the maximum state value for + * @param timestamp the point in time to end the check + * @return a historic item with the maximum state value till the given point in time, or a {@link HistoricItem} + * constructed from the item if the default persistence service does not refer to a + * {@link QueryablePersistenceService} + */ + public static @Nullable HistoricItem maximumTill(Item item, ZonedDateTime timestamp) { + return internalMaximumBetween(item, null, timestamp); + } + + /** + * Gets the historic item with the maximum value of the state of a given item between two points in + * time. The default persistence service is used. + * + * @param item the item to get the maximum state value for * @param begin the point in time to start the check * @param end the point in time to stop the check - * @return a {@link HistoricItem} with the maximum state value since the given point in time, or null + * @return a {@link HistoricItem} with the maximum state value between two points in time, or null * if no states found or if the default persistence service does not refer to an available * {@link QueryablePersistenceService} */ public static @Nullable HistoricItem maximumBetween(final Item item, ZonedDateTime begin, ZonedDateTime end) { - return internalMaximum(item, begin, end, getDefaultServiceId()); + return internalMaximumBetween(item, begin, end); } /** @@ -426,33 +811,58 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * {@link QueryablePersistenceService} */ public static @Nullable HistoricItem maximumSince(final Item item, ZonedDateTime timestamp, String serviceId) { - return internalMaximum(item, timestamp, null, serviceId); + return internalMaximumBetween(item, timestamp, null, serviceId); } /** - * Gets the historic item with the maximum value of the state of a given item since + * Gets the historic item with the maximum value of the state of a given item till * a certain point in time. The {@link PersistenceService} identified by the serviceId is used. * * @param item the item to get the maximum state value for + * @param timestamp the point in time to end the check + * @param serviceId the name of the {@link PersistenceService} to use + * @return a {@link HistoricItem} with the maximum state value till the given point in time, or a + * {@link HistoricItem} constructed from the item's state if item's state is the + * maximum value or if the given serviceId does not refer to an available + * {@link QueryablePersistenceService} + */ + public static @Nullable HistoricItem maximumTill(final Item item, ZonedDateTime timestamp, String serviceId) { + return internalMaximumBetween(item, null, timestamp, serviceId); + } + + /** + * Gets the historic item with the maximum value of the state of a given item between two points in + * time. The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the item to get the maximum state value for * @param begin the point in time to start the check * @param end the point in time to stop the check * @param serviceId the name of the {@link PersistenceService} to use - * @return a {@link HistoricItem} with the maximum state value since the given point in time, or + * @return a {@link HistoricItem} with the maximum state value between two points in time, or * null no states found or if the given serviceId does not refer to an * available {@link QueryablePersistenceService} */ public static @Nullable HistoricItem maximumBetween(final Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { - return internalMaximum(item, begin, end, serviceId); + return internalMaximumBetween(item, begin, end, serviceId); + } + + private static @Nullable HistoricItem internalMaximumBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end) { + String serviceId = getDefaultServiceId(); + return serviceId != null ? internalMaximumBetween(item, begin, end, serviceId) : null; } - private static @Nullable HistoricItem internalMaximum(final Item item, ZonedDateTime begin, + private static @Nullable HistoricItem internalMaximumBetween(final Item item, @Nullable ZonedDateTime begin, @Nullable ZonedDateTime end, String serviceId) { Iterable result = getAllStatesBetweenWithBoundaries(item, begin, end, serviceId); + if (result == null) { + return null; + } Iterator it = result.iterator(); HistoricItem maximumHistoricItem = null; - // include current state only if no end time is given - DecimalType maximum = end == null ? item.getStateAs(DecimalType.class) : null; + + DecimalType maximum = null; while (it.hasNext()) { HistoricItem historicItem = it.next(); DecimalType value = historicItem.getState().as(DecimalType.class); @@ -463,7 +873,7 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi } } } - return historicItemOrCurrentState(item, maximumHistoricItem, maximum); + return historicItemOrCurrentState(item, maximumHistoricItem); } /** @@ -477,22 +887,36 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * the default persistence service does not refer to an available {@link QueryablePersistenceService} */ public static @Nullable HistoricItem minimumSince(Item item, ZonedDateTime timestamp) { - return minimumSince(item, timestamp, getDefaultServiceId()); + return internalMinimumBetween(item, timestamp, null); } /** - * Gets the historic item with the minimum value of the state of a given item between - * two certain points in time. The default persistence service is used. + * Gets the historic item with the minimum value of the state of a given item till + * a certain point in time. The default persistence service is used. * * @param item the item to get the minimum state value for - * @param begin the beginning point in time - * @param end the end point in time to + * @param timestamp the point in time to which to search for the minimum state value + * @return the historic item with the minimum state value till the given point in time or a {@link HistoricItem} + * constructed from the item's state if item's state is the minimum value or if + * the default persistence service does not refer to an available {@link QueryablePersistenceService} + */ + public static @Nullable HistoricItem minimumTill(Item item, ZonedDateTime timestamp) { + return internalMinimumBetween(item, null, timestamp); + } + + /** + * Gets the historic item with the minimum value of the state of a given item between + * two certain points in time. The default persistence service is used. + * + * @param item the item to get the minimum state value for + * @param begin the beginning point in time + * @param end the ending point in time to * @return the historic item with the minimum state value between the given points in time, or null if * not state was found or if * the default persistence service does not refer to an available {@link QueryablePersistenceService} */ public static @Nullable HistoricItem minimumBetween(final Item item, ZonedDateTime begin, ZonedDateTime end) { - return internalMinimum(item, begin, end, getDefaultServiceId()); + return internalMinimumBetween(item, begin, end); } /** @@ -507,7 +931,22 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * the given serviceId does not refer to an available {@link QueryablePersistenceService}. */ public static @Nullable HistoricItem minimumSince(final Item item, ZonedDateTime timestamp, String serviceId) { - return internalMinimum(item, timestamp, null, serviceId); + return internalMinimumBetween(item, timestamp, null, serviceId); + } + + /** + * Gets the historic item with the minimum value of the state of a given item till + * a certain point in time. The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the item to get the minimum state value for + * @param timestamp the point in time to which to search for the minimum state value + * @param serviceId the name of the {@link PersistenceService} to use + * @return the historic item with the minimum state value till the given point in time, or a {@link HistoricItem} + * constructed from the item's state if item's state is the minimum value or if + * the given serviceId does not refer to an available {@link QueryablePersistenceService}. + */ + public static @Nullable HistoricItem minimumTill(final Item item, ZonedDateTime timestamp, String serviceId) { + return internalMinimumBetween(item, null, timestamp, serviceId); } /** @@ -524,15 +963,25 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi */ public static @Nullable HistoricItem minimumBetween(final Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { - return internalMinimum(item, begin, end, serviceId); + return internalMinimumBetween(item, begin, end, serviceId); + } + + private static @Nullable HistoricItem internalMinimumBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end) { + String serviceId = getDefaultServiceId(); + return serviceId != null ? internalMinimumBetween(item, begin, end, serviceId) : null; } - private static @Nullable HistoricItem internalMinimum(final Item item, ZonedDateTime begin, + private static @Nullable HistoricItem internalMinimumBetween(final Item item, @Nullable ZonedDateTime begin, @Nullable ZonedDateTime end, String serviceId) { Iterable result = getAllStatesBetweenWithBoundaries(item, begin, end, serviceId); + if (result == null) { + return null; + } Iterator it = result.iterator(); HistoricItem minimumHistoricItem = null; - DecimalType minimum = end == null ? item.getStateAs(DecimalType.class) : null; + + DecimalType minimum = null; while (it.hasNext()) { HistoricItem historicItem = it.next(); DecimalType value = historicItem.getState().as(DecimalType.class); @@ -543,7 +992,7 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi } } } - return historicItemOrCurrentState(item, minimumHistoricItem, minimum); + return historicItemOrCurrentState(item, minimumHistoricItem); } /** @@ -552,12 +1001,26 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * * @param item the {@link Item} to get the variance for * @param timestamp the point in time from which to compute the variance + * @return the variance between then and now, or null 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) { + return internalVarianceBetween(item, timestamp, null); + } + + /** + * Gets the variance of the state of the given {@link Item} till 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 * @return the variance between now and then, or null 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 DecimalType varianceSince(Item item, ZonedDateTime timestamp) { - return varianceSince(item, timestamp, getDefaultServiceId()); + public static @Nullable State varianceTill(Item item, ZonedDateTime timestamp) { + return internalVarianceBetween(item, null, timestamp); } /** @@ -571,8 +1034,8 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * 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 DecimalType varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return varianceBetween(item, begin, end, getDefaultServiceId()); + public static @Nullable State varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { + return internalVarianceBetween(item, begin, end); } /** @@ -582,12 +1045,27 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * @param item the {@link Item} to get the variance for * @param timestamp the point in time from which to compute the variance * @param serviceId the name of the {@link PersistenceService} to use + * @return the variance between then and now, or null 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, String serviceId) { + return internalVarianceBetween(item, timestamp, null, serviceId); + } + + /** + * Gets the variance of the state of the given {@link Item} till 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 serviceId the name of the {@link PersistenceService} to use * @return the variance between now and then, or null 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 DecimalType varianceSince(Item item, ZonedDateTime timestamp, String serviceId) { - return internalVariance(item, timestamp, null, serviceId); + public static @Nullable State varianceTill(Item item, ZonedDateTime timestamp, String serviceId) { + return internalVarianceBetween(item, null, timestamp, serviceId); } /** @@ -602,22 +1080,30 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * 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 DecimalType varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end, - String serviceId) { - return internalVariance(item, begin, end, serviceId); + public static @Nullable State varianceBetween(Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { + return internalVarianceBetween(item, begin, end, serviceId); } - private static @Nullable DecimalType internalVariance(Item item, ZonedDateTime begin, @Nullable ZonedDateTime end, - String serviceId) { + private static @Nullable State internalVarianceBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end) { + String serviceId = getDefaultServiceId(); + return serviceId != null ? internalVarianceBetween(item, begin, end, serviceId) : null; + } + + private static @Nullable State internalVarianceBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end, String serviceId) { Iterable result = getAllStatesBetweenWithBoundaries(item, begin, end, serviceId); - Iterator it = result.iterator(); - DecimalType averageSince = internalAverage(item, it, end); + if (result == null) { + return null; + } + State averageState = internalAverageBetween(item, begin, end, serviceId); - if (averageSince != null) { - BigDecimal average = averageSince.toBigDecimal(), sum = BigDecimal.ZERO; + if (averageState != null) { + DecimalType dt = averageState.as(DecimalType.class); + BigDecimal average = dt != null ? dt.toBigDecimal() : BigDecimal.ZERO, sum = BigDecimal.ZERO; int count = 0; - it = result.iterator(); + Iterator it = result.iterator(); while (it.hasNext()) { HistoricItem historicItem = it.next(); DecimalType value = historicItem.getState().as(DecimalType.class); @@ -630,7 +1116,14 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi // avoid division by zero if (count > 0) { - return new DecimalType(sum.divide(BigDecimal.valueOf(count), MathContext.DECIMAL64)); + BigDecimal variance = sum.divide(BigDecimal.valueOf(count), MathContext.DECIMAL64); + if (item instanceof NumberItem numberItem) { + Unit unit = numberItem.getUnit(); + if (unit != null) { + return new QuantityType<>(variance, unit.multiply(unit)); + } + } + return new DecimalType(variance); } } return null; @@ -645,12 +1138,29 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * * @param item the {@link Item} to get the standard deviation for * @param timestamp the point in time from which to compute the standard deviation + * @return the standard deviation between then and now, or null 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) { + return internalDeviationBetween(item, timestamp, null); + } + + /** + * Gets the standard deviation of the state of the given {@link Item} till 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 * @return the standard deviation between now and then, or null 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 DecimalType deviationSince(Item item, ZonedDateTime timestamp) { - return deviationSince(item, timestamp, getDefaultServiceId()); + public static @Nullable State deviationTill(Item item, ZonedDateTime timestamp) { + return internalDeviationBetween(item, timestamp, null); } /** @@ -667,8 +1177,8 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * service available, or it is not a {@link QueryablePersistenceService}, or if there is no persisted state * for the given item in the given interval */ - public static @Nullable DecimalType deviationBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return deviationBetween(item, begin, end, getDefaultServiceId()); + public static @Nullable State deviationBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { + return internalDeviationBetween(item, begin, end); } /** @@ -685,8 +1195,26 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * serviceId it is not available or is not a {@link QueryablePersistenceService}, or if there * is no persisted state for the given item at the given timestamp */ - public static @Nullable DecimalType deviationSince(Item item, ZonedDateTime timestamp, String serviceId) { - return internalDeviation(item, timestamp, null, serviceId); + public static @Nullable State deviationSince(Item item, ZonedDateTime timestamp, String serviceId) { + return internalDeviationBetween(item, timestamp, null, serviceId); + } + + /** + * Gets the standard deviation of the state of the given {@link Item} till 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 serviceId the name of the {@link PersistenceService} to use + * @return the standard deviation between now and then, or null if the persistence service given by + * serviceId it is not available or is not a {@link QueryablePersistenceService}, or if there + * is no persisted state for the given item at the given timestamp + */ + public static @Nullable State deviationTill(Item item, ZonedDateTime timestamp, String serviceId) { + return internalDeviationBetween(item, null, timestamp, serviceId); } /** @@ -704,21 +1232,33 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * serviceId it is not available or is not a {@link QueryablePersistenceService}, or if there * is no persisted state for the given item in the given interval */ - public static @Nullable DecimalType deviationBetween(Item item, ZonedDateTime begin, ZonedDateTime end, + public static @Nullable State deviationBetween(Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { - return internalDeviation(item, begin, end, serviceId); + return internalDeviationBetween(item, begin, end, serviceId); } - private static @Nullable DecimalType internalDeviation(Item item, ZonedDateTime begin, @Nullable ZonedDateTime end, - String serviceId) { - DecimalType variance = internalVariance(item, begin, end, serviceId); + private static @Nullable State internalDeviationBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end) { + String serviceId = getDefaultServiceId(); + return serviceId != null ? internalDeviationBetween(item, begin, end, serviceId) : null; + } - if (variance != null) { - BigDecimal bd = variance.toBigDecimal(); + private static @Nullable State internalDeviationBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end, String serviceId) { + State variance = internalVarianceBetween(item, begin, end, serviceId); + if (variance != null) { + DecimalType dt = variance.as(DecimalType.class); // avoid ArithmeticException if variance is less than zero - if (BigDecimal.ZERO.compareTo(bd) <= 0) { - return new DecimalType(bd.sqrt(MathContext.DECIMAL64)); + if (dt != null && DecimalType.ZERO.compareTo(dt) <= 0) { + BigDecimal deviation = dt.toBigDecimal().sqrt(MathContext.DECIMAL64); + if (item instanceof NumberItem numberItem) { + Unit unit = numberItem.getUnit(); + if (unit != null) { + return new QuantityType<>(deviation, unit); + } + } + return new DecimalType(deviation); } } return null; @@ -734,8 +1274,22 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * 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 DecimalType averageSince(Item item, ZonedDateTime timestamp) { - return averageSince(item, timestamp, getDefaultServiceId()); + public static @Nullable State averageSince(Item item, ZonedDateTime timestamp) { + return internalAverageBetween(item, timestamp, null); + } + + /** + * Gets the average value of the state of a given {@link Item} till 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 + * @return the average value to 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 averageTill(Item item, ZonedDateTime timestamp) { + return internalAverageBetween(item, null, timestamp); } /** @@ -749,8 +1303,8 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * previous states could be found or if the default persistence service does not refer to an available * {@link QueryablePersistenceService}. */ - public static @Nullable DecimalType averageBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return averageBetween(item, begin, end, getDefaultServiceId()); + public static @Nullable State averageBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { + return internalAverageBetween(item, begin, end); } /** @@ -765,8 +1319,24 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * refer to an available {@link QueryablePersistenceService}. The current state is included in the * calculation. */ - public static @Nullable DecimalType averageSince(Item item, ZonedDateTime timestamp, String serviceId) { - return averageBetween(item, timestamp, null, serviceId); + public static @Nullable State averageSince(Item item, ZonedDateTime timestamp, String serviceId) { + return internalAverageBetween(item, timestamp, null, serviceId); + } + + /** + * Gets the average value of the state of a given {@link Item} till 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 serviceId the name of the {@link PersistenceService} to use + * @return the average value to 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 averageTill(Item item, ZonedDateTime timestamp, String serviceId) { + return internalAverageBetween(item, null, timestamp, serviceId); } /** @@ -781,17 +1351,30 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * previous states could be found or if the persistence service given by serviceId does not * refer to an available {@link QueryablePersistenceService} */ - public static @Nullable DecimalType averageBetween(Item item, ZonedDateTime begin, ZonedDateTime end, - String serviceId) { + public static @Nullable State averageBetween(Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { + return internalAverageBetween(item, begin, end, serviceId); + } + + private static @Nullable State internalAverageBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end) { + String serviceId = getDefaultServiceId(); + return serviceId != null ? internalAverageBetween(item, begin, end, serviceId) : null; + } + + private static @Nullable State internalAverageBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end, String serviceId) { Iterable result = getAllStatesBetweenWithBoundaries(item, begin, end, serviceId); + if (result == null) { + return null; + } Iterator it = result.iterator(); - return internalAverage(item, it, end); - } + ZonedDateTime now = ZonedDateTime.now(); + ZonedDateTime beginTime = begin == null ? now : begin; + ZonedDateTime endTime = end == null ? now : end; - @SuppressWarnings("null") - private static @Nullable DecimalType internalAverage(Item item, Iterator it, ZonedDateTime endTime) { - if (endTime == null) { - endTime = ZonedDateTime.now(); + if (beginTime.isEqual(endTime)) { + HistoricItem historicItem = internalPersistedState(item, beginTime, serviceId); + return historicItem != null ? historicItem.getState() : null; } BigDecimal sum = BigDecimal.ZERO; @@ -799,13 +1382,23 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi HistoricItem lastItem = null; ZonedDateTime firstTimestamp = null; + // if (beginTime.equals(now)) { + // HistoricItem historicItem = internalPersistedState(item, now, serviceId); + // if (historicItem != null) { + // lastItem = new RetimedHistoricItem(historicItem, now); + // firstTimestamp = now; + // } + // } while (it.hasNext()) { HistoricItem thisItem = it.next(); - if (lastItem != null) { - BigDecimal value = lastItem.getState().as(DecimalType.class).toBigDecimal(); - BigDecimal weight = BigDecimal - .valueOf(Duration.between(lastItem.getTimestamp(), thisItem.getTimestamp()).toMillis()); - sum = sum.add(value.multiply(weight)); + if (lastItem != null && lastItem.getState() instanceof State state) { + DecimalType dtState = state.as(DecimalType.class); + if (dtState != null) { + BigDecimal value = dtState.toBigDecimal(); + BigDecimal weight = BigDecimal + .valueOf(Duration.between(lastItem.getTimestamp(), thisItem.getTimestamp()).toMillis()); + sum = sum.add(value.multiply(weight)); + } } if (firstTimestamp == null) { @@ -813,17 +1406,28 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi } lastItem = thisItem; } - - if (lastItem != null) { - BigDecimal value = lastItem.getState().as(DecimalType.class).toBigDecimal(); - BigDecimal weight = BigDecimal.valueOf(Duration.between(lastItem.getTimestamp(), endTime).toMillis()); - sum = sum.add(value.multiply(weight)); - } + // if (endTime.equals(now) && lastItem != null && lastItem.getState() instanceof State state) { + // DecimalType dtState = state.as(DecimalType.class); + // if (dtState != null) { + // BigDecimal value = dtState.toBigDecimal(); + // BigDecimal weight = BigDecimal.valueOf(Duration.between(lastItem.getTimestamp(), now).toMillis()); + // sum = sum.add(value.multiply(weight)); + // } + // } if (firstTimestamp != null) { BigDecimal totalDuration = BigDecimal.valueOf(Duration.between(firstTimestamp, endTime).toMillis()); - return totalDuration.signum() == 0 ? null - : new DecimalType(sum.divide(totalDuration, MathContext.DECIMAL64)); + if (totalDuration.signum() == 0) { + return null; + } + BigDecimal average = sum.divide(totalDuration, MathContext.DECIMAL64); + if (item instanceof NumberItem numberItem) { + Unit unit = numberItem.getUnit(); + if (unit != null) { + return new QuantityType<>(average, unit); + } + } + return new DecimalType(average); } return null; @@ -839,8 +1443,22 @@ public static boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTi * states could be found or if the default persistence service does not refer to a * {@link QueryablePersistenceService} */ - public static DecimalType sumSince(Item item, ZonedDateTime timestamp) { - return sumSince(item, timestamp, getDefaultServiceId()); + public @Nullable static State sumSince(Item item, ZonedDateTime timestamp) { + return internalSumBetween(item, timestamp, null); + } + + /** + * Gets the sum of the state of a given item till a certain point in time. + * The default persistence service is used. + * + * @param item the item for which we will sum its persisted state values to timestamp + * @param timestamp the point in time to which to start the summation + * @return the sum of the state values to timestamp, or {@link DecimalType#ZERO} if no historic + * states could be found or if the default persistence service does not refer to a + * {@link QueryablePersistenceService} + */ + public @Nullable static State sumTill(Item item, ZonedDateTime timestamp) { + return internalSumBetween(item, null, timestamp); } /** @@ -855,8 +1473,8 @@ public static DecimalType sumSince(Item item, ZonedDateTime timestamp) { * states could be found or if the default persistence service does not refer to a * {@link QueryablePersistenceService} */ - public static DecimalType sumBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return sumBetween(item, begin, end, getDefaultServiceId()); + public @Nullable static State sumBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { + return internalSumBetween(item, begin, end); } /** @@ -870,8 +1488,23 @@ public static DecimalType sumBetween(Item item, ZonedDateTime begin, ZonedDateTi * states could be found for the item or if serviceId does not refer to a * {@link QueryablePersistenceService} */ - public static DecimalType sumSince(Item item, ZonedDateTime timestamp, String serviceId) { - return internalSum(item, timestamp, null, serviceId); + public @Nullable static State sumSince(Item item, ZonedDateTime timestamp, String serviceId) { + return internalSumBetween(item, timestamp, null, serviceId); + } + + /** + * Gets the sum of the state of a given item till a certain point in time. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the item for which we will sum its persisted state values to timestamp + * @param timestamp the point in time to which to start the summation + * @param serviceId the name of the {@link PersistenceService} to use + * @return the sum of the state values to the given point in time, or {@link DecimalType#ZERO} if no historic + * states could be found for the item or if serviceId does not refer to a + * {@link QueryablePersistenceService} + */ + public @Nullable static State sumTill(Item item, ZonedDateTime timestamp, String serviceId) { + return internalSumBetween(item, null, timestamp, serviceId); } /** @@ -887,24 +1520,39 @@ public static DecimalType sumSince(Item item, ZonedDateTime timestamp, String se * states could be found for the item or if serviceId does not refer to a * {@link QueryablePersistenceService} */ - public static DecimalType sumBetween(Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { - return internalSum(item, begin, end, serviceId); + public @Nullable static State sumBetween(Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { + return internalSumBetween(item, begin, end, serviceId); } - private static DecimalType internalSum(Item item, ZonedDateTime begin, @Nullable ZonedDateTime end, - String serviceId) { - Iterable result = getAllStatesBetween(item, begin, end, serviceId); - Iterator it = result.iterator(); + private static @Nullable State internalSumBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end) { + String serviceId = getDefaultServiceId(); + return serviceId != null ? internalSumBetween(item, begin, end, serviceId) : null; + } - BigDecimal sum = BigDecimal.ZERO; - while (it.hasNext()) { - HistoricItem historicItem = it.next(); - DecimalType value = historicItem.getState().as(DecimalType.class); - if (value != null) { - sum = sum.add(value.toBigDecimal()); + private @Nullable static State internalSumBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end, String serviceId) { + Iterable result = internalGetAllStatesBetween(item, begin, end, serviceId); + if (result != null) { + Iterator it = result.iterator(); + + BigDecimal sum = BigDecimal.ZERO; + while (it.hasNext()) { + HistoricItem historicItem = it.next(); + DecimalType value = historicItem.getState().as(DecimalType.class); + if (value != null) { + sum = sum.add(value.toBigDecimal()); + } } + if (item instanceof NumberItem numberItem) { + Unit unit = numberItem.getUnit(); + if (unit != null) { + return new QuantityType<>(sum, unit); + } + } + return new DecimalType(sum); } - return new DecimalType(sum); + return null; } /** @@ -918,8 +1566,23 @@ private static DecimalType internalSum(Item item, ZonedDateTime begin, @Nullable * there is no persisted state for the given item at the given timestamp available * in the default persistence service */ - public static @Nullable DecimalType deltaSince(Item item, ZonedDateTime timestamp) { - return deltaSince(item, timestamp, getDefaultServiceId()); + public static @Nullable State deltaSince(Item item, ZonedDateTime timestamp) { + return internalDeltaBetween(item, timestamp, null); + } + + /** + * Gets the difference value of the state of a given item till a certain point in time. + * The default persistence service is used. + * + * @param item the item to get the average state value for + * @param timestamp the point in time to which to compute the delta + * @return the difference between then and now, or null if there is no default persistence + * service available, the default persistence service is not a {@link QueryablePersistenceService}, or if + * there is no persisted state for the given item at the given timestamp available + * in the default persistence service + */ + public static @Nullable State deltaTill(Item item, ZonedDateTime timestamp) { + return internalDeltaBetween(item, null, timestamp); } /** @@ -933,8 +1596,8 @@ private static DecimalType internalSum(Item item, ZonedDateTime begin, @Nullable * refer to an available {@link QueryablePersistenceService}, or if there is no persisted state for the * given item for the given points in time */ - public static @Nullable DecimalType deltaBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { - return deltaBetween(item, begin, end, getDefaultServiceId()); + public static @Nullable State deltaBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { + return internalDeltaBetween(item, begin, end); } /** @@ -949,16 +1612,24 @@ private static DecimalType internalSum(Item item, ZonedDateTime begin, @Nullable * item at the given timestamp using the persistence service named * serviceId */ - public static @Nullable DecimalType deltaSince(Item item, ZonedDateTime timestamp, String serviceId) { - HistoricItem itemThen = historicState(item, timestamp, serviceId); - if (itemThen != null) { - DecimalType valueThen = itemThen.getState().as(DecimalType.class); - DecimalType valueNow = item.getStateAs(DecimalType.class); - if (valueThen != null && valueNow != null) { - return new DecimalType(valueNow.toBigDecimal().subtract(valueThen.toBigDecimal())); - } - } - return null; + public static @Nullable State deltaSince(Item item, ZonedDateTime timestamp, String serviceId) { + return internalDeltaBetween(item, timestamp, null, serviceId); + } + + /** + * Gets the difference value of the state of a given item till a certain point in time. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the item to get the delta for + * @param timestamp the point in time to which to compute the delta + * @param serviceId the name of the {@link PersistenceService} to use + * @return the difference between then and now, or null if the given serviceId does not refer to an + * available {@link QueryablePersistenceService}, or if there is no persisted state for the given + * item at the given timestamp using the persistence service named + * serviceId + */ + public static @Nullable State deltaTill(Item item, ZonedDateTime timestamp, String serviceId) { + return internalDeltaBetween(item, null, timestamp, serviceId); } /** @@ -973,15 +1644,34 @@ private static DecimalType internalSum(Item item, ZonedDateTime begin, @Nullable * available {@link QueryablePersistenceService}, or if there is no persisted state for the given * item at the given points in time */ - public static @Nullable DecimalType deltaBetween(Item item, ZonedDateTime begin, ZonedDateTime end, - String serviceId) { - HistoricItem itemStart = historicState(item, begin, serviceId); - HistoricItem itemStop = historicState(item, end, serviceId); - if (itemStart != null && itemStop != null) { - DecimalType valueStart = itemStart.getState().as(DecimalType.class); - DecimalType valueStop = itemStop.getState().as(DecimalType.class); - if (valueStart != null && valueStop != null) { - return new DecimalType(valueStop.toBigDecimal().subtract(valueStart.toBigDecimal())); + public static @Nullable State deltaBetween(Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { + return internalDeltaBetween(item, begin, end, serviceId); + } + + private static @Nullable State internalDeltaBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end) { + String serviceId = getDefaultServiceId(); + return serviceId != null ? internalDeltaBetween(item, begin, end, serviceId) : null; + } + + private static @Nullable State internalDeltaBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end, String serviceId) { + HistoricItem itemStart = internalPersistedState(item, begin, serviceId); + HistoricItem itemStop = internalPersistedState(item, end, serviceId); + DecimalType valueStart = itemStart != null ? itemStart.getState().as(DecimalType.class) : null; + DecimalType valueStop = itemStop != null ? itemStop.getState().as(DecimalType.class) : null; + if (begin == null && end != null && end.isAfter(ZonedDateTime.now())) { + valueStart = getItemValue(item); + } + if (begin != null && end == null && begin.isBefore(ZonedDateTime.now())) { + valueStop = getItemValue(item); + } + + if (valueStart != null && valueStop != null) { + BigDecimal delta = valueStop.toBigDecimal().subtract(valueStart.toBigDecimal()); + if (item instanceof NumberItem numberItem) { + Unit unit = numberItem.getUnit(); + return (unit != null) ? new QuantityType<>(delta, unit) : new DecimalType(delta); } } return null; @@ -999,8 +1689,24 @@ private static DecimalType internalSum(Item item, ZonedDateTime begin, @Nullable * the given timestamp, or if there is a state but it is zero (which would cause a * divide-by-zero error) */ - public static DecimalType evolutionRate(Item item, ZonedDateTime timestamp) { - return evolutionRate(item, timestamp, getDefaultServiceId()); + public static @Nullable DecimalType evolutionRateSince(Item item, ZonedDateTime timestamp) { + return internalEvolutionRateBetween(item, timestamp, null); + } + + /** + * Gets the evolution rate of the state of a given {@link Item} till a certain point in time. + * The default {@link PersistenceService} is used. + * + * @param item the item to get the evolution rate value for + * @param timestamp the point in time to which to compute the evolution rate + * @return the evolution rate in percent (positive and negative) between then and now, or null if + * there is no default persistence service available, the default persistence service is not a + * {@link QueryablePersistenceService}, or if there is no persisted state for the given item at + * the given timestamp, or if there is a state but it is zero (which would cause a + * divide-by-zero error) + */ + public static @Nullable DecimalType evolutionRateTill(Item item, ZonedDateTime timestamp) { + return internalEvolutionRateBetween(item, null, timestamp); } /** @@ -1016,8 +1722,8 @@ public static DecimalType evolutionRate(Item item, ZonedDateTime timestamp) { * at the given interval, or if there is a state but it is zero (which would cause a * divide-by-zero error) */ - public static DecimalType evolutionRate(Item item, ZonedDateTime begin, ZonedDateTime end) { - return evolutionRate(item, begin, end, getDefaultServiceId()); + public static @Nullable DecimalType evolutionRateBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { + return internalEvolutionRateBetween(item, begin, end); } /** @@ -1034,18 +1740,26 @@ public static DecimalType evolutionRate(Item item, ZonedDateTime begin, ZonedDat * serviceId, or if there is a state but it is zero (which would cause a divide-by-zero * error) */ - public static @Nullable DecimalType evolutionRate(Item item, ZonedDateTime timestamp, String serviceId) { - HistoricItem itemThen = historicState(item, timestamp, serviceId); - if (itemThen != null) { - DecimalType valueThen = itemThen.getState().as(DecimalType.class); - DecimalType valueNow = item.getStateAs(DecimalType.class); - if (valueThen != null && valueThen.toBigDecimal().compareTo(BigDecimal.ZERO) != 0 && valueNow != null) { - // ((now - then) / then) * 100 - return new DecimalType(valueNow.toBigDecimal().subtract(valueThen.toBigDecimal()) - .divide(valueThen.toBigDecimal(), MathContext.DECIMAL64).movePointRight(2)); - } - } - return null; + public static @Nullable DecimalType evolutionRateSince(Item item, ZonedDateTime timestamp, String serviceId) { + return internalEvolutionRateBetween(item, timestamp, null, serviceId); + } + + /** + * Gets the evolution rate of the state of a given {@link Item} till a certain point in time. + * The {@link PersistenceService} identified by the serviceId is used. + * + * @param item the {@link Item} to get the evolution rate value for + * @param timestamp the point in time to which to compute the evolution rate + * @param serviceId the name of the {@link PersistenceService} to use + * @return the evolution rate in percent (positive and negative) between then and now, or null if + * the persistence service given by serviceId is not available or is not a + * {@link QueryablePersistenceService}, or if there is no persisted state for the given + * item at the given timestamp using the persistence service given by + * serviceId, or if there is a state but it is zero (which would cause a divide-by-zero + * error) + */ + public static @Nullable DecimalType evolutionRateTill(Item item, ZonedDateTime timestamp, String serviceId) { + return internalEvolutionRateBetween(item, null, timestamp, serviceId); } /** @@ -1063,19 +1777,33 @@ public static DecimalType evolutionRate(Item item, ZonedDateTime begin, ZonedDat * given by serviceId, or if there is a state but it is zero (which would cause a * divide-by-zero error) */ - public static @Nullable DecimalType evolutionRate(Item item, ZonedDateTime begin, ZonedDateTime end, + public static @Nullable DecimalType evolutionRateBetween(Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { - HistoricItem itemBegin = historicState(item, begin, serviceId); - HistoricItem itemEnd = historicState(item, end, serviceId); - - if (itemBegin != null && itemEnd != null) { - DecimalType valueBegin = itemBegin.getState().as(DecimalType.class); - DecimalType valueEnd = itemEnd.getState().as(DecimalType.class); - if (valueBegin != null && valueBegin.toBigDecimal().compareTo(BigDecimal.ZERO) != 0 && valueEnd != null) { - // ((now - then) / then) * 100 - return new DecimalType(valueEnd.toBigDecimal().subtract(valueBegin.toBigDecimal()) - .divide(valueBegin.toBigDecimal(), MathContext.DECIMAL64).movePointRight(2)); - } + return internalEvolutionRateBetween(item, begin, end, serviceId); + } + + private static @Nullable DecimalType internalEvolutionRateBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end) { + String serviceId = getDefaultServiceId(); + return serviceId != null ? internalEvolutionRateBetween(item, begin, end, serviceId) : null; + } + + private static @Nullable DecimalType internalEvolutionRateBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end, String serviceId) { + HistoricItem itemStart = internalPersistedState(item, begin, serviceId); + HistoricItem itemStop = internalPersistedState(item, end, serviceId); + DecimalType valueStart = itemStart != null ? itemStart.getState().as(DecimalType.class) : null; + DecimalType valueStop = itemStop != null ? itemStop.getState().as(DecimalType.class) : null; + if (begin == null && end != null && end.isAfter(ZonedDateTime.now())) { + valueStart = getItemValue(item); + } + if (begin != null && end == null && begin.isBefore(ZonedDateTime.now())) { + valueStop = getItemValue(item); + } + + if (valueStart != null && valueStop != null) { + return new DecimalType(valueStop.toBigDecimal().subtract(valueStart.toBigDecimal()) + .divide(valueStart.toBigDecimal(), MathContext.DECIMAL64).movePointRight(2)); } return null; } @@ -1085,11 +1813,42 @@ public static DecimalType evolutionRate(Item item, ZonedDateTime begin, ZonedDat * The default {@link PersistenceService} is used. * * @param item the {@link Item} to query + * @param timestamp the beginning point in time + * @return the number of values persisted for this item, null + * if the default persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} + */ + public static @Nullable Long countSince(Item item, ZonedDateTime timestamp) { + return internalCountBetween(item, timestamp, null); + } + + /** + * Gets the number of available data points of a given {@link Item} from now to a point in time. + * The default {@link PersistenceService} is used. + * + * @param item the {@link Item} to query + * @param timestamp the ending point in time + * @return the number of values persisted for this item, null + * if the default persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} + */ + public static @Nullable Long countTill(Item item, ZonedDateTime timestamp) { + return internalCountBetween(item, null, timestamp); + } + + /** + * Gets the number of available data points of a given {@link Item} between two points in time. + * The default {@link PersistenceService} is used. + * + * @param item the {@link Item} to query * @param begin the beginning point in time - * @return the number of values persisted for this item + * @param end the end point in time + * @return the number of values persisted for this item, null + * if the default persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} */ - public static long countSince(Item item, ZonedDateTime begin) { - return countSince(item, begin, getDefaultServiceId()); + public static @Nullable Long countBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { + return internalCountBetween(item, begin, end); } /** @@ -1099,42 +1858,62 @@ public static long countSince(Item item, ZonedDateTime begin) { * @param item the {@link Item} to query * @param begin the beginning point in time * @param serviceId the name of the {@link PersistenceService} to use - * @return the number of values persisted for this item + * @return the number of values persisted for this item, null + * if the persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} */ - public static long countSince(Item item, ZonedDateTime begin, String serviceId) { - return countBetween(item, begin, null, serviceId); + public static @Nullable Long countSince(Item item, ZonedDateTime begin, String serviceId) { + return internalCountBetween(item, begin, null, serviceId); } /** - * Gets the number of available historic data points of a given {@link Item} between two points in time. - * The default {@link PersistenceService} is used. + * Gets the number of available data points of a given {@link Item} from now to a point in time. + * The {@link PersistenceService} identified by the serviceId is used. * * @param item the {@link Item} to query - * @param begin the beginning point in time - * @param end the end point in time - * @return the number of values persisted for this item + * @param timestamp the ending point in time + * @param serviceId the name of the {@link PersistenceService} to use + * @return the number of values persisted for this item, null + * if the persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} */ - public static long countBetween(Item item, ZonedDateTime begin, @Nullable ZonedDateTime end) { - return countBetween(item, begin, end, getDefaultServiceId()); + public static @Nullable Long countTill(Item item, ZonedDateTime timestamp, String serviceId) { + return internalCountBetween(item, null, timestamp, serviceId); } /** - * Gets the number of available historic data points of a given {@link Item} between two points in time. + * Gets the number of available data points of a given {@link Item} between two points in time. * The {@link PersistenceService} identified by the serviceId is used. * * @param item the {@link Item} to query * @param begin the beginning point in time * @param end the end point in time * @param serviceId the name of the {@link PersistenceService} to use - * @return the number of values persisted for this item + * @return the number of values persisted for this item, null + * if the persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} */ - public static long countBetween(Item item, ZonedDateTime begin, @Nullable ZonedDateTime end, String serviceId) { - Iterable historicItems = getAllStatesBetween(item, begin, end, serviceId); - if (historicItems instanceof Collection collection) { - return collection.size(); - } else { - return StreamSupport.stream(historicItems.spliterator(), false).count(); + public static @Nullable Long countBetween(Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { + return internalCountBetween(item, begin, end, serviceId); + } + + private static @Nullable Long internalCountBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end) { + String serviceId = getDefaultServiceId(); + return serviceId != null ? internalCountBetween(item, begin, end, serviceId) : null; + } + + private static @Nullable Long internalCountBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end, String serviceId) { + Iterable result = internalGetAllStatesBetween(item, begin, end, serviceId); + if (result != null) { + if (result instanceof Collection collection) { + return Long.valueOf(collection.size()); + } else { + return StreamSupport.stream(result.spliterator(), false).count(); + } } + return null; } /** @@ -1142,11 +1921,42 @@ public static long countBetween(Item item, ZonedDateTime begin, @Nullable ZonedD * The default {@link PersistenceService} is used. * * @param item the {@link Item} to query + * @param timestamp the beginning point in time + * @return the number of state changes for this item, null + * if the default persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} + */ + public static @Nullable Long countStateChangesSince(Item item, ZonedDateTime timestamp) { + return internalCountStateChangesBetween(item, timestamp, null); + } + + /** + * Gets the number of changes in data points of a given {@link Item} from now until a point in time. + * The default {@link PersistenceService} is used. + * + * @param item the {@link Item} to query + * @param timestamp the ending point in time + * @return the number of state changes for this item, null + * if the default persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} + */ + public static @Nullable Long countStateChangesTill(Item item, ZonedDateTime timestamp) { + return internalCountStateChangesBetween(item, null, timestamp); + } + + /** + * Gets the number of changes in data points of a given {@link Item} between two points in time. + * The default {@link PersistenceService} is used. + * + * @param item the {@link Item} to query * @param begin the beginning point in time - * @return the number of state changes for this item + * @param end the end point in time + * @return the number of state changes for this item, null + * if the default persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} */ - public static long countStateChangesSince(Item item, ZonedDateTime begin) { - return countStateChangesSince(item, begin, getDefaultServiceId()); + public static @Nullable Long countStateChangesBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { + return internalCountStateChangesBetween(item, begin, end); } /** @@ -1154,78 +1964,75 @@ public static long countStateChangesSince(Item item, ZonedDateTime begin) { * The {@link PersistenceService} identified by the serviceId is used. * * @param item the {@link Item} to query - * @param begin the beginning point in time + * @param timestamp the beginning point in time * @param serviceId the name of the {@link PersistenceService} to use - * @return the number of state changes for this item + * @return the number of state changes for this item, null + * if the persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} */ - public static long countStateChangesSince(Item item, ZonedDateTime begin, String serviceId) { - return countStateChangesBetween(item, begin, null, serviceId); + public static @Nullable Long countStateChangesSince(Item item, ZonedDateTime timestamp, String serviceId) { + return internalCountStateChangesBetween(item, timestamp, null, serviceId); } /** - * Gets the number of changes in historic data points of a given {@link Item} between two points in time. - * The default {@link PersistenceService} is used. + * Gets the number of changes in data points of a given {@link Item} from now until a point in time. + * The {@link PersistenceService} identified by the serviceId is used. * * @param item the {@link Item} to query - * @param begin the beginning point in time - * @param end the end point in time - * @return the number of state changes for this item + * @param timestamp the ending point in time + * @param serviceId the name of the {@link PersistenceService} to use + * @return the number of state changes for this item, null + * if the persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} */ - public static long countStateChangesBetween(Item item, ZonedDateTime begin, @Nullable ZonedDateTime end) { - return countStateChangesBetween(item, begin, end, getDefaultServiceId()); + public static @Nullable Long countStateChangesTill(Item item, ZonedDateTime timestamp, String serviceId) { + return internalCountStateChangesBetween(item, null, timestamp, serviceId); } /** - * Gets the number of changes in historic data points of a given {@link Item} between two points in time. + * Gets the number of changes in data points of a given {@link Item} between two points in time. * The {@link PersistenceService} identified by the serviceId is used. * * @param item the {@link Item} to query * @param begin the beginning point in time * @param end the end point in time * @param serviceId the name of the {@link PersistenceService} to use - * @return the number of state changes for this item + * @return the number of state changes for this item, null + * if the persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} */ - public static long countStateChangesBetween(Item item, ZonedDateTime begin, @Nullable ZonedDateTime end, + public static @Nullable Long countStateChangesBetween(Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { - Iterable result = getAllStatesBetween(item, begin, end, serviceId); - Iterator it = result.iterator(); - - if (!it.hasNext()) { - return 0; - } - - long count = 0; - State previousState = it.next().getState(); - while (it.hasNext()) { - HistoricItem historicItem = it.next(); - State state = historicItem.getState(); - if (!state.equals(previousState)) { - previousState = state; - count++; - } - } - return count; + return internalCountStateChangesBetween(item, begin, end, serviceId); } - private static @Nullable PersistenceService getService(String serviceId) { - if (registry != null) { - return serviceId != null ? registry.get(serviceId) : registry.getDefault(); - } - return null; + private static @Nullable Long internalCountStateChangesBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end) { + String serviceId = getDefaultServiceId(); + return serviceId != null ? internalCountStateChangesBetween(item, begin, end, serviceId) : null; } - private static @Nullable String getDefaultServiceId() { - if (registry != null) { - String id = registry.getDefaultId(); - if (id != null) { - return id; - } else { - LoggerFactory.getLogger(PersistenceExtensions.class) - .warn("There is no default persistence service configured!"); + private static @Nullable Long internalCountStateChangesBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end, String serviceId) { + Iterable result = internalGetAllStatesBetween(item, begin, end, serviceId); + if (result != null) { + Iterator it = result.iterator(); + + if (!it.hasNext()) { + return Long.valueOf(0); } - } else { - LoggerFactory.getLogger(PersistenceExtensions.class) - .warn("PersistenceServiceRegistryImpl is not available!"); + + long count = 0; + State previousState = it.next().getState(); + while (it.hasNext()) { + HistoricItem historicItem = it.next(); + State state = historicItem.getState(); + if (!state.equals(previousState)) { + previousState = state; + count++; + } + } + return count; } return null; } @@ -1239,8 +2046,36 @@ public static long countStateChangesBetween(Item item, ZonedDateTime begin, @Nul * @return the historic items since the given point in time, or null if no historic items could be * found. */ - public static Iterable getAllStatesSince(Item item, ZonedDateTime timestamp) { - return getAllStatesBetween(item, timestamp, null); + public static @Nullable Iterable getAllStatesSince(Item item, ZonedDateTime timestamp) { + return internalGetAllStatesBetween(item, timestamp, null); + } + + /** + * Retrieves the future items for a given item till a certain point in time. + * The default persistence service is used. + * + * @param item the item for which to retrieve the future item + * @param timestamp the point in time to which to retrieve the states + * @return the future items to the given point in time, or null if no future items could be + * found. + */ + public static @Nullable Iterable getAllStatesTill(Item item, ZonedDateTime timestamp) { + return internalGetAllStatesBetween(item, null, timestamp); + } + + /** + * Retrieves the historic items for a given item between two certain points in time. + * The default persistence service is used. + * + * @param item the item for which to retrieve the historic item + * @param begin the point in time from which to retrieve the states + * @param end the point in time to which to retrieve the states + * @return the historic items between the given points in time, or null if no historic items could be + * found. + */ + public static @Nullable Iterable getAllStatesBetween(Item item, ZonedDateTime begin, + ZonedDateTime end) { + return internalGetAllStatesBetween(item, begin, end); } /** @@ -1250,27 +2085,29 @@ public static Iterable getAllStatesSince(Item item, ZonedDateTime * @param item the item for which to retrieve the historic item * @param timestamp the point in time from which to retrieve the states * @param serviceId the name of the {@link PersistenceService} to use - * @return the historic items since the given point in time, or null if no historic items could be + * @return the future items to the given point in time, or null if no historic items could be * found or if the provided serviceId does not refer to an available * {@link QueryablePersistenceService} */ - public static Iterable getAllStatesSince(Item item, ZonedDateTime timestamp, String serviceId) { - return getAllStatesBetween(item, timestamp, null, serviceId); + public static @Nullable Iterable getAllStatesSince(Item item, ZonedDateTime timestamp, + String serviceId) { + return internalGetAllStatesBetween(item, timestamp, null, serviceId); } /** - * Retrieves the historic items for a given item beetween two certain points in time. - * The default persistence service is used. + * Retrieves the future items for a given item till a certain point in time + * through a {@link PersistenceService} identified by the serviceId. * - * @param item the item for which to retrieve the historic item - * @param begin the point in time from which to retrieve the states - * @param end the point in time to which to retrieve the states - * @return the historic items between the given points in time, or null if no historic items could be - * found. + * @param item the item for which to retrieve the future item + * @param timestamp the point in time to which to retrieve the states + * @param serviceId the name of the {@link PersistenceService} to use + * @return the historic items since the given point in time, or null if no historic items could be + * found or if the provided serviceId does not refer to an available + * {@link QueryablePersistenceService} */ - public static Iterable getAllStatesBetween(Item item, ZonedDateTime begin, - @Nullable ZonedDateTime end) { - return getAllStatesBetween(item, begin, end, getDefaultServiceId()); + public static @Nullable Iterable getAllStatesTill(Item item, ZonedDateTime timestamp, + String serviceId) { + return internalGetAllStatesBetween(item, null, timestamp, serviceId); } /** @@ -1285,64 +2122,134 @@ public static Iterable getAllStatesBetween(Item item, ZonedDateTim * found or if the provided serviceId does not refer to an available * {@link QueryablePersistenceService} */ - public static Iterable getAllStatesBetween(Item item, ZonedDateTime begin, - @Nullable ZonedDateTime end, String serviceId) { + public static @Nullable Iterable getAllStatesBetween(Item item, ZonedDateTime begin, + ZonedDateTime end, String serviceId) { + return internalGetAllStatesBetween(item, begin, end, serviceId); + } + + private static @Nullable Iterable internalGetAllStatesBetween(Item item, + @Nullable ZonedDateTime begin, @Nullable ZonedDateTime end) { + String serviceId = getDefaultServiceId(); + return serviceId != null ? internalGetAllStatesBetween(item, begin, end, serviceId) : null; + } + + private static @Nullable Iterable internalGetAllStatesBetween(Item item, + @Nullable ZonedDateTime begin, @Nullable ZonedDateTime end, String serviceId) { PersistenceService service = getService(serviceId); - if (service instanceof QueryablePersistenceService qService) { + if (service != null && service instanceof QueryablePersistenceService qService) { FilterCriteria filter = new FilterCriteria(); - filter.setBeginDate(begin); + ZonedDateTime now = ZonedDateTime.now(); + if ((begin == null && end == null) || (begin != null && end == null && begin.isAfter(now)) + || (begin == null && end != null && end.isBefore(now))) { + LoggerFactory.getLogger(PersistenceExtensions.class).warn( + "Querying persistence service with open begin and/or end not allowed: begin {}, end {}, now {}", + begin, end, now); + return null; + } + if (begin != null) { + filter.setBeginDate(begin); + } else { + filter.setBeginDate(ZonedDateTime.now()); + } if (end != null) { filter.setEndDate(end); + } else { + filter.setEndDate(ZonedDateTime.now()); } filter.setItemName(item.getName()); filter.setOrdering(Ordering.ASCENDING); return qService.query(filter); - } else { - LoggerFactory.getLogger(PersistenceExtensions.class) - .warn("There is no queryable persistence service registered with the id '{}'", serviceId); - return List.of(); } + LoggerFactory.getLogger(PersistenceExtensions.class) + .warn("There is no queryable persistence service registered with the id '{}'", serviceId); + return null; } - private static Iterable getAllStatesBetweenWithBoundaries(Item item, ZonedDateTime begin, - @Nullable ZonedDateTime end, String serviceId) { - Iterable betweenItems = getAllStatesBetween(item, begin, end, serviceId); + private static @Nullable Iterable getAllStatesBetweenWithBoundaries(Item item, + @Nullable ZonedDateTime begin, @Nullable ZonedDateTime end, String serviceId) { + Iterable betweenItems = internalGetAllStatesBetween(item, begin, end, serviceId); + + ZonedDateTime now = ZonedDateTime.now(); + if ((begin == null && end == null) || (begin != null && end == null && begin.isAfter(now)) + || (begin == null && end != null && end.isBefore(now)) + || (begin != null && end != null && end.isBefore(begin))) { + return null; + } + + ZonedDateTime beginTime = (begin == null) ? now : begin; + ZonedDateTime endTime = (end == null) ? now : end; List betweenItemsList = new ArrayList<>(); - for (HistoricItem historicItem : betweenItems) { - betweenItemsList.add(historicItem); + if (betweenItems != null) { + for (HistoricItem historicItem : betweenItems) { + betweenItemsList.add(historicItem); + } } // add HistoricItem at begin if (betweenItemsList.isEmpty() || !betweenItemsList.get(0).getTimestamp().equals(begin)) { - if (!begin.isAfter(ZonedDateTime.now())) { - HistoricItem first = historicState(item, begin, serviceId); - - if (first != null) { - betweenItemsList.add(0, new RetimedHistoricItem(first, begin)); - } + HistoricItem first = beginTime.equals(now) ? historicItemOrCurrentState(item, null) + : internalPersistedState(item, beginTime, serviceId); + if (first != null) { + first = new RetimedHistoricItem(first, beginTime); + } + if (first != null) { + betweenItemsList.add(0, first); } } // add HistoricItem at end - if (end != null && !end.isAfter(ZonedDateTime.now())) { - if (betweenItemsList.isEmpty() - || !betweenItemsList.get(betweenItemsList.size() - 1).getTimestamp().equals(end)) { - HistoricItem last = historicState(item, end, serviceId); + if (betweenItemsList.isEmpty() + || !betweenItemsList.get(betweenItemsList.size() - 1).getTimestamp().equals(end)) { + HistoricItem last = endTime.equals(now) ? historicItemOrCurrentState(item, null) + : internalPersistedState(item, endTime, serviceId); + if (last != null) { + last = new RetimedHistoricItem(last, endTime); + } + if (last != null) { + betweenItemsList.add(last); + } + } + return !betweenItemsList.isEmpty() ? betweenItemsList : null; + } - if (last != null) { - betweenItemsList.add(new RetimedHistoricItem(last, end)); - } + private static @Nullable PersistenceService getService(String serviceId) { + return registry != null ? registry.get(serviceId) : null; + } + + private static @Nullable String getDefaultServiceId() { + if (registry != null) { + String id = registry.getDefaultId(); + if (id != null) { + return id; + } else { + LoggerFactory.getLogger(PersistenceExtensions.class) + .warn("There is no default persistence service configured!"); } + } else { + LoggerFactory.getLogger(PersistenceExtensions.class) + .warn("PersistenceServiceRegistryImpl is not available!"); } + return null; + } - return betweenItemsList; + private static @Nullable DecimalType getItemValue(Item item) { + if (item instanceof NumberItem numberItem) { + Unit unit = numberItem.getUnit(); + if (unit != null) { + QuantityType qt = item.getStateAs(QuantityType.class); + qt = (qt != null) ? qt.toUnit(unit) : qt; + if (qt != null) { + return new DecimalType(qt.toBigDecimal()); + } + } + } + return item.getStateAs(DecimalType.class); } - private static @Nullable HistoricItem historicItemOrCurrentState(Item item, HistoricItem historicItem, - DecimalType value) { - if (historicItem == null && value != null) { + private static @Nullable HistoricItem historicItemOrCurrentState(Item item, @Nullable HistoricItem historicItem) { + if (historicItem == null) { // there are no historic states we couldn't determine a value, construct a HistoricItem from the current // state return new HistoricItem() { 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 0819f3f0fac..d2c8a7d7116 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 @@ -12,21 +12,13 @@ */ package org.openhab.core.persistence.extensions; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.closeTo; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.when; +import static org.openhab.core.persistence.extensions.TestPersistenceService.*; -import java.time.Duration; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; @@ -45,24 +37,28 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; +import org.openhab.core.i18n.TimeZoneProvider; import org.openhab.core.i18n.UnitProvider; import org.openhab.core.items.GenericItem; import org.openhab.core.items.ItemRegistry; import org.openhab.core.items.ItemUtil; import org.openhab.core.library.CoreItemFactory; import org.openhab.core.library.types.DecimalType; -import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.unit.SIUnits; +import org.openhab.core.library.unit.Units; import org.openhab.core.persistence.HistoricItem; import org.openhab.core.persistence.PersistenceService; import org.openhab.core.persistence.PersistenceServiceRegistry; +import org.openhab.core.types.State; /** * @author Kai Kreuzer - Initial contribution * @author Chris Jackson - Initial contribution * @author Jan N. Klug - Fix averageSince calculation * @author Jan N. Klug - Interval method tests and refactoring + * @author Mark Herwege - Changed return types to State for some interval methods to also return unit + * @author Mark Herwege - Extended for future dates */ @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) @@ -75,6 +71,7 @@ public class PersistenceExtensionsTest { private @Mock @NonNullByDefault({}) ItemRegistry itemRegistryMock; private @Mock @NonNullByDefault({}) UnitProvider unitProviderMock; + private @Mock @NonNullByDefault({}) TimeZoneProvider timeZoneProviderMock; private @NonNullByDefault({}) GenericItem numberItem, quantityItem, switchItem; @@ -88,10 +85,16 @@ public void setUp() { TEST_QUANTITY_NUMBER); switchItem = itemFactory.createItem(CoreItemFactory.SWITCH, TEST_SWITCH); + numberItem.setState(STATE); + quantityItem.setState(new QuantityType(STATE, SIUnits.CELSIUS)); + switchItem.setState(SWITCH_STATE); + when(itemRegistryMock.get(TEST_NUMBER)).thenReturn(numberItem); when(itemRegistryMock.get(TEST_QUANTITY_NUMBER)).thenReturn(quantityItem); when(itemRegistryMock.get(TEST_SWITCH)).thenReturn(switchItem); + when(timeZoneProviderMock.getTimeZone()).thenReturn(ZoneId.systemDefault()); + new PersistenceExtensions(new PersistenceServiceRegistry() { private final PersistenceService testPersistenceService = new TestPersistenceService(itemRegistryMock); @@ -114,431 +117,1171 @@ public Set getAll() { @Override public @Nullable PersistenceService get(@Nullable String serviceId) { - return TestPersistenceService.ID.equals(serviceId) ? testPersistenceService : null; + return TestPersistenceService.SERVICE_ID.equals(serviceId) ? testPersistenceService : null; } - }); + }, timeZoneProviderMock); } @Test - public void testHistoricStateDecimalType() { - HistoricItem historicItem = PersistenceExtensions.historicState(numberItem, - ZonedDateTime.of(2012, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + public void testPersistedStateDecimalType() { + HistoricItem historicItem = PersistenceExtensions.persistedState(numberItem, + ZonedDateTime.of(HISTORIC_END, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); assertThat(historicItem.getState(), is(instanceOf(DecimalType.class))); - assertEquals("2012", historicItem.getState().toString()); + assertEquals(value(HISTORIC_END), historicItem.getState()); + + historicItem = PersistenceExtensions.persistedState(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 12, 31, 0, 0, 0, 0, ZoneId.systemDefault()), + SERVICE_ID); + assertNotNull(historicItem); + assertEquals(value(HISTORIC_INTERMEDIATE_VALUE_1), historicItem.getState()); + + historicItem = PersistenceExtensions.persistedState(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertEquals(value(HISTORIC_INTERMEDIATE_VALUE_1), historicItem.getState()); + + historicItem = PersistenceExtensions.persistedState(numberItem, ZonedDateTime.now(), SERVICE_ID); + assertNotNull(historicItem); + assertEquals(value(TestPersistenceService.HISTORIC_END), historicItem.getState()); + + historicItem = PersistenceExtensions.persistedState(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_NOVALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertEquals(value(HISTORIC_END), historicItem.getState()); - historicItem = PersistenceExtensions.historicState(numberItem, - ZonedDateTime.of(2011, 12, 31, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + historicItem = PersistenceExtensions.persistedState(numberItem, + ZonedDateTime.of(FUTURE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); - assertEquals("2011", historicItem.getState().toString()); + assertEquals(value(FUTURE_START), historicItem.getState()); - historicItem = PersistenceExtensions.historicState(numberItem, - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + historicItem = PersistenceExtensions.persistedState(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); - assertEquals("2011", historicItem.getState().toString()); + assertEquals(value(FUTURE_INTERMEDIATE_VALUE_3), historicItem.getState()); - historicItem = PersistenceExtensions.historicState(numberItem, - ZonedDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + historicItem = PersistenceExtensions.persistedState(numberItem, + ZonedDateTime.of(FUTURE_END, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); - assertEquals("2000", historicItem.getState().toString()); + assertEquals(value(FUTURE_END), historicItem.getState()); + + historicItem = PersistenceExtensions.persistedState(numberItem, + ZonedDateTime.of(AFTER_END, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertEquals(value(FUTURE_END), historicItem.getState()); // default persistence service - historicItem = PersistenceExtensions.historicState(numberItem, - ZonedDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + historicItem = PersistenceExtensions.persistedState(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); assertNull(historicItem); } @Test - public void testHistoricStateQuantityType() { - HistoricItem historicItem = PersistenceExtensions.historicState(quantityItem, - ZonedDateTime.of(2012, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + public void testPersistedStateQuantityType() { + HistoricItem historicItem = PersistenceExtensions.persistedState(quantityItem, + ZonedDateTime.of(HISTORIC_END, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); assertThat(historicItem.getState(), is(instanceOf(QuantityType.class))); - assertEquals("2012 °C", historicItem.getState().toString()); + assertEquals(new QuantityType<>(value(HISTORIC_END), SIUnits.CELSIUS), historicItem.getState()); - historicItem = PersistenceExtensions.historicState(quantityItem, - ZonedDateTime.of(2011, 12, 31, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + historicItem = PersistenceExtensions.persistedState(quantityItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 12, 31, 0, 0, 0, 0, ZoneId.systemDefault()), + SERVICE_ID); assertNotNull(historicItem); - assertEquals("2011 °C", historicItem.getState().toString()); + assertEquals(new QuantityType<>(value(HISTORIC_INTERMEDIATE_VALUE_1), SIUnits.CELSIUS), + historicItem.getState()); - historicItem = PersistenceExtensions.historicState(quantityItem, - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + historicItem = PersistenceExtensions.persistedState(quantityItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); - assertEquals("2011 °C", historicItem.getState().toString()); + assertEquals(new QuantityType<>(value(HISTORIC_INTERMEDIATE_VALUE_1), SIUnits.CELSIUS), + historicItem.getState()); - historicItem = PersistenceExtensions.historicState(quantityItem, - ZonedDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + historicItem = PersistenceExtensions.persistedState(quantityItem, ZonedDateTime.now(), SERVICE_ID); assertNotNull(historicItem); - assertEquals("2000 °C", historicItem.getState().toString()); + assertEquals(new QuantityType<>(value(HISTORIC_END), SIUnits.CELSIUS), historicItem.getState()); + + historicItem = PersistenceExtensions.persistedState(quantityItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_NOVALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertEquals(new QuantityType<>(value(HISTORIC_END), SIUnits.CELSIUS), historicItem.getState()); + + historicItem = PersistenceExtensions.persistedState(quantityItem, + ZonedDateTime.of(FUTURE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertEquals(new QuantityType<>(value(FUTURE_START), SIUnits.CELSIUS), historicItem.getState()); + + historicItem = PersistenceExtensions.persistedState(quantityItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertEquals(new QuantityType<>(value(FUTURE_INTERMEDIATE_VALUE_3), SIUnits.CELSIUS), historicItem.getState()); + + historicItem = PersistenceExtensions.persistedState(quantityItem, + ZonedDateTime.of(FUTURE_END, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertEquals(new QuantityType<>(value(FUTURE_END), SIUnits.CELSIUS), historicItem.getState()); + + historicItem = PersistenceExtensions.persistedState(quantityItem, + ZonedDateTime.of(AFTER_END, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertEquals(new QuantityType<>(value(FUTURE_END), SIUnits.CELSIUS), historicItem.getState()); // default persistence service - historicItem = PersistenceExtensions.historicState(quantityItem, - ZonedDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + historicItem = PersistenceExtensions.persistedState(quantityItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); assertNull(historicItem); } @Test - public void testHistoricSwitchState() { + public void testPersistedStateOnOffType() { ZonedDateTime now = ZonedDateTime.now().truncatedTo(ChronoUnit.HOURS).minusMinutes(1); - HistoricItem historicItem = PersistenceExtensions.historicState(switchItem, now.minusHours(15), - TestPersistenceService.ID); + HistoricItem historicItem = PersistenceExtensions.persistedState(switchItem, now.plusHours(SWITCH_START), + SERVICE_ID); assertNull(historicItem); - historicItem = PersistenceExtensions.historicState(switchItem, now.minusHours(14), TestPersistenceService.ID); + historicItem = PersistenceExtensions.persistedState(switchItem, now.plusHours(SWITCH_ON_INTERMEDIATE_1), + SERVICE_ID); + assertNotNull(historicItem); + assertEquals(switchValue(SWITCH_ON_INTERMEDIATE_1), historicItem.getState()); + + historicItem = PersistenceExtensions.persistedState(switchItem, now.plusHours(SWITCH_OFF_INTERMEDIATE_1), + SERVICE_ID); assertNotNull(historicItem); - assertEquals(OnOffType.ON, historicItem.getState()); + assertEquals(switchValue(SWITCH_OFF_INTERMEDIATE_1), historicItem.getState()); - historicItem = PersistenceExtensions.historicState(switchItem, now.minusHours(4), TestPersistenceService.ID); + historicItem = PersistenceExtensions.persistedState(switchItem, now.plusHours(SWITCH_OFF_INTERMEDIATE_2), + SERVICE_ID); assertNotNull(historicItem); - assertEquals(OnOffType.OFF, historicItem.getState()); + assertEquals(switchValue(SWITCH_OFF_INTERMEDIATE_2), historicItem.getState()); + + historicItem = PersistenceExtensions.persistedState(switchItem, now.plusHours(SWITCH_ON_INTERMEDIATE_3), + SERVICE_ID); + assertNotNull(historicItem); + assertEquals(switchValue(SWITCH_ON_INTERMEDIATE_3), historicItem.getState()); + } @Test public void testMaximumSinceDecimalType() { - numberItem.setState(new DecimalType(1)); HistoricItem historicItem = PersistenceExtensions.maximumSince(numberItem, - ZonedDateTime.of(2012, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + ZonedDateTime.of(HISTORIC_END, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); assertThat(historicItem.getState(), is(instanceOf(DecimalType.class))); - assertEquals("2012", historicItem.getState().toString()); + assertEquals(value(HISTORIC_END), historicItem.getState()); historicItem = PersistenceExtensions.maximumSince(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); - assertEquals("2012", historicItem.getState().toString()); - assertEquals(ZonedDateTime.of(2012, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), historicItem.getTimestamp()); + assertEquals(value(HISTORIC_END), historicItem.getState()); + assertEquals(ZonedDateTime.of(HISTORIC_END, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + historicItem.getTimestamp()); // default persistence service historicItem = PersistenceExtensions.maximumSince(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(historicItem); + } + + @Test + public void testMaximumTillDecimalType() { + HistoricItem historicItem = PersistenceExtensions.maximumTill(numberItem, + ZonedDateTime.of(FUTURE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); - assertEquals("1", historicItem.getState().toString()); + assertThat(historicItem.getState(), is(instanceOf(DecimalType.class))); + assertEquals(value(FUTURE_START), historicItem.getState()); + + historicItem = PersistenceExtensions.maximumTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertEquals(value(FUTURE_INTERMEDIATE_VALUE_3), historicItem.getState()); + assertEquals(ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + historicItem.getTimestamp()); + + // default persistence service + historicItem = PersistenceExtensions.maximumTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(historicItem); } @Test public void testMaximumBetweenDecimalType() { HistoricItem historicItem = PersistenceExtensions.maximumBetween(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertThat(historicItem, is(notNullValue())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(instanceOf(DecimalType.class))); + assertThat(historicItem.getState(), is(value(HISTORIC_INTERMEDIATE_VALUE_2))); + + historicItem = PersistenceExtensions.maximumBetween(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(instanceOf(DecimalType.class))); + assertThat(historicItem.getState(), is(value(FUTURE_INTERMEDIATE_VALUE_4))); + + historicItem = PersistenceExtensions.maximumBetween(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); assertThat(historicItem.getState(), is(instanceOf(DecimalType.class))); - assertThat(historicItem.getState().toString(), is("2011")); + assertThat(historicItem.getState(), is(value(FUTURE_INTERMEDIATE_VALUE_4))); + // default persistence service historicItem = PersistenceExtensions.maximumBetween(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); - assertThat(historicItem, is(nullValue())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(historicItem); } @Test public void testMaximumSinceQuantityType() { - quantityItem.setState(QuantityType.valueOf(1, SIUnits.CELSIUS)); HistoricItem historicItem = PersistenceExtensions.maximumSince(quantityItem, - ZonedDateTime.of(2012, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertThat(historicItem, is(notNullValue())); + ZonedDateTime.of(HISTORIC_END, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); assertThat(historicItem.getState(), is(instanceOf(QuantityType.class))); - assertThat(historicItem.getState().toString(), is("2012 °C")); + assertThat(historicItem.getState(), is(new QuantityType<>(value(HISTORIC_END), SIUnits.CELSIUS))); historicItem = PersistenceExtensions.maximumSince(quantityItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertThat(historicItem, is(notNullValue())); - assertThat(historicItem.getState().toString(), is("2012 °C")); - assertThat(historicItem.getTimestamp(), is(ZonedDateTime.of(2012, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()))); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(new QuantityType<>(value(HISTORIC_END), SIUnits.CELSIUS))); + assertThat(historicItem.getTimestamp(), + is(ZonedDateTime.of(HISTORIC_END, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()))); // default persistence service historicItem = PersistenceExtensions.maximumSince(quantityItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); - assertThat(historicItem, is(notNullValue())); - assertThat(historicItem.getState().toString(), is("1 °C")); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(historicItem); + + // test with alternative unit + quantityItem.setState(QuantityType.valueOf(5000, Units.KELVIN)); + historicItem = PersistenceExtensions.maximumSince(quantityItem, + ZonedDateTime.of(HISTORIC_END, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(instanceOf(QuantityType.class))); + assertThat(historicItem.getState(), is(new QuantityType<>(4726.85, SIUnits.CELSIUS))); + } + + @Test + public void testMaximumTillQuantityType() { + HistoricItem historicItem = PersistenceExtensions.maximumTill(quantityItem, + ZonedDateTime.of(FUTURE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(instanceOf(QuantityType.class))); + assertEquals(new QuantityType<>(value(FUTURE_START), SIUnits.CELSIUS), historicItem.getState()); + + historicItem = PersistenceExtensions.maximumTill(quantityItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertEquals(new QuantityType<>(value(FUTURE_INTERMEDIATE_VALUE_3), SIUnits.CELSIUS), historicItem.getState()); + assertEquals(ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + historicItem.getTimestamp()); + + // default persistence service + historicItem = PersistenceExtensions.maximumTill(quantityItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(historicItem); } @Test public void testMaximumBetweenQuantityType() { HistoricItem historicItem = PersistenceExtensions.maximumBetween(quantityItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertThat(historicItem, is(notNullValue())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(instanceOf(QuantityType.class))); + assertThat(historicItem.getState(), + is(new QuantityType<>(value(HISTORIC_INTERMEDIATE_VALUE_2), SIUnits.CELSIUS))); + + historicItem = PersistenceExtensions.maximumBetween(quantityItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(instanceOf(QuantityType.class))); + assertThat(historicItem.getState(), + is(new QuantityType<>(value(FUTURE_INTERMEDIATE_VALUE_4), SIUnits.CELSIUS))); + + historicItem = PersistenceExtensions.maximumBetween(quantityItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); assertThat(historicItem.getState(), is(instanceOf(QuantityType.class))); - assertThat(historicItem.getState().toString(), is("2011 °C")); + assertThat(historicItem.getState(), + is(new QuantityType<>(value(FUTURE_INTERMEDIATE_VALUE_4), SIUnits.CELSIUS))); + // default persistence service historicItem = PersistenceExtensions.maximumBetween(quantityItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); - assertThat(historicItem, is(nullValue())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(historicItem); } @Test - public void testMaximumSinceSwitch() { - switchItem.setState(OnOffType.OFF); - + public void testMaximumSinceOnOffType() { ZonedDateTime now = ZonedDateTime.now(); - HistoricItem historicItem = PersistenceExtensions.maximumSince(switchItem, now.minusHours(15), - TestPersistenceService.ID); + HistoricItem historicItem = PersistenceExtensions.maximumSince(switchItem, now.plusHours(SWITCH_START), + SERVICE_ID); assertNotNull(historicItem); - assertEquals(OnOffType.ON, historicItem.getState()); + assertEquals(switchValue(SWITCH_ON_1), historicItem.getState()); - historicItem = PersistenceExtensions.maximumSince(switchItem, now.minusHours(6), TestPersistenceService.ID); + historicItem = PersistenceExtensions.maximumSince(switchItem, now.plusHours(SWITCH_OFF_INTERMEDIATE_1), + SERVICE_ID); assertNotNull(historicItem); - assertEquals(OnOffType.ON, historicItem.getState()); + assertEquals(switchValue(SWITCH_ON_2), historicItem.getState()); - historicItem = PersistenceExtensions.maximumSince(switchItem, now.minusHours(1), TestPersistenceService.ID); + historicItem = PersistenceExtensions.maximumSince(switchItem, now.plusHours(SWITCH_ON_INTERMEDIATE_21), + SERVICE_ID); assertNotNull(historicItem); - assertEquals(OnOffType.ON, historicItem.getState()); + assertEquals(switchValue(SWITCH_ON_2), historicItem.getState()); - historicItem = PersistenceExtensions.maximumSince(switchItem, now, TestPersistenceService.ID); + historicItem = PersistenceExtensions.maximumSince(switchItem, now, SERVICE_ID); assertNotNull(historicItem); - assertEquals(OnOffType.ON, historicItem.getState()); + assertEquals(switchValue(SWITCH_ON_2), historicItem.getState()); + + historicItem = PersistenceExtensions.maximumSince(switchItem, now.plusHours(SWITCH_ON_INTERMEDIATE_22), + SERVICE_ID); + assertNull(historicItem); + } - historicItem = PersistenceExtensions.maximumSince(switchItem, now.plusHours(1), TestPersistenceService.ID); + @Test + public void testMaximumTillOnOffType() { + ZonedDateTime now = ZonedDateTime.now(); + HistoricItem historicItem = PersistenceExtensions.maximumTill(switchItem, + now.plusHours(SWITCH_OFF_INTERMEDIATE_2), SERVICE_ID); assertNotNull(historicItem); - assertEquals(OnOffType.OFF, historicItem.getState()); + assertEquals(switchValue(SWITCH_ON_2), historicItem.getState()); + + historicItem = PersistenceExtensions.maximumTill(switchItem, now.plusHours(SWITCH_ON_INTERMEDIATE_3), + SERVICE_ID); + assertNotNull(historicItem); + assertEquals(switchValue(SWITCH_ON_3), historicItem.getState()); + + historicItem = PersistenceExtensions.maximumTill(switchItem, now.plusHours(SWITCH_END), SERVICE_ID); + assertNotNull(historicItem); + assertEquals(switchValue(SWITCH_ON_3), historicItem.getState()); + + historicItem = PersistenceExtensions.maximumTill(switchItem, now.plusHours(SWITCH_ON_INTERMEDIATE_21), + SERVICE_ID); + assertNull(historicItem); } @Test public void testMinimumSinceDecimalType() { - numberItem.setState(new DecimalType(5000)); HistoricItem historicItem = PersistenceExtensions.minimumSince(numberItem, - ZonedDateTime.of(1940, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); assertThat(historicItem.getState(), is(instanceOf(DecimalType.class))); - assertEquals("5000", historicItem.getState().toString()); + assertEquals(value(HISTORIC_START), historicItem.getState()); historicItem = PersistenceExtensions.minimumSince(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); - assertEquals("2005", historicItem.getState().toString()); - assertEquals(ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), historicItem.getTimestamp()); + assertEquals(value(HISTORIC_INTERMEDIATE_VALUE_1), historicItem.getState()); + assertEquals(ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + historicItem.getTimestamp()); // default persistence service historicItem = PersistenceExtensions.minimumSince(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(historicItem); + } + + @Test + public void testMinimumTillDecimalType() { + HistoricItem historicItem = PersistenceExtensions.minimumTill(numberItem, + ZonedDateTime.of(FUTURE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); - assertEquals("5000", historicItem.getState().toString()); + assertThat(historicItem.getState(), is(instanceOf(DecimalType.class))); + assertEquals(value(HISTORIC_END), historicItem.getState()); + + historicItem = PersistenceExtensions.minimumTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertEquals(value(HISTORIC_END), historicItem.getState()); + + // default persistence service + historicItem = PersistenceExtensions.minimumTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(historicItem); } @Test public void testMinimumBetweenDecimalType() { HistoricItem historicItem = PersistenceExtensions.minimumBetween(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertThat(historicItem, is(notNullValue())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(instanceOf(DecimalType.class))); + assertThat(historicItem.getState(), is(value(HISTORIC_INTERMEDIATE_VALUE_1))); + + historicItem = PersistenceExtensions.minimumBetween(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); assertThat(historicItem.getState(), is(instanceOf(DecimalType.class))); - assertThat(historicItem.getState().toString(), is("2005")); + assertThat(historicItem.getState(), is(value(FUTURE_INTERMEDIATE_VALUE_3))); historicItem = PersistenceExtensions.minimumBetween(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); - assertThat(historicItem, is(nullValue())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(instanceOf(DecimalType.class))); + assertThat(historicItem.getState(), is(value(HISTORIC_INTERMEDIATE_VALUE_1))); + + // default persistence service + historicItem = PersistenceExtensions.minimumBetween(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(historicItem); } @Test public void testMinimumSinceQuantityType() { - quantityItem.setState(QuantityType.valueOf(5000, SIUnits.CELSIUS)); HistoricItem historicItem = PersistenceExtensions.minimumSince(quantityItem, - ZonedDateTime.of(1940, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); assertThat(historicItem.getState(), is(instanceOf(QuantityType.class))); - assertEquals("5000 °C", historicItem.getState().toString()); + assertEquals(new QuantityType<>(value(HISTORIC_START), SIUnits.CELSIUS), historicItem.getState()); historicItem = PersistenceExtensions.minimumSince(quantityItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); - assertEquals("2005 °C", historicItem.getState().toString()); - assertEquals(ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), historicItem.getTimestamp()); + assertEquals(new QuantityType<>(value(HISTORIC_INTERMEDIATE_VALUE_1), SIUnits.CELSIUS), + historicItem.getState()); + assertEquals(ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + historicItem.getTimestamp()); // default persistence service historicItem = PersistenceExtensions.minimumSince(quantityItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(historicItem); + + // test with alternative unit + quantityItem.setState(QuantityType.valueOf(273.15, Units.KELVIN)); + historicItem = PersistenceExtensions.minimumSince(quantityItem, + ZonedDateTime.of(HISTORIC_END, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(instanceOf(QuantityType.class))); + assertThat(historicItem.getState(), is(new QuantityType<>(0, SIUnits.CELSIUS))); + } + + @Test + public void testMinimumTillQuantityType() { + HistoricItem historicItem = PersistenceExtensions.minimumTill(quantityItem, + ZonedDateTime.of(FUTURE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(instanceOf(QuantityType.class))); + assertEquals(new QuantityType<>(value(HISTORIC_END), SIUnits.CELSIUS), historicItem.getState()); + + historicItem = PersistenceExtensions.minimumTill(quantityItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); - assertEquals("5000 °C", historicItem.getState().toString()); + assertEquals(new QuantityType<>(value(HISTORIC_END), SIUnits.CELSIUS), historicItem.getState()); + + // default persistence service + historicItem = PersistenceExtensions.minimumTill(quantityItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(historicItem); } @Test public void testMinimumBetweenQuantityType() { HistoricItem historicItem = PersistenceExtensions.minimumBetween(quantityItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertThat(historicItem, is(notNullValue())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(instanceOf(QuantityType.class))); + assertThat(historicItem.getState(), + is(new QuantityType<>(value(HISTORIC_INTERMEDIATE_VALUE_1), SIUnits.CELSIUS))); + + historicItem = PersistenceExtensions.minimumBetween(quantityItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); assertThat(historicItem.getState(), is(instanceOf(QuantityType.class))); - assertThat(historicItem.getState().toString(), is("2005 °C")); + assertThat(historicItem.getState(), + is(new QuantityType<>(value(FUTURE_INTERMEDIATE_VALUE_3), SIUnits.CELSIUS))); historicItem = PersistenceExtensions.minimumBetween(quantityItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); - assertThat(historicItem, is(nullValue())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(instanceOf(QuantityType.class))); + assertThat(historicItem.getState(), + is(new QuantityType<>(value(HISTORIC_INTERMEDIATE_VALUE_1), SIUnits.CELSIUS))); + + // default persistence service + historicItem = PersistenceExtensions.minimumBetween(quantityItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(historicItem); } @Test - public void testMinimumSinceSwitch() { - switchItem.setState(OnOffType.ON); - + public void testMinimumSinceOnOffType() { ZonedDateTime now = ZonedDateTime.now(); - HistoricItem historicItem = PersistenceExtensions.minimumSince(switchItem, now.minusHours(15), - TestPersistenceService.ID); + HistoricItem historicItem = PersistenceExtensions.minimumSince(switchItem, now.plusHours(SWITCH_START), + SERVICE_ID); assertNotNull(historicItem); - assertEquals(OnOffType.OFF, historicItem.getState()); + assertEquals(switchValue(SWITCH_OFF_1), historicItem.getState()); - historicItem = PersistenceExtensions.minimumSince(switchItem, now.minusHours(6), TestPersistenceService.ID); + historicItem = PersistenceExtensions.minimumSince(switchItem, now.plusHours(SWITCH_OFF_INTERMEDIATE_1), + SERVICE_ID); assertNotNull(historicItem); - assertEquals(OnOffType.OFF, historicItem.getState()); + assertEquals(switchValue(SWITCH_OFF_INTERMEDIATE_1), historicItem.getState()); - historicItem = PersistenceExtensions.minimumSince(switchItem, now.minusHours(1), TestPersistenceService.ID); + historicItem = PersistenceExtensions.minimumSince(switchItem, now.plusHours(SWITCH_ON_INTERMEDIATE_21), + SERVICE_ID); assertNotNull(historicItem); - assertEquals(OnOffType.ON, historicItem.getState()); + assertEquals(switchValue(SWITCH_ON_INTERMEDIATE_21), historicItem.getState()); - historicItem = PersistenceExtensions.minimumSince(switchItem, now, TestPersistenceService.ID); + historicItem = PersistenceExtensions.minimumSince(switchItem, now, SERVICE_ID); assertNotNull(historicItem); - assertEquals(OnOffType.ON, historicItem.getState()); + assertEquals(switchValue(SWITCH_ON_INTERMEDIATE_22), historicItem.getState()); - historicItem = PersistenceExtensions.minimumSince(switchItem, now.plusHours(1), TestPersistenceService.ID); - assertNotNull(historicItem); - assertEquals(OnOffType.ON, historicItem.getState()); + historicItem = PersistenceExtensions.minimumSince(switchItem, now.plusHours(SWITCH_ON_INTERMEDIATE_22), + SERVICE_ID); + assertNull(historicItem); } @Test - public void testVarianceSince() { - numberItem.setState(new DecimalType(3025)); - - ZonedDateTime startStored = ZonedDateTime.of(2003, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - ZonedDateTime endStored = ZonedDateTime.of(2012, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + public void testVarianceSinceDecimalType() { + ZonedDateTime startStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, + ZoneId.systemDefault()); + double expectedAverage = average(HISTORIC_INTERMEDIATE_VALUE_1, null); + + double expected = DoubleStream + .concat(IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_END) + .mapToDouble(i -> Double.valueOf(i)), DoubleStream.of(STATE.doubleValue())) + .map(d -> Math.pow(d - expectedAverage, 2)).sum() + / (HISTORIC_END + 1 - HISTORIC_INTERMEDIATE_VALUE_1 + 1); + State variance = PersistenceExtensions.varianceSince(numberItem, startStored, SERVICE_ID); + assertNotNull(variance); + DecimalType dt = variance.as(DecimalType.class); + assertNotNull(dt); + assertEquals(expected, dt.doubleValue(), 0.01); - long storedInterval = Duration.between(startStored, endStored).toDays(); - long recentInterval = Duration.between(endStored, ZonedDateTime.now()).toDays(); - double expectedAverage = ((2003.0 + 2011.0) / 2.0 * storedInterval + 2012.0 * recentInterval) - / (storedInterval + recentInterval); + // default persistence service + variance = PersistenceExtensions.varianceSince(numberItem, startStored); + assertNull(variance); + } - double expected = IntStream.of(2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012) - .mapToDouble(i -> Double.parseDouble(Integer.toString(i))).map(d -> Math.pow(d - expectedAverage, 2)) - .sum() / 10d; - DecimalType variance = PersistenceExtensions.varianceSince(numberItem, startStored, TestPersistenceService.ID); + @Test + public void testVarianceTillDecimalType() { + ZonedDateTime endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, + ZoneId.systemDefault()); + double expectedAverage = average(null, FUTURE_INTERMEDIATE_VALUE_3); + + double expected = DoubleStream + .concat(DoubleStream.of(STATE.doubleValue()), + IntStream.rangeClosed(FUTURE_START, FUTURE_INTERMEDIATE_VALUE_3) + .mapToDouble(i -> Double.valueOf(i))) + .map(d -> Math.pow(d - expectedAverage, 2)).sum() + / (1 + FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START + 1); + State variance = PersistenceExtensions.varianceTill(numberItem, endStored, SERVICE_ID); assertNotNull(variance); - assertEquals(expected, variance.doubleValue(), 0.01); + DecimalType dt = variance.as(DecimalType.class); + assertNotNull(dt); + assertEquals(expected, dt.doubleValue(), 0.01); // default persistence service - variance = PersistenceExtensions.varianceSince(numberItem, startStored); + variance = PersistenceExtensions.varianceTill(numberItem, endStored); assertNull(variance); } @Test - public void testVarianceBetween() { - ZonedDateTime startStored = ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - ZonedDateTime endStored = ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + public void testVarianceBetweenDecimalType() { + ZonedDateTime startStored = 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 expectedAverage1 = average(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2); + + double expected = IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2) + .mapToDouble(i -> Double.valueOf(i)).map(d -> Math.pow(d - expectedAverage1, 2)).sum() + / (HISTORIC_INTERMEDIATE_VALUE_2 - HISTORIC_INTERMEDIATE_VALUE_1 + 1); + + State variance = PersistenceExtensions.varianceBetween(numberItem, startStored, endStored, SERVICE_ID); + assertNotNull(variance); + DecimalType dt = variance.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + + startStored = 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()); + double expectedAverage2 = average(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4); + + expected = IntStream.rangeClosed(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4) + .mapToDouble(i -> Double.valueOf(i)).map(d -> Math.pow(d - expectedAverage2, 2)).sum() + / (FUTURE_INTERMEDIATE_VALUE_4 - FUTURE_INTERMEDIATE_VALUE_3 + 1); + + variance = PersistenceExtensions.varianceBetween(numberItem, startStored, endStored, SERVICE_ID); + assertNotNull(variance); + dt = variance.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + + startStored = 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()); + double expectedAverage3 = average(HISTORIC_INTERMEDIATE_VALUE_1, FUTURE_INTERMEDIATE_VALUE_3); - double expected = DoubleStream.of(2005, 2006, 2007, 2008, 2009, 2010, 2011) - .map(d -> Math.pow(d - (2005.0 + 2010.0) / 2.0, 2)).sum() / 7d; + expected = IntStream + .concat(IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_END), + IntStream.rangeClosed(FUTURE_START, FUTURE_INTERMEDIATE_VALUE_3)) + .mapToDouble(i -> Double.valueOf(i)).map(d -> Math.pow(d - expectedAverage3, 2)).sum() + / (FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START + 1 + HISTORIC_END - HISTORIC_INTERMEDIATE_VALUE_1 + 1); - DecimalType variance = PersistenceExtensions.varianceBetween(numberItem, startStored, endStored, - TestPersistenceService.ID); - assertThat(variance, is(notNullValue())); - assertThat(variance.doubleValue(), is(closeTo(expected, 0.01))); + variance = PersistenceExtensions.varianceBetween(numberItem, startStored, endStored, SERVICE_ID); + assertNotNull(variance); + dt = variance.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); // default persistence service variance = PersistenceExtensions.varianceBetween(numberItem, startStored, endStored); - assertThat(variance, is(nullValue())); + assertNull(variance); + } + + @Test + public void testVarianceSinceQuantityType() { + ZonedDateTime startStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, + ZoneId.systemDefault()); + double expectedAverage = average(HISTORIC_INTERMEDIATE_VALUE_1, null); + + double expected = DoubleStream + .concat(IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_END) + .mapToDouble(i -> Double.valueOf(i)), DoubleStream.of(STATE.doubleValue())) + .map(d -> Math.pow(d - expectedAverage, 2)).sum() + / (HISTORIC_END + 1 - HISTORIC_INTERMEDIATE_VALUE_1 + 1); + State variance = PersistenceExtensions.varianceSince(quantityItem, startStored, SERVICE_ID); + assertNotNull(variance); + QuantityType qt = variance.as(QuantityType.class); + assertNotNull(qt); + assertEquals(expected, qt.doubleValue(), 0.01); + assertEquals(SIUnits.CELSIUS.multiply(SIUnits.CELSIUS), qt.getUnit()); + + // default persistence service + variance = PersistenceExtensions.varianceSince(quantityItem, startStored); + assertNull(variance); + } + + @Test + public void testVarianceTillQuantityType() { + ZonedDateTime endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, + ZoneId.systemDefault()); + double expectedAverage = average(null, FUTURE_INTERMEDIATE_VALUE_3); + + double expected = DoubleStream + .concat(DoubleStream.of(STATE.doubleValue()), + IntStream.rangeClosed(FUTURE_START, FUTURE_INTERMEDIATE_VALUE_3) + .mapToDouble(i -> Double.valueOf(i))) + .map(d -> Math.pow(d - expectedAverage, 2)).sum() + / (1 + FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START + 1); + State variance = PersistenceExtensions.varianceTill(quantityItem, endStored, SERVICE_ID); + assertNotNull(variance); + QuantityType qt = variance.as(QuantityType.class); + assertNotNull(qt); + assertEquals(expected, qt.doubleValue(), 0.01); + assertEquals(SIUnits.CELSIUS.multiply(SIUnits.CELSIUS), qt.getUnit()); + + // default persistence service + variance = PersistenceExtensions.varianceTill(quantityItem, endStored); + assertNull(variance); + } + + @Test + public void testVarianceBetweenQuantityType() { + ZonedDateTime startStored = 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 expectedAverage1 = average(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2); + + double expected = IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2) + .mapToDouble(i -> Double.valueOf(i)).map(d -> Math.pow(d - expectedAverage1, 2)).sum() + / (HISTORIC_INTERMEDIATE_VALUE_2 - HISTORIC_INTERMEDIATE_VALUE_1 + 1); + + State variance = PersistenceExtensions.varianceBetween(quantityItem, startStored, endStored, SERVICE_ID); + assertNotNull(variance); + QuantityType qt = variance.as(QuantityType.class); + assertNotNull(qt); + assertThat(qt.doubleValue(), is(closeTo(expected, 0.01))); + assertEquals(SIUnits.CELSIUS.multiply(SIUnits.CELSIUS), qt.getUnit()); + + startStored = 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()); + double expectedAverage2 = average(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4); + + expected = IntStream.rangeClosed(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4) + .mapToDouble(i -> Double.valueOf(i)).map(d -> Math.pow(d - expectedAverage2, 2)).sum() + / (FUTURE_INTERMEDIATE_VALUE_4 - FUTURE_INTERMEDIATE_VALUE_3 + 1); + + variance = PersistenceExtensions.varianceBetween(quantityItem, startStored, endStored, SERVICE_ID); + assertNotNull(variance); + qt = variance.as(QuantityType.class); + assertNotNull(qt); + assertThat(qt.doubleValue(), is(closeTo(expected, 0.01))); + assertEquals(SIUnits.CELSIUS.multiply(SIUnits.CELSIUS), qt.getUnit()); + + startStored = 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()); + double expectedAverage3 = average(HISTORIC_INTERMEDIATE_VALUE_1, FUTURE_INTERMEDIATE_VALUE_3); + + expected = IntStream + .concat(IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_END), + IntStream.rangeClosed(FUTURE_START, FUTURE_INTERMEDIATE_VALUE_3)) + .mapToDouble(i -> Double.valueOf(i)).map(d -> Math.pow(d - expectedAverage3, 2)).sum() + / (FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START + 1 + HISTORIC_END - HISTORIC_INTERMEDIATE_VALUE_1 + 1); + + variance = PersistenceExtensions.varianceBetween(quantityItem, startStored, endStored, SERVICE_ID); + assertNotNull(variance); + qt = variance.as(QuantityType.class); + assertNotNull(qt); + assertThat(qt.doubleValue(), is(closeTo(expected, 0.01))); + assertEquals(SIUnits.CELSIUS.multiply(SIUnits.CELSIUS), qt.getUnit()); + + // default persistence service + variance = PersistenceExtensions.varianceBetween(quantityItem, startStored, endStored); + assertNull(variance); } @Test public void testDeviationSinceDecimalType() { - ZonedDateTime startStored = ZonedDateTime.of(2003, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - ZonedDateTime endStored = ZonedDateTime.of(2012, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - - long storedInterval = Duration.between(startStored, endStored).toDays(); - long recentInterval = Duration.between(endStored, ZonedDateTime.now()).toDays(); - double expectedAverage = ((2003.0 + 2011.0) / 2.0 * storedInterval + 2012.0 * recentInterval) - / (storedInterval + recentInterval); - - double expected = Math.sqrt(DoubleStream.of(2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012) - .map(d -> Math.pow(d - expectedAverage, 2)).sum() / 10d); - DecimalType deviation = PersistenceExtensions.deviationSince(numberItem, startStored, - TestPersistenceService.ID); + ZonedDateTime startStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, + ZoneId.systemDefault()); + double expectedAverage = average(HISTORIC_INTERMEDIATE_VALUE_1, null); + + double expected = Math.sqrt(DoubleStream + .concat(IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_END) + .mapToDouble(i -> Double.valueOf(i)), DoubleStream.of(STATE.doubleValue())) + .map(d -> Math.pow(d - expectedAverage, 2)).sum() + / (HISTORIC_END + 1 - HISTORIC_INTERMEDIATE_VALUE_1 + 1)); + State deviation = PersistenceExtensions.deviationSince(numberItem, startStored, SERVICE_ID); assertNotNull(deviation); - assertEquals(expected, deviation.doubleValue(), 0.01); + DecimalType dt = deviation.as(DecimalType.class); + assertNotNull(dt); + assertEquals(expected, dt.doubleValue(), 0.01); // default persistence service deviation = PersistenceExtensions.deviationSince(numberItem, startStored); assertNull(deviation); } + @Test + public void testDeviationTillDecimalType() { + ZonedDateTime endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, + ZoneId.systemDefault()); + double expectedAverage = average(null, FUTURE_INTERMEDIATE_VALUE_3); + + double expected = Math.sqrt(DoubleStream + .concat(DoubleStream.of(STATE.doubleValue()), + IntStream.rangeClosed(FUTURE_START, FUTURE_INTERMEDIATE_VALUE_3) + .mapToDouble(i -> Double.valueOf(i))) + .map(d -> Math.pow(d - expectedAverage, 2)).sum() + / (1 + FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START + 1)); + State deviation = PersistenceExtensions.deviationTill(numberItem, endStored, SERVICE_ID); + assertNotNull(deviation); + DecimalType dt = deviation.as(DecimalType.class); + assertNotNull(dt); + assertEquals(expected, dt.doubleValue(), 0.01); + + // default persistence service + deviation = PersistenceExtensions.deviationTill(numberItem, endStored); + assertNull(deviation); + } + @Test public void testDeviationBetweenDecimalType() { - ZonedDateTime startStored = ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - ZonedDateTime endStored = ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + ZonedDateTime startStored = 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 expectedAverage = average(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2); + + double expected = Math.sqrt(IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2) + .mapToDouble(i -> Double.parseDouble(Integer.toString(i))).map(d -> Math.pow(d - expectedAverage, 2)) + .sum() / (HISTORIC_INTERMEDIATE_VALUE_2 - HISTORIC_INTERMEDIATE_VALUE_1 + 1)); + State deviation = PersistenceExtensions.deviationBetween(numberItem, startStored, endStored, SERVICE_ID); + assertNotNull(deviation); + DecimalType dt = deviation.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + + startStored = 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()); + double expectedAverage2 = average(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4); + + expected = Math.sqrt(IntStream.rangeClosed(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4) + .mapToDouble(i -> Double.valueOf(i)).map(d -> Math.pow(d - expectedAverage2, 2)).sum() + / (FUTURE_INTERMEDIATE_VALUE_4 - FUTURE_INTERMEDIATE_VALUE_3 + 1)); + + deviation = PersistenceExtensions.deviationBetween(numberItem, startStored, endStored, SERVICE_ID); + assertNotNull(deviation); + dt = deviation.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + + startStored = 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()); + double expectedAverage3 = average(HISTORIC_INTERMEDIATE_VALUE_1, FUTURE_INTERMEDIATE_VALUE_3); + + expected = Math.sqrt(IntStream + .concat(IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_END), + IntStream.rangeClosed(FUTURE_START, FUTURE_INTERMEDIATE_VALUE_3)) + .mapToDouble(i -> Double.valueOf(i)).map(d -> Math.pow(d - expectedAverage3, 2)).sum() + / (FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START + 1 + HISTORIC_END - HISTORIC_INTERMEDIATE_VALUE_1 + 1)); + + deviation = PersistenceExtensions.deviationBetween(numberItem, startStored, endStored, SERVICE_ID); + assertNotNull(deviation); + dt = deviation.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + + // default persistence service + deviation = PersistenceExtensions.deviationBetween(numberItem, startStored, endStored); + assertNull(deviation); + } + + @Test + public void testDeviationSinceQuantityType() { + ZonedDateTime startStored = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, + ZoneId.systemDefault()); + double expectedAverage = average(HISTORIC_INTERMEDIATE_VALUE_1, null); + + double expected = Math.sqrt(DoubleStream + .concat(IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_END) + .mapToDouble(i -> Double.valueOf(i)), DoubleStream.of(STATE.doubleValue())) + .map(d -> Math.pow(d - expectedAverage, 2)).sum() + / (HISTORIC_END + 1 - HISTORIC_INTERMEDIATE_VALUE_1 + 1)); + State deviation = PersistenceExtensions.deviationSince(quantityItem, startStored, SERVICE_ID); + assertNotNull(deviation); + QuantityType qt = deviation.as(QuantityType.class); + assertNotNull(qt); + assertEquals(expected, qt.doubleValue(), 0.01); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); + + // default persistence service + deviation = PersistenceExtensions.deviationSince(quantityItem, startStored); + assertNull(deviation); + } + + @Test + public void testDeviationTillQuantityType() { + ZonedDateTime endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, + ZoneId.systemDefault()); + double expectedAverage = average(null, FUTURE_INTERMEDIATE_VALUE_3); + + double expected = Math.sqrt(DoubleStream + .concat(DoubleStream.of(STATE.doubleValue()), + IntStream.rangeClosed(FUTURE_START, FUTURE_INTERMEDIATE_VALUE_3) + .mapToDouble(i -> Double.valueOf(i))) + .map(d -> Math.pow(d - expectedAverage, 2)).sum() + / (1 + FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START + 1)); + State deviation = PersistenceExtensions.deviationTill(quantityItem, endStored, SERVICE_ID); + assertNotNull(deviation); + QuantityType qt = deviation.as(QuantityType.class); + assertNotNull(qt); + assertEquals(expected, qt.doubleValue(), 0.01); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); + + // default persistence service + deviation = PersistenceExtensions.deviationTill(quantityItem, endStored); + assertNull(deviation); + } + + @Test + public void testDeviationBetweenQuantityType() { + ZonedDateTime startStored = 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 expectedAverage = average(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2); + + double expected = Math.sqrt(IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2) + .mapToDouble(i -> Double.parseDouble(Integer.toString(i))).map(d -> Math.pow(d - expectedAverage, 2)) + .sum() / (HISTORIC_INTERMEDIATE_VALUE_2 - HISTORIC_INTERMEDIATE_VALUE_1 + 1)); + State deviation = PersistenceExtensions.deviationBetween(quantityItem, startStored, endStored, SERVICE_ID); + assertNotNull(deviation); + QuantityType qt = deviation.as(QuantityType.class); + assertNotNull(qt); + assertEquals(expected, qt.doubleValue(), 0.01); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); + + startStored = 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()); + double expectedAverage2 = average(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4); + + expected = Math.sqrt(IntStream.rangeClosed(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4) + .mapToDouble(i -> Double.valueOf(i)).map(d -> Math.pow(d - expectedAverage2, 2)).sum() + / (FUTURE_INTERMEDIATE_VALUE_4 - FUTURE_INTERMEDIATE_VALUE_3 + 1)); + + deviation = PersistenceExtensions.deviationBetween(quantityItem, startStored, endStored, SERVICE_ID); + assertNotNull(deviation); + qt = deviation.as(QuantityType.class); + assertNotNull(qt); + assertEquals(expected, qt.doubleValue(), 0.01); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); + + startStored = 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()); + double expectedAverage3 = average(HISTORIC_INTERMEDIATE_VALUE_1, FUTURE_INTERMEDIATE_VALUE_3); + + expected = Math.sqrt(IntStream + .concat(IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_END), + IntStream.rangeClosed(FUTURE_START, FUTURE_INTERMEDIATE_VALUE_3)) + .mapToDouble(i -> Double.valueOf(i)).map(d -> Math.pow(d - expectedAverage3, 2)).sum() + / (FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START + 1 + HISTORIC_END - HISTORIC_INTERMEDIATE_VALUE_1 + 1)); + + deviation = PersistenceExtensions.deviationBetween(quantityItem, startStored, endStored, SERVICE_ID); + assertNotNull(deviation); + qt = deviation.as(QuantityType.class); + assertNotNull(qt); + assertEquals(expected, qt.doubleValue(), 0.01); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); + + // default persistence service + deviation = PersistenceExtensions.deviationBetween(quantityItem, startStored, endStored); + assertNull(deviation); + } + + @Test + public void testAverageSinceDecimalType() { + ZonedDateTime start = ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + double expected = average(BEFORE_START, null); + State average = PersistenceExtensions.averageSince(numberItem, start, SERVICE_ID); + assertNotNull(average); + DecimalType dt = average.as(DecimalType.class); + assertNotNull(dt); + assertEquals(expected, dt.doubleValue(), 0.01); + + start = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = average(HISTORIC_INTERMEDIATE_VALUE_1, null); + average = PersistenceExtensions.averageSince(numberItem, start, SERVICE_ID); + assertNotNull(average); + dt = average.as(DecimalType.class); + assertNotNull(dt); + assertEquals(expected, dt.doubleValue(), 0.01); + + // default persistence service + average = PersistenceExtensions.averageSince(numberItem, start); + assertNull(average); + } + + @Test + public void testAverageTillDecimalType() { + ZonedDateTime end = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + double expected = average(null, FUTURE_INTERMEDIATE_VALUE_3); + State average = PersistenceExtensions.averageTill(numberItem, end, SERVICE_ID); + assertNotNull(average); + DecimalType dt = average.as(DecimalType.class); + assertNotNull(dt); + assertEquals(expected, dt.doubleValue(), 0.01); + + // default persistence service + average = PersistenceExtensions.averageTill(numberItem, end); + assertNull(average); + } + + @Test + public void testAverageBetweenDecimalType() { + 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 = average(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2); + State average = PersistenceExtensions.averageBetween(numberItem, beginStored, endStored, SERVICE_ID); + assertNotNull(average); + DecimalType dt = average.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 = average(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4); + + average = PersistenceExtensions.averageBetween(numberItem, beginStored, endStored, SERVICE_ID); + assertNotNull(average); + dt = average.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 = average(HISTORIC_INTERMEDIATE_VALUE_1, FUTURE_INTERMEDIATE_VALUE_3); + + average = PersistenceExtensions.averageBetween(numberItem, beginStored, endStored, SERVICE_ID); + assertNotNull(average); + dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(expected, 0.01))); + + // default persistence service + average = PersistenceExtensions.averageBetween(quantityItem, beginStored, endStored); + assertNull(average); + } + + @Test + public void testAverageSinceQuantityType() { + ZonedDateTime start = ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + double expected = average(BEFORE_START, null); + State average = PersistenceExtensions.averageSince(quantityItem, start, SERVICE_ID); + assertNotNull(average); + QuantityType qt = average.as(QuantityType.class); + assertNotNull(qt); + assertEquals(expected, qt.doubleValue(), 0.01); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); + + start = ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + expected = average(HISTORIC_INTERMEDIATE_VALUE_1, null); + average = PersistenceExtensions.averageSince(quantityItem, start, SERVICE_ID); + assertNotNull(average); + qt = average.as(QuantityType.class); + assertNotNull(qt); + assertEquals(expected, qt.doubleValue(), 0.01); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); + + // default persistence service + average = PersistenceExtensions.averageSince(quantityItem, start); + assertNull(average); + } + + @Test + public void testAverageTillQuantityType() { + ZonedDateTime end = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + double expected = average(null, FUTURE_INTERMEDIATE_VALUE_3); + State average = PersistenceExtensions.averageTill(quantityItem, end, SERVICE_ID); + assertNotNull(average); + QuantityType qt = average.as(QuantityType.class); + assertNotNull(qt); + assertEquals(expected, qt.doubleValue(), 0.01); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); + + // default persistence service + average = PersistenceExtensions.averageTill(quantityItem, end); + assertNull(average); + } + + @Test + public void testAverageBetweenQuantityType() { + 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 = average(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2); + State average = PersistenceExtensions.averageBetween(quantityItem, beginStored, endStored, SERVICE_ID); + + assertNotNull(average); + QuantityType qt = average.as(QuantityType.class); + assertNotNull(qt); + assertThat(qt.doubleValue(), is(closeTo(expected, 0.01))); + assertEquals(SIUnits.CELSIUS, 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 = average(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4); - double expected = Math.sqrt(DoubleStream.of(2005, 2006, 2007, 2008, 2009, 2010, 2011) - .map(d -> Math.pow(d - (2005.0 + 2010.0) / 2.0, 2)).sum() / 7d); + average = PersistenceExtensions.averageBetween(quantityItem, beginStored, endStored, SERVICE_ID); + assertNotNull(average); + qt = average.as(QuantityType.class); + assertNotNull(qt); + assertThat(qt.doubleValue(), is(closeTo(expected, 0.01))); + assertEquals(SIUnits.CELSIUS, 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 = average(HISTORIC_INTERMEDIATE_VALUE_1, FUTURE_INTERMEDIATE_VALUE_3); - DecimalType deviation = PersistenceExtensions.deviationBetween(numberItem, startStored, endStored, - TestPersistenceService.ID); - assertThat(deviation, is(notNullValue())); - assertThat(deviation.doubleValue(), is(closeTo(expected, 0.01))); + average = PersistenceExtensions.averageBetween(quantityItem, beginStored, endStored, SERVICE_ID); + assertNotNull(average); + qt = average.as(QuantityType.class); + assertNotNull(qt); + assertThat(qt.doubleValue(), is(closeTo(expected, 0.01))); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); // default persistence service - deviation = PersistenceExtensions.deviationBetween(numberItem, startStored, endStored); - assertThat(deviation, is(nullValue())); + average = PersistenceExtensions.averageBetween(quantityItem, beginStored, endStored); + assertNull(average); } @Test - public void testDeviationSinceQuantityType() { - quantityItem.setState(QuantityType.valueOf(3025, SIUnits.CELSIUS)); + public void testAverageSinceOnOffType() { + // switch is 5h ON, 5h OFF, and 5h ON (until now) - ZonedDateTime startStored = ZonedDateTime.of(2003, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - ZonedDateTime endStored = ZonedDateTime.of(2012, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); + ZonedDateTime now = ZonedDateTime.now().truncatedTo(ChronoUnit.MINUTES); + State average = PersistenceExtensions.averageSince(switchItem, now.plusHours(SWITCH_START), SERVICE_ID); + assertNotNull(average); + DecimalType dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), + is(closeTo((SWITCH_OFF_1 - SWITCH_ON_1 - SWITCH_ON_2) / (-1.0 * SWITCH_START), 0.01))); - long storedInterval = Duration.between(startStored, endStored).toDays(); - long recentInterval = Duration.between(endStored, ZonedDateTime.now()).toDays(); - double expectedAverage = ((2003.0 + 2011.0) / 2.0 * storedInterval + 2012.0 * recentInterval) - / (storedInterval + recentInterval); + average = PersistenceExtensions.averageSince(switchItem, now.plusHours(SWITCH_OFF_INTERMEDIATE_1), SERVICE_ID); + assertNotNull(average); + dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(-SWITCH_ON_2 / (-1.0 * SWITCH_OFF_INTERMEDIATE_1), 0.01))); - double expected = Math.sqrt(DoubleStream.of(2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012) - .map(d -> Math.pow(d - expectedAverage, 2)).sum() / 10d); + average = PersistenceExtensions.averageSince(switchItem, now.plusHours(SWITCH_ON_2), SERVICE_ID); + assertNotNull(average); + dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(-SWITCH_ON_2 / (-1.0 * SWITCH_ON_2), 0.01))); - DecimalType deviation = PersistenceExtensions.deviationSince(quantityItem, startStored, - TestPersistenceService.ID); - assertNotNull(deviation); - assertEquals(expected, deviation.doubleValue(), 0.01); + average = PersistenceExtensions.averageSince(switchItem, now.plusHours(SWITCH_ON_INTERMEDIATE_21), SERVICE_ID); + assertNotNull(average); + dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), + is(closeTo(-SWITCH_ON_INTERMEDIATE_21 / (-1.0 * SWITCH_ON_INTERMEDIATE_21), 0.01))); - // default persistence service - deviation = PersistenceExtensions.deviationSince(quantityItem, startStored); - assertNull(deviation); + average = PersistenceExtensions.averageSince(switchItem, now, SERVICE_ID); + assertNotNull(average); + dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(1d, 0.01))); + + average = PersistenceExtensions.averageSince(switchItem, now.plusHours(1), SERVICE_ID); + assertNull(average); } @Test - public void testDeviationBetweenQuantityType() { - ZonedDateTime startStored = ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - ZonedDateTime endStored = ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - - double expected = Math.sqrt(DoubleStream.of(2005, 2006, 2007, 2008, 2009, 2010, 2011) - .map(d -> Math.pow(d - (2005.0 + 2010.0) / 2.0, 2)).sum() / 7d); + public void testAverageTillOnOffType() { + // switch is 5h ON, 5h OFF, and 5h ON (from now) - DecimalType deviation = PersistenceExtensions.deviationBetween(quantityItem, startStored, endStored, - TestPersistenceService.ID); - assertThat(deviation, is(notNullValue())); - assertThat(deviation.doubleValue(), is(closeTo(expected, 0.01))); + ZonedDateTime now = ZonedDateTime.now().truncatedTo(ChronoUnit.MINUTES); + State average = PersistenceExtensions.averageTill(switchItem, now.plusHours(SWITCH_END), SERVICE_ID); + assertNotNull(average); + DecimalType dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), + is(closeTo((SWITCH_OFF_3 - SWITCH_ON_3 + SWITCH_OFF_2) / (1.0 * SWITCH_END), 0.01))); - // default persistence service - deviation = PersistenceExtensions.deviationBetween(quantityItem, startStored, endStored); - assertThat(deviation, is(nullValue())); - } + average = PersistenceExtensions.averageTill(switchItem, now.plusHours(SWITCH_OFF_INTERMEDIATE_2), SERVICE_ID); + assertNotNull(average); + dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(SWITCH_OFF_2 / (1.0 * SWITCH_OFF_INTERMEDIATE_2), 0.01))); - @Test - public void testAverageSinceDecimalType() { - ZonedDateTime startStored = ZonedDateTime.of(1940, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - DecimalType average = PersistenceExtensions.averageSince(numberItem, startStored, TestPersistenceService.ID); - assertNull(average); + average = PersistenceExtensions.averageTill(switchItem, now.plusHours(SWITCH_ON_3), SERVICE_ID); + assertNotNull(average); + dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(SWITCH_OFF_2 / (1.0 * SWITCH_ON_3), 0.01))); - startStored = ZonedDateTime.of(2003, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - ZonedDateTime endStored = ZonedDateTime.of(2012, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - long storedInterval = Duration.between(startStored, endStored).toDays(); - long recentInterval = Duration.between(endStored, ZonedDateTime.now()).toDays(); - double expected = ((2003.0 + 2011.0) / 2.0 * storedInterval + 2012.0 * recentInterval) - / (storedInterval + recentInterval); + average = PersistenceExtensions.averageTill(switchItem, now.plusHours(SWITCH_ON_INTERMEDIATE_22), SERVICE_ID); + assertNotNull(average); + dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(SWITCH_ON_INTERMEDIATE_22 / (1.0 * SWITCH_ON_INTERMEDIATE_22), 0.01))); - average = PersistenceExtensions.averageSince(numberItem, startStored, TestPersistenceService.ID); + average = PersistenceExtensions.averageTill(switchItem, now.plusMinutes(1), SERVICE_ID); assertNotNull(average); - assertEquals(expected, average.doubleValue(), 0.01); + dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(1d, 0.01))); - // default persistence service - average = PersistenceExtensions.averageSince(numberItem, startStored); + average = PersistenceExtensions.averageTill(switchItem, now.minusHours(1), SERVICE_ID); assertNull(average); } @@ -568,7 +1311,7 @@ public Set getAll() { public @Nullable PersistenceService get(@Nullable String serviceId) { return TestCachedValuesPersistenceService.ID.equals(serviceId) ? persistenceService : null; } - }); + }, timeZoneProviderMock); ZonedDateTime now = ZonedDateTime.now(); ZonedDateTime beginStored = now.minusHours(27); @@ -578,294 +1321,532 @@ public Set getAll() { persistenceService.addHistoricItem(beginStored.plusHours(2), new DecimalType(0), TEST_NUMBER); persistenceService.addHistoricItem(beginStored.plusHours(25), new DecimalType(50), TEST_NUMBER); persistenceService.addHistoricItem(beginStored.plusHours(26), new DecimalType(0), TEST_NUMBER); + numberItem.setState(new DecimalType(0)); - DecimalType average = PersistenceExtensions.averageSince(numberItem, beginStored, + State average = PersistenceExtensions.averageSince(numberItem, beginStored, TestCachedValuesPersistenceService.ID); - assertThat(average.doubleValue(), is(closeTo((100.0 + 50.0) / 27.0, 0.01))); + assertNotNull(average); + DecimalType dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo((100.0 + 50.0) / 27.0, 0.01))); average = PersistenceExtensions.averageSince(numberItem, beginStored.plusHours(3), TestCachedValuesPersistenceService.ID); - assertThat(average.doubleValue(), is(closeTo(50.0 / 24.0, 0.01))); + assertNotNull(average); + dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(50.0 / 24.0, 0.01))); average = PersistenceExtensions.averageSince(numberItem, now.minusMinutes(30), TestCachedValuesPersistenceService.ID); - assertThat(average.doubleValue(), is(closeTo(0, 0.01))); - } - - @Test - public void testAverageBetweenDecimalType() { - ZonedDateTime beginStored = ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - ZonedDateTime endStored = ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - DecimalType average = PersistenceExtensions.averageBetween(numberItem, beginStored, endStored, - TestPersistenceService.ID); - - assertThat(average, is(notNullValue())); - assertThat(average.doubleValue(), is(closeTo((2005.0 + 2010.0) / 2.0, 0.01))); - - // default persistence service - average = PersistenceExtensions.averageBetween(quantityItem, beginStored, endStored); - assertThat(average, is(nullValue())); - } - - @Test - public void testAverageSinceQuantityType() { - quantityItem.setState(QuantityType.valueOf(3025, SIUnits.CELSIUS)); - - ZonedDateTime startStored = ZonedDateTime.of(1940, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - DecimalType average = PersistenceExtensions.averageSince(quantityItem, startStored, TestPersistenceService.ID); - assertNull(average); - - startStored = ZonedDateTime.of(2003, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - ZonedDateTime endStored = ZonedDateTime.of(2012, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - long storedInterval = Duration.between(startStored, endStored).toDays(); - long recentInterval = Duration.between(endStored, ZonedDateTime.now()).toDays(); - double expected = ((2003.0 + 2011.0) / 2.0 * storedInterval + 2012.0 * recentInterval) - / (storedInterval + recentInterval); - - average = PersistenceExtensions.averageSince(quantityItem, startStored, TestPersistenceService.ID); assertNotNull(average); - assertEquals(expected, average.doubleValue(), 0.01); - - // default persistence service - average = PersistenceExtensions.averageSince(quantityItem, startStored); - assertNull(average); + dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(0, 0.01))); } @Test - public void testAverageBetweenQuantityType() { - ZonedDateTime beginStored = ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - ZonedDateTime endStored = ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); - DecimalType average = PersistenceExtensions.averageBetween(quantityItem, beginStored, endStored, - TestPersistenceService.ID); - - assertThat(average, is(notNullValue())); - assertThat(average.doubleValue(), is(closeTo((2005.0 + 2010.0) / 2, 0.01))); + public void testAverageTillDecimalTypeIrregularTimespans() { + TestCachedValuesPersistenceService persistenceService = new TestCachedValuesPersistenceService(); + new PersistenceExtensions(new PersistenceServiceRegistry() { - // default persistence service - average = PersistenceExtensions.averageBetween(quantityItem, beginStored, endStored); - assertThat(average, is(nullValue())); - } + @Override + public @Nullable String getDefaultId() { + // not available + return null; + } - @Test - public void testAverageSinceSwitch() { - // switch is 5h ON, 6h OFF, and 4h ON (until now) + @Override + public @Nullable PersistenceService getDefault() { + // not available + return null; + } - ZonedDateTime now = ZonedDateTime.now().truncatedTo(ChronoUnit.MINUTES); - DecimalType average = PersistenceExtensions.averageSince(switchItem, now.minusHours(15), - TestPersistenceService.ID); - assertThat(average, is(notNullValue())); - assertThat(average.doubleValue(), is(closeTo(9.0 / 15.0, 0.01))); + @Override + public Set getAll() { + return Set.of(persistenceService); + } - average = PersistenceExtensions.averageSince(switchItem, now.minusHours(7), TestPersistenceService.ID); - assertThat(average, is(notNullValue())); - assertThat(average.doubleValue(), is(closeTo(4.0 / 7.0, 0.01))); + @Override + public @Nullable PersistenceService get(@Nullable String serviceId) { + return TestCachedValuesPersistenceService.ID.equals(serviceId) ? persistenceService : null; + } + }, timeZoneProviderMock); - average = PersistenceExtensions.averageSince(switchItem, now.minusHours(6), TestPersistenceService.ID); - assertThat(average, is(notNullValue())); - assertThat(average.doubleValue(), is(closeTo(0.833, 0.2))); + ZonedDateTime now = ZonedDateTime.now(); + ZonedDateTime beginStored = now.plusHours(1); - average = PersistenceExtensions.averageSince(switchItem, now.minusHours(5), TestPersistenceService.ID); - assertThat(average, is(notNullValue())); - assertThat(average.doubleValue(), is(closeTo(1d, 0.2))); + persistenceService.addHistoricItem(beginStored, new DecimalType(0), TEST_NUMBER); + persistenceService.addHistoricItem(beginStored.plusHours(1), new DecimalType(0), TEST_NUMBER); + persistenceService.addHistoricItem(beginStored.plusHours(2), new DecimalType(50), TEST_NUMBER); + persistenceService.addHistoricItem(beginStored.plusHours(3), new DecimalType(0), TEST_NUMBER); + persistenceService.addHistoricItem(beginStored.plusHours(25), new DecimalType(100), TEST_NUMBER); + numberItem.setState(new DecimalType(0)); - average = PersistenceExtensions.averageSince(switchItem, now.minusHours(1), TestPersistenceService.ID); - assertThat(average, is(notNullValue())); - assertThat(average.doubleValue(), is(closeTo(1d, 0.001))); + State average = PersistenceExtensions.averageTill(numberItem, beginStored.plusHours(26), + TestCachedValuesPersistenceService.ID); + assertNotNull(average); + DecimalType dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo((100.0 + 50.0) / 27.0, 0.01))); - average = PersistenceExtensions.averageSince(switchItem, now, TestPersistenceService.ID); - assertThat(average, is(notNullValue())); - assertThat(average.doubleValue(), is(closeTo(1d, 0.001))); + average = PersistenceExtensions.averageTill(numberItem, beginStored.plusHours(24), + TestCachedValuesPersistenceService.ID); + assertNotNull(average); + dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(50.0 / 25.0, 0.01))); - average = PersistenceExtensions.averageSince(switchItem, now.plusHours(1), TestPersistenceService.ID); - assertThat(average, is(nullValue())); + average = PersistenceExtensions.averageTill(numberItem, now.plusMinutes(30), + TestCachedValuesPersistenceService.ID); + assertNotNull(average); + dt = average.as(DecimalType.class); + assertNotNull(dt); + assertThat(dt.doubleValue(), is(closeTo(0, 0.01))); } @Test public void testAverageBetweenZeroDuration() { ZonedDateTime now = ZonedDateTime.now(); - assertDoesNotThrow( - () -> PersistenceExtensions.averageBetween(quantityItem, now, now, TestPersistenceService.ID)); - assertThat(PersistenceExtensions.averageBetween(quantityItem, now, now, TestPersistenceService.ID), - is(nullValue())); + State state = PersistenceExtensions.averageBetween(quantityItem, now, now, SERVICE_ID); + assertNotNull(state); + QuantityType qt = state.as(QuantityType.class); + assertNotNull(qt); + assertEquals(HISTORIC_END, qt.doubleValue(), 0.01); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); } @Test public void testSumSinceDecimalType() { - DecimalType sum = PersistenceExtensions.sumSince(numberItem, - ZonedDateTime.of(1940, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + State sum = PersistenceExtensions.sumSince(numberItem, + ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(sum); - assertEquals(0.0, sum.doubleValue(), 0.001); + DecimalType dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertEquals(IntStream.rangeClosed(HISTORIC_START, HISTORIC_END).sum(), dt.doubleValue(), 0.001); sum = PersistenceExtensions.sumSince(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(sum); - assertEquals(IntStream.of(2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012).sum(), sum.doubleValue(), 0.001); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertEquals(IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_END).sum(), dt.doubleValue(), 0.001); // default persistence service sum = PersistenceExtensions.sumSince(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(sum); + } + + @Test + public void testSumTillDecimalType() { + State sum = PersistenceExtensions.sumTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(sum); - assertEquals(0.0, sum.doubleValue(), 0.001); + DecimalType dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertEquals(IntStream.rangeClosed(FUTURE_START, FUTURE_INTERMEDIATE_VALUE_3).sum(), dt.doubleValue(), 0.001); + + // default persistence service + sum = PersistenceExtensions.sumTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(sum); } @Test public void testSumBetweenDecimalType() { - DecimalType sum = PersistenceExtensions.sumBetween(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertThat(sum, is(notNullValue())); - assertThat(sum.doubleValue(), is(closeTo(14056.0, 0.1))); + State sum = PersistenceExtensions.sumBetween(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(sum); + DecimalType dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertEquals(IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2).sum(), + dt.doubleValue(), 0.001); + + sum = PersistenceExtensions.sumBetween(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertEquals(IntStream.rangeClosed(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4).sum(), + dt.doubleValue(), 0.001); sum = PersistenceExtensions.sumBetween(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(sum); + dt = sum.as(DecimalType.class); + assertNotNull(dt); + assertEquals( + IntStream.concat(IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_END), + IntStream.rangeClosed(FUTURE_START, FUTURE_INTERMEDIATE_VALUE_3)).sum(), + dt.doubleValue(), 0.001); - assertThat(sum, is(notNullValue())); - assertThat(sum.doubleValue(), is(closeTo(0.0, 0.1))); + // default persistence service + sum = PersistenceExtensions.sumBetween(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(sum); } @Test public void testSumSinceQuantityType() { - DecimalType sum = PersistenceExtensions.sumSince(quantityItem, - ZonedDateTime.of(1940, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + State sum = PersistenceExtensions.sumSince(quantityItem, + ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(sum); + QuantityType qt = sum.as(QuantityType.class); + assertNotNull(qt); + assertEquals(IntStream.rangeClosed(HISTORIC_START, HISTORIC_END).sum(), qt.doubleValue(), 0.001); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); + + sum = PersistenceExtensions.sumSince(quantityItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(sum); - assertEquals(0.0, sum.doubleValue(), 0.001); + qt = sum.as(QuantityType.class); + assertNotNull(qt); + assertEquals(IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_END).sum(), qt.doubleValue(), 0.001); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); + // default persistence service sum = PersistenceExtensions.sumSince(quantityItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(sum); + } + + @Test + public void testSumTillQuantityType() { + State sum = PersistenceExtensions.sumTill(quantityItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(sum); - assertEquals(IntStream.of(2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012).sum(), sum.doubleValue(), 0.001); + QuantityType qt = sum.as(QuantityType.class); + assertNotNull(qt); + assertEquals(IntStream.rangeClosed(FUTURE_START, FUTURE_INTERMEDIATE_VALUE_3).sum(), qt.doubleValue(), 0.001); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); // default persistence service sum = PersistenceExtensions.sumSince(quantityItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(sum); + } + + @Test + public void testSumBetweenQuantityType() { + State sum = PersistenceExtensions.sumBetween(quantityItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(sum); + QuantityType qt = sum.as(QuantityType.class); + assertNotNull(qt); + assertEquals(IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_INTERMEDIATE_VALUE_2).sum(), + qt.doubleValue(), 0.001); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); + + sum = PersistenceExtensions.sumBetween(quantityItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(sum); - assertEquals(0.0, sum.doubleValue(), 0.001); + qt = sum.as(QuantityType.class); + assertNotNull(qt); + assertEquals(IntStream.rangeClosed(FUTURE_INTERMEDIATE_VALUE_3, FUTURE_INTERMEDIATE_VALUE_4).sum(), + qt.doubleValue(), 0.001); + + sum = PersistenceExtensions.sumBetween(quantityItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(sum); + qt = sum.as(QuantityType.class); + assertNotNull(qt); + assertEquals( + IntStream.concat(IntStream.rangeClosed(HISTORIC_INTERMEDIATE_VALUE_1, HISTORIC_END), + IntStream.rangeClosed(FUTURE_START, FUTURE_INTERMEDIATE_VALUE_3)).sum(), + qt.doubleValue(), 0.001); + + // default persistence service + sum = PersistenceExtensions.sumBetween(quantityItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + + assertNull(sum); } @Test public void testLastUpdate() { - numberItem.setState(new DecimalType(2005)); - ZonedDateTime lastUpdate = PersistenceExtensions.lastUpdate(numberItem, TestPersistenceService.ID); + ZonedDateTime lastUpdate = PersistenceExtensions.lastUpdate(numberItem, SERVICE_ID); assertNotNull(lastUpdate); - assertEquals(ZonedDateTime.of(2012, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), lastUpdate); + assertEquals(ZonedDateTime.of(HISTORIC_END, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), lastUpdate); // default persistence service lastUpdate = PersistenceExtensions.lastUpdate(numberItem); assertNull(lastUpdate); } + @Test + public void testNextUpdate() { + ZonedDateTime nextUpdate = PersistenceExtensions.nextUpdate(numberItem, SERVICE_ID); + assertNotNull(nextUpdate); + assertEquals(ZonedDateTime.of(FUTURE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), nextUpdate); + + // default persistence service + nextUpdate = PersistenceExtensions.lastUpdate(numberItem); + assertNull(nextUpdate); + } + @Test public void testDeltaSince() { - numberItem.setState(new DecimalType(2012)); - DecimalType delta = PersistenceExtensions.deltaSince(numberItem, - ZonedDateTime.of(1940, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + State delta = PersistenceExtensions.deltaSince(numberItem, + ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNull(delta); delta = PersistenceExtensions.deltaSince(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(delta); + DecimalType dt = delta.as(DecimalType.class); + assertNotNull(dt); + DecimalType dtState = numberItem.getState().as(DecimalType.class); + assertNotNull(dtState); + assertEquals(dtState.doubleValue() - HISTORIC_INTERMEDIATE_VALUE_1, dt.doubleValue(), 0.001); + + delta = PersistenceExtensions.deltaSince(quantityItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(delta); - assertEquals(7, delta.doubleValue(), 0.001); + QuantityType qt = delta.as(QuantityType.class); + assertNotNull(qt); + QuantityType qtState = quantityItem.getState().as(QuantityType.class); + assertNotNull(qtState); + assertEquals(qtState.doubleValue() - HISTORIC_INTERMEDIATE_VALUE_1, qt.doubleValue(), 0.001); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); - numberItem.setState(new QuantityType<>(2012, SIUnits.CELSIUS)); + // default persistence service delta = PersistenceExtensions.deltaSince(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(delta); + } + + @Test + public void testDeltaTill() { + State delta = PersistenceExtensions.deltaTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(delta); + DecimalType dt = delta.as(DecimalType.class); + assertNotNull(dt); + DecimalType dtState = numberItem.getState().as(DecimalType.class); + assertNotNull(dtState); + assertEquals(FUTURE_INTERMEDIATE_VALUE_3 - dtState.doubleValue(), dt.doubleValue(), 0.001); + + delta = PersistenceExtensions.deltaTill(quantityItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(delta); - assertEquals(7, delta.doubleValue(), 0.001); + QuantityType qt = delta.as(QuantityType.class); + assertNotNull(qt); + QuantityType qtState = quantityItem.getState().as(QuantityType.class); + assertNotNull(qtState); + assertEquals(FUTURE_INTERMEDIATE_VALUE_3 - dtState.doubleValue(), qt.doubleValue(), 0.001); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); // default persistence service - delta = PersistenceExtensions.deltaSince(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + delta = PersistenceExtensions.deltaTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); assertNull(delta); } @Test public void testDeltaBetween() { - DecimalType delta = PersistenceExtensions.deltaBetween(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertThat(delta, is(notNullValue())); - assertThat(delta.doubleValue(), is(closeTo(6, 0.001))); + State delta = PersistenceExtensions.deltaBetween(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(delta); + DecimalType dt = delta.as(DecimalType.class); + assertNotNull(dt); + assertEquals(HISTORIC_INTERMEDIATE_VALUE_2 - HISTORIC_INTERMEDIATE_VALUE_1, dt.doubleValue(), 0.001); + + delta = PersistenceExtensions.deltaBetween(quantityItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(delta); + QuantityType qt = delta.as(QuantityType.class); + assertNotNull(qt); + assertEquals(HISTORIC_INTERMEDIATE_VALUE_2 - HISTORIC_INTERMEDIATE_VALUE_1, qt.doubleValue(), 0.001); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); + + delta = PersistenceExtensions.deltaBetween(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(delta); + dt = delta.as(DecimalType.class); + assertNotNull(dt); + assertEquals(FUTURE_INTERMEDIATE_VALUE_4 - FUTURE_INTERMEDIATE_VALUE_3, dt.doubleValue(), 0.001); + + delta = PersistenceExtensions.deltaBetween(quantityItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(delta); + qt = delta.as(QuantityType.class); + assertNotNull(qt); + assertEquals(FUTURE_INTERMEDIATE_VALUE_4 - FUTURE_INTERMEDIATE_VALUE_3, qt.doubleValue(), 0.001); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); + + delta = PersistenceExtensions.deltaBetween(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(delta); + dt = delta.as(DecimalType.class); + assertNotNull(dt); + assertEquals(FUTURE_INTERMEDIATE_VALUE_3 - HISTORIC_INTERMEDIATE_VALUE_1, dt.doubleValue(), 0.001); delta = PersistenceExtensions.deltaBetween(quantityItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertThat(delta, is(notNullValue())); - assertThat(delta.doubleValue(), is(closeTo(6, 0.001))); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(delta); + qt = delta.as(QuantityType.class); + assertNotNull(qt); + assertEquals(FUTURE_INTERMEDIATE_VALUE_3 - HISTORIC_INTERMEDIATE_VALUE_1, qt.doubleValue(), 0.001); + assertEquals(SIUnits.CELSIUS, qt.getUnit()); // default persistence service delta = PersistenceExtensions.deltaBetween(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); - assertThat(delta, is(nullValue())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(delta); } @Test - public void testEvolutionRate() { - numberItem.setState(new DecimalType(2012)); - DecimalType rate = PersistenceExtensions.evolutionRate(numberItem, - ZonedDateTime.of(1940, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + public void testEvolutionRateSince() { + DecimalType rate = PersistenceExtensions.evolutionRateSince(numberItem, + ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertThat(rate, is(nullValue())); - rate = PersistenceExtensions.evolutionRate(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertThat(rate, is(notNullValue())); + rate = PersistenceExtensions.evolutionRateSince(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(rate); // ((now - then) / then) * 100 - assertThat(rate.doubleValue(), is(closeTo(0.349, 0.001))); - - rate = PersistenceExtensions.evolutionRate(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertThat(rate, is(notNullValue())); + assertThat(rate.doubleValue(), + is(closeTo( + 100.0 * (STATE.doubleValue() - HISTORIC_INTERMEDIATE_VALUE_1) / HISTORIC_INTERMEDIATE_VALUE_1, + 0.001))); + + rate = PersistenceExtensions.evolutionRateSince(quantityItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(rate); // ((now - then) / then) * 100 - assertThat(rate.doubleValue(), is(closeTo(0.299, 0.001))); + assertThat(rate.doubleValue(), + is(closeTo( + 100.0 * (STATE.doubleValue() - HISTORIC_INTERMEDIATE_VALUE_1) / HISTORIC_INTERMEDIATE_VALUE_1, + 0.001))); - numberItem.setState(new QuantityType<>(2012, SIUnits.CELSIUS)); - rate = PersistenceExtensions.evolutionRate(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertThat(rate, is(notNullValue())); - // ((now - then) / then) * 100 - assertThat(rate.doubleValue(), is(closeTo(0.349, 0.001))); + // default persistence service + rate = PersistenceExtensions.evolutionRateSince(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(rate); + } - rate = PersistenceExtensions.evolutionRate(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertThat(rate, is(notNullValue())); - // ((now - then) / then) * 100 - assertThat(rate.doubleValue(), is(closeTo(0.299, 0.001))); + @Test + public void testEvolutionRateTill() { + DecimalType rate = PersistenceExtensions.evolutionRateTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(rate); + // ((then - now) / now) * 100 + assertThat(rate.doubleValue(), + is(closeTo(100.0 * (FUTURE_INTERMEDIATE_VALUE_3 - STATE.doubleValue()) / STATE.doubleValue(), 0.001))); + + rate = PersistenceExtensions.evolutionRateTill(quantityItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(rate); + // ((then - now) / now) * 100 + assertThat(rate.doubleValue(), + is(closeTo(100.0 * (FUTURE_INTERMEDIATE_VALUE_3 - STATE.doubleValue()) / STATE.doubleValue(), 0.001))); // default persistence service - rate = PersistenceExtensions.evolutionRate(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); - assertThat(rate, is(nullValue())); + rate = PersistenceExtensions.evolutionRateTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(rate); + } - rate = PersistenceExtensions.evolutionRate(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); - assertThat(rate, is(nullValue())); + @Test + public void testEvolutionRateBetween() { + DecimalType rate = PersistenceExtensions.evolutionRateBetween(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(rate); + // ((now - then) / then) * 100 + assertThat(rate.doubleValue(), is(closeTo( + 100.0 * (HISTORIC_INTERMEDIATE_VALUE_2 - HISTORIC_INTERMEDIATE_VALUE_1) / HISTORIC_INTERMEDIATE_VALUE_1, + 0.001))); + + rate = PersistenceExtensions.evolutionRateBetween(quantityItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(rate); + // ((now - then) / then) * 100 + assertThat(rate.doubleValue(), is(closeTo( + 100.0 * (HISTORIC_INTERMEDIATE_VALUE_2 - HISTORIC_INTERMEDIATE_VALUE_1) / HISTORIC_INTERMEDIATE_VALUE_1, + 0.001))); + + rate = PersistenceExtensions.evolutionRateBetween(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(rate); + // ((now - then) / then) * 100 + assertThat(rate.doubleValue(), is(closeTo( + 100.0 * (FUTURE_INTERMEDIATE_VALUE_4 - FUTURE_INTERMEDIATE_VALUE_3) / FUTURE_INTERMEDIATE_VALUE_3, + 0.001))); + + rate = PersistenceExtensions.evolutionRateBetween(quantityItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(rate); + // ((now - then) / then) * 100 + assertThat(rate.doubleValue(), is(closeTo( + 100.0 * (FUTURE_INTERMEDIATE_VALUE_4 - FUTURE_INTERMEDIATE_VALUE_3) / FUTURE_INTERMEDIATE_VALUE_3, + 0.001))); + + rate = PersistenceExtensions.evolutionRateBetween(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(rate); + // ((now - then) / then) * 100 + assertThat(rate.doubleValue(), is(closeTo( + 100.0 * (FUTURE_INTERMEDIATE_VALUE_3 - HISTORIC_INTERMEDIATE_VALUE_1) / HISTORIC_INTERMEDIATE_VALUE_1, + 0.001))); + + rate = PersistenceExtensions.evolutionRateBetween(quantityItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertNotNull(rate); + // ((now - then) / then) * 100 + assertThat(rate.doubleValue(), is(closeTo( + 100.0 * (FUTURE_INTERMEDIATE_VALUE_3 - HISTORIC_INTERMEDIATE_VALUE_1) / HISTORIC_INTERMEDIATE_VALUE_1, + 0.001))); + + // default persistence service + rate = PersistenceExtensions.evolutionRateBetween(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(rate); } @Test public void testPreviousStateDecimalTypeNoSkip() { - HistoricItem prevStateItem = PersistenceExtensions.previousState(numberItem, false, TestPersistenceService.ID); + HistoricItem prevStateItem = PersistenceExtensions.previousState(numberItem, false, SERVICE_ID); assertNotNull(prevStateItem); assertThat(prevStateItem.getState(), is(instanceOf(DecimalType.class))); - assertEquals("2012", prevStateItem.getState().toString()); + assertEquals(value(HISTORIC_END), prevStateItem.getState()); numberItem.setState(new DecimalType(4321)); - prevStateItem = PersistenceExtensions.previousState(numberItem, false, TestPersistenceService.ID); + prevStateItem = PersistenceExtensions.previousState(numberItem, false, SERVICE_ID); assertNotNull(prevStateItem); - assertEquals("2012", prevStateItem.getState().toString()); + assertEquals(value(HISTORIC_END), prevStateItem.getState()); - numberItem.setState(new DecimalType(2012)); - prevStateItem = PersistenceExtensions.previousState(numberItem, false, TestPersistenceService.ID); + numberItem.setState(new DecimalType(HISTORIC_END)); + prevStateItem = PersistenceExtensions.previousState(numberItem, false, SERVICE_ID); assertNotNull(prevStateItem); - assertEquals("2012", prevStateItem.getState().toString()); + assertEquals(value(HISTORIC_END), prevStateItem.getState()); numberItem.setState(new DecimalType(3025)); - prevStateItem = PersistenceExtensions.previousState(numberItem, false, TestPersistenceService.ID); + prevStateItem = PersistenceExtensions.previousState(numberItem, false, SERVICE_ID); assertNotNull(prevStateItem); - assertEquals("2012", prevStateItem.getState().toString()); + assertEquals(value(HISTORIC_END), prevStateItem.getState()); // default persistence service prevStateItem = PersistenceExtensions.previousState(numberItem, false); @@ -874,26 +1855,25 @@ public void testPreviousStateDecimalTypeNoSkip() { @Test public void testPreviousStateQuantityTypeNoSkip() { - HistoricItem prevStateItem = PersistenceExtensions.previousState(quantityItem, false, - TestPersistenceService.ID); + HistoricItem prevStateItem = PersistenceExtensions.previousState(quantityItem, false, SERVICE_ID); assertNotNull(prevStateItem); assertThat(prevStateItem.getState(), is(instanceOf(QuantityType.class))); - assertEquals("2012 °C", prevStateItem.getState().toString()); + assertEquals(new QuantityType<>(value(HISTORIC_END), SIUnits.CELSIUS), prevStateItem.getState()); quantityItem.setState(QuantityType.valueOf(4321, SIUnits.CELSIUS)); - prevStateItem = PersistenceExtensions.previousState(quantityItem, false, TestPersistenceService.ID); + prevStateItem = PersistenceExtensions.previousState(quantityItem, false, SERVICE_ID); assertNotNull(prevStateItem); - assertEquals("2012 °C", prevStateItem.getState().toString()); + assertEquals(new QuantityType<>(value(HISTORIC_END), SIUnits.CELSIUS), prevStateItem.getState()); - quantityItem.setState(QuantityType.valueOf(2012, SIUnits.CELSIUS)); - prevStateItem = PersistenceExtensions.previousState(quantityItem, false, TestPersistenceService.ID); + quantityItem.setState(QuantityType.valueOf(HISTORIC_END, SIUnits.CELSIUS)); + prevStateItem = PersistenceExtensions.previousState(quantityItem, false, SERVICE_ID); assertNotNull(prevStateItem); - assertEquals("2012 °C", prevStateItem.getState().toString()); + assertEquals(new QuantityType<>(value(HISTORIC_END), SIUnits.CELSIUS), prevStateItem.getState()); quantityItem.setState(QuantityType.valueOf(3025, SIUnits.CELSIUS)); - prevStateItem = PersistenceExtensions.previousState(quantityItem, false, TestPersistenceService.ID); + prevStateItem = PersistenceExtensions.previousState(quantityItem, false, SERVICE_ID); assertNotNull(prevStateItem); - assertEquals("2012 °C", prevStateItem.getState().toString()); + assertEquals(new QuantityType<>(value(HISTORIC_END), SIUnits.CELSIUS), prevStateItem.getState()); // default persistence service prevStateItem = PersistenceExtensions.previousState(quantityItem, false); @@ -902,10 +1882,10 @@ public void testPreviousStateQuantityTypeNoSkip() { @Test public void testPreviousStateDecimalTypeSkip() { - numberItem.setState(new DecimalType(2012)); - HistoricItem prevStateItem = PersistenceExtensions.previousState(numberItem, true, TestPersistenceService.ID); + numberItem.setState(new DecimalType(HISTORIC_END)); + HistoricItem prevStateItem = PersistenceExtensions.previousState(numberItem, true, SERVICE_ID); assertNotNull(prevStateItem); - assertEquals("2011", prevStateItem.getState().toString()); + assertEquals(value(HISTORIC_END - 1), prevStateItem.getState()); // default persistence service prevStateItem = PersistenceExtensions.previousState(numberItem, true); @@ -914,162 +1894,353 @@ public void testPreviousStateDecimalTypeSkip() { @Test public void testPreviousStateQuantityTypeSkip() { - quantityItem.setState(QuantityType.valueOf(2012, SIUnits.CELSIUS)); - HistoricItem prevStateItem = PersistenceExtensions.previousState(quantityItem, true, TestPersistenceService.ID); + quantityItem.setState(QuantityType.valueOf(HISTORIC_END, SIUnits.CELSIUS)); + HistoricItem prevStateItem = PersistenceExtensions.previousState(quantityItem, true, SERVICE_ID); assertNotNull(prevStateItem); - assertEquals("2011 °C", prevStateItem.getState().toString()); + assertEquals(new QuantityType<>(value(HISTORIC_END - 1), SIUnits.CELSIUS), prevStateItem.getState()); // default persistence service prevStateItem = PersistenceExtensions.previousState(quantityItem, true); assertNull(prevStateItem); } + @Test + public void testNextStateDecimalTypeNoSkip() { + HistoricItem nextStateItem = PersistenceExtensions.nextState(numberItem, false, SERVICE_ID); + assertNotNull(nextStateItem); + assertThat(nextStateItem.getState(), is(instanceOf(DecimalType.class))); + assertEquals(value(FUTURE_START), nextStateItem.getState()); + + numberItem.setState(new DecimalType(4321)); + nextStateItem = PersistenceExtensions.nextState(numberItem, false, SERVICE_ID); + assertNotNull(nextStateItem); + assertEquals(value(FUTURE_START), nextStateItem.getState()); + + numberItem.setState(new DecimalType(FUTURE_START)); + nextStateItem = PersistenceExtensions.nextState(numberItem, false, SERVICE_ID); + assertNotNull(nextStateItem); + assertEquals(value(FUTURE_START), nextStateItem.getState()); + + numberItem.setState(new DecimalType(3025)); + nextStateItem = PersistenceExtensions.nextState(numberItem, false, SERVICE_ID); + assertNotNull(nextStateItem); + assertEquals(value(FUTURE_START), nextStateItem.getState()); + + // default persistence service + nextStateItem = PersistenceExtensions.nextState(numberItem, false); + assertNull(nextStateItem); + } + + @Test + public void testNextStateQuantityTypeNoSkip() { + HistoricItem nextStateItem = PersistenceExtensions.nextState(quantityItem, false, SERVICE_ID); + assertNotNull(nextStateItem); + assertThat(nextStateItem.getState(), is(instanceOf(QuantityType.class))); + assertEquals(new QuantityType<>(value(FUTURE_START), SIUnits.CELSIUS), nextStateItem.getState()); + + quantityItem.setState(QuantityType.valueOf(4321, SIUnits.CELSIUS)); + nextStateItem = PersistenceExtensions.nextState(quantityItem, false, SERVICE_ID); + assertNotNull(nextStateItem); + assertEquals(new QuantityType<>(value(FUTURE_START), SIUnits.CELSIUS), nextStateItem.getState()); + + quantityItem.setState(QuantityType.valueOf(FUTURE_START, SIUnits.CELSIUS)); + nextStateItem = PersistenceExtensions.nextState(quantityItem, false, SERVICE_ID); + assertNotNull(nextStateItem); + assertEquals(new QuantityType<>(value(FUTURE_START), SIUnits.CELSIUS), nextStateItem.getState()); + + quantityItem.setState(QuantityType.valueOf(3025, SIUnits.CELSIUS)); + nextStateItem = PersistenceExtensions.nextState(quantityItem, false, SERVICE_ID); + assertNotNull(nextStateItem); + assertEquals(new QuantityType<>(value(FUTURE_START), SIUnits.CELSIUS), nextStateItem.getState()); + + // default persistence service + nextStateItem = PersistenceExtensions.nextState(quantityItem, false); + assertNull(nextStateItem); + } + + @Test + public void testNextStateDecimalTypeSkip() { + numberItem.setState(new DecimalType(FUTURE_START)); + HistoricItem nextStateItem = PersistenceExtensions.nextState(numberItem, true, SERVICE_ID); + assertNotNull(nextStateItem); + assertEquals(value(FUTURE_START + 1), nextStateItem.getState()); + + // default persistence service + nextStateItem = PersistenceExtensions.nextState(numberItem, true); + assertNull(nextStateItem); + } + + @Test + public void testNextStateQuantityTypeSkip() { + quantityItem.setState(QuantityType.valueOf(FUTURE_START, SIUnits.CELSIUS)); + HistoricItem nextStateItem = PersistenceExtensions.nextState(quantityItem, true, SERVICE_ID); + assertNotNull(nextStateItem); + assertEquals(new QuantityType<>(value(FUTURE_START + 1), SIUnits.CELSIUS), nextStateItem.getState()); + + // default persistence service + nextStateItem = PersistenceExtensions.nextState(quantityItem, true); + assertNull(nextStateItem); + } + @Test public void testChangedSince() { - boolean changed = PersistenceExtensions.changedSince(numberItem, - ZonedDateTime.of(1940, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertFalse(changed); + Boolean changed = PersistenceExtensions.changedSince(numberItem, + ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(changed, true); changed = PersistenceExtensions.changedSince(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertTrue(changed); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(changed, true); // default persistence service changed = PersistenceExtensions.changedSince(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); - assertFalse(changed); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(changed); + } + + @Test + public void testChangedTill() { + Boolean changed = PersistenceExtensions.changedTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(changed, true); + + // default persistence service + changed = PersistenceExtensions.changedTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(changed); } @Test public void testChangedBetween() { - boolean changed = PersistenceExtensions.changedBetween(numberItem, - ZonedDateTime.of(2019, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2019, 5, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertFalse(changed); + Boolean changed = PersistenceExtensions.changedBetween(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 5, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(changed, false); + + changed = PersistenceExtensions.changedBetween(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(changed, true); + + changed = PersistenceExtensions.changedBetween(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 5, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(changed, false); changed = PersistenceExtensions.changedBetween(numberItem, - ZonedDateTime.of(2006, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2008, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertTrue(changed); + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(changed, true); // default persistence service changed = PersistenceExtensions.changedBetween(numberItem, - ZonedDateTime.of(2004, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); - assertFalse(changed); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(changed); } @Test public void testUpdatedSince() { - boolean updated = PersistenceExtensions.updatedSince(numberItem, - ZonedDateTime.of(1940, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertFalse(updated); + Boolean updated = PersistenceExtensions.updatedSince(numberItem, + ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(updated, true); updated = PersistenceExtensions.updatedSince(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertTrue(updated); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(updated, true); // default persistence service updated = PersistenceExtensions.updatedSince(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); - assertFalse(updated); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(updated); + } + + @Test + public void testUpdatedTill() { + Boolean updated = PersistenceExtensions.updatedTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(updated, true); + + // default persistence service + updated = PersistenceExtensions.updatedTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(updated); } @Test public void testUpdatedBetween() { - boolean updated = PersistenceExtensions.updatedBetween(numberItem, - ZonedDateTime.of(1940, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(1970, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertFalse(updated); + Boolean updated = PersistenceExtensions.updatedBetween(numberItem, + ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(updated, true); updated = PersistenceExtensions.updatedBetween(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertTrue(updated); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(updated, true); updated = PersistenceExtensions.updatedBetween(numberItem, - ZonedDateTime.of(2019, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2021, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertTrue(updated); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_NOVALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_NOVALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + SERVICE_ID); + assertEquals(updated, false); - // default persistence service updated = PersistenceExtensions.updatedBetween(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); - assertFalse(updated); - } - - @Test - public void testCountBetween() { - long counts = PersistenceExtensions.countBetween(numberItem, - ZonedDateTime.of(1940, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(1970, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertEquals(0, counts); + ZonedDateTime.of(FUTURE_INTERMEDIATE_NOVALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_NOVALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(updated, false); - counts = PersistenceExtensions.countBetween(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertEquals(7, counts); + updated = PersistenceExtensions.updatedBetween(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(updated, true); - counts = PersistenceExtensions.countBetween(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); - assertEquals(0, counts); + // default persistence service + updated = PersistenceExtensions.updatedBetween(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(updated); } @Test public void testCountSince() { - long counts = PersistenceExtensions.countSince(numberItem, - ZonedDateTime.of(1980, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertEquals(33, counts); + Long counts = PersistenceExtensions.countSince(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(HISTORIC_END - HISTORIC_INTERMEDIATE_VALUE_1 + 1, counts); counts = PersistenceExtensions.countSince(numberItem, - ZonedDateTime.of(2007, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertEquals(6, counts); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(HISTORIC_END - HISTORIC_INTERMEDIATE_VALUE_2 + 1, counts); counts = PersistenceExtensions.countSince(numberItem, - ZonedDateTime.of(2020, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_NOVALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + SERVICE_ID); assertEquals(0, counts); + // default persistence service counts = PersistenceExtensions.countSince(numberItem, - ZonedDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(counts); + } + + @Test + public void testCountTill() { + Long counts = PersistenceExtensions.countTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_NOVALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertEquals(0, counts); + + counts = PersistenceExtensions.countTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START + 1, counts); + + counts = PersistenceExtensions.countTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(FUTURE_INTERMEDIATE_VALUE_4 - FUTURE_START + 1, counts); + + // default persistence service + counts = PersistenceExtensions.countTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(counts); + } + + @Test + public void testCountBetween() { + Long counts = PersistenceExtensions.countBetween(numberItem, + ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(HISTORIC_INTERMEDIATE_VALUE_1 - HISTORIC_START + 1, counts); + + counts = PersistenceExtensions.countBetween(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(HISTORIC_INTERMEDIATE_VALUE_2 - HISTORIC_INTERMEDIATE_VALUE_1 + 1, counts); + + counts = PersistenceExtensions.countBetween(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(FUTURE_INTERMEDIATE_VALUE_4 - FUTURE_INTERMEDIATE_VALUE_3 + 1, counts); + + counts = PersistenceExtensions.countBetween(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START + 1 + HISTORIC_END - HISTORIC_INTERMEDIATE_VALUE_1 + 1, + counts); + + // default persistence service + counts = PersistenceExtensions.countBetween(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(counts); } @Test public void testCountStateChangesSince() { - long counts = PersistenceExtensions.countStateChangesSince(numberItem, - ZonedDateTime.of(1980, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertEquals(32, counts); + Long counts = PersistenceExtensions.countStateChangesSince(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(HISTORIC_END - HISTORIC_INTERMEDIATE_VALUE_1, counts); counts = PersistenceExtensions.countStateChangesSince(numberItem, - ZonedDateTime.of(2007, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertEquals(5, counts); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(HISTORIC_END - HISTORIC_INTERMEDIATE_VALUE_2, counts); counts = PersistenceExtensions.countStateChangesSince(numberItem, - ZonedDateTime.of(2020, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_NOVALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + SERVICE_ID); assertEquals(0, counts); + // default persistence service counts = PersistenceExtensions.countStateChangesSince(numberItem, - ZonedDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(counts); + } + + @Test + public void testCountStateChangesTill() { + Long counts = PersistenceExtensions.countStateChangesTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_NOVALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertEquals(0, counts); + + counts = PersistenceExtensions.countStateChangesTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START, counts); + + counts = PersistenceExtensions.countStateChangesTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(FUTURE_INTERMEDIATE_VALUE_4 - FUTURE_START, counts); + + // default persistence service + counts = PersistenceExtensions.countStateChangesTill(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(counts); } @Test public void testCountStateChangesBetween() { - long counts = PersistenceExtensions.countStateChangesBetween(numberItem, - ZonedDateTime.of(1940, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(1970, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertEquals(0, counts); + Long counts = PersistenceExtensions.countStateChangesBetween(numberItem, + ZonedDateTime.of(BEFORE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(HISTORIC_INTERMEDIATE_VALUE_1 - HISTORIC_START, counts); counts = PersistenceExtensions.countStateChangesBetween(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), TestPersistenceService.ID); - assertEquals(6, counts); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(HISTORIC_INTERMEDIATE_VALUE_2 - HISTORIC_INTERMEDIATE_VALUE_1, counts); + + counts = PersistenceExtensions.countBetween(numberItem, + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(FUTURE_INTERMEDIATE_VALUE_4 - FUTURE_INTERMEDIATE_VALUE_3 + 1, counts); + counts = PersistenceExtensions.countBetween(numberItem, + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); + assertEquals(FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START + 1 + HISTORIC_END - HISTORIC_INTERMEDIATE_VALUE_1 + 1, + counts); + + // default persistence service counts = PersistenceExtensions.countStateChangesBetween(numberItem, - ZonedDateTime.of(2005, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), - ZonedDateTime.of(2011, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); - assertEquals(0, counts); + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), + ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); + assertNull(counts); } } diff --git a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestCachedValuesPersistenceService.java b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestCachedValuesPersistenceService.java index 6c6f2f3fd41..250d42604be 100644 --- a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestCachedValuesPersistenceService.java +++ b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestCachedValuesPersistenceService.java @@ -25,8 +25,8 @@ import org.openhab.core.persistence.FilterCriteria; import org.openhab.core.persistence.FilterCriteria.Ordering; import org.openhab.core.persistence.HistoricItem; +import org.openhab.core.persistence.ModifiablePersistenceService; import org.openhab.core.persistence.PersistenceItemInfo; -import org.openhab.core.persistence.QueryablePersistenceService; import org.openhab.core.persistence.strategy.PersistenceStrategy; import org.openhab.core.types.State; @@ -36,7 +36,7 @@ * @author Florian Binder - Initial contribution */ @NonNullByDefault -public class TestCachedValuesPersistenceService implements QueryablePersistenceService { +public class TestCachedValuesPersistenceService implements ModifiablePersistenceService { public static final String ID = "testCachedHistoricItems"; @@ -62,6 +62,19 @@ public void store(Item item) { public void store(Item item, @Nullable String alias) { } + @Override + public void store(Item item, ZonedDateTime date, State state) { + } + + @Override + public void store(Item item, ZonedDateTime date, State state, @Nullable String alias) { + } + + @Override + public boolean remove(FilterCriteria filter) throws IllegalArgumentException { + return true; + } + @Override public Iterable query(FilterCriteria filter) { Stream stream = historicItems.stream(); @@ -70,16 +83,19 @@ public Iterable query(FilterCriteria filter) { throw new UnsupportedOperationException("state filtering is not supported yet"); } - if (filter.getItemName() != null) { - stream = stream.filter(hi -> filter.getItemName().equals(hi.getName())); + String itemName = filter.getItemName(); + if (itemName != null) { + stream = stream.filter(hi -> itemName.equals(hi.getName())); } - if (filter.getBeginDate() != null) { - stream = stream.filter(hi -> !filter.getBeginDate().isAfter(hi.getTimestamp())); + ZonedDateTime beginDate = filter.getBeginDate(); + if (beginDate != null) { + stream = stream.filter(hi -> !beginDate.isAfter(hi.getTimestamp())); } - if (filter.getEndDate() != null) { - stream = stream.filter(hi -> !filter.getEndDate().isBefore(hi.getTimestamp())); + ZonedDateTime endDate = filter.getEndDate(); + if (endDate != null) { + stream = stream.filter(hi -> !endDate.isBefore(hi.getTimestamp())); } if (filter.getOrdering() == Ordering.ASCENDING) { 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 3a3deea4b9d..b42e7df8307 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 @@ -12,6 +12,7 @@ */ package org.openhab.core.persistence.extensions; +import java.time.Duration; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; @@ -21,6 +22,7 @@ import java.util.Locale; import java.util.Objects; import java.util.Set; +import java.util.stream.LongStream; import java.util.stream.Stream; import javax.measure.Unit; @@ -45,11 +47,44 @@ * A simple persistence service used for unit tests * * @author Kai Kreuzer - Initial contribution + * @author Mark Herwege - Allow future values */ @NonNullByDefault public class TestPersistenceService implements QueryablePersistenceService { - public static final String ID = "test"; + public static final String SERVICE_ID = "test"; + + static final int SWITCH_START = -15; + static final int SWITCH_ON_1 = -15; + static final int SWITCH_ON_INTERMEDIATE_1 = -12; + static final int SWITCH_OFF_1 = -10; + static final int SWITCH_OFF_INTERMEDIATE_1 = -6; + static final int SWITCH_ON_2 = -5; + static final int SWITCH_ON_INTERMEDIATE_21 = -1; + static final int SWITCH_ON_INTERMEDIATE_22 = +1; + static final int SWITCH_OFF_2 = +5; + static final int SWITCH_OFF_INTERMEDIATE_2 = +7; + static final int SWITCH_ON_3 = +10; + static final int SWITCH_ON_INTERMEDIATE_3 = +12; + static final int SWITCH_OFF_3 = +15; + static final int SWITCH_END = +15; + static final OnOffType SWITCH_STATE = OnOffType.ON; + + static final int BEFORE_START = 1940; + static final int HISTORIC_START = 1950; + static final int HISTORIC_INTERMEDIATE_VALUE_1 = 2005; + static final int HISTORIC_INTERMEDIATE_VALUE_2 = 2011; + static final int HISTORIC_END = 2012; + static final int HISTORIC_INTERMEDIATE_NOVALUE_3 = 2019; + static final int HISTORIC_INTERMEDIATE_NOVALUE_4 = 2021; + static final int FUTURE_INTERMEDIATE_NOVALUE_1 = 2051; + static final int FUTURE_INTERMEDIATE_NOVALUE_2 = 2056; + static final int FUTURE_START = 2060; + static final int FUTURE_INTERMEDIATE_VALUE_3 = 2070; + static final int FUTURE_INTERMEDIATE_VALUE_4 = 2077; + static final int FUTURE_END = 2100; + static final int AFTER_END = 2110; + static final DecimalType STATE = new DecimalType(HISTORIC_END); private final ItemRegistry itemRegistry; @@ -59,7 +94,7 @@ public TestPersistenceService(ItemRegistry itemRegistry) { @Override public String getId() { - return ID; + return SERVICE_ID; } @Override @@ -73,18 +108,17 @@ public void store(Item item, @Nullable String alias) { @Override public Iterable query(FilterCriteria filter) { if (PersistenceExtensionsTest.TEST_SWITCH.equals(filter.getItemName())) { - ZonedDateTime now = ZonedDateTime.now().truncatedTo(ChronoUnit.MINUTES), - nowMinusFifteenHours = now.minusHours(15), - beginDate = filter.getBeginDate() != null ? filter.getBeginDate() : nowMinusFifteenHours, - endDate = filter.getEndDate() != null ? filter.getEndDate() : now; - if (endDate.isBefore(beginDate)) { - return List.of(); - } + ZonedDateTime now = ZonedDateTime.now().truncatedTo(ChronoUnit.MINUTES); + ZonedDateTime nowMinusHours = now.plusHours(SWITCH_START); + ZonedDateTime endDate = filter.getEndDate(); + endDate = endDate != null ? endDate : now; + ZonedDateTime beginDate = filter.getBeginDate(); + beginDate = beginDate != null ? beginDate : endDate.isAfter(now) ? now : endDate.minusHours(1); - List results = new ArrayList<>(16); - for (int i = 0; i <= 15; i++) { - final int hours = i; - final ZonedDateTime theDate = nowMinusFifteenHours.plusHours(hours); + List results = new ArrayList<>(31); + for (int i = SWITCH_START; i <= SWITCH_END; i++) { + final int hour = i; + final ZonedDateTime theDate = nowMinusHours.plusHours(i - SWITCH_START); if (!theDate.isBefore(beginDate) && !theDate.isAfter(endDate)) { results.add(new HistoricItem() { @Override @@ -94,7 +128,8 @@ public ZonedDateTime getTimestamp() { @Override public State getState() { - return OnOffType.from(hours < 5 || hours > 10); + return OnOffType.from(hour < SWITCH_OFF_1 || (hour >= SWITCH_ON_2 && hour < SWITCH_OFF_2) + || hour >= SWITCH_ON_3); } @Override @@ -117,22 +152,27 @@ public String getName() { } return stream.toList(); } else { - int startValue = 1950; - int endValue = 2012; + int startValue = HISTORIC_START; + int endValue = FUTURE_END; - if (filter.getBeginDate() != null) { - startValue = filter.getBeginDate().getYear(); + ZonedDateTime beginDate = filter.getBeginDate(); + if (beginDate != null && beginDate.getYear() >= startValue) { + startValue = beginDate.getYear(); } - if (filter.getEndDate() != null) { - endValue = filter.getEndDate().getYear(); + ZonedDateTime endDate = filter.getEndDate(); + if (endDate != null && endDate.getYear() <= endValue) { + endValue = endDate.getYear(); } - if (endValue <= startValue || startValue < 1950) { + if (endValue <= startValue) { return List.of(); } List results = new ArrayList<>(endValue - startValue); for (int i = startValue; i <= endValue; i++) { + if (i > HISTORIC_END && i < FUTURE_START) { + continue; + } final int year = i; results.add(new HistoricItem() { @Override @@ -182,4 +222,46 @@ public String getLabel(@Nullable Locale locale) { public List getDefaultStrategies() { return List.of(); } + + static OnOffType switchValue(int hour) { + return (hour >= SWITCH_ON_1 && hour < SWITCH_OFF_1) || (hour >= SWITCH_ON_2 && hour < SWITCH_OFF_2) + || (hour >= SWITCH_ON_3 && hour < SWITCH_OFF_3) ? OnOffType.ON : OnOffType.OFF; + } + + static DecimalType value(long year) { + if (year < HISTORIC_START) { + return DecimalType.ZERO; + } else if (year <= HISTORIC_END) { + return new DecimalType(year); + } else if (year < FUTURE_START) { + return new DecimalType(HISTORIC_END); + } else if (year <= FUTURE_END) { + return new DecimalType(year); + } else { + return new DecimalType(FUTURE_END); + } + } + + static double average(@Nullable Integer beginYear, @Nullable Integer endYear) { + ZonedDateTime now = ZonedDateTime.now(); + ZonedDateTime beginDate = beginYear != null + ? ZonedDateTime.of(beginYear >= HISTORIC_START ? beginYear : HISTORIC_START, 1, 1, 0, 0, 0, 0, + ZoneId.systemDefault()) + : 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(); + return 1.0 * sum / duration; + } } From 586a54d1871293db96bb53bbc82544f141be8a95 Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Wed, 10 Jan 2024 17:28:22 +0100 Subject: [PATCH 02/13] spotless Signed-off-by: Mark Herwege --- .../core/persistence/extensions/PersistenceExtensions.java | 1 - .../core/persistence/extensions/PersistenceExtensionsTest.java | 1 - 2 files changed, 2 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 94b7efeaffd..965500bfd31 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 @@ -427,7 +427,6 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser */ public static @Nullable HistoricItem previousState(Item item, boolean skipEqual, String serviceId) { return internalAdjacentState(item, skipEqual, false, serviceId); - } /** 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 d2c8a7d7116..7f694aab797 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 @@ -258,7 +258,6 @@ public void testPersistedStateOnOffType() { SERVICE_ID); assertNotNull(historicItem); assertEquals(switchValue(SWITCH_ON_INTERMEDIATE_3), historicItem.getState()); - } @Test From 836e73b5138d3e0bbaf3c2e289305a9ecd1d8c75 Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Wed, 10 Jan 2024 17:34:47 +0100 Subject: [PATCH 03/13] fix compiler error Signed-off-by: Mark Herwege --- .../core/persistence/extensions/PersistenceExtensions.java | 4 ++-- 1 file changed, 2 insertions(+), 2 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 965500bfd31..0d90472345a 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 @@ -1390,8 +1390,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser // } while (it.hasNext()) { HistoricItem thisItem = it.next(); - if (lastItem != null && lastItem.getState() instanceof State state) { - DecimalType dtState = state.as(DecimalType.class); + if (lastItem != null) { + DecimalType dtState = lastItem.getState().as(DecimalType.class); if (dtState != null) { BigDecimal value = dtState.toBigDecimal(); BigDecimal weight = BigDecimal From f7c6df4f824bf32d445f4fdb09814be45de9f4db Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Wed, 10 Jan 2024 17:38:50 +0100 Subject: [PATCH 04/13] fix null warnings Signed-off-by: Mark Herwege --- .../persistence/extensions/PersistenceExtensions.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 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 0d90472345a..de35ac4069c 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 @@ -187,7 +187,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries) { private static void internalPersist(Item item, TimeSeries timeSeries, String serviceId) { PersistenceService service = getService(serviceId); - ZoneId timeZone = timeZoneProvider != null ? timeZoneProvider.getTimeZone() : ZoneId.systemDefault(); + TimeZoneProvider tzProvider = timeZoneProvider; + ZoneId timeZone = tzProvider != null ? tzProvider.getTimeZone() : ZoneId.systemDefault(); if (service != null && service instanceof ModifiablePersistenceService modifiableService) { timeSeries.getStates() .forEach(s -> modifiableService.store(item, s.timestamp().atZone(timeZone), s.state(), serviceId)); @@ -2214,12 +2215,14 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } private static @Nullable PersistenceService getService(String serviceId) { - return registry != null ? registry.get(serviceId) : null; + PersistenceServiceRegistry reg = registry; + return reg != null ? reg.get(serviceId) : null; } private static @Nullable String getDefaultServiceId() { - if (registry != null) { - String id = registry.getDefaultId(); + PersistenceServiceRegistry reg = registry; + if (reg != null) { + String id = reg.getDefaultId(); if (id != null) { return id; } else { From abdf2c171afc2149a65bae15534471225a4c1577 Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Wed, 10 Jan 2024 17:58:22 +0100 Subject: [PATCH 05/13] add remove commands Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) 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 de35ac4069c..aa65cf00fba 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 @@ -2166,6 +2166,125 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser return null; } + /** + * Removes from persistence the historic items for a given item since a certain point in time. + * The default persistence service is used. + * This will only have effect if the p{@link PersistenceService} is a {@link ModifiablePersistenceService}. + * + * @param item the item for which to remove the historic item + * @param timestamp the point in time from which to remove the states + */ + public static void removeAllStatesSince(Item item, ZonedDateTime timestamp) { + internalRemoveAllStatesBetween(item, timestamp, null); + } + + /** + * Removes from persistence the future items for a given item till a certain point in time. + * The default persistence service is used. + * This will only have effect if the p{@link PersistenceService} is a {@link ModifiablePersistenceService}. + * + * @param item the item for which to remove the future item + * @param timestamp the point in time to which to remove the states + */ + public static void removeAllStatesTill(Item item, ZonedDateTime timestamp) { + internalRemoveAllStatesBetween(item, null, timestamp); + } + + /** + * Removes from persistence the historic items for a given item between two certain points in time. + * The default persistence service is used. + * This will only have effect if the p{@link PersistenceService} is a {@link ModifiablePersistenceService}. + * + * @param item the item for which to remove the historic item + * @param begin the point in time from which to remove the states + * @param end the point in time to which to remove the states + */ + public static void removeAllStatesBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { + internalRemoveAllStatesBetween(item, begin, end); + } + + /** + * Removes from persistence the historic items for a given item since a certain point in time + * through a {@link PersistenceService} identified by the serviceId. + * This will only have effect if the p{@link PersistenceService} is a {@link ModifiablePersistenceService}. + * + * @param item the item for which to remove the historic item + * @param timestamp the point in time from which to remove the states + * @param serviceId the name of the {@link PersistenceService} to use + */ + public void removeAllStatesSince(Item item, ZonedDateTime timestamp, String serviceId) { + internalRemoveAllStatesBetween(item, timestamp, null, serviceId); + } + + /** + * Removes from persistence the future items for a given item till a certain point in time + * through a {@link PersistenceService} identified by the serviceId. + * This will only have effect if the p{@link PersistenceService} is a {@link ModifiablePersistenceService}. + * + * @param item the item for which to remove the future item + * @param timestamp the point in time to which to remove the states + * @param serviceId the name of the {@link PersistenceService} to use + */ + public static void removeAllStatesTill(Item item, ZonedDateTime timestamp, String serviceId) { + internalRemoveAllStatesBetween(item, null, timestamp, serviceId); + } + + /** + * Removes from persistence the historic items for a given item beetween two certain points in time + * through a {@link PersistenceService} identified by the serviceId. + * This will only have effect if the p{@link PersistenceService} is a {@link ModifiablePersistenceService}. + * + * @param item the item for which to remove the historic item + * @param begin the point in time from which to remove the states + * @param end the point in time to which to remove the states + * @param serviceId the name of the {@link PersistenceService} to use + */ + public static void removeAllStatesBetween(Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { + internalRemoveAllStatesBetween(item, begin, end, serviceId); + } + + private static void internalRemoveAllStatesBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end) { + String serviceId = getDefaultServiceId(); + if (serviceId != null) { + internalRemoveAllStatesBetween(item, begin, end, serviceId); + } + } + + private static void internalRemoveAllStatesBetween(Item item, @Nullable ZonedDateTime begin, + @Nullable ZonedDateTime end, String serviceId) { + PersistenceService service = getService(serviceId); + if (service != null && service instanceof ModifiablePersistenceService mService) { + FilterCriteria filter = new FilterCriteria(); + ZonedDateTime now = ZonedDateTime.now(); + if ((begin == null && end == null) || (begin != null && end == null && begin.isAfter(now)) + || (begin == null && end != null && end.isBefore(now))) { + LoggerFactory.getLogger(PersistenceExtensions.class).warn( + "Querying persistence service with open begin and/or end not allowed: begin {}, end {}, now {}", + begin, end, now); + return; + } + if (begin != null) { + filter.setBeginDate(begin); + } else { + filter.setBeginDate(ZonedDateTime.now()); + } + if (end != null) { + filter.setEndDate(end); + } else { + filter.setEndDate(ZonedDateTime.now()); + } + filter.setItemName(item.getName()); + filter.setOrdering(Ordering.ASCENDING); + + mService.remove(filter); + return; + } + LoggerFactory.getLogger(PersistenceExtensions.class) + .warn("There is no queryable persistence service registered with the id '{}'", serviceId); + return; + } + private static @Nullable Iterable getAllStatesBetweenWithBoundaries(Item item, @Nullable ZonedDateTime begin, @Nullable ZonedDateTime end, String serviceId) { Iterable betweenItems = internalGetAllStatesBetween(item, begin, end, serviceId); From cd678903586310332d985e71ff790ceb4e2c260c Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Wed, 10 Jan 2024 18:02:43 +0100 Subject: [PATCH 06/13] fix Signed-off-by: Mark Herwege --- .../core/persistence/extensions/PersistenceExtensions.java | 2 +- 1 file changed, 1 insertion(+), 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 aa65cf00fba..f6b17e9a8a7 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 @@ -2212,7 +2212,7 @@ public static void removeAllStatesBetween(Item item, ZonedDateTime begin, ZonedD * @param timestamp the point in time from which to remove the states * @param serviceId the name of the {@link PersistenceService} to use */ - public void removeAllStatesSince(Item item, ZonedDateTime timestamp, String serviceId) { + public static void removeAllStatesSince(Item item, ZonedDateTime timestamp, String serviceId) { internalRemoveAllStatesBetween(item, timestamp, null, serviceId); } From ed5901028864c420fcd9089cfeffb3344edc19fa Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Fri, 12 Jan 2024 13:48:51 +0100 Subject: [PATCH 07/13] test remove methods Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 28 +- .../extensions/PersistenceExtensionsTest.java | 297 +++++++++++++----- .../TestCachedValuesPersistenceService.java | 8 +- 3 files changed, 242 insertions(+), 91 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 f6b17e9a8a7..c3f398e42c2 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 @@ -2043,8 +2043,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the item for which to retrieve the historic item * @param timestamp the point in time from which to retrieve the states - * @return the historic items since the given point in time, or null if no historic items could be - * found. + * @return the historic items since the given point in time, or null + * if the default persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} + * */ public static @Nullable Iterable getAllStatesSince(Item item, ZonedDateTime timestamp) { return internalGetAllStatesBetween(item, timestamp, null); @@ -2056,8 +2058,9 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the item for which to retrieve the future item * @param timestamp the point in time to which to retrieve the states - * @return the future items to the given point in time, or null if no future items could be - * found. + * @return the future items to the given point in time, or null + * if the default persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} */ public static @Nullable Iterable getAllStatesTill(Item item, ZonedDateTime timestamp) { return internalGetAllStatesBetween(item, null, timestamp); @@ -2070,8 +2073,9 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item for which to retrieve the historic item * @param begin the point in time from which to retrieve the states * @param end the point in time to which to retrieve the states - * @return the historic items between the given points in time, or null if no historic items could be - * found. + * @return the historic items between the given points in time, or null + * if the default persistence service is not available or does not refer to a + * {@link QueryablePersistenceService} */ public static @Nullable Iterable getAllStatesBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { @@ -2085,8 +2089,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item for which to retrieve the historic item * @param timestamp the point in time from which to retrieve the states * @param serviceId the name of the {@link PersistenceService} to use - * @return the future items to the given point in time, or null if no historic items could be - * found or if the provided serviceId does not refer to an available + * @return the historic items since the given point in time, or null + * if the provided serviceId does not refer to an available * {@link QueryablePersistenceService} */ public static @Nullable Iterable getAllStatesSince(Item item, ZonedDateTime timestamp, @@ -2101,8 +2105,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item for which to retrieve the future item * @param timestamp the point in time to which to retrieve the states * @param serviceId the name of the {@link PersistenceService} to use - * @return the historic items since the given point in time, or null if no historic items could be - * found or if the provided serviceId does not refer to an available + * @return the future items to the given point in time, or null + * if the provided serviceId does not refer to an available * {@link QueryablePersistenceService} */ public static @Nullable Iterable getAllStatesTill(Item item, ZonedDateTime timestamp, @@ -2118,8 +2122,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param begin the point in time from which to retrieve the states * @param end the point in time to which to retrieve the states * @param serviceId the name of the {@link PersistenceService} to use - * @return the historic items between the given points in time, or null if no historic items could be - * found or if the provided serviceId does not refer to an available + * @return the historic items between the given points in time, or null + * if the provided serviceId does not refer to an available * {@link QueryablePersistenceService} */ public static @Nullable Iterable getAllStatesBetween(Item item, ZonedDateTime begin, 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 7f694aab797..9d94fa086c3 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 @@ -1286,55 +1286,25 @@ public void testAverageTillOnOffType() { @Test public void testAverageSinceDecimalTypeIrregularTimespans() { - TestCachedValuesPersistenceService persistenceService = new TestCachedValuesPersistenceService(); - new PersistenceExtensions(new PersistenceServiceRegistry() { - - @Override - public @Nullable String getDefaultId() { - // not available - return null; - } - - @Override - public @Nullable PersistenceService getDefault() { - // not available - return null; - } - - @Override - public Set getAll() { - return Set.of(persistenceService); - } - - @Override - public @Nullable PersistenceService get(@Nullable String serviceId) { - return TestCachedValuesPersistenceService.ID.equals(serviceId) ? persistenceService : null; - } - }, timeZoneProviderMock); - ZonedDateTime now = ZonedDateTime.now(); - ZonedDateTime beginStored = now.minusHours(27); + int historicHours = 27; + int futureHours = 0; - persistenceService.addHistoricItem(beginStored, new DecimalType(0), TEST_NUMBER); - persistenceService.addHistoricItem(beginStored.plusHours(1), new DecimalType(100), TEST_NUMBER); - persistenceService.addHistoricItem(beginStored.plusHours(2), new DecimalType(0), TEST_NUMBER); - persistenceService.addHistoricItem(beginStored.plusHours(25), new DecimalType(50), TEST_NUMBER); - persistenceService.addHistoricItem(beginStored.plusHours(26), new DecimalType(0), TEST_NUMBER); - numberItem.setState(new DecimalType(0)); + createTestCachedValuesPersistenceService(now, historicHours, futureHours); - State average = PersistenceExtensions.averageSince(numberItem, beginStored, + State average = PersistenceExtensions.averageSince(numberItem, now.minusHours(historicHours), TestCachedValuesPersistenceService.ID); assertNotNull(average); DecimalType dt = average.as(DecimalType.class); assertNotNull(dt); - assertThat(dt.doubleValue(), is(closeTo((100.0 + 50.0) / 27.0, 0.01))); + assertThat(dt.doubleValue(), is(closeTo((100.0 + 50.0) / historicHours, 0.01))); - average = PersistenceExtensions.averageSince(numberItem, beginStored.plusHours(3), + average = PersistenceExtensions.averageSince(numberItem, now.minusHours(historicHours).plusHours(3), TestCachedValuesPersistenceService.ID); assertNotNull(average); dt = average.as(DecimalType.class); assertNotNull(dt); - assertThat(dt.doubleValue(), is(closeTo(50.0 / 24.0, 0.01))); + assertThat(dt.doubleValue(), is(closeTo(50.0 / (historicHours - 3.0), 0.01))); average = PersistenceExtensions.averageSince(numberItem, now.minusMinutes(30), TestCachedValuesPersistenceService.ID); @@ -1346,55 +1316,25 @@ public Set getAll() { @Test public void testAverageTillDecimalTypeIrregularTimespans() { - TestCachedValuesPersistenceService persistenceService = new TestCachedValuesPersistenceService(); - new PersistenceExtensions(new PersistenceServiceRegistry() { - - @Override - public @Nullable String getDefaultId() { - // not available - return null; - } - - @Override - public @Nullable PersistenceService getDefault() { - // not available - return null; - } - - @Override - public Set getAll() { - return Set.of(persistenceService); - } - - @Override - public @Nullable PersistenceService get(@Nullable String serviceId) { - return TestCachedValuesPersistenceService.ID.equals(serviceId) ? persistenceService : null; - } - }, timeZoneProviderMock); - ZonedDateTime now = ZonedDateTime.now(); - ZonedDateTime beginStored = now.plusHours(1); + int historicHours = 0; + int futureHours = 27; - persistenceService.addHistoricItem(beginStored, new DecimalType(0), TEST_NUMBER); - persistenceService.addHistoricItem(beginStored.plusHours(1), new DecimalType(0), TEST_NUMBER); - persistenceService.addHistoricItem(beginStored.plusHours(2), new DecimalType(50), TEST_NUMBER); - persistenceService.addHistoricItem(beginStored.plusHours(3), new DecimalType(0), TEST_NUMBER); - persistenceService.addHistoricItem(beginStored.plusHours(25), new DecimalType(100), TEST_NUMBER); - numberItem.setState(new DecimalType(0)); + createTestCachedValuesPersistenceService(now, historicHours, futureHours); - State average = PersistenceExtensions.averageTill(numberItem, beginStored.plusHours(26), + State average = PersistenceExtensions.averageTill(numberItem, now.plusHours(futureHours), TestCachedValuesPersistenceService.ID); assertNotNull(average); DecimalType dt = average.as(DecimalType.class); assertNotNull(dt); - assertThat(dt.doubleValue(), is(closeTo((100.0 + 50.0) / 27.0, 0.01))); + assertThat(dt.doubleValue(), is(closeTo((100.0 + 50.0) / futureHours, 0.01))); - average = PersistenceExtensions.averageTill(numberItem, beginStored.plusHours(24), + average = PersistenceExtensions.averageTill(numberItem, now.plusHours(futureHours).minusHours(2), TestCachedValuesPersistenceService.ID); assertNotNull(average); dt = average.as(DecimalType.class); assertNotNull(dt); - assertThat(dt.doubleValue(), is(closeTo(50.0 / 25.0, 0.01))); + assertThat(dt.doubleValue(), is(closeTo(50.0 / (futureHours - 2.0), 0.01))); average = PersistenceExtensions.averageTill(numberItem, now.plusMinutes(30), TestCachedValuesPersistenceService.ID); @@ -2242,4 +2182,213 @@ public void testCountStateChangesBetween() { ZonedDateTime.of(HISTORIC_INTERMEDIATE_VALUE_2, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); assertNull(counts); } + + @Test + public void testRemoveAllStatesSince() { + ZonedDateTime now = ZonedDateTime.now(); + int historicHours = 27; + int futureHours = 27; + createTestCachedValuesPersistenceService(now, historicHours, futureHours); + + assertNotNull(PersistenceExtensions.getAllStatesSince(numberItem, now.minusHours(historicHours), + TestCachedValuesPersistenceService.ID)); + assertThat(PersistenceExtensions.countSince(numberItem, now.minusHours(historicHours), + TestCachedValuesPersistenceService.ID), is(5L)); + HistoricItem historicItem = PersistenceExtensions.previousState(numberItem, + TestCachedValuesPersistenceService.ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(new DecimalType(0))); + + PersistenceExtensions.removeAllStatesSince(numberItem, now.minusHours(1), + TestCachedValuesPersistenceService.ID); + assertNotNull(PersistenceExtensions.getAllStatesSince(numberItem, now.minusHours(historicHours), + TestCachedValuesPersistenceService.ID)); + assertThat(PersistenceExtensions.countSince(numberItem, now.minusHours(historicHours), + TestCachedValuesPersistenceService.ID), is(4L)); + historicItem = PersistenceExtensions.previousState(numberItem, TestCachedValuesPersistenceService.ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(new DecimalType(50))); + + PersistenceExtensions.removeAllStatesSince(numberItem, now.minusHours(3), + TestCachedValuesPersistenceService.ID); + assertNotNull(PersistenceExtensions.getAllStatesSince(numberItem, now.minusHours(historicHours), + TestCachedValuesPersistenceService.ID)); + assertThat(PersistenceExtensions.countSince(numberItem, now.minusHours(historicHours), + TestCachedValuesPersistenceService.ID), is(3L)); + historicItem = PersistenceExtensions.previousState(numberItem, TestCachedValuesPersistenceService.ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(new DecimalType(0))); + + PersistenceExtensions.removeAllStatesSince(numberItem, now.minusHours(historicHours + 1), + TestCachedValuesPersistenceService.ID); + assertNotNull(PersistenceExtensions.getAllStatesSince(numberItem, now.minusHours(historicHours), + TestCachedValuesPersistenceService.ID)); + assertThat(PersistenceExtensions.countSince(numberItem, now.minusHours(historicHours), + TestCachedValuesPersistenceService.ID), is(0L)); + historicItem = PersistenceExtensions.previousState(numberItem, TestCachedValuesPersistenceService.ID); + assertNull(historicItem); + } + + @Test + public void testRemoveAllStatesTill() { + ZonedDateTime now = ZonedDateTime.now(); + int historicHours = 27; + int futureHours = 27; + createTestCachedValuesPersistenceService(now, historicHours, futureHours); + + assertNotNull(PersistenceExtensions.getAllStatesTill(numberItem, now.plusHours(futureHours), + TestCachedValuesPersistenceService.ID)); + assertThat(PersistenceExtensions.countTill(numberItem, now.plusHours(futureHours), + TestCachedValuesPersistenceService.ID), is(5L)); + HistoricItem historicItem = PersistenceExtensions.nextState(numberItem, TestCachedValuesPersistenceService.ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(new DecimalType(0))); + + PersistenceExtensions.removeAllStatesTill(numberItem, now.plusHours(1), TestCachedValuesPersistenceService.ID); + assertNotNull(PersistenceExtensions.getAllStatesTill(numberItem, now.plusHours(futureHours), + TestCachedValuesPersistenceService.ID)); + assertThat(PersistenceExtensions.countTill(numberItem, now.plusHours(futureHours), + TestCachedValuesPersistenceService.ID), is(4L)); + historicItem = PersistenceExtensions.nextState(numberItem, TestCachedValuesPersistenceService.ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(new DecimalType(50))); + + PersistenceExtensions.removeAllStatesTill(numberItem, now.plusHours(2), TestCachedValuesPersistenceService.ID); + assertNotNull(PersistenceExtensions.getAllStatesTill(numberItem, now.plusHours(futureHours), + TestCachedValuesPersistenceService.ID)); + assertThat(PersistenceExtensions.countTill(numberItem, now.plusHours(futureHours), + TestCachedValuesPersistenceService.ID), is(3L)); + historicItem = PersistenceExtensions.nextState(numberItem, TestCachedValuesPersistenceService.ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(new DecimalType(0))); + + PersistenceExtensions.removeAllStatesTill(numberItem, now.plusHours(futureHours + 1), + TestCachedValuesPersistenceService.ID); + assertNotNull(PersistenceExtensions.getAllStatesTill(numberItem, now.plusHours(futureHours), + TestCachedValuesPersistenceService.ID)); + assertThat(PersistenceExtensions.countTill(numberItem, now.plusHours(futureHours), + TestCachedValuesPersistenceService.ID), is(0L)); + historicItem = PersistenceExtensions.nextState(numberItem, TestCachedValuesPersistenceService.ID); + assertNull(historicItem); + } + + @Test + public void testRemoveAllStatesBetween() { + ZonedDateTime now = ZonedDateTime.now(); + int historicHours = 27; + int futureHours = 27; + createTestCachedValuesPersistenceService(now, historicHours, futureHours); + + assertNotNull(PersistenceExtensions.getAllStatesBetween(numberItem, now.minusHours(historicHours), + now.plusHours(futureHours), TestCachedValuesPersistenceService.ID)); + assertThat(PersistenceExtensions.countBetween(numberItem, now.minusHours(historicHours), + now.plusHours(futureHours), TestCachedValuesPersistenceService.ID), is(10L)); + HistoricItem historicItem = PersistenceExtensions.previousState(numberItem, + TestCachedValuesPersistenceService.ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(new DecimalType(0))); + historicItem = PersistenceExtensions.nextState(numberItem, TestCachedValuesPersistenceService.ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(new DecimalType(0))); + + PersistenceExtensions.removeAllStatesBetween(numberItem, now.minusHours(2), now.minusHours(1), + TestCachedValuesPersistenceService.ID); + assertNotNull(PersistenceExtensions.getAllStatesBetween(numberItem, now.minusHours(historicHours), + now.plusHours(futureHours), TestCachedValuesPersistenceService.ID)); + assertThat(PersistenceExtensions.countBetween(numberItem, now.minusHours(historicHours), + now.plusHours(futureHours), TestCachedValuesPersistenceService.ID), is(8L)); + historicItem = PersistenceExtensions.previousState(numberItem, TestCachedValuesPersistenceService.ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(new DecimalType(0))); + historicItem = PersistenceExtensions.nextState(numberItem, TestCachedValuesPersistenceService.ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(new DecimalType(0))); + + PersistenceExtensions.removeAllStatesBetween(numberItem, now.plusHours(1), now.plusHours(2), + TestCachedValuesPersistenceService.ID); + assertNotNull(PersistenceExtensions.getAllStatesBetween(numberItem, now.minusHours(historicHours), + now.plusHours(futureHours), TestCachedValuesPersistenceService.ID)); + assertThat(PersistenceExtensions.countBetween(numberItem, now.minusHours(historicHours), + now.plusHours(futureHours), TestCachedValuesPersistenceService.ID), is(6L)); + historicItem = PersistenceExtensions.previousState(numberItem, TestCachedValuesPersistenceService.ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(new DecimalType(0))); + historicItem = PersistenceExtensions.nextState(numberItem, TestCachedValuesPersistenceService.ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(new DecimalType(0))); + + PersistenceExtensions.removeAllStatesBetween(numberItem, now.minusHours(historicHours - 2), + now.plusHours(futureHours - 2), TestCachedValuesPersistenceService.ID); + assertNotNull(PersistenceExtensions.getAllStatesBetween(numberItem, now.minusHours(historicHours), + now.plusHours(futureHours), TestCachedValuesPersistenceService.ID)); + assertThat(PersistenceExtensions.countBetween(numberItem, now.minusHours(historicHours), + now.plusHours(futureHours), TestCachedValuesPersistenceService.ID), is(3L)); + historicItem = PersistenceExtensions.previousState(numberItem, TestCachedValuesPersistenceService.ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(new DecimalType(100))); + historicItem = PersistenceExtensions.nextState(numberItem, TestCachedValuesPersistenceService.ID); + assertNotNull(historicItem); + assertThat(historicItem.getState(), is(new DecimalType(0))); + + PersistenceExtensions.removeAllStatesBetween(numberItem, now.minusHours(historicHours + 1), + now.plusHours(futureHours + 1), TestCachedValuesPersistenceService.ID); + assertNotNull(PersistenceExtensions.getAllStatesBetween(numberItem, now.minusHours(historicHours), + now.plusHours(futureHours), TestCachedValuesPersistenceService.ID)); + assertThat(PersistenceExtensions.countBetween(numberItem, now.minusHours(historicHours), + now.plusHours(futureHours), TestCachedValuesPersistenceService.ID), is(0L)); + historicItem = PersistenceExtensions.previousState(numberItem, TestCachedValuesPersistenceService.ID); + assertNull(historicItem); + historicItem = PersistenceExtensions.nextState(numberItem, TestCachedValuesPersistenceService.ID); + assertNull(historicItem); + } + + private void createTestCachedValuesPersistenceService(ZonedDateTime now, int historicHours, int futureHours) { + // Check that test is relevant and fail if badly configured + assertTrue(historicHours == 0 || historicHours > 5); + assertTrue(futureHours == 0 || futureHours > 5); + + TestCachedValuesPersistenceService persistenceService = new TestCachedValuesPersistenceService(); + new PersistenceExtensions(new PersistenceServiceRegistry() { + + @Override + public @Nullable String getDefaultId() { + // not available + return null; + } + + @Override + public @Nullable PersistenceService getDefault() { + // not available + return null; + } + + @Override + public Set getAll() { + return Set.of(persistenceService); + } + + @Override + public @Nullable PersistenceService get(@Nullable String serviceId) { + return TestCachedValuesPersistenceService.ID.equals(serviceId) ? persistenceService : null; + } + }, timeZoneProviderMock); + + if (historicHours > 0) { + ZonedDateTime beginHistory = now.minusHours(historicHours); + persistenceService.store(numberItem, beginHistory, new DecimalType(0)); + persistenceService.store(numberItem, beginHistory.plusHours(1), new DecimalType(100)); + persistenceService.store(numberItem, beginHistory.plusHours(2), new DecimalType(0)); + persistenceService.store(numberItem, now.minusHours(2), new DecimalType(50)); + persistenceService.store(numberItem, now.minusHours(1), new DecimalType(0)); + } + numberItem.setState(new DecimalType(0)); + if (futureHours > 0) { + ZonedDateTime endFuture = now.plusHours(futureHours); + persistenceService.store(numberItem, now.plusHours(1), new DecimalType(0)); + persistenceService.store(numberItem, now.plusHours(2), new DecimalType(50)); + persistenceService.store(numberItem, now.plusHours(3), new DecimalType(0)); + persistenceService.store(numberItem, endFuture.minusHours(2), new DecimalType(100)); + persistenceService.store(numberItem, endFuture.minusHours(1), new DecimalType(0)); + } + } } diff --git a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestCachedValuesPersistenceService.java b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestCachedValuesPersistenceService.java index 250d42604be..7f708885461 100644 --- a/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestCachedValuesPersistenceService.java +++ b/bundles/org.openhab.core.persistence/src/test/java/org/openhab/core/persistence/extensions/TestCachedValuesPersistenceService.java @@ -18,6 +18,7 @@ import java.util.Locale; import java.util.Set; import java.util.stream.Stream; +import java.util.stream.StreamSupport; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -45,10 +46,6 @@ public class TestCachedValuesPersistenceService implements ModifiablePersistence public TestCachedValuesPersistenceService() { } - public void addHistoricItem(ZonedDateTime timestamp, State state, String itemName) { - historicItems.add(new CachedHistoricItem(timestamp, state, itemName)); - } - @Override public String getId() { return ID; @@ -64,6 +61,7 @@ public void store(Item item, @Nullable String alias) { @Override public void store(Item item, ZonedDateTime date, State state) { + historicItems.add(new CachedHistoricItem(date, state, item.getName())); } @Override @@ -72,7 +70,7 @@ public void store(Item item, ZonedDateTime date, State state, @Nullable String a @Override public boolean remove(FilterCriteria filter) throws IllegalArgumentException { - return true; + return historicItems.removeAll(StreamSupport.stream(query(filter).spliterator(), false).toList()); } @Override From 8f943b358faed271903d9d32ef396dca857e5c1b Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Mon, 22 Jan 2024 08:52:29 +0100 Subject: [PATCH 08/13] replace Till with Until Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 58 +++--- .../extensions/PersistenceExtensionsTest.java | 182 +++++++++--------- 2 files changed, 120 insertions(+), 120 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 c3f398e42c2..ef5ef45c29c 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 @@ -551,7 +551,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * if the default persistence service is not available or does not refer to a * {@link QueryablePersistenceService} */ - public static @Nullable Boolean changedTill(Item item, ZonedDateTime timestamp) { + public static @Nullable Boolean changedUntil(Item item, ZonedDateTime timestamp) { return internalChangedBetween(item, null, timestamp); } @@ -595,7 +595,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * null if the provided serviceId does not refer to an available * {@link QueryablePersistenceService} */ - public static @Nullable Boolean changedTill(Item item, ZonedDateTime timestamp, String serviceId) { + public static @Nullable Boolean changedUntil(Item item, ZonedDateTime timestamp, String serviceId) { return internalChangedBetween(item, null, timestamp, serviceId); } @@ -673,7 +673,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * {@link QueryablePersistenceService}, or null if the default persistence service is not * available */ - public static @Nullable Boolean updatedTill(Item item, ZonedDateTime timestamp) { + public static @Nullable Boolean updatedUntil(Item item, ZonedDateTime timestamp) { return internalUpdatedBetween(item, null, timestamp); } @@ -719,7 +719,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * since timestamp, null if the given serviceId does not refer to a * {@link QueryablePersistenceService} */ - public static @Nullable Boolean updatedTill(Item item, ZonedDateTime timestamp, String serviceId) { + public static @Nullable Boolean updatedUntil(Item item, ZonedDateTime timestamp, String serviceId) { return internalUpdatedBetween(item, null, timestamp, serviceId); } @@ -779,7 +779,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * constructed from the item if the default persistence service does not refer to a * {@link QueryablePersistenceService} */ - public static @Nullable HistoricItem maximumTill(Item item, ZonedDateTime timestamp) { + public static @Nullable HistoricItem maximumUntil(Item item, ZonedDateTime timestamp) { return internalMaximumBetween(item, null, timestamp); } @@ -826,7 +826,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * maximum value or if the given serviceId does not refer to an available * {@link QueryablePersistenceService} */ - public static @Nullable HistoricItem maximumTill(final Item item, ZonedDateTime timestamp, String serviceId) { + public static @Nullable HistoricItem maximumUntil(final Item item, ZonedDateTime timestamp, String serviceId) { return internalMaximumBetween(item, null, timestamp, serviceId); } @@ -900,7 +900,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * constructed from the item's state if item's state is the minimum value or if * the default persistence service does not refer to an available {@link QueryablePersistenceService} */ - public static @Nullable HistoricItem minimumTill(Item item, ZonedDateTime timestamp) { + public static @Nullable HistoricItem minimumUntil(Item item, ZonedDateTime timestamp) { return internalMinimumBetween(item, null, timestamp); } @@ -945,7 +945,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * constructed from the item's state if item's state is the minimum value or if * the given serviceId does not refer to an available {@link QueryablePersistenceService}. */ - public static @Nullable HistoricItem minimumTill(final Item item, ZonedDateTime timestamp, String serviceId) { + public static @Nullable HistoricItem minimumUntil(final Item item, ZonedDateTime timestamp, String serviceId) { return internalMinimumBetween(item, null, timestamp, serviceId); } @@ -1019,7 +1019,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * 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 varianceTill(Item item, ZonedDateTime timestamp) { + public static @Nullable State varianceUntil(Item item, ZonedDateTime timestamp) { return internalVarianceBetween(item, null, timestamp); } @@ -1064,7 +1064,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * 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 varianceTill(Item item, ZonedDateTime timestamp, String serviceId) { + public static @Nullable State varianceUntil(Item item, ZonedDateTime timestamp, String serviceId) { return internalVarianceBetween(item, null, timestamp, serviceId); } @@ -1159,7 +1159,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * 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 deviationTill(Item item, ZonedDateTime timestamp) { + public static @Nullable State deviationUntil(Item item, ZonedDateTime timestamp) { return internalDeviationBetween(item, timestamp, null); } @@ -1213,7 +1213,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * serviceId it is not available or is not a {@link QueryablePersistenceService}, or if there * is no persisted state for the given item at the given timestamp */ - public static @Nullable State deviationTill(Item item, ZonedDateTime timestamp, String serviceId) { + public static @Nullable State deviationUntil(Item item, ZonedDateTime timestamp, String serviceId) { return internalDeviationBetween(item, null, timestamp, serviceId); } @@ -1288,7 +1288,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * 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 averageTill(Item item, ZonedDateTime timestamp) { + public static @Nullable State averageUntil(Item item, ZonedDateTime timestamp) { return internalAverageBetween(item, null, timestamp); } @@ -1335,7 +1335,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * refer to an available {@link QueryablePersistenceService}. The current state is included in the * calculation. */ - public static @Nullable State averageTill(Item item, ZonedDateTime timestamp, String serviceId) { + public static @Nullable State averageUntil(Item item, ZonedDateTime timestamp, String serviceId) { return internalAverageBetween(item, null, timestamp, serviceId); } @@ -1457,7 +1457,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * states could be found or if the default persistence service does not refer to a * {@link QueryablePersistenceService} */ - public @Nullable static State sumTill(Item item, ZonedDateTime timestamp) { + public @Nullable static State sumUntil(Item item, ZonedDateTime timestamp) { return internalSumBetween(item, null, timestamp); } @@ -1503,7 +1503,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * states could be found for the item or if serviceId does not refer to a * {@link QueryablePersistenceService} */ - public @Nullable static State sumTill(Item item, ZonedDateTime timestamp, String serviceId) { + public @Nullable static State sumUntil(Item item, ZonedDateTime timestamp, String serviceId) { return internalSumBetween(item, null, timestamp, serviceId); } @@ -1581,7 +1581,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * there is no persisted state for the given item at the given timestamp available * in the default persistence service */ - public static @Nullable State deltaTill(Item item, ZonedDateTime timestamp) { + public static @Nullable State deltaUntil(Item item, ZonedDateTime timestamp) { return internalDeltaBetween(item, null, timestamp); } @@ -1628,7 +1628,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * item at the given timestamp using the persistence service named * serviceId */ - public static @Nullable State deltaTill(Item item, ZonedDateTime timestamp, String serviceId) { + public static @Nullable State deltaUntil(Item item, ZonedDateTime timestamp, String serviceId) { return internalDeltaBetween(item, null, timestamp, serviceId); } @@ -1705,7 +1705,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * the given timestamp, or if there is a state but it is zero (which would cause a * divide-by-zero error) */ - public static @Nullable DecimalType evolutionRateTill(Item item, ZonedDateTime timestamp) { + public static @Nullable DecimalType evolutionRateUntil(Item item, ZonedDateTime timestamp) { return internalEvolutionRateBetween(item, null, timestamp); } @@ -1758,7 +1758,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * serviceId, or if there is a state but it is zero (which would cause a divide-by-zero * error) */ - public static @Nullable DecimalType evolutionRateTill(Item item, ZonedDateTime timestamp, String serviceId) { + public static @Nullable DecimalType evolutionRateUntil(Item item, ZonedDateTime timestamp, String serviceId) { return internalEvolutionRateBetween(item, null, timestamp, serviceId); } @@ -1832,7 +1832,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * if the default persistence service is not available or does not refer to a * {@link QueryablePersistenceService} */ - public static @Nullable Long countTill(Item item, ZonedDateTime timestamp) { + public static @Nullable Long countUntil(Item item, ZonedDateTime timestamp) { return internalCountBetween(item, null, timestamp); } @@ -1877,7 +1877,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * if the persistence service is not available or does not refer to a * {@link QueryablePersistenceService} */ - public static @Nullable Long countTill(Item item, ZonedDateTime timestamp, String serviceId) { + public static @Nullable Long countUntil(Item item, ZonedDateTime timestamp, String serviceId) { return internalCountBetween(item, null, timestamp, serviceId); } @@ -1940,7 +1940,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * if the default persistence service is not available or does not refer to a * {@link QueryablePersistenceService} */ - public static @Nullable Long countStateChangesTill(Item item, ZonedDateTime timestamp) { + public static @Nullable Long countStateChangesUntil(Item item, ZonedDateTime timestamp) { return internalCountStateChangesBetween(item, null, timestamp); } @@ -1985,7 +1985,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * if the persistence service is not available or does not refer to a * {@link QueryablePersistenceService} */ - public static @Nullable Long countStateChangesTill(Item item, ZonedDateTime timestamp, String serviceId) { + public static @Nullable Long countStateChangesUntil(Item item, ZonedDateTime timestamp, String serviceId) { return internalCountStateChangesBetween(item, null, timestamp, serviceId); } @@ -2046,7 +2046,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @return the historic items since the given point in time, or null * if the default persistence service is not available or does not refer to a * {@link QueryablePersistenceService} - * + * */ public static @Nullable Iterable getAllStatesSince(Item item, ZonedDateTime timestamp) { return internalGetAllStatesBetween(item, timestamp, null); @@ -2062,7 +2062,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * if the default persistence service is not available or does not refer to a * {@link QueryablePersistenceService} */ - public static @Nullable Iterable getAllStatesTill(Item item, ZonedDateTime timestamp) { + public static @Nullable Iterable getAllStatesUntil(Item item, ZonedDateTime timestamp) { return internalGetAllStatesBetween(item, null, timestamp); } @@ -2109,7 +2109,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * if the provided serviceId does not refer to an available * {@link QueryablePersistenceService} */ - public static @Nullable Iterable getAllStatesTill(Item item, ZonedDateTime timestamp, + public static @Nullable Iterable getAllStatesUntil(Item item, ZonedDateTime timestamp, String serviceId) { return internalGetAllStatesBetween(item, null, timestamp, serviceId); } @@ -2190,7 +2190,7 @@ public static void removeAllStatesSince(Item item, ZonedDateTime timestamp) { * @param item the item for which to remove the future item * @param timestamp the point in time to which to remove the states */ - public static void removeAllStatesTill(Item item, ZonedDateTime timestamp) { + public static void removeAllStatesUntil(Item item, ZonedDateTime timestamp) { internalRemoveAllStatesBetween(item, null, timestamp); } @@ -2229,7 +2229,7 @@ public static void removeAllStatesSince(Item item, ZonedDateTime timestamp, Stri * @param timestamp the point in time to which to remove the states * @param serviceId the name of the {@link PersistenceService} to use */ - public static void removeAllStatesTill(Item item, ZonedDateTime timestamp, String serviceId) { + public static void removeAllStatesUntil(Item item, ZonedDateTime timestamp, String serviceId) { internalRemoveAllStatesBetween(item, null, timestamp, serviceId); } 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 9d94fa086c3..73a68d4c8dd 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 @@ -282,14 +282,14 @@ public void testMaximumSinceDecimalType() { } @Test - public void testMaximumTillDecimalType() { - HistoricItem historicItem = PersistenceExtensions.maximumTill(numberItem, + public void testMaximumUntilDecimalType() { + HistoricItem historicItem = PersistenceExtensions.maximumUntil(numberItem, ZonedDateTime.of(FUTURE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); assertThat(historicItem.getState(), is(instanceOf(DecimalType.class))); assertEquals(value(FUTURE_START), historicItem.getState()); - historicItem = PersistenceExtensions.maximumTill(numberItem, + historicItem = PersistenceExtensions.maximumUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); assertEquals(value(FUTURE_INTERMEDIATE_VALUE_3), historicItem.getState()); @@ -297,7 +297,7 @@ public void testMaximumTillDecimalType() { historicItem.getTimestamp()); // default persistence service - historicItem = PersistenceExtensions.maximumTill(numberItem, + historicItem = PersistenceExtensions.maximumUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); assertNull(historicItem); } @@ -362,14 +362,14 @@ public void testMaximumSinceQuantityType() { } @Test - public void testMaximumTillQuantityType() { - HistoricItem historicItem = PersistenceExtensions.maximumTill(quantityItem, + public void testMaximumUntilQuantityType() { + HistoricItem historicItem = PersistenceExtensions.maximumUntil(quantityItem, ZonedDateTime.of(FUTURE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); assertThat(historicItem.getState(), is(instanceOf(QuantityType.class))); assertEquals(new QuantityType<>(value(FUTURE_START), SIUnits.CELSIUS), historicItem.getState()); - historicItem = PersistenceExtensions.maximumTill(quantityItem, + historicItem = PersistenceExtensions.maximumUntil(quantityItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); assertEquals(new QuantityType<>(value(FUTURE_INTERMEDIATE_VALUE_3), SIUnits.CELSIUS), historicItem.getState()); @@ -377,7 +377,7 @@ public void testMaximumTillQuantityType() { historicItem.getTimestamp()); // default persistence service - historicItem = PersistenceExtensions.maximumTill(quantityItem, + historicItem = PersistenceExtensions.maximumUntil(quantityItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); assertNull(historicItem); } @@ -443,23 +443,23 @@ public void testMaximumSinceOnOffType() { } @Test - public void testMaximumTillOnOffType() { + public void testMaximumUntilOnOffType() { ZonedDateTime now = ZonedDateTime.now(); - HistoricItem historicItem = PersistenceExtensions.maximumTill(switchItem, + HistoricItem historicItem = PersistenceExtensions.maximumUntil(switchItem, now.plusHours(SWITCH_OFF_INTERMEDIATE_2), SERVICE_ID); assertNotNull(historicItem); assertEquals(switchValue(SWITCH_ON_2), historicItem.getState()); - historicItem = PersistenceExtensions.maximumTill(switchItem, now.plusHours(SWITCH_ON_INTERMEDIATE_3), + historicItem = PersistenceExtensions.maximumUntil(switchItem, now.plusHours(SWITCH_ON_INTERMEDIATE_3), SERVICE_ID); assertNotNull(historicItem); assertEquals(switchValue(SWITCH_ON_3), historicItem.getState()); - historicItem = PersistenceExtensions.maximumTill(switchItem, now.plusHours(SWITCH_END), SERVICE_ID); + historicItem = PersistenceExtensions.maximumUntil(switchItem, now.plusHours(SWITCH_END), SERVICE_ID); assertNotNull(historicItem); assertEquals(switchValue(SWITCH_ON_3), historicItem.getState()); - historicItem = PersistenceExtensions.maximumTill(switchItem, now.plusHours(SWITCH_ON_INTERMEDIATE_21), + historicItem = PersistenceExtensions.maximumUntil(switchItem, now.plusHours(SWITCH_ON_INTERMEDIATE_21), SERVICE_ID); assertNull(historicItem); } @@ -486,20 +486,20 @@ public void testMinimumSinceDecimalType() { } @Test - public void testMinimumTillDecimalType() { - HistoricItem historicItem = PersistenceExtensions.minimumTill(numberItem, + public void testMinimumUntilDecimalType() { + HistoricItem historicItem = PersistenceExtensions.minimumUntil(numberItem, ZonedDateTime.of(FUTURE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); assertThat(historicItem.getState(), is(instanceOf(DecimalType.class))); assertEquals(value(HISTORIC_END), historicItem.getState()); - historicItem = PersistenceExtensions.minimumTill(numberItem, + historicItem = PersistenceExtensions.minimumUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); assertEquals(value(HISTORIC_END), historicItem.getState()); // default persistence service - historicItem = PersistenceExtensions.minimumTill(numberItem, + historicItem = PersistenceExtensions.minimumUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); assertNull(historicItem); } @@ -565,20 +565,20 @@ public void testMinimumSinceQuantityType() { } @Test - public void testMinimumTillQuantityType() { - HistoricItem historicItem = PersistenceExtensions.minimumTill(quantityItem, + public void testMinimumUntilQuantityType() { + HistoricItem historicItem = PersistenceExtensions.minimumUntil(quantityItem, ZonedDateTime.of(FUTURE_START, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); assertThat(historicItem.getState(), is(instanceOf(QuantityType.class))); assertEquals(new QuantityType<>(value(HISTORIC_END), SIUnits.CELSIUS), historicItem.getState()); - historicItem = PersistenceExtensions.minimumTill(quantityItem, + historicItem = PersistenceExtensions.minimumUntil(quantityItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(historicItem); assertEquals(new QuantityType<>(value(HISTORIC_END), SIUnits.CELSIUS), historicItem.getState()); // default persistence service - historicItem = PersistenceExtensions.minimumTill(quantityItem, + historicItem = PersistenceExtensions.minimumUntil(quantityItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); assertNull(historicItem); } @@ -666,7 +666,7 @@ public void testVarianceSinceDecimalType() { } @Test - public void testVarianceTillDecimalType() { + public void testVarianceUntilDecimalType() { ZonedDateTime endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); double expectedAverage = average(null, FUTURE_INTERMEDIATE_VALUE_3); @@ -677,14 +677,14 @@ public void testVarianceTillDecimalType() { .mapToDouble(i -> Double.valueOf(i))) .map(d -> Math.pow(d - expectedAverage, 2)).sum() / (1 + FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START + 1); - State variance = PersistenceExtensions.varianceTill(numberItem, endStored, SERVICE_ID); + State variance = PersistenceExtensions.varianceUntil(numberItem, endStored, SERVICE_ID); assertNotNull(variance); DecimalType dt = variance.as(DecimalType.class); assertNotNull(dt); assertEquals(expected, dt.doubleValue(), 0.01); // default persistence service - variance = PersistenceExtensions.varianceTill(numberItem, endStored); + variance = PersistenceExtensions.varianceUntil(numberItem, endStored); assertNull(variance); } @@ -765,7 +765,7 @@ public void testVarianceSinceQuantityType() { } @Test - public void testVarianceTillQuantityType() { + public void testVarianceUntilQuantityType() { ZonedDateTime endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); double expectedAverage = average(null, FUTURE_INTERMEDIATE_VALUE_3); @@ -776,7 +776,7 @@ public void testVarianceTillQuantityType() { .mapToDouble(i -> Double.valueOf(i))) .map(d -> Math.pow(d - expectedAverage, 2)).sum() / (1 + FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START + 1); - State variance = PersistenceExtensions.varianceTill(quantityItem, endStored, SERVICE_ID); + State variance = PersistenceExtensions.varianceUntil(quantityItem, endStored, SERVICE_ID); assertNotNull(variance); QuantityType qt = variance.as(QuantityType.class); assertNotNull(qt); @@ -784,7 +784,7 @@ public void testVarianceTillQuantityType() { assertEquals(SIUnits.CELSIUS.multiply(SIUnits.CELSIUS), qt.getUnit()); // default persistence service - variance = PersistenceExtensions.varianceTill(quantityItem, endStored); + variance = PersistenceExtensions.varianceUntil(quantityItem, endStored); assertNull(variance); } @@ -867,7 +867,7 @@ public void testDeviationSinceDecimalType() { } @Test - public void testDeviationTillDecimalType() { + public void testDeviationUntilDecimalType() { ZonedDateTime endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); double expectedAverage = average(null, FUTURE_INTERMEDIATE_VALUE_3); @@ -878,14 +878,14 @@ public void testDeviationTillDecimalType() { .mapToDouble(i -> Double.valueOf(i))) .map(d -> Math.pow(d - expectedAverage, 2)).sum() / (1 + FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START + 1)); - State deviation = PersistenceExtensions.deviationTill(numberItem, endStored, SERVICE_ID); + State deviation = PersistenceExtensions.deviationUntil(numberItem, endStored, SERVICE_ID); assertNotNull(deviation); DecimalType dt = deviation.as(DecimalType.class); assertNotNull(dt); assertEquals(expected, dt.doubleValue(), 0.01); // default persistence service - deviation = PersistenceExtensions.deviationTill(numberItem, endStored); + deviation = PersistenceExtensions.deviationUntil(numberItem, endStored); assertNull(deviation); } @@ -965,7 +965,7 @@ public void testDeviationSinceQuantityType() { } @Test - public void testDeviationTillQuantityType() { + public void testDeviationUntilQuantityType() { ZonedDateTime endStored = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); double expectedAverage = average(null, FUTURE_INTERMEDIATE_VALUE_3); @@ -976,7 +976,7 @@ public void testDeviationTillQuantityType() { .mapToDouble(i -> Double.valueOf(i))) .map(d -> Math.pow(d - expectedAverage, 2)).sum() / (1 + FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START + 1)); - State deviation = PersistenceExtensions.deviationTill(quantityItem, endStored, SERVICE_ID); + State deviation = PersistenceExtensions.deviationUntil(quantityItem, endStored, SERVICE_ID); assertNotNull(deviation); QuantityType qt = deviation.as(QuantityType.class); assertNotNull(qt); @@ -984,7 +984,7 @@ public void testDeviationTillQuantityType() { assertEquals(SIUnits.CELSIUS, qt.getUnit()); // default persistence service - deviation = PersistenceExtensions.deviationTill(quantityItem, endStored); + deviation = PersistenceExtensions.deviationUntil(quantityItem, endStored); assertNull(deviation); } @@ -1067,17 +1067,17 @@ public void testAverageSinceDecimalType() { } @Test - public void testAverageTillDecimalType() { + public void testAverageUntilDecimalType() { ZonedDateTime end = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); double expected = average(null, FUTURE_INTERMEDIATE_VALUE_3); - State average = PersistenceExtensions.averageTill(numberItem, end, SERVICE_ID); + State average = PersistenceExtensions.averageUntil(numberItem, end, SERVICE_ID); assertNotNull(average); DecimalType dt = average.as(DecimalType.class); assertNotNull(dt); assertEquals(expected, dt.doubleValue(), 0.01); // default persistence service - average = PersistenceExtensions.averageTill(numberItem, end); + average = PersistenceExtensions.averageUntil(numberItem, end); assertNull(average); } @@ -1146,10 +1146,10 @@ public void testAverageSinceQuantityType() { } @Test - public void testAverageTillQuantityType() { + public void testAverageUntilQuantityType() { ZonedDateTime end = ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()); double expected = average(null, FUTURE_INTERMEDIATE_VALUE_3); - State average = PersistenceExtensions.averageTill(quantityItem, end, SERVICE_ID); + State average = PersistenceExtensions.averageUntil(quantityItem, end, SERVICE_ID); assertNotNull(average); QuantityType qt = average.as(QuantityType.class); assertNotNull(qt); @@ -1157,7 +1157,7 @@ public void testAverageTillQuantityType() { assertEquals(SIUnits.CELSIUS, qt.getUnit()); // default persistence service - average = PersistenceExtensions.averageTill(quantityItem, end); + average = PersistenceExtensions.averageUntil(quantityItem, end); assertNull(average); } @@ -1245,42 +1245,42 @@ public void testAverageSinceOnOffType() { } @Test - public void testAverageTillOnOffType() { + public void testAverageUntilOnOffType() { // switch is 5h ON, 5h OFF, and 5h ON (from now) ZonedDateTime now = ZonedDateTime.now().truncatedTo(ChronoUnit.MINUTES); - State average = PersistenceExtensions.averageTill(switchItem, now.plusHours(SWITCH_END), SERVICE_ID); + State average = PersistenceExtensions.averageUntil(switchItem, now.plusHours(SWITCH_END), SERVICE_ID); assertNotNull(average); DecimalType dt = average.as(DecimalType.class); assertNotNull(dt); assertThat(dt.doubleValue(), is(closeTo((SWITCH_OFF_3 - SWITCH_ON_3 + SWITCH_OFF_2) / (1.0 * SWITCH_END), 0.01))); - average = PersistenceExtensions.averageTill(switchItem, now.plusHours(SWITCH_OFF_INTERMEDIATE_2), SERVICE_ID); + average = PersistenceExtensions.averageUntil(switchItem, now.plusHours(SWITCH_OFF_INTERMEDIATE_2), SERVICE_ID); assertNotNull(average); dt = average.as(DecimalType.class); assertNotNull(dt); assertThat(dt.doubleValue(), is(closeTo(SWITCH_OFF_2 / (1.0 * SWITCH_OFF_INTERMEDIATE_2), 0.01))); - average = PersistenceExtensions.averageTill(switchItem, now.plusHours(SWITCH_ON_3), SERVICE_ID); + average = PersistenceExtensions.averageUntil(switchItem, now.plusHours(SWITCH_ON_3), SERVICE_ID); assertNotNull(average); dt = average.as(DecimalType.class); assertNotNull(dt); assertThat(dt.doubleValue(), is(closeTo(SWITCH_OFF_2 / (1.0 * SWITCH_ON_3), 0.01))); - average = PersistenceExtensions.averageTill(switchItem, now.plusHours(SWITCH_ON_INTERMEDIATE_22), SERVICE_ID); + average = PersistenceExtensions.averageUntil(switchItem, now.plusHours(SWITCH_ON_INTERMEDIATE_22), SERVICE_ID); assertNotNull(average); dt = average.as(DecimalType.class); assertNotNull(dt); assertThat(dt.doubleValue(), is(closeTo(SWITCH_ON_INTERMEDIATE_22 / (1.0 * SWITCH_ON_INTERMEDIATE_22), 0.01))); - average = PersistenceExtensions.averageTill(switchItem, now.plusMinutes(1), SERVICE_ID); + average = PersistenceExtensions.averageUntil(switchItem, now.plusMinutes(1), SERVICE_ID); assertNotNull(average); dt = average.as(DecimalType.class); assertNotNull(dt); assertThat(dt.doubleValue(), is(closeTo(1d, 0.01))); - average = PersistenceExtensions.averageTill(switchItem, now.minusHours(1), SERVICE_ID); + average = PersistenceExtensions.averageUntil(switchItem, now.minusHours(1), SERVICE_ID); assertNull(average); } @@ -1315,28 +1315,28 @@ public void testAverageSinceDecimalTypeIrregularTimespans() { } @Test - public void testAverageTillDecimalTypeIrregularTimespans() { + public void testAverageUntilDecimalTypeIrregularTimespans() { ZonedDateTime now = ZonedDateTime.now(); int historicHours = 0; int futureHours = 27; createTestCachedValuesPersistenceService(now, historicHours, futureHours); - State average = PersistenceExtensions.averageTill(numberItem, now.plusHours(futureHours), + State average = PersistenceExtensions.averageUntil(numberItem, now.plusHours(futureHours), TestCachedValuesPersistenceService.ID); assertNotNull(average); DecimalType dt = average.as(DecimalType.class); assertNotNull(dt); assertThat(dt.doubleValue(), is(closeTo((100.0 + 50.0) / futureHours, 0.01))); - average = PersistenceExtensions.averageTill(numberItem, now.plusHours(futureHours).minusHours(2), + average = PersistenceExtensions.averageUntil(numberItem, now.plusHours(futureHours).minusHours(2), TestCachedValuesPersistenceService.ID); assertNotNull(average); dt = average.as(DecimalType.class); assertNotNull(dt); assertThat(dt.doubleValue(), is(closeTo(50.0 / (futureHours - 2.0), 0.01))); - average = PersistenceExtensions.averageTill(numberItem, now.plusMinutes(30), + average = PersistenceExtensions.averageUntil(numberItem, now.plusMinutes(30), TestCachedValuesPersistenceService.ID); assertNotNull(average); dt = average.as(DecimalType.class); @@ -1378,8 +1378,8 @@ public void testSumSinceDecimalType() { } @Test - public void testSumTillDecimalType() { - State sum = PersistenceExtensions.sumTill(numberItem, + public void testSumUntilDecimalType() { + State sum = PersistenceExtensions.sumUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(sum); DecimalType dt = sum.as(DecimalType.class); @@ -1387,7 +1387,7 @@ public void testSumTillDecimalType() { assertEquals(IntStream.rangeClosed(FUTURE_START, FUTURE_INTERMEDIATE_VALUE_3).sum(), dt.doubleValue(), 0.001); // default persistence service - sum = PersistenceExtensions.sumTill(numberItem, + sum = PersistenceExtensions.sumUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); assertNull(sum); } @@ -1455,8 +1455,8 @@ public void testSumSinceQuantityType() { } @Test - public void testSumTillQuantityType() { - State sum = PersistenceExtensions.sumTill(quantityItem, + public void testSumUntilQuantityType() { + State sum = PersistenceExtensions.sumUntil(quantityItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(sum); QuantityType qt = sum.as(QuantityType.class); @@ -1564,8 +1564,8 @@ public void testDeltaSince() { } @Test - public void testDeltaTill() { - State delta = PersistenceExtensions.deltaTill(numberItem, + public void testDeltaUntil() { + State delta = PersistenceExtensions.deltaUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(delta); DecimalType dt = delta.as(DecimalType.class); @@ -1574,7 +1574,7 @@ public void testDeltaTill() { assertNotNull(dtState); assertEquals(FUTURE_INTERMEDIATE_VALUE_3 - dtState.doubleValue(), dt.doubleValue(), 0.001); - delta = PersistenceExtensions.deltaTill(quantityItem, + delta = PersistenceExtensions.deltaUntil(quantityItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(delta); QuantityType qt = delta.as(QuantityType.class); @@ -1585,7 +1585,7 @@ public void testDeltaTill() { assertEquals(SIUnits.CELSIUS, qt.getUnit()); // default persistence service - delta = PersistenceExtensions.deltaTill(numberItem, + delta = PersistenceExtensions.deltaUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); assertNull(delta); } @@ -1681,15 +1681,15 @@ public void testEvolutionRateSince() { } @Test - public void testEvolutionRateTill() { - DecimalType rate = PersistenceExtensions.evolutionRateTill(numberItem, + public void testEvolutionRateUntil() { + DecimalType rate = PersistenceExtensions.evolutionRateUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(rate); // ((then - now) / now) * 100 assertThat(rate.doubleValue(), is(closeTo(100.0 * (FUTURE_INTERMEDIATE_VALUE_3 - STATE.doubleValue()) / STATE.doubleValue(), 0.001))); - rate = PersistenceExtensions.evolutionRateTill(quantityItem, + rate = PersistenceExtensions.evolutionRateUntil(quantityItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertNotNull(rate); // ((then - now) / now) * 100 @@ -1697,7 +1697,7 @@ public void testEvolutionRateTill() { is(closeTo(100.0 * (FUTURE_INTERMEDIATE_VALUE_3 - STATE.doubleValue()) / STATE.doubleValue(), 0.001))); // default persistence service - rate = PersistenceExtensions.evolutionRateTill(numberItem, + rate = PersistenceExtensions.evolutionRateUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); assertNull(rate); } @@ -1938,13 +1938,13 @@ public void testChangedSince() { } @Test - public void testChangedTill() { - Boolean changed = PersistenceExtensions.changedTill(numberItem, + public void testChangedUntil() { + Boolean changed = PersistenceExtensions.changedUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertEquals(changed, true); // default persistence service - changed = PersistenceExtensions.changedTill(numberItem, + changed = PersistenceExtensions.changedUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); assertNull(changed); } @@ -1995,13 +1995,13 @@ public void testUpdatedSince() { } @Test - public void testUpdatedTill() { - Boolean updated = PersistenceExtensions.updatedTill(numberItem, + public void testUpdatedUntil() { + Boolean updated = PersistenceExtensions.updatedUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertEquals(updated, true); // default persistence service - updated = PersistenceExtensions.updatedTill(numberItem, + updated = PersistenceExtensions.updatedUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); assertNull(updated); } @@ -2063,21 +2063,21 @@ public void testCountSince() { } @Test - public void testCountTill() { - Long counts = PersistenceExtensions.countTill(numberItem, + public void testCountUntil() { + Long counts = PersistenceExtensions.countUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_NOVALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertEquals(0, counts); - counts = PersistenceExtensions.countTill(numberItem, + counts = PersistenceExtensions.countUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertEquals(FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START + 1, counts); - counts = PersistenceExtensions.countTill(numberItem, + counts = PersistenceExtensions.countUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertEquals(FUTURE_INTERMEDIATE_VALUE_4 - FUTURE_START + 1, counts); // default persistence service - counts = PersistenceExtensions.countTill(numberItem, + counts = PersistenceExtensions.countUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); assertNull(counts); } @@ -2134,21 +2134,21 @@ public void testCountStateChangesSince() { } @Test - public void testCountStateChangesTill() { - Long counts = PersistenceExtensions.countStateChangesTill(numberItem, + public void testCountStateChangesUntil() { + Long counts = PersistenceExtensions.countStateChangesUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_NOVALUE_1, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertEquals(0, counts); - counts = PersistenceExtensions.countStateChangesTill(numberItem, + counts = PersistenceExtensions.countStateChangesUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertEquals(FUTURE_INTERMEDIATE_VALUE_3 - FUTURE_START, counts); - counts = PersistenceExtensions.countStateChangesTill(numberItem, + counts = PersistenceExtensions.countStateChangesUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_4, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()), SERVICE_ID); assertEquals(FUTURE_INTERMEDIATE_VALUE_4 - FUTURE_START, counts); // default persistence service - counts = PersistenceExtensions.countStateChangesTill(numberItem, + counts = PersistenceExtensions.countStateChangesUntil(numberItem, ZonedDateTime.of(FUTURE_INTERMEDIATE_VALUE_3, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault())); assertNull(counts); } @@ -2230,43 +2230,43 @@ public void testRemoveAllStatesSince() { } @Test - public void testRemoveAllStatesTill() { + public void testRemoveAllStatesUntil() { ZonedDateTime now = ZonedDateTime.now(); int historicHours = 27; int futureHours = 27; createTestCachedValuesPersistenceService(now, historicHours, futureHours); - assertNotNull(PersistenceExtensions.getAllStatesTill(numberItem, now.plusHours(futureHours), + assertNotNull(PersistenceExtensions.getAllStatesUntil(numberItem, now.plusHours(futureHours), TestCachedValuesPersistenceService.ID)); - assertThat(PersistenceExtensions.countTill(numberItem, now.plusHours(futureHours), + assertThat(PersistenceExtensions.countUntil(numberItem, now.plusHours(futureHours), TestCachedValuesPersistenceService.ID), is(5L)); HistoricItem historicItem = PersistenceExtensions.nextState(numberItem, TestCachedValuesPersistenceService.ID); assertNotNull(historicItem); assertThat(historicItem.getState(), is(new DecimalType(0))); - PersistenceExtensions.removeAllStatesTill(numberItem, now.plusHours(1), TestCachedValuesPersistenceService.ID); - assertNotNull(PersistenceExtensions.getAllStatesTill(numberItem, now.plusHours(futureHours), + PersistenceExtensions.removeAllStatesUntil(numberItem, now.plusHours(1), TestCachedValuesPersistenceService.ID); + assertNotNull(PersistenceExtensions.getAllStatesUntil(numberItem, now.plusHours(futureHours), TestCachedValuesPersistenceService.ID)); - assertThat(PersistenceExtensions.countTill(numberItem, now.plusHours(futureHours), + assertThat(PersistenceExtensions.countUntil(numberItem, now.plusHours(futureHours), TestCachedValuesPersistenceService.ID), is(4L)); historicItem = PersistenceExtensions.nextState(numberItem, TestCachedValuesPersistenceService.ID); assertNotNull(historicItem); assertThat(historicItem.getState(), is(new DecimalType(50))); - PersistenceExtensions.removeAllStatesTill(numberItem, now.plusHours(2), TestCachedValuesPersistenceService.ID); - assertNotNull(PersistenceExtensions.getAllStatesTill(numberItem, now.plusHours(futureHours), + PersistenceExtensions.removeAllStatesUntil(numberItem, now.plusHours(2), TestCachedValuesPersistenceService.ID); + assertNotNull(PersistenceExtensions.getAllStatesUntil(numberItem, now.plusHours(futureHours), TestCachedValuesPersistenceService.ID)); - assertThat(PersistenceExtensions.countTill(numberItem, now.plusHours(futureHours), + assertThat(PersistenceExtensions.countUntil(numberItem, now.plusHours(futureHours), TestCachedValuesPersistenceService.ID), is(3L)); historicItem = PersistenceExtensions.nextState(numberItem, TestCachedValuesPersistenceService.ID); assertNotNull(historicItem); assertThat(historicItem.getState(), is(new DecimalType(0))); - PersistenceExtensions.removeAllStatesTill(numberItem, now.plusHours(futureHours + 1), + PersistenceExtensions.removeAllStatesUntil(numberItem, now.plusHours(futureHours + 1), TestCachedValuesPersistenceService.ID); - assertNotNull(PersistenceExtensions.getAllStatesTill(numberItem, now.plusHours(futureHours), + assertNotNull(PersistenceExtensions.getAllStatesUntil(numberItem, now.plusHours(futureHours), TestCachedValuesPersistenceService.ID)); - assertThat(PersistenceExtensions.countTill(numberItem, now.plusHours(futureHours), + assertThat(PersistenceExtensions.countUntil(numberItem, now.plusHours(futureHours), TestCachedValuesPersistenceService.ID), is(0L)); historicItem = PersistenceExtensions.nextState(numberItem, TestCachedValuesPersistenceService.ID); assertNull(historicItem); From 4435498a6e9f5aef1de63dcfc14bba870f47e079 Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Mon, 22 Jan 2024 13:25:53 +0100 Subject: [PATCH 09/13] change javadoc till into until Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 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 ef5ef45c29c..129808c8e14 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 @@ -663,12 +663,12 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Checks if the state of a given item will be updated till a certain point in time. + * Checks if the state of a given item will be updated until a certain point in time. * The default persistence service is used. * * @param item the item to check for state updates * @param timestamp the point in time to end the check - * @return true if item state is updated, false if either item is not updated till + * @return true if item state is updated, false if either item is not updated until * timestamp, null if the default persistence does not refer to a * {@link QueryablePersistenceService}, or null if the default persistence service is not * available @@ -709,7 +709,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Checks if the state of a given item will be updated till a certain point in time. + * Checks if the state of a given item will be updated until a certain point in time. * The {@link PersistenceService} identified by the serviceId is used. * * @param item the item to check for state changes @@ -770,12 +770,12 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the historic item with the maximum value of the state of a given item till + * Gets the historic item with the maximum value of the state of a given item until * a certain point in time. The default persistence service is used. * * @param item the item to get the maximum state value for * @param timestamp the point in time to end the check - * @return a historic item with the maximum state value till the given point in time, or a {@link HistoricItem} + * @return a historic item with the maximum state value until the given point in time, or a {@link HistoricItem} * constructed from the item if the default persistence service does not refer to a * {@link QueryablePersistenceService} */ @@ -815,13 +815,13 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the historic item with the maximum value of the state of a given item till + * Gets the historic item with the maximum value of the state of a given item until * a certain point in time. The {@link PersistenceService} identified by the serviceId is used. * * @param item the item to get the maximum state value for * @param timestamp the point in time to end the check * @param serviceId the name of the {@link PersistenceService} to use - * @return a {@link HistoricItem} with the maximum state value till the given point in time, or a + * @return a {@link HistoricItem} with the maximum state value until the given point in time, or a * {@link HistoricItem} constructed from the item's state if item's state is the * maximum value or if the given serviceId does not refer to an available * {@link QueryablePersistenceService} @@ -891,12 +891,12 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the historic item with the minimum value of the state of a given item till + * Gets the historic item with the minimum value of the state of a given item until * a certain point in time. The default persistence service is used. * * @param item the item to get the minimum state value for * @param timestamp the point in time to which to search for the minimum state value - * @return the historic item with the minimum state value till the given point in time or a {@link HistoricItem} + * @return the historic item with the minimum state value until the given point in time or a {@link HistoricItem} * constructed from the item's state if item's state is the minimum value or if * the default persistence service does not refer to an available {@link QueryablePersistenceService} */ @@ -935,13 +935,13 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the historic item with the minimum value of the state of a given item till + * Gets the historic item with the minimum value of the state of a given item until * a certain point in time. The {@link PersistenceService} identified by the serviceId is used. * * @param item the item to get the minimum state value for * @param timestamp the point in time to which to search for the minimum state value * @param serviceId the name of the {@link PersistenceService} to use - * @return the historic item with the minimum state value till the given point in time, or a {@link HistoricItem} + * @return the historic item with the minimum state value until the given point in time, or a {@link HistoricItem} * constructed from the item's state if item's state is the minimum value or if * the given serviceId does not refer to an available {@link QueryablePersistenceService}. */ @@ -1010,7 +1010,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the variance of the state of the given {@link Item} till a certain point in time. + * 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 @@ -1054,7 +1054,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the variance of the state of the given {@link Item} till a certain point in time. + * 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 @@ -1147,7 +1147,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the standard deviation of the state of the given {@link Item} till a certain point in time. + * 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 @@ -1200,7 +1200,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the standard deviation of the state of the given {@link Item} till a certain point in time. + * 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 @@ -1279,7 +1279,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the average value of the state of a given {@link Item} till a certain point in time. + * 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 @@ -1324,7 +1324,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the average value of the state of a given {@link Item} till a certain point in time. + * 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 @@ -1448,7 +1448,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the sum of the state of a given item till a certain point in time. + * Gets the sum of the state of a given item until a certain point in time. * The default persistence service is used. * * @param item the item for which we will sum its persisted state values to timestamp @@ -1493,7 +1493,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the sum of the state of a given item till a certain point in time. + * Gets the sum of the state of a given item until a certain point in time. * The {@link PersistenceService} identified by the serviceId is used. * * @param item the item for which we will sum its persisted state values to timestamp @@ -1571,7 +1571,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the difference value of the state of a given item till a certain point in time. + * Gets the difference value of the state of a given item until a certain point in time. * The default persistence service is used. * * @param item the item to get the average state value for @@ -1617,7 +1617,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the difference value of the state of a given item till a certain point in time. + * Gets the difference value of the state of a given item until a certain point in time. * The {@link PersistenceService} identified by the serviceId is used. * * @param item the item to get the delta for @@ -1694,7 +1694,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the evolution rate of the state of a given {@link Item} till a certain point in time. + * Gets the evolution rate of the state of a given {@link Item} until a certain point in time. * The default {@link PersistenceService} is used. * * @param item the item to get the evolution rate value for @@ -1745,7 +1745,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the evolution rate of the state of a given {@link Item} till a certain point in time. + * Gets the evolution rate 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 evolution rate value for @@ -2053,7 +2053,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Retrieves the future items for a given item till a certain point in time. + * Retrieves the future items for a given item until a certain point in time. * The default persistence service is used. * * @param item the item for which to retrieve the future item @@ -2099,7 +2099,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Retrieves the future items for a given item till a certain point in time + * Retrieves the future items for a given item until a certain point in time * through a {@link PersistenceService} identified by the serviceId. * * @param item the item for which to retrieve the future item @@ -2183,7 +2183,7 @@ public static void removeAllStatesSince(Item item, ZonedDateTime timestamp) { } /** - * Removes from persistence the future items for a given item till a certain point in time. + * Removes from persistence the future items for a given item until a certain point in time. * The default persistence service is used. * This will only have effect if the p{@link PersistenceService} is a {@link ModifiablePersistenceService}. * @@ -2221,7 +2221,7 @@ public static void removeAllStatesSince(Item item, ZonedDateTime timestamp, Stri } /** - * Removes from persistence the future items for a given item till a certain point in time + * Removes from persistence the future items for a given item until a certain point in time * through a {@link PersistenceService} identified by the serviceId. * This will only have effect if the p{@link PersistenceService} is a {@link ModifiablePersistenceService}. * From 32fc5121327f1a5a29d4cd7e1932088db8c7a1c8 Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Tue, 23 Jan 2024 14:53:58 +0100 Subject: [PATCH 10/13] javadoc changes Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 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 129808c8e14..3b477289eaa 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 @@ -444,7 +444,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser /** * Returns the next state of a given item. * - * @param item the item to get the previous state value for + * @param item the item to get the next state value for * @param skipEqual if true, skips equal state values and searches the first state not equal the current state * @return the next state or null if no next state could be found, or if the default * persistence service is not configured or does not refer to a {@link QueryablePersistenceService} @@ -1439,9 +1439,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the item for which we will sum its persisted state values since timestamp * @param timestamp the point in time from which to start the summation - * @return the sum of the state values since timestamp, or {@link DecimalType#ZERO} if no historic - * states could be found or if the default persistence service does not refer to a - * {@link QueryablePersistenceService} + * @return the sum of the state values since timestamp, or null if timestamp is in the + * future or the default persistence service does not refer to a {@link QueryablePersistenceService} */ public @Nullable static State sumSince(Item item, ZonedDateTime timestamp) { return internalSumBetween(item, timestamp, null); @@ -1453,9 +1452,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the item for which we will sum its persisted state values to timestamp * @param timestamp the point in time to which to start the summation - * @return the sum of the state values to timestamp, or {@link DecimalType#ZERO} if no historic - * states could be found or if the default persistence service does not refer to a - * {@link QueryablePersistenceService} + * @return the sum of the state values until timestamp, or null if timestamp is in the + * past or the default persistence service does not refer to a {@link QueryablePersistenceService} */ public @Nullable static State sumUntil(Item item, ZonedDateTime timestamp) { return internalSumBetween(item, null, timestamp); @@ -1469,8 +1467,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * end * @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 sum of the state values between the given points in time, or {@link DecimalType#ZERO} if no historic - * states could be found or if the default persistence service does not refer to a + * @return the sum of the state values between the given points in time, or null if begin is after + * end or if the default persistence service does not refer to a * {@link QueryablePersistenceService} */ public @Nullable static State sumBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { @@ -1484,9 +1482,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item for which we will sum its persisted state values since timestamp * @param timestamp the point in time from which to start the summation * @param serviceId the name of the {@link PersistenceService} to use - * @return the sum of the state values since the given point in time, or {@link DecimalType#ZERO} if no historic - * states could be found for the item or if serviceId does not refer to a - * {@link QueryablePersistenceService} + * @return the sum of the state values since timestamp, or null if timestamp is in the + * future or serviceId does not refer to a {@link QueryablePersistenceService} */ public @Nullable static State sumSince(Item item, ZonedDateTime timestamp, String serviceId) { return internalSumBetween(item, timestamp, null, serviceId); @@ -1499,9 +1496,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item for which we will sum its persisted state values to timestamp * @param timestamp the point in time to which to start the summation * @param serviceId the name of the {@link PersistenceService} to use - * @return the sum of the state values to the given point in time, or {@link DecimalType#ZERO} if no historic - * states could be found for the item or if serviceId does not refer to a - * {@link QueryablePersistenceService} + * @return the sum of the state values until timestamp, or null if timestamp is in the + * past or serviceId does not refer to a {@link QueryablePersistenceService} */ public @Nullable static State sumUntil(Item item, ZonedDateTime timestamp, String serviceId) { return internalSumBetween(item, null, timestamp, serviceId); @@ -1516,9 +1512,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @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 sum of the state values between the given points in time, or {@link DecimalType#ZERO} if no historic - * states could be found for the item or if serviceId does not refer to a - * {@link QueryablePersistenceService} + * @return the sum of the state values between the given points in time, or null if begin is after + * end or serviceId does not refer to a {@link QueryablePersistenceService} */ public @Nullable static State sumBetween(Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { return internalSumBetween(item, begin, end, serviceId); From 70711876e8b4305e44995be952b6c33b98f00ead Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Tue, 23 Jan 2024 17:36:00 +0100 Subject: [PATCH 11/13] javadoc updates Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 326 +++++++++--------- 1 file changed, 164 insertions(+), 162 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 3b477289eaa..21df4ee700e 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 @@ -259,8 +259,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param timestamp the point in time for which the persisted item should be retrieved * @param serviceId the name of the {@link PersistenceService} to use * @return the persisted item at the given point in time, or null if no persisted item could be found - * or - * if the provided serviceId does not refer to an available + * or if the provided serviceId does not refer to an available * {@link QueryablePersistenceService} */ public static @Nullable HistoricItem persistedState(Item item, ZonedDateTime timestamp, String serviceId) { @@ -301,8 +300,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the item for which the last historic update time is to be returned * @return point in time of the last historic update to item, or null if there are no - * historic - * persisted updates or the default persistence service is not available or a + * historic persisted updates or the default persistence service is not available or not a * {@link QueryablePersistenceService} */ public static @Nullable ZonedDateTime lastUpdate(Item item) { @@ -315,8 +313,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item for which the last historic update time is to be returned * @param serviceId the name of the {@link PersistenceService} to use * @return point in time of the last historic update to item, or null if there are no - * historic - * persisted updates or if persistence service given by serviceId does not refer to an + * historic persisted updates or if persistence service given by serviceId does not refer to an * available {@link QueryablePersistenceService} */ public static @Nullable ZonedDateTime lastUpdate(Item item, String serviceId) { @@ -328,8 +325,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the item for which the first future update time is to be returned * @return point in time of the first future update to item, or null if there are no - * future - * persisted updates or the default persistence service is not available or a + * future persisted updates or the default persistence service is not available or not a * {@link QueryablePersistenceService} */ public static @Nullable ZonedDateTime nextUpdate(Item item) { @@ -342,8 +338,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item for which the first future update time is to be returned * @param serviceId the name of the {@link PersistenceService} to use * @return point in time of the first future update to item, or null if there are no - * future - * persisted updates or if persistence service given by serviceId does not refer to an + * future persisted updates or if persistence service given by serviceId does not refer to an * available {@link QueryablePersistenceService} */ public static @Nullable ZonedDateTime nextUpdate(Item item, String serviceId) { @@ -534,8 +529,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item to check for state changes * @param timestamp the point in time to start the check * @return true if item state has changed, false if it has not changed, null - * if the default persistence service is not available or does not refer to a - * {@link QueryablePersistenceService} + * if timestamp is in the future, if the default persistence service is not available or does + * not refer to a {@link QueryablePersistenceService} */ public static @Nullable Boolean changedSince(Item item, ZonedDateTime timestamp) { return internalChangedBetween(item, timestamp, null); @@ -548,8 +543,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item to check for state changes * @param timestamp the point in time to end the check * @return true if item state will change, false if it will not change, null - * if the default persistence service is not available or does not refer to a - * {@link QueryablePersistenceService} + * if timestamp> is in the past, if the default persistence service is not available or does + * not refer to a {@link QueryablePersistenceService} */ public static @Nullable Boolean changedUntil(Item item, ZonedDateTime timestamp) { return internalChangedBetween(item, null, timestamp); @@ -560,10 +555,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * The default persistence service is used. * * @param item the item to check for state changes - * @return true if item state changes, false if either item does not change in - * the given interval, null if the default persistence does not refer to a - * {@link QueryablePersistenceService}, or null if the default persistence service is not - * available + * @return true if item state changes, false if the item does not change in + * the given interval, null if begin is after end, if the default + * persistence does not refer to a {@link QueryablePersistenceService}, or null if the default + * persistence service is not available */ public static @Nullable Boolean changedBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { return internalChangedBetween(item, begin, end); @@ -577,8 +572,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param timestamp the point in time to start the check * @param serviceId the name of the {@link PersistenceService} to use * @return true if item state has changed, or false if it has not changed, - * null if the provided serviceId does not refer to an available - * {@link QueryablePersistenceService} + * null if timestamp is in the future, if the provided serviceId does + * not refer to an available {@link QueryablePersistenceService} */ public static @Nullable Boolean changedSince(Item item, ZonedDateTime timestamp, String serviceId) { return internalChangedBetween(item, timestamp, null, serviceId); @@ -592,8 +587,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param timestamp the point in time to end the check * @param serviceId the name of the {@link PersistenceService} to use * @return true if item state will change, or false if it will not change, - * null if the provided serviceId does not refer to an available - * {@link QueryablePersistenceService} + * null if timestamp is in the past, if the provided serviceId does + * not refer to an available {@link QueryablePersistenceService} */ public static @Nullable Boolean changedUntil(Item item, ZonedDateTime timestamp, String serviceId) { return internalChangedBetween(item, null, timestamp, serviceId); @@ -607,9 +602,9 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param begin the point in time to start the check * @param end the point in time to stop the check * @param serviceId the name of the {@link PersistenceService} to use - * @return true if item state changed or false if either the item does not change - * in the given interval, null if the given serviceId does not refer to a - * {@link QueryablePersistenceService} + * @return true if item state changed or false if the item does not change + * in the given interval, null if begin is after end, if the given + * serviceId does not refer to a {@link QueryablePersistenceService} */ public static @Nullable Boolean changedBetween(Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { @@ -653,10 +648,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the item to check for state updates * @param timestamp the point in time to start the check - * @return true if item state was updated, false if either item has not been updated since - * timestamp, null if the default persistence does not refer to a - * {@link QueryablePersistenceService}, or null if the default persistence service is not - * available + * @return true if item state was updated, false if the item has not been updated since + * timestamp, null if timestamp is in the future, if the default + * persistence does not refer to a {@link QueryablePersistenceService}, or null if the default + * persistence service is not available */ public static @Nullable Boolean updatedSince(Item item, ZonedDateTime timestamp) { return internalUpdatedBetween(item, timestamp, null); @@ -668,10 +663,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the item to check for state updates * @param timestamp the point in time to end the check - * @return true if item state is updated, false if either item is not updated until - * timestamp, null if the default persistence does not refer to a - * {@link QueryablePersistenceService}, or null if the default persistence service is not - * available + * @return true if item state is updated, false if the item is not updated until + * timestamp, null if timestamp is in the past, if the default + * persistence does not refer to a {@link QueryablePersistenceService}, or null if the default + * persistence service is not available */ public static @Nullable Boolean updatedUntil(Item item, ZonedDateTime timestamp) { return internalUpdatedBetween(item, null, timestamp); @@ -684,10 +679,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item to check for state updates * @param begin the point in time to start the check * @param end the point in time to stop the check - * @return true if item state was updated, false if either item has not been updated in - * the given interval, null if the default persistence does not refer to a - * {@link QueryablePersistenceService}, or null if the default persistence service is not - * available + * @return true if item state was updated, false if the item has not been updated in + * the given interval, null if begin is after end, if the default + * persistence does not refer to a {@link QueryablePersistenceService}, or null if the default + * persistence service is not available */ public static @Nullable Boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { return internalUpdatedBetween(item, begin, end); @@ -700,9 +695,9 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item to check for state changes * @param timestamp the point in time to start the check * @param serviceId the name of the {@link PersistenceService} to use - * @return true if item state was updated or false if either the item has not been updated - * since timestamp, null if the given serviceId does not refer to a - * {@link QueryablePersistenceService} + * @return true if item state was updated or false if the item has not been updated + * since timestamp, null if timestamp is in the future, if the given + * serviceId does not refer to a {@link QueryablePersistenceService} */ public static @Nullable Boolean updatedSince(Item item, ZonedDateTime timestamp, String serviceId) { return internalUpdatedBetween(item, timestamp, null, serviceId); @@ -715,9 +710,9 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item to check for state changes * @param timestamp the point in time to end the check * @param serviceId the name of the {@link PersistenceService} to use - * @return true if item state was updated or false if either the item is not updated - * since timestamp, null if the given serviceId does not refer to a - * {@link QueryablePersistenceService} + * @return true if item state was updated or false if the item is not updated + * since timestamp, null if timestamp is in the past, if the given + * serviceId does not refer to a {@link QueryablePersistenceService} */ public static @Nullable Boolean updatedUntil(Item item, ZonedDateTime timestamp, String serviceId) { return internalUpdatedBetween(item, null, timestamp, serviceId); @@ -731,9 +726,9 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param begin the point in time to start the check * @param end the point in time to stop the check * @param serviceId the name of the {@link PersistenceService} to use - * @return true if item state was updated or false if either the item is not updated - * in the given interval, null if the given serviceId does not refer to a - * {@link QueryablePersistenceService} + * @return true if item state was updated or false if the item is not updated + * in the given interval, null if begin is after end, if the given + * serviceId does not refer to a {@link QueryablePersistenceService} */ public static @Nullable Boolean updatedBetween(Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { @@ -761,9 +756,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the item to get the maximum state value for * @param timestamp the point in time to start the check - * @return a historic item with the maximum state value since the given point in time, or a {@link HistoricItem} - * constructed from the item if the default persistence service does not refer to a - * {@link QueryablePersistenceService} + * @return a historic item with the maximum state value since the given point in time, a + * {@link HistoricItem} constructed from the item's state if item's state is the + * maximum value, null if timestamp is in the future or if the default + * persistence service does not refer to a {@link QueryablePersistenceService} */ public static @Nullable HistoricItem maximumSince(Item item, ZonedDateTime timestamp) { return internalMaximumBetween(item, timestamp, null); @@ -775,9 +771,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the item to get the maximum state value for * @param timestamp the point in time to end the check - * @return a historic item with the maximum state value until the given point in time, or a {@link HistoricItem} - * constructed from the item if the default persistence service does not refer to a - * {@link QueryablePersistenceService} + * @return a historic item with the maximum state value until the given point in time, a + * {@link HistoricItem} constructed from the item's state if item's state is the + * maximum value, null if timestamp is in the past or if the default + * persistence service does not refer to a {@link QueryablePersistenceService} */ public static @Nullable HistoricItem maximumUntil(Item item, ZonedDateTime timestamp) { return internalMaximumBetween(item, null, timestamp); @@ -790,9 +787,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item to get the maximum state value for * @param begin the point in time to start the check * @param end the point in time to stop the check - * @return a {@link HistoricItem} with the maximum state value between two points in time, or null - * if no states found or if the default persistence service does not refer to an available - * {@link QueryablePersistenceService} + * @return a {@link HistoricItem} with the maximum state value between two points in time, a + * {@link HistoricItem} constructed from the item's state if no persisted states found, or + * null if begin is after end or if the default persistence service + * does not refer to an available{@link QueryablePersistenceService} */ public static @Nullable HistoricItem maximumBetween(final Item item, ZonedDateTime begin, ZonedDateTime end) { return internalMaximumBetween(item, begin, end); @@ -805,10 +803,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item to get the maximum state value for * @param timestamp the point in time to start the check * @param serviceId the name of the {@link PersistenceService} to use - * @return a {@link HistoricItem} with the maximum state value since the given point in time, or a + * @return a {@link HistoricItem} with the maximum state value since the given point in time, a * {@link HistoricItem} constructed from the item's state if item's state is the - * maximum value or if the given serviceId does not refer to an available - * {@link QueryablePersistenceService} + * maximum value, null if timestamp is in the future or if the given + * serviceId does not refer to an available {@link QueryablePersistenceService} */ public static @Nullable HistoricItem maximumSince(final Item item, ZonedDateTime timestamp, String serviceId) { return internalMaximumBetween(item, timestamp, null, serviceId); @@ -821,10 +819,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item to get the maximum state value for * @param timestamp the point in time to end the check * @param serviceId the name of the {@link PersistenceService} to use - * @return a {@link HistoricItem} with the maximum state value until the given point in time, or a + * @return a {@link HistoricItem} with the maximum state value until the given point in time, a * {@link HistoricItem} constructed from the item's state if item's state is the - * maximum value or if the given serviceId does not refer to an available - * {@link QueryablePersistenceService} + * maximum value, null if timestamp is in the past or if the given + * serviceId does not refer to an available {@link QueryablePersistenceService} */ public static @Nullable HistoricItem maximumUntil(final Item item, ZonedDateTime timestamp, String serviceId) { return internalMaximumBetween(item, null, timestamp, serviceId); @@ -838,9 +836,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param begin the point in time to start the check * @param end the point in time to stop the check * @param serviceId the name of the {@link PersistenceService} to use - * @return a {@link HistoricItem} with the maximum state value between two points in time, or - * null no states found or if the given serviceId does not refer to an - * available {@link QueryablePersistenceService} + * @return a {@link HistoricItem} with the maximum state value between two points in time, a + * {@link HistoricItem} constructed from the item's state if no persisted states found, or + * null if begin is after end or if the given serviceId + * does not refer to an available {@link QueryablePersistenceService} */ public static @Nullable HistoricItem maximumBetween(final Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { @@ -882,9 +881,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the item to get the minimum state value for * @param timestamp the point in time from which to search for the minimum state value - * @return the historic item with the minimum state value since the given point in time or a {@link HistoricItem} - * constructed from the item's state if item's state is the minimum value or if - * the default persistence service does not refer to an available {@link QueryablePersistenceService} + * @return a historic item with the minimum state value since the given point in time, a + * {@link HistoricItem} constructed from the item's state if item's state is the + * minimum value, null if timestamp is in the future or if the default + * persistence service does not refer to a {@link QueryablePersistenceService} */ public static @Nullable HistoricItem minimumSince(Item item, ZonedDateTime timestamp) { return internalMinimumBetween(item, timestamp, null); @@ -896,9 +896,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the item to get the minimum state value for * @param timestamp the point in time to which to search for the minimum state value - * @return the historic item with the minimum state value until the given point in time or a {@link HistoricItem} - * constructed from the item's state if item's state is the minimum value or if - * the default persistence service does not refer to an available {@link QueryablePersistenceService} + * @return a historic item with the minimum state value until the given point in time, a + * {@link HistoricItem} constructed from the item's state if item's state is the + * minimum value, null if timestamp is in the past or if the default + * persistence service does not refer to a {@link QueryablePersistenceService} */ public static @Nullable HistoricItem minimumUntil(Item item, ZonedDateTime timestamp) { return internalMinimumBetween(item, null, timestamp); @@ -911,9 +912,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item to get the minimum state value for * @param begin the beginning point in time * @param end the ending point in time to - * @return the historic item with the minimum state value between the given points in time, or null if - * not state was found or if - * the default persistence service does not refer to an available {@link QueryablePersistenceService} + * @return a {@link HistoricItem} with the minimum state value between two points in time, a + * {@link HistoricItem} constructed from the item's state if no persisted states found, or + * null if begin is after end or if the default persistence service + * does not refer to an available{@link QueryablePersistenceService} */ public static @Nullable HistoricItem minimumBetween(final Item item, ZonedDateTime begin, ZonedDateTime end) { return internalMinimumBetween(item, begin, end); @@ -926,9 +928,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item to get the minimum state value for * @param timestamp the point in time from which to search for the minimum state value * @param serviceId the name of the {@link PersistenceService} to use - * @return the historic item with the minimum state value since the given point in time, or a {@link HistoricItem} - * constructed from the item's state if item's state is the minimum value or if - * the given serviceId does not refer to an available {@link QueryablePersistenceService}. + * @return a {@link HistoricItem} with the minimum state value since the given point in time, a + * {@link HistoricItem} constructed from the item's state if item's state is the + * minimum value, null if timestamp is in the future or if the given + * serviceId does not refer to an available {@link QueryablePersistenceService} */ public static @Nullable HistoricItem minimumSince(final Item item, ZonedDateTime timestamp, String serviceId) { return internalMinimumBetween(item, timestamp, null, serviceId); @@ -941,9 +944,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the item to get the minimum state value for * @param timestamp the point in time to which to search for the minimum state value * @param serviceId the name of the {@link PersistenceService} to use - * @return the historic item with the minimum state value until the given point in time, or a {@link HistoricItem} - * constructed from the item's state if item's state is the minimum value or if - * the given serviceId does not refer to an available {@link QueryablePersistenceService}. + * @return a {@link HistoricItem} with the minimum state value until the given point in time, a + * {@link HistoricItem} constructed from the item's state if item's state is the + * minimum value, null if timestamp is in the past or if the given + * serviceId does not refer to an available {@link QueryablePersistenceService} */ public static @Nullable HistoricItem minimumUntil(final Item item, ZonedDateTime timestamp, String serviceId) { return internalMinimumBetween(item, null, timestamp, serviceId); @@ -957,9 +961,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param begin the beginning point in time * @param end the end point in time to * @param serviceId the name of the {@link PersistenceService} to use - * @return the historic item with the minimum state value between the given points in time, or null if - * not state was found or if the given serviceId does not refer to an available - * {@link QueryablePersistenceService} + * @return a {@link HistoricItem} with the minimum state value between two points in time, a + * {@link HistoricItem} constructed from the item's state if no persisted states found, or + * null if begin is after end or if the given serviceId + * does not refer to an available {@link QueryablePersistenceService} */ public static @Nullable HistoricItem minimumBetween(final Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { @@ -1001,9 +1006,9 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the {@link Item} to get the variance for * @param timestamp the point in time from which to compute the variance - * @return the variance between then and now, or null 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 + * @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) { return internalVarianceBetween(item, timestamp, null); @@ -1015,9 +1020,9 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the {@link Item} to get the variance for * @param timestamp the point in time to which to compute the variance - * @return the variance between now and then, or null 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 + * @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) { return internalVarianceBetween(item, null, timestamp); @@ -1030,9 +1035,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @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 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 + * @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); @@ -1045,9 +1051,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the {@link Item} to get the variance for * @param timestamp the point in time from which to compute the variance * @param serviceId the name of the {@link PersistenceService} to use - * @return the variance between then and now, or null 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 + * @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, String serviceId) { return internalVarianceBetween(item, timestamp, null, serviceId); @@ -1060,9 +1067,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the {@link Item} to get the variance for * @param timestamp the point in time to which to compute the variance * @param serviceId the name of the {@link PersistenceService} to use - * @return the variance between now and then, or null 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 + * @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, String serviceId) { return internalVarianceBetween(item, null, timestamp, serviceId); @@ -1076,9 +1084,11 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @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 the given points in time, or null 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 + * @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, String serviceId) { return internalVarianceBetween(item, begin, end, serviceId); @@ -1138,9 +1148,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the {@link Item} to get the standard deviation for * @param timestamp the point in time from which to compute the standard deviation - * @return the standard deviation between then and now, or null 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 + * @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) { return internalDeviationBetween(item, timestamp, null); @@ -1155,9 +1166,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the {@link Item} to get the standard deviation for * @param timestamp the point in time to which to compute the standard deviation - * @return the standard deviation between now and then, or null 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 + * @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) { return internalDeviationBetween(item, timestamp, null); @@ -1173,9 +1185,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @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 - * @return the standard deviation between now and then, or null 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 in the given interval + * @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) { return internalDeviationBetween(item, begin, end); @@ -1191,9 +1204,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @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 serviceId the name of the {@link PersistenceService} to use - * @return the standard deviation between now and then, or null if the persistence service given by - * serviceId it is not available or is not a {@link QueryablePersistenceService}, or if there - * is no persisted state for the given item at the given timestamp + * @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, String serviceId) { return internalDeviationBetween(item, timestamp, null, serviceId); @@ -1209,9 +1223,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @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 serviceId the name of the {@link PersistenceService} to use - * @return the standard deviation between now and then, or null if the persistence service given by - * serviceId it is not available or is not a {@link QueryablePersistenceService}, or if there - * is no persisted state for the given item at the given timestamp + * @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, String serviceId) { return internalDeviationBetween(item, null, timestamp, serviceId); @@ -1228,9 +1243,11 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @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 standard deviation between now and then, or null if the persistence service given by - * serviceId it is not available or is not a {@link QueryablePersistenceService}, or if there - * is no persisted state for the given item in the given interval + * @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, String serviceId) { @@ -1284,8 +1301,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @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 - * @return the average value to timestamp or null if no - * previous states could be found or if the default persistence service does not refer to an available + * @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) { @@ -1299,8 +1316,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @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 - * @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 + * @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) { @@ -1330,8 +1347,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @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 serviceId the name of the {@link PersistenceService} to use - * @return the average value to timestamp, or null if no - * previous states could be found or if the persistence service given by serviceId does not + * @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. */ @@ -1347,8 +1364,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @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 average value since timestamp, or null if no - * previous states could be found or if the persistence service given by serviceId does not + * @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, String serviceId) { @@ -1382,13 +1399,6 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser HistoricItem lastItem = null; ZonedDateTime firstTimestamp = null; - // if (beginTime.equals(now)) { - // HistoricItem historicItem = internalPersistedState(item, now, serviceId); - // if (historicItem != null) { - // lastItem = new RetimedHistoricItem(historicItem, now); - // firstTimestamp = now; - // } - // } while (it.hasNext()) { HistoricItem thisItem = it.next(); if (lastItem != null) { @@ -1406,14 +1416,6 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } lastItem = thisItem; } - // if (endTime.equals(now) && lastItem != null && lastItem.getState() instanceof State state) { - // DecimalType dtState = state.as(DecimalType.class); - // if (dtState != null) { - // BigDecimal value = dtState.toBigDecimal(); - // BigDecimal weight = BigDecimal.valueOf(Duration.between(lastItem.getTimestamp(), now).toMillis()); - // sum = sum.add(value.multiply(weight)); - // } - // } if (firstTimestamp != null) { BigDecimal totalDuration = BigDecimal.valueOf(Duration.between(firstTimestamp, endTime).toMillis()); @@ -1554,7 +1556,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * Gets the difference value of the state of a given item since a certain point in time. * The default persistence service is used. * - * @param item the item to get the average state value for + * @param item the item to get the delta state value for * @param timestamp the point in time from which to compute the delta * @return the difference between now and then, or null if there is no default persistence * service available, the default persistence service is not a {@link QueryablePersistenceService}, or if @@ -1569,7 +1571,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * Gets the difference value of the state of a given item until a certain point in time. * The default persistence service is used. * - * @param item the item to get the average state value for + * @param item the item to get the delta state value for * @param timestamp the point in time to which to compute the delta * @return the difference between then and now, or null if there is no default persistence * service available, the default persistence service is not a {@link QueryablePersistenceService}, or if @@ -1581,7 +1583,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the difference value of the state of a given item between two certain point in time. + * Gets the difference value of the state of a given item between two points in time. * The default persistence service is used. * * @param item the item to get the delta for @@ -1628,7 +1630,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Gets the difference value of the state of a given item between two certain point in time. + * Gets the difference value of the state of a given item between two points in time. * The {@link PersistenceService} identified by the serviceId is used. * * @param item the item to get the delta for @@ -1796,7 +1798,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser valueStop = getItemValue(item); } - if (valueStart != null && valueStop != null) { + if (valueStart != null && valueStop != null && !valueStart.equals(DecimalType.ZERO)) { return new DecimalType(valueStop.toBigDecimal().subtract(valueStart.toBigDecimal()) .divide(valueStart.toBigDecimal(), MathContext.DECIMAL64).movePointRight(2)); } @@ -1809,8 +1811,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the {@link Item} to query * @param timestamp the beginning point in time - * @return the number of values persisted for this item, null - * if the default persistence service is not available or does not refer to a + * @return the number of values persisted for this item, null if timestamp is in the + * future, if the default persistence service is not available or does not refer to a * {@link QueryablePersistenceService} */ public static @Nullable Long countSince(Item item, ZonedDateTime timestamp) { @@ -1823,8 +1825,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * * @param item the {@link Item} to query * @param timestamp the ending point in time - * @return the number of values persisted for this item, null - * if the default persistence service is not available or does not refer to a + * @return the number of values persisted for this item, null if timestamp is in the + * past, if the default persistence service is not available or does not refer to a * {@link QueryablePersistenceService} */ public static @Nullable Long countUntil(Item item, ZonedDateTime timestamp) { @@ -1838,8 +1840,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the {@link Item} to query * @param begin the beginning point in time * @param end the end point in time - * @return the number of values persisted for this item, null - * if the default persistence service is not available or does not refer to a + * @return the number of values persisted for this item, null if begin is after + * end, if the default persistence service is not available or does not refer to a * {@link QueryablePersistenceService} */ public static @Nullable Long countBetween(Item item, ZonedDateTime begin, ZonedDateTime end) { @@ -1853,8 +1855,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the {@link Item} to query * @param begin the beginning point in time * @param serviceId the name of the {@link PersistenceService} to use - * @return the number of values persisted for this item, null - * if the persistence service is not available or does not refer to a + * @return the number of values persisted for this item, null if timestamp is in the + * future, if the persistence service is not available or does not refer to a * {@link QueryablePersistenceService} */ public static @Nullable Long countSince(Item item, ZonedDateTime begin, String serviceId) { @@ -1868,8 +1870,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param item the {@link Item} to query * @param timestamp the ending point in time * @param serviceId the name of the {@link PersistenceService} to use - * @return the number of values persisted for this item, null - * if the persistence service is not available or does not refer to a + * @return the number of values persisted for this item, null if timestamp is in the + * past, if the persistence service is not available or does not refer to a * {@link QueryablePersistenceService} */ public static @Nullable Long countUntil(Item item, ZonedDateTime timestamp, String serviceId) { @@ -1884,8 +1886,8 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser * @param begin the beginning point in time * @param end the end point in time * @param serviceId the name of the {@link PersistenceService} to use - * @return the number of values persisted for this item, null - * if the persistence service is not available or does not refer to a + * @return the number of values persisted for this item, null if begin is after + * end, if the persistence service is not available or does not refer to a * {@link QueryablePersistenceService} */ public static @Nullable Long countBetween(Item item, ZonedDateTime begin, ZonedDateTime end, String serviceId) { @@ -2062,7 +2064,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Retrieves the historic items for a given item between two certain points in time. + * Retrieves the historic items for a given item between two points in time. * The default persistence service is used. * * @param item the item for which to retrieve the historic item @@ -2110,7 +2112,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser } /** - * Retrieves the historic items for a given item beetween two certain points in time + * Retrieves the historic items for a given item between two points in time * through a {@link PersistenceService} identified by the serviceId. * * @param item the item for which to retrieve the historic item @@ -2190,7 +2192,7 @@ public static void removeAllStatesUntil(Item item, ZonedDateTime timestamp) { } /** - * Removes from persistence the historic items for a given item between two certain points in time. + * Removes from persistence the historic items for a given item between two points in time. * The default persistence service is used. * This will only have effect if the p{@link PersistenceService} is a {@link ModifiablePersistenceService}. * @@ -2229,7 +2231,7 @@ public static void removeAllStatesUntil(Item item, ZonedDateTime timestamp, Stri } /** - * Removes from persistence the historic items for a given item beetween two certain points in time + * Removes from persistence the historic items for a given item beetween two points in time * through a {@link PersistenceService} identified by the serviceId. * This will only have effect if the p{@link PersistenceService} is a {@link ModifiablePersistenceService}. * From 5d4af9efc5f26090e8c2fcd25e58439daa0395f0 Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Wed, 24 Jan 2024 08:58:30 +0100 Subject: [PATCH 12/13] keep but deprecate evolutionRate Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) 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 21df4ee700e..699daf81cc4 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 @@ -1674,6 +1674,27 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser return null; } + /** + * Gets the evolution rate of the state of a given {@link Item} since a certain point in time. + * The default {@link PersistenceService} is used. + * + * This method has been deprecated and {@link #evolutionRateSince(Item, ZonedDateTime)} should be used instead. + * + * @param item the item to get the evolution rate value for + * @param timestamp the point in time from which to compute the evolution rate + * @return the evolution rate in percent (positive and negative) between now and then, or null if + * there is no default persistence service available, the default persistence service is not a + * {@link QueryablePersistenceService}, or if there is no persisted state for the given item at + * the given timestamp, or if there is a state but it is zero (which would cause a + * divide-by-zero error) + */ + @Deprecated + public static @Nullable DecimalType evolutionRate(Item item, ZonedDateTime timestamp) { + LoggerFactory.getLogger(PersistenceExtensions.class).info( + "The evolutionRate method has been deprecated and will be removed in a future version, use evolutionRateSince instead."); + return internalEvolutionRateBetween(item, timestamp, null); + } + /** * Gets the evolution rate of the state of a given {@link Item} since a certain point in time. * The default {@link PersistenceService} is used. @@ -1723,6 +1744,30 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser return internalEvolutionRateBetween(item, begin, end); } + /** + * Gets the evolution rate of the state of a given {@link Item} since a certain point in time. + * The {@link PersistenceService} identified by the serviceId is used. + * + * This method has been deprecated and {@link #evolutionRateSince(Item, ZonedDateTime, String)} should be used + * instead. + * + * @param item the {@link Item} to get the evolution rate value for + * @param timestamp the point in time from which to compute the evolution rate + * @param serviceId the name of the {@link PersistenceService} to use + * @return the evolution rate in percent (positive and negative) between now and then, or null if + * the persistence service given by serviceId is not available or is not a + * {@link QueryablePersistenceService}, or if there is no persisted state for the given + * item at the given timestamp using the persistence service given by + * serviceId, or if there is a state but it is zero (which would cause a divide-by-zero + * error) + */ + @Deprecated + public static @Nullable DecimalType evolutionRate(Item item, ZonedDateTime timestamp, String serviceId) { + LoggerFactory.getLogger(PersistenceExtensions.class).info( + "The evolutionRate method has been deprecated and will be removed in a future version, use evolutionRateSince instead."); + return internalEvolutionRateBetween(item, timestamp, null, serviceId); + } + /** * Gets the evolution rate of the state of a given {@link Item} since a certain point in time. * The {@link PersistenceService} identified by the serviceId is used. From c2abf556f9fdb02bb20f5a74fe364bc93a4030e9 Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Mon, 29 Apr 2024 17:10:28 +0200 Subject: [PATCH 13/13] review adjustments Signed-off-by: Mark Herwege --- .../extensions/PersistenceExtensions.java | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 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 699daf81cc4..f29ffcf862b 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 @@ -147,7 +147,7 @@ private static void internalPersist(Item item, ZonedDateTime timestamp, State st private static void internalPersist(Item item, ZonedDateTime timestamp, State state, String serviceId) { PersistenceService service = getService(serviceId); - if (service != null && service instanceof ModifiablePersistenceService modifiableService) { + if (service instanceof ModifiablePersistenceService modifiableService) { modifiableService.store(item, timestamp, state, serviceId); return; } @@ -189,7 +189,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser PersistenceService service = getService(serviceId); TimeZoneProvider tzProvider = timeZoneProvider; ZoneId timeZone = tzProvider != null ? tzProvider.getTimeZone() : ZoneId.systemDefault(); - if (service != null && service instanceof ModifiablePersistenceService modifiableService) { + if (service instanceof ModifiablePersistenceService modifiableService) { timeSeries.getStates() .forEach(s -> modifiableService.store(item, s.timestamp().atZone(timeZone), s.state(), serviceId)); return; @@ -277,7 +277,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser return null; } PersistenceService service = getService(serviceId); - if (service != null && service instanceof QueryablePersistenceService qService) { + if (service instanceof QueryablePersistenceService qService) { FilterCriteria filter = new FilterCriteria(); filter.setEndDate(timestamp); filter.setItemName(item.getName()); @@ -286,12 +286,11 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser Iterable result = qService.query(filter); if (result.iterator().hasNext()) { return result.iterator().next(); - } else { - return null; } + } else { + LoggerFactory.getLogger(PersistenceExtensions.class) + .warn("There is no queryable persistence service registered with the id '{}'", serviceId); } - LoggerFactory.getLogger(PersistenceExtensions.class) - .warn("There is no queryable persistence service registered with the id '{}'", serviceId); return null; } @@ -352,7 +351,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser private static @Nullable ZonedDateTime internalAdjacentUpdate(Item item, boolean forward, String serviceId) { PersistenceService service = getService(serviceId); - if (service != null && service instanceof QueryablePersistenceService qService) { + if (service instanceof QueryablePersistenceService qService) { FilterCriteria filter = new FilterCriteria(); filter.setItemName(item.getName()); if (forward) { @@ -365,12 +364,11 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser Iterable result = qService.query(filter); if (result.iterator().hasNext()) { return result.iterator().next().getTimestamp(); - } else { - return null; } + } else { + LoggerFactory.getLogger(PersistenceExtensions.class) + .warn("There is no queryable persistence service registered with the id '{}'", serviceId); } - LoggerFactory.getLogger(PersistenceExtensions.class) - .warn("There is no queryable persistence service registered with the id '{}'", serviceId); return null; } @@ -484,7 +482,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser private static @Nullable HistoricItem internalAdjacentState(Item item, boolean skipEqual, boolean forward, String serviceId) { PersistenceService service = getService(serviceId); - if (service != null && service instanceof QueryablePersistenceService qService) { + if (service instanceof QueryablePersistenceService qService) { FilterCriteria filter = new FilterCriteria(); filter.setItemName(item.getName()); if (forward) { @@ -516,9 +514,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser items = null; } } + } else { + LoggerFactory.getLogger(PersistenceExtensions.class) + .warn("There is no queryable persistence service registered with the id '{}'", serviceId); } - LoggerFactory.getLogger(PersistenceExtensions.class) - .warn("There is no queryable persistence service registered with the id '{}'", serviceId); return null; } @@ -2182,7 +2181,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser private static @Nullable Iterable internalGetAllStatesBetween(Item item, @Nullable ZonedDateTime begin, @Nullable ZonedDateTime end, String serviceId) { PersistenceService service = getService(serviceId); - if (service != null && service instanceof QueryablePersistenceService qService) { + if (service instanceof QueryablePersistenceService qService) { FilterCriteria filter = new FilterCriteria(); ZonedDateTime now = ZonedDateTime.now(); if ((begin == null && end == null) || (begin != null && end == null && begin.isAfter(now)) @@ -2206,9 +2205,10 @@ private static void internalPersist(Item item, TimeSeries timeSeries, String ser filter.setOrdering(Ordering.ASCENDING); return qService.query(filter); + } else { + LoggerFactory.getLogger(PersistenceExtensions.class) + .warn("There is no queryable persistence service registered with the id '{}'", serviceId); } - LoggerFactory.getLogger(PersistenceExtensions.class) - .warn("There is no queryable persistence service registered with the id '{}'", serviceId); return null; } @@ -2300,7 +2300,7 @@ private static void internalRemoveAllStatesBetween(Item item, @Nullable ZonedDat private static void internalRemoveAllStatesBetween(Item item, @Nullable ZonedDateTime begin, @Nullable ZonedDateTime end, String serviceId) { PersistenceService service = getService(serviceId); - if (service != null && service instanceof ModifiablePersistenceService mService) { + if (service instanceof ModifiablePersistenceService mService) { FilterCriteria filter = new FilterCriteria(); ZonedDateTime now = ZonedDateTime.now(); if ((begin == null && end == null) || (begin != null && end == null && begin.isAfter(now)) @@ -2324,10 +2324,10 @@ private static void internalRemoveAllStatesBetween(Item item, @Nullable ZonedDat filter.setOrdering(Ordering.ASCENDING); mService.remove(filter); - return; + } else { + LoggerFactory.getLogger(PersistenceExtensions.class) + .warn("There is no queryable persistence service registered with the id '{}'", serviceId); } - LoggerFactory.getLogger(PersistenceExtensions.class) - .warn("There is no queryable persistence service registered with the id '{}'", serviceId); return; }