bleak icon indicating copy to clipboard operation
bleak copied to clipboard

Immediate disconnect after successful connection With esp as server and raspi as client

Open GarmischWg opened this issue 6 months ago • 0 comments

  • bleak version: 0.22.2
  • Python version: 3.8
  • Operating System: Ubuntu 22.04 server
  • BlueZ version (bluetoothctl -v) in case of Linux: 5.53

Description

I am attemtpting to connect my raspberry pi (as a client) to the esp (as a server). As there might be multiple esp/raspi talking to the main esp, i chose the server multi-connect code for the esp for testing.

What happens is that the raspi and esp would immediately disconnect after connecting.

From my understanding, the initial connection is successful, because the onConnect() callback was triggered on the esp side.

The following code runs on my raspi:

import asyncio
from bleak import BleakClient, BleakScanner


# Add your device's address here.
# Can be UUID or MAC address
address = 'EC:DA:3B:67:6E:FD'

async def main():
    device = await BleakScanner.find_device_by_address(address)

    print(f"device found: {device}")

    async with BleakClient(device) as client:
        print(f'Client connection = {client.is_connected}') # prints True or False

if __name__ == "__main__":
    asyncio.run(main())

The following code is running on my esp32s3

/*
    Video: https://www.youtube.com/watch?v=oCMOYS71NIU
    Based on Neil Kolban example for IDF:
   https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
    Ported to Arduino ESP32 by Evandro Copercini
    updated by chegewara

   Create a BLE server that, once we receive a connection, will send periodic
   notifications. The service advertises itself as:
   4fafc201-1fb5-459e-8fcc-c5c9c331914b And has a characteristic of:
   beb5483e-36e1-4688-b7f5-ea07361b26a8

   The design of creating the BLE server is:
   1. Create a BLE Server
   2. Create a BLE Service
   3. Create a BLE Characteristic on the Service
   4. Create a BLE Descriptor on the characteristic
   5. Start the service.
   6. Start advertising.

   A connect hander associated with the server starts a background task that
   performs notification every couple of seconds.
*/
#include <Arduino.h>
#include <BLE2902.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>

BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint32_t value = 0;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

class MyServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) {
    deviceConnected = true;
    BLEDevice::startAdvertising();
  };

  void onDisconnect(BLEServer* pServer) { deviceConnected = false; }
};

void setup() {
  Serial.begin(115200);

  // Create the BLE Device
  BLEDevice::init("ESP32");

  // Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService* pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
      CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ |
                               BLECharacteristic::PROPERTY_WRITE |
                               BLECharacteristic::PROPERTY_NOTIFY |
                               BLECharacteristic::PROPERTY_INDICATE);

  // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
  // Create a BLE Descriptor
  pCharacteristic->addDescriptor(new BLE2902());

  // Start the service
  pService->start();

  // Start advertising
  BLEAdvertising* pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(false);
  pAdvertising->setMinPreferred(
      0x0);  // set value to 0x00 to not advertise this parameter
  BLEDevice::startAdvertising();
  Serial.println("Waiting a client connection to notify...");
}

void loop() {
  // notify changed value
  if (deviceConnected) {
    pCharacteristic->setValue((uint8_t*)&value, 4);
    pCharacteristic->notify();
    value++;
    delay(10);  // bluetooth stack will go into congestion, if too many packets
                // are sent, in 6 hours test i was able to go as low as 3ms
  }
  // disconnecting
  if (!deviceConnected && oldDeviceConnected) {
    delay(500);  // give the bluetooth stack the chance to get things ready
    pServer->startAdvertising();  // restart advertising
    Serial.println("start advertising");
    oldDeviceConnected = deviceConnected;
  }
  // connecting
  if (deviceConnected && !oldDeviceConnected) {
    // do stuff here on connecting
    oldDeviceConnected = deviceConnected;
  }
}

What I Did

  • For the mac address using in the raspi code, i have confirmed that it is indeed correct with nRF android app and bluetoothctl on raspi.

  • Connecting to the esp with my android phone is successful

Logs

ESP Serial output On esp, this is the serial output

Waiting a client connection to notify...
start advertising (When the raspi code is ran)
start advertising

Strangely, the start advertising line was shown for 2 times.

Raspi output

python3 src/bluetooth_sender/testing.py 
device found: EC:DA:3B:67:6E:FD: ESP32
Traceback (most recent call last):
  File "src/bluetooth_sender/testing.py", line 18, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.8/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "src/bluetooth_sender/testing.py", line 14, in main
    async with BleakClient(device) as client:
  File "/usr/local/lib/python3.8/dist-packages/bleak/__init__.py", line 570, in __aenter__
    await self.connect()
  File "/usr/local/lib/python3.8/dist-packages/bleak/__init__.py", line 615, in connect
    return await self._backend.connect(**kwargs)
  File "/usr/local/lib/python3.8/dist-packages/bleak/backends/bluezdbus/client.py", line 273, in connect
    await self.get_services(
  File "/usr/local/lib/python3.8/dist-packages/bleak/backends/bluezdbus/client.py", line 661, in get_services
    self.services = await manager.get_services(
  File "/usr/local/lib/python3.8/dist-packages/bleak/backends/bluezdbus/manager.py", line 666, in get_services
    await self._wait_for_services_discovery(device_path)
  File "/usr/local/lib/python3.8/dist-packages/bleak/backends/bluezdbus/manager.py", line 799, in _wait_for_services_discovery
    raise BleakError("failed to discover services, device disconnected")
bleak.exc.BleakError: failed to discover services, device disconnected

GarmischWg avatar Aug 06 '24 15:08 GarmischWg