[JSR223] Trigger "Item GROUP_NAME received update" does not work

your code works, do you have this import on top of your file?

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

Thanks for your feedback.

I defined all three imports:

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

strange, when i try your code in a new file it works for me:

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

@rule("Trigger for GROUP_NAME received update")
@when("Item ivi received update")
def GROUP_NAMEReceivedUpdate(event):
    LogAction.logInfo("presence-new", "Item SK {} received update: {}", event.itemName, event.itemState)
    # STUFF

loig:

2020-05-20 13:44:14.021 [INFO ] [.smarthome.model.script.presence-new] - Item ivi received update: OFF

… i used a item “ivi” for testing purposes - do you really use an item (not a group-member because you call it “group_name”)?

The trigger for "@when("Item ITEM_NAME received update") works fine. I am using a Group. Here are some more details:

Group:Switch:OR(ON,OFF) gPRESENTCHRISTOPH

The GROUP_NAME in my examples has to be replaced by gPRESENTCHRISTOPH. And, Yes, the Group contains several Items of type Switch. The are updated frequently.

@rule("Trigger for gPRESENTCHRISTOPH received update")
@when("Item gPRESENTCHRISTOPH received update")
def gPRESENTCHRISTOPHReceivedUpdate(event):
    LogAction.logInfo("presence-new", "Item {} received update: {}", event.itemName, event.itemState)
    # STUFF

aah, then i think you have to write:

@when("Member of gPRESENTCHRISTOPH changed")

sorry, has to be

@when("Member of gPRESENTCHRISTOPH received update")

and then you will get the item name and the state with:

    item = event.itemName
    state = event.itemState

The Member of trigger condition is NOT functionally equivalent to triggering from the Group Item itself.
Consider that a switch can change without changing group state.

In this case @cweitkamp is looking for updates - it is true that a member update should always trigger a group update, but this is a workaround.

Yes, exactly. An enhanced DSL example:

rule "Trigger for GROUP_NAME received update"
when
    Item GROUP_NAME received update
then
    logInfo("presence", "Item GROUP_NAME received update: {}", newState)
end

rule "Trigger Member of GROUP_NAME received update"
when
    Member of GROUP_NAME received update
then
    logInfo("presence", "Item {} of GROUP_NAME received update: {}", triggeringItem.name, newState)
end

The first rules always gives me the Group state - after the aggregation function has been applied. The second rule yields the member state - which is not what I am expecting.

2020-05-20 12:09:19.029 [INFO ] [ipse.smarthome.model.script.presence] - gPRESENTCHRISTOPH received update: ON
2020-05-20 12:09:19.064 [INFO ] [ipse.smarthome.model.script.presence] - Member item1 of gPRESENTCHRISTOPH received update: ON
2020-05-20 12:09:20.669 [INFO ] [ipse.smarthome.model.script.presence] - Member item2 of gPRESENTCHRISTOPH received update: OFF
2020-05-20 12:09:20.674 [INFO ] [ipse.smarthome.model.script.presence] - gPRESENTCHRISTOPH received update: ON

2020-05-20 12:09:24.738 [INFO ] [ipse.smarthome.model.script.presence] - gPRESENTCHRISTOPH received update: ON
2020-05-20 12:09:24.745 [INFO ] [ipse.smarthome.model.script.presence] - Member item1 of gPRESENTCHRISTOPH received update: ON
2020-05-20 12:09:27.645 [INFO ] [ipse.smarthome.model.script.presence] - gPRESENTCHRISTOPH received update: ON
2020-05-20 12:09:27.654 [INFO ] [ipse.smarthome.model.script.presence] - Member item2 of gPRESENTCHRISTOPH received update: OFF

// Edit: Just as a side note: the @when("Member of GROUP_NAME received update") trigger in Jython is working too.

@cweitkamp, the NGRE does not have a GroupItemStateEvent and ItemStateUpdate is not implemented for GroupItems. I can understand the reasoning and it could be pretty dangerous for smaller systems with large groups if this were to be implemented.

Could you use this instead?

@when("Item gPRESENTCHRISTOPH changed")

BTW, your original rule will trigger if you update the group directly, but not through the aggregated group function…

event.postUpdate("gPRESENTCHRISTOPH", "ON")

That’s quite a drawback, really. It’s not unreasonable to use a Group to detect an update, without caring who dunnit. I suppose Member of updated and ignoring the member has the same practical effect.

I would see Group changed as vital in many circumstances, but you’re saying that works and only updated is missing.

In fairness, it can be a bit weird in e.g. DSL Rules, as multiple Group updates can be fired from one member change.

But … you don’t do that to Groups. (I think you can’t do that, in practice)

Correct

For example, you can post an update to a group of dimmers in a rule, all of the mebers will be sent the update and ItemStateUpateTrigger will pick it up. Manually turning on the lights or individually updating them through a UI or rule will not be caught by ItemStateUpateTrigger.

Thank you for the links. That brings light into darkness. I can understand the reasons. But it makes me wonder why it is working in DSL rules. Nonetheless I think I can change my rule to use the @when("Item GROUP_NAME changed") trigger instead. Everything else would be a potty workaround.

Btw. We should remove it from the examples in helper library docs.

I updated the docs as soon as I saw this topic :smile:! I didn’t remove anything though, since this will still work, just not for updates made through group functions.

Uh, that’s how commands work. But the last thing a Group should be doing is distributing update to all members.

Why do you feel this way? One of the main pieces of functionality for groups is to bulk send updates or commands.

Groups distribute commands only to members. Never state updates. It works exactly the opposite, where a Group state update (and possible change) is derived from member updates. We’re at cross purposes somewhere.

Click… my thinking has gone backwards and you’re absolutely correct. I’m glad I asked or I would have been scratching my head all day wondering about your comment!

Before the availability of Member of triggers, we used to have all sorts of troubles in DSL because a single member change could fire a burst of Group updates. Something to do with iterations calculating Group state.

Using Member of xxx updated overcomes that problem, only one event, hurrah!
but
brings its own limitation. Should that member update eventually cause a change in Group state (via the aggregation function) it hasn’t happened yet at the member update event.
If the triggered rule examines Group state, you have a race condition.

Really the same race exists in DSL for most of a “burst” of Group update events, but the very last event is the final update of the final state. In many cases that’s good enough.

If I understand the intent correctly, you need to trigger on updates to any member or if the group itself receives an update. I also presume that you don’t care what the source of the update is if you’re triggering this way in the DSL rule. Therefore you can just use both Member of and Item triggers to get the same trigger conditions you had.

Further, you could check if the triggering item was the group or one of its members and have different behaviour if needed.

The ugly way we used to figure out triggeringItem before there was a triggeringItem implicit variable and Member of Rule triggers was as follows:

  • save all the members of the Group to persistence
  • trigger the Rule on updates to the Group
  • set up a Rule latch so only one instance runs at a time (optional)
  • sleep for long enough for Persistence to write the new state to the DB
  • val triggeringItem = MyGroup.members.sortBy[ i | i.lastUpdate ].last or something like that, it’s been years since I’ve seen it

And indeed, the Rule would trigger n-1 times where n is the number of members of the Group.