iBeacon: how to distinguish between iBeacons with the same minor and major value - ios

iBeacon specifications says:
The UUID, major and minor values provide the identifying information
for the iBeacon.
Major and minor values are used to distinguish products or elements within a region. The Apple documentation is quiet clear on how to do it and the store example is quiet good.
However all this works well only when there is one element category per region (or sub-region) but it doesn't work well if we want the APP to be able to distinguish among elements with the same minor and major within the same region.
Is there some other unique identifier associated to an iBeacon that can be monitored/detected so that I can distinguish iBeacons with the same minor and major value?
EDIT: Additional information
To test this I have created two iBeacons with the same UUID and same major and minor value and then started monitoring for the iBeacons within the UUID that I specified.
The callback code that I have implemented for iBeacons ranged in the regions is the following:
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
NSLog(#"Did range %lu beacon in region %#", (unsigned long)[beacons count], region.identifier);
for (int i=0; i<[beacons count]; i++) {
CLBeacon *beacon = [beacons objectAtIndex:i];
// <- breakpoint!
NSString *_cnt = [[NSString alloc] initWithFormat:#"Number of beacons is : %lu and the current one %i is %f away from you %#",(unsigned long)[beacons count], i, beacon.accuracy, beacon.description];
}
}
When I add a breakpoint to the beacon line I see that both CLBeacon objects detected have the same information:
CLBeacon (uuid:<__NSConcreteUUID 0x17003d8e0> 74278BDA-B644-4520-8F0C-720EAF059935, major:20, minor:0, proximity:1 +/- 0.17m, rssi:-42)
CLBeacon (uuid:<__NSConcreteUUID 0x17003e840> 74278BDA-B644-4520-8F0C-720EAF059935, major:20, minor:0, proximity:2 +/- 0.28m, rssi:-47)
So as of now I am unable to distinguish among them unless I specify a major and minor value.
Here is the screenshot of the App I am using to configure the iBeacons (there are no other fields that I can configure):
I wonder if within the blue tooth signal there is some sort of unique identifier that identifies each hardware.

This is actually a common problem, and it is difficult to solve. While best practices usually say that different beacons should not share the same ProximityUUID/major/minor, there are sometimes legitimate edge cases where multiple beacons are transmitting the same identifiers in the same place. (At Radius Networks, for example, we put default identifiers into our beacons, so if you order two of them they will initially have identical identifiers until you change them.)
Using CoreLocation APIs, two different beacons with the same identifiers will show up as two beacons in the didRangeBeacons:InRegion: callback. This is because internally, iOS maintains uniqueness using the hardware address. Unfortunately, CoreLocation does not expose the hardware mac address or any other indication of which beacon with the same identifier is which.
Using CoreBluetooth APIs in the foreground, you can get callbacks for each iBeacon seen. And while you cannot get their hardware mac address, iOS does assign a unique identifier to each of them (probably based on a hash of the mac address) so you can tell them apart. Unfortunately, iOS does not let you read the contents of the advertisement using CoreBluetooth so you can't read the iBeacon identifiers. All you can really do is count how many different Bluetooth LE are around that might or might not be iBeacons.
It is possible to do some hacky tricks to try and correlate the information from CoreBluetooth and CoreLocation by using timestamps of when devices appeared and their RSSI readings. But these tricks are not extremely reliable and prone to failure when many beacons are around.

The - combination between UUID, major and minor should be unique. There shouldn't be two beacons with the same combination, this is the beacon identifier!

Your statement that you want "to be able to distinguish among elements with the same minor and major within the same region" doesn't make sense, as the combination of UUID, major and minor is the most specific you can get.
You can have multiple beacons with the same UUID/major/minor if you need to get greater geographical coverage, but these beacons will be indistinguishable from one-another.
How you apply meaning to major and minor values is entirely up to you - If you need to distinguish two locations then simply apply different minor values.

Related

Get some information from Beacon

I want to get the major & minor values and the battery level as well as the proximity UUID, but I'm not sure how to get those values from Beacon object. It doesn't seem there are the functions to get them. Could you provide the sample code to get those values from Beacon object?
When using the iBeacon layout:
beacon.getId1().toString(); // ProximityUUID
beacon.getId2().toInt; // major
beacon.getId3().toInt(); // minor
The battery level is not present with the iBeacon layout. With some hardware manufacturers, it is available if you configure the beacon to transmit he AltBeacon layout. In that case you may be able to use:
beacon.getDataFields().get(0); // battery level

How to get the mac address of a beacon in objective-c without knowing its UUID, major and minor values?

In my application I need to search the nearest beacons and detect their mac addresses to calculate the user exact location in the building. The question is that can we detect the closest beacon mac address from the iOS application without the beacon's UUID, major and minor values?
Think about it: If you don't know the UUID of the beacon, how would you know it's location? A beacon doesn't know where it is. Someone must have physically put the beacons in their places, must have written down their locations, and must have made that location available to your app. In that case you would assume that they also wrote down the UUIDs.
Apple's idea is that you can't (easily) write an app that just finds any beacon. The beacons must be related to your app, otherwise they are none of your business. Let's say you write an app for a supermarket which uses the same UUID for all beacons. The app is supposed to ignore all other UUIDs.
Have you tried ?
- (void)beaconManager:(ESTBeaconManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(ESTBeaconRegion *)region
{
self.beaconsArray = beacons;
ESTBeacon *beacon = [self.beaconsArray objectAtIndex:i];
NSLog(#"beacon.macAddress = %#",beacon.macAddress);
}
The generic iBeacon protocol, as supported by Core Location, does not expose the beacons's MAC address. You need to know the UUID that is configured in your beacon and set this in your beacon region.
Other beacons may expose additional information as per the other answer.

Trigger didEnterRegion event only once, for multiple iBeacon with Different UUID, major and minor

I need to, didEnterRegion and didExitRegion should callback only once, for multiple iBeacon with different uuid, major and minor value.
Grouping iBeacon in one Region, i have tried using region identifier but it's working only when two iBeacon have same UUID.
my question is
how to group multiple iBeacon in same region meanwhile, iBeacon have different-different UUIDs?
Unfortunately, you can't do that. The way the CLBeaconRegion class is designed by Apple, you have to specify a single ProximityUUID that is shared by all CLBeacon instances to be detected by the region.
As a workaround, you can either rework your beacon identifiers so they all share the same ProximityUUID or you can use multiple regions. But you are correct that if you have multiple regions, you will get multiple callbacks with beacons grouped by their ProximityUUID.

iBeacons: how to get broadcasted beacon power (txPower)

iBeacons seem to broadcast their txPower parameter (report RSSI power at 1 meter distance) which is used in calculating beacon.accuracy and beacon.proximity properties (details on iBeacon advertisements packet can be found here).
However, CLBeacon class does not seem to have a property for txPower. Is there a way I can get txPower using Core Location framework, or need I to go down to Core Bluetooth? The reason I need this, is I want to experiment with custom beacon accuracy/proximity calculation for very quick beacon immediate range discovery. In this circumstances reverse calculating txPower from accuracy is no helper.
Unfortunately you can not get this value programmatically with either CoreLocation or CoreBluetooth. Apple blocks access to all iBeacon data with CoreBluetooth (See my breakdown of this here.) Similarly with CoreLocation it is simply not exposed in the CLBeacon class as you have seen.
Since you say you can't to do a reverse-calculation, then the only other ways I can think of to do this are:
Use an Android, OSX Mavericks, or Linux device, which offer no such restrictions on reading this field.
Make a lookup table in your iOS app of all your iBeacons (with unique UUID/major/minor values vs. their txPower value)
Option 2 above obviously requires that you assign unique identifiers to all your iBeacons under test.

Detect iBeacon with different major and minor values

I am trying a simple test right now.
Device 1:
Acts as beacon with UUID: XXX-XXX-XXX
Major: 1000
Minor: 1234
self.peripheralData = [MyRegion peripheralDataWithMeasuredPower:nil];
[self.peripheralManager startAdvertising:self.peripheralData];
Device 2:
Acts as listener for region with UUID: XXX-XXX-XXX
locationManager startMonitoringForRegion:_region
Device 2 does not detect Device 1. It only detects Device 1 if I program to listen to the region to have major:1000 and minor: 1234.
Does this sound right?
Let's say i have 100 phones acting as beacon with same uuid and identifier but different major and minor values. And I have 50 phones acting as listeners for the specific uuid and idenfitifer... Can I find all beacons with that uuid and read their major and minor values?
What am I doing wrong?
When you initialize your region, use
region = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:identifierString];
instead of something like
region = [[CLBeaconRegion alloc] initWithProximityUUID:uuid major:[major integerValue] minor:[minor integerValue] identifier:identifierString];
By not specifying the major and minor values, all beacons with the matching UUID should be detected. It works for me.
I think the key to your problem lies in this comment:
Sure. It's just created using initwithuuid major and minor – Legolas
yesterday
There are 3 different calls to create a beacon region:
initWithProximityUUID:identifier:
,
initWithProximityUUID:major:identifier:
and
initWithProximityUUID:major:minor:identifier:
If you want to detect beacons with any UUID, you need to use the first form that does not specify the major or minor value.
Then you need to also call startRangingBeaconsInRegion: and look at the beacon objects that are returned in the ranging calls.
DidEnterRegion calls only include major or minor values if they are part of the region.
The ranging callbacks include all the beacons that are detected, including their major and minor values, distance and proximity, etc.
To eliminate a problem in your code, try doing the exact same thing with my free Locate for iBeacon app in the app store. Try making one or both sides of the transmitter/detector be this app vs. your custom app.
If it does not work with Locate for iBeacon on both sides, then something is wrong with one of your devices. If it does work with Locate for iBeacon on one side, please post your code for the side that is having trouble.
Which delegate methods are you using for the Location Manager? Sometimes DidEnter is not called if you're already in the region i.e. you turn on the transmitting beacon before starting the one that's doing the monitoring. If that's the case monitor for state changes instead and you should be good.
Also, I highly recommend using David's Locate iBeacon app. It will really speed up your development process. Thanks D!

Resources