I'm trying to use the ESP32 to check if my iPhone is in the house using the bluetooth.
The problem is that when I scan near devices with the ESP32's bluetooth, the iPhone only sends two things:
Mac address
Service UUID
The Mac address changes every 15 minutes more or less, so it's useless.
And the UUID is not unique.
I find other devices with the same UUID (strange)
Someone knows how can I workaround these limitations and recognise if my iPhone is near or not?
Thank you all!
This is all by design of Bluetooth. Bluetooth intentionally makes tracking unpaired devices difficult. See Bluetooth Technology
Protecting Your Privacy for a very high-level overview of how this works.
If you pair with the phone, you can get the IRK (Identity Resolution Key), and with that you get resolve the "real" MAC address and identify the phone. That said, if you're using esp-idf, the code indicates that it doesn't support RPA (Resolvable Private Address). See also BLE generating and resolving random mac addresses does not work correctly where they also suggest this is a limitation of the ESP32.
That said, iPhones do advertise a LocalName, and if this is just for use in your house, and you control your phone's device name, you can just look for that in the advertising packet. Note that the local name may be truncated or eliminated if it is long or there are other things the phone needs to advertise. If it's not advertising it, you can connect and read it from GAP. See How do you get the actual name of a bluetooth low energy device?
Related
I was wondering if it is possible to uniquely identify Bluetooth devices around you with iOS..
My first idea was to get the MAC address (or any other kind of unique GUID) but I was reading on the internet that such info is not shared until you pair the devices, which is something we didn't want to do in our scenario.
Also, it shouldn't be something too iOS specific, cause the idea is to discover also Android devices and implement something similar even on Android (with a separated app)
To recap these are the requirements:
solution not too iOS specific
no pairing involved
get a unique identifier from a simple Bluetooth scan
Do you have any idea/code example to share?
Thanks in advance
By design, no. Bluetooth devices randomly modify their addresses specifically to avoid this kind of tracking. For several helpful links to how this important privacy feature is implemented, see How do BLE IoT devices usually generate their private MAC addresses?
I'm a new developer developing a BLE service on iOS and Android. Currently there is a problem that I am facing, that the device address on iOS is the UUID mapped from the mac address, and on Android it is the mac address of the device. So now is there a way on iOS, from the mac address I received can get the corresponding UUID? Thanks everyone!
I am not sure how to do it.
the device address on iOS is the UUID mapped from the mac address
This is incorrect. The peripheral ID is not "from" the MAC address. It's just a random UUID. It's not even stable (it can, and does, change over time, though not quickly). There is no way on iOS to get the MAC address of a BLE device, or even to absolutely uniquely identify a BLE device unless you control the firmware. If you do control the firmware, then you can provide some mechanism to uniquely identify the device over a protocol of your own design.
As a broad rule, you can use the peripheral ID to identify or connect to a device you've connected to before. This isn't 100%, because the ID does change sometimes. But for the most part it does work (and it's intended to work, so Apple won't just break this arbitrarily). But you cannot otherwise identify the device.
As a corollary, the peripheral ID on one iPhone is completely unrelated to the peripheral ID on another phone for the same device. This is intentional.
You will have to adjust your design to deal with these facts.
In iOS not possible to get mac address of CBPeripheral object.
Now I have no. of BLE devices with different UUIDs but with same peripheral name. User has to first register to that BLE device by registration command to that BLE device whose MAC address will get at the time of QR code scanning. But how can I get that to which device user is doing registration as in iOS I am not getting MAC address in peripheral?
As Dorian Roy notes, a good basic approach is to encode the MAC into the manufacturer specific data in the advertising packet. The MAC is 6 bytes, so you generally should have room if you're not already storing too much there. You can usually get away with the lower 3 bytes if all your devices have the same OUI (the manufacturer prefix).
I've actually designed systems that just advertise the last byte of the MAC, and then double-check by connecting to fetch the full MAC. You've got better than a 50% chance of no collisions until there's about 20 devices advertising in the same room. If there are likely fewer than 3 devices in the same room, then there's less than a 2% chance of collision (but remember, that means 1 in 50 situations will have a collision, so you can't ignore it). Obviously the more bytes you include, the better.
There is a subtle corner case with this design that may or may not matter to you. The device may already be BLE connected to the phone. This can happen due to another app (such as LightBlue), but also due to your own app. Say you connect to a device, and then your app dies and you're relaunched. The device may still be connected to the phone's BLE system, and it won't advertise. The way you discover that device is with retrieveConnectedPeripherals. But in that case, you'll never see an advertising packet. If this MAC-check is a one-time event, then this situation may not be a major issue for you, but it's something to remember if customers complain that your app can't find the device. (The easiest solution is to reboot the device, and if that's not possible, to reboot the phone.)
Paul's suggestion of exposing your MAC via a characteristic is a necessary piece, but it's comparatively slow, and a bit complicated in practice since there may be multiple devices advertising. I typically would start with the advertising packet if you can, and only connect to likely correct devices, and then check their characteristic. Connecting is expensive. Only connect if there's a good chance you're right.
We are using Swift and IOS CBCentralManager. We have a Bluetooth Low energy (Dual mode device)
The Dual mode device advertising packet does not have a name or shortened name due to a lack of space.
When we call "scanForPeripherals(withServices:options:)" with the service UUID which is included in the Advertising frame we only get a response if we also have a short device name included.
So with a name field, we can detect the device. Without the name field we can not detect the device. We are expecting a CBPeripheral to be returned, obviously with a NIL name.
We get a response on early Iphones, such as Iphone 5, but later Iphones and Ipads do not get a response.
3rd party software such as Lightblue can detect these devices. This 3rd party software detects correctly every time on every device we have tested.
There must be something we are missing.
I found a poorly documented option by Apple. It seems that this is the option to cover this use case.
let CBCentralManagerScanOptionAllowDuplicatesKey: String
Apple must see a duplicate ID (or null) if there is no name in the Advertisment.
Here is apples write up Apple Scan feature AllowDuplicatesKey
This must pop up quite often because of the size limits of the Advertising frames in BLE.
I can see why many devs would choose not to waste space in the 32 byte advertising frame on a name for the GUI when the device is not consumer targeted.
I'm working on an application for iOS (Objective-C).
I'm looking for a way to connect to a BLE device so that you can specify the MAC or UUID of this device.
Currently I have two BLE devices with the same name so the app is not able to differentiate between the two , which gives many problems (these devices do not have the same functions).
Is there any way to specify the MAC or UUID when connected to BLE device?
RSSI signal strength discover the differentiate two or more device.
If once time UUID get from peripheral then also differentiate peripheral.
Note: iOS doesn't give permission to read MAC address of peripheral.
The MAC of the device is not available, nor is any other particularly useful identifier. However, since "these devices do not have the same functions," they should have different services that they advertise. When calling scanForPeripherals(withServices:options:) you should be passing the specific service or services you're interested in. This is much better for performance, and also will automatically filter out devices you are not interested in. Passing nil for serviceUUIDs should only be done for a generic BLE scanner.
If you control the device firmware, you can add services to identify the type of device, or add information in the manufacturer's advertising data to distinguish the devices during scanning.
If these devices advertise the same services and are otherwise identical, then you will need to connect to both and query them to determine which device you wanted. You still will not receive a MAC, however, unless the device provides it via some characteristic.
Typically, a given device will continue to have the same CBPeripheral UUID, and this can be used to reconnect to previously known devices. However, if the device never pairs securely, this UUID is not always stable, either.