I am having some rules to update state when i use the buttons to control my lights.
rule “Knapp Garderob”
when
Item Light_GF_Corridor_Wardrobe_BTN1 received update
then
postUpdate(Light_GF_Corridor_Wardrobe , Light_GF_Corridor_Wardrobe_BTN1.state.toString)
end
rule “Knapp Vardagsrum Tak”
when
Item Light_GF_Living_Ceiling_BTN1 received update
then
postUpdate(Light_GF_Living_Ceiling_BTN1 , Light_GF_Living_Ceiling_BTN1.state.toString)
end
rule “Knapp Köksbord Tak”
when
Item Light_GF_Living_CeilinTable_BTN1 received update
then
postUpdate(Light_GF_Living_CeilinTable , Light_GF_Living_CeilinTable_BTN1.state.toString)
end
rule “Knapp Källarkorridor”
when
Item Light_C_Hallway_BTN1 received update
then
postUpdate(Light_C_Hallway , Light_C_Hallway_BTN1.state.toString)
end
rule “Knapp Källarkorridor”
when
Item Light_C_Hallway_BTN2 received update
then
postUpdate(Light_C_Hallway , Light_C_Hallway_BTN2.state.toString)
end
Is there anyway to do this more efficient,
All buttons is in the same group Buttons and the naming of the buttons is always name of the lamp and the 4 last characters is _BTN?.
Put all of the buttons in a group like you have. You don’t list it so we will call it gLightButtons.
The rule will then be something like:
rule "Buttons to light mapping"
when
// Hack to get at the most recently pressed button
Thread::sleep(100) // experiment with this value, the purpose is to give persistence time to save the state so lastUpdate will work properly. You may not need it at all but if the wrong button keeps coming up, make this sleep longer
val button = gLightButtons.members.sortBy[lastUpdate].last
val lightName = button.name.substring(0, button.name.lastIndexOf('_')) // test this, there may be an off by one error here
postUpdate(lightName, button.state.toString)
end
I think the above will fail silently or with a hard to read error if lightName doesn’t exist as an Item. You can add a check by putting all of your lights in a group (gLights) and checking to see if the light exists in the group before calling postUpdate.
val light = gLights.members.filter(s|s.name == lightName).head
if(light != null) light.postUpdate(button.state.toString)
else logError("Rule name", lightName + " does not exist!")
Finally, depending on what your Light and Button items are bound to, you might be able to bind them to the same Item which will keep them all in sync for you, though I’ve never successfully done that. You usually see this approach with MQTT type switches you can search for to find some examples.
rule “Buttons to light mapping”
when
Item Buttons received update
then
Thread::sleep(500)
val changedbutton = Buttons.members.sortBy[lastUpdate].last
end
I receive an error when I press a button
2015-12-16 22:11:46.137 [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule ‘Buttons to light mapping’
java.lang.NullPointerException: null
The most common error is not having persistence setup correctly or at all. Do you have persistence setup? Are all the members of Buttons being saved to persistence? If using rrd4j, are you using an every minute strategy for all the members of Buttons?
// persistence strategies have a name and a definition and are referred to in the “Items” section
Strategies {
// for rrd charts, we need a cron strategy
everyMinute : “0 * * * * ?”
default = everyChange
Try adding Buttons* to everyMinute and see if tha helps. Beyond that I’m stumped. For some reason either Buttons is null, Buttons.members is null, or lastUpdate is returning null. The most likely seems to be the lastUpdate but who knows.
@rlkoshak It is now working, I think that the problem was that I had not used some of the Buttons.
Working script:
rule “Buttons to light mapping”
when
Item Buttons received update
then
Thread::sleep(200)
val changedbutton = Buttons.members.sortBy[lastUpdate].last
val lightname = changedbutton.name.substring(0, changedbutton.name.lastIndexOf(‘_’)) // test this, there may be an off by one error here
postUpdate(lightname, changedbutton.state.toString)
logInfo(“Buttons”, changedbutton.name.toString + " " + changedbutton.state.toString )
end
But there is one problem, each press generates two entries
2015-12-28 11:11:27.341 [INFO ] [g.openhab.model.script.Buttons] - Light_GF_Living_Ceiling_BTN1 ON
2015-12-28 11:11:27.352 [INFO ] [g.openhab.model.script.Buttons] - Light_GF_Living_Ceiling_BTN1 ON
2015-12-28 11:11:41.119 [INFO ] [g.openhab.model.script.Buttons] - Light_GF_Living_Ceiling_BTN1 OFF
2015-12-28 11:11:41.135 [INFO ] [g.openhab.model.script.Buttons] - Light_GF_Living_Ceiling_BTN1 OFF
@smerschjo I will try Jsr223.
If I enable JSR 223 Script Engine, can I still use traditional Rules?
This is expected behavior unfortunately. The way that the state of a Group is calculated causes it to be updated for each member of the group so, if you have two members of group Buttons then a “received update” triggered rule will be triggered twice for each button press.
This will not be fixed in OH1, and some could argue it really isn’t so much a bug as it is unexpected behavior. I don’t know how groups will work in OH 2.
I’ve gotten around this problem by writing my rules so the double trigger doesn’t really matter and where I can’t do that I list each Item in the when clause instead of triggering on Group updates. I suppose you could also implement some sort of time based check and ignore the second one.