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.
Related
What is the purpose of the txPower in a Beacon? According to this, How to set Transmitting Speed vs Scanning Speeds for Altbeacon Library, the maximum transmission power is already set by default.
Then what is the meaning of the txPower that can be set when sending the beacon and what are the possible values for it?
The txPower field sets one of the bytes in the over the air beacon advertisement. It indicates what a receiving device should expect the signal strength in RSSI to be when the beacon transmitter is one meter away.
A receiving device can then compare the txPower value to the actual measured signal strength and if it is stronger, that means the beacon is closer than one meter. If it is weaker then the beacon is farther than one meter. These two values (actual signal strength vs txPower) can be plugged in to a formula to get a rough distance estimate.
The reason this is a configurable field in the advertisement is twofold:
Not all transmitters have the same output power, so for best results the value should be set on a per device basis. (In practice this is rarely done.)
Obstructions and reflections of the radio signal can impact the expected signal strength at the receiver. For example, a beacon is installed under a counter or in a cabinet. For this reason, measuring the signal after installation (calibration) is recommended for best results.
The default txPower field for the iPhone 4s (the first phone supporting iBeacon for both reception and transmission.) was -59 dBm. This is fairly typical of mobile phones built since then and dedicated transmitters at the full power allowed by regulatory agencies. But variations of 5dB on specific device models are not uncommon.
Read more in my blog post here: http://www.davidgyoungtech.com/2020/05/15/how-far-can-you-go
When I tried to create iBeacon and then detect the beacon for some region range notifier does't notify the bacon for very small interval of time after again it starts appearing but there is drop for second and beacon gets disappear and again is start to appear.
I expect when an beacon is emitting then Range notifier should always return the beacon but sometimes it goes to 0 count and then again it returns the beacon.
**val beacon = Beacon.Builder()
.setId1("f7826da6-4fa2-4e98-8024-bc5b71e0893e")
.setId2("1")
.setId3("2")
.setManufacturer(0x004c)
.setTxPower("-59")
.build()**
**beaconTransmitter = BeaconTransmitter (this, BeaconParser()
.setBeaconLayout ("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24");
beaconTransmitter?.startAdvertising(beacon)
mBeaconManager = BeaconManager.getInstanceForApplication(applicationContext)
mBeaconManager?.beaconParsers?.add(BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"))**
**private val mRangeNotifier = RangeNotifier { beacons, region ->
//Here I receive zero beacon some time, mostly it works but form very small interval of time beacon count is zero
}**
There should be proper detection of beacon so no inconsistency occurs, at least I could always track the beacons.
I have tested it on -
One plus 5 with Android version 9
One plus 6 Plus with Android version 9
Poco F1 with Android version 8
Library version - 2.16.4
There are lots of variables here where there could be a problem:
The code shown (or supporting code not shown in the question.)
Hardware issues with the transmitting phone.
Hardware issues with the receiving phone.
Because you are working with three different phones, the combinations of possible sources of trouble grow with the combinations of phones.
In order to track this down, you must simplify your test cases:
Use a reference beacon transmitter for your tests that is most reliable. Choose a hardware beacon (best) or laptop-based beacon transmitter program (better) if you have one available. If you have no other choice, pick one of the phones to be the transmitter, and choose the one you suspect is most reliable.
Use an off-the-shelf beacon detector program based on this same library such as Beacon Scope, and test detections of the beacon. Using an off the shelf program will eliminate any coding errors in your detection software.
Test the off the shelf detection on each of your phones. This will tell you which, if any, have hardware trouble if they fail to detect reliably.
Once you have a reliable transmitter and know which phones are reliable detectors, go back to your program and work to make it as reliable as what you see with Beacon Scope using the most reliable transmitter.
I have written a Application detecting IBeacons (swift, IOS).
While i can detect another iPhones RSSI, Accuracy and Proximity correctly, when detecting my beacon (Qualcomm), it gets found, but does not display any useful values for the mentioned Variables.
Other Apps, downloaded from the App Store, also return the same (useless) values.
I therefore assume that it's not an explicit code bug, but has to do with the beacon (Maybe there are not enough packages being sensed by my Phone).
Does anyone know how to fix this?
This typically happens when the power calibration constant is incorrectly set in the beacon. This constant should be set to the measured RSSI at one meter. A typical value is -59. You may wish to see if you can configure this value in the Gimbal admin console.
It is also possible that the battery is low in the beacon and the signal is very weak. Replacing the battery may resolve the issue.
I have been working on a prototype iOS app utilizing iBeacons to provide location-relevant information to office employees depending on where in the office they are. The ideal use case is that whenever an employee enters or exits their office, a callback is fired which provides them some information in the form of a notification (it might make a server query to get information first, etc - that sort of thing). We also want to be able to do this when the app is backgrounded or terminated; fortunately, we already know that beacon region boundary crossings trigger the appropriate CoreLocation callbacks even if the app is backgrounded or suspended.
From looking around, I understand that broadly, I have two options for how to approach the beacon region monitoring:
Give each iBeacon its own CLBeaconRegion, and monitor for each of these regions independently.
Monitor for CLBeaconRegions that correspond to multiple iBeacons - for example, each iBeacon has the same UUID and only monitor for a CLBeaconRegion corresponding to that UUID - then try to determine which beacon triggered the boundary crossing using ranging.
Thus far, I had chosen option #1. The advantage of this approach is that I get didEnterRegion: and didExitRegion: calls for each individual beacon and immediately know which beacon I have entered/exited. Also, I only get one enter call and one exit call, which is exactly what I want. Unfortunately, I just realized that this approach also limits me to 20 beacons (since each beacon gets its own region).
I'm not as familiar with the exact implementation details of #2, so correct me if I'm wrong. But it seems that this approach has more drawbacks:
Apple discourages ranging when the app is in the background because the results may not be as accurate.
The ranging calls fire once every second, while I only want to have "enter/exit" callbacks.
If the beacons have region overlap, the ranging calls might continually flip which one is "closest", which would further complicate things.
Basically, I'm wondering if there is a way to utilize option #2, but still have the benefits of option #1 - a quick and easy way to immediately determine which beacon triggered the region change with only one enter or exit callback?
I hope this question is clear enough. It's not all entirely clear in my own head, especially how ranging works.
Option #2 is absolutely more complicated, but you must accept these complications in order to get around the 20 region monitoring limit.
A few points:
In the background, you only have around 5 seconds of ranging time, which does not give you as much time to average RSSI (signal strength) from each beacon to get a good distance estimate. So, yes, the estimates will be less accurate. If you understand this limitation and can live with it for your use case, there is nothing wrong with ranging in the background.
Yes, you will get multiple ranging calls per beacon after region entry, and you won't get any callbacks on region exit. You have to write extra code to take care of this. I have done this by maintaining a NSMutableArray of all the unique beacons (same uuid/major/minor) seen and update it in the ranging callback. You can then access this array in the region exit callback, so you know which beacons disappeared. Of course, it is possible that additional beacons were seen after the 5 seconds of background ranging time expires, but your app will never know about them. With this option, you must accept this limitation.
While it is true that errors on the distance estimate in ranging may incorrectly tell you which beacon is closest, you have an even worse problem when doing monitoring, because you don't get a distance estimate at all. If multiple beacons come into monitoring range around the same time, there is no guarantee that the first entered region callback you get will be for the closest beacon. So if your use case requires taking action based on the closest beacon, then you must do ranging (knowing that there may be error on the distance estimate.)
The drawback of the second approach is detecting the entry of a particular beacon will be purely based on ranging, that will not work if the application is killed. The reason is we will get didEnterRegion only once, because we are monitoring only one region with a particular UID. The next beacon with same UID will not be detected again if the application is terminated or if the background ranging stopped.
I recommend a combination of the mentioned approaches ,
Use same UID for all the beacons.
A beacon is uniquely identified using major/minor value that is collected when ranging.
As mentioned in apple doc, always keep number of monitoring regions below 20 by removing and adding beacons when the user moves from beacon to beacon (better to keep a beacon neighbour relationship graph in the server.)
Start ranging when entering the region ... and identify major/minor and calculate proximity.
Stop ranging when exiting the region.
Find the closest beacon from ranging method (need to skip unknown range beacons).
Monitor only the neighbours of the closest beacon in a given time.
When implementing both options, We should consider one fact, An iBeacon will be detected in 200feet distance. There may be multiple beacons in 200feet range.
If you use the same UUID for every beacon, you can just set the major/minor numbers to differentiate between the different beacons. This way, you are only monitoring for 1 beacon instead of > 20. Then just sort out which one is which from the other identifiers. This is how it works currently with Starbucks and other retailer apps. 1 beacon no matter where you are in the world, and different identifiers to sort things out on the back end.
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.