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.
Related
I have played around with Airlocate and two iPhones. Also between a Linux /hcitool beacon transmitter and Airlocate ranging. I see that the set of proximity UUIDs to be tracked are hardcoded in the Airlocate source code.
Is it possible for an iOS app to get a more generic call back , when it is in the vicinity of any iBeacon (any proximity UUID) and let that app decide how to go about behaving the way it wants.
I understand that this should definitely be possible from the OS perspective, as I see a 9 byte iBeacon prefix in the start of the PDU, which is independent of the proximity UUID.
Another query - I view hardcoding the proximity UUID in the APP as some sort of pairing . How is general bluetooth pairing different from this.
My aim in asking these questions is to understand the feasibility of using beacons to beam (broadcast) data, so that all recipients in the vicinity can receive it. If I choose to go with a specific 16 byte proximity UUID, then I am left with only 5 bytes (Major/minor/power) to beam data. Otherwise I get 21 bytes
By "more generic call back", it seems like you are trying to listen to iBeacons that are not deployed by you. The answer to this is NO, you can't do that.
According to this post:http://beekn.net/2013/10/ibeacons-can-my-ios-app-find-beacons-that-arent-mine/ , in order to listen to an iBeacon, you must know its proximityUUID first.
Unfortunately Apple decides to limited your ability to do that. CoreBluetooth framework can detect iBeacon nearby but since it only returns the device UUID, not the proximityUUID, you cannot add callback to them.
And Android can read the proximityUUID of any iBeacon without any problem.
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.
I am working on a project where I first wanted to advertise a device as an iBeacon and make it possible to connect to that device via Core Bluetooth at the same time. Besides the fact that this is not easily doable (a device cannot advertise as an iBeacon and CB device at the same time), I noticed that the iBeacon part seems unnecessary - discovering peripherals with Core Bluetooth seems to be basically the same as discovering iBeacons.
My first Question: Am I right in assuming this? Or does iBeacon provide anything that central/peripherals in CB do not? Especially in regard to background advertisement/searching?
The only issue I can see right now is that the CLBeacon gives me both an rssi and an accuracy (and from this, the approximated proximity is calculated). With Core Bluetooth, centralManager:didDiscoverPeripheral:advertisementData:RSSI: gives me only an RSSI. Is there any way to retrieve the accuracy here so I can calculate a proximity? This is important for me and I guess relying on RSSI only for the proximity will give me less accurate results?
My second Question: Can I get the accuracy that I get with iBeacon in Core Bluetooth or a similar measure to calculate the proximity?
You can calculate your own distance estimate with RSSI using an algorithm like the one I posted here:
https://stackoverflow.com/a/20434019/1461050
The trick is that you will need as many RSSI measurements as possible averaged over a time window of 20 seconds or so to reduce the noise on the estimate.
The main advantages of using CoreLocation APIs to detect standard iBeacons vs. using CoreBluetooth to detect custom beacons are:
A variety of cheap off-the shelf hardware is available for the iBeacon standard.
CoreLocation can scan for iBeacons in the background (likely using hardware assist on iPhone 5+) in a way that can automatically launch your app relatively quickly, even if the user did not manually launch it since boot. As of iOS 7.1, even if the user kills the app from the task switcher, CoreLocation can re-launch it into the background if an iBeacon is detected. I do not believe all this is possible with CoreBluetooth.
The iBeacon transmission allows you to easily read the UUID/major/minor identifier combination in iOS without pairing. This 20 bytes of data (with the major and minor fields able to be set to arbitrary values) is more than you can get from a 16 byte Bluetooth Service UUID.
You don't have to roll your own software for distance estimation.
When you start advertising a CLBeacon with peripheral data, can you pass in a NSString or UIImage into this dictionary that you could then have show up when the beacon is discovered?
For example, if I wanted to create write a message to a friend and then when the friend entered the beacon area, could I have the message show up on their phone by storing the message in the NSDictionary and then extracting it? If so, how? If not, is there another way?
Thanks!
So you are asking if you could add extra information to the beacon advertisement that's sent by a beacon device that a custom application could look for?
The answer is no. The iBeacon protocol is a very short, fixed packet of data. There's no facility for adding extra information to the packets.
You could design and implement your own BLE service that's an alternative to iBeacons and implement it on both the transmitter and the receiver.
You could also use a hybrid approach, where you use standard iBeacon discovery to find beacons, and when you detect a beacon you're interested in, trigger a 2-way BLE conversation with the beacon and ask it for additional information. It's my understanding that some of the BLE devices that are being sold as iBeacons can run custom software that would implement this sort of thing. (Many of these devices have ARM processors in them, the same family of chips that power iOS devices.
No, you cannot do this. iOS-based iBeacons (like all other standard iBeacons) will only transmit a three-part identifier and a transmitter power calibration value. That's it. You cannot transmit anything else.
Even if you did make a custom Bluetooth LE advertisement that sends additional data besides the standard iBeacon fields, you wouldn't be able to see this data with the standard APIs for seeing iBeacons.
If you want to tie other data to an iBeacon, you have to do it through another channel, by some kind of lookup that matches the data up with the identifiers above. Three common ways to do this:
Hard-code a static lookup table in your app.
Use a Web Service to look up the value based on the iBeacon identifiers.
Fetch the data directly from a (non-standard) iBeacon using a secondary BluetoothLE communication channel.
My company has a web service called ProximityKit that makes it easy to tie data to iBeacons in your app. You log into a web interface to type in key/value pairs to associate with each iBeacon, then the included iOS client library automatically gives you those key/value pairs when the iBeacon is visible.
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.