Bluetooth RSSI/Inquiry scan on Mac - proximity detection to iPhone without connecting?
Asked Answered
M

2

6

I have to dash away from the computer frequently, and I want to trigger some commands to run when my iPhone is close enough/far enough from my iMac (next to it vs. 2-3 metres away/other side of a wall). A couple of minutes latency is fine.


Partial solution: proximity

I've downloaded reduxcomputing-proximity and it works, but this only triggers when the device goes in to/out of range of bluetooth, but my desired range is much smaller.

(Proximity polls [IOBluetoothDevice -remoteNameRequest] to see if the device is in bluetooth range or not.)

Enhancement: rawRSSI

I've used [IOBluetoothDevice -rawRSSI] to get the RSSI when I am connected to the iPhone (when disconnected this just returns +127), but in order to save the battery life of my iPhone I'd rather avoid establishing a full bluetooth connection.

Am I correct in thinking that maintaining a connection will consume more battery life than just polling every couple of minutes?

I've overridden the isInRange method of proximity here to give me a working solution that's probably relatively battery intensive compared to the previous remoteNameRequest: method:

- (BOOL)isInRange {
    BluetoothHCIRSSIValue RSSI = 127; /* Valid Range: -127 to +20 */
    if (device) {
        if (![device isConnected]) {
            [device openConnection];
        }
        if ([device isConnected]) {
            RSSI = [device rawRSSI];
            [device closeConnection];
        }
    }
    return (RSSI >= -60 && RSSI <= 20);
}

(Proximity uses synchronous calls - if and when I fit it to my needs I will edit it to be asynchronous but for now that's not important.)


Under Linux: l2ping - inquiry scan?

This SO post references getting an RSSI during an 'inquiry scan' which sounds like what I want, but it talks about using the Linux Bluez library, whilst I am on a Mac - I'd rather do it without having to stray too far if possible! (I have considered using a VM with USB pass-thru to hook up a second bluetooth device... But a simpler solution would be preferable!)

I see there is a IOBluetoothDeviceInquiry class, but I am not sure if this is useful to me. I don't intend to learn bluetooth protocol just for this simple problem!


The commands

For interest, and not particularly relevant to the solution, here are the Apple Scripts I currently trigger when

in range:

tell application "Skype"
    send command "SET USERSTATUS ONLINE" script name "X"
    do shell script "afplay '/System/Library/Sounds/Blow.aiff'"
end tell

out of range:

tell application "Skype"
    send command "SET USERSTATUS AWAY" script name "X"
    do shell script "afplay '/System/Library/Sounds/Basso.aiff'"
end tell

Though these are likely to get longer!

Millesimal answered 3/11, 2011 at 16:22 Comment(0)
C
1

In terms of tradeoffs for your use case doing a continuous or periodic inquiry will consume same or even a bit more energy as doing a periodic connect / read RSSI and disconnect. Depending on the use case it sometimes may be more efficient to maintain the connection in a low power mode (sniff with 2.56 sec interval) and remain connected if the device is in range. And use RSSI to monitor proximity (although it is not accurate as interference due to objects change rssi drastically even though the device might be in proximity)

Chrysalid answered 7/11, 2011 at 17:45 Comment(1)
So if I call my isInRange method above with a 30-60s delay between calls then that's a fairly efficient way of doing it? (I'm not worried about the iMac's power drain, only the iPhone.) I've been running it a few days now and it doesn't seem to be draining the battery much faster, but it's hard to tell.Millesimal
V
2

You are correct that making a connection will cost more energy. However, I'm not aware of APIs on mac OS that will give you access to the RSSI from inquiry scan packets. You could get access to the raw packets from your BT adapter using Mac OS PacketLogger. See this post Bluetooth sniffer - preferably mac osx

You could programmaticly put your device in discovery every couple of minutes, capture the inquiry scan packets with the packetlogger, and parse out the RSSI. You can use WireShark to help you understand how to decode the packets and find RSSI.

Your simplest option is probably to just periodically create a connection, measure RSSI, and then tear down the connection.

Virge answered 3/11, 2011 at 17:23 Comment(1)
Thanks, TJD. Sounds like my current solution is definitely the simplest. I'll run it for a few days and see how bad the battery drain is, and if it is okay then I will stick with it. :) When I get a free weekend I might experiment with PacketLogger as you say - I've used WireShark a lot before.Millesimal
C
1

In terms of tradeoffs for your use case doing a continuous or periodic inquiry will consume same or even a bit more energy as doing a periodic connect / read RSSI and disconnect. Depending on the use case it sometimes may be more efficient to maintain the connection in a low power mode (sniff with 2.56 sec interval) and remain connected if the device is in range. And use RSSI to monitor proximity (although it is not accurate as interference due to objects change rssi drastically even though the device might be in proximity)

Chrysalid answered 7/11, 2011 at 17:45 Comment(1)
So if I call my isInRange method above with a 30-60s delay between calls then that's a fairly efficient way of doing it? (I'm not worried about the iMac's power drain, only the iPhone.) I've been running it a few days now and it doesn't seem to be draining the battery much faster, but it's hard to tell.Millesimal

© 2022 - 2024 — McMap. All rights reserved.