I am trying to write a Bluetooth LE app that accesses a Zephyr HxM Smart heart monitor. This monitor has several Bluetooth services, but I am interested in the Battery Service, Heart Rate Service, and a Custom Service that has Activity and Peak Acceleration. There is one characteristic for each, Battery Level, (BAT), Heart Rate Measurement (HR), and Custom Measurement (CUS). The HxM updates about once per sec.
I am doing this with a Galaxy S4 with Android 4.4.
It is not working as expected from the documentation.
My initial approach was to do:
Read BAT
Set notification for HR
Set notification for CUS.
Then wait for the callbacks. Setting notification means calling
BluetoothGatt.setCharacteristicNotification(Characteristic char , boolean enabled)
(One could also do notification for BAT, however, the spec does not require this to be supported. The HxM, however, does support it.)
This didn't work. I got BAT and notifications for HR, but not CUS. If I eliminated the second step, I got notifications for CUS. I couldn't get both. (This indicates I am reading the characteristics correctly, so that is [probably] not the problem.)
I found some indications there were problems with the Bluetooth stack for Android being synchronous, but no hard documentation. I then tried the following:
Read BAT.
Wait for the BAT reading, then set notification for HR,
Get HR, then disable notification for HR, and start notification for CUS.
Get CUS, then disable notification for CUS, and start notification for HR.
And continue to loop.
I got BAT and that is all.
By trial and error, I discovered the following works:
Read BAT.
Wait for the BAT reading, then set notification for HR,
Get HR, then start notification for CUS.
Get CUS, then start notification for HR.
And continue to loop.
(Same as above but without disabling notifications.) Typically, I get a HR reading, then the CUS one within 200 ms. One can assume they are from the same update. (There are no timestamps in the data, which have to be kept short to be LE.) In reality the logic is more complicated, as timers are necessary in case expected readings don't come in. This logic is FAR more complicated (and more prone to error) than my first try, which is what the documentation seems to say is what is appropriate.
I have contacted Zephyr, and they say the HxM Smart has been extensively tested on Windows, and will do simultaneous notifications as it should. There are also indications it works as it should on iOS.
There is a further problem that I do not understand. In order to get notifications, you have to enable the Characteristics locally for notification with something like:
BluetoothGattDescriptor descriptor = characteristic
.getDescriptor(UUID_CLIENT_CHARACTERISTIC_CONFIG);
resSet = descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
resWrite = mBluetoothGatt.writeDescriptor(descriptor);
This is a per characteristic setting, and should only need to be done once, when the characteristic is first received. Instead, I find I have to do it every time I set the notifications. It is possible this just causes a sufficient time delay for things to work. I don't know. This trial and error is taking a lot of my time. It would be nice to have a definitive statement of how it works.
I should note that for all calls that return a result, the result is true (success).
I apologize for the long statement. My question is:
I find no documentation that I have to do the things described. All indications are that you set up notifications and wait for the callbacks. Is there documentation, or is this a bug, or just a bad implementation? (Or is it my error?) I would especially like to know where is the documentation for what I have had to do.
Second, there is a further complication. I have tried to debug into the routines to see what the code is actually doing. When I get to BluetoothGatt.class, the source lines don't match what the debug stack says. I thus assume that the S4 is not using standard Android. I don't know where to go from there. It has been frustrating, and while I have something that appears to work, it is kludgy and almost certainly less robust.
Thanks for any help.
I had the same problem with writing multiple values in sequence, putting a Thread.sleep(200) in between them solved the problem (alas i should say). Maybe this helps as well with getting notifications.
Tested this on android 4.4.2 on Nexus 5. And no, 4.4 does not solve all problems...
Im probably very late to this but you should implement a queuing architecture for setting up your characteristics to send notifications. I used a similar technique to miznick in the post https://stackoverflow.com/a/18207869/3314615 and ended up just writing wrapper code for the native BLE stack since there are several apps i use BLE for. Ever since then I have had no issues receiving notifications. I agree with you that the Android BLE documentation should have some sort of information or warning about the BLE Stack not being synchronous. Frankly, i believe it should be re-written to handle synchronous write calls and just queue them.
First, you set Notification(i.e. setCharacteristicNotification and set Descriptor) for first characteristic.
And, Set notification for second characteristic in onDescriptorWrite callback function.
Related
I found what was wrong:
So apparently http://www.epochconverter.com/ is makes assumptions of the precision of the input values, and from those assumptions values around 841073068 goes to 1996/1997. I'm not sure what is the assumption that leads to that exact date, but honestly I don't care.
Using the attached debugger I called new Date(System.currentTimeMillis()) and it correctly gave me a 10th Jan-1070 date, meaning the clock is not jumping out of the way like crazy.
Original question:
I'm running a single-board computer with Android for and IoT case (this https://developer.qualcomm.com/hardware/dragonboard-410c). The OS running is the plain vanilla Android supplied by Qualcomm.
Currently I'm testing the reliability of the board to be left executing for long periods at once and I'm seeing some very very weird behavior that I can't find an explanation for.
The board was powered up 10 days ago and it have no access to internet (WiFi is on but no access point setup and no Ethernet). The bluetooth is on and there're iBeacons and Eddystone in the office. Also there are WiFi in the area.
If I go now to Settings -> Date and Time, or check the notification shade or enter the clock app, or the calendar app, I see 10th of January 1970. Which is expected and basically showing for how long the board been running.
The app on it have an always running service, which does some data processing and some disk-logging (for debugging).
From the logs, I can see that System.currentTimeMillis() was returning an expected value when the board was initially powered on. That means, the beginning of the logs indicate an epoch time in January 1970.
But at the end of the logs (and also attaching the debugger on the live process), the value of System.currentTimeMillis() is somewhere in Sep/Oct 1996. Example values: 841073068, 841263234, 841579239
So my question is:
What is happening here?
Why System.currentTimeMillis() value changed and what could have changed it?
Why the Android UI (notification, clock app, settings) still shows me 1970? Where are they getting this value from?
edit:
There's been some confusion on the answers, and I can see my question was lacking the details.
I do not want to measure difference of time. I need an actual time stamp. Those values will be reported with bluetooth LE events via POST to our backend. This "no network" thing is a reliability test that we're running on the board, but we do expect to have network most of the time, and the boards should auto-update their times from network using the normal Android ways.
I'm just trying to understand on the current batch of testing, what went wrong and why.
Well, as you already know, the current system time (System.currentTimeMillis()) can be modified by any process if desired, it's perfectly be possible that it was modified by another process. It's not a reliable method to measure up-time.
I would rater use something like:
SystemClock.uptimeMillis()
Which returns the elapsed time (in milliseconds) since the device booted (not including time spent in deep-sleep).
I would also like to mention that I suspect that Bluetooth has something to do with it, I can imagine that Bluetooth uses the system time for pairing and security just like SSL does (but I'm no expert). GPS could also be a problem as GPS can be used to obtain an UTC time value, but I'm not sure if your board has a GPS module.
Regarding your edit:
Obtaining a valid time-stamp would be quite easy: server time minus the elapsed time reported by your board. But I suggest you either choose to accept the time reported by System.currentTimeMillis() or use the elapsed time instead. At the company I work we also work with embedded Android devices and on our server dashboard we can see both the up-time (up since) and the current device time, but they should not be mixed, at least in my opinion, especially since System.currentTimeMillis() is subject to changes and is affected by summer and winter time.
If you want to measure something, better try System.nanoTime(). Here is difference - https://stackoverflow.com/a/351571/2793494
I'm using QBluetoothDeviceDiscoveryAgent to search BLE devices on an Android phone.
I request device search to be started by calling QBluetoothDeviceDiscoveryAgent::start(). After a few seconds, QBluetoothDeviceDiscoveryAgent::finished() is emitted, but I did not call QBluetoothDeviceDiscoveryAgent::stop().
At this point, my BLE device was not found yet (it's slow...I know), and it won't as the system decided on its own to stop the search....so I need to restart the search manually.
Why is the system stopping the search? Qt doc says about QBluetoothDeviceDiscoveryAgent::finished():
This signal is emitted when Bluetooth device discovery completes.
What does that mean? How could anyone decide that discovery completes? Does it come from BLE standard? As a end user, I'm the only one who knows when it's completed, i.e. when the device I'm looking for was found....
As commented by Frank Osterfeld, the android implementation of QBluetoothDeviceDiscoveryAgent (see line 273) silently creates a 10 seconds timeout that stops the search automatically.
It's a pain for users who want to search for longer than 10sec...
Filled a bug report here: https://bugreports.qt.io/browse/QTBUG-53012
I want to make an app (or service) that always looks for beacons every minute. If it finds one, it shall start an intentService and upload coordinates to my server.
I have looked at examples in the altbeacon documentation and they are indeed working. However, I am not able to tweak it the way I want.
The best example I found was how to start an app in the background. Here I can set the interval time, scan time, and it is doing what it should - except it only announces new beacons (didEnterRegion method).
There is also an example that continuously scans for beacons (Getting Ranging Updates from Nearby Beacons With Telemetry), but I have not been able to control the interval and scan time (even though it says it is configurable). Also, I must make sure that this will always run, and never goes into some kind of sleepmode.
Lastly, I have tried to mix all of this into my own service using various timer approaches, but I was told by a distant co-worker that the altbeacon library makes a service by itself, and I should not have to.
Does anyone have any tips on how to do this?
Edit
I have used davidgyoung's approach, since the example seems to be pretty much out of the box for me. I will need a few days to test, and get back with an update.
Doing this with the Android Beacon Library is quite straightforward, and you can use the reference app as a starting point.
It is true that you do not need to make your own service, as the library has one of its own. Using the reference app as-is, it starts up automatically on the background and scans for beacons at boot, and will restart itself within five minutes using an AlarmManager even if you kill the app.
Using this approach, simply start ranging in the Application class and process your results in a callback method in that class.
I believe you can use Estimote API for this. Manually you can create service, create instance of BeaconManager if it == null on service or your command started. Add setMonitoringListener and now you can send results from onEnteredRegion.
Let me summarize my problem and what I would like to achieve.
I have a SonyEricsson X10i phone with Android 2.3.3. I realized that sometimes my phone not receiving calls even if it indicating full coverage. I checked myself in the MSC/VLR and it indicates that I registered and my phone is currently active (and also there is no IMSI DETACH flag), so it should working correctly (only the last Activate Date is a little bit old ~couple of hours, which can be good as well, without SMS/Call/Location Update), as I mentioned before the phone indicates full coverage and it seems it’s on the network. But when I tried to call it I only reached the Voice Mail.
In the MSC/VLR I see No Paging Response Cause for the call, but the phone does nothing. I tried with other SW version (4.0.3 ICS), but the same result. But I not noticed similar behaviour with a different handset (same type).
Sorry for the long summary.
So because what I described above, I ‘m trying to write an application/service which will perform GSM/UMTS location update in 15-20 minutes, but I couldn’t find any kind of procedure in android.telephony.gsm.GsmCellLocation, android.telephony.TelephonyManager which will do this for me.
My other concern is the
getState()/setStateOutOfService()/ setState() procedures from ServiceState class…
It seems they not really working. For example, when I first call the getState() I always get back STATE_OUT_OF_SERVICE, which is not true…
When I’m set the state to STATE_POWER_OFF or STATE_IN_SERVICE, at least I get back that state from getState() afterwards, but the phone does nothing for that . (Not even indicate out of coverage,etc…)
Every suggestion/comment are welcome.
I have also seen this problem many times (2 phones from the same manufacturer as yours). From your question, I understand that you want to force the phone to send an MM periodic location update (which it should be sending anyway).
This is too low level, and there's nowhere you can force this directly in the programming interface. The mobility management procedure is part of the phone stack, and is specified in detail in 3GPP TS 24.008, available from www.3gpp.org. Paragraph 4.2.2 defines when the phone is supposed to send these location updates.
The only other thing would be to try by indirect means to force the phone into a condition where it would send a location update. You might be able to do that by trying to select another network manually. If it's successful, and you then manually re-select your home network, then you would trigger a location update. If it's rejected and falls back to its home network, then I think a location update would be triggered as well.
But there would also be small costs to this - battery use while it does a networks scan, and time lost while it scans and does manual network selection.
(My personal experience is that the lost calls don't happen often enough to justify this.)
I am doing my Master thesis at the moment on WiFi positioning and in order to test my algorithms I needed to collect some data.
To do this I have written a short and very simple program for Android which simply collects the RSSI for all availible access points found by each scan and saves them to file. I have set up a BroadcastReceiver that listens on the event WifiManager.SCAN_RESULTS_AVAILABLE_ACTION and I use a Timer, here called tim, to initiate scans with a WifiManager, called wifi as follows:
tim.schedule(new TimerTask(){
#Override
public void run(){
wifi.startScan();
}
}, 0, 1000);
The problem I am having now is that the initiated scans don't seem to happen every second even if I succeed in initiating them and every now and then there are other scans initiated from some other app that gets recorded as well.
Is there any easy way to scan on a set interval and not receive the scans initiated by some other app?
The whole app can be found on https://github.com/while/RSSIMiner if it helps in any way.
Is there any easy way to scan on a set interval?
If this doesn't work well, I'm afraid not. From my experience, "hardware related" methods may not work exactly like their definition says. For example, I once created a small app which records your position every X minutes. So I call requestLocationUpdates with some minTime parameter. But my phone simply ignores the minTime value, and I get updates from the GPS as soon as they're available, whcih is not what I wanted. I posted a question about it here, and got this answer, from which we learn that prior to jelly bean, devices may simply ignore this value...
So it may be something similar now. I'd try to run this code on the latest Android version. And I don't understand that much in Wifi, but isn't 1 second a too frequent interval for scans? Perhaps the system doesn't ignore the scan request (So it returns true) but the hardware does?
Can we ignore the scans initiated by some other app?
As far as I know, it's negative here too. There are no extras contained in the SCAN_RESULTS_AVAILABLE_ACTION broadcast so you can't know which app initiated the scan.
The best solution will be to defnie your requirements. You can use the ScanResult.timestamp to determine if you should use this result or not. For example, if you're trying to get the RSSI for each access point each second, you can compare the current BSSID to previous BSSIDs. If the current BSSID was included in a scan result from the last second, you can simply ignore it. Then, it doesn't matter how many results you get.
Another, much more simple soltuion will be to create a boolean called scanInitiated and set it to true when starting a scan. When receiving the broacast, use the data only if scanInitiated is true, and then set it to false. This isn't so reliable when the intervals are short, but for long intervals it will work great.