1

I'm attempting to receive data from my Texas sensor tag, but so far I just managed to connect and write characteristics to it.

this is my setCharacteristicNotification(); the part commented below does not work and I didn't managed to use it.

    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
                                              boolean enabled) {
        if(bluetoothAdapter == null || bluetoothGatt == null) return;

        bluetoothGatt.setCharacteristicNotification(characteristic, enabled);

        if(GattUUIDs.containsUuid(characteristic.getUuid())) {
//            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
//                    UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
            BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(
                    GattUUIDs.UUID_CLIENT_CHAR_CONFIG, BluetoothGattDescriptor.PERMISSION_WRITE |
                    BluetoothGattDescriptor.PERMISSION_READ);

            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            bluetoothGatt.writeDescriptor(descriptor);

        }
    }

When I try to call the commented block, this is what I receive:

java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.bluetooth.BluetoothGattDescriptor.setValue(byte[])' on a null object reference

This is my Client Characteristic Configuration UUID:

public static final UUID UUID_CLIENT_CHAR_CONFIG =
         UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG);
public static String CLIENT_CHARACTERISTIC_CONFIG = "f0002902-0451-4000-b000-000000000000";

I think that it has some sort of problem in my descriptor because I can register it but I never got a callback from it.


If it helps, this is my Service:

import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import java.util.List;
import java.util.UUID;


/**
 * Created by alan on 2/23/16.
 */
public class DeviceService extends Service {

    private final static String TAG = DeviceService.class.getSimpleName();

    private BluetoothGatt bluetoothGatt;
    private String deviceAddress;
    private BluetoothManager bluetoothManager;
    private BluetoothAdapter bluetoothAdapter;
    private int connectionState = STATE_DISCONNECTED;

    public final IBinder binder = new LocalBinder();
    public static final int STATE_DISCONNECTED = 0;
    public static final int STATE_CONNECTING   = 1;
    public static final int STATE_CONNECTED    = 2;

    public static final String ACTION_GATT_SERVICES_DISCOVERED = "action_gatt_services_discovered";
    public static final String ACTION_GATT_DISCONNECTED        = "action_gatt_disconnected";
    public static final String ACTION_GATT_CONNECTED           = "action_gatt_connected";
    public static final String ACTION_DATA_AVAILABLE           = "action_data_available";
    public static final String ACTION_DATA_NOTIFY              = "action_data_notify";
    public static final String ACTION_DATA_WRITE               = "action_data_write";
    public static final String ACTION_DATA_READ                = "action_data_read";
    public static final String EXTRA_DATA                      = "extra_data";


    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        close();
        return super.onUnbind(intent);
    }

    public boolean initialize() {
        if(bluetoothManager == null) {
            bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
            if(bluetoothManager == null) {
                Log.e(TAG,"CANNOT INITIALIZE BLUETOOTH");
                return false;
            }
        }bluetoothAdapter = bluetoothManager.getAdapter();
        if(bluetoothAdapter == null) {
            Log.e(TAG,"CANNOT FIND AN ADAPTER");
            return false;
        }return true;
    }

    public boolean connect(final String address) {
        Log.w(TAG,"CONNECT PROCESS INITIALIZED");
        if(bluetoothAdapter == null || address == null) {
            Log.e(TAG,"ADAPTER NOT INITIALIZED");
            return false;
        }
        //previously connected device, attempt to reconnect
        if(deviceAddress != null && deviceAddress.equals(address)
                &&bluetoothGatt != null) {
            Log.d(TAG, "TRYING TO USE EXISTING GATT");
            if(bluetoothGatt.connect()) {
                connectionState = STATE_CONNECTING;
                bluetoothGatt.connect();
                return true;
            } else
                return false;
        }

        final BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
        if(device == null) {
            Log.e(TAG, "DEVICE NOT FOUND");
            return false;
        }
        bluetoothGatt = device.connectGatt(this, false, gattCallback);
        deviceAddress = address;
        connectionState = STATE_CONNECTING;
        return true;
    }

    public void disconnect() {
        if(bluetoothAdapter == null || bluetoothGatt == null) {
            Log.w(TAG, "BLUETOOTH NOT INITIALIZED");
            return;
        }
        bluetoothGatt.disconnect();
    }

    public void close() {
        if(bluetoothGatt == null)
            return;
        bluetoothGatt.close();
        bluetoothGatt = null;
    }

    public class LocalBinder extends Binder {
        DeviceService getService() {
          return DeviceService.this;
        }
    }

    private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            String intentAction;
            if(newState == BluetoothProfile.STATE_CONNECTED) {
                intentAction = ACTION_GATT_CONNECTED;
                connectionState = STATE_CONNECTED;
                broadcastUpdate(intentAction);
                Log.i(TAG,"CONNECTED TO GATT SERVER!");
                bluetoothGatt.discoverServices();
            } else if(newState == BluetoothProfile.STATE_DISCONNECTED) {
                intentAction = ACTION_GATT_DISCONNECTED;
                connectionState = STATE_DISCONNECTED;
                Log.i(TAG,"DISCONNECTED FROM GATT SERVER");
                broadcastUpdate(intentAction);
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            Log.e(TAG,"STATUS: " + String.valueOf(status));
            if (status == BluetoothGatt.GATT_SUCCESS)
                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt,
                                         BluetoothGattCharacteristic characteristic,
                                         int status) {

            if (status == BluetoothGatt.GATT_SUCCESS)
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                                            BluetoothGattCharacteristic characteristic) {
            Log.e(TAG,"CHAR CHANGED \n" + gatt.toString() + "\n" + characteristic.getUuid().toString() + "\n");
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt,
                                          BluetoothGattCharacteristic characteristic,
                                          int status) {
            Log.e(TAG,"CHAR WROTE" + gatt.toString() + "\n" + characteristic.getUuid().toString() + "\n");
            if(status == BluetoothGatt.GATT_SUCCESS)
                broadcastUpdate(ACTION_DATA_WRITE, characteristic);
        }
    };

    public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
        if(bluetoothAdapter == null || bluetoothGatt == null) {
            Log.e(TAG, "ADAPTER NOT INITIALIZED");
            return;
        }
        bluetoothGatt.readCharacteristic(characteristic);
    }

    public void writeCharacteristic(BluetoothGattCharacteristic characteristic, byte[] value) {
        if(bluetoothAdapter == null || bluetoothGatt == null) {
            Log.e(TAG, "ADAPTER NOT INITIALIZED");
            return;
        }
        characteristic.setValue(value);
        characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
        bluetoothGatt.writeCharacteristic(characteristic);
        System.out.println("Write value: " + value[0] + " on UUID: " + characteristic.getUuid().toString());
    }

    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
                                              boolean enabled) {
        if(bluetoothAdapter == null || bluetoothGatt == null) return;

        bluetoothGatt.setCharacteristicNotification(characteristic, enabled);

        if(GattUUIDs.containsUuid(characteristic.getUuid())) {
            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
                    UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
//            BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(
//                    GattUUIDs.UUID_CLIENT_CHAR_CONFIG, BluetoothGattDescriptor.PERMISSION_WRITE |
//                    BluetoothGattDescriptor.PERMISSION_READ);

            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            bluetoothGatt.writeDescriptor(descriptor);

        }
    }

    public void setCharacteristicIndication(BluetoothGattCharacteristic characteristic,
                                            boolean enabled) {
        if(bluetoothAdapter ==null || bluetoothGatt == null) return;

        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
                UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
        bluetoothGatt.writeDescriptor(descriptor);

        bluetoothGatt.setCharacteristicNotification(characteristic, enabled);
    }

    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);
        final UUID uuid = characteristic.getUuid();
        Log.w(TAG,"BROADCAST UPDATE WITH ACTION: " + action);
        if(GattUUIDs.containsUuid(uuid)) {
            Log.e(TAG,"PASSOU AQUI");
            int flag = characteristic.getProperties();
            int format;

            if((flag & 0x01) != 0)
                format = BluetoothGattCharacteristic.FORMAT_UINT16;
            else
                format = BluetoothGattCharacteristic.FORMAT_UINT8;

            byte[] data = characteristic.getValue();

            if (GattUUIDs.UUID_IR_TEMPERATURE_MEASUREMENT.equals(uuid)) {
                float objectTemperature  = ((((float)data[1] * 256 + (float)data[0]) / (float)4)) * (float)0.03125;
                float ambientTemperature = ((((float)data[3] * 256 + (float)data[2]) / (float)4)) * (float)0.03125;

//                final int temp_data = characteristic.getIntValue(format, 1);
                intent.putExtra(EXTRA_DATA, String.format("%.2f %.2f", objectTemperature, ambientTemperature));
            } else if (GattUUIDs.UUID_IR_TEMPERATURE_CONFIG.equals(uuid)) {
                if (data[0] == 0)
                    intent.putExtra(EXTRA_DATA, "IR DISABLED");
                else
                    intent.putExtra(EXTRA_DATA, "IR ENABLED");
            } else if (GattUUIDs.UUID_IR_TEMPERATURE_PERIOD.equals(uuid))
                intent.putExtra(EXTRA_DATA, String.format("%d",data[0]*10));

            else if (GattUUIDs.UUID_OPTICAL_MEASUREMENT.equals(uuid)) {
                int m = (data[1] * 256 + data[0]) & 0x0FFF;
                int e = ((data[1] * 256 + data[0]) & 0xF000) >> 12;
                double lux = m * 0.01 * Math.pow(2.0,e);
                intent.putExtra(EXTRA_DATA, String.format("%.2f",lux));
            } else if (GattUUIDs.UUID_OPTICAL_CONFIG.equals(uuid)) {
                if(data[0] == 0)
                    intent.putExtra(EXTRA_DATA, "OPTICAL DISABLED");
                else
                    intent.putExtra(EXTRA_DATA, "OPTICAL ENABLED");
            } else if (GattUUIDs.UUID_OPTICAL_PERIOD.equals(uuid))
                intent.putExtra(EXTRA_DATA, String.format("%d",data[0] * 10));

            else if (GattUUIDs.UUID_MOVEMENT_MEASUREMENT.equals(uuid))
                intent.putExtra(EXTRA_DATA, String.format("%d %d %d %d %d %d %d %d %d",
                        (data[0] + data[1]*256),
                        (data[2] + data[3]*256),
                        (data[4] + data[5]*256),
                        (data[6] + data[7]*256),
                        (data[8] + data[9]*256),
                        (data[10] + data[11]*256),
                        (data[12] + data[13]*256),
                        (data[14] + data[15]*256),
                        (data[16] + data[17]*256)));
            else if (GattUUIDs.UUID_MOVEMENT_CONFIG.equals(uuid)) {
                if (data[0] == 0)
                    intent.putExtra(EXTRA_DATA, "MOVEMENT DISABLED");
                else
                    intent.putExtra(EXTRA_DATA, "MOVEMENT ENABLEd");
            } else if (GattUUIDs.UUID_MOVEMENT_PERIOD.equals(uuid))
                intent.putExtra(EXTRA_DATA, String.format("%d",data[0] * 10));

            else {
                if (data != null && data.length > 0) {
                    final StringBuilder stringBuilder = new StringBuilder(data.length);
                    for(byte byteChar : data)
                        stringBuilder.append(String.format("%02X ",byteChar));
                    intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
                }
            }
        }
        sendBroadcast(intent);
    }

    public List<BluetoothGattService> getSupportedGattServices() {
        if(bluetoothGatt == null) return null;

        return bluetoothGatt.getServices();
    }
}

and this is my device control:

import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;

import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.CompoundButton;
import android.widget.Switch;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

/**
 * Created by alan on 2/23/16.
 */
public class DeviceControl extends AppCompatActivity {

    private final String TAG = DeviceControl.class.getSimpleName();

    private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacterics = new ArrayList<>();
    private BluetoothGattCharacteristic bluetoothGattCharacteristic;
    public static String ADDRESS;
    private DeviceService deviceService;
    private boolean connected = false;
    private TextView dataText;
    private Switch temperatureSwitch,
                   movementSwitch,
                   opticalSwitch;

    private final String LIST_NAME = "NAME";
    private final String LIST_UUID = "UUID";

    private final ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(TAG,"ONSERVICECONNECTED");
            deviceService = ((DeviceService.LocalBinder)service).getService();
            if(!deviceService.initialize())
                finish();
            deviceService.connect(ADDRESS);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            deviceService = null;
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceBundle) {
        super.onCreate(savedInstanceBundle);
        setContentView(R.layout.activity_device_control);

        dataText = (TextView)findViewById(R.id.dataText);
        temperatureSwitch = (Switch)findViewById(R.id.temperatureSwitch);
        movementSwitch    = (Switch)findViewById(R.id.movementSwitch);
        opticalSwitch     = (Switch)findViewById(R.id.opticalSwitch);

        temperatureSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

                if(isChecked && connected)
                    writeCharacteristic(GattUUIDs.UUID_IR_TEMPERATURE_CONFIG, true);
                else if(!isChecked && connected)
                    writeCharacteristic(GattUUIDs.UUID_IR_TEMPERATURE_CONFIG, false);
            }
        });

        Bundle extras = getIntent().getExtras();

        if(extras != null) {
            setTitle(extras.getString("title"));
            ADDRESS = extras.getString("address");

            Intent intent = new Intent(this, DeviceService.class);
            bindService(intent, serviceConnection, BIND_AUTO_CREATE);
        }
        registerReceiver(broadcastReceiver, makeIntentFilter());
    }

    public void writeCharacteristic(UUID toFind, boolean read) {
        BluetoothGattCharacteristic gattCharacteristic = null;
        byte[] enable = {(byte)0x01},
                disable = {(byte)0x00};
        for(int i = 0; i < mGattCharacterics.size(); i++) {
            for(int j = 0; j < mGattCharacterics.get(i).size(); j++) {
                if(mGattCharacterics.get(i).get(j).getUuid().equals(toFind))
                    gattCharacteristic = mGattCharacterics.get(i).get(j);
            }
        }
        if(gattCharacteristic != null) {
            if(read)
                deviceService.writeCharacteristic(gattCharacteristic, enable);
            else
                deviceService.writeCharacteristic(gattCharacteristic, disable);
            deviceService.setCharacteristicNotification(gattCharacteristic, true);
        } else
            Log.e(TAG,"NOTHING FOUND");


    }

    @Override
    protected void onResume() {
        super.onResume();
        registerReceiver(broadcastReceiver, makeIntentFilter());
        Log.w(TAG,"REGISTER RECEIVER");

        if (deviceService != null) {
            final boolean result = deviceService.connect(ADDRESS);
            Log.d(TAG,"CONNECT RESULT = " + result);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(broadcastReceiver);
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        deviceService.disconnect();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(serviceConnection);
        deviceService = null;
    }

    private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            Log.e(TAG,"BROADCAST ACTION"+action);
            switch (action) {
                case DeviceService.ACTION_GATT_CONNECTED:
                    connected = true;
                    break;
                case DeviceService.ACTION_GATT_DISCONNECTED:
                    connected = false;
                    break;
                case DeviceService.ACTION_GATT_SERVICES_DISCOVERED:
                    getGattServices(deviceService.getSupportedGattServices());
                    break;
                case DeviceService.ACTION_DATA_AVAILABLE:
                    displayData(intent.getStringExtra(DeviceService.EXTRA_DATA));
            }
        }
    };

    private void displayData(String data) {
        if(data != null)
            dataText.setText(data);
    }

    private void getGattServices(List<BluetoothGattService> gattServices) {
        if(gattServices == null) return;
        String uuid = null;
        ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<>();
        ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData
                = new ArrayList<>();
        mGattCharacterics = new ArrayList<>();

        for (BluetoothGattService gattService : gattServices) {
            HashMap<String, String> currentServiceData = new HashMap<>();
            uuid = gattService.getUuid().toString();
            currentServiceData.put(LIST_NAME, GattAttributes.lookup(uuid, "UnknownService"));
            currentServiceData.put(LIST_UUID, uuid);
            gattServiceData.add(currentServiceData);

            ArrayList<HashMap<String, String>> gattCharacteristicGroupData = new ArrayList<>();
            List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
            ArrayList<BluetoothGattCharacteristic> charas = new ArrayList<>();

            for(BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
                charas.add(gattCharacteristic);
                HashMap<String, String> currentCharaData = new HashMap<>();
                uuid = gattCharacteristic.getUuid().toString();
                currentCharaData.put(LIST_NAME, GattAttributes.lookup(uuid, "UnknownCharacteristic"));
                currentCharaData.put(LIST_UUID, uuid);
                gattCharacteristicGroupData.add(currentCharaData);
                //System.out.println("GATTCHAR\n\n" + gattCharacteristic.toString()+"\n");
            }
            mGattCharacterics.add(charas);
            gattCharacteristicData.add(gattCharacteristicGroupData);
        }
    }

    private static IntentFilter makeIntentFilter() {
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(DeviceService.ACTION_GATT_CONNECTED);
        intentFilter.addAction(DeviceService.ACTION_GATT_DISCONNECTED);
        intentFilter.addAction(DeviceService.ACTION_GATT_SERVICES_DISCOVERED);
        intentFilter.addAction(DeviceService.ACTION_DATA_AVAILABLE);
        return intentFilter;
    }
}

Thanks for your attention.

Alan
  • 73
  • 2
  • 8
  • Where did you get your UUID from? It seems like it doesn't exist on the device. There are apps that you can use to see what characteristics are on your device: https://play.google.com/store/apps/details?id=com.macdom.ble.blescanner. – tachyonflux Feb 26 '16 at 20:57
  • thanks for the reply @karaokyo but I solved the problem, it was in my writeCharacteristic function. And, also, I wasn't calling the notify function in the correct way. To work properly you have to set the configuration for the sensor, than you read it and finally you set the notification for the measurement characteristic. I still don't know if this is the correct way of doing it, but it's working. – Alan Feb 29 '16 at 12:07
  • @AlanWeingärtner can you show how did you solve it? – h__ Mar 27 '16 at 20:26
  • OK. I did some changes - first I used flag ENABLE_NOTIFICATION_VALUE instead yours. Also I used the descriptor in characteristic not the "standard" address – h__ Mar 27 '16 at 20:54

0 Answers0