Get some information from Beacon - altbeacon

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

Related

Is locationManager.startUpdatingLocation() really needed to monitor or range beacons?

I did not get a convincing answer to why startUpdatingLocation should be used to range beacons. Is is required to monitor/range beacons in background or to get notifications when user is already in region and starts monitoring beacons? Came across posts which say this can actually increase the battery consumption. Would like to not call this method it it is not necessary.
It is not necessary. I have built dozens of beacon apps and they all range and monitor beacons just fine without this enabled.
You only need to call that method if you also need GPS (or other geo sensor) location updates.
Try it and see!

Obtaining Major/Minor values 'without' monitoring?

I am aware that monitoring is used to notify an application when it enters a specific region.
The goal is to simply set up a backend that adds +1 to a count-value that represents the amount of times a smart device entered a region. But I don't think I understood the way monitoring works yet.
If I were to set that only a certain UUID value shall be monitored, the application will be notified at any region of any iBeacon with the same UUID it enters. Is there any way to also obtain Major and Minor values of the regions withouth specifically asking for them / setting them up? It should be possible as the data payload also contains the Major and Minor values anyways?! Or would I need to specify any created beacon with their respective UUID, Major and Minor to be monitored in order to track and increase a count-value?
Let me reprhase: Is it possible to obtain UUID, Major and Minor value when entering any region without having to set up CLLocationManager or monitoring in generall (for Major and Minor) as the payload contains that information? Reading through similar topics on here suggested that in this case ranging comes into play. This got me more confused as I thought ranging only uses the measured power within the data payload to determine the aproximate distance?
Is it possible to obtain UUID, Major and Minor value when entering any
region without having to set up CLLocationManager or monitoring in
generall (for Major and Minor) as the payload contains that
information?
No. locationManager:didEnterRegion: will be called with a CLRegion object, which will be a CLBeaconRegion containing UUID, major and minor numbers, but those won't correspond to the identifier for, say, the specific beacon that caused the entry event, just to the region you've already supplied. (To be more specific, if you started monitoring just based on UUID, for example, you'll get a CLBeaconRegion with major and minor set to nil, not populated by the values for the beacon that caused the event.)
There's nothing wrong with your reasoning—the device does have the information you're interested in—iOS just doesn't make it available at the application level.
Reading through similar topics on here suggested that in this case
ranging comes into play.
Yes, you can start ranging on (or before) region entry, at which point you'll have a list of full identifiers of beacons visible in the region. There's a good answer covering this in a different question.

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

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.

Reading iBeacon measuredPower in iOS

According to the ibeacon protocol "measuredPower" is supposed to be sent by every ibeacon in its advertising packet as the last value after uuid, major & minor values. However, the iOS corelocation service does not have any method which returns this "measuredPower". Also, if we reconfigure an ibeacon and change its txPower then the beacon should ideally advertise a different "measuredPower". Do all beacons do this? And how do we fetch the measuredPower of a beacon in iOS/corelocation.
Directly, it's not possible on iOS. The closest you have is the RSSI on CLBeacon. Given a known distance, you should be able to calculate the signal power.

How to limit the advertising range of a beacon?

Is it possible to limit the ranging of the beacon, so that only devices within a certain close range(or proximity) can identify and connect to the beacon? Lets say for example the devices outside 0.5 meter zone shouldn't be able to see or connect to the beacon. I am using a iOS device as a beacon. In the Apple's CoreLocation API, there is a method called peripheralDataWithMeasuredPower in the CLBeaconRegion class which says:
peripheralDataWithMeasuredPower:
Retrieves data that can be used to advertise the current device as a beacon.
(NSMutableDictionary *)peripheralDataWithMeasuredPower:(NSNumber *)measuredPower
Parameters:
measuredPower:
The received signal strength indicator (RSSI) value (measured in decibels) for the device. This value represents the measured strength of the beacon from one meter away and is used during ranging. Specify nil to use the default value for the device.
Can this be used to limit the range of beacon? If yes, I am unable to understand how to decide the value to set for measurePower parameter? What are they trying to say by ...value represents the measured strength of the beacon from one meter away..?
Please forgive if this is a very basic question. I've recently started iOS development and will appreciate your help. Thanks.
Unfortunately, there is no easy way to adjust the range of an iBeacon without special hardware.
The power field that you mention is simply a calibration value transmitted by an iBeacon. It doesn't affect the actual physical radio range of the iBeacon. If the transmitter can be seen by an iPhone 50 meters away, altering the power field value will not change this at all. The only thing it does is change is the calibration constant which is an input to the distance estimation algorithm (used for the accuracy and proximity fields) inside the iOS software. Altering the power field will affect the estimated distance returned by the API, but it won't change the actual distance at which the iBeacon is first detected.
Altering the transmit power of a standard bluetooth iBeacon is practically impossible. In theory you can use metal shielding to construct a "faraday cage" around the transmitter to mute its power, but my experience is that it isn't very effective and it is highly susceptible to tiny imperfections in the shielding. If you want to change the transmit power you have to have somebody build you custom hardware.
The software alternative is to use the ranging API to track an iBeacon while it is visible, and only perform an action when the estimated distance is close enough, say 0.5 meters as you suggest. This works great -- only in the foreground.
If you require actually waking up your app in the background at a close range, this won't work. The best you can do is have the monitoring API wake up your app when the iBeacon is first detected, and then send a notification to the user and start ranging. If the user elects to bring the app to the foreground (at 50 meters) you can keep monitoring and then perform your desired action at 0.5 meters. If the user does not elect to bring the app to the foreground, iOS will only give you about 5 seconds of time to continue ranging before it suspends your app. It is very unlikely that the distance will change from 50 meters to 0.5 meters in this time.
With most BLE chips I've investigated, there are usually at least four settings for transmission power level that can be used to limit the advertising range.
The Texas Instruments CC2541 (as used in their SensorTag development device) and CC2540 have +4, 0, -6, and -23 as their power level options. However, changing that in the SensorTag does require a recompile of the firmware. As-is, the provided firmware mentions the power level in only one place, but that is just a value that is broadcasted to inform any central listener how loud the beacon is—so that the central device can better calculate an estimated range based on received signal strength (RSSI). An additional line must be added to the firmware to actually change the transmission power. For example:
HCI_EXT_SetTxPowerCmd( HCI_EXT_TX_POWER_0_DBM );
Based on this, there should be two places on an iOS device where you can set the power level: one that just informs the listeners what the level is, and one where the BLE chip's true transmission power is actually changed. However, expect these values to be restricted to only a few enumerated choices which may or may not meet your real-world range needs.
(The SensorTag's -23 setting would probably do well for a 0.5 meter detection range. But if you want the SensorTag to always be advertising, it will require an additional firmware change.)
Have you looked to see if the proximity property was helpful? From the apple docs:
CLProximity
Constants that reflect the relative distance to a beacon.
typedef {
CLProximityUnknown,
CLProximityImmediate,
CLProximityNear,
CLProximityFar
} CLProximity;
I would also experiment trying to combine the the proximity with accuracy and rssi.
It's gonna vary from beacon to beacon. If you use beacons from Radius Networks, they have a transmit power setting that lets you essentially limit the ability of the beacon radio to broadcast to long ranges. I don't know if other brands have it, but most do not from what I've seen.

Resources