Hi there,
I'm new to Android BLE development and simply trying to read out a BLE temperature sensor that encodes the temp. in the service data from the advertising packets.
This works, however the update rate is very slow (~1min), while the two sensors send out an advertising packet every second. So it seems like a great deal of packets get dropped/scanner misbehaves.
When I look at the sensors with NRF connect, the update rate is perfect, so I must be doing something terribly wrong here?
I tried many different types of filtering (in the callback, before the callback,...) and scanning modes. Very little change..
Thanks a lot in advance, I'm learning a lot!
package com.portacapena.ble.grinn_ble; import android.Manifest; import android.app.AlertDialog; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothManager; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.location.Location; import android.location.LocationManager; import android.os.AsyncTask; import android.os.ParcelUuid; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.text.method.ScrollingMovementMethod; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.UUID; import java.util.Vector; import static java.util.Locale.US; public class MainActivity extends AppCompatActivity { BluetoothManager btManager; BluetoothAdapter btAdapter; BluetoothLeScanner btScanner; Button startScanningButton; Button stopScanningButton; TextView peripheralTextView; private final static int REQUEST_ENABLE_BT = 1; private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); peripheralTextView = (TextView) findViewById(R.id.PeripheralTextView); peripheralTextView.setMovementMethod(new ScrollingMovementMethod()); startScanningButton = (Button) findViewById(R.id.StartScanButton); startScanningButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { startScanning(); } }); stopScanningButton = (Button) findViewById(R.id.StopScanButton); stopScanningButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { stopScanning(); } }); stopScanningButton.setVisibility(View.INVISIBLE); btManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE); btAdapter = btManager.getAdapter(); btScanner = btAdapter.getBluetoothLeScanner(); if (btAdapter != null && !btAdapter.isEnabled()) { Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent,REQUEST_ENABLE_BT); } // Make sure we have access coarse location enabled, if not, prompt the user to enable it if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("This app needs location access"); builder.setMessage("Please grant location access so this app can detect peripherals."); builder.setPositiveButton(android.R.string.ok, null); builder.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION); } }); builder.show(); } startScanning(); } // Device scan callback. private ScanCallback leScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { //peripheralTextView.append("Device Name: " + result.getDevice().getName() + " rssi: " + result.getRssi() + "\n"); ScanRecord scanRecord = result.getScanRecord(); String mac = result.getDevice().getAddress(); //String deviceName = scanRecord.getDeviceName(); byte[] serviceData = scanRecord.getServiceData(ParcelUuid.fromString("00001809-0000-1000-8000-00805f9b34fb")); Log.d("serviceData", serviceData.toString()); StringBuilder hexOut = new StringBuilder(); Log.d("Hex", hexOut.toString()); long exponent = unsignedToSigned(serviceData[3],8); Log.d("exponent",Long.toString(exponent)); long[] mant = new long[3]; mant[0] = (serviceData[2] << 16) & 0xFFFFFF; mant[1] = (serviceData[1] << 8) & 0xFFFF; mant[2] = (serviceData[0]) & 0xFF; long mantissa = unsignedToSigned(mant[0] + mant[1] + mant[2],24); Log.d("mantissa", Long.toString(mantissa)); double temp = mantissa * Math.pow(10,exponent); Log.d("Temperatuur",Double.toString(temp)); peripheralTextView.append("Adres: " + mac + " Temperatuur: " + String.format(Locale.US,"%.2f",temp) + "\n"); // auto scroll for text view final int scrollAmount = peripheralTextView.getLayout().getLineTop(peripheralTextView.getLineCount()) - peripheralTextView.getHeight(); // if there is no need to scroll, scrollAmount will be <=0 if (scrollAmount > 0) peripheralTextView.scrollTo(0, scrollAmount); } public long unsignedToSigned(long unsigned, int size){ long signed = 0; if ((unsigned & (1 << (size-1))) != 0) { signed = (-1) * (1 << (size - 1)) + unsigned ^ (1 << (size - 1)) ; } else { signed = unsigned; } return signed; } }; @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case PERMISSION_REQUEST_COARSE_LOCATION: { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { System.out.println("coarse location permission granted"); } else { final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Functionality limited"); builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons when in the background."); builder.setPositiveButton(android.R.string.ok, null); builder.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { } }); builder.show(); } return; } } } public void startScanning() { System.out.println("start scanning"); //peripheralTextView.setText(""); startScanningButton.setVisibility(View.INVISIBLE); stopScanningButton.setVisibility(View.VISIBLE); byte[] emptyData = new byte[0]; byte[] mask = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; final Vector<ScanFilter> filter = new Vector<ScanFilter>(); ScanFilter.Builder builder = new ScanFilter.Builder().setServiceData(ParcelUuid.fromString("00001809-0000-1000-8000-00805f9b34fb"),emptyData,mask);//.setDeviceName("BTTEMP(MCP)"); //builder.setServiceData(ParcelUuid.fromString("00001809-0000-1000-8000-00805f9b34fb"),emptyData); filter.add(builder.build()); final ScanSettings.Builder scanSettingsBuilder = new ScanSettings.Builder(); scanSettingsBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY); scanSettingsBuilder.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE); scanSettingsBuilder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES); scanSettingsBuilder.setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT); AsyncTask.execute(new Runnable() { @Override public void run() { btScanner.startScan(filter, scanSettingsBuilder.build(), leScanCallback); Log.d("scan","Scan gestart"); } }); } public void stopScanning() { System.out.println("stopping scanning"); peripheralTextView.append("Stopped Scanning"); startScanningButton.setVisibility(View.VISIBLE); stopScanningButton.setVisibility(View.INVISIBLE); AsyncTask.execute(new Runnable() { @Override public void run() { btScanner.stopScan(leScanCallback); } }); } }