Storing only if N% different

Hello,

New to openhab. I have installed openhabian and have a large network of plugwise sockets connected and working well. These sockets record power usage in watts (decimals). I would like to make this data persistent so I have install an influxdb. I have all the values gong into the DB on change.

But I am getting a lot of data where the values are mostly just oscillating between small difference e.g. 57.132432 W then 58.32424 then back to 57.23422.

I can see I can create a strategy to store based on time say every minute. Is it possible to instead only store if the new value is different to the last value beyond some threshold? Like in my case n Watts?

Thanks

James

As far as I know this can’t be done with persistence directly.

But you can use a rule and a proxy item. Let the rule trigger on every change of the original sensor value. Then check if the new value and the old value differ more than the threshold you wanna have. If so update the proxy item with the state of the original item. And of course persistence know has to be set up for the proxy item.

I use this to smoothen sensor values for my light sensor. If needed I can post the actual code tomorrow evening when I’m back home

Hi Sebastian, would you be able to share your code when you get the chance? I’m hoping to be in a similar situation to James shortly (though only using a couple of Sonoff POWs) where I’ll want data on when exactly things change, but not an over-abundance of data, so a proven pre-filtering method would be much appreciated.
Thanks
Lee

Sure, here we go:

items:

Number sWzHelligkeit		"Helligkeit Wohnzimmer [%.0f Lux]"	  // filtered sensor value, updated by rule
Number sWzHelligkeit_Raw	"Helligkeit Wohnzimmer - Raw [%.2f Lux]"  { <binding for sensor> }

rule:

rule "WzHelligkeit"
// just update proxy item if sensor value changed more than 1Lux + round value
when
  Item sWzHelligkeit_Raw changed
then
  var float diff
  if (sWzHelligkeit.state instanceof DecimalType) {
    diff = (sWzHelligkeit.state as Number).floatValue - (sWzHelligkeit_Raw.state as Number).floatValue
  }
  else { diff = 99 }
  if (Math.abs(diff)>1) { 
    sWzHelligkeit.sendCommand(Math.round((sWzHelligkeit_Raw.state as Number).floatValue))
  }  

end

Some comments on the rule

  • the check for instanceof is used to prevent to rule to fail during to casting to float if the item state is ņull or UNDEF (esp. at startup)
  • the else statement is used to get an initial value in this case (doesn’t matter if it is 99 or 4711 or whatever, but it has to be bigger than your threshold. Another way would be to use a restoreOnStartup persistence for the proxy item
  • the threshold (in this case “1”) is defined statically in the code. It can also be represented by a Number item to make it changeable from the UI.
  • The round function is optional. You can of course also post the actual value from your sensor to the proxy item
1 Like

Thanks for that! I see exactly what you are doing and I will try and emulate.

Going to see if I can make it more generic to apply to a group of similar objects rather than having a rule for each!

Thanks again,

James

Again thanks for your help. After a bit more googling I wrote a generic function based on your code. It takes the two items and a threshold.

val org.eclipse.xtext.xbase.lib.Functions$Function3 filter = [
        NumberItem raw,
        NumberItem filtered,
        int threshold |
                var float diff
                if (raw.state instanceof DecimalType && filtered.state instanceof DecimalType) {
                    diff = (raw.state as Number).floatValue - (filtered.state as Number).floatValue
                }
                else { diff = 10000 }

                if (Math.abs(diff)>threshold) {

                        postUpdate(filtered, Math.round((raw.state as Number).floatValue))
                }
]

And I then just used these in my rules…

rule "LivingRoomTV_Power_Change"
when Item LivingRoomTV_Power_Raw changed then
        filter.apply(LivingRoomTV_Power_Raw, LivingRoomTV_Power,10)
end

rule "Server_Power_Change"
when Item Server_Power_Raw changed then
        filter.apply(Server_Power_Raw, Server_Power,5)
end

Its not rounding by a percentage n difference but an actual value, I think that is what I actually want. Its nice I can pass different thresholds in based on the object to cut down on the storage noise.

Thanks again for the help.

James

1 Like