I have several “virtual” switches - that have no actual binding (just for monitoring states ON/OFF and send command to arduino which controls actual relays by its ID)
Switch LR_Lights "Lights in the Living room" (gSwitches) #switch_Id = 1
Switch HALL_Lights "Hall lights" (gSwitches) #switch_Id = 2;
and in rules it goes something like this:
rule "LR Lights switch triggered"
when
Item LR_Lights changed
then
if (LR_Lights.state == ON) {
Arduino.sendCommand("<setRelay;1;1>")
} else {
Arduino.sendCommand("<setRelay;1;0>")
}
end
where <setRelat;1;1> - is a switch ID
QUESTION: how to store this ID in item file and how to later access it in rules with something like:
var switch_id = LR_Lights.someMethod('switchID') #get switchId for that item
Arduino.sendCommand("<setRelay;" + switch_id + ";0>")
Or am I doing it completely wrong? (sorry just starting with openhab)
This is actually a really good question. I’ve written a lot around this sort of thing in the past but I don’t think I’ve ever made a single posting on this specific subject.
There are a number of ways you can go about this but my preferred approach would be to take advantage of Groups and Design Pattern: Associated Items.
So what we will do is encode the switch_id in the name of some more Design Pattern: Unbound Item (aka Virtual Item) s. Then we will use a Group to loop through and parse out the switch_id from the unbound Item’s name.
Items
Group:Switch LR_Lights_Ids
Switch Arduino_1 (LR_Lights_Ids)
Switch Arduino_2 (LR_Lights_Ids)
Group:Switch HALL_Lights_Ids
Switch Arduino_3 (LR_Lights_Ids, HALL_Lights_Ids) // the same switch can be in multiple groups
Rules
rule "LR Lights switch triggered"
when
Item LR_Lights received command // this is a better trigger for an actuator
then
LR_Lights_Ids.members.forEach[sw |
val id = sw.name.split("_").get(1) // get the switch ID based on the unbound Item's name
val state = if(receivedCommand == ON) 1 else 0 // get the new state based on the received command
Arduino.sendCommand("<setRelay;" + id + ";" + state + ">") // send the command to the Arduino
]
end
Group:Switch Lights // I don't know the full set of Items in gSwitches so am showing a new Group instead
Switch LR_Lights (gSwitches, Lights)
Switch HALL_Lights (gSwitches, Lights)
Group:Switch Room_Relays
Group:Switch LR_Lights_Ids (Room_Relays)
Switch Arduino_1 (LR_Lights_Ids)
Switch Arduino_2 (LR_Lights_Ids)
Group:Switch HALL_Lights_Ids (Room_Relays)
Switch Arduino_3 (LR_Lights_Ids, HALL_Lights_Ids) // the same switch can be in multiple groups
rule "A switch was triggered"
when
Item LR_Lights received command or
Item HALL_Lights received command
then
// get the switch that triggered the rule
Thread::sleep(100) // give persistence a chance to catch up
val trigger = Lights.members.filter[light | light.lastUpdate != null].sortBy[lastUpdate].last
// get the Group of Arduino switch ID items
val arduinos = Room_Relays.findFirst[grp | grp.name = trigger.name + "_Ids"] as GroupItem
// Send the command to all of the Arduinos by ID
arduinos.members.forEach[sw |
val id = sw.name.split("_").get(1) // get the switch ID based on the unbound Item's name
val state = if(receivedCommand == ON) 1 else 0 // get the new state based on the received command
Arduino.sendCommand("<setRelay;" + id + ";" + state + ">") // send the command to the Arduino
]
end
@rlkoshak
thx for very constructive reply and code examples. That was my idea too - just to parse a name of an item - as the most quick solution. But I really thought there were some more elegant way of doing this.
Thanks again -I’ve read a lot of your posts and think you’re doing such a great contribution for this community!