I have boards to which I connect using BLE, now there is a need to connect to 2 boards at the same time, is it possible?

  • Yes, it is possible, but it all depends on the details of the implementation - who is the server and who is the client. - Vladyslav Matviienko
  • @metalurgus i server - Amir Shabanov
  • Well, it means, in general terms, if you have nothing special - try connecting 2 at once - Vladyslav Matviienko
  • On the Wiki they write that the number of devices depends on the implementation - Andrew Romanenko
  • @AndrewRomanenko I have only 2 devices, the documentation seems to also write what's possible with several, and I even understood what the joke is, I need to write a service for each connection, but this is not accurate, I am currently reading the documentation, I can answer the question myself coming soon - Amir Shabanov

1 answer 1

I have an application that connects to several BLE thermometers. Approximately the architecture is a general service, which contains an array of thermometer objects, the service hangs in memory and periodically checks if anyone is dead. Each thermometer has its own callback, here’s a piece of class. Queues are used to read the characteristics (advice from the English stack), otherwise everything will collapse. Part of the code is not related to the bluetooth cut out

public class SmartThermometer { public static final String ADAPTER_POSITION = "ADAPTER_POSITION"; public static final String TEMP_MAX = "TEMP_MAX"; public static final String TEMP_MIN = "TEMP_MIN"; public static final String TEMP_CURR = "TEMP_CURR"; private static final String TAG = SmartThermometer.class.getSimpleName(); public long _ID = DbModel.UNSAVED_ID; public int mDeviceRssi; public String mDeviceMacAddress; public String mDeviceName; public String mDeviceModelNumber; public String mDeviceSerialNumber; public String mDeviceFirmwareRevisionNumber; public String mDeviceHardwareRevisionNumber; public String mDeviceSoftwareRevisionNumber; public String mDeviceManufacturer; public String mDeviceMeasureUnits; public int mDeviceBatteryLevel; public long measureTime;// = -1; public int mDeviceColorLabel = Color.BLACK; public int mDeviceBackgroundColor = Color.WHITE; public float intermediateTemperature = 1000f; public float maxTemperature = -1000f; public float minTemperature = 1000f; public boolean selected = false; public boolean autoconnect = true; public int mConnectionState = BLEService.STATE_DISCONNECTED; public boolean isNotifyEnabled = false; public float minAlarm = -1000f; public float maxAlarm = -1000f; SharedPreferences preferences; private long adapterPosition; private BluetoothGatt mBluetoothGatt; private Queue<BluetoothGattDescriptor> descriptorWriteQueue = new LinkedList<BluetoothGattDescriptor>(); private Queue<BluetoothGattCharacteristic> characteristicReadQueue = new LinkedList<BluetoothGattCharacteristic>(); private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { String intentAction; Log.e(TAG, "State changed " + newState); if (newState == BluetoothProfile.STATE_CONNECTED) { // intentAction = BLEService.ACTION_GATT_CONNECTED; mConnectionState = BLEService.STATE_CONNECTED; // broadcastUpdate(intentAction); Log.e(TAG, "Connected to GATT server."); // Attempts to discover services after successful connection. Log.e(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices()); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { intentAction = BLEService.ACTION_GATT_DISCONNECTED; mConnectionState = BLEService.STATE_DISCONNECTED; intermediateTemperature = 1000f; isNotifyEnabled = false; Log.e(TAG, "Disconnected from GATT server."); broadcastUpdate(intentAction); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { Log.e(TAG, "Services discovered"); getTemperatureByNotify(true); broadcastUpdate(BLEService.ACTION_GATT_SERVICES_DISCOVERED); //readInfoTypes(); if (mDeviceSerialNumber == null) { // readInfoTypes(); } //else { // broadcastUpdate(BLEService.ACTION_GATT_SERVICES_DISCOVERED); //getTemperatureByNotify(true); //getBatteryByNotify(true); //readInfoTypes(); getBatteryByNotify(true); // } } else { Log.e(TAG, "onServicesDiscovered received: " + status); disconnect(); //connect(true); //mBluetoothGatt.discoverServices(); // disconnect(); } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { characteristicReadQueue.remove(); if (status == BluetoothGatt.GATT_SUCCESS) { UUID uuid = characteristic.getUuid(); if (uuid.equals(RelsibBluetoothProfile.SERIAL_NUMBER_UUID)) { setmDeviceSerialNumber(characteristic.getStringValue(0).substring(0, 12)); Log.e(TAG, "Device serial + " + mDeviceSerialNumber); // return; } if (uuid.equals(RelsibBluetoothProfile.MANUFACTURER_NAME_UUID)) { mDeviceManufacturer = characteristic.getStringValue(0).substring(0, 10); Log.e(TAG, "Device Manufacturer + " + mDeviceManufacturer); // return; } if (uuid.equals(RelsibBluetoothProfile.MODEL_NUMBER_UUID)) { mDeviceModelNumber = characteristic.getStringValue(0).substring(0, 10); Log.e(TAG, "Device model + " + mDeviceModelNumber); // return; } if (uuid.equals(RelsibBluetoothProfile.BATTERY_LEVEL)) { mDeviceBatteryLevel = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0); Log.e(TAG, "Battery level + " + mDeviceBatteryLevel); // return; } if (characteristicReadQueue.size() > 0) mBluetoothGatt.readCharacteristic(characteristicReadQueue.element()); if (characteristicReadQueue.size() == 0) { BLEService.tableThermometers.save(SmartThermometer.this); broadcastUpdate(BLEService.EXTRA_DATA); //getTemperatureByNotify(true); //getBatteryByNotify(true); } } } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { UUID uuid = characteristic.getUuid(); Log.e(TAG, "onChange "); if (uuid.equals(RelsibBluetoothProfile.INTERMEDIATE_TEMPERATURE)) { intermediateTemperature = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_FLOAT, 1); switch (mDeviceMeasureUnits) { case MeasureUnits.Fahrenheit: intermediateTemperature = round(intermediateTemperature * 1.8f + 32f, 1); break; case MeasureUnits.Kelvin: intermediateTemperature = round(intermediateTemperature - 273.15f, 1); break; default: break; } if (maxTemperature <= intermediateTemperature) { setMaxTemperature(intermediateTemperature); } if (minTemperature >= intermediateTemperature) { minTemperature = intermediateTemperature; } broadcastUpdate(BLEService.ACTION_DATA_AVAILABLE, characteristic); //getBatteryByNotify(true); } if (uuid.equals(RelsibBluetoothProfile.BATTERY_LEVEL)) { mDeviceBatteryLevel = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0); Log.e(TAG, "Battery level + " + mDeviceBatteryLevel); BLEService.tableThermometers.save(SmartThermometer.this); broadcastUpdate(BLEService.EXTRA_DATA); } } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorWrite(gatt, descriptor, status); if (status == BluetoothGatt.GATT_SUCCESS) { Log.d(TAG, "Callback: Wrote GATT Descriptor successfully."); } else { Log.d(TAG, "Callback: Error writing GATT Descriptor: " + status); } descriptorWriteQueue.remove(); //pop the item that we just finishing writing //if there is more to write, do it! if (descriptorWriteQueue.size() > 0) mBluetoothGatt.writeDescriptor(descriptorWriteQueue.element()); else if (characteristicReadQueue.size() > 0) mBluetoothGatt.readCharacteristic(characteristicReadQueue.element()); } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { super.onReadRemoteRssi(gatt, rssi, status); mDeviceRssi = rssi; } }; private void broadcastUpdate(final String action) { final Intent intent = new Intent(action); intent.putExtra(ADAPTER_POSITION, adapterPosition); //intent.putExtra(TEMP_CURR,intermediateTemperature); //intent.putExtra(TEMP_MAX,maxTemperature); // intent.putExtra(TEMP_MIN,minTemperature); BLEService.mActivityContext.sendBroadcast(intent); } public void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) { final Intent intent = new Intent(action); BLEService.mActivityContext.sendBroadcast(intent); } // @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; SmartThermometer that = (SmartThermometer) o; return mDeviceMacAddress.equals(that.mDeviceMacAddress); } @Override public int hashCode() { return mDeviceMacAddress.hashCode(); } public boolean connect(boolean autoConnect) { Log.e(TAG, "start connecting"); if (BLEService.mBluetoothAdapter == null || mDeviceMacAddress == null) { Log.e(TAG, "BluetoothAdapter not initialized or unspecified address."); return false; } //Previously connected device. Try to reconnect. if (mDeviceMacAddress != null // && address.equals(mDeviceMacAddress) && mBluetoothGatt != null) { Log.e(TAG, "Trying to use an existing mBluetoothGatt for connection."); if (mBluetoothGatt.connect()) { mConnectionState = BLEService.STATE_CONNECTING; return true; } else { return false; } } BluetoothDevice device = BLEService.mBluetoothAdapter.getRemoteDevice(mDeviceMacAddress); //address if (device == null) { Log.e(TAG, "Device not found. Unable to connect."); mConnectionState = BLEService.STATE_DISCONNECTED; return false; } mBluetoothGatt = device.connectGatt(BLEService.mActivityContext, autoConnect, mGattCallback); if (mBluetoothGatt == null) { mConnectionState = BLEService.STATE_DISCONNECTED; return false; } Log.e(TAG, "Trying to create a new connection."); mConnectionState = BLEService.STATE_CONNECTING; return true; } public void disconnect() { if (BLEService.mBluetoothAdapter == null || mBluetoothGatt == null) { Log.e(TAG, "BluetoothAdapter not initialized"); return; } intermediateTemperature = 1000f; broadcastUpdate(BLEService.ACTION_GATT_DISCONNECTED); mBluetoothGatt.disconnect(); } public void close() { if (mBluetoothGatt == null) { return; } //mConnectionState=BLEService.STATE_DISCONNECTED; mBluetoothGatt.close(); mBluetoothGatt = null; Log.e(TAG, "KILL connection"); } public void readCharacteristic(UUID serviceUUID, UUID characteristicUUID) { if (BLEService.mBluetoothAdapter == null || mBluetoothGatt == null) { Log.e(TAG, "BluetoothAdapter not initialized or gatt null"); return; } BluetoothGattService mCustomService = mBluetoothGatt.getService(serviceUUID); BluetoothGattCharacteristic mReadCharacteristic = mCustomService.getCharacteristic(characteristicUUID); if (mReadCharacteristic == null) { Log.e(TAG, "READ_CHAR_NULL" + mDeviceMacAddress); return; } characteristicReadQueue.add(mReadCharacteristic); //if there is only 1 item in the queue, then read it. If more than 1, we handle asynchronously in the callback above //GIVE PRECEDENCE to descriptor writes. They must all finish first. if ((characteristicReadQueue.size() == 1) && (descriptorWriteQueue.size() == 0)) { mBluetoothGatt.readCharacteristic(mReadCharacteristic); } } public boolean getTemperatureByNotify(boolean enabled) { setCharacteristicNotify(RelsibBluetoothProfile.HEALTH_THERMOMETER_SERVICE, RelsibBluetoothProfile.INTERMEDIATE_TEMPERATURE, enabled); measureTime = SystemClock.elapsedRealtime(); isNotifyEnabled = enabled; return true; } public void getBatteryByNotify(boolean enabled) { setCharacteristicNotify(RelsibBluetoothProfile.BATTERY_SERVICE, RelsibBluetoothProfile.BATTERY_LEVEL, enabled); Log.e(TAG, "call get battery by notify + isnotify " + enabled); } public boolean setCharacteristicNotify(UUID mServiceName, UUID mCharacteristicName, boolean enabled) { Log.e(TAG, "CALL setCharacteristicNotify " + mCharacteristicName.toString() + " " + mDeviceMacAddress); if (BLEService.mBluetoothAdapter == null) { Log.e(TAG, "BluetoothAdapter not initialized"); return false; } /*check if the service is available on the device*/ if (mBluetoothGatt == null) { Log.e(TAG, "GATT FAILED"); return false; } BluetoothGattService mCustomService = mBluetoothGatt.getService(mServiceName); if (mCustomService == null) { Log.e(TAG, "NOTIFY_FAILED " + mDeviceMacAddress); return false; } BluetoothGattCharacteristic characteristic = mCustomService.getCharacteristic(mCharacteristicName); mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); BluetoothGattDescriptor descriptor = characteristic.getDescriptor( RelsibBluetoothProfile.CLIENT_CHARACTERISTIC_CONFIG); if (enabled) { descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); } else { descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); } /*****/ descriptorWriteQueue.add(descriptor); //if there is only 1 item in the queue, then read it. If more than 1, we handle asynchronously in the callback above //GIVE PRECEDENCE to descriptor writes. They must all finish first. if (((descriptorWriteQueue.size() == 1) && characteristicReadQueue.size() == 0)) { mBluetoothGatt.writeDescriptor(descriptor); } //mBluetoothGatt.writeDescriptor(descriptor); return true; } public void readInfoTypes() { readCharacteristic(RelsibBluetoothProfile.GENERIC_ACCESS_SERVICE, RelsibBluetoothProfile.DEVICE_NAME); readCharacteristic(RelsibBluetoothProfile.DEVICE_INFORMATION_SERVICE, RelsibBluetoothProfile.MODEL_NUMBER_UUID); readCharacteristic(RelsibBluetoothProfile.DEVICE_INFORMATION_SERVICE, RelsibBluetoothProfile.SERIAL_NUMBER_UUID); readCharacteristic(RelsibBluetoothProfile.DEVICE_INFORMATION_SERVICE, RelsibBluetoothProfile.MANUFACTURER_NAME_UUID); readCharacteristic(RelsibBluetoothProfile.BATTERY_SERVICE, RelsibBluetoothProfile.BATTERY_LEVEL); } public Long getId() { return _ID; } public void setId(Long _ID) { this._ID = _ID; } public void shutdown() { intermediateTemperature = 1000f; mConnectionState = BLEService.STATE_DISCONNECTED; isNotifyEnabled = false; if (mBluetoothGatt == null) { Log.w(TAG, "BluetoothAdapter not initialized"); return; } /*check if the service is available on the device*/ BluetoothGattService mCustomService = mBluetoothGatt.getService(RelsibBluetoothProfile.RELSIBPROFILE_SERV); if (mCustomService == null) { Log.w(TAG, "Custom BLE Service not found"); return; } BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(RelsibBluetoothProfile.RELSIBPROFILE_SHUTDOWN); mWriteCharacteristic.setValue(RelsibBluetoothProfile.SHUTDOWN_THERMOMETER, android.bluetooth.BluetoothGattCharacteristic.FORMAT_UINT8, 0); if (!mBluetoothGatt.writeCharacteristic(mWriteCharacteristic)) { Log.w(TAG, "Failed to write characteristic"); } }