I am working on my home automation app. I am using estimotes iBeacons and what I want to do is give my Home Automation Control the ability to know my proximity in my home. Each iBeacon is given a virtual switch on my Home Controller and when I come in contact with a iBeacon my device either in foreground or background will update my control to turn on my switch for when I am near a beacon and turn it off when I have wondered away from my beacon. All of this works perfectly and I am loving it, however some of my conditions rely on me to be in a proximity for a period of time, and what I am noticing is after a couple of minutes or even after a half hour of being near a beacon, the iPhone 5s basically drops its connection and then fires it back up, causing it to perform an exit (turn off my virtual switch) and then immediately perform an enter (turn back on the virtual switch). As you can imagine this is very annoying to the wife and myself in the middle of the night when the bedroom lights start to flicker on and off because of the exit/enter. I have read about people having this problem and tried everything I have seen on the internet to no avail.
What I noticed is that whenever a monitor crossing has been crossed for a iBeacon, both the didDetermineState and the corresponding Enter/Exit call back functions are called. What can I do to get this to stop occurring? I can provide code examples if needed but this is more of a general question.
This is a common problem with iBeacons (and wives of geeks like us), and the simple solution is a software filter. You must ignore region exit events that last only a few seconds until you verify that there is no subsequent entry event.
You can do this by creating a variable (e.g justExitedRegion) that tracks these events. When you get an exit region notification, set justExitedRegion=YES and start a five second timer. When the timer goes off, if justExitedRegion==YES, perform your exit logic normally and set justExitedRegion=NO. Otherwise skip processing the exit logic.
Meanwhile, if you get an entry notification and justExitedRegion==YES, set justExitedRegion to NO and skip your entry processing.
If you just want to know whether you're at home or not at home, you could fire up the GPS on the phone and check your location.
Assuming you have a wifi network at home that your iPhone sees regularly, geolocation will work very well even inside the house where there will be no GPS signal. It will know no the latitude/longitude of the wifi base station and give that as your current location.
So use iBeacon as your primary location detection, but verify the data it gives you using GPS.
Also, you should contact Estimote to be sure you don't have a faulty unit or something. It is pretty new hardware, there could be issues.
Related
Hi i have a swift app that communicate with a BLE device with a beacon.
When i kill the app the beacon wake the app in background and it connect to the device and start communicating.
The interval of detection / connexion mostly take between 30 sec to up to 1 min after i kill the app. but sometime it take like 3 4 min.
Did anyone faced such issue and have an idea of whet could be happening it's the same process why it vary from time to time did it have a relation with the device itself ?
thx
Since iOS is closed source, it is impossible to say with certainty why delays in beacon detection happen. This is especially true in individual cases -- there are lots of variables.
However, we do have some ideas of how iOS CoreLocation manages to detect beacons based on reverse engineering, and I have some insight on based on building the Android Beacon Library which uses similar concepts.
Here is what we do know:
CoreLocation uses BLE hardware filters for pattern matching to get detections as quickly as possible. If a hardware filter slot is available, beacon monitoring will use the Bluetooth chip itself to look for a pattern first matching. This will give you a detection in less than a second when a beacon first appears.
In some cases hardware filters cannot be used (they are exhausted) or the beacon is known to be in the vicinity, so it is ignored. In these cases, a periodic backup scan is used to look for beacons.
The backup scan happens at different rates depending not the state of the phone and the beacon/bluetooth scanning state of apps running on the phone. If no apps are actively scanning and the screen is off, this can be every few minutes.
When the screen is turned on, it typically triggers a backup scan.
If your app is visible in the foreground and using ranging APIs or actively doing a BLE scan with CoreBluetooth, it is scanning at a 100% duty cycle.
In other cases, the duty cycle will be lower. If you are testing with a beacon that does not advertise frequently (e.g. less than the 10Hz in the iBeacon spec) it may miss detections at 10% duty cycle scan.
A few things to consider based on your description:
You may have exhausted all of the BLE hardware filters on your phone, and your app may not be getting one. Unfortunately, this optimization is completely hidden, so there is no way to tell for sure. You can increase the chances of getting a hardware slot by uninstalling any apps you think may be scanning for Bluetooth, then uninstalling and reinstalling your app, and restarting the phone. If all else fails, do a factory reset on a test phone.
Whenever you reboot your phone, it takes much longer for things to be fully booted than it appears. Location services are amongst the last things to be fully initialized. Always wait 5 minutes after reboot before doing any time-sensitive testing.
It takes time for iOS to detect it is in an out of region state with a beacon. This is typically 30 seconds if the app is visible on the screen, but if it is not, it may take significantly longer because of the timing of backup scans. And you cannot get a new region entry event if iOS doesn't realize you have exited yet.
If you kill your app when a beacon is visible (or when it had recently been visible) iOS may not know the in region / out of region state. If it thinks it is in region when it is not, it can take a long time to figure out it is out of region.
I have a GPS program the runs in the background and I thought I beta tested it thoroughly.
I recently submitted it to the App store for approval.
Since then I have inadvertently found out that Airplane Mode seems to disable the GPS stream and that there is no programatic way to tell if Airplane mode is on or not.
So I have to simply inform the user that, if it is more than 2 seconds since the last GPS fix, they should check that Airplane Mode is off. This seems a bit kludgy.
Is there a better way to do this?
AND, what else have I forgot about that can stop the GPS stream completely?
Thanks, Carmen
if it is more than 2 seconds since ..
This is a verry bad idea. When standing still at traffic signals, or for other reasons, you don't get a new location.
Either raise to 5 minutes, or better use a status bar which shows GPS is off.
No need to annoy users with messages.
what else have I forgot about that can stop the GPS stream completely?
The user disables the Location permission for your app. (But you can detect that.)
These both reasons, airplane mode and location permission disabled should be the only one from software view. (device internal causes)
Device external causes:
Of course using the device indoors, in tunnels or when having other obstructions to sky this hinders the GPS signal to be received.
My app registers for background location updates (not Significant Change. I need more granularity than kilometers)
That part works fine. I just want to stop the updates after the app has been in the background for 60 minutes. The way I'm doing it right now is to call stopUpdatingLocation in my CLLocationManager delegate.
However, I am unsure if this will actually stop my app from receiving background location updates, or if it will, but will just ignore them. Ideally, I'd like to not have my app be responsible for battery drain except for a small period of time after user activity.
Apple's documentation tends to send me in circles on this one. Right when I think "Executing Code in the Background" is about to spill the answer, it directs me to "Location Awareness Programming Guide." Right when that one is about to get specific about this question, it sends me back to "Executing Code in the Background." :)
I'm not sure whether your app has total control over this, but the docs for stopUpdatingLocation do state the following ...
Disabling event delivery gives the receiver the option of disabling the appropriate hardware (and thereby saving power) when no clients need location data
Which would suggest that should your app be the only one requesting background location data, and you request it to stop the GPS receiver would disable the appropriate hardware to save on power, which I think it was you're looking for.
What I can suggest is that you enable Power logging in Settings -> Developer, then run your app for an hour or so to a point where you think GPS is disabled, run for another hour and then compare the power usage in Instruments. This should provide you with a much clearer picture.
Calling stopUpdatingLocation will indeed stop GPS and so on, but if you place this call inside locationManager:didUpdateToLocation:fromLocation of your CLLocationManager delegate, then it might never be called.
Keep in mind that this method is only executed whenever a more accurate position or a (according to the active distance filter) significantly different position is available. If the device does not move at all and if the circumstances affecting the accuracy also do not change, it may not be called for hours (I have verified it for several minutes myself) and GPS will also stay enabled for this long.
For apps that only work in the foreground, you can use an NSTimer of 60minutes, but for apps that run in the background, the closest to a working solution that I have found so far, is a scheduled UILocalNotification. But even that requires the user to confirm an alert, before the app is restarted and able to turn the GPS off.
Maybe beginBackgroundTaskWithExpirationHandler: is the key to a better solution, but I have not completely figured it out, yet.
I'm trying to create an app similar to TravAlert which apparently 'pings' the GPS periodically to figure out where you are. Unfortunately, I'm having a heck of a time figuring out how to do it.
I can't use an NSTimer to fire off the GPS checks because NSTimer doesn't run in the background (which this app presumably must do). I can't use Local or Push notifications as "timers" because they automatically come with a notification and I don't want the use to know every single time that the GPS was queried.
I also tried using CoreLocation's startMonitoringSignificantLocationChanges and that works to a degree, but I can just see the case where the user happens to be in a region of poor cell service (apparently startMonitoringSignificantLocationChanges uses cell tower triangulation as a means of determining location) and thus the app fails to fire.
Any idea how TravAlert does it?
Thanks!
P.S. I'm not trying to rip off TravAlert by making a better app - this is for a college class and unfortunately neither my professor or anybody else in my class has the faintest idea as to how to replicate TravAlert's GPS "ping".
startMonitoringSignificantLocationChanges is the right choice for your app. You can get finer detailed location whilst your app is running. The other option to run the GPS in the background is intended for navigation apps hooked up in a car due to high power consumption.
I have a requirement in my iPhone app that I know when somebody running the same app is close by.
I'm thinking that GameKit using Bluetooth would let me do that. GPS location is not precise enough in this particular case.
However, if the user closes the app then the function won't work anymore. Even under iOS4, the task switching will close down the BonJour services so I can't have the app run in the background.
Seems to me I can only have this function if the user leaves the app up and running. Would you agree? Or is there a different approach I can take?
People are very concerned with privacy, so they would naturally expect such privacy invading functionality to be switched off when they close down the application.
If they choose to have this feature enabled, then it's a different matter. Then they expect that somebody else may locate them.
You might however consider implementing some sort of opt-in offline service, where the latest gps position is stored on a server including a timestamp. When somebody else (with the app running) moves within a certain distance of this location while it's still "fresh", then you send off a notification to the first device. That way the user would be notified that somebody may be close, and can then switch on their own device.