Threshold Alert and Open Reminder [4.0.0.0;4.9.9.9]

I think I may have found the problem but need to run some experiments to verify. I think the issue is as follows:

  1. When first entering alerting the rule detects that it’s the first time through if(record.alertTimer === null && !record.isAlerting). So whether or not there is already a timer is one of the criteria to determine if this is the first alert.

  2. There is no timeout (i.e. wait for some amount of time before calling the alert rule) and there is no reminder period. This causes the timer that sends the alert to run immediately.

  3. Looping timer works by return value of the function the timer calls. If it returns something that can be converted to a time, that’s when it schedules the timer function to run again. When it returns null the timer exits and cleans up after itself by setting record.alertTimer to null.

  4. When there is no repeatTime property defined the time to reschedule the timer becomes null and the timer cleans itself up by setting record.alertTimer to null.

  5. The next time an event comes in that is over the alert value it’s seen as a brand new alert because there’s no timer.

I’ve been tearing my hair out looking at the hysteresis but the problem is the reminder timer. All my instances of this template use the reminder so I aparently never tested it without a reminder.

I need to think about how best to handle this for a bit because the straight forward approach would be a breaking change.

In the mean time you should be able to avoid the problem by setting a rediculous reminder period, like P1WT (one weekl). That will keep the alert timer around as long as the value remains above the threhold so the rule will see that it has already alerted. At worse, if the value remains above the threshold, you’ll get a reminder once a week.

1 Like

Thanks, that explains things. I’ve added the reminder period for now.

  • If the timer cleans up itself and sets the timers to null, doesn’t that also mean that the timer will be set to null after the repeat time is hit? For example, if you set the repeat time to 12 hours, the timer will be set to null after the 12 hours passed and the repeat alert is triggered. If the value keeps still rising, you’ll get another fresh alert. So in fact, this would be just postponing the effect, correct?

  • What about using the cache status as an indicator if an alert is new. If the record does not exist and a new one is created, it’s a new/initial alert. When the end routine is triggered just purge the record from the cache. Would that be a solution?

  • The alert is not repeating anymore, but it seems like there’s still some issue with quantity sates and hysteresis:

2024-07-22 12:11:54.392 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Netatmo_Rain_Sensor_Rain_1h's new state is 0 mm which is no longer in the alerting state, previously alerted = true
2024-07-22 12:11:54.394 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Applying hysteresis with: 0 mm, 0.3 mm, 0.2 mm
2024-07-22 12:11:54.397 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Applying hysteresis, delta = NaN hystRange = 0.2 mm
2024-07-22 12:11:54.398 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Netatmo_Rain_Sensor_Rain_1h did not pass hysteresis, remaining in alerting state

Best,
Florian

No because in that case it reschedules itself instead of setting itself to null. So as long as there is a repeat scheduled the timer exists.

The repeat continues to reschedule itself until the Item is no longer alerting.

No, because the timer reschedules itself it still will exist even after calling the reminder rule. The timer continues to exist and rechedule itself (it’s a LoopingTimer from OHRT to be precise) and so the test to see if we’ve already alerted works.

Right now the existence of the reminder timer is what tells the rule that we’ve already alerted. I need to change that to use something else as we won’t always have a reminder timer after that first alert.

The record gets created on the very first event from a given Item and persists until the rule is unloaded. And since the tests to determine whether or not an Item is alerting or not requires information from the record (e.g. threshold and hysteresis) the record will always exist by the time we need to check to see if we’ve already alerted. It’s a chicken and egg problem.

I might need to add a new flag to the record which isn’t a big deal over all but I need to work through the edge cases to make sure that doesn’t break something.

OK, I think there are two bugs here then.

On line 285 can you add something to the log statement so I can tell if it’s correctly detecting that you are using Quantities? Something like:

console.debug('Applying Quantity hysteresis, delta = ' + delta + ' hystRange = ' + hyst);

That will tell me if it’s skipping that if and falling to the second if statement where it treats the values like numbers instead.

All three properties should be a Quantity by this point but if there is something wrong with stateToValue() that part might be failing. Some things have indeed changed in how openhab-js does Quantity so I might be running into one of those changes.

But I need more info to understand whether it’s failing to calculate the delta as Quantity or whether it’s failing to detect that the values are Quantity, or it’s failing to actually convert the values to Quantity.

I’ve struggled to reproduce the hystersis behavior. No matter what I try it is working for me. I’ll need some logs with the change I discussed above to make more progress on that problem.

I’m still working on the reminder timer problem.

1 Like

Hi,

apologies for the delay. Here’s the logs:

2024-08-05 10:23:43.958 [DEBUG] [ThresholdAlert.3ac6b6a352           ] - Starting threshold alert
2024-08-05 10:23:43.959 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Processing an Item event
2024-08-05 10:23:43.960 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Processing state 0.1 of type object
2024-08-05 10:23:43.961 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - state is a QuantityType, converting to Quantity: 0.1
2024-08-05 10:23:43.961 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Processing state 0.1 mm from Netatmo_Rain_Sensor_Rain_1h
2024-08-05 10:23:43.962 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Populating record from Item metadata or rule defauls
2024-08-05 10:23:43.984 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Converting threshold to value
2024-08-05 10:23:43.985 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Processing state 0.3 mm of type string
2024-08-05 10:23:43.985 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - state is a string: 0.3 mm
2024-08-05 10:23:43.986 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - state is a Quantity: 0.3 mm
2024-08-05 10:23:43.987 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Converting hysteresis to value
2024-08-05 10:23:43.988 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Processing state 0.2 mm of type string
2024-08-05 10:23:43.988 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - state is a string: 0.2 mm
2024-08-05 10:23:43.989 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - state is a Quantity: 0.2 mm
2024-08-05 10:23:43.990 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Processing event for Item Netatmo_Rain_Sensor_Rain_1h with properties:
  Threshold          - 0.3 mm
  Operator           - >=
  Invert             - false
  Reschedule         - false
  Alert Delay        -
  Reminder Period    - PT12H
  Alert Rule ID      - 9586d73c23
  End Alert Rule ID  - 9586d73c23
  Init Alert Rule ID -
  Gatekeeper Delay   - 0
  Hystersis          - 0.2 mm
  Rate Limt          -
  DnD Start          - 00:00
  DnD End            - 00:00
2024-08-05 10:23:43.991 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Checking if we are in the alerting state: 0.1 mm >= 0.3 mm
2024-08-05 10:23:43.993 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Result is false
2024-08-05 10:23:43.994 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Netatmo_Rain_Sensor_Rain_1h's new state is 0.1 mm which is no longer in the alerti>
2024-08-05 10:23:43.995 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Applying hysteresis with: 0.1 mm, 0.3 mm, 0.2 mm
2024-08-05 10:23:43.997 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Applying hysteresis, delta = NaN hystRange = 0.2 mm
2024-08-05 10:23:43.997 [DEBUG] [c6b6a352.Netatmo_Rain_Sensor_Rain_1h] - Netatmo_Rain_Sensor_Rain_1h did not pass hysteresis, remaining in alerting state

I made the changes as suggested so we’re definitely ending up in the else if clause for numbers and not for quantity states, which is weird because the logs above suggest all 3 variables are quantity states. Is there a reason why you check two times for undefined and not for alert.unit?

curr.unit !== undefined && alert.unit && hyst.unit !== undefined

Best,
Florian

That’s not deliberate but it shouldn’t make a difference. if it’s undefined it will be treated as false. But just in case go ahead and add the !== undefined for the alert.unit too.

I notice that some time ago but in my tests it didn’t seem to make a difference so I didn’t bring it up.

It’s definitely calculating delta as NaN. The log statement is ambiguous though because it’s the same for numbers and quantity types.

I’m going to upload a new version with some better logging in the hysteresis function and some additional error checking to see if we can’t figure out what’s happening here. Watch for an update and then try that version of the rule.

If you want to just edit your existing rule I’ll post the changes I’ve made too.

Believe it or not, but adding !== undefined to alert.unit fixed the comparison for whatever reason. I am getting end alerts now.

1 Like

Excellent news. I’m still not sure why it didn’t work before but I was going to submit that change anyway just to be consistent. Thanks for letting me know it worked!

So I just need to find two hours or so next to each other to work on the alerting problem when a reminder timer isn’t created and all the issues should be solved.

1 Like

Ok, I now also know why this is the case:

It seems alert.unit curr.unit, hyst.unit are defined, but they are all three null.

I added console.debug('Quantity units, curr = ' + curr.unit + ' alert = ' + alert.unit + ' hyst = ' + hyst.unit); right after the if statement and got "Quantity units, curr = null alert = null"

Looking at curr, alert, hyst, they are all Quantity objects and they carry values with the correct units, e.g. 0.3 mm, 0.1 mm, 0.2 mm. Also all mathematical operations such as curr.lessThan(alert) are working as expected despite curr.unit and alert.unit being null.

You can reproduce the issue yourself, just don’t know whether this is intended or a bug:

var a = Quantity('20 mm');
var b = Quantity('20 %');

console.log('a: ' + a.unit);
console.log('b: ' + b.unit);

8:09.678 [INFO ] [nhab.automation.script.ui.scratchpad] - a null
8:09.692 [INFO ] [nhab.automation.script.ui.scratchpad] - b Percent

Looking at the output of .unit, I would expect it to be a Length. That potentially means that mm is not a default unit and can thus be null. I wonder if thus a type check would be safer, e.g. if(curr typeof Quantity) instead of if(curr.unit !== undefined).

1 Like

I’m trying to get this to help detect battery levels not being reported for some time, but I must have it misconfigured as it never fires. My alert rule has a console.log() at the top of it, so I should get a log if it is ever called, but nothing happens.

I have a Group called gBatteryLevel which is a group of Number:Dimensionless Items. I have set the expire metadata on select Items to go to UNDEF (update state, not send command, should it be the latter?) after 24 hours. I can see that the states of a few of my Items have indeed changed to UNDEF, but I see no evidence this rule ran.

My configuration is:

configuration:
  dndEnd: 00:00
  rateLimit: ""
  invert: false
  initAlertRule: ""
  dndStart: 00:00
  alertRule: NotifySensorBatteryNotReporting
  endAlertRule: ""
  thresholdState: UNDEF
  defaultRemPeriod: PT24H
  operator: ==
  hysteresis: ""
  reschedule: false
  namespace: thresholdAlert
  gkDelay: 0
  defaultAlertDelay: PT24H
  group: gBatteryLevel
triggers:
  - id: "2"
    configuration:
      groupName: gBatteryLevel
    type: core.GroupStateChangeTrigger

If I run this rule manually, I see:

2024-09-03 21:08:57.217 [INFO ] [.Threshold Alert.BatteryNotReporting] - Rule triggered without an Item event, ExecutionEvent checking the rule config
2024-09-03 21:08:57.227 [INFO ] [.Threshold Alert.BatteryNotReporting] - Cancelling any running timers
2024-09-03 21:08:57.275 [WARN ] [.Threshold Alert.BatteryNotReporting] - gBatteryLevel contains Quantity states by thresholdStr UNDEF does not have units, comparison will revert to number or string comparison.
2024-09-03 21:08:57.310 [INFO ] [.Threshold Alert.BatteryNotReporting] - No end alert rule configured, no rule will be called when alerting ends
2024-09-03 21:08:57.311 [INFO ] [.Threshold Alert.BatteryNotReporting] - No initial alert rule configured, no rule will be called when the alert state is first detected
2024-09-03 21:08:57.353 [INFO ] [.Threshold Alert.BatteryNotReporting] - These Items do not have thresholdAlert metadata and will use the default properties defined in the rule: OutsideTemperatureBattery, IndoorTemperatureSNZB02PBatteryLevel, IndoorAqaraTemperatureHumidityPressureSensor_BatteryLevel, SecondBathTubMotionBatteryLevel, Front_Door_Outside_PIR_Battery, ZigbeeTemperature1BatteryLevel, FrontDoorInsideMotionSensorBatteryLevel, ZigbeeTemp2_Battery_Level, Kitchen_ZigBee_SNZB03P_Battery_Level, MBDRMClosetMotionSensorBatteryLevel, AtticHeatPumpXiaomiAqaraWaterLeakSensor_BatteryLevel, Leak_Sensor_Battery_Level, Outdoor_Sensor_Battery, Living_Room2_PIR_Battery, HWHeaterSensorBattery, HallSensorBatteryLevel, MasterBathSensorBatteryLevel, Living_Room_PIR_Battery, Garage_Door_Sensor_Battery, MasterBathDoorBattery, SecondBathTubDoorBattery, Garage_Temperature_Sensor_Battery, WashingMachineLidBattery, HalfBathBatteryLevel
2024-09-03 21:08:57.372 [INFO ] [.Threshold Alert.BatteryNotReporting] - Threshold Alert configs check out as OK

I’m sure there is something obvious I’m missing, but I don’t see it. Is using UNDEF for the expire value not possible? I can see gBatteryLevel changing in the events log, but it doesn’t switch to UNDEF - does that mean it is not reporting the change to this rule?

The Group is defined as:

Group:Number:MIN gBatteryLevel

thanks for any help

You’ve configured the rule to alert when the state of a member of gBattery (group: gBatteryLevel) remains in the threshold state of UNDEF (thresholdState: UNDEF) for 24 four hours (defaultAlertDelay: PT24H).

If no Items change to UNDEF and or no Item remains UNDEF for 24 hours, the rule won’t do anything becuase as configured, no Item is in the alerting state.

You should probably change the thresholdState to UnDefType so it captures NULL as well as UNDEF.

You should have expire timers on all members of gBattery to update the Item to UNDEF or NULL when the Item is not updated for a given amount of time. Then your alerting delay should be something short because you’ve already waited the expire time for the Item to change to UNDEF/NULL.

But, again, if your Items are not in the UNDEF state, they are not alerting and there’s nothing for the rule to do.

They are in the UNDEF state and have been there for more than 24 hours. So something should have happened?

I’ve updated the rule to trigger on UnDefType and trigger in 10s:

configuration:
  dndEnd: 00:00
  rateLimit: ""
  invert: false
  initAlertRule: ""
  dndStart: 00:00
  thresholdState: UnDefType
  alertRule: NotifySensorBatteryNotReporting
  endAlertRule: ""
  operator: ==
  defaultRemPeriod: PT24H
  hysteresis: ""
  reschedule: false
  namespace: thresholdAlert
  gkDelay: 0
  defaultAlertDelay: PT10S
  group: gBatteryLevel
triggers:
  - id: "2"
    configuration:
      groupName: gBatteryLevel
    type: core.GroupStateChangeTrigger

I’ll see if that does anything different.

2024-09-04 21:53:03.009 [INFO ] [s.Threshold Alert.BatteryNotReported] - Rule triggered without an Item event, ExecutionEvent checking the rule config
2024-09-04 21:53:03.011 [INFO ] [s.Threshold Alert.BatteryNotReported] - Cancelling any running timers
2024-09-04 21:53:03.012 [INFO ] [s.Threshold Alert.BatteryNotReported] - Threshold is UnDefType, this will cause Item states of NULL and UNDEF to be converted to UnDefType for comparisons.
2024-09-04 21:53:03.022 [INFO ] [s.Threshold Alert.BatteryNotReported] - No end alert rule configured, no rule will be called when alerting ends
2024-09-04 21:53:03.022 [INFO ] [s.Threshold Alert.BatteryNotReported] - No initial alert rule configured, no rule will be called when the alert state is first detected
2024-09-04 21:53:03.041 [INFO ] [s.Threshold Alert.BatteryNotReported] - These Items do not have thresholdAlert metadata and will use the default properties defined in the rule: OutsideTemperatureBattery, IndoorTemperatureSNZB02PBatteryLevel, IndoorAqaraTemperatureHumidityPressureSensor_BatteryLevel, SecondBathTubMotionBatteryLevel, Front_Door_Outside_PIR_Battery, ZigbeeTemperature1BatteryLevel, FrontDoorInsideMotionSensorBatteryLevel, ZigbeeTemp2_Battery_Level, Kitchen_ZigBee_SNZB03P_Battery_Level, MBDRMClosetMotionSensorBatteryLevel, AtticHeatPumpXiaomiAqaraWaterLeakSensor_BatteryLevel, Leak_Sensor_Battery_Level, Outdoor_Sensor_Battery, Living_Room2_PIR_Battery, HWHeaterSensorBattery, HallSensorBatteryLevel, MasterBathSensorBatteryLevel, Living_Room_PIR_Battery, Garage_Door_Sensor_Battery, MasterBathDoorBattery, SecondBathTubDoorBattery, Garage_Temperature_Sensor_Battery, WashingMachineLidBattery, HalfBathBatteryLevel
2024-09-04 21:53:03.059 [INFO ] [s.Threshold Alert.BatteryNotReported] - Threshold Alert configs check out as OK

Did they change to UNDEF after the Threshold Alert rule was loaded? If they were UNDEF to start there’s nothing to trigger the rule.