I am developing an application where I have to connect to Bluetooth device on Android 4.3.
And I want to get the battery level by using Battery_Service and Battery_Level.
public class BluetoothLeService extends Service {
private static final UUID Battery_Service_UUID =
UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb");
private static final UUID Battery_Level_UUID =
UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb");
public void getbattery() {
BluetoothGattService batteryService = mBluetoothGatt.getService(Battery_Service_UUID);
if(batteryService == null) {
Log.d(TAG, "Battery service not found!");
return;
}
BluetoothGattCharacteristic batteryLevel = batteryService.getCharacteristic(Battery_Level_UUID);
if(batteryLevel == null) {
Log.d(TAG, "Battery level not found!");
return;
}
mBluetoothGatt.readCharacteristic(batteryLevel);
// What should I do that I can get the battery level ??
Log.d(TAG, "Battery level " + mBluetoothGatt.readCharacteristic(batteryLevel););
}
}
But the value of mBluetoothGatt.readCharacteristic(batteryLevel); is not the battery level value
How to read the battery?
I have solved this problem.
public class BluetoothLeService extends Service {
private static final UUID Battery_Service_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb");
private static final UUID Battery_Level_UUID = UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb");
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if(status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
Log.v(TAG, "characteristic.getStringValue(0) = " + characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0));
intent.putExtra(DeviceControl.EXTRAS_DEVICE_BATTERY, characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0));
sendBroadcast(intent);
}
public void getbattery() {
BluetoothGattService batteryService = mBluetoothGatt.getService(Battery_Service_UUID);
if(batteryService == null) {
Log.d(TAG, "Battery service not found!");
return;
}
BluetoothGattCharacteristic batteryLevel = batteryService.getCharacteristic(Battery_Level_UUID);
if(batteryLevel == null) {
Log.d(TAG, "Battery level not found!");
return;
}
mBluetoothGatt.readCharacteristic(batteryLevel);
Log.v(TAG, "batteryLevel = " + mBluetoothGatt.readCharacteristic(batteryLevel));
}
}
When you call the function getbattery() , it will call onCharacteristicRead.
and onCharacteristicRead will call broadcastUpdate and transmit the characteristic and action to it.
And the characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0) in broadcastUpdate is the battery value of the BLE device.
Related
For some reason device does not transmit data (heart rate) over BLE. It connects fine, phone app is also able to discover services and connect to service.
I started up with iOS and Health app and actually saw some data coming through, so, it worked initially. Later, created the base for the BLE connectivity on Android app, it connected just fine, discovered the correct services and connected to these. And no data. Re-checked with iOS, also silence. Assuming that it is device'd problem (faulty sensors etc), took it to the shop I purchased it from. Tested it, worked like a charm with ANT+. So, it has to be BLE issue. The code itself is pretty much sample code from Android dev guides.
{
//0x180D - heart rate service
//0x2A37 - heart rate characteristic
private static HrmHandler instance;
private static UUID UUID_HRM_SERVICE = UUID.fromString("0000180d-0000-1000-8000-00805f9b34fb");
private static UUID UUID_HRM_CHARACTERISTIC = UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb");
private static String LOG_TAG = HrmHandler.class.getSimpleName();
private BluetoothAdapter mBtAdapter;
private BluetoothDevice mBtDevice;
private String mBtDeviceAddress;
private Context mContext;
public static HrmHandler getInstance() {
if (instance == null)
instance = new HrmHandler();
return instance;
}
public void connect(Context ctx) {
mContext = ctx;
BluetoothManager bt_manager = (BluetoothManager) ctx.getSystemService(Context.BLUETOOTH_SERVICE);
mBtAdapter = bt_manager.getAdapter();
if (mBtAdapter == null || !mBtAdapter.isEnabled()) return;
mBtAdapter.startLeScan(new UUID[] {UUID_HRM_SERVICE}, this);
}
public void disconnect() {
}
#Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
Log.v(LOG_TAG, "Found HRM device " + device.getName());
mBtDevice = device;
mBtAdapter.stopLeScan(this);
mBtDeviceAddress = mBtDevice.getAddress();
mBtDevice.connectGatt(mContext, false,this);
}
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
Log.v(LOG_TAG, String.format("Connection state change, new state %d", newState));
if (mBtDeviceAddress == null || !mBtDeviceAddress.equals(gatt.getDevice().getAddress()))
return; //we are not interested about that connection state
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.v(LOG_TAG, "Device connected");
gatt.discoverServices();
return;
}
if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.v(LOG_TAG, "Device disconnected");
return;
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (gatt != null) {
BluetoothGattCharacteristic characteristic = null;
List<BluetoothGattService> services = gatt.getServices();
for (BluetoothGattService s : services) {
Log.v(LOG_TAG, String.format("Discovered %s, uuid %s", s.toString(), s.getUuid().toString()));
}
BluetoothGattService service = gatt.getService(UUID_HRM_SERVICE);
if (service != null)
characteristic = service.getCharacteristic(UUID_HRM_CHARACTERISTIC);
gatt.readCharacteristic(characteristic);
gatt.setCharacteristicNotification(characteristic, true);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (!UUID_HRM_CHARACTERISTIC.equals(characteristic.getUuid())) {
Log.v(LOG_TAG, "READ: Not interesting characteristic " + characteristic.getUuid().toString());
return;
}
int flags = characteristic.getProperties();
int format = (flags & 0x01) != 0 ? BluetoothGattCharacteristic.FORMAT_UINT16 : BluetoothGattCharacteristic.FORMAT_UINT8;
int heart_rate = characteristic.getIntValue(format, 1);
Log.v(LOG_TAG, String.format("Heart rate %d bpm", heart_rate) );
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
if (!UUID_HRM_CHARACTERISTIC.equals(characteristic.getUuid())) {
Log.v(LOG_TAG, "CHANGED: Not interesting characteristic " + characteristic.getUuid().toString());
return;
}
gatt.readCharacteristic(characteristic);
}
Can anyone help me forward, especially someone at Garmin, or is it common and known issue and I just should forget about it and try to go forward with ANT+?
I call on my bluetooth adapter mBluetoothAdapter.startDiscovery(); which then returns me a list of BluetoothDevices. When I press on 1 of those devices, I do this:
mBluetoothGatt = bluetoothDevice.connectGatt(MainActivity.this, false, mGattCallback);
Where my callback is:
private final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnectionState = STATE_CONNECTED;
Log.i(TAG, "Connected to GATT server.");
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
List<BluetoothGattService> listBGS = mBluetoothGatt.getServices();
Log.i("","list size: " + listBGS.size());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.w(TAG, "onServicesDiscovered GATT_SUCCESS: " + status);
List<BluetoothGattService> listBGS = mBluetoothGatt.getServices();
Log.i("","list size: " + listBGS.size());
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.w(TAG, "onCharacteristicRead GATT_SUCCESS: " + status + " / char: " + characteristic);
}
}
};
Now, when I try it on phones, I get STATE_CONNECTED on onConnectionStateChange , and I then call discoverServices, and I get back a GATT_SUCCESS onServicesDiscoveres. So I can take the uuids from my services.
BUT when I try it on a beacon, I get back STATE_CONNECTED and when I call discoverServices, I get back an status code: 129 -> GATT_INTERNAL_ERROR
Why is this happening for my beacons? Is there another way, how I can take the devices uuid?
I just need the UUID to be able to do this after, for the beaconManager:
try {
beaconManager.startMonitoringBeaconsInRegion(new Region("myMonitoringUniqueId", null, null, null));
} catch (RemoteException e) { }
EDIT
I know that the beacon should ask me for a code to pair, but it doesn't. Why?
I tried adding this code:
final IntentFilter pairingRequestFilter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
pairingRequestFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY - 1);
registerReceiver(mPairingRequestRecevier, pairingRequestFilter);
But still I don't get a request to pair and input my passkey
This is my pairingRequestReceiver:
private final BroadcastReceiver mPairingRequestRecevier = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction()))
{
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR);
if (type == BluetoothDevice.PAIRING_VARIANT_PIN)
{
device.setPin(intToByteArray(123456));
abortBroadcast();
}
else
{
Log.e("","Unexpected pairing type: " + type);
}
}
}
};
After hours of trial and error I did manage to find a way to make it work like this:
1.I start the discovery the same, but when I select an bluetooth device, I ask to bond (pair) with it like this:
private void pairDevice(BluetoothDevice device) {
try {
Method method = device.getClass().getMethod("createBond", (Class[]) null);
method.invoke(device, (Object[]) null);
} catch (Exception e) {
e.printStackTrace();
}
}
I have a ACTION_BOND_STATE_CHANGED receiver:
private final BroadcastReceiver mPairReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
final int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);
final int prevState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, BluetoothDevice.ERROR);
if (state == BluetoothDevice.BOND_BONDED && prevState == BluetoothDevice.BOND_BONDING) {
Log.i("","Paired");
mBluetoothGatt = btDevice.connectGatt(MainActivity.this, false, mGattCallback);
} else if (state == BluetoothDevice.BOND_NONE && prevState == BluetoothDevice.BOND_BONDED){
Log.i("","Unpaired");
}
}
}
};
Which I register like this:
IntentFilter intent = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver(mPairReceiver, intent);
And only after this, I try to connect with my BluetoothGattCallback. Hence, I can discover the services, and so on
Although similar questions have been asked but it's slightly different. I know how to pass data to a connected BLE device but I think I'm doing something wrong for which I need help.
The code below contains all the methods from my class that is extending BroadcastReceiver.
I scan and connect to a device specified by `PEN_ADDRESS`.
In `onServicesDiscovered` method I look for a service whose `UUID` contains `abcd`.
Then I loop through the characteristics of this services and look for three characteristics with specific strings in their `UUID`.
The third characteristic is a writable characteristic in which I'm trying to write data by calling the method `writeCharac(mGatt,writeChar1,123);`
The data `123` passed above is just a dummy data.
I debugged my code while trying writing to this characteristic but on putting breakpoints inside the writeCharac method, I found that the status value is false, indicating that the write was not successful.
Am I missing something here? Please do help!
public class BackgroundReceiverFire extends BroadcastReceiver {
Context context;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothGatt mGatt;
private BluetoothLeService mBluetoothLeService;
private boolean mScanning;
private final String TAG = "READING: ";
private BluetoothDevice mDevice;
private Handler mHandler;
private static final int REQUEST_ENABLE_BT = 1;
private final String PEN_ADDRESS = "FB:23:AF:42:5C:56";
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
public void onReceive(Context context, Intent intent) {
this.context = context;
Toast.makeText(context, "Started Scanning", LENGTH_SHORT).show();
initializeBluetooth();
startScan();
}
private void initializeBluetooth() {
mHandler = new Handler();
// Use this check to determine whether BLE is supported on the device. Then you can
// selectively disable BLE-related features.
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
final BluetoothManager bluetoothManager =
(BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null) {
Toast.makeText(this.context, "No Bluetooth", LENGTH_SHORT).show();
return;
}
}
private void startScan() {
scanLeDevice(true);
}
private void stopScan() {
scanLeDevice(false);
}
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, SCAN_PERIOD);
mScanning = true;
//Scanning for the device
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
if (device.getAddress().matches(PEN_ADDRESS)) {
connectBluetooth(device);
Toast.makeText(context, "Device Found: " + device.getAddress(), Toast.LENGTH_LONG).show();
}
}
};
private void connectBluetooth(BluetoothDevice insulinPen) {
if (mGatt == null) {
Log.d("connectToDevice", "connecting to device: " + insulinPen.toString());
mDevice = insulinPen;
mGatt = insulinPen.connectGatt(context, true, gattCallback);
scanLeDevice(false);// will stop after first device detection
}
}
private void enableBluetooth() {
if (!mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.enable();
}
scanLeDevice(true);
}
private void disableBluetooth() {
if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
}
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
Log.i("onConnectionStateChange", "Status: " + status);
switch (newState) {
case BluetoothProfile.STATE_CONNECTED:
gatt.discoverServices();
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.e("gattCallback", "STATE_DISCONNECTED");
Log.i("gattCallback", "reconnecting...");
BluetoothDevice mDevice = gatt.getDevice();
mGatt = null;
connectBluetooth(mDevice);
break;
default:
Log.e("gattCallback", "STATE_OTHER");
break;
}
}
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
mGatt = gatt;
List<BluetoothGattService> services = mGatt.getServices();
Log.i("onServicesDiscovered", services.toString());
Iterator<BluetoothGattService> serviceIterator = services.iterator();
while(serviceIterator.hasNext()){
BluetoothGattService bleService = serviceIterator.next();
if(bleService.getUuid().toString().contains("abcd")){
//Toast.makeText(context,"Got the service",Toast.LENGTH_SHORT);
BluetoothGattCharacteristic readChar1 = bleService.getCharacteristics().get(0);
for (BluetoothGattDescriptor descriptor : readChar1.getDescriptors()) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mGatt.writeDescriptor(descriptor);
mGatt.setCharacteristicNotification(readChar1, true);
}
//mGatt.readCharacteristic(readChar1);
BluetoothGattCharacteristic readChar2 = bleService.getCharacteristics().get(1);
for (BluetoothGattDescriptor descriptor : readChar2.getDescriptors()) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mGatt.writeDescriptor(descriptor);
mGatt.setCharacteristicNotification(readChar2, true);
}
//mGatt.readCharacteristic(readChar2);
BluetoothGattCharacteristic writeChar1 = bleService.getCharacteristics().get(2);
for (BluetoothGattDescriptor descriptor : writeChar1.getDescriptors()) {
descriptor.setValue( BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mGatt.writeDescriptor(descriptor);
mGatt.setCharacteristicNotification(writeChar1, true);
}
writeCharac(mGatt,writeChar1,123);
}
}
//gatt.readCharacteristic(therm_char);
}
public void writeCharac(BluetoothGatt gatt, BluetoothGattCharacteristic charac, int value ){
if (mBluetoothAdapter == null || gatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
/*
BluetoothGattCharacteristic charac = gattService
.getCharacteristic(uuid);
*/
if (charac == null) {
Log.e(TAG, "char not found!");
}
int unixTime = value;
String unixTimeString = Integer.toHexString(unixTime);
byte[] byteArray = hexStringToByteArray(unixTimeString);
charac.setValue(byteArray);
boolean status = mGatt.writeCharacteristic(charac);
if(status){
Toast.makeText(context,"Written Successfully",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(context,"Error writing characteristic",Toast.LENGTH_SHORT).show();
}
}
public byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len/2];
for(int i = 0; i < len; i+=2){
data[i/2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16));
}
return data;
}
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic
characteristic, int status) {
Log.i("onCharacteristicRead", characteristic.toString());
String characteristicValue = characteristic.getValue().toString();
Log.d("CHARACTERISTIC VALUE: ", characteristicValue);
gatt.disconnect();
}
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic
characteristic) {
String value = characteristic.getValue().toString();
Log.d(TAG,value);
}
};
Although the BLE API is asynchronous in nature, the actual signal transmission is inevitably synchronous. You have to wait for the previous connect/write/read call to callback before starting any connecting/writing/reading operation.
In your code onServicesDiscovered(BluetoothGatt gatt, int status) function, you called mGatt.writeDescriptor(descriptor) twice before trying to write the characteristic. The API will refuse to start your write request as it is being busy writing the descriptor, and return false for your mGatt.writeCharacteristic(charac) call.
So just wait for the writeDescriptor to callback before calling writeCharacteristic. This nature is not well documented but you can find some source here and here.
Thanks #reTs and #pooja for suggestions. The issue was due to these two lines
mGatt = nullconnectBluetooth(mDevice);
in STATE_DISCONNECTED. I had figured it out but don't remember the exact reason. Posting it just in case it is helpful.
My goal in this question is push the rssilevel from one .java file to the other.
I tried to push from class 1 to class 2, as well as pulling data dfrom class 1 to class 2 and i have always had my app crash.
I tried
ProximityManager temp = new ProximityManager();
int temp = temp.rssilevel;
The above code is in a class in the same package, but different .java file and class. They are linked.
and it would not work, any other ideas please!
EDIT: Also how would i call the function playSound() in another class?
i would normaly do something like Public ProximityManager mProximityManager;
then call mProximityManager.playSound(); but i get an app crash when i do this.
public class ProximityManager implements BleManager<ProximityManagerCallbacks> {
private final String TAG = "ProximityManager";
private ProximityManagerCallbacks mCallbacks;
private BluetoothGattServer mBluetoothGattServer;
private BluetoothGatt mBluetoothGatt;
private BluetoothDevice mDeviceToConnect;
private Context mContext;
private Handler mHandler;
private LogSession mLogSession;
private Ringtone mRingtoneNotification;
private Ringtone mRingtoneAlarm;
public int rssilevel;
public final static UUID IMMEIDIATE_ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
public final static UUID LINKLOSS_SERVICE_UUID = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb");
private static final UUID ALERT_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A06-0000-1000-8000-00805f9b34fb");
private final static UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb");
private final static UUID BATTERY_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb");
private final static UUID TX_POWER_UUID = UUID.fromString("00001804-0000-1000-8000-00805f9b34fb");
private final static String ERROR_CONNECTION_STATE_CHANGE = "Error on connection state change";
private final static String ERROR_DISCOVERY_SERVICE = "Error on discovering services";
private final static String ERROR_AUTH_ERROR_WHILE_BONDED = "Phone has lost bonding information";
private final static String ERROR_WRITE_CHARACTERISTIC = "Error on writing characteristic";
private final static String ERROR_READ_CHARACTERISTIC = "Error on reading characteristic";
private final static int HIGH_ALERT = 2;
private final static int MID_ALERT = 1;
private final static int NO_ALERT = 0;
private BluetoothGattCharacteristic mAlertLevelCharacteristic, mLinklossCharacteristic, mBatteryCharacteristic;
private boolean userDisconnectedFlag = false;
public void getrssi( int rssilevel) {
this.rssilevel = rssilevel;
}
public ProximityManager(Context context) {
initializeAlarm(context);
mHandler = new Handler();
// Register bonding broadcast receiver
final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
context.registerReceiver(mBondingBroadcastReceiver, filter);
}
private void openGattServer(Context context, BluetoothManager manager) {
mBluetoothGattServer = manager.openGattServer(context, mGattServerCallbacks);
}
private void closeGattServer() {
if (mBluetoothGattServer != null) {
// mBluetoothGattServer.cancelConnection(mBluetoothGatt.getDevice()); // FIXME this method does not cancel the connection
mBluetoothGattServer.close(); // FIXME This method does not cause BluetoothGattServerCallback#onConnectionStateChange(newState=DISCONNECTED) to be called on Nexus phones.
mBluetoothGattServer = null;
}
}
private void addImmediateAlertService() {
/*
* This method must be called in UI thread. It works fine on Nexus devices but if called from other thread (f.e. from onServiceAdded in gatt server callback) it hangs the app.
*/
BluetoothGattCharacteristic alertLevel = new BluetoothGattCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID, BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE,
BluetoothGattCharacteristic.PERMISSION_WRITE);
alertLevel.setValue(HIGH_ALERT, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
BluetoothGattService immediateAlertService = new BluetoothGattService(IMMEIDIATE_ALERT_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
immediateAlertService.addCharacteristic(alertLevel);
mBluetoothGattServer.addService(immediateAlertService);
}
private void addLinklossService() {
/*
* This method must be called in UI thread. It works fine on Nexus devices but if called from other thread (f.e. from onServiceAdded in gatt server callback) it hangs the app.
*/
BluetoothGattCharacteristic linklossAlertLevel = new BluetoothGattCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID, BluetoothGattCharacteristic.PROPERTY_WRITE
| BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_WRITE);
linklossAlertLevel.setValue(HIGH_ALERT, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
BluetoothGattService linklossService = new BluetoothGattService(LINKLOSS_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
linklossService.addCharacteristic(linklossAlertLevel);
mBluetoothGattServer.addService(linklossService);
}
private BluetoothGattServerCallback mGattServerCallbacks = new BluetoothGattServerCallback() {
#Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
DebugLogger.d(TAG, "[Proximity Server] onCharacteristicReadRequest " + device.getName());
}
#Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset,
byte[] value) {
DebugLogger.d(TAG, "[Proximity Server] onCharacteristicWriteRequest " + device.getName());
final int receivedValue = value[0];
if (receivedValue != NO_ALERT) {
Logger.i(mLogSession, "[Proximity Server] Immediate alarm request received: ON");
playAlarm();
} else {
Logger.i(mLogSession, "[Proximity Server] Immediate alarm request received: OFF");
stopAlarm();
}
}
#Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
DebugLogger.d(TAG, "[Proximity Server] onConnectionStateChange " + device.getName() + " status: " + status + " new state: " + newState);
}
#Override
public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
DebugLogger.d(TAG, "[Proximity Server] onDescriptorReadRequest " + device.getName());
}
#Override
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
DebugLogger.d(TAG, "[Proximity Server] onDescriptorWriteRequest " + device.getName());
}
#Override
public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
DebugLogger.d(TAG, "[Proximity Server] onExecuteWrite " + device.getName());
}
#Override
public void onServiceAdded(final int status, final BluetoothGattService service) {
DebugLogger.d(TAG, "[Proximity Server] onServiceAdded " + service.getUuid());
mHandler.post(new Runnable() {
#Override
public void run() {
// adding another service from callback thread fails on Samsung S4 with Android 4.3
if (IMMEIDIATE_ALERT_SERVICE_UUID.equals(service.getUuid()))
addLinklossService();
else {
DebugLogger.d(TAG, "[Proximity Server] Gatt server started");
Logger.i(mLogSession, "[Proximity Server] Gatt server started");
if (mBluetoothGatt == null) {
mBluetoothGatt = mDeviceToConnect.connectGatt(mContext, false, mGattCallback);
mDeviceToConnect = null;
} else {
mBluetoothGatt.connect();
}
}
}
});
}
};
/**
* Callbacks for activity {HTSActivity} that implements HTSManagerCallbacks interface activity use this method to register itself for receiving callbacks
*/
#Override
public void setGattCallbacks(ProximityManagerCallbacks callbacks) {
mCallbacks = callbacks;
}
/**
* Sets the log session that can be used to log events
*
* #param logSession
*/
public void setLogger(LogSession logSession) {
mLogSession = logSession;
}
#Override
public void connect(Context context, BluetoothDevice device) {
mContext = context;
// save the device that we want to connect to
mDeviceToConnect = device;
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
if (preferences.getBoolean(ProximityActivity.PREFS_GATT_SERVER_ENABLED, true)) {
final BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
try {
DebugLogger.d(TAG, "[Proximity Server] Starting Gatt server...");
Logger.v(mLogSession, "[Proximity Server] Starting Gatt server...");
openGattServer(context, bluetoothManager);
addImmediateAlertService();
// the BluetoothGattServerCallback#onServiceAdded callback will proceed further operations
} catch (final Exception e) {
// On Nexus 4&7 with Android 4.4 (build KRT16S) sometimes creating Gatt Server fails. There is a Null Pointer Exception thrown from addCharacteristic method.
Logger.e(mLogSession, "[Proximity Server] Gatt server failed to start");
Log.e(TAG, "Creating Gatt Server failed", e);
}
} else {
if (mBluetoothGatt == null) {
mBluetoothGatt = mDeviceToConnect.connectGatt(context, false, mGattCallback);
mDeviceToConnect = null;
} else {
mBluetoothGatt.connect();
}
}
}
#Override
public void disconnect() {
if (mBluetoothGatt != null) {
userDisconnectedFlag = true;
mBluetoothGatt.disconnect();
stopAlarm();
closeGattServer();
}
}
private void initializeAlarm(Context context) {
final Uri alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
mRingtoneAlarm = RingtoneManager.getRingtone(context, alarmUri);
mRingtoneAlarm.setStreamType(AudioManager.STREAM_ALARM);
final Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
mRingtoneNotification = RingtoneManager.getRingtone(context, notification);
}
private void playNotification() {
DebugLogger.d(TAG, "playNotification");
mRingtoneNotification.play();
}
private void playAlarm() {
DebugLogger.d(TAG, "playAlarm");
final AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
am.setStreamVolume(AudioManager.STREAM_ALARM, am.getStreamMaxVolume(AudioManager.STREAM_ALARM), AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
mRingtoneAlarm.play();
}
private void stopAlarm() {
DebugLogger.d(TAG, "stopAlarm");
mRingtoneAlarm.stop();
}
/**
* BluetoothGatt callbacks for connection/disconnection, service discovery, receiving indication, etc
*/
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
DebugLogger.d(TAG, "Device connected");
mBluetoothGatt.discoverServices();
//This will send callback to ProximityActivity when device get connected
mCallbacks.onDeviceConnected();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
DebugLogger.d(TAG, "Device disconnected");
if (userDisconnectedFlag) {
mCallbacks.onDeviceDisconnected();
userDisconnectedFlag = false;
} else {
playNotification();
mCallbacks.onLinklossOccur();
}
}
} else {
mCallbacks.onError(ERROR_CONNECTION_STATE_CHANGE, status);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
final List<BluetoothGattService> services = gatt.getServices();
for (BluetoothGattService service : services) {
if (service.getUuid().equals(IMMEIDIATE_ALERT_SERVICE_UUID)) {
DebugLogger.d(TAG, "Immediate Alert service is found");
mAlertLevelCharacteristic = service.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID);
} else if (service.getUuid().equals(LINKLOSS_SERVICE_UUID)) {
DebugLogger.d(TAG, "Linkloss service is found");
mLinklossCharacteristic = service.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID);
} else if (service.getUuid().equals(BATTERY_SERVICE_UUID)) {
DebugLogger.d(TAG, "Battery service is found");
mBatteryCharacteristic = service.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC_UUID);
}
}
if (mLinklossCharacteristic == null) {
mCallbacks.onDeviceNotSupported();
gatt.disconnect();
} else {
mCallbacks.onServicesDiscovered(mAlertLevelCharacteristic != null);
writeLinklossAlertLevel(HIGH_ALERT);
}
} else {
mCallbacks.onError(ERROR_DISCOVERY_SERVICE, status);
}
mBluetoothGatt.readRemoteRssi();
DebugLogger.d(TAG, "Finished READING THE RSSI");
}
#Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
if (rssi != 0) {
rssilevel = rssi; }
else {
rssilevel = 0; }
DebugLogger.d(TAG, "READING THE RSSI");
}
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (characteristic.getUuid().equals(BATTERY_LEVEL_CHARACTERISTIC_UUID)) {
int batteryValue = characteristic.getValue()[0];
mCallbacks.onBatteryValueReceived(batteryValue);
}
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED);
mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status);
}
} else {
mCallbacks.onError(ERROR_READ_CHARACTERISTIC, status);
}
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (characteristic.getUuid().equals(ALERT_LEVEL_CHARACTERISTIC_UUID)) {
if (mBatteryCharacteristic != null) {
readBatteryLevel();
}
}
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED);
mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status);
}
} else {
mCallbacks.onError(ERROR_WRITE_CHARACTERISTIC, status);
}
}
};
private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent intent) {
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1);
// skip other devices
if (!device.getAddress().equals(mBluetoothGatt.getDevice().getAddress()))
return;
DebugLogger.i(TAG, "Bond state changed for: " + device.getName() + " new state: " + bondState + " previous: " + previousBondState);
if (bondState == BluetoothDevice.BOND_BONDING) {
mCallbacks.onBondingRequired();
return;
}
if (bondState == BluetoothDevice.BOND_BONDED) {
if (mLinklossCharacteristic != null) {
writeLinklossAlertLevel(HIGH_ALERT);
}
mCallbacks.onBonded();
}
}
};
private void readBatteryLevel() {
if (mBatteryCharacteristic != null) {
DebugLogger.d(TAG, "reading battery characteristic");
mBluetoothGatt.readCharacteristic(mBatteryCharacteristic);
} else {
DebugLogger.w(TAG, "Battery Level Characteristic is null");
}
}
#SuppressWarnings("unused")
private void readLinklossAlertLevel() {
if (mLinklossCharacteristic != null) {
DebugLogger.d(TAG, "reading linkloss alert level characteristic");
mBluetoothGatt.readCharacteristic(mLinklossCharacteristic);
} else {
DebugLogger.w(TAG, "Linkloss Alert Level Characteristic is null");
}
}
private void writeLinklossAlertLevel(int alertLevel) {
if (mLinklossCharacteristic != null) {
DebugLogger.d(TAG, "writing linkloss alert level characteristic");
mLinklossCharacteristic.setValue(alertLevel, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
mBluetoothGatt.writeCharacteristic(mLinklossCharacteristic);
} else {
DebugLogger.w(TAG, "Linkloss Alert Level Characteristic is not found");
}
}
public void writeImmediateAlertOn() {
if (mAlertLevelCharacteristic != null) {
DebugLogger.d(TAG, "writing Immediate alert characteristic On");
mAlertLevelCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
mAlertLevelCharacteristic.setValue(HIGH_ALERT, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
mBluetoothGatt.writeCharacteristic(mAlertLevelCharacteristic);
} else {
DebugLogger.w(TAG, "Immediate Alert Level Characteristic is not found");
}
}
public void writeImmediateAlertOff() {
if (mAlertLevelCharacteristic != null) {
DebugLogger.d(TAG, "writing Immediate alert characteristic Off");
mAlertLevelCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
mAlertLevelCharacteristic.setValue(NO_ALERT, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
mBluetoothGatt.writeCharacteristic(mAlertLevelCharacteristic);
} else {
DebugLogger.w(TAG, "Immediate Alert Level Characteristic is not found");
}
}
#Override
public void closeBluetoothGatt() {
try {
mContext.unregisterReceiver(mBondingBroadcastReceiver);
} catch (Exception e) {
// the receiver must have been not registered or unregistered before
}
if (mBluetoothGatt != null) {
mBluetoothGatt.close();
mBluetoothGatt = null;
}
if (mBluetoothGattServer != null) {
mBluetoothGattServer.close();
mBluetoothGattServer = null;
}
mCallbacks = null;
mLogSession = null;
mRingtoneAlarm = mRingtoneNotification = null;
}
}
in the following coding i am getting battery level of some percentage.but i want to call notify characteristics so that for every 5 to 10 secs it updates the percentage of battery.so please help me.the following is my device control activity,in this i coded as follows.
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
}
}
};
and in the following method i am setting battery value and displaying in the value in percentage on image.
private void displayData(String data) {
Log.v("______________________No serives_______________",data );
if (data != null) {
mBluetoothLeService.setCharacteristicNotification(mNotifyCharacteristic, true);
battery.setText(data);
int x=Integer.parseInt(battery.getText().toString());
image_level.getLayoutParams().height = x*2;
}
else if (data==null)
battery.setText(data);
}
and the following is my ble service in this i add the set notification method wh
ich is as follows.
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
//For cube write
if (UUID_BatteryService.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
public boolean writeCharacteristic(BluetoothGattCharacteristic i){
//check mBluetoothGatt is available
if (mBluetoothGatt == null) {
Log.e(TAG, "lost connection");
return false;
}
BluetoothGattService Service = mBluetoothGatt.getService(UUID_BatteryService);
if (Service == null) {
Log.e(TAG, "service not found!");
//////////NO service found...........
return false;
}
boolean status = mBluetoothGatt.writeCharacteristic(i);
Log.e(TAG, "bluetooth write status"+status);
return status;
}
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
if(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG_BATTERY.
toString().
equalsIgnoreCase(characteristic.getUuid().toString())) {
Log.v("_____________","in broadcastupdate..........");
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
final int flag = characteristic.getProperties();
int format = -1;
if ((flag & 0x01) != 0) {
format = BluetoothGattCharacteristic.FORMAT_UINT16;
Log.d(TAG, " format UINT16.");
} else {
format = BluetoothGattCharacteristic.FORMAT_UINT8;
Log.d(TAG, " UINT8.");
}
int batterylevel = characteristic.getIntValue(format, 0);
intent.putExtra(EXTRA_DATA, String.valueOf(batterylevel));
//intent.putExtra(EXTRA_DATA,new String(data));
}
}
sendBroadcast(intent);
}
If I well understood your question, you will need a Timer in order to check you battery level regularly.
For instance, you could use this code after starting your device control activity, maybe at the end of the onServiceConnected method :
please put the timer at the end of onServiceConnected() method of mServiceConnection object
Timer timer = new Timer("batteryTimer");
TimerTask task = new TimerTask() {
#Override
public void run() {
mBluetoothLeService.getBattery();
}
};
timer.scheduleAtFixedRate(task, 0, 5000);
And do not forget to call timer.cancel() when the activity is finishing.
And in the service, you could put something like that :
public void getBattery() {
if (mBluetoothGatt == null) {
Log.e(TAG, "lost connection");
}
BluetoothGattService batteryService = mBluetoothGatt.getService(Battery_Service_UUID);
if(batteryService == null) {
Log.d(TAG, "Battery service not found!");
return;
}
BluetoothGattCharacteristic batteryLevel = batteryService.getCharacteristic(Battery_Level_UUID);
if(batteryLevel == null) {
Log.d(TAG, "Battery level not found!");
return;
}
mBluetoothGatt.readCharacteristic(batteryLevel);
}
It is an example which would need to be modified but that gives you an idea on how to do it.
Somebody already did access to the battery value in the link below :
How to get the battery level after connect to the BLE device?