I'm having trouble finding the major and minor number of a bluetooth beacon using RxBle. Any help would be appreciated. I've tried this
rxBleClient = ProxiApplication.getRxBleClient(this)
scanDisposable = rxBleClient.scanBleDevices(
ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.build(),
ScanFilter.Builder()
.build()
).observeOn(AndroidSchedulers.mainThread())
.doFinally(this::dispose)
.subscribe({
Log.v("MainActivity", "scan results: ${it}"]
}, {
Log.v("MainActivity", "error: $it")
})
Related
The issue started happening after I disabled google fit. Link
Checking permissions with
GoogleSignIn.hasPermissions(googleAccount, fitnessOptions) returns true.
Also the method for requesting permissions asks to select an account, but after selecting an account I get the same exception trying to read data.
GoogleSignIn.requestPermissions(
activity,
GOOGLE_FIT_PERMISSIONS_REQUEST_CODE,
googleAccount,
fitnessOptions
)
Here is the code that I'm using to try to read data from GoogleFit.
var end = DateHelper.getEndOfDay(endDate)
if (DateHelper.isToday(endDate)) {
/* make sure current day query time is until current time, not end of the day */
end = Calendar.getInstance().time
}
val start = DateHelper.getStartOfDay(startDate)
val datasource = DataSource.Builder()
.setAppPackageName("com.google.android.gms")
.setDataType(DataType.TYPE_STEP_COUNT_DELTA)
.setType(DataSource.TYPE_DERIVED)
.setStreamName("estimated_steps")
.build()
val request = DataReadRequest.Builder()
.aggregate(datasource)
.bucketByTime(1, TimeUnit.DAYS)
.setTimeRange(start.time, end.time, TimeUnit.SECONDS)
.build()
val fitnessOptions: GoogleSignInOptionsExtension = FitnessOptions.builder()
.addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
.addDataType(DataType.AGGREGATE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
.build()
val googleSignInAccount: GoogleSignInAccount =
GoogleSignIn.getAccountForExtension(this.reactContext, fitnessOptions)
Fitness.getHistoryClient(this.reactContext, googleSignInAccount)
.readData(request)
.addOnSuccessListener { response ->
val totalSteps = response.buckets
.flatMap { it.dataSets }
.flatMap { it.dataPoints }
.sumBy { it.getValue(Field.FIELD_STEPS).asInt() }
Log.i(TAG, "Total steps: $totalSteps")
promise.resolve(totalSteps)
}
.addOnFailureListener { e: Exception ->
Log.i(TAG, "onFailure()");
Log.i(TAG, "Error $e");
promise.reject(e);
}
Is there any way to force account authorization to sign in the user? Or what is the reason I get this error, because the method to check if account has permission returns true.
I want to fetch resting heart rate from Google fit api.
I found two solutions to the problem:
Is there a way to read daily resting heart rate from the Google Fit API?
How to get Heart Rate values from Google Fit History? but they did not help me.
Source code:
fun fetchHeartPoints() {
val account = GoogleSignIn.getLastSignedInAccount(context)
if (account != null) {
try {
val requestData = getHeartPointsRequestData()
withContext(thread.io()) {
val response = Fitness
.getHistoryClient(context, account)
.readData(requestData)
.await()
val heartRateData = response.buckets
.asSequence()
.flatMap { it.dataSets }
.flatMap { it.dataPoints }
.map { it.toHeartRateData() }
.groupBy { it.startDate }
.toList()
Logger.d("Resting heart rate data: $heartRateData")
}
} catch (e: Exception) {
Logger.e("Exception : $e")
}
}
}
private fun getHeartPointsRequestData(): DataReadRequest {
val (start, end) = getStartAndEndDateForGoogleFit()
return DataReadRequest.Builder()
.aggregate(DataType.TYPE_HEART_RATE_BPM)
.aggregate( DataType.AGGREGATE_HEART_RATE_SUMMARY)
.enableServerQueries()
.setTimeRange(start, end, TimeUnit.MILLISECONDS)
.bucketByTime(1, TimeUnit.DAYS)
.build()
}
In response I get:
[(01 Apr 2022 18:48:06, [HeartRateData(value=min: 66.0 max: 94.0 average: 74.66672, startDate=01 Apr 2022 18:48:06, endDate=01 Apr 2022 23:57:42, unit=count/min, itemId=e15e74d971391afe318fafb366ca97d3)]
But this is heart rate data, not resting heart rate.
Do you have any ideas on this issue?
I am doing a scan for a device with a specific service UUID, the function scan, the device is found, and I connect.
I connect to the device every 2 minutes for 20 seconds.
Everything is working.
After a while the phone no longer connects to the device.
The device is found but unnamed.
I have to turn off the bluetooth and turn it on manually
Then it works again.
When I turn off and turn on the bluetooth programaticcally it doesn't work.
I guess it's a cache problem? ...
private fun startScan() {
if (isScanning) return
log("Start scanning for ${searchedDevice?.uuid.toString()}...")
val builder: ScanFilter.Builder = ScanFilter.Builder()
searchedDevice?.let {
builder.setServiceUuid(ParcelUuid.fromString(it.uuid.toString()))
}
val filter: ScanFilter = builder.build()
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setReportDelay(200)
.build()
isScanning = true
bluetoothLeScanner.startScan(listOf(filter), settings, scanCallback)
}
onBacthScan:
override fun onBatchScanResults(results: MutableList<ScanResult>?) {
super.onBatchScanResults(results)
results?.firstOrNull()?.let {
connectToPeripheral(it.device, connectionCompletion)
}
}
}
OnConnection:
override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
super.onConnectionStateChange(gatt, status, newState)
I get status 133 what is?
EDIT:
Error 133 is:
case 0x0085:
return "GATT ERROR"; // Device not reachable
How to solve this error programaticcally
Am running a foreground service to scan ble devices which is working fine when the phone is not locked. But when the phone is locked, the scanner is unable to detect any devices near by. The scanned count is always 0 when the phone is locked. I have also added the filter for my scanner but still no fortune. Looking for some help.
//adding filters of the manufacturer and the uuid
fun startScan(){
settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build()
val builder = ScanFilter.Builder()
builder.setManufacturerData(0x004c, byteArrayOf())
val manufactureFilter= builder.build()
val uuidBuilder = ScanFilter.Builder()
val serviceUuidString = "f8c62883-xxxx-xxxx-xxxx-430326af8bd0"
val serviceUuidMaskString = "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"
val parcelUuid: ParcelUuid = ParcelUuid.fromString(serviceUuidString)
val parcelUuidMask: ParcelUuid = ParcelUuid.fromString(serviceUuidMaskString)
uuidBuilder.setServiceUuid(parcelUuid, parcelUuidMask)
val uuidFilter = uuidBuilder.build()
filters = ArrayList<ScanFilter>()
filters.add(manufactureFilter)
filters.add(uuidFilter)
scanLeDevice(true)
}
//to start the ble scan for a short period
fun scanLeDevice(enable: Boolean) {
if (enable) {
Log.i(TAG, "Scanning started")
if(beaconCollectionTimer != null){
beaconCollectionTimer?.cancel()
}
beaconCollectionTimer = Timer()
beaconCollectionTimer?.schedule(object : TimerTask(){
override fun run() {
scanLeDevice(false)
}
}, SCANNING_INTERVEL)
bluetoothAdapter.getBluetoothLeScanner()
.startScan(filters, settings, mScanCallback)
} else {
Log.i(TAG, "scanning stopped")
if (bluetoothAdapter.getBluetoothLeScanner() != null) {
bluetoothAdapter.getBluetoothLeScanner().stopScan(mScanCallback)
}
isScanning = false
}
}
After trying various libraries to get my scanner work properly, I realized that the issue is not in the code but with the battery saver. All I did is removed the app from the battery optimization apps list and my scanner started working as expected. Even after the screen is locked am able to run the bleScanner and detect the near by devices.
I'm developing a step counter with Google Fit.
I tried to implement as it is defined in Google Fit docs. But the problem is that when I query step count it always returns empty dataset but when I query with readDailyTotal function it returns a dataset.
I am not able to find what is the cause.
I get the required permission for required step count permission
val fitnessOptions = FitnessOptions.builder()
.addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
.addDataType(DataType.TYPE_STEP_COUNT_CUMULATIVE, FitnessOptions.ACCESS_READ)
.addDataType(DataType.AGGREGATE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
.build()
if (! GoogleSignIn.hasPermissions(GoogleSignIn.getLastSignedInAccount(activity),
fitnessOptions)) {
GoogleSignIn.requestPermissions(
activity, // your activity
REQUEST_CODE_GOOGLE_FIT_PERMISSIONS,
GoogleSignIn.getLastSignedInAccount(activity),
fitnessOptions
)
} else {
onSuccess.invoke()
}
I subscribe to the application for recording step counts.
Fitness.getRecordingClient(context, client!!)
.subscribe(DataType.TYPE_STEP_COUNT_DELTA)
.addOnSuccessListener {
onSuccess.invoke()
}
.addOnFailureListener { e ->
onFail.invoke(e)
}
I query 1 week period with history API but it always returns an empty dataset.
// Setting a start and end date using a range of 1 week before this moment.
val cal = Calendar.getInstance()
val now = Date()
cal.time = now
val endTime = cal.timeInMillis
cal.add(Calendar.WEEK_OF_YEAR, -1)
val startTime = cal.timeInMillis
val dateFormat = DateFormat.getDateInstance()
Log.i(TAG, "Range Start: " + dateFormat.format(startTime))
Log.i(TAG, "Range End: " + dateFormat.format(endTime))
val readRequest = DataReadRequest.Builder()
// The data request can specify multiple data types to return, effectively
// combining multiple data queries into one call.
// In this example, it's very unlikely that the request is for several hundred
// datapoints each consisting of a few steps and a timestamp. The more likely
// scenario is wanting to see how many steps were walked per day, for 7 days.
.aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA)
// Analogous to a "Group By" in SQL, defines how data should be aggregated.
// bucketByTime allows for a time span, whereas bucketBySession would allow
// bucketing by "sessions", which would need to be defined in code.
.bucketByTime(1, TimeUnit.DAYS)
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
.enableServerQueries()
.build()
Fitness.getHistoryClient(context, client)
.readData(readRequest)
.addOnSuccessListener { dataReadResponse ->
dumpDataSets(dataReadResponse.dataSets)
onSuccess.invoke(dataReadResponse)
}
.addOnFailureListener { e ->
onFail.invoke(e)
}
.addOnCompleteListener { task ->
dumpDataSets(task.result!!.dataSets)
onComplete.invoke(task)
}
Datasets can be found in buckets:
dataReadResponse.buckets.forEach { bucket ->
bucket.dataSet.forEach { dataSet ->
dataSet.dataPoints.forEach { dataPoint ->
// USE DataPoint
}
}
}