Beacon - StartRanging and stopRanging depend on the Beacon Proximity - ios

Can somebody help me how to solve the issue.
My current beacon setup :
Beacon device - Estimote.
UUID - same for the two beacons.
I have placed each beacon in two rooms, rooms are 20-30 Meters away from each other
I'm hitting webservice and updating something (when the proximity is near or immediate) when i enter a specific room (checking if major and minor of this room actually belongs to this room)
3.It also hits another webservice and updating something (when the proximity is far and unknown).
Problem with the current algorithm:
1. When i enter room 1 and if it is near or immediate, it hits webservice1. When this happens, room2 proximity will be far or unknown, then again webservice2 is hitting and also there are lot of fluctuation. Sometimes when i'm in room1, room2 beacon proximity shows as near. I don't this to happen
New Approach and Questions
I would like to Monitor for specific region , say room1 when i'm near say 5 meters away, and start ranging the beacon only when proximity is near or immediate. and stop ranging when proximity is far or unknown or i'm more than 5 meters away
When i move near to room2 (5 meters away) and if the proximity of room2 is near or immediate, it should start ranging room2 and stop ranging room1
I would like to have clear approach or way to write algorithm to achieve the above. Calculation can be using the proximity or using some other idea (like combination of RSSI and proximity or something else)
It would be great if you can explain me in detail with example on how to achieve the new approach or you can tell me if there is any other better approach, but please explain with code.
My foremost concern is, it should't range room 2 beacon when i'm in room1 or just 5 meter away from room1 and vice versa.

Have you thought about putting each beacon in its own region? So room 1 would be a region, and room 2 would be another region.
After that I would make use of locationManager:didEnterRegion: and locationManager:didExitRegion:. Within these, you can start and stop the ranging of your two beacon regions depending on which room you are in.
Please note, the Apple Docs state that:
When testing your region monitoring code in iOS Simulator or on a device, realize that region events may not happen immediately after a region boundary is crossed. To prevent spurious notifications, iOS doesn’t deliver region notifications until certain threshold conditions are met. Specifically, the user’s location must cross the region boundary, move away from the boundary by a minimum distance, and remain at that minimum distance for at least 20 seconds before the notifications are reported.
The specific threshold distances are determined by the hardware and
the location technologies that are currently available. For example,
if Wi-Fi is disabled, region monitoring is significantly less
accurate. However, for testing purposes, you can assume that the
minimum distance is approximately 200 meters.
EXAMPLE:
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
if (region.identifier == YOUR ROOM 1 IDENTIFIER)
{
//Start ranging room 1
}
else
{
//Start ranging room 2
}
}
- (void)locationManager:(CLLocationManager *)manager
didExitRegion:(CLRegion *)region
{
if (region.identifier == YOUR ROOM 1 IDENTIFIER)
{
//Stop ranging room 1
}
else
{
//Stop ranging room 2
}
}

The core problem is sending info to the server at inappropriate times. It really has nothing to do with starting ranging.
You cannot start ranging when proximity is relatively close -- you have to range in order to determine proximity.
Rather than an algorithm that starts and stops ranging, I suggest you simply leave it on all the time, and build a filter that decides when to make the server calls. Here's a starting point for the logic I would suggest:
Call the server if all the following are true:
beacon.accuracy < 3
all other beacons detected have beacon.accuracy > 3
no server call has been made for this beacon recently
EDIT: You can reduce the fluctuation on the accuracy reading by setting your beacon transmitter power as high as possible to maximize the signal to noise ratio.

Related

Detecting beacons depending on its distance from the device

I'm developing a small application based on technology iBeacon.
The general idea is to place a beacon on each piece of art in a museum that has certain information associated.
The problem comes when several beacons are too close together, despite configure the beacon with the lowest transmission power, the application detects both beacons.
I have tried several manufacturers, Estimote, radius networks, onyx beacon, BlueCat ...
Even setting the beacons at the lowest level of transmission, 0.5 to 1 meters, according to their specifications.Located in front of a piece of art, the application detects the nearest beacon, but also detects beacons that are more than 4 meters. How is this possible if according to the manufacturers, the distance broadcasting in the lower range is about one meter?
Any idea about it? I would appreciate some help.
Thanks
It's important to understand that Bluetooth beacons are radio transmitters. Like all radio transmitters, the signal will continue for large distances, but get weaker and weaker the further it goes. There is no hard maximum distance that Bluetooth radio signals will travel. Beacons pulse out advertisements as packets over the radio. The further you go, the smaller percentage of packets will be received.
When people say that a beacon has a range of 40-50 meters, that typically means that a large percentage of the packets will be received at this distance. But it is not a hard limit. In testing in open areas, I have seen rare detections of a single beacon packet at 200 meters away.
The same principle applies when you "dial down" the transmitter power on the beacon to give it a range of only a few meters. In some cases where radio conditions are favorable (clear line of sight, phone aimed just the right direction, an object behind the beacon that reflects the signal back to you like a dish antenna) the phone will detect the beacon at a much greater distance.
A better approach for your use case may be to turn up the beacon all the way, and rely on beacon ranging to decide which beacon is closest. You would then compare the estimated distance of all the beacons that are visible and take action on the one that has the shortest distance. If you take this approach, however, be sure to turn the transmitter power back up on your beacons. The weaker the signal, the less accurate the distance estimates tend to be.
I have written the following logic. #davidyoung , please verifiy and suggest if you have a better logic
beaconManager.addRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
if(!beacons.isEmpty()){
Beacon beacon = getNearestBeacon(beacons);
if(isUserNearBeaconForLong(beacon)){
logToDisplay("Long time near "+beacon.getId1());
}
}
});
/*Finds the nearest Beacon out of all detected beacons*/
private Beacon getNearestBeacon(Collection<Beacon> beacons) {
List beaconList = new ArrayList<Beacon>(beacons);
Collections.sort(beaconList,new BeaconDistanceComparator());
return (Beacon) beaconList.get(0);
}
private boolean isUserNearBeaconForLong(Beacon beacon) {
//Some logic to detect that the same Beacon is seen as the nearest for a long time to identify a person is waiting near that artwork
}
class BeaconDistanceComparator implements Comparator {
#Override
public int compare(Object lhs, Object rhs) {
Beacon beacon1 = (Beacon) lhs;
Beacon beacon2 = (Beacon) rhs;
if(beacon1.getDistance() == beacon2.getDistance())
return 0;
else if(beacon1.getDistance()>beacon2.getDistance())
return 1;
else
return -1;
}
}
The ranging period can be say every 5 seconds
I am yet to test this solution as my Beacons will be shipped by tomorrow. I will update my solution if I find any issues in this.

iBeacons Multiple Monitoring

I am developing an application which will have multiple ibeacons to detect and react according. The client has different stores in which he wants to deploy the beacons. I am now in a situation where the ibeacons are very close to each other. All the beacons share the same UUID but different major and minor values.
The situation is this:
A user enters the shop and it receive first notification through beacon monitoring. Now to get the other notification for the other beacon the user has to left the region and enter it again in order for the didEnterRegion to call otherwise the user will not get the alert for the other beacons. And that is not happening in my case. The beacons are close to each other that the user not really leaves the region once it enters it. And the notifications do not come through ranging once the device is locked or the application is killed.
Any suggestions on how to tackle this problem in a real case scenario. How to get the notification for all the beacons on a lock screen. I am using the estimote beacons for development.
This is a common problem. As you have seen, background detection is only triggered by region monitoring, and if your regions are set up to cover multiple beacons in the same physical area, you won't get background notifications as you move between them.
You can only get entry/exit updates in the background for a maximum of 20 BeaconRegions per app. So the common solution is to creatively use these 20 BeaconRegions for maximum results. If you have 20 or fewer different beacons within range of each other, the technique is straightforward -- you simply create one region for each beacon, and monitor on all of these.
If you need to work with > 20 beacons, then you have to come up with a numbering scheme that helps this along. For example, you can set all of the beacons' ProximityUUIDs to the same value, number your major values 1-20, and then set the minor values to a unique number for each beacon. You then would then monitor for the 20 regions, each with a different major number. You would also set up simultaneous ranging so you can also get the minor identifier of detected beacons. Like this:
CLBeaconRegion *region1 = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:#"region1" major:1 ];
CLBeaconRegion *region2 = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:#"region2" major:2 ];
...
CLBeaconRegion *region20 = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:#"region20" major:20 ];
[locationManager startMonitoringBeaconsInRegion:region1];
[locationManager startRangingBeaconsInRegion:region1];
[locationManager startMonitoringBeaconsInRegion:region2];
[locationManager startRangingBeaconsInRegion:region2];
...
[locationManager startMonitoringBeaconsInRegion:region20];
[locationManager startRangingBeaconsInRegion:region20];
This technique works well if you can ensure that there is never a case where two beacons with the same minor number that would be within radio range of a mobile device simultaneously (e.g. beacons with the same minor must be > 100 meters apart). If you can't do this, then you have to start making compromises.
Multiple beacons monitoring is not possible. Since iOS has limits, maximum number of supported regions should be 20. We can achieve your use case by doing the followings.
Group all the beacons with single UUID. We can monitor one region instead monitoring multiple regions
Capture the nearby beacons through ranging(Monitoring will trigger only enter and exit. When the user stays within the region for longer time, then monitoring delegated won't be triggered.) Sort the beacons with proximity received through didRange method.
If no beacons found with "Immediate" Proximity, move to next proximity Near.
Display notification if we found any one beacon with proximity Immediate. If more than one beacons are found with immediate proximity, then sort using RSSI. Lowest RSSI will be the closest beacon and display the notification for the closest one.
If no beacons found with "Near" Proximity, move to next proximity Far.
Display notification if we found any one beacon with proximity Near. If more than one beacons are found with near proximity, then sort using RSSI. Lowest RSSI will be the nearest beacon and display the notification for the nearest one.
If no beacons found with "Far" Proximity, then you don't have any beacons nearby.
Display notification if we found any one beacon with proximity Far. If more than one beacons are found with Far proximity, then sort using RSSI. Lowest RSSI will be the nearest beacon and display the notification for the nearest one.
Unknown - You can ignore this
You can approach this problem and solve it way easier. Stop triggering the notification when the users exit the region. Use instead the proximity function which will give you more flexibility: use CLProximity. You can choose between immediate, close, far etc. So based on the minor of the beacons and its proximity you can trigger the notifications you want.

iBeacons: Detect proximity change in background

I'm trying to understand how you are supposed to detect proximity changes in the background.
The only window I get to range is when I enter a region, but this might be pretty far away.
I would like to present something when the user enters "near" or "immidiate", but if you get "didEnterRegion" at far, than stand around, then approach the beacon, you don't get any more ranging time, because you are still in the same region.
Is there a way to either extend the "ranging" time to let the user get near the beacon, or can you make "enterRegion" happen at a different proximity than "far"?
Background ranging time is limited to a few seconds as Charles says in his answer.
If you need to delay action until you are in the immediate region, then you must use iBeacons that allow you to reduce the transmit power so the transmission radius is smaller. The RadBeacon product from RadiusNetworks has this configurability for this exact purpose.
If you configure a RadBeacon for minimum transmit power, your phone will not detect it until it is a few feet away, sending you the entry event and starting your limited ranging window at that time.
Full disclosure: I am Chief Engineer for Radius Networks.
This walkthrough shows how to do what you're asking. I'm in the process of adapting and testing it for iOS 8, but the resulting app works well on iOS 7, pushing local notifications whenever the proximity changes.
In the best practices section in Apple's Getting Started with iBeacon guide it mentions that ranging API should not be used in the background.
• Ranging API are not expected to be used in the background. For best results, ranging should
be used when your app is frontmost and the user is interacting with your app.
Could be a shortcut to app rejection, so take caution.
Given this, you shouldn't really be expected to determine proximity when in the background. I'm also employing the low signal technique, but it becomes a little trickier to differentiate between beacons when you only use one monitored region for multiple beacons...
What's possible with iBeacons in background is pretty limited.
What you can do is monitor regions in the background (which gives you the didEnter / didExitRegion events).
You can also switch on ranging for the beacon and, for the 10 or so seconds after you get a beacon enter / exit event from region monitoring you will also get ranging info (i.e. the immediate / near / far data).
Perhaps you could trigger a local notification at that point to try to get the user to bring your app into foreground - then you'd be able to get the ranging data. If not then, based on my tests, you're only going to get the 10 seconds of ranging data.
To your question about adjusting the ranging time or adjusting the enterRegion proximity - no, these aren't possible in the current version of iOS.

iOS Geofence CLCircularRegion monitoring. locationManager:didExitRegion does not seem to work as expected

I am currently trying to get my app to monitor particular regions using CoreLocation however I am finding that it does not seem to work as expected, it seems to me that it cannot work with small a small radius set for each location i.e. 10m.
I've also put together a little test app which plots the circle radius on a map so I can visually see what is happening.
The code I am using for monitoring locations is as follows:
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
// Set-up a region
CLLocationDegrees latitude = 52.64915;
CLLocationDegrees longitude = -1.1506367;
CLLocationCoordinate2D centerCoordinate = CLLocationCoordinate2DMake(latitude, longitude);
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:centerCoordinate
radius:10 // Metres
identifier:#"testLocation"];
[self.locationManager startMonitoringForRegion:region];
I have not put up the code here for DidEnter region etc as I know that works when I go over 100m away from the monitored region.
Here is a screen shot of the app when I am well over 10 meters away from the purple location on the map, the did exit region events do not fire, however if I switch my location to London it fires and also when I set my location back to where the blue location is currently it also fires.
Does anyone know if there is a limitation with the minimum region radius at all or perhaps I am doing something wrong.
Thanks Aaron
I don't think region monitoring will work well for such a small radius.
The best accuracy with the GPS chip and kCLLocationAccuracyBestForNavigation is often just 10 meters.
Apple says (in the Location & Maps PG) that the minimum distance for regions should be assumed to be 200m
I've heard that region monitoring is using WiFi to get it's position (which makes sense for power savings). WiFi accuracy is more like 20m-100m. I'm not sure how having another app using background location (i.e. using GPS) would affect this. Probably, the location manager would share information to make the accuracy better.
Region monitoring can take 30 seconds to fire once inside a region, and a couple of minutes to fire after leaving a region (to prevent location glitches from triggering it).
When region-monitoring was first introduced, they said that it would only work with 100m regions and anything smaller would be bumped up. This probably still happens.
There's a deprecated method startMonitoringForRegion:desiredAccuracy: which allowed you to specify the distance past the region border to start generating notifications. Presumably this feature has been rolled into startMonitoringForRegion: but is still there. A 10m region might end up with a 10m buffer.
If you want to do this, specify a larger region around where you want to monitor, and when the device wakes up in that region, start background location updates (GPS) and use CLCircularRegion's -containsCoordinate: to trigger when the device is within 10m manually. This method is officially sanctioned by Apple (see WWDC 2013 Session 307).
From the CLCircularRegion docs:
Remember that the location manager does not generate notifications immediately upon crossing a region boundary. Instead, it applies time and distance criteria to ensure that the crossing was intended and should genuinely trigger a notification. So choose a center point and radius that are appropriate and give you enough time to alert the user.
From the Location & Maps PG:
Region events may not happen immediately after a region boundary is crossed. To prevent spurious notifications, iOS doesn’t deliver region notifications until certain threshold conditions are met. Specifically, the user’s location must cross the region boundary, move away from the boundary by a minimum distance, and remain at that minimum distance for at least 20 seconds before the notifications are reported.
The specific threshold distances are determined by the hardware and the location technologies that are currently available. For example, if Wi-Fi is disabled, region monitoring is significantly less accurate. However, for testing purposes, you can assume that the minimum distance is approximately 200 meters.
There's further inside scoop from this post by Kevin McMahon, who asked the Core Location engineers about region monitoring at a lab at WWDC 2012. This info will have changed in the meantime, but the part about region categories is interesting. Here's an edit:
Fine Region (0 - 150m)
- With the floor of 100m this category's range is effectively 100-150m.
- For regions this size performance is heavily dependent on the location-related hardware
- The amount of time that it takes Core Location to detect and call the appropriate delegate method is roughly 2-3 minutes on average after the region boundary has been crossed.
- Some developers have figured out independently that smaller regions would see quicker callbacks and would cluster smaller regions to cover one large area to improve region crossing notifications.
This seems to be a bug in CLLocationManager. I've done extensive testing using various region radius configurations and locationManager:didExitRegion does not fire in an expected way. This seems to be either a rather nasty bug or region monitoring does not happen at all like the documentation suggests. I have the test harness available to anyone who wants it:
http://www.mediafire.com/download/x863zkttltyalk6/LocationTest.zip
Run it in the simulator and start the test by by selecting Debug -> Location -> Freeway Drive in the iOS simulator menu. The number you see is the distance from the center of the monitored region. The background color will be green while the device is within the monitored region and red when outside the region. The text below the distance are event logs.
After running the app, you should see locationManager:didExitRegion fire at 5319 meters from the monitored region. The route will loop every 37 minutes and you'll see the device exiting the region always at 5319 meters.
I've submitted a radar with Apple (17064346). I'll update this answer once I hear back from them. At least then we'll have some input from the canonical source.
Here's the detailed text sent to Apple:
Using a test app on the iOS simulator as well as on an iPhone 5S the
CLLocationManager doesn't seem to fire didExitRegion callbacks in an
expected way. Regardless of the radius of the circular region being
monitored, the callback won't happen until a threshold of around 5000
meters is hit.
Steps to Reproduce:
1. Run the attached app
2. Start region tracking by selecting Debug -> Location -> Freeway Drive in the iOS simulator
3. Monitor the app. The large # indicates the distance from the center of the watched region.
4. After about 190 seconds and 5300 meters didExitRegion will finally fire.
Ths issue does not seem to be related at all to the size of the region. According to the Apple docs, even small regions are supported:
In iOS 6, regions with a radius between 1 and 400 meters work better
on iPhone 4S or later devices. (In iOS 5, regions with a radius
between 1 and 150 meters work better on iPhone 4S and later devices.)
On these devices, an app can expect to receive the appropriate region
entered or region exited notification within 3 to 5 minutes on
average, if not sooner.
Although region events don't happen instantaneously, they should happen fairly quickly. From the Apple docs:
Region events may not happen immediately after a region boundary is
crossed. To prevent spurious notifications, iOS doesn’t deliver region
notifications until certain threshold conditions are met.
Specifically, the user’s location must cross the region boundary, move
away from the boundary by a minimum distance, and remain at that
minimum distance for at least 20 seconds before the notifications are
reported.
This is not at all what I am seeing in the test harness. On the simulator the device will always be 5000+ meters away from the region before a locationManager:didExitRegion event occurs.
I like the answers by both Michael and Nevan. I would like to add more information from my personal experience/opinion in developing Location Based iOS Application with Region Monitoring and also highlight some important points:-
Be realistic on Region Monitoring
Region Monitoring is using Global Positioning System (GPS), Wifi and other technologies to determine if the device is inside or outside the monitored region. Don't forget that our earth is 510 square kilometers and about 30% are land (149 million km2). It is a huge area. Remember the recent MH370 missing case? Our current most advance technology could not even pinpoint an estimated region of that missing plane.
If you want to monitor for a small region with only 10 meter radius. It could possibly work inside a highly dense city with a lot of cell towers and wifi connected areas. But at the same time, the signal might be blocked by high rise towers which might cause the signal loss for a few seconds/minutes which caused the delay in delivering the notification.
So, you really have to consider the above information before deciding how big is the region that you want to monitor. Personally I think 10 meter radius is too small.
Be Realistic on the Number of Monitored Regions
The current Core Location technology can only monitors up to maximum 20 regions on a single app. Make sure that the monitored regions are not too close to each other as well.
I personally have tested 3 regions that are about 100 meters in radius which are about 200 meters aways from each others. Sometimes I can get notifications from all these 3 regions when I am driving through them, but sometimes, I can only get the notification from the First region only. What could be the reason? I could not know. The regions might be too close to each other. Or the cell towers decide that my device does not actually inside the monitored region.
There was one person on StackOverFlow who wants to monitor 1800 points on our Earth. Don't be like him as he is quite unrealistic and probably does not understand the limitation of current Core Location technology. Link: Check if the user location is near of some points
Fine Tune The LocationManager
If your app needs to monitor a small area or needs the location update frequently. Here are the potential properties of your location Manager.
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.activityType = CLActivityTypeAutomotiveNavigation;
kCLLocationAccuracyBestForNavigation will consume more battery compare with kCLLocationAccuracyBest. But, it will be more accurate.
I found a glitch in region monitoring in iOS 7 when there are multiple notifications triggered at the same time in different monitored regions. I have found a solution to filter out this glitch. For more info, please visit: Region Monitoring Glitch on iOS 7 - Multiple Notifications at the same time
Don't Be Over Ambitious
You might have used some apps which can monitor a small region and are very accurate and able to notify your the same second you step into the region. And you have the inspiration to develop the exact same app to compete with them. But do you understand what happens behind scene? What additional technologies that they are using? And what partners that they are collaborating with?
I have done some research on that and found out that some of the technologies that they use are not available publicly. Some of those companies are heavily funded and could pay a premium to the telecommunication companies in order to get the best location accuracy for the best user experience. I do not understand the details on how it works. I believe most of the location determination is actually on the server end (back end), not the mobile (front end).
So, the apps that are developed by those companies not only can pinpoint the best accurate location but also does not consume a lot of battery.
NOTE: I just want to share my 2 cents. The above information consists of my experience and personal opinion. It might not be 100% accurate as I am still learning Core Location and Region Monitoring.
I do agree with Michael G. Emmons, and want to share my experience too:
I tested my code with three regions as shown in the image below:
Explaining the behaviour:
My current location is Region-1, and i start monitoring for the above
three regions, and call to requestStateForRegion, to determine, if there is any region inside, where i am currenly standing.
Then i get "Enter" notifications, for first two region (region-1, and region 2), but it should only detect the region-1.
Now when i enter in region-2, i get the Enter notification for region-3. but i should get the notification for region-2 here.
Now when i enter in region-1 again, i get the Exit event fired for the region-3, and this continues.
but i don't get any Enter/Exit events for first two regions, until i move at-least more than 7Km-10Km far from first two regions.
Expected Behaviour:
- Enter/Exit event should be triggered only when i am crossing the boundary of regions, or inside the regions, not before 500 meter from the region.
My Assumption:
What i have noticed after all the experiment, that when i call
"requestStateForRegion" for all three regions,
it detects all regions inside region of radius 5000m, thats why it
detects first two regions at the same time (region-1 create a circle
of 5000m radius, and region-2 comes in its range, thats why region -2
is also getting detected).
and when user moves far more than 10Km, their Exit events will be called and when user comes back in these regions, their Enter event will be fired. Its the same case as explained by Aaron Wardle above.
Region-3 is getting detected, because,when user enters in region-1, ie. 8-9km far from the region-3, so Exit event is fired for this, and when user is on the route for region-2, here even when region-3 is 5000 meters far, still it detects the region-3 and fire, Enter event for region-3.
So i think that all the regions inside 5000 meters are being detected, and as user moves away 10 km from detected region, its Exit event will be fired. otherwise if user is inside the 5Km range, it will never call it Enter/Exit events again.
Please update me on, if anyone has fixed this issue, or Apple documents anywhere about this issue.
Based on #Nevan's answer, which indicated some sort of coverage in WWDC 2013 307 (which didn't directly address this), I came up with a reasonable solution to getting < 10m accuracy for the arrival to a location, though I have a feeling that implementing -(void)locationManager:didVisit: might make this more battery-conservative, but would provide less frequent updates.
First, have some regions with 0..150m radius, and start monitoring. Doesn't really matter, as the system seems to trigger these at around 150~200m:
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:CLLocationCoordinate2DMake(location.lat, location.lng) radius:50 identifier:location.name];
[_locationManager startMonitoringForRegion:region];
Then, implement
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
for (CLCircularRegion *enteredRegion in _locationManager.monitoredRegions.allObjects) {
if ([enteredRegion.identifier isEqualToString:region.identifier]) {
self.locationManager.activityType = CLActivityTypeFitness;
self.locationManager.distanceFilter = 5;
[self.locationManager startUpdatingLocation];
break;
}
}
}
The system will start monitoring and reporting to your delegate a stream of locations, even if your app is suspended (need UIBackgroundModes to include location array element).
To check if one of those locations is within the centre of one of your regions, Implement:
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
CLLocation *firstLocation = [locations firstObject];
CGFloat const DESIRED_RADIUS = 10.0;
CLCircularRegion *circularRegion = [[CLCircularRegion alloc] initWithCenter:firstLocation.coordinate radius:DESIRED_RADIUS identifier:#"radiusCheck"];
for (CLCircularRegion *enteredRegion in _locationManager.monitoredRegions.allObjects) {
if ([circularRegion containsCoordinate:enteredRegion.center]) {
[_locationManager stopUpdatingLocation];
NSLog(#"You are within %# of %#, #(DESIRED_RADIUS), enteredRegion.identifier);
break;
} else if ([enteredRegion containsCoordinate:circularRegion.center]) {
NSLog(#"You are within the region, but not yet %#m from %#", #(DESIRED_RADIUS), enteredRegion.identifier);
}
}
}
You'll also want to implement:
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
[_locationManager stopUpdatingLocation];
}
This is more like an important comment. From Region Monitoring and iBeacon
Testing an iOS App’s Region Monitoring Support
When testing your region monitoring code in iOS Simulator or on a
device, realize that region events may not happen immediately after a
region boundary is crossed. To prevent spurious notifications, iOS
doesn’t deliver region notifications until certain threshold
conditions are met. Specifically, the user’s location must cross the
region boundary, move away from the boundary by a minimum distance,
and remain at that minimum distance for at least 20 seconds before the
notifications are reported.
The specific threshold distances are determined by the hardware and
the location technologies that are currently available. For example,
if Wi-Fi is disabled, region monitoring is significantly less
accurate. However, for testing purposes, you can assume that the
minimum distance is approximately 200 meters.
Sounds like even 1 meter should work (and work better on iPhone 4S+ devices):
startMonitoringForRegion:
(...)
In iOS 6, regions with a radius between 1 and 400 meters work better on iPhone 4S or later devices. (In iOS 5, regions with a radius between 1 and 150 meters work better on iPhone 4S and later devices.) On these devices, an app can expect to receive the appropriate region entered or region exited notification within 3 to 5 minutes on average, if not sooner.
In the past few days iv'e been testing a geofencing feature on my iOS 8.1 device (iPhone 5S) for an app iv'e developed.
The app is registering few regions to the iOS gefence service. The app's logic needs that each geofence radius is between 40 to 80 meters.
I'm seeing so far that in areas with larger number of cell towers and Wifi hot-spots, the geofence detection is good enough on entering regions. That is, in down town areas, business areas etc' the geofence detection is working fine.
Unfortunately, the opposite occurs in areas with few cell towers & wifi networks. My neighborhood, for example, is about 1000 meters width and 500 height (1KM x 0.5KM), and there are no cell towers in it. There are few cell towers thought, on the perimeter that surrounds the neighborhood. Unfortunately In the perimeter of the neighborhood the geofence service detects nothing.
Needless to say that i'm testing with Wifi enabled on the device.
When i test my app on Android: the geofencing service on android 4.3, 4.4 & 5.1 works much better than on iOS. The Android's geofencing service does not detect 100% of region transitions, however it detects 50%-90% of the region transitions.
I conclude the following: If there would have been more cell towers & Wifi hot-spots & if Apple would have improved the geofence service then the detection on iOS devices would have been as good as in Android's.
Geofencing works by detecting a user moving from one cell network tower to another cell network tower.
Therefore smallest area you can define is dictated by how close together the cell towers are.
Inside a shopping mall or sports stadium, it might be able to do 10 metres — cell towers are often extremely close together. In a regional area anything smaller than 100km can fail.
If you need smaller areas, you need to use bluetooth instead of cell towers (iBeacons). If there is a bluetooth low energy device in the target area you can set the range to very short (centimetres) or reasonably large (up to 30 metres or so). Note this all depends on the quality of the iBeacon hardware, some are better than others.
Unfortunately bluetooth (version 4.0 or newer) and cell network towers are the only way to monitor locations without significantly draining battery. Keeping the GPS active to check for a 10 metre boundary would drain the battery from full to completely flat in about 2 hours even with the screen switched off.

Proximity range for Beacons changes back and forth even when the App is in the same place

Beacon Proximity range changes the proximity response as Near - Immediate - Far, even while the ios Device remains in the same place.
As I open a view when the proximity response is Near. I get the proximity response back and forth, Near - immediate then Near. It shows up the view again and again
How can we solve this issue. Is there any event handler.
Thanks.
The proximity and accuracy values appear to be quite 'noisy'. It can also depend on your environment. Water (and therefore people) absorbs the frequencies used by Bluetooth so people moving can have an impact, but I observe variation in between 1.2m and 1.9m when both devices are sitting on my desk.
I think you are going to have to deal with the noise in your app. Once a view has opened you should keep it open until the beacon is 'far' (or you get a region exit) for some period of time. If the state transitions back to near or immediate then reset the timer.
You need to use some code similar to the following -
-(void)locationManager:(CLLocationManager *)manager
didRangeBeacons:(NSArray *)beacons
inRegion:(CLBeaconRegion *)region {
CLBeacon *beacon=beacons[0];
switch (beacon.proximity) {
case CLProximityFar:
if (self.farTimer==nil) {
self.farTimer=[NSTimer scheduledTimerWithTimeInterval:30 target:self selector:#selector(farTimerFired:) userInfo:beacon repeats:NO];
}
break;
case CLProximityNear:
case CLProximityImmediate:
if (self.farTimer!=nil) {
[self.farTimer invalidate];
self.farTimer=nil;
}
break;
case CLProximityUnknown:
NSLog(#"Beacon proximity is unknown");
break;
}
}
-(void) farTimerFired:(NSTimer *)timer {
CLBeacon *beacon=(CLBeacon *)timer.userInfo;
NSLog(#"Beacon %# is really far",beacon.proximityUUID.UUIDString);
self.farTimer=nil;
}
Understand that the proximity value is just an estimate based on radio signal strength, so this is expected behavior due to noise as #Paulw11 says in his answer.
Two things you can do to make the proximity (and accuracy) readings as solid as possible:
Choose an iBeacon with as fast of a transmission rate as possible. Different ibeacons transmit advertisements at different frequencies from 30 times per second to once per second or less. Generally, faster transmission rates give you less noisy distance estimates because they give iOS more radio signal strength measurements to work with. For your testing, Try an iOS-based iBeacon like Locate for iBeacon to see if it helps. It is known to transmit 30x per second.
Make sure your iBeacon is properly calibrated. This will not reduce the noise, but it will make sure the readings you get are correct as possible on average. If not properly calibrated you may see jumps between immediate and near more often when the device is solidly in the immediate zone, because it is calculating the distance as too far away.
Beyond this, A software filter on the proximity value might help as #Paulw11 suggests, but it still won't be perfect. You simply have to decide if you can live with the noise for your use case.

Resources