Threshold Alert and Open Reminder [4.0.0.0;5.9.9.9]

Have you created two seaparate instances of the Threshold Alert rule? Are both triggered by the same Group Item?

That’s going to lead to chaos as both rules will trigger on changes to both Items. If you have soemthing different you want to do between the two Items, you should use metadata to override the properties that are different for each Item, not create two separate rules. Or if you do create two separate rules, the rule must only be triggered by the one Item that rule apples to.

This is more evidence your config is the problem here. But both the salon TA rule and the eetkamer TA rule are triggered by the same Group and that Group has both the salon and eetkamer Items in it, both the salon and the eetkamer TA rule will be triggered by changes to either Item.

Your configuration should be as follows:

  1. Create one Group and add both the salon and eetkamer Items as members.
  2. Create one instance of the TA rule template, configure everything as desired but leave the Alert Rule empty.
  3. Navigate to the salon Item and add Item metadata in the namespace “thresholdAlert” and set the config property of alertRuleID to “haard_salon_procesbescherming_UIT”
  4. Navigate to the eetkamer Item and add Item metadata in the namesplace “thresholdAlert” and set the config property of alertRuleID to “haard_eetkamer_procesbescherming_UIT”
  5. Run the TA rule created in step 2 manually and look at the logs for errors.

An example of what the metadata should look like:

value: " "
config:
  alertRuleID: haard_salon_procesbescherming_UIT

The rule is doing exactly what it’s configured to do based on these logs. It’s just that both Items are driving both rules.

Note, I can tell it’s two rules because the logger names are different.

No, there was only the one rule. There was only one rule I switched to DEBUG anyway… I now deleted it, and tried to recreate it following your steps.

I’m not sure what you mean, but there really was only one rule… Now there’s no rule in which haarden_procesbeschermingstimers is mentioned:

If I leave “Alert Rule” (which is registered as “required”) empty, an empty rule is created:

The logger name for the rule is: org.openhab.automation.rules_tools.Threshold Alert.<ruleUID>

The logger names in your log are [.haard_salon_procesbeschermingstimer] and [ard_eetkamer_procesbeschermingstimer].

Therefore you would have one rule with the ruleUID “haard_salon_procesbeschermingstimer” and a second rule with the uid presumably “haard_eetkamer_procesbeschermingstimer”.

However, I now remember that the Item name gets appended to the logger name for Item event triggers to the rule. So indeed I was mistaken.

The events in the first log are as follows:

Sequence Event Timestamp
1 TA triggered by salon changing to 0 s 16:43:33.413
2 TA determines salon is in the alerting state 16:43:33.415
3 Calling initial alert rule is scheduled, should do nothing 16:43:33:419
4 Creating a looping timer for two seconds at 16:43:35.415 16:43:33.425
5 Alert.haarden-procesbescherming-UIT is called, I can’t tell if this is from a previous run of the rule or not, ignoring for now 16:43:33.446
6 TA triggered by eetkamer changing to 0 s 16:43:33.446
7 TA determines eetkamer is in the alerting state 16:43:33.447
8 Calling initial alert rule is scheduled, should do nothing 16:43:33.450
9 Creating a looping timer for two seconds at 16:43:35.447 16:43:33.454
10 The init alert rule is finally called for salon, does nothing as expected 16:43:33:525
11 The init alert rule is finally called for eetkamer, does nothing as expected 16:43:33:526
12 Alert timer for salon runs, checks to see we are still alerting and schedules a call to the alerting rule 16:43:35.426
13 Alert timer for eetkamer runs, checks to see we are still alerting and schedules a call to the alerting rule 16:43:35.536

There were some additional events that triggered the rule interleaved in the above which I skipped.

But according to these logs, the alert rule was called for both salon and eetkamer within 11-89 msec of the expected time. salon was scheduled to be called at 16:43:35.415 and was actually called at 16:43:35.426. eetkamer was scheduled to be called at 16:43:35.447 and was actually called at 16:43:35.536.

So in terms of the processing of the events from the two Items, the rule performed as expected. It was triggered when both changed and the alerting rule was called two seconds after it changed to 0 s. Even though both changed to 0 s within milliseconds of each other, both events were processed.

I do see there’s an issue with the logger names in the timers which I’ve taken a note to address.

Apparently that’s a change I’ve planned but haven’t implemented as I thought I had (I just need to remove the required flag from the template. Since the property is required for now, just choose anything. It might be informative to create a new rule to be called as the default just to show that the actual rule called comes from the Item metadata.

Why are you wanting to call two different rules though, one for each Item. The name of the Item that is alerting, along with a bunch of other information, is passed into your called rule. Assuming these do the same thing just with different Items, why not just have the one rule and figure out which Item to command based on the passed in information?

Overall, this might have uncovered a bug in the rule template (it’s an unusual use case) but I can’t see how. Each Item has it’s own record and that record is passed into a function generator which should fix it when the Timer runs. But something might not work as I think there.

I’ve checked in a new 1.3 version of the rule template which fixes the logger issue in the timer as well as potentially fixes any issue with the record, assuming there is one there.

But a better overall approach would probably be to make your called rule generic. Given your Item naming convention, it’s probably just something as simple as (assuming a managed JS rule):

var location = alertItem.split('_')[1];
console.info('Turning off ' + location + " two seconds after end of timer");
items["haard_" + location + "_procesbescherming"].sendCommand("OFF");

This rule builds the name of the Item to command based on the name of the Item that alerted. That’s a hole lot simpler and easier to maintain in the long run than creating custom metadata configs for each Item.

1 Like

You’re right. I had missed that part of the instructions :grimacing: So I’m glad something was discovered, and it wasn’t a total waste of time :stuck_out_tongue:

However, I do have another case (with different items as above), but the goal is a bit different. I want a (fireplace switch) item to be turned on when the (room) temperature of a group member is below a certain threshold, but to be turned on, when it’s above another threshold. So when it’s too cold, the fire goes on, but when it’s getting too warm, it goes off.

To make matters more complicated, there are again two fireplaces, and both rooms might have different thresholds. I thought of doing that with a variable, based on the triggering item name (similar as above):

var kamersenhaarden = [
  "eetkamer",
  "salon"
];
var verderzoeken = true;
for (let x = 0; x < kamersenhaarden.length && verderzoeken; x++) {
  if (String(event.itemName).toLowerCase().includes(kamersenhaarden[x])) {
    var kamernaam = kamersenhaarden[x];
    verderzoeken = false;
  }
}
var thresholdStrtekst = "haard_"+ kamernaam +"_temperatuurgestuurd_uit";
var thresholdStr = items.getItem(thresholdStrtekst).state;

Maybe I should make two group items, both with the same room temperature items as members, and then a TA rule per group?

Use a separate TA rule instance for that.

For now put the threshold in each fireplace Item’s metadata. In the future I have plans to make it so you can use an Item instead of needing to hard code it like this.

To be clear, it’s not wrong or unexpected to override certain properties of the TA rule through Item metadata. It was just unexpected to use that to change the alert rule called by the TA rule. I myself use Item metadata to set different thresholds for my humidifiers.

To summarize:

  1. create one Group and put the thermostat reading Items into this Group
  2. create a new instance of the TA rule for the fireplaces and set the threshold and hysteresis as desired. For example, if the threhsold is set to65 °F, hysteresis to 3 °F, and the comparison set to < your alert rule will be called as alerting when the temp gets below 65 °F (your rule should turn on the fireplace) and it will be called as end of alert when the temp gets above 68. °F.
  3. set the thersholdAlert Item metadata on the thermostat Items so each has a their own threhold and hysteresis values; that will override the defaults of the rule
  4. in your alerting rule, calcuate the name of the Switch Item using triggeringItem as demonstrated above and sendCommand ON and OFF based on whether isAlerting is true or false
var fireplaceSwitch = // use string manipulation or navigate the semantic model hierarchy
items[fireplaceSwitch].sendCommand((isAlerting) ? 'ON' : 'OFF');

As an example of navigating the semantic model, I have a TA rule which calles the following when a sensor Item doesn’t report for too long of a time. It uses the semantic model and Item tags to determine which Item is the statis Item.

var equipment = actions.Semantics.getEquipment(items[alertItem]);
var statusItem = items[equipment.name+'_Status'];
if(equipment === null || statusItem === null) {
  console.warn(alertItem + ' does not belong to an equipment or equipment doesn\'t have a Status Item!');
  false;
}
else {
  var statusItem = items[equipment.name+'_Status'];
  console.info('Sensor status reporting called for ' + alertItem + ', equipment ' + equipment.label + ', is alerting ' + isAlerting + ', and is initial alert ' + isInitialAlert 
               + ', current equipment state is ' + statusItem.state);
  // Sensor is offline                         Sensor back online
  (isAlerting && statusItem.state != 'OFF') || (!isAlerting && statusItem.state != 'ON');
}
1 Like

Aha, so that’s what this hysteresis is. I couldn’t wrap my head around it.

Sounds great!

Can I (in the Item metadata) refer to other the state of other Items for these values? Because these thresholds would be values that residents might want to change, based on how they feel. :slight_smile:

This:

value: " "
config:
  thresholdState: =items["haard_eetkamer_temperatuurgestuurd_aan"].state

doesn’t seem to work… Is this impossible, or is the syntax wrong?

(items["Thermostaat_eetkamer_ambientTemp"].getMetadata().thresholdAlert.configuration.thresholdState logs as =items["haard_eetkamer_temperatuurgestuurd_aan"].state.

Logging items["haard_eetkamer_temperatuurgestuurd_aan"].state results in 12 °C.)

It’s impossible for now. As I said above, I have plans to make it so the threhold can be set by an Item but that’s not possible now.

Expressions like that are applicable to MainUI Widgets only. They have no applicability outside that.

If you don’t want to wait (who knows how long it will take for me to get to it at this point) you can modify the code of the rule yourself to pull the threshold from another item instead of using the threhold property. You’d do so in the “refreshRecord” function.

I didn’t mean in the rule parameters, but in the metadata of an Item.

But I assume this answers that question.

I still can’t get this to work for me to detect UNDEF. I see these lines, shouldn’t UNDEF == UnDefType? I’m missing something obvious, but I don’t know what it is. Should the Operator be ‘===’?

Version is 1.3, OH is on 4.2.2.

2024-11-10 08:28:01.244 [DEBUG] [tReporting.OutsideTemperatureBattery] - Checking if we are in the alerting state: UNDEF == UnDefType
2024-11-10 08:28:01.244 [DEBUG] [tReporting.OutsideTemperatureBattery] - Result is false

Set up is here:

2024-11-08 15:11:48.990 [INFO ] [.Threshold Alert.BatteryNotReporting] - Rule triggered without an Item event, ExecutionEvent checking the rule config
2024-11-08 15:11:49.043 [INFO ] [.Threshold Alert.BatteryNotReporting] - Threshold Alert configs check out as OK
2024-11-08 15:12:32.467 [DEBUG] [.Threshold Alert.BatteryNotReporting] - Starting threshold alert
2024-11-08 15:12:32.468 [INFO ] [.Threshold Alert.BatteryNotReporting] - Rule triggered without an Item event, ExecutionEvent checking the rule config
2024-11-08 15:12:32.469 [DEBUG] [.Threshold Alert.BatteryNotReporting] - Rule config defaults:
  Group                     - gBatteryLevel
  Threhsold                 - UnDefType
  Operator                  - ==
  Invert Operator           - false
  Reschedule                - false
  Default Alert Delay       - PT10S
  Default Reminder Duration - PT24H
  DND Start                 - 00:00
  DND End                   - 00:00
  Alert Rule                - NotifySensorBatteryNotReporting
  End Alert Rule            -
  Alert Group               - gBatteryLevel
  Alert Items               - IndoorAqaraTemperatureHumidityPressureSensor_BatteryLevel, Living_Room2_PIR_Battery, OutsideTemperatureBattery, Outdoor_Sensor_Battery, HWHeaterSensorBattery, Kitchen_ZigBee_SNZB03P_Battery_Level, IndoorTemperatureSNZB02PBatteryLevel, ZigbeeTemperature1BatteryLevel, FrontDoorInsideMotionSensorBatteryLevel, SecondBathTubMotionBatteryLevel, Front_Door_Outside_PIR_Battery, MasterBathSensorBatteryLevel, WashingMachineLidBattery, Living_Room_PIR_Battery, HallSensorBatteryLevel, ZigbeeTemp2_Battery_Level, SecondBathTubDoorBattery, Garage_Temperature_Sensor_Battery, MasterBathDoorBattery, Leak_Sensor_Battery_Level, AtticHeatPumpXiaomiAqaraWaterLeakSensor_BatteryLevel, HalfBathBatteryLevel, MBDRMClosetMotionSensorBatteryLevel, Garage_Door_Sensor_Battery, TuyaZigbeeWaterSensorBatteryLevel
  Gatekeeper Delay          - 0
  Rate Limit                -
2024-11-08 15:12:32.470 [INFO ] [.Threshold Alert.BatteryNotReporting] - Cancelling any running timers
2024-11-08 15:12:32.470 [INFO ] [.Threshold Alert.BatteryNotReporting] - Threshold is UnDefType, this will cause Item states of NULL and UNDEF to be converted to UnDefType for comparisons.
2024-11-08 15:12:32.478 [INFO ] [.Threshold Alert.BatteryNotReporting] - No end alert rule configured, no rule will be called when alerting ends
2024-11-08 15:12:32.478 [INFO ] [.Threshold Alert.BatteryNotReporting] - No initial alert rule configured, no rule will be called when the alert state is first detected
2024-11-08 15:12:32.496 [INFO ] [.Threshold Alert.BatteryNotReporting] - These Items do not have thresholdAlert metadata and will use the default properties defined in the rule: IndoorAqaraTemperatureHumidityPressureSensor_BatteryLevel, Living_Room2_PIR_Battery, OutsideTemperatureBattery, Outdoor_Sensor_Battery, HWHeaterSensorBattery, Kitchen_ZigBee_SNZB03P_Battery_Level, IndoorTemperatureSNZB02PBatteryLevel, ZigbeeTemperature1BatteryLevel, FrontDoorInsideMotionSensorBatteryLevel, SecondBathTubMotionBatteryLevel, Front_Door_Outside_PIR_Battery, MasterBathSensorBatteryLevel, WashingMachineLidBattery, Living_Room_PIR_Battery, HallSensorBatteryLevel, ZigbeeTemp2_Battery_Level, SecondBathTubDoorBattery, Garage_Temperature_Sensor_Battery, MasterBathDoorBattery, Leak_Sensor_Battery_Level, AtticHeatPumpXiaomiAqaraWaterLeakSensor_BatteryLevel, HalfBathBatteryLevel, MBDRMClosetMotionSensorBatteryLevel, Garage_Door_Sensor_Battery, TuyaZigbeeWaterSensorBatteryLevel

Full debug log is here:

2024-11-10 08:28:01.229 [DEBUG] [.Threshold Alert.BatteryNotReporting] - Starting threshold alert
2024-11-10 08:28:01.231 [DEBUG] [tReporting.OutsideTemperatureBattery] - Processing an Item event
2024-11-10 08:28:01.232 [DEBUG] [tReporting.OutsideTemperatureBattery] - Processing state UNDEF of type object
2024-11-10 08:28:01.233 [DEBUG] [tReporting.OutsideTemperatureBattery] - Not numeric, leaving as a string: UNDEF
2024-11-10 08:28:01.233 [DEBUG] [tReporting.OutsideTemperatureBattery] - Processing state UNDEF from OutsideTemperatureBattery
2024-11-10 08:28:01.234 [DEBUG] [tReporting.OutsideTemperatureBattery] - Populating record from Item metadata or rule defauls
2024-11-10 08:28:01.238 [DEBUG] [tReporting.OutsideTemperatureBattery] - Converting threshold to value
2024-11-10 08:28:01.238 [DEBUG] [tReporting.OutsideTemperatureBattery] - Processing state UnDefType of type string
2024-11-10 08:28:01.239 [DEBUG] [tReporting.OutsideTemperatureBattery] - state is a string: UnDefType
2024-11-10 08:28:01.239 [DEBUG] [tReporting.OutsideTemperatureBattery] - state is an undef type, normalizing to UnDefType
2024-11-10 08:28:01.240 [DEBUG] [tReporting.OutsideTemperatureBattery] - Converting hysteresis to value
2024-11-10 08:28:01.241 [DEBUG] [tReporting.OutsideTemperatureBattery] - Processing state  of type string
2024-11-10 08:28:01.241 [DEBUG] [tReporting.OutsideTemperatureBattery] - state is a string:
2024-11-10 08:28:01.242 [DEBUG] [tReporting.OutsideTemperatureBattery] - state is the empty string, no conversion possible
2024-11-10 08:28:01.243 [DEBUG] [tReporting.OutsideTemperatureBattery] - Processing event for Item OutsideTemperatureBattery with properties:
  Threshold          - UnDefType
  Operator           - ==
  Invert             - false
  Reschedule         - false
  Alert Delay        - PT10S
  Reminder Period    - PT24H
  Alert Rule ID      - NotifySensorBatteryNotReporting
  End Alert Rule ID  -
  Init Alert Rule ID -
  Gatekeeper Delay   - 0
  Hystersis          -
  Rate Limt          -
  DnD Start          - 00:00
  DnD End            - 00:00
2024-11-10 08:28:01.244 [DEBUG] [tReporting.OutsideTemperatureBattery] - Checking if we are in the alerting state: UNDEF == UnDefType
2024-11-10 08:28:01.244 [DEBUG] [tReporting.OutsideTemperatureBattery] - Result is false
2024-11-10 08:28:01.245 [DEBUG] [tReporting.OutsideTemperatureBattery] - OutsideTemperatureBattery's new state is UNDEF which is no longer in the alerting state, previously alerted = false
2024-11-10 08:28:01.246 [DEBUG] [tReporting.OutsideTemperatureBattery] - Exiting alerting state but alert was never sent, not sending an end alert for OutsideTemperatureBattery

So after some thinking… I want the fireplace to go out when the temperature reaches 20 °C, and ignite again as soon as the temperature drops below 15 °C.

If I get it straight:

  1. var thresholdStr = "20 °C"; (a string)
  2. var alertRuleUID = 'haarden_temperatuurgestuurd_UIT'; (a rule that turns off the fireplace)
  3. var hystRange = "-5 °C"; (a string)
  4. var endAlertUID = 'haarden_temperatuurgestuurd_AAN'; (a rule that ignites the fireplace)

Correct?

If so, I’d get the value of thresholdStr and hystRange from items and convert them to strings.

The metadata overrides the rule parameters. If it’s not possible in the parameters, it’s not possible in the Item metadata.

No, when the threshold is UnDefType it’s a more involved comparison than just a straight == and that accounts for any differences between == and ===.

I’m not sure what’s is going on here and it may take some investigation. It’s correctly detecting that the state is an UnDefType:

state is an undef type, normalizing to UnDefType

But then it’s not suing the normalized value later on.

Checking if we are in the alerting state: UNDEF == UnDefType

There might be a regression that needs to be tracked down.

Not quite. You want to use 5 °C as the hysteresis. Hysteresis for this rule always needs to be a positive number.

I think you need to set the threashold to 15, and the hysterersis to 5. With < as the comparison, the furnace will come on at 15 and turn off at 20 I think.

And again, this is not supported by the rule. You’ll have to modify the rule yourself to support this or wait until I can get around to it and there is no guarantee when that will be.

I suppose that has the same logical outcome indeed. I’m correct in that both the hysteresis and the thresholds are strings?

That was my plan.

The relevant hysteresis code is:

  // Quantity
  if(curr.unit !== undefined && alert.unit != undefined && hyst.unit !== undefined) {
    try {
      const delta = (curr.lessThan(alert)) ? alert.subtract(curr) : curr.subtract(alert);
      console.debug('Applying hysteresis using Quantities, delta = ' + delta + ' hystRange = ' + hyst);
      return delta.greaterThan(hyst);
    } catch(e) {
      console.error('Attempting to apply hysteresis with Quantities of incompatable units. Not applying hysteresis');
      return true;
    }
  }

I have a possible explanation for the issue I’m seeing. stateToValue gets called multiple times. The first time it has the event. The state is not a string, so it falls through to the Quantity type and Decimal type checks, neither of which is true, so it just returns the state as the string ‘UNDEF’. This is not correct, it should be ‘UnDefType’.

The second time stateToValue is called it is getting the comparison value which is indeed a string and it does convert to UnDefType.

1st pass:

2024-11-10 08:28:01.231 [DEBUG] [tReporting.OutsideTemperatureBattery] - Processing an Item event
2024-11-10 08:28:01.232 [DEBUG] [tReporting.OutsideTemperatureBattery] - Processing state UNDEF of type object
2024-11-10 08:28:01.233 [DEBUG] [tReporting.OutsideTemperatureBattery] - Not numeric, leaving as a string: UNDEF

2nd pass:

2024-11-10 08:28:01.238 [DEBUG] [tReporting.OutsideTemperatureBattery] - Processing state UnDefType of type string
2024-11-10 08:28:01.239 [DEBUG] [tReporting.OutsideTemperatureBattery] - state is a string: UnDefType
2024-11-10 08:28:01.239 [DEBUG] [tReporting.OutsideTemperatureBattery] - state is an undef type, normalizing to UnDefType

I added a brute force compare at the top of stateToValue and this is now working for me. I’m sure there is a better fix possible, but perhaps it helps point to a solution.

var stateToValue = (state) => {
  console.debug('Processing state ' + state + ' of type ' + typeof state);
  if(typeof state === 'object') {
    console.debug('state is an object, checking for UnDefType');
    var stringState = state.toString();
    if (stringState == 'UnDefType' || stringState == 'NULL' || stringState == 'UNDEF') {
      console.debug('state object is an undef type, normalizing to UnDefType');
      return 'UnDefType';
    }  
  }

I had a chance to look into this and there is definitely a regression.

Line 194 should read:

const currState = stateToValue(items[name].state);

not

const currState = stateToValue(items[name].rawState);

Lines 345 and 464 should similarly use .state and not .rawState.

Finally line 938 should read

procEvent(event.itemName, stateToValue(event.itemState.toString()));

I’ll get these changes checked in as well as some code in stateToValue to handle the case where the value passed in isn’t a String. I’m not sure where the disconnect happened between old me and current me but now I know how to proceed. Check for an update to the OP with a version 1.4 to get the fixes. You’ll need to remove the template, readd, and recreate your rules from the new template.

1 Like

Tried to install v1.4 and I get this:

2024-11-13 16:28:36.995 [ERROR] [tion.MarketplaceRuleTemplateProvider] - Unable to parse YAML: while parsing a block node
 in 'reader', line 102, column 3:
      name: dndEnd
      ^
expected the node content, but found '?'
 in 'reader', line 102, column 3:
      name: dndEnd
      ^

 at [Source: (StringReader); line: 101, column: 3] (through reference chain: org.openhab.core.automation.dto.RuleTemplateDTO["configDescriptions"])
2024-11-13 16:28:36.996 [ERROR] [ty.CommunityRuleTemplateAddonHandler] - Rule template from marketplace is invalid: Unable to parse YAML

any ideas on what is wrong?

That’s really weird. I didn’t even touch that part of the code but somehow a stray newline got inserted in a place it shouldn’t which basically broke the YAML formatting. I fixed that and tested and was able to install the currently posted verison.

Thanks, it loaded up just fine now.

This is one example for how rule template development is kind of broken. It’s really hard to test the installation because the only way to install a template is through the marketplace.

I’m glad that worked. I’ll have to pay closer attention to the upper parts of the code in the future.

Rule template development is kind of broken really, I wish there were better options. I thought I had an issue open to support loading templates from the file system but couldn’t find it. I only found Marketplace: Support multiple templates in one file · Issue #2509 · openhab/openhab-core · GitHub