diff --git a/bundles/org.openhab.transform.basicprofiles/src/main/java/org/openhab/transform/basicprofiles/internal/profiles/StateFilterProfile.java b/bundles/org.openhab.transform.basicprofiles/src/main/java/org/openhab/transform/basicprofiles/internal/profiles/StateFilterProfile.java index 0c1dce30fc3d8..421125f65a4e1 100644 --- a/bundles/org.openhab.transform.basicprofiles/src/main/java/org/openhab/transform/basicprofiles/internal/profiles/StateFilterProfile.java +++ b/bundles/org.openhab.transform.basicprofiles/src/main/java/org/openhab/transform/basicprofiles/internal/profiles/StateFilterProfile.java @@ -343,8 +343,7 @@ public boolean check(State input) { if (rhsState == null) { rhsItem = getItemOrNull(rhsString); } else if (rhsState instanceof FunctionType rhsFunction) { - if (acceptedState == UnDefType.UNDEF && (rhsFunction.getType() == FunctionType.Function.DELTA - || rhsFunction.getType() == FunctionType.Function.DELTA_PERCENT)) { + if (rhsFunction.alwaysAccept()) { return true; } rhsItem = getLinkedItem(); @@ -364,8 +363,7 @@ public boolean check(State input) { return false; } } else if (lhsState instanceof FunctionType lhsFunction) { - if (acceptedState == UnDefType.UNDEF && (lhsFunction.getType() == FunctionType.Function.DELTA - || lhsFunction.getType() == FunctionType.Function.DELTA_PERCENT)) { + if (lhsFunction.alwaysAccept()) { return true; } lhsItem = getLinkedItem(); @@ -540,6 +538,22 @@ public FunctionType(Function type, Optional windowSize) { }; } + public boolean alwaysAccept() { + if ((type == Function.DELTA || type == Function.DELTA_PERCENT) && acceptedState == UnDefType.UNDEF) { + return true; + } + if (type == Function.DELTA_PERCENT) { + // avoid division by zero + if (acceptedState instanceof QuantityType base) { + return base.toBigDecimal().compareTo(BigDecimal.ZERO) == 0; + } + if (acceptedState instanceof DecimalType base) { + return base.toBigDecimal().compareTo(BigDecimal.ZERO) == 0; + } + } + return false; + } + @Override public @Nullable T as(@Nullable Class target) { if (target == DecimalType.class || target == QuantityType.class) { diff --git a/bundles/org.openhab.transform.basicprofiles/src/test/java/org/openhab/transform/basicprofiles/internal/profiles/StateFilterProfileTest.java b/bundles/org.openhab.transform.basicprofiles/src/test/java/org/openhab/transform/basicprofiles/internal/profiles/StateFilterProfileTest.java index de2a38b12292d..a2c38ebe3ecec 100644 --- a/bundles/org.openhab.transform.basicprofiles/src/test/java/org/openhab/transform/basicprofiles/internal/profiles/StateFilterProfileTest.java +++ b/bundles/org.openhab.transform.basicprofiles/src/test/java/org/openhab/transform/basicprofiles/internal/profiles/StateFilterProfileTest.java @@ -710,6 +710,10 @@ public static Stream testFunctions() { Arguments.of(decimalItem, "< 10%", decimals, DecimalType.valueOf("0.91"), true), // Arguments.of(decimalItem, "< 10%", decimals, DecimalType.valueOf("0.89"), false), // + // Check against possible division-by-zero errors in $DELTA_PERCENT + Arguments.of(decimalItem, "> 10%", List.of(DecimalType.ZERO), DecimalType.valueOf("1"), true), // + Arguments.of(decimalItem, "< 10%", List.of(DecimalType.ZERO), DecimalType.valueOf("1"), true), // + Arguments.of(decimalItem, "1 == $MIN", decimals, DecimalType.valueOf("20"), true), // Arguments.of(decimalItem, "0 < $MIN", decimals, DecimalType.valueOf("20"), true), // Arguments.of(decimalItem, "$MIN > 0", decimals, DecimalType.valueOf("20"), true), //