mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[basicprofiles] Fix delta state filter handling of negative values (#17997)
* [basicprofiles] Pass the initial data for delta state filter Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
This commit is contained in:
parent
1c1318d4ef
commit
eea928c9be
@ -341,7 +341,12 @@ public class StateFilterProfile implements StateProfile {
|
||||
|
||||
if (rhsState == null) {
|
||||
rhsItem = getItemOrNull(rhsString);
|
||||
} else if (rhsState instanceof FunctionType) {
|
||||
} else if (rhsState instanceof FunctionType rhsFunction) {
|
||||
if (acceptedState == UnDefType.UNDEF && (rhsFunction.getType() == FunctionType.Function.DELTA
|
||||
|| rhsFunction.getType() == FunctionType.Function.DELTA_PERCENT)) {
|
||||
acceptedState = input;
|
||||
return true;
|
||||
}
|
||||
rhsItem = getLinkedItem();
|
||||
}
|
||||
|
||||
@ -359,6 +364,11 @@ public class StateFilterProfile implements StateProfile {
|
||||
return false;
|
||||
}
|
||||
} else if (lhsState instanceof FunctionType lhsFunction) {
|
||||
if (acceptedState == UnDefType.UNDEF && (lhsFunction.getType() == FunctionType.Function.DELTA
|
||||
|| lhsFunction.getType() == FunctionType.Function.DELTA_PERCENT)) {
|
||||
acceptedState = input;
|
||||
return true;
|
||||
}
|
||||
lhsItem = getLinkedItem();
|
||||
lhsState = lhsFunction.calculate();
|
||||
if (lhsState == null) {
|
||||
@ -660,27 +670,18 @@ public class StateFilterProfile implements StateProfile {
|
||||
}
|
||||
|
||||
private @Nullable State calculateDelta() {
|
||||
if (acceptedState == UnDefType.UNDEF) {
|
||||
logger.debug("No previous data to calculate delta");
|
||||
acceptedState = newState;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (newState instanceof QuantityType newStateQuantity) {
|
||||
QuantityType result = newStateQuantity.subtract((QuantityType) acceptedState);
|
||||
return result.toBigDecimal().compareTo(BigDecimal.ZERO) < 0 ? result.negate() : result;
|
||||
}
|
||||
BigDecimal result = ((DecimalType) newState).toBigDecimal()
|
||||
.subtract(((DecimalType) acceptedState).toBigDecimal());
|
||||
return result.compareTo(BigDecimal.ZERO) < 0 ? new DecimalType(result.negate()) : new DecimalType(result);
|
||||
.subtract(((DecimalType) acceptedState).toBigDecimal()) //
|
||||
.abs();
|
||||
return new DecimalType(result);
|
||||
}
|
||||
|
||||
private @Nullable State calculateDeltaPercent() {
|
||||
State calculatedDelta = calculateDelta();
|
||||
if (calculatedDelta == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BigDecimal bdDelta;
|
||||
BigDecimal bdBase;
|
||||
if (acceptedState instanceof QuantityType acceptedStateQuantity) {
|
||||
@ -691,6 +692,7 @@ public class StateFilterProfile implements StateProfile {
|
||||
bdDelta = ((DecimalType) calculatedDelta).toBigDecimal();
|
||||
bdBase = ((DecimalType) acceptedState).toBigDecimal();
|
||||
}
|
||||
bdBase = bdBase.abs();
|
||||
BigDecimal percent = bdDelta.multiply(BigDecimal.valueOf(100)).divide(bdBase, 2, RoundingMode.HALF_EVEN);
|
||||
return new DecimalType(percent);
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
@ -658,8 +659,10 @@ public class StateFilterProfileTest {
|
||||
NumberItem powerItem = new NumberItem("Number:Power", "powerItem", UNIT_PROVIDER);
|
||||
NumberItem decimalItem = new NumberItem("decimalItem");
|
||||
List<Number> numbers = List.of(1, 2, 3, 4, 5);
|
||||
List<Number> negatives = List.of(-1, -2, -3, -4, -5);
|
||||
List<QuantityType> quantities = numbers.stream().map(n -> new QuantityType(n, Units.WATT)).toList();
|
||||
List<DecimalType> decimals = numbers.stream().map(DecimalType::new).toList();
|
||||
List<DecimalType> negativeDecimals = negatives.stream().map(DecimalType::new).toList();
|
||||
|
||||
return Stream.of( //
|
||||
// test custom window size
|
||||
@ -695,6 +698,9 @@ public class StateFilterProfileTest {
|
||||
Arguments.of(decimalItem, "$DELTA_PERCENT < 10", decimals, DecimalType.valueOf("0.91"), true), //
|
||||
Arguments.of(decimalItem, "$DELTA_PERCENT < 10", decimals, DecimalType.valueOf("0.89"), false), //
|
||||
|
||||
Arguments.of(decimalItem, "$DELTA_PERCENT < 10", negativeDecimals, DecimalType.valueOf("0"), false), //
|
||||
Arguments.of(decimalItem, "10 > $DELTA_PERCENT", negativeDecimals, DecimalType.valueOf("0"), false), //
|
||||
|
||||
Arguments.of(decimalItem, "< 10%", decimals, DecimalType.valueOf("1.09"), true), //
|
||||
Arguments.of(decimalItem, "< 10%", decimals, DecimalType.valueOf("1.11"), false), //
|
||||
Arguments.of(decimalItem, "< 10%", decimals, DecimalType.valueOf("0.91"), true), //
|
||||
@ -762,4 +768,30 @@ public class StateFilterProfileTest {
|
||||
profile.onStateUpdateFromHandler(input);
|
||||
verify(mockCallback, times(expected ? 1 : 0)).sendUpdate(input);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = { //
|
||||
"$DELTA > 10", //
|
||||
"$DELTA < 10", //
|
||||
"10 < $DELTA", //
|
||||
"10 > $DELTA", //
|
||||
"$DELTA_PERCENT > 10", //
|
||||
"$DELTA_PERCENT < 10", //
|
||||
"10 < $DELTA_PERCENT", //
|
||||
"10 > $DELTA_PERCENT", //
|
||||
"> 10%", //
|
||||
"< 10%" //
|
||||
})
|
||||
public void testFirstDataIsAcceptedForDeltaFunctions(String conditions) throws ItemNotFoundException {
|
||||
NumberItem decimalItem = new NumberItem("decimalItem");
|
||||
|
||||
when(mockContext.getConfiguration()).thenReturn(new Configuration(Map.of("conditions", conditions)));
|
||||
when(mockItemRegistry.getItem(decimalItem.getName())).thenReturn(decimalItem);
|
||||
when(mockItemChannelLink.getItemName()).thenReturn(decimalItem.getName());
|
||||
|
||||
StateFilterProfile profile = new StateFilterProfile(mockCallback, mockContext, mockItemRegistry);
|
||||
|
||||
profile.onStateUpdateFromHandler(DecimalType.valueOf("1"));
|
||||
verify(mockCallback, times(1)).sendUpdate(DecimalType.valueOf("1"));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user