Modifying/intercept item state with rule possible?

is there a possibity to overwrite an item state before it get’s persisted ?
i have an power meter with current transformers connected to my system, i need to recalc the value with a factor of 5. Do i need two items or is that possible with jsut one item ?

  • is there a way with transformation rules
  • rules itself ?

thanks in advance

Lars

That depends on how your item gets this state. For example the mqtt binding allows an incoming transformation. That way the state is corrected before it is stored and persisted.
If such is not possible I would use a second item and a rule.

1 Like

Take a look into profiles, in your case using the JavaScript transformation.

But note that transform profile only currently works with String type Items, so probably of limited use here.

i read the description of pacive, there is no hint, that it is only working on string items…

one question to that: the item is already created, that is an addional item definition for transformation for the same item, just to get to let the transformation service know?

Yes, two Items if you cannot apply the transformation in the binding that you have not told us about.

It is possible to make a rule that will transform a single Item’s state when it changes. But think about the logic here - what happens next when you change the Item state? It goes around again. And again.

yes that would be the next question, if there is any possibility way to “inject/intercept” values in the processing chain

Tell us what the chain is for a meaningful answer i.e what is one end (your Item type?) and what is at the other end (what binding or other data source are you starting with?).

There are three two approaches, two of which have already been mentioned.

Approach Advantage Disadvantage
  1. transformation to adjust the value at the binding level | Usually pretty easy to apply, Map, Scale, and JavaScript are most useful | Every value received get’s returned (no filtering out of values), not all bindings support them
  2. Profile | Very easy to apply | Only works on Items with Channels, only can work with String Items
  3. Proxy Item and Rule | Works with any Item, can filter values | Requires a second proxy Item
  4. Rule | Works with any Item, can filter values | Requires removing the Item from the .persist file

1 and 2 have already been discussed. As mentioned, you cannot insert or throw away any values with this approach. Every received value must result in an Item state. Profiles have further limitations.

3 has also already been discussed here. Create a proxy Item which gets persisted. Then have a Rule that only updates that proxy Item when the Item linked to the sensor is valid. The Item linked to the sensor does not get persisted itself.

4 is an approach not yet mentioned. In this approach, remove the Item from the .persist file. We will not be persisting the data automatically. Instead when the Item changes trigger a rule and only if the state is valid then call MyItem.persist() (if you have more than one persistence engine, you need to pass the name of the database engine you want to persist to. If you want to replace the value just call update without calling .persist().

from core.actions import PersistenceExtensions
from core.rules import rule
from core.triggers import when

@rule("Persist Foo")
@when("Item Foo changed")
def persist_foo(event):
    if event.itemState < DecimalType(0) and event.itemState > DecimalType(100):
        persist_foo.log.info("State {} is not valid, changing to 0".format(event.itemState)
        events.postUpdate(event.itemName, event.itemState)
    else:
        PersistenceExtensions.persist(ir.getItem(event.itemName), "rrd4j")

rule "Persist Foo"
when
    Item Foo changed
then
    if(newState < 0 and newState > 100){
        logInfo("Persist Foo", "State " + newState + " is not valid, changing to 0")
        Foo.postUpdate(0)
    else {
        Foo.persist("rrd4j")
    }
end

Instead of updating you can just ignore the value when it’s out of range. You can sue what ever criteria in the if that is appropriate.

In the Rules above, the Rule will be called again with the postUpdate(0) but the next time the value passes the criteria and gets persisted, stopping the loop.

thank’s a lot for listing all possibilities!!
i will go with the proxy item

I have an additional question here. I have definied strategies, that will persist items every 2 or 5 minutes. I left the default = everyChange. The Items to persist use the 2 or 5 Minutes strategy - not everyChange.

So when I create a rule that fires on Item of Group changed, and I change the value in the rule and postUpdate - would it work? Or will the wrong value still be persisted? Would I still need to have to remove the items from .persist file? (As it is a nested group, I would like to avoid this :wink:

:person_shrugging: You don’t show your file and your description leaves way too many details out.

If the Item is configured to persist every two minutes, the value will be saved on the next two minute poll period. If it’s set to persist every five minutes, it will be saved on the next five minute poll period.

If it’s not configured to persist at all then it won’t be saved to persistence at all.

.persist files are an allow list. Only those Items explicitly listed get saved. But there are two short cuts. If the Item is a member of a Group which is listed in the file with *, it will get saved based on that strategy. If there is a * entry then that policy applies to all Items.