Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[basicprofiles] Fix inability to filter a percent QuantityType input #18091

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
5 changes: 5 additions & 0 deletions bundles/org.openhab.transform.basicprofiles/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,16 @@ The `LHS_OPERAND` and the `RHS_OPERAND` can be either one of these:
It is calculated as `($DELTA / current_data) * 100`.
Note that this can also be done by omitting the `LHS_OPERAND` and using a number followed with a percent sign `%` as the `RHS_OPERAND`.
See the example below.
- `$INPUT` to represent the incoming value.
Conditions that compare QuantityType inputs to a constant must include the relevant unit (e.g. `> 100 W`).
However, when the unit is `%`, such conditions (e.g. `> 10 %`) will trigger a `$DELTA_PERCENT` check.
To avoid this, write the condition as `$INPUT > 10 %`.
- `$AVERAGE`, or `$AVG` to represent the average of the previous unfiltered incoming values.
- `$STDDEV` to represent the _population_ standard deviation of the previous unfiltered incoming values.
- `$MEDIAN` to represent the median value of the previous unfiltered incoming values.
- `$MIN` to represent the minimum value of the previous unfiltered incoming values.
- `$MAX` to represent the maximum value of the previous unfiltered incoming values.

These are only applicable to numeric states.
By default, 5 samples of the previous values are kept.
This can be customized by specifying the "window size" or sample count applicable to the function, e.g. `$MEDIAN(10)` will return the median of the last 10 values.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ public String toString() {
*/
class FunctionType implements State {
enum Function {
INPUT,
DELTA,
DELTA_PERCENT,
AVERAGE,
Expand All @@ -535,6 +536,7 @@ public FunctionType(Function type, Optional<Integer> windowSize) {
int start = windowSize.map(w -> size - w).orElse(0);
List<State> states = start <= 0 ? previousStates : previousStates.subList(start, size);
return switch (type) {
case INPUT -> newState;
case DELTA -> calculateDelta();
case DELTA_PERCENT -> calculateDeltaPercent();
case AVG, AVERAGE -> calculateAverage(states);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;

import javax.measure.Unit;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -67,6 +70,7 @@
import org.openhab.core.thing.profiles.ProfileContext;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.openhab.core.types.util.UnitUtils;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.ComponentContext;

Expand Down Expand Up @@ -657,14 +661,22 @@ public void testComparingInputStateWithItem(GenericItem linkedItem, State inputS

public static Stream<Arguments> testFunctions() {
NumberItem powerItem = new NumberItem("Number:Power", "powerItem", UNIT_PROVIDER);
NumberItem percentItem = new NumberItem("Number:Dimensionless", "percentItem", 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();
Unit percentUnit = Objects.requireNonNull(UnitUtils.parseUnit("%"));
List<QuantityType> percents = numbers.stream().map(n -> new QuantityType(n, percentUnit)).toList();
List<DecimalType> decimals = numbers.stream().map(DecimalType::new).toList();
List<DecimalType> negativeDecimals = negatives.stream().map(DecimalType::new).toList();

return Stream.of( //
Arguments.of(decimalItem, "$INPUT < 10", decimals, DecimalType.valueOf("3"), true), //
Arguments.of(decimalItem, "$INPUT < 10", decimals, DecimalType.valueOf("10"), false), //
Arguments.of(percentItem, "$INPUT < 10 %", percents, QuantityType.valueOf("-10 %"), true), //
Arguments.of(percentItem, "$INPUT < 10 %", percents, QuantityType.valueOf("10 %"), false), //

// test custom window size
Arguments.of(decimalItem, "$AVERAGE(3) == 4", decimals, DecimalType.valueOf("5"), true), //
Arguments.of(decimalItem, "$AVERAGE(4) == 3.5", decimals, DecimalType.valueOf("5"), true), //
Expand Down