简体   繁体   English

如何从 BLE 设备读取数据

[英]How to read data from BLE device

So, I have been struggling for some time now with this BLE.所以,我一直在为这个 BLE 苦苦挣扎一段时间。 I am working on an Appcelerator module that can enable communication (read/write data) from some devices with an Android tablet.我正在开发一个 Appcelerator 模块,该模块可以启用与 Android 平板电脑的某些设备的通信(读/写数据)。 I am able to scan, discover devices, connect to it and discover it's services.我能够扫描、发现设备、连接到它并发现它的服务。 What I am unable to do is to read data.我无法做的是读取数据。 As you can see on the below code, the contents on method readData() ALWAYS return false.正如您在下面的代码中看到的,方法 readData() 的内容总是返回 false。 (writeDescriptor, readCharacteristic, readDescriptor). (writeDescriptor、readCharacteristic、readDescriptor)。 No matter what, this always returns false.无论如何,这总是返回 false。 The callback is never called, and I am completely stuck.回调永远不会被调用,我完全被卡住了。 What on earth am I doing wrong?我到底做错了什么? How can I set those stuff on readData() to be true, and what to do after that?如何将 readData() 上的这些内容设置为 true,之后该怎么做? Thank you all in advance!谢谢大家!

I have checked stackOverflow many many times and tried lots of solutions proposed here, but nothing seems to work.我已经多次检查 stackOverflow 并尝试了很多这里提出的解决方案,但似乎没有任何效果。 As far as I understood, my steps are correct.据我了解,我的步骤是正确的。 Something is missing... Just don't know what...少了点什么……就是不知道是什么……

public class AndroidbleModule extends KrollModule  {

    private BluetoothManager btManager;
    private BluetoothAdapter btAdapter;
    private BluetoothDevice btDevice;
    private TiApplication appContext;
    private Activity activity;
    private BluetoothLeScanner btScanner;

    public AndroidbleModule() {
        super();
        appContext = TiApplication.getInstance();
        activity = appContext.getCurrentActivity();
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        filter.addAction(BluetoothDevice.ACTION_UUID);
        filter.addAction(BluetoothDevice.ACTION_FOUND);
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
        appContext.registerReceiver(new BlutoothStateChangedBroadcastReceiver(AndroidbleModule.this, btAdapter),
                filter);
    }

    private BluetoothGatt bluetoothGatt;
    private BluetoothGattCallbackHandler btGattHandler = new BluetoothGattCallbackHandler(AndroidbleModule.this);

    @Kroll.method
    public void connectToDevice(String device) {

        if (bluetoothGatt != null) {
            bluetoothGatt.disconnect();
        }
        for (String devName : btDevices.keySet()) {

            if(device.equals(devName)) {
                BluetoothDevice deviceAddress = btDevices.get(devName);
                bluetoothGatt = deviceAddress.connectGatt(appContext, false, btGattHandler);
                bluetoothGatt.connect();
                bluetoothGatt.discoverServices();
                deviceAddress.createBond();
                deviceAddress.getBondState();   
                btDevice = deviceAddress;
            }
        }
    }
    BluetoothGattCharacteristic charac;
    BluetoothGattDescriptor desc;

    @Kroll.method
    public void setNotifications() {
        List<BluetoothGattService> btGattServicesList = bluetoothGatt.getServices();
        List<BluetoothGattCharacteristic> btGattCharList = btGattServicesList.get(2).getCharacteristics();
        List<BluetoothGattDescriptor> btDescList = btGattCharList.get(1).getDescriptors();
        BluetoothGattCharacteristic characteristic = btGattCharList.get(1);
        BluetoothGattDescriptor descriptor = btDescList.get(0);

        bluetoothGatt.setCharacteristicNotification(characteristic, true);
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);

        charac = characteristic;
        desc = descriptor;
    }

    @Kroll.method
    public void readData() {
        bluetoothGatt.writeDescriptor(desc);
        bluetoothGatt.readCharacteristic(charac);
        bluetoothGatt.readDescriptor(desc);
    }

    private Set<String> devSet = new LinkedHashSet<String>();

    HashMap<String, BluetoothDevice> btDevices = new HashMap<String, BluetoothDevice>();

    private ScanCallback scanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {

            BluetoothDevice device;
            device = result.getDevice();

            KrollDict kd = new KrollDict();
            kd.put("name", device.getName());
            kd.put("address", device.getAddress());

            System.out.println("Devices Found on Scan: " + kd.toString());

            btDevice = device;
            devSet.add(device.getName());
            btDevices.put(device.getName(), device);
        }
    };

    @Kroll.method
    public void startScanning(@Kroll.argument(optional = true) int _scanmode) {
        if (btAdapter != null) {
            btScanner = btAdapter.getBluetoothLeScanner();
            btScanner.startScan(scanCallback);
            isScanning = true;
        }
    }
}

First, my connectToDevice() method, with the changes mentioned:首先,我的 connectToDevice() 方法,其中提到的更改:

public void connectToDevice(String device) {
    if (bluetoothGatt != null) {
        bluetoothGatt.disconnect();
    }
    for (String devName : btDevices.keySet()) {

        if(device.equals(devName)) {
            BluetoothDevice deviceAddress = btDevices.get(devName);
            bluetoothGatt = deviceAddress.connectGatt(appContext, false, btGattHandler);
            btDevice = deviceAddress;
        }
    }
}

The onConnectionStateChanged() callback method: onConnectionStateChanged() 回调方法:

public void onConnectionStateChange(final BluetoothGatt gatt,
        final int status, final int newState) {
    gatt.getDevice().createBond();
    KrollDict kd = new KrollDict();
    kd.put("newState", newState);
    kd.put("status", status);
    if (proxy.hasListeners("didConnectionStateChange")) {
        proxy.fireEvent("didConnectionStateChange", kd);
    }
    gatt.discoverServices();
}

The onServicesDiscovered() callback method: onServicesDiscovered() 回调方法:

public void onServicesDiscovered(final BluetoothGatt gatt, final int status) {
    BluetoothDevice device = gatt.getDevice();
    KrollDict kdServices = new KrollDict();
    KrollDict kdCharacteristics = new KrollDict();

    List<BluetoothGattService> services = gatt.getServices();
    kdServices.put("device", device.getAddress());
    kdCharacteristics.put("device", device.getAddress());

    Log.i(LCAT, device.getAddress() + " services count: " + services.size());

    ArrayList<Object> listServices = new ArrayList<>();
    HashMap<String, Object> hashChar = new HashMap<String, Object>();

    for (BluetoothGattService service : services) {
        Log.i(LCAT,
                "Service: " + service.getType() + " " + service.getUuid());

        HashMap<String, Object> listService = new HashMap<String, Object>();
        listService.put("serviceType", service.getType());
        listService.put("serviceUuid", service.getUuid());
        listServices.add(listService);

        ArrayList<HashMap<String, Object>> listChars = new ArrayList<HashMap<String, Object>>();
        List<BluetoothGattCharacteristic> characteristics = service
                .getCharacteristics();
        for (BluetoothGattCharacteristic btc : characteristics) {
            Log.i(LCAT, "uuid: " + btc.getUuid());

            HashMap<String, Object> listChar = new HashMap<String, Object>();
            listChar.put("uuid", btc.getUuid());
            listChar.put("value", btc.getValue());

            listChars.add(listChar);
            // TODO not needed at the moment
             byte[] data = btc.getValue();
             if (data != null && data.length > 0) {
             final StringBuilder stringBuilder = new
             StringBuilder(data.length);
             for (byte byteChar : data) {
             stringBuilder.append(String.format("%02X ", byteChar));
             }

             Log.i(LCAT, "String val: " + btc.getUuid() + " " +
             btc.getValue() + " " + stringBuilder.toString());
             }
            gatt.readCharacteristic(btc);
        }
        hashChar.put("serviceUuid", service.getUuid());
        hashChar.put("chars", listChars);
    }
    if (proxy.hasListeners("didDiscoverServices"))
        proxy.fireEvent("didDiscoverServices", kdServices);
    if (proxy.hasListeners("didDiscoverCharacteristicsForService"))
        proxy.fireEvent("didDiscoverCharacteristicsForService",
                kdCharacteristics);
    System.out.println("Services successfully discovered!");
}

The setNotifications() I've left untouched, and as you can see, it's returning true for everything. setNotifications() 我没有动过,正如你所看到的,它对所有东西都返回 true。 Now, when I call readData() (just left one gatt call, which is writeCharacteristic()), it returns false, as seen in the last line of the log.现在,当我调用 readData()(只剩下一个 gatt 调用,即 writeCharacteristic())时,它返回 false,如日志的最后一行所示。 Check it out.一探究竟。

The Log:日志:

I/System.out: connectToDevice() called!
I/System.out: Device successfully connected!

BluetoothDevice: createBond() for device FA:45:B9:7C:86:7C called by pid: 6194 tid: 6207

BLE: (Binder:6194_2) [19078,19078] FA:45:B9:7C:86:7C services count: 3
BLE: (Binder:6194_2) [1,19079] Service: 0 00001800-0000-1000-8000-00805f9b34fb
BLE: (Binder:6194_2) [0,19079] uuid: 00002a00-0000-1000-8000-00805f9b34fb
BLE: (Binder:6194_2) [1,19080] uuid: 00002a01-0000-1000-8000-00805f9b34fb
BLE: (Binder:6194_2) [0,19080] uuid: 00002a04-0000-1000-8000-00805f9b34fb
BLE: (Binder:6194_2) [1,19081] uuid: 00002aa6-0000-1000-8000-00805f9b34fb
BLE: (Binder:6194_2) [0,19081] Service: 0 00001801-0000-1000-8000-00805f9b34fb
BLE: (Binder:6194_2) [0,19081] Service: 0 6e400001-b5a3-f393-e0a9-e50e24dcca9e
BLE: (Binder:6194_2) [0,19081] uuid: 6e400002-b5a3-f393-e0a9-e50e24dcca9e
BLE: (Binder:6194_2) [0,19081] uuid: 6e400003-b5a3-f393-e0a9-e50e24dcca9e
I/System.out: Services successfully discovered!

I/System.out: btGattServicesList - [android.bluetooth.BluetoothGattService@c893553, android.bluetooth.BluetoothGattService@5dd2e90, android.bluetooth.BluetoothGattService@6bce389]
I/System.out: btGattCharList - [android.bluetooth.BluetoothGattCharacteristic@b6cf8e, android.bluetooth.BluetoothGattCharacteristic@6e7d3af]
I/System.out: btDescList - [android.bluetooth.BluetoothGattDescriptor@b8ea3bc]

I/System.out: setCharacteristicNotification = true
I/System.out: Enable Notification Value = true
I/System.out: characteristic.addDescriptor(descriptor) = true

I/System.out: bluetoothGatt.writeCharacteristic(charac) false

What the hell is missing or going wrong here?这里到底缺少什么或出了什么问题?

So, after a lot of time wasted, I figured it out.所以,在浪费了很多时间之后,我想通了。 setNotifications is only the first step. setNotifications 只是第一步。 We must tell the device to start streaming data so the App can collect it.我们必须告诉设备开始流式传输数据,以便应用程序可以收集它。 It is done via bluetoothGatt.writeCharacteristic(characteristic) After we proper set the writings, of course.它是通过 bluetoothGatt.writeCharacteristic(characteristic) 完成的,当然,在我们正确设置文字之后。 With this done, the bytes just keep coming!完成此操作后,字节就会不断出现! =) =)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM