Add parameter on Hysteresis Profile to exclude current Item State from calculation (#5556)

Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
This commit is contained in:
Christoph Weitkamp
2026-05-17 00:24:32 +02:00
committed by GitHub
parent 4d5610fd57
commit 1c786e7181
4 changed files with 58 additions and 14 deletions
@@ -43,8 +43,9 @@ import tech.units.indriya.AbstractUnit;
public class SystemHysteresisStateProfile implements StateProfile {
static final String LOWER_PARAM = "lower";
private static final String UPPER_PARAM = "upper";
private static final String INVERTED_PARAM = "inverted";
static final String UPPER_PARAM = "upper";
static final String INVERTED_PARAM = "inverted";
static final String EXCLUDE_ITEM_STATE_PARAM = "excludeItemState";
private final Logger logger = LoggerFactory.getLogger(SystemHysteresisStateProfile.class);
@@ -54,6 +55,7 @@ public class SystemHysteresisStateProfile implements StateProfile {
private final QuantityType<?> upper;
private final OnOffType low;
private final OnOffType high;
private final boolean excludeItemState;
private Type previousType = UnDefType.UNDEF;
@@ -75,10 +77,15 @@ public class SystemHysteresisStateProfile implements StateProfile {
}
this.upper = convertedUpperParam;
final Object paramValue = context.getConfiguration().get(INVERTED_PARAM);
final boolean inverted = paramValue != null && Boolean.parseBoolean(paramValue.toString());
final Object invertedParamValue = context.getConfiguration().get(INVERTED_PARAM);
final boolean inverted = invertedParamValue != null && Boolean.parseBoolean(invertedParamValue.toString());
this.low = OnOffType.from(inverted);
this.high = OnOffType.from(!inverted);
final Object excludeItemStateParamValue = context.getConfiguration().get(EXCLUDE_ITEM_STATE_PARAM);
this.excludeItemState = excludeItemStateParamValue != null
&& Boolean.parseBoolean(excludeItemStateParamValue.toString());
;
}
private @Nullable QuantityType<?> getParam(ProfileContext context, String param) {
@@ -161,10 +168,18 @@ public class SystemHysteresisStateProfile implements StateProfile {
}
private Type mapValue(double lower, double upper, double value) {
if (value <= lower) {
return low;
} else if (value >= upper) {
return high;
if (excludeItemState) {
if (value < lower) {
return low;
} else if (value >= upper) {
return high;
}
} else {
if (value <= lower) {
return low;
} else if (value > upper) {
return high;
}
}
return previousType;
}
@@ -18,5 +18,10 @@
<description>Inverts resulting mapping of ON / OFF, if true.</description>
<default>false</default>
</parameter>
<parameter name="excludeItemState" type="boolean">
<label>Exclude Item State</label>
<description>Do not include Item State in comparison.</description>
<default>false</default>
</parameter>
</config-description>
</config-description:config-descriptions>
@@ -10,6 +10,8 @@ profile.config.system.hysteresis.upper.label = Upper Bound
profile.config.system.hysteresis.upper.description = Maps to ON if value is greater than or equal to upper bound (plain number or number with unit).
profile.config.system.hysteresis.inverted.label = Inverted
profile.config.system.hysteresis.inverted.description = Inverts resulting mapping of ON / OFF, if true.
profile.config.system.hysteresis.excludeItemState.label = Exclude Item State
profile.config.system.hysteresis.excludeItemState.description = Do not include Item State in comparison.
profile-type.system.range.label = Range
profile.config.system.range.lower.label = Lower Bound
profile.config.system.range.lower.description = Maps to ON if value is between lower and upper bound (plain number or number with unit).
@@ -185,13 +185,33 @@ public class SystemHysteresisStateProfileTest {
@Test
public void testInvertedParameter() {
final StateProfile profile = initProfile(BigDecimal.TEN, null, true);
final StateProfile profile = initProfile(BigDecimal.TEN, null, true, false);
verifySendCommand(profile, PercentType.HUNDRED, OnOffType.OFF);
verifySendCommand(profile, PERCENT_TYPE_TEN, OnOffType.ON);
verifySendCommand(profile, PercentType.ZERO, OnOffType.ON);
verifySendUpdate(profile, PercentType.HUNDRED, OnOffType.OFF);
verifySendUpdate(profile, PERCENT_TYPE_TEN, OnOffType.ON);
verifySendUpdate(profile, PercentType.ZERO, OnOffType.ON);
}
@Test
public void testInvertedParameterExcludeItemState() {
final StateProfile profile = initProfile(BigDecimal.TEN, null, true, true);
verifySendCommand(profile, PercentType.HUNDRED, OnOffType.OFF);
verifySendCommand(profile, PERCENT_TYPE_TEN, OnOffType.OFF);
verifySendCommand(profile, PercentType.ZERO, OnOffType.ON);
verifySendUpdate(profile, PercentType.HUNDRED, OnOffType.OFF);
verifySendUpdate(profile, PERCENT_TYPE_TEN, OnOffType.OFF);
verifySendUpdate(profile, PercentType.ZERO, OnOffType.ON);
}
@Test
public void testExcludeItemStateParameter() {
final StateProfile profile = initProfile(BigDecimal.TEN, null, false, true);
verifySendCommand(profile, PERCENT_TYPE_TEN, OnOffType.ON);
verifySendUpdate(profile, PERCENT_TYPE_TEN, OnOffType.ON);
}
@ParameterizedTest
@MethodSource("parameters")
public void testOnCommandFromHandler(ParameterSet parameterSet) {
@@ -211,14 +231,16 @@ public class SystemHysteresisStateProfileTest {
}
private StateProfile initProfile(@Nullable Object lower, @Nullable Object upper) {
return initProfile(lower, upper, false);
return initProfile(lower, upper, false, false);
}
private StateProfile initProfile(@Nullable Object lower, @Nullable Object upper, boolean inverted) {
private StateProfile initProfile(@Nullable Object lower, @Nullable Object upper, boolean inverted,
boolean excludeItemState) {
final Map<String, @Nullable Object> properties = new HashMap<>(2);
properties.put("lower", lower);
properties.put("upper", upper);
properties.put("inverted", inverted);
properties.put(SystemHysteresisStateProfile.LOWER_PARAM, lower);
properties.put(SystemHysteresisStateProfile.UPPER_PARAM, upper);
properties.put(SystemHysteresisStateProfile.INVERTED_PARAM, inverted);
properties.put(SystemHysteresisStateProfile.EXCLUDE_ITEM_STATE_PARAM, excludeItemState);
when(mockContext.getConfiguration()).thenReturn(new Configuration(properties));
return new SystemHysteresisStateProfile(mockCallback, mockContext);
}