I use that MAP file in a rule which checks if one or more bluetooth devices are present:
rule "Presence JSON"
when
Item bluetoothDevicesJSON received update
then
val jsonMsg = bluetoothDevicesJSON.state.toString
//val senderAddress = transform("JSONPATH", "$.sensorAddress", jsonMsg)
var int numberOfdevices = Integer::parseInt(transform("JSONPATH", "$.devices.length()", jsonMsg)) - 1
for (i : 0 .. numberOfdevices) {
val deviceAddress = transform("JSONPATH", "$.devices["+ i +"].address", jsonMsg)
//val deviceRSSI = transform("JSONPATH", "$.devices[" + i + "].rssi", jsonMsg)
val sw = gPresent.members.filter[s|s.name == transform("MAP", "addresses.map", deviceAddress)].head
if (sw !== null) {
sw.sendCommand(ON)
}
}
end
That seems to work quite well. Unfortunately, there are quite a few other devices “in” that bluetoothDevicesJSON string, for which there is no entry in the MAP file. My openHAB log now consists of many entries like the following:
2018-04-05 11:06:09.438 [WARN ] [rm.AbstractFileTransformationService] - Could not transform '4D-54-78-AA-C3-A7' with the file 'addresses.map' : Target value not found in map for '4D-54-78-AA-C3-A7'
Is there a way to check for the existence of an entry first before “doing” the actualy transformation? Or what could I do about that?
I am afraid, you can do that.
But you can add the other MACs addresses in the MAP file and transform them to the same arbitrary value and then get your rule to check for that
Yea, I thought of that, then started adding address with “UnknownX” as device name, but after having added 16 unknown device addresses, it looks like at least one of my devices, if not more, uses some kind of randomized addresses. So that won’t work either.
Most devices do this nowadays. It’s a privacy feature. I know for sure that Apple and most newer Android devices do. Older FitBit devices do not and tracker tiles and the like definitely do not.
This is going to be a hack but it just might be worth it in this case.
read in the contents of the map file to a String
split the String on newlines
split each line on =
put the MACs into a Set
import java.util.Set
import java.util.HashSet
val Set<String> validMacs = new HashSet<String>()
rule "Get Valid Mac"
when
System started
then
val lines = executeCommandLine("cat /etc/openhab2/transform/addresses.map").split("\n")
lines.forEach[ line |
val mac = line.split("=")
validMacs.put(mac)
]
end
rule "Presence JSON"
when
...
if(validMacs.contains(deviceAddress)) {
val sw = gPresent.members.filter ...
...
I’ve just typed in the above. It may not work a written. But it illustrates the idea.
Your approach gave me an idea for one of my rules. Thanks for posting!
You’re welcome! A lot of the presence stuff I use comes from your “Generic Presence Detection” thread, so thank you for that!
And thank’s for your hack, which I am now using. There were just a few things that had to be corrected to make it work. The code now looks as follows:
import java.util.Set
import java.util.HashSet
val Set<String> validMacs = new HashSet<String>()
rule "Get valid presence MAC addresses"
when
System started
then
validMacs.clear()
val lines = executeCommandLine("cat /etc/openhab2/transform/presenceDevices.map", 1000).split("\n")
lines.forEach[ line |
val mac = line.split("=").get(0)
validMacs.add(mac)
logInfo("Presence", "Added MAC to valid presence MAC list: " + mac)
]
end
You shouldn’t have to clear validMacs in the System started rule. That rule only runs once after OH starts and therefore validMacs will also have just been created and therefore already empty.
It occurred to me that the forEach loop could become a one-liner with a map reduce:
lines.map[ split("=").get(0) ].reduce[ validMacs, mac | validMacs.put(mac) ]
or even better a map forEach
lines.map[ split("=").get(0) ].forEach[ mac | validMacs.put(mac) ]
I’ve never done a map this complicated before but have no reason to believe it won’t work. I always forget about the map/reduce methods. They are super powerful.