Behaviour of profiles that send on/off like "hysteris" and its description

I have now dealt with Profiles for the first time and have read the documentation: Items | openHAB.

It was unclear to me whether, for example, the hysteresis value is also set back to OFF in a certain situation (which I presumed), but this is not explicitly mentioned in the doc, so I looked at the code and yes, this happens in mapValue.

This Profile can be used to trigger alarms when number values exceed a given lower bound - sends ON to the Switch Item.

code excerpt:

mapValue(....) {

  if (value <= lower) {
      return low;
  } else if (value >= upper) {
      return high;
  return previousType;

FYI: low == OFF, high == ON unless inverted is on. upper equals lower, if no upper is given.

Should we add the to the description when exactly the item is set back to OFF? Is the following understanding correct?

  • in case only lower value is given (is this really a hysteresis then?) it sends OFF to the switch, when the value falls below or is equal to lower.
  • in case an upper value is provided, ON is only sent when it exceeds/equals the upper value and keeps it until then falls below/equals lower and the OFF is sent to the switch item.
  • the values ON/OFF are inverted if inverted is set.

Do I understand it correctly ^ and if yes, does it make sense to add a more comprehensive documentation to the description? (I am happy to to that for this profile and the others that send ON/OFFS)

I’m always for having the docs be explicit and complete. This does seem like an important part that’s missing.

What does upper and high default to? Given this code snippet I don’t see how the upper check can be skipped. These have to have some value so it’s not a half hysteresis, it just defaults the high bound. documenting what that default is would be useful though.

  • lower and upper are the given hysteris params and upper defaults to upper if not provided.

and low and high represent the state values to be sent.

 this.low = inverted ? OnOffType.ON : OnOffType.OFF;
 this.high = inverted ? OnOffType.OFF : OnOffType.ON;

Here is the link to the code

Looking at the constructor it looks like the upper gets set to lower when it doesn’t exist.

        final QuantityType<?> convertedUpperParam = upperParam == null ? lower
                : upperParam.toInvertibleUnit(lower.getUnit());

Given that, the mapValue will return low or previousType which is set to UNDEF. But that can only work in cases where a stateUpdate is sent to the Item. If the Profile is configured to sendCommand, the UNDEF is ignored because it’s not a Command.

My reading of the docs indicated that it always sends the command so indeed, without the upper defined, it will only send low as a command or nothing at all.

At least that’s how I read the code, but I wonder under what circumstances, if any public void onStateUpdateFromHandler(State state) would ever be called. If there is one, than the behavior is the Item will be updated to low or UNDEF. Maybe whether it’s a command or update depends on whether the Channel is sending a command or posting an update.

So, maybe we ask @cweitkamp ? :smiley: to enlighten us and then let’s update the docs accordingly.

The Hysteresis Profile acts similar to a threshold when no upper value is given. In this case upper is set to the same value as lower and the mapValue can be interpreted like this:

if (value <= lower) {
      return low;
  } else if (value >= lower) {
      return high;
  return previousType;

Meaning it either returns low (OFF) or high (ON) or the other way around if inverted=true.

The hysteresis logic applies only if both lower and upper are set.

Did you see the examples in the Advanced Examples section?

/** Hysteresis Profile **/
Number:Temperature Outdoor_Temperature { channel="openweathermap:weather-and-forecast:api:local:current#temperature" }
// Triggers a temperature high alarm (Switch = ON) as of 30 °c and stays ON until temperature drops below 29 °C
Switch Outdoor_Temperature_High_Alert { channel="openweathermap:weather-and-forecast:api:local:current#temperature" [profile="system:hysteresis", lower="29 °C", upper="30 °C"] }
// Temperture low alert below 0 °C
Switch Outdoor_Temperature_Low_Alert { channel="openweathermap:weather-and-forecast:api:local:current#temperature" [profile="system:hysteresis", lower="0 °C", inverted="true"] }

/** Battery Level Profile **/
Number Battery_Level { channel="serialbutton:button:mybutton:battery-level" }
// Indicates a battery low alarm if battery level drops below 15
Switch Low_Battery { channel="serialbutton:button:mybutton:battery-level" [profile="system:hysteresis", lower=15, inverted="true"] }

The comment /** Battery Level Profile **/ may be misleading as the Hysteresis Profile is used for it too.