OH1: Get the name of the item which called the rule?

(Max G) #1

Building on the example found here:


… which loops through sequentially named items; starts them off, and creates a timer, which on expiry switches an item OFF, and call the next one ON.

I need to issue further commands when the timer expires.
However, the timer only accepts a val (const) and not var (variable).

The problem is: I want to record the water used by the valve being switched OFF and store it in the item Irrigation1_i_ValveVolume.

After giving this some thought I figured that a new rule is required on valve OFF; e.g.

rule "Irrigation group 1 valve cascade OFF"
  when
    Item Irrigation1_1 received command OFF or
    Item Irrigation1_2 received command OFF or
    Item Irrigation1_3 received command OFF or
    Item Irrigation1_4 received command OFF
  then
...
end

Hmm, searching the forum revealed this:

… short answer: not possible…

However… Rich to the rescue, with:

Adding the rule:

rule "Irrigation group 1 valve cascade OFF"
  when
    Item Irrigation1_1 received command OFF or
    Item Irrigation1_2 received command OFF or
    Item Irrigation1_3 received command OFF or
    Item Irrigation1_4 received command OFF
  then
    val trigger = gIrrigation1.members.sortBy[lastUpdate].last
    logInfo("Irrigation1.off", "... trigger.....: {}", trigger)

… gives me this… (trigger is 1 x valve 1 and 3 x valve 4)

2018-03-24 19:41:20.357 [INFO ] [nhab.model.script.Irrigation.0] - System Start: Irrigation .
2018-03-24 19:41:28.312 [INFO ] [hab.model.script.Irrigation1.0] - System Start: Irrigation initialise state: done.
2018-03-24 19:41:59.961 [INFO ] [hab.model.script.Irrigation1.1] - Irrigation group 1 started...
2018-03-24 19:42:03.757 [INFO ] [hab.model.script.Irrigation1.1] - ... turning Irrigation1_1 ON
2018-03-24 19:43:29.213 [INFO ] [enhab.model.script.Irrigation1] - ... turning Irrigation1_1 OFF
2018-03-24 19:43:35.267 [INFO ] [o.model.script.Irrigation1.off] - ... trigger.....: Irrigation1_1 (Type=SwitchItem, State=OFF)
2018-03-24 19:43:37.202 [INFO ] [enhab.model.script.Irrigation1] - ... turning Irrigation1_2 ON
2018-03-24 19:44:39.416 [INFO ] [enhab.model.script.Irrigation1] - ... turning Irrigation1_2 OFF
2018-03-24 19:44:39.465 [INFO ] [o.model.script.Irrigation1.off] - ... trigger.....: Irrigation1_4 (Type=SwitchItem, State=OFF)
2018-03-24 19:44:40.559 [INFO ] [enhab.model.script.Irrigation1] - ... turning Irrigation1_3 ON
2018-03-24 19:45:40.799 [INFO ] [enhab.model.script.Irrigation1] - ... turning Irrigation1_3 OFF
2018-03-24 19:45:40.847 [INFO ] [o.model.script.Irrigation1.off] - ... trigger.....: Irrigation1_4 (Type=SwitchItem, State=OFF)
2018-03-24 19:45:41.936 [INFO ] [enhab.model.script.Irrigation1] - ... turning Irrigation1_4 ON
2018-03-24 19:46:42.155 [INFO ] [enhab.model.script.Irrigation1] - ... turning Irrigation1_4 OFF
2018-03-24 19:46:42.199 [INFO ] [o.model.script.Irrigation1.off] - ... trigger.....: Irrigation1_4 (Type=SwitchItem, State=OFF)
2018-03-24 19:46:43.903 [INFO ] [enhab.model.script.Irrigation1] - Irrigation group 1 finished.
2018-03-24 19:46:48.346 [INFO ] [enhab.model.script.Irrigation1] - Irrigation group 1 -> reset Now Switch

There is only a one second sleep between the OFF and ON…
Happy to extend to longer value?! changed to 5 seconds -> same outcome.
Or does this need a different approach?

0 Likes

(hr2) #2
0 Likes

(Max G) #3

Thanks, it confuses the heck out of me… :frowning:

0 Likes

(Rich Koshak) #4

Tl;Dr is when using receivedCommand the rule triggers before the item updates. This was true for oh 1.x too. So to get the actual commands sent to the item you must use receivedCommand instead of MyItem.state.

0 Likes

(Josar) #5

Further improvement would be Member of group trigger.

0 Likes

(Max G) #6

Thanks… maybe its doing my head in – trying to figure this out for the last six hours flat :frowning:
Could you please elaborate on that sentence? (It makes no sense to me – sorry.)

Looks like an OH2 thing…?
I am still on OH1.

0 Likes

(Josar) #7

Oh sorry didn’t grasp that.

Use the implicit variable receivedCommand instead of the item.state . This contains the actual command which triggered the rule.

0 Likes

(Max G) #8

Instead of:
Item Irrigation1_1 received command ON or
use this:
Item Irrigation1_1 received command or
???

I think the day has been going for too long… I have started sending MQTT commands to items, because I can’t update the item directly (and crap like that)… off to bed now…

0 Likes

(Josar) #9
 logInfo("RuleExamples", "Command which triggered the rule: " + receivedCommand)

1 Like

(Rich Koshak) #10

Longer explanation.

When a command is generated the event gets put on the event bus.

Immediately the rule gets triggered and executes.

At the same time the Item registry gets updated with the new state.

So for a brief time, the rule will be running but the Item registry will not yet have updated.

When you call MyItem.state what you are getting is the value stored in the registry. So for a brief time when you call MyItem.state in a rule triggered by received command you will get the old state instead of the commanded state.

This is why when you have a rule triggered by receivedCommand you should use receivedCommand instead of MyItem.state.

1 Like

(Vincent Regaud) #11

Do you mean "you should use receivedCommand instead… ?

0 Likes

(Rich Koshak) #12

I did. Thanks for catching that. Lack of sleep…

0 Likes

(Max G) #13

:slight_smile: tell me about it.

Again thank you guys for your help.
However, even after a nights sleep, I do not know what to do with your answers.

Since I cannot use the timer to deal with calculations when it ‘expires’, I need to have another rule that deals with the valve OFF state. So, I started this rule:

rule "Irrigation group 1 valve cascade OFF"
  when
    Item Irrigation1_1 received command OFF or
    Item Irrigation1_2 received command OFF or
    Item Irrigation1_3 received command OFF or
    Item Irrigation1_4 received command OFF
  then
    val triggerItem = gIrrigation1.members.sortBy[lastUpdate].last
    logInfo("Irrigation1.off.01", "... triggerItem..........: {}", triggerItem)
    
    val currValveName   = triggerItem + receivedCommand.toString
    logInfo("Irrigation1.off.02", "... currValveName........: {}", currValveName)
end

With the same ideas as the start rule, though different approach:
gIrrigation1.members.sortBy[lastUpdate].last which ought to give me the last (youngest = greatest) time stamp.

If I understand you correctly, I am querying the ‘state database’ which may not have an update yet, and should work with receivedCommand.

I sort of get that, but I do not want the items state, I want its name. The output of above rule is:

[odel.script.Irrigation1.off.01] - ... triggerItem..........: Irrigation1_4 (Type=SwitchItem, State=OFF)
[odel.script.Irrigation1.off.02] - ... currValveName........: Irrigation1_4 (Type=SwitchItem, State=OFF)OFF

At present, this rule always returns valve 4 when looping through 1…4

I am really sorry, but I just don’t get it. Get what? How I can get the item name that triggered this rule.
Do I need different rule? One per valve OFF?
I have four rules now, as I could not figure out how to use only one (due to above the issue).

Here what I want to achieve, but it looks very flawed (this openHAB DSL does my head in, for some unknown reason, I do seem to get it – just finished coding the hardware 300 lines of code in C – no problem) – anyway… I wish I could do a postUpdate() with the state of another item; which I couldn’t, then used variables and published to an item via MQTT. Somehow I think this is not right.

These rules are the same for each valve:

rule "Irrigation group 1 valve 1 OFF"
  when
    Item Irrigation1_1 received command OFF
  then
    var int valveVolume = (PumpStation1_Meter.state as Number).intValue
    valveVolume = valveVolume - Irrigation1_VolumePrevious
    publish("mymosquitto", "ArgyleCourt/Property/PumpStation1/Volume1", valveVolume.toString)
    
    Irrigation1_VolumePrevious = (PumpStation1_Meter.state as DecimalType).intValue
    PumpStation1_VolumeSession = PumpStation1_VolumeSession + valveVolume
    
    var int valveFlow = (PumpStation1_Flow.state as Number).intValue
    logInfo("Irrigation1.off", "... valveFlow -> {}", valveFlow)
    publish("mymosquitto", "ArgyleCourt/Property/PumpStation1/Flow1", valveFlow.toString)
    
end

There are two items, which receive the MQTT command; which I wanted to update directly (but failed).

Number   Irrigation1_1_ValveVolume "Zone 1: Volume [%d]" <sprinkler>|(gIrri1All) {mqtt="<[mymosquitto:ArgyleCourt/Property/PumpStation1/Volume1:state:default]"}
Number   Irrigation1_1_ValveFlow   "Zone 1: Flow [%d]"   <sprinkler>|(gIrri1All) {mqtt="<[mymosquitto:ArgyleCourt/Property/PumpStation1/Flow1:state:default]"}

Any help appreciated.

[edit] Also, would appreciate feedback on the code itself; as it would highlight where I lack understanding. don’t be shy, I am an ex-German, hence, I can take it straight :slight_smile:

0 Likes

(Vincent Regaud) #14

To get the name if the item that triggered the rule you can use the implicit variable, triggeringItem

So you can do:

sendCommand(triggeringItem.name.toString + "_ValveVolume", 999)
sendCommand(triggeringItem.name.toString + "_ValveFlow", 999)
1 Like

(Max G) #15

have tried these versions:
val triggerItem = triggeringItem
val triggerItem = gIrrigation1.triggeringItem
val triggerItem = gIrrigation1.members.triggeringItem.toString
var String triggerItem = triggeringItem.name.toString
all throw errors… The method or field of triigeringItem is undefined in Designer.

I would like to have the name of the item in a var so I can mod the ‘number’ of the valve in the item.
E.g. var nameOfItem = triggeringItem.name.toString

[edit] aha; triggeringItem is an OH2 thing?!

0 Likes

(Rich Koshak) #16

You probably need to added a Thread::sleep because in this case I think you are running into another timing issue. It takes even longer for an Item’s state to get saved to a database and when you call lastUpdate you are querying the database.

You have a further issue that could be caused by what state your .persist strategy is. For example, if you persist every minute and just so happen to trigger the rule near that time then last update will reflect that periodic time. If you use an every update strategy then lastUpdate will reflect the last update, whether it was an update or a command.

In OH 1.x, the only way to reliably know without timing problems or dealing with the vaguaries of persistence is to have one rule per Item. Getting the item that triggered a rule until 2.2 release has always been a hack and unreliable.

In OH 2.2 release and beyond you have access to the triggeringItem implicit variable which will always be the Item that caused the rule to trigger. In 2.3 snapshot there is the Member of trigger that will populate triggeringItem with the member of the group that caused the rule to trigger.

There code itself looks good to me.

1 Like

(Max G) #17

… is as I understand OH2 (not OH1 I am using, sorry)

persist is;

gIrri1All*			: strategy = everyMinute, everyChange, restoreOnStartup

OK, thank you for the explanation; I think I understand the underlying issues now…
Is it then a safe idea/approach to use one rule and add per valve an:

if(valve1 received command off) valveName = item.name
...
if(valve4 received command off) valveName = item.name

use this global val to then run the calculations?

Otherwise 4 rules it is; but I will have a second pump station with 8 valves. :frowning:

[or maybe it is time to move to OH2]

0 Likes

(Max G) #18

Just for completeness of the discussion…
Most certainly a timing issue…

2018-03-25 11:43:31.029 [INFO ] [enhab.model.script.Irrigation1] - Irrigation group 1 finished.
2018-03-25 11:43:37.194 [INFO ] [enhab.model.script.Irrigation1] - Irrigation group 1 -> reset Now Switch
2018-03-25 11:43:42.345 [INFO ] [odel.script.Irrigation1_4.off1] - ... valveVolume .............. -> 10
2018-03-25 11:43:46.518 [INFO ] [.m.script.Irrigation1.Finished] - VolumeSession (added) -> 13
2018-03-25 11:43:48.182 [INFO ] [odel.script.Irrigation1_4.off2] - ... added to VolumePrevious .. -> 1030
2018-03-25 11:43:48.641 [INFO ] [.m.script.Irrigation1.Finished] - SessionVolume -> 13
2018-03-25 11:43:51.087 [INFO ] [odel.script.Irrigation1_4.off3] - ... VolumeSession valve ...... -> 23
2018-03-25 11:43:52.927 [INFO ] [odel.script.Irrigation1_4.off4] - ... valveFlow ................ -> 9

The learning here is, three rules involved Irrigation1, Finished, and Irrigation1_4.
The order should be:

Irrigation1_4
Irrigation1
Finished

I have added the code from Finished into Irrigation1_4… this works.

Interestingly enough, there are 20 seconds in the finish run, which should happen in no mare than 2.

Well, whatever it is… this case is closed. :slight_smile:

Thanks for all your help! – it is always hard to get into the code/problem of someone else.

0 Likes

(Rich Koshak) #19

I would encourage this.

The problem is those if statements won’t work. Once you are inside the rule, there is no direct way to know what item triggered the role.

The lastUpdate hack can sometimes work but as you are seeing there are a lot of cases where it won’t and everything needs to be configured just right.

You can make it work but:

  • you can’t use rrd4j, the once per minute strategy will cause it not to work. mapdb works though
  • you have to use every command as the strategy if you care about commands or every update if you care about updates
  • you have to add a small sleep before the sort by lastUpdate. The amount of the sleep will have to be determined experimentally.
  • and even with all of the above, as with anything that depends on timing, there will be times when the wrong answered is calculated

The lastUpdate hack has always been a workaround. Now that we have triggeringItem and soon to have Member of triggers I discourage it’s use. If you have rules like this I strongly encourage upgrading to 2.2.

If you do four rules, you can put the logic into a lambda.

1 Like

(Max G) #20

Thank you, all understood.

A 15 seconds sleep for the ON command in the timer, solved the funny calculation issues; all runs now in sequence as envisaged.

(If I only had time) … I installed OH2 on a new rPi last August, got stuck on the screen showing which admin tool to use… (you answered it back then) and I have not moved on it since – it still stands on that screen :slight_smile:

And a big thank you for the work you put into this community helping me and others! I certainly appreciate it.

0 Likes