BiDirectional HashMap in OH?

I have a Vantage Qlink system linked via a Serial port and I’m trying to get it fully integrated into OH 2.3.0.
Whenever I Switch / Dim a light, it outputs the new status like “LO 1 2 2 5 100”, “1 2 2 5” is the address, 100 is the load value (100 = Max, 0 = Off).
When I change a Dimmer Item in OH to let’s say 80%, a command “VLB# 1 2 2 5 80” is sent to Vantage Qlink.

I could craft pretty generic code to handle these cases (see below)

BUT, now my question, how can I avoid the 2 HasMaps with address -> item and item -> address?

I need similar code for 50+ inputs…

In java Apache world, there exist a BidiMap…

Any help is appreciated !

vantage.items

String Vantage "Vantage [%s]" { serial="/dev/ttyUSB7@19200" }

Group:Dimmer    Spots           "Spots"

Dimmer Keuken_Spots_midden "Blok" (Spots)
Dimmer Keuken_Spots_kookvuur "Kookvuur" (Spots)
Dimmer Keuken_Spots_plafond "Plafond" (Spots)
Dimmer Bureau1_Spots_plafond "Plafond" (Spots)
... and 60 more

vantage.rules

// Import minimal set (new since 2.2)
import java.util.HashMap

// Mappings
var HashMap<String, String> loadToItemsMap = newLinkedHashMap(
    "1 2 3 6"           ->      "Bureau1_Spots_plafond",
    "1 2 2 4"           ->      "Keuken_Spots_midden",
    "1 2 2 3"           ->      "Keuken_Spots_kookvuur",
    "1 2 3 1"           ->      "Keuken_Spots_plafond",
... and 60 more
)

var HashMap<String, String> itemsToCommand = newLinkedHashMap(
    "Bureau1_Spots_plafond"     -> "1 2 3 6",
    "Keuken_Spots_midden"       -> "1 2 2 4",
    "Keuken_Spots_kookvuur"     -> "1 2 2 3",
    "Keuken_Spots_plafond"      -> "1 2 3 1"
)
... and 60 more
)

rule "vantage Spots changed"
when
        Member of Spots received command
then {
        var myCommand = "VLB# "+itemsToCommand.get(triggeringItem.name) + " " + receivedCommand

        logInfo("vantage", "Spots changed "+triggeringItem.name+" "+receivedCommand+" to Vantage => "+myCommand)
        Vantage.sendCommand(myCommand+"\r")
}
end

rule "vantage changed event"
when
        Item Vantage received command
then {
         var String message = receivedCommand.split(" ")

         var String master = new String(message.get(1))
         var String enclosure = new String(message.get(2))
         var String module = new String(message.get(3))
         var String load = new String(message.get(4))
         var String value = new String(message.get(5))

         var String key = master + " " + enclosure + " " + module + " " + load
         var MyItem = loadToItemsMap.get(key)

         postUpdate(MyItem,value)
}
end

The approach I would take is to leverage Design Pattern: Encoding and Accessing Values in Rules using approach 3.

...
Dimmer Keuken_Spots_midden_1_2_2_4 "Block" (Spots)
Dimmer Keuken_Spots_kookvuur_1_2_2_3 "Kookvuur" (Spots)
...
rule "vantage Spots changed"
when
    Member of Spots received command
then 
    val parts = triggeringItem.name.split("_")
    var myCommand = "VLB# " + parts.get(3) + " " + parts.get(4) + " " + parts.get(5) + " " + parts.get(6) + " " + receivedCommand

    logInfo("vantage", "Spots changed " + triggeringItem.name + " " + receivedCommand + " to Vantage => " + myCommand)
    Vantage.sendCommand(myCommand+"\r")
end

rule "vantage changed event"
when
    Item Vantage received command
then
    var message = receivedCommand.split(" ")

    var master = message.get(1)
    var enclosure = message.get(2)
    var module = message.get(3)
    var load = message.get(4)
    var value = message.get(5)

    var key = master + " " + enclosure + " " + module + " " + load
    val MyItem = Spots.members.findFirst[ i | i.name.endsWith(key) ]

    MyItem.postUpdate(value)
end

Note that I also cleaned up some redundancies in the code.

With this approach you are trading some not as friendly Item names but gaining the elimination of the Maps entirely.

Cool !
That’s a nice approach.
Many thanks for this… I will apply instantly the Design Pattern (and will read the other ones).