HowTo limit range of Item values by definition

I use OH 3.3 file based configuration and rules.
Sometimes it happens that some sensor reading is false/unavailable and that causes unexpected results in calculations. E.g. the daily water consumption spikes to 40000 litres because the sensor was offline for some days. That looks awful in a chart.

I know I could build some workaround in a rule, but doing that for thousands of items is a nightmare.

Is possible to limit the possible numeric range directly in the items definition, e.g.

Number dailyWater “DailyWater” (gWater) {channel=“http:url:ESP32Cam:Channel_WaterReading” , minValue = 0, maxValue=200 }

The range transformation sounds tempting but it apparently is meant for triggering rules.

No.

well yes, but if you’ve got thousands of Items generating false values it might be worth reviewing exactly why.

I don’t know what that means.

For numeric Item states updated from a channel, you could apply a profile with SCALE transformation, although I think that will not do what you want.
A JS transformation can be used to select pass-through or block.

@rossko57 Well, usually things go wrong when a sensor fails and values expire. I definitely look into this whenever it happens but as it happens rarely, I still sometimes encounter failures after years of flawless operation.

Defining limits for Items would add an additional layer of safety and would make everything more robust.
I looked into SCALE, it is not exactly what I want. It filter values coming from a channel but not those assigned to an item by a rule.

What I would like is an item defined as

Item MyNumber {min=0, max=100}

And that Item can never ever have any other values (maybe undef or so) If a rule updates it with the value 200, that value is intercepted and limited to 100.

Indeed, but umm, if it is your rule that is assigning incorrect values, it would seem smart to make your rule smarter so as not to do that.
Rules are allowed to postUpdate state UNDEF

What you want does not exist (yet).

This is exactly the sort of thing the expire functionality was created for.
If updates stop arriving at an Item, it can set the state to some chosen value, like 0 or UNDEF
It does depend on the technology involved (binding) if updates stop arriving or not.

There is also a rule template in the marketplace that can be used to detect and alert when Item expire. I have a bunch of sensors that report on a pretty regular basis. So I set an expire on those Items to update the Items to UNDEF when there is no report. I use Open Reminder [3.3.0;3.4.9) to detect when that happens, wait a little bit in case it’s only momentary (i.e. debounce) and then call another rule where redial action can take place (in my case I generate an alert notification).

For my sensors I use the following config values for the rule:

configuration:
  dndEnd: 08:00
  reschedule: false
  defaultTimeout: PT5m
  invert: true
  alertRuleUID: sensor_offline_alert
  groupTriggers: Sensors
  dndStart: 22:00
  repeatPeriod: PT8h
  timeoutMetadata: rem_time
  alertState: UNDEF

That will alert me except between 22:00 and 08:00 when a sensor goes offline and call sensor_offline_alert every 8 hours until the sensor goes back online. Notice there’s no code. That’s the beauty of rule templates, it’s just config, not coding.

I could set a different initial timeout (i.e. debounce period) on an Item by Item basis with rem_time metadata but I just use the default five minutes for this rule.

The sensor_offline_alert rule looks like this:

configuration: {}
triggers: []
conditions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/javascript;version=ECMAScript-2021
      script: >
        var { itemRegistry } = require('@runtime');


        //console.log('Received an alert on ' + alertItem);


        var equipment = actions.Semantics.getEquipment(itemRegistry.getItem(alertItem)); // requires the Java Item, not JS Item

        var statusItem = items.getItem(equipment.name + '_Status');


        //console.log('received an offline alert for equipment ' + equipment.name + ' and status Item ' + statusItem.name);


        // Just went offline

        statusItem.state == 'ON';
    type: script.ScriptCondition
actions:
  - inputs: {}
    id: "1"
    configuration:
      type: application/javascript;version=ECMAScript-2021
      script: >-
        var { itemRegistry } = require('@runtime');

        var {alerting} = require('rlk_personal');

        var logger = log('Sensor Offline');


        var equipment = actions.Semantics.getEquipment(itemRegistry.getItem(alertItem)); // requires the Java Item, not JS Item

        var statusItem = items.getItem(equipment.name + '_Status').postUpdate('OFF');


        alerting.sendAlert(equipment.label + ' has stopped reporting and is likely offline');
    type: script.ScriptAction

Notice that this rule uses the semantic model to ensure that only one alert per equipment is generated.

I’ve another pair of rules to alert me when it goes back online.

Beyond that the already mentioned JS Transformation could be used to limit the values to a range as you describe for values that come from Channels. For the values coming from your rules, well like @rossko57 said, don’t do that. Add something to your rule to prevent that. You have full control over the rule.

@rlkoshak , @rossko57
Thank you both for the elaborate answer and the time you put into this. I really appreciate this.

Unfortunately, I don’t quite recognize the syntax of the rule you propose as I am using DSL rules only. I did some digging and was able to create a workaround for now that hopefully adds stability and log entries for debugging. It does check the state of an item for null and if it is within bounds.


val check =  [ GenericItem s, Double min_ , Double max_    | 
	var Double retval=min_
	var Double min_t = min_
	var Double max_t = max_
	
	if (min_>max_) {
		logInfo("check", "WARNING "+ s.name+" limits faulty. min > max. Swapping them now.")
		min_t = max_
		max_t = min_
	}
	

	if (s.state !== null)   {
		retval = (s.state as Number).doubleValue()
	} else {
		logInfo("check", "WARNING "+ s.name+" is null. Changed to min value.")
	}
	if (retval < min_t) {retval = min_t  }
	if (retval > max_t) {retval = max_t  }
	return (retval)
]

and the rule for testing:

 
rule CheckMinMaxTest
when 
    Time cron "0 0/1 * * * ?"  // every 1 minutes
then 
    var rangedLimited =  check.apply(Vito_Aussentemperatur24h, 0.0, 3.0)
    logInfo("checktest","original "+ Vito_Aussentemperatur24h.state+" changed to "+ rangedLimited)
  
end

Seems to do the trick. Now would you happen to know if I can put that into a library or header file and import/include it for all my other rules ?

Note that this is never, ever, true.
If an Item object exists, it has a non-null state.
That state’s value might be NULL, but NULL is a value and is not null.
.state can also be UNDEF

That’s a UI rule using JS Scripting. But you could use any language you desire.

If you were to:

  • add an expire to the sensor Item so they go to UNDEF when not updated for too long
  • add all those Items to a Group
  • write your rule to alert (see below)
  • install and instantiate a rule using the Open Reminder rule template

The only code you’d have tow write is as follows:

rule "Alert when sensor is offline"
when
then
    sendBroadcastNotification("Item " + alertItem + " is offline!");
end

Or how ever you generate alerts. Detecting that the sensor went offline, and setting timer management and such is all handled by the rule template. All you need to mess with is sending the actual alert.

That’s what my reply is saying. It addresses reporting “when a sensor fails and values expire” with minimal coding on your part.

Little typo in :

=>

sendBroadcastNotification("Item " + alertItem + " is offline!");
1 Like