Правильный способ последовательного подключения к устройствам BluetoothGatt - PullRequest
1 голос
/ 28 мая 2019

Я уже внедрил логику сканирования устройства с низким энергопотреблением Bluetooth, но немного борюсь с использованием сервиса BluetoothGatt. Что я хочу сделать, это подключиться к каждому из моих устройств ESP32 последовательно с моего телефона Android, чтобы я мог получить данные и затем перейти к следующему устройству (и отключиться от предыдущего). Таким образом, между ESP32 и телефоном Android будет только одно активное соединение. ESP32 уже запрограммирован, поэтому, если телефон Android подключается к нему через BluetoothGatt, он отправляет данные (максимум 20 байтов).

Настоящая борьба заключается в том, чтобы понять, как управлять этими соединениями для правильного закрытия / освобождения ресурсов.

Каким будет правильный / самый простой способ управления этими BluetoothGatt соединениями?

Моя реализация в основном подключается к сервису Gatt нового устройства, когда отправленные данные "end" Проблема в том, что это работает, если одно устройство ESP32 активно. Если активны другие устройства, что-то происходит, и данные не поступают от службы Gatt.

Вот часть моей реализации (извините, я не могу больше уменьшить размер кода):

1) Я использую сканер BLE для обнаружения новых устройств

private Handler _leScanHandler = new Handler();
private final BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
        final int newRSSI = rssi;
        _leScanHandler.post(new Runnable() {
            @Override
            public void run() {
                addDeviceToListOnLEScan(device, newRSSI);
            }
        });
    }
};

2) И вызываемый метод в основном управляет BluetoothGatt соединениями.

public void addDeviceToListOnLEScan(BluetoothDevice device, int rssi) {

    // Gets only user defined devices
    boolean isUserDefinedDevice = _definedDevicesHashMap.containsKey(device.getAddress());
    if (!isUserDefinedDevice) {
        return;
    }

    // Adds device and updates 'LastModifiedTime = Date(System.currentTimeMillis())'
    addOrUpdateDevice(device.getAddress(), _scannedDevices);

    // Called only once on each connect button press to enable gatt operations
    if (!_isInitialConnectionHasBeenMade) {
        _isDataSendingCompleteFromCurrentGatt = true;
        _isInitialConnectionHasBeenMade = true;
    }

    // Sequential BLE device connect/disconnect operations
    if (_isDataSendingCompleteFromCurrentGatt) {

        BluetoothGatt previousGatt = _definedDevicesHashMap(previousAddress);
        if (previousGatt != null) {
            previousGatt.disconnect(); // ?
        }

        BluetoothGatt nextGatt = _definedDevicesHashMap(nextAddress);
        if (/* Checks if 'nextAddress' is in _scannedDevices */
            /* And whether device 'IsActive()' */) {

            if (nextGatt == null) {
                nextGatt = connectToDeviceGattService(nextGatt)     
            }
            else {
                // Do something here ?
            }
            _isDataSendingCompleteFromCurrentGatt = false;  
        }
    }
}

3) Следующие переменные / классы, которые я использую

private boolean _isDataSendingCompleteFromCurrentGatt = false;
private boolean _isInitialConnectionHasBeenMade = false;
private HashMap<String, BluetoothGatt> _definedDevicesHashMap;
_definedDevicesHashMap.put("ff:ff:9f:c8:c2:93", null);
_definedDevicesHashMap.put("ff:ff:9f:c8:c4:91", null);
...

private HashMap<String, MyBLEDevice> _scannedDevices;

public class MyBLEDevice
{
    private final int deviceInactivityTimeout = 10;
    private String MacAddress;
    private Date _lastModifiedDate;
    public boolean isDeviceActive() {
        // Just gets the time difference (DateNow - lastModified) / 1000 < 10s
    }
}

4) Метод, который я использую для подключения к устройству

public BluetoothGatt connectToDeviceGattService(BluetoothGatt currentGatt, BluetoothDevice device, BluetoothGattCallback callback) {
    _bluetoothAdapter.cancelDiscovery();
    if (currentGatt == null) {
        currentGatt = device.connectGatt(_activity, true, callback);
    }
    else {
        // Is anything here needed ?
    }

    return currentGatt;
}

5) BluetoothGatt обратный вызов

private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {

            // Discover services ?

        } else if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_DISCONNECTED) {

            // Do nothing ?

        } else if (status != BluetoothGatt.GATT_SUCCESS) {

            // Disconnect from current BluetoothGatt instance? 
            // Also close the connection ?

            _isDataSendingCompleteFromCurrentGatt = true;
        }
    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        enableGattConfigurationCharacteristic();
    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
        _gattServiceHandler.post(new Runnable() {
            @Override
            public void run() {
                handleMessage(Message.obtain(null, MSG_CHARACTERISTIC_CHANGE, characteristic));
            }
        });
    }
};

6) И, наконец, обработчик, который используется для получения данных от обратного вызова Гатта

private static final int MSG_CHARACTERISTIC_CHANGE = 0;
private Handler _gattServiceHandler = new Handler();
private void handleMessage(Message msg) {
    BluetoothGattCharacteristic characteristic;
    switch (msg.what) {
        case MSG_CHARACTERISTIC_CHANGE: {
            characteristic = (BluetoothGattCharacteristic) msg.obj;
            if (BLELogic.PROPERTY_NOTIFY_CHAR_UUID.equals(characteristic.getUuid())) {

                String notification = BluetoothExtension.getCharacteristicValue(characteristic);
                if (notification.equals("end")) {
                    _isDataSendingCompleteFromCurrentGatt = true;           
                } else {
                    UpdateViewOnGattNotificationSent(notification);
                }
            }
        }
        default:
            return;
    }
}

Вначале я хотел упростить всю логику, но похоже, что при использовании сервисных соединений BLE / Gatt в этом нет ничего простого.

1 Ответ

0 голосов
/ 28 мая 2019

Вот Вопрос и ответ , который может вас заинтересовать

Коротко от ответа:

Для достижения нескольких соединений BLE необходимо хранить несколько BluetoothGatt объект и использовать эти объекты для различных устройств. к хранить несколько объектов подключения BluetoothGatt вы можете использовать карту <>

частная карта подключенаDeviceMap; .............

...