Bluetooth RSSI value drops inexplicably when iPhone is at rest - ios

We are writing a pair of Core Bluetooth applications. The MacOS application is implementing a CBCentral​Manager and the iOS application is implementing a CBPeripheralManager. The iOS peripheral's UIBackgroundModes key is set to bluetooth-peripheral in its Info.plist file.
The apps are paired and are successfully sending messages back and forth over Bluetooth every 30 seconds. This works whether the iOS app is in the foreground or background.
The Mac application is receiving the RSSI value of the iPhone. With the iPhone sitting next to the Mac the RSSI value fluctuates generally in the range of -45 to -65 dBs (with occasional drops to -75 dBs). But after an extended length of time without the iPhone moving the RSSI drops to a range of -55 to -75 dBs (with occasional drops to -85 dBs or more).
The graph below illustrates the behavior. The X axis is time in seconds and the Y axis is dBs. In this example the RSSI stays in the range -45 to -55 dBs for 300 seconds. But then for seemingly no reason the RSSI drops to the range -55 to -75 dBs and stays in the range indefinitely.
During this period of lower RSSI value the apps continue to successfully send messages back and forth so it does not appear that the iOS app has been suspended.
At about 600 seconds the iPhone is picked up (which is appears to be correlated with a small uptick of RSSI value) and then the iPhone is moved 20 feet away (which causes the RSSI to drop as we expected). Then at 900 seconds the iPhone is moved back to its starting location which corresponds to the last rise in RSSI value.
We are obviously expecting the RSSI value to drop when the iPhone is moved away and to increase when the iPhone is moved close again.
But we have no explanation for why there was the initial drop of RSSI value at around 300 seconds. Our problem is that we cannot differentiate between the RSSI dropping for that unexplained reason and the RSSI dropping because the iPhone is moved away from the Mac.
Questions:
1) Is there an explanation for the RSSI dropping on its own without any change in the environment? Could iOS be reducing the Transmit Power?
2) Is there any way to prevent the RSSI from dropping or force it back up programmatically?
3) Is there a way to programmatically recognize that the system has reduced the signal strength which would allow us to calibrate subsequent values?
Any explanations, fixes, and/or suggestions would be greatly appreciated.
RSSI vs Time (in seconds)

Related

CLLocationManager False didExitRegion

With CLLocationManager
I am defining regions and responding to didEnterRegion and didExitRegion. This works fine in that I get the callbacks for the Enter and Exit as the device moves between regions.
The problem is that I have run the app overnight a few times with the phone device sitting on a table and not moving. The phone device is in the center of an entered region.
During the night, about once an hour, I get a didExitRegion and then within less than 15 seconds I get a didEnterReqion.
My solution to filter these phantom exit/enter pairs was to set up a timer when I get an exit to wait 15 seconds and then if I do not receive an Enter for the same region within that timer window then I process the Exit.
This works if the app is in foreground, BUT in background it fails. In background mode I still get the didExitEvent but I think the App is going back in to background mode before the 15 second window has elapsed do I don't fire that timer until the phone goes back in to foreground mode.
The Radius of my Region is 250M and the accuracy mode is nearest 10 meters. My device, while sitting still, is centered in the Region and yet I still get these phantom Exit/Enter pairs once an hour.
Either I need to find a way to stop the phantom exit/enter pairs, or need a way to keep the timer running the full 15 seconds before the app moves back to background mode.
Does anyone have a good solution for dealing with random exit/enter or enter/exit pairs for stationary devices?
Also what is the max time that a timer can run upon an app waking event in background mode?
Geofencing does not use triangulation (that's why "accuracy mode" you mentioned is totally irrelevant). Geofencing relies on a "digital signature" - set of wifi access points and cell towers your iPhone detected along with strength of signal coming from these sources. Whenever this digital signature changes, the phone might be fooled into triggering a geofence event.
However, before reporting the event, iOS runs triangulation (in most cases without GPS) - and the resulting location is available to you to check if you are really outside the geofence. If location accuracy is too low relative to size of your geofence, you may obtain a better reading - requestLocation() will do the trick, as it will not run for more than 10 seconds.
By the way, that triangulation sequence the iOS runs after detecting a geofence event most likely is why your phone registers didEnter event shortly after didExit.
Arming a timer in background mode makes no sense, as iOS silently suspends background tasks after first 15 to 20 seconds of background execution. This behavior was introduced with iOS 7 and enforced for timers during iOS 10 lifetime.

didDetermineStateForRegion and didExitRegion returning false responses

I am showing the user a local notification when they enter a beacon region, and when they exit a beacon region. The exit is the most important because I tell the user how long they dwelled in that location. I am using region monitoring because it allows me to keep track of the beacons even when the app is in the background or suspended. I am experiencing a bug where I am monitoring 3 beacons (this happens with 2 and 1, but less frequently). My phone will sleep, and I will continue to monitor for the beacons. Then, my app will wake due to didExitRegion for one of the beacons, even though all 3 beacons are sitting face up on the same desk as my phone. It is a different beacon each time, so I have ruled our signal strength. Then, once the app is awake, it rediscovers the beacon and immediately re enters (because it never left the signal in the first place). I am detecting the signals with an android device at the same time, and the beacons are broadcasting the whole time, so the iPhone should not be losing these signals, especially not for a long enough time to consider it an exit.
I tried to remedy this by using
[self.locationManager requestStateForRegion:region];
However, in these situations this will return state 2, which is CLRegionStateOutside.
How should I get around this? Has anyone had a similar experience. I should be able to dwell in a beacon region for 1 minute or 1 hour and only get an exit when the beacon is undetected for 30 seconds.
A few things to check:
Verify this happens with multiple iOS devices. It is possible that the iOS device has a hardware problem such that it has weaker Bluetooth LE reception, or picks up more radio noise. I have never seen this myself, but I have heard reports of others who insist they have seen it on some iOS devices.
Check the signal level received by the iOS device and the Android device by ranging the beacon using an app like Locate for iOS and Android. The signal levels should be similar on both devices. A strong signal will have an RSSI of about -60 or less negative. A weak signal will have an RSSI of about -100 or more negative. If you have a weak signal, it may cause intermittent detection losses because radio noise will sometimes prevent packets from being received properly. If you can configure your beacons to increase their transmitter power level, do so.
With the Locate app in the foreground, range the beacon to check the signal level and rotate it at different angles. Some beacons have antenna patterns that are much weaker on one side. You may find that the orientation gives a much weaker signal, and again, a weak signal can cause dropouts.
Check the specs or configuration settings of your beacon to see how often your beacons are transmitting. Beacons that are configured to transmit rarely to conserve battery (e.g. once every 5 seconds) are more likely to cause this situation because it only takes 6 missed packets in a row (rare but possible) to cause a region exit.
One other possibility is that there is an unusual amount of radio noise periodically in your vicinity in the Bluetooth frequency range. This is unlikely, but I have seen it before. I live across the street from a U.S. Marine installation with powerful antennas, and at home I often get much higher packet CRC error rates than I do in the office.

ios "smart" location tracker and battery drain

I'm creating an activity tracker similar to the "Moves" app that seeks to track steps, distance, calories and active time.
For Iphone5s+ devices, I am using the built in M7 chip to determine Steps, and then making estimates at the rest from that. For M7 devices I never use GPS. There is basically no battery drain and the interpolated numbers are reasonable enough for the need. This gets walking/running data reasonably enough.
However to support Iphone5 and Iphone4 at least, I need to use GPS to get location and then interpolate steps and calories from the distance. I'm running into significant battery drain issues (somewhat expected), and am seeking advice on how to minimize this. I'm also using the accelerometer in addition to speed to help make an educated guess on activity type (walking,running,biking,transport)
Some things I've tried for GPS optimization:
Deferred Updates: The Iphone5 and a minimum version of IOS supports this. The code to do this is straight forward, however whether the device actually uses it is questionable. I've only seen it work on 1 out of 4 devices, where it does regularly. 3 other devices have never deferred updates from the same code. Another user suggested other apps prevent the device from sleeping, including when I had "Moves" also installed. This thus hasn't helped much beyond theory.
Reduce Accuracy: reduce the accuracy of continuous location polling. I started at High, but reduced to 10m, then hundreds of meters, etc. This doesn't seem to help and polling still seems to occur at a regular interval anyway.
startMonitoringSignificantLocationChanges: In order to reduce endless gps polling when the user may not be moving for hours at a time (especially at night), I switched from continuous polling to significant changes only after the device stopped moving for an arbitrary 2 minutes. I then re enable continuous tracking after any significant location update. This works pretty much as expected-- if it stops tracking then battery drain slows, and when it resumes continuously, battery drain resumes. Further, if a user starts walking, there is no guarantee of a significant motion event for some time. This is very poor for accuracy. Sometimes it doesn't seem to resume at all.
I've been relatively impressed that the "Moves" app, among others is able to track location so well with respectable battery drain. It can go most of a day until needing a charge. With my code, users have reported full battery drain in a couple of hours.
What kind of optimizations could be used to improve this but still maintain a reasonable accuracy in tracking movement?
PROGRESS UPDATE:
startMonitoringSignificantLocationChanges. I set this up with a timer that switches to significant monitoring after 2 minutes of inactivity (not moving). Normal location tracking is then resumed again on any significant change, or when the app becomes active from reopening. This seems to work well. My phone still goes from 100% to 10% in 8 hours overnight of sitting around. It is an old iphone with some battery troubles, but normally it might just lose 30-40% uncharged overnight with no apps running. I need to test more, but startMonitoringSignificantLocationChanges still seems to use some battery.
Further, startMonitoringSignificantLocationChanges has some expected accuracy issues in terms of when it restarts the app. In rural setting, it can go several kilometers before restarting. This could be okay for a long drive, but if I want to catch a 30 minute walk, it may miss that entirely. In urban setting it seems to kick in within 2-3 blocks of movement, which is reasonable.
Even if I used continuous location tracking that stopped+started on a timer to check for movement, I'd still likely have worst case of a minute of lag between restarts before resuming continuous logging.
PROGRESS UPDATE 2:
Significant change updates described above have a fatal flaw for me: they don't always start fast enough. Sometimes it takes 1-2 miles it seems!
As an a better approach, I've tried keeping continuous location updates on, but toggling the "desiredAccuracy" property from high to low accuracy when the device is not moving. This should essentially turn the GPS receiver off during inactivity. I've been experimenting between 100meter and 1km accuracy for inactivity with promising results. It does seem to use slightly more batter than only using significant change monitoring, but it seems more responsive as well.
Nothing of your above proposed solutions works.
You need GPS, and that is enabled if you speficiy full precision (CLLocationAcuracyBest).
if I remeber correctly there is a difference betwween CLLocationAcuracyBest and CLLocationAcuracyBestForNavigation that way that the latter uses additonaly the acceleration sensor, which in sum uses more battery.
There is no half battery GPS mode!
A GPS chip is enabled or not.
For distance counting you need GPS, cell Tower and Wlan locations will not work.
And only the cell tower an Wlan locationg can save battery.
On Iphone4 such an full precision GPS App (e.g my) lasts about 8 hours untill the battery is low.
8 hours are enough, if the user has a benefit of the app.

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.

Increase iBeacon range

So I am currently using one device as a transmitter with a specific major and minor value and its broadcasting with
self.peripheralData = [[[CSMBeaconRegion alloc] initAsTransmitter] peripheralDataWithMeasuredPower:nil];
[self.peripheralManager startAdvertising:self.peripheralData];
And I am having a receiver that starts ranging and displays the major and minor value of the transmitter.
Everything works well. But when i start walking away from the device, and go beyond 10 meters, I lose connection. When i walk back, i still do not have connection. I can only restart the connection when I am less than 1m from the transmitter.
How can i increase the range of transmitter to its MAX?
Should I set some value to peripheralDataWithMeasuredPower?
The power of the iBeacon signal is based on BLE, you can't change it. The peripheralDataWithMeasuredPower is just use to calibrate ranging on the beacon.
Regarding your beacon not connecting when you come back in range, this is internal to the iBeacon system. It should work but sometimes there is a delay after you come in range of a beacon before your device detects it.
Something is wrong here. When using an iPad or iPhone as a transmitter, you should be able to detect its iBeacon transmission beyond 10m, even if you can't reach the 50m nominal range. Are you testing in an area with many obstructions?
And even if it does drop off at 10m, you should not have to return to 1m to detect it again (is that a typo?). If you simply wait at 10m away, are you sure it won't detect it again?
While #Patrick-Tescher is correct that you cannot change the transmit power of an iOS device acting as an iBeacon, some hardware iBeacons like Radius Networks' RadBeacon do allow you to configure their transmitter power. But you typically change the transmitter power with a proprietary mechanism that is specific to the beacon, and not with iOS APIs.
Also, while your iOS device may have a short range, dedicated hardware iBeacons often have a range that exceeds the 50m nominal range of Bluetooth LE.
Full disclosure: I am an employee of Radius Networks.

Resources