Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*/
package org.openhab.core.persistence;

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Iterator;
import java.util.Set;
Expand All @@ -22,7 +24,6 @@
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.persistence.FilterCriteria.Ordering;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;

/**
* A queryable persistence service which can be used to store and retrieve
Expand Down Expand Up @@ -65,6 +66,11 @@ default Iterable<HistoricItem> query(FilterCriteria filter, @Nullable String ali
FilterCriteria aliasFilter = new FilterCriteria(filter).setItemName(alias);
return StreamSupport.stream(query(aliasFilter).spliterator(), false).map(hi -> new HistoricItem() {

@Override
public Instant getInstant() {
return hi.getInstant();
}

@Override
public ZonedDateTime getTimestamp() {
return hi.getTimestamp();
Expand Down Expand Up @@ -111,28 +117,32 @@ public String getName() {
* @return a {@link PersistedItem} or null if the item has not been persisted
*/
default @Nullable PersistedItem persistedItem(String itemName, @Nullable String alias) {
State currentState = UnDefType.NULL;
ZonedDateTime lastUpdate = null;
State currentState;
Instant lastUpdate;

FilterCriteria filter = new FilterCriteria().setItemName(itemName).setEndDate(ZonedDateTime.now())
.setOrdering(Ordering.DESCENDING).setPageSize(1).setPageNumber(0);
Iterator<HistoricItem> it = query(filter, alias).iterator();
if (it.hasNext()) {
HistoricItem historicItem = it.next();
currentState = historicItem.getState();
lastUpdate = historicItem.getTimestamp();
lastUpdate = historicItem.getInstant();
} else {
return null;
}

final State state = currentState;
final ZonedDateTime lastStateUpdate = lastUpdate;
final Instant lastStateUpdate = lastUpdate;

return new PersistedItem() {
@Override
public Instant getInstant() {
return lastStateUpdate;
}

@Override
public ZonedDateTime getTimestamp() {
return lastStateUpdate;
return lastStateUpdate.atZone(ZoneId.systemDefault());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.math.BigDecimal;
import java.math.MathContext;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
Expand Down Expand Up @@ -71,6 +72,7 @@
* @author Mark Herwege - add median methods
* @author Mark Herwege - use item lastChange and lastUpdate methods if not in peristence
* @author Mark Herwege - add Riemann sum methods
* @author Jörg Sautter - use Instant instead of ZonedDateTime in Riemann sum methods
*/
@Component(immediate = true)
@NonNullByDefault
Expand Down Expand Up @@ -1926,7 +1928,7 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable

private static @Nullable BigDecimal average(ZonedDateTime begin, ZonedDateTime end, Iterator<HistoricItem> it,
@Nullable Unit<?> unit, @Nullable RiemannType type) {
BigDecimal sum = riemannSum(begin, end, it, unit, type);
BigDecimal sum = riemannSum(begin.toInstant(), end.toInstant(), it, unit, type);
BigDecimal totalDuration = BigDecimal.valueOf(Duration.between(begin, end).toMillis());
if (totalDuration.signum() == 0) {
return null;
Expand Down Expand Up @@ -2195,35 +2197,39 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable
Item baseItem = item instanceof GroupItem groupItem ? groupItem.getBaseItem() : item;
Unit<?> unit = (baseItem instanceof NumberItem numberItem)
&& (numberItem.getUnit() instanceof Unit<?> numberItemUnit) ? numberItemUnit.getSystemUnit() : null;
BigDecimal sum = riemannSum(beginTime, endTime, it, unit, type).scaleByPowerOfTen(-3);
BigDecimal sum = riemannSum(beginTime.toInstant(), endTime.toInstant(), it, unit, type).scaleByPowerOfTen(-3);
if (unit != null) {
return new QuantityType<>(sum, unit.multiply(Units.SECOND));
}
return new DecimalType(sum);
}

private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Iterator<HistoricItem> it,
@Nullable Unit<?> unit, @Nullable RiemannType type) {
private static BigDecimal riemannSum(Instant begin, Instant end, Iterator<HistoricItem> it, @Nullable Unit<?> unit,
@Nullable RiemannType type) {
RiemannType riemannType = type == null ? RiemannType.LEFT : type;

BigDecimal sum = BigDecimal.ZERO;
HistoricItem prevItem = null;
HistoricItem nextItem = null;
HistoricItem nextItem;
DecimalType prevState = null;
DecimalType nextState = null;
DecimalType nextState;
Instant prevInstant = null;
Instant nextInstant;
Duration prevDuration = Duration.ZERO;
Duration nextDuration = Duration.ZERO;
Duration nextDuration;

boolean midpointStartBucket = true; // The start and end buckets for the midpoint calculation should be
// considered for the full length, this flag is used to find the start
// bucket
if ((riemannType == RiemannType.MIDPOINT) && it.hasNext()) {
prevItem = it.next();
prevInstant = prevItem.getInstant();
prevState = getPersistedValue(prevItem, unit);
}

while (it.hasNext()) {
nextItem = it.next();
nextInstant = nextItem.getInstant();
BigDecimal weight = BigDecimal.ZERO;
BigDecimal value = BigDecimal.ZERO;
switch (riemannType) {
Expand All @@ -2232,24 +2238,24 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite
prevState = getPersistedValue(prevItem, unit);
if (prevState != null) {
value = prevState.toBigDecimal();
weight = BigDecimal.valueOf(
Duration.between(prevItem.getTimestamp(), nextItem.getTimestamp()).toMillis());
weight = BigDecimal.valueOf(Duration.between(prevInstant, nextInstant).toMillis());
}
}
prevItem = nextItem;
prevInstant = nextInstant;
break;
case RIGHT:
nextState = getPersistedValue(nextItem, unit);
if (nextState != null) {
value = nextState.toBigDecimal();
if (prevItem == null) {
weight = BigDecimal.valueOf(Duration.between(begin, nextItem.getTimestamp()).toMillis());
weight = BigDecimal.valueOf(Duration.between(begin, nextInstant).toMillis());
} else {
weight = BigDecimal.valueOf(
Duration.between(prevItem.getTimestamp(), nextItem.getTimestamp()).toMillis());
weight = BigDecimal.valueOf(Duration.between(prevInstant, nextInstant).toMillis());
}
}
prevItem = nextItem;
prevInstant = nextInstant;
break;
case TRAPEZOIDAL:
if (prevItem != null) {
Expand All @@ -2258,11 +2264,11 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite
if (prevState != null && nextState != null) {
value = prevState.toBigDecimal().add(nextState.toBigDecimal())
.divide(BigDecimal.valueOf(2));
weight = BigDecimal.valueOf(
Duration.between(prevItem.getTimestamp(), nextItem.getTimestamp()).toMillis());
weight = BigDecimal.valueOf(Duration.between(prevInstant, nextInstant).toMillis());
}
}
prevItem = nextItem;
prevInstant = nextInstant;
break;
case MIDPOINT:
if (prevItem != null) {
Expand All @@ -2272,19 +2278,20 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite
if (midpointStartBucket && !prevDuration.isZero() && prevState != null) {
// Add half of the start bucket with the start value (left approximation)
sum = sum.add(prevState.toBigDecimal()
.multiply(BigDecimal.valueOf(prevDuration.dividedBy(2).toMillis())));
.multiply(BigDecimal.valueOf(prevDuration.toMillis() / 2)));
midpointStartBucket = false;
}
nextDuration = Duration.between(prevItem.getTimestamp(), nextItem.getTimestamp());
nextDuration = Duration.between(prevInstant, nextInstant);
weight = prevDuration.isZero() || nextDuration.isZero() ? BigDecimal.ZERO
: BigDecimal.valueOf(prevDuration.plus(nextDuration).dividedBy(2).toMillis());
: BigDecimal.valueOf(prevDuration.plus(nextDuration).toMillis() / 2);
if (!nextDuration.isZero()) {
prevDuration = nextDuration;
}
prevState = currentState;
}
}
prevItem = nextItem;
prevInstant = nextInstant;
break;
}
sum = sum.add(value.multiply(weight));
Expand All @@ -2295,7 +2302,7 @@ private static BigDecimal riemannSum(ZonedDateTime begin, ZonedDateTime end, Ite
DecimalType dtState = getPersistedValue(prevItem, unit);
if (dtState != null) {
BigDecimal value = dtState.toBigDecimal();
BigDecimal weight = BigDecimal.valueOf(prevDuration.dividedBy(2).toMillis());
BigDecimal weight = BigDecimal.valueOf(prevDuration.toMillis() / 2);
sum = sum.add(value.multiply(weight));
}
}
Expand Down