How to store additional info in ITEM?

Hello,

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

If you were to apply some of the principals Design Pattern: Working with Groups in Rules, if you put your existing Design Pattern: Proxy Item into a Group and have them configured with persistence you can create a single rule for all of your Rooms.

Items

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
1 Like

@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!

I just wrote this up as a Design Pattern:

For better or worse, encoding the value in the Item name IS the elegant solution. :slight_smile: