sorry, another question about changed to ON or changed to OFF:
rule "test"
when
Item test changed
then
if(test.state == ON) {
stuff1.sendCommand(ON)
}
if(test.state == OFF) {
stuff2.sendCommand(ON)
}
end
will this work reliably? I remember I might have had some issues with these, something like the item state does not change fast enough so when the rule executes it reads the old state, so I separated it into 2 rules, one with “test changed to ON” and another “test changed to OFF”. Or am I mistaken and this should work within a single rule?
I think I prefer the first version, easier to read and follow.
There might be a trick in RulesDSL to do this more easily, but I’m more used to JRuby and this is how I would do it in JRuby:
rule "test" do
changed test1, attach: example1
changed test2, attach: example2
changed test3, attach: example3
# add as many as you like
run do |event|
stuff.on if event.attachment.on?
end
end
No, this won’t work for two reasons:
For time triggers, triggeringItemName simply doesn’t exist, currently.
Even if it existed, you can’t write triggeringItemName.state because xxxItemName would be a simple string, not an item object. In RulesDSL it’s a bit messy, but doable to grab the item object from a name.
In JRuby, you could do it like this (right now already implemented)
rule "datetime item trigger" do
every :day, at: TestAlarm1
run do |event|
logger.info "The triggering item state is: #{event.item.state}"
end
end
Although, theoretically, the item’s state should be very close to the current time since that’s what caused the rule to trigger.
I’m pretty sure that the given code in Postings 1 and 2 does not work as intended, because triggeringItemName is a string variable, so there is no method .state for this variable.
The a more efficient way would be to build two groups:
Now it’s possible to use another Trigger and to shorten the code:
rule "test"
when
Member of gTtest changed
then
val strItem = triggeringItem.name.split("_").get(1)
val swItem = gExample.members.filter[i|i.name.endsWith(strItem)].head
if(swItem.state == ON)
stuff.sendCommand(ON)
end
Keep attention to the fact, that I changed the naming slightly, as it’s way easier to get the second name from the first name when using underscores. But of course it’s possible to get the part after “test” in other ways.
Afaik Time is will not set triggeringItemName.
Please be aware that the rule isn’t triggered on a command, but on a change, that is: the state of the item changed.
In question of the third posting: You have typos in the code (more closing brackets then opening brackets). A cleaner solution:
rule "test"
when
Item test changed
then
if(newState == ON)
stuff1.sendCommand(ON)
else if(newState == OFF)
stuff2.sendCommand(ON)
end
newState is another implicit variable which is set when the rule is triggered by a changed or received update event.
If a rule is triggered by a received command there is another implicit variable receivedCommand.
HI, thanks for all the answers and clarifications.
This code actually indeed works, even though you say it shouldn’t.
Is there any better/official way then triggeringItemName.state to get the triggering item? In case I don’t want to create group? because the items that are triggering are totally different, one is a physical button, another one is Presence. I just want to know who triggered the rule without having them in a group just for this rule…
There is no triggeringItemName.state, it’s only triggeringItemName. Maybe openHAB ignores the .state silently.
As shown in my example, it would be way more efficient to use Groups.
You can use as many groups as you want.
You can place as many Items in as many groups as you want.
The one and only rule is: only one of the groups may be part of the semantic model.
So, there is absolute no point in not using groups here.
thanks, indeed .state is obsolete here, works without it
if(triggeringItemName == "TestSwitch")
this works.
I still don’t understand what is wrong with this approach, every time I want to know who triggered the rule, I do the above line. Why would I further complicate with creating numerous groups if this works.
Unless you are secretly planning to deprecate triggeringItemName and these are hints I should stay away from it
I’m confused, aren’t general rules that statements need {} brackets?
So, { stuff1.sendCommand(ON) } and { stuff2.sendCommand(ON) } no?
I tried the rule without brackets, and it worked but threw some error…
No. The rule is, that a conditional branch will only affect the next command. If you want to use more than one command conditionally, you have to use curly brackets to mark them as a block of commands:
if(a == b)
logInfo("message","message 1")
logInfo("message","message 2")
message 2 will be logged, regardless if a == b or not.
if(a == b) {
logInfo("message","message 1")
logInfo("message","message 2")
}
Either both or none message will be logged
There is nothing wrong with it, but if you want to check 6 individual items, the rule is (at least) like this:
rule "test"
when
Item test1 changed or
Item test2 changed or
Item test3 changed or
Item test4 changed or
Item test5 changed or
Item test6 changed
then
if(triggeringItemName == "test1" && example1.state == ON ) stuff.sendCommand(ON)
if(triggeringItemName == "test2" && example2.state == ON ) stuff.sendCommand(ON)
if(triggeringItemName == "test3" && example3.state == ON ) stuff.sendCommand(ON)
if(triggeringItemName == "test4" && example4.state == ON ) stuff.sendCommand(ON)
if(triggeringItemName == "test5" && example5.state == ON ) stuff.sendCommand(ON)
if(triggeringItemName == "test6" && example6.state == ON ) stuff.sendCommand(ON)
end
or:
rule "test"
when
Item test1 changed or
Item test2 changed or
Item test3 changed or
Item test4 changed or
Item test5 changed or
Item test6 changed
then
if((triggeringItemName == "test1" && example1.state == ON) ||
(triggeringItemName == "test2" && example2.state == ON) ||
(triggeringItemName == "test3" && example3.state == ON) ||
(triggeringItemName == "test4" && example4.state == ON) ||
(triggeringItemName == "test5" && example5.state == ON) ||
(triggeringItemName == "test6" && example6.state == ON)) stuff.sendCommand(ON)
end
There are numerous ways to get the same result:
rule "test"
when
Item test1 changed or
Item test2 changed or
Item test3 changed or
Item test4 changed or
Item test5 changed or
Item test6 changed
then
switch(triggeringItemName) {
case "test1" : if(example1.state == ON) stuff.sendCommand(ON)
case "test2" : if(example2.state == ON) stuff.sendCommand(ON)
case "test3" : if(example3.state == ON) stuff.sendCommand(ON)
case "test4" : if(example4.state == ON) stuff.sendCommand(ON)
case "test5" : if(example5.state == ON) stuff.sendCommand(ON)
case "test6" : if(example6.state == ON) stuff.sendCommand(ON)
}
end
But you will always end in many lines of similar code which can be avoided by using Group Items and matching names.
Please be aware that there is no need to use Item names like shown above, the only requirement is that it’s (easily) possible to “calculate” the name of the second condition Item name from the first (the triggering Item) one.
understood, thanks. I know I mentioned multiple items as an example question, but in reality I needed just part of the rule to check which one of 2 items triggered it