Unreliable peripheral discovery

Hi all,

Full disclosure--I'm brand new to networking. I'm doing my best to fumble through the code, but after nearly 10 hours of troubleshooting, I can't figure out how to solve my issue.

The overview of my project is that I will have 20 centrals, and one peripheral. The peripheral will have one read | write String characteristic. The String characteristic will be updated 3 times per second. The centrals will read the characteristic 1 to 2 times per second, and will occasionally write to the characteristic.

Based on my understanding of how peripherals and centrals work, only one central can be connected at any given time. Therefore, my centrals need to connect, read the characteristic, and then immediately disconnect to allow the other centrals to connect.

I want the central to do the following:
step 1) discover the peripheral,
step 2) write a new number to the peripheral's characteristics,
step 3) disconnect, and
step 4) do steps 1-3 all over again infinitely.

Instead if at any point the central has failed to connect to the peripheral (when the serial monitor reports "Connecting ..." then, "Failed to connect!"), it will never be able to discover the peripheral again: (the serial monitor will report "No peripheral discovered" infinitely).

Please see below for my code and for the central's serial output.

Here's my peripheral code:

// Taken from this post: https://forum.arduino.cc/index.php?topic=672382.0

/*
  String Characteristic 
 
  This example creates a BLE peripheral with a service that contains String
  characteristics that can be read and written.
  The length of the String characteristic needs to be fixed.

  The circuit:
  - Arduino Nano 33 BLE Sense board.

  You can use a generic BLE central app, like LightBlue (iOS and Android) or
  nRF Connect (Android), to interact with the services and characteristics
  created in this sketch.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

//----------------------------------------------------------------------------------------------------------------------
// BLE UUIDs
//----------------------------------------------------------------------------------------------------------------------

#define BLE_UUID_TEST_SERVICE               "9A48ECBA-2E92-082F-C079-9E75AAE428B1"
#define BLE_UUID_FILE_NAME                  "2D2F88C4-F244-5A80-21F1-EE0224E80658"

//----------------------------------------------------------------------------------------------------------------------
// BLE
//----------------------------------------------------------------------------------------------------------------------

BLEService testService( BLE_UUID_TEST_SERVICE );
BLEStringCharacteristic botPosCharacteristic( BLE_UUID_FILE_NAME, BLERead | BLEWrite, 20 );

String botPos = "0123456789ABCDEF";


void setup() {
  Serial.begin( 9600 );
  //while ( !Serial );

  BLE.begin();
 
  // set advertised local name and service UUID:
  BLE.setDeviceName( "Arduino Nano 33 BLE Peripheral" );
  BLE.setLocalName( "String Characteristic Board" );
  BLE.setAdvertisedService( testService );

  testService.addCharacteristic( botPosCharacteristic );  // BLE add characteristics
  BLE.addService( testService );  // add service
  botPosCharacteristic.writeValue( botPos );  // set the initial value for the characeristic:
  BLE.advertise();  // start advertising
}

void loop() {
  // listen for BLE peripherals to connect:
  BLEDevice central = BLE.central();

  if ( central )
  {
    Serial.print( "Connected to central: " );
    Serial.println( central.address() );

    while ( central.connected() )
    {
      if ( botPosCharacteristic.written() )
      {
        botPos = botPosCharacteristic.value();
        Serial.print( "New file name: " );
        Serial.println( botPos );
      }
    }

    Serial.print( F( "Disconnected from central: " ) );
    Serial.println( central.address() );
  }
}

And here's my central code:

/*
  String Characteristic

  This example scans for BLE peripherals until one with the advertised service
  "19b10000-e8f2-537e-4f6c-d104768a1214" UUID is found. Once discovered and connected,
  it will remotely control the BLE Peripheral's LED, when the button is pressed or released.

  The circuit:
  - Arduino Nano 33 BLE Sense board.

  You can use it with another board that is compatible with this library and the
  Peripherals.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

int count = 2;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  BLE.begin();  // initialize the BLE hardware
  Serial.println("BLE Central - Read String");
  BLE.scanForUuid("9A48ECBA-2E92-082F-C079-9E75AAE428B1"); // start scanning for peripherals
}

void loop() {
  BLEDevice peripheral = BLE.available(); // check if a peripheral has been discovered
  delay(400);

  if (peripheral) { // discovered a peripheral, print out address, local name, and advertised service
    Serial.print("Found ");
    Serial.print(peripheral.address());
    Serial.print(" '");
    Serial.print(peripheral.localName());
    Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid());
    Serial.println();
    if (peripheral.localName() != "String Characteristic Board") {
      return;
    }
    BLE.stopScan(); // stop scanning
    readPeriphString(peripheral);
    BLE.scanForUuid("9A48ECBA-2E92-082F-C079-9E75AAE428B1"); // start scanning for peripherals
  } else { // No peripheral discovered
    Serial.println("No peripheral discovered");
  }
}

void readPeriphString(BLEDevice peripheral) {
  Serial.println("Connecting ..."); // connect to the peripheral
  if (peripheral.connect()) {
    Serial.println("Connected");
  } else {
    Serial.println("Failed to connect!");
    peripheral.disconnect();
    return;
  }
  // discover peripheral attributes
  Serial.println("Discovering attributes ...");
  if (peripheral.discoverAttributes()) {
    Serial.println("Attributes discovered");
  } else {
    Serial.println("Attribute discovery failed!");
    peripheral.disconnect();
    return;
  }

  BLECharacteristic botPosCharacteristic = peripheral.characteristic("2D2F88C4-F244-5A80-21F1-EE0224E80658");   // retrieve the Robot Position characteristic

  if (!botPosCharacteristic) {
    Serial.println("Peripheral does not have Robot Position Characteristic!");
    peripheral.disconnect();
    return;
  } else if (!botPosCharacteristic.canWrite()) {
    Serial.println("Peripheral does not have a writable Robot Position Characteristic!");
    peripheral.disconnect();
    return;
  }

  while (peripheral.connected()) { // while the peripheral is connected
    Serial.println("Writing to peripheral");
    if (count == 2) {
      botPosCharacteristic.writeValue((byte)0x02);
      count = 4;
    }
    if (count == 4) {
      botPosCharacteristic.writeValue((byte)0x04);
      count = 6;
    }
    if (count == 6) {
      botPosCharacteristic.writeValue((byte)0x04);
      count = 2;
    }
    peripheral.disconnect();
    return;
  }
  Serial.println("Peripheral disconnected");
}

Here's an example readout:

16:01:30.896 -> BLE Central - Read String
16:01:31.320 -> No peripheral discovered
16:01:31.735 -> No peripheral discovered
16:01:32.135 -> Found e6:fa:d5:93:80:81 'String Characteristic Board' 9a48ecba-2e92-082f-c079-9e75aae428b1
16:01:32.135 -> Connecting ...
16:01:32.317 -> Connected
16:01:32.317 -> Discovering attributes ...
16:01:32.788 -> Attributes discovered
16:01:32.788 -> Writing to peripheral
16:01:33.364 -> No peripheral discovered
16:01:33.751 -> Found e6:fa:d5:93:80:81 'String Characteristic Board' 9a48ecba-2e92-082f-c079-9e75aae428b1
16:01:33.789 -> Connecting ...
16:01:34.002 -> Connected
16:01:34.002 -> Discovering attributes ...
16:01:34.472 -> Attributes discovered
16:01:34.472 -> Writing to peripheral
16:01:35.040 -> No peripheral discovered
16:01:35.464 -> Found e6:fa:d5:93:80:81 'String Characteristic Board' 9a48ecba-2e92-082f-c079-9e75aae428b1
16:01:36.477 -> Connecting ...
16:01:37.461 -> Failed to connect!
16:01:39.876 -> No peripheral discovered
16:01:40.263 -> No peripheral discovered
16:01:40.680 -> No peripheral discovered
16:01:41.071 -> No peripheral discovered
16:01:41.456 -> No peripheral discovered
16:01:41.872 -> No peripheral discovered
16:01:42.257 -> No peripheral discovered

Thanks for any insights :slight_smile:

This actually makes me wonder:

Am I maybe using the wrong technology? Should I be using the Nano 33 IoT with WiFi instead?

It's critical that all 20 centrals can reliably ALWAYS read the peripheral's characteristic at least once a second for... at least an hour long period (ideally as long as 8 hours).

SheCurvesMobius:
It's critical that all 20 centrals can reliably ALWAYS read the peripheral's characteristic at least once a second for... at least an hour long period (ideally as long as 8 hours).

You are using a wireless technology. critical and ALWAYS are two words that you should not require. You should design your application in a way that it can work with disconnects and wireless interruption. Especially with WiFi and Bluetooth which both use a worldwide free ISM band.

Additionally the Arduino Nano 33 BLE at the moment has some issues that might affect your application. The Arduino Nano 33 IoT seems to work better even using the same BLE library.

If you have the power available to use WiFi, I suspect you would have less trouble getting the connections to work. Even if you need the peripheral to use BLE because of power restrictions its probably easier to connect one central and then distribute the data via WiFi.

If you use a protocol like MQTT (a publish/subscribe protocol based on TCP/IP using a central node called a broker) you could create a very scalable solution in no time.

1 Like

Hi Klaus_K,

Thanks so much for your response!

It's extremely good to know that BLE is not going to be as reliable as WiFi. I've also never heard of MQTT, so thank you for introducing me to that. I've begun research on it, am going to pivot to using WiFi with MQTT.

I will just affirm two points from k_klaus: there does indeed seem to be an issue with the Nano 33 BLE in terms of maintaining connection to other Nano 33 BLEs. I believe k_klaus's comment on this is based on a back/forth exchange we've been having in a separate post thread where I discussed having a hard time getting the 33 BLE to operate as a peripheral while staying connected to another 33 BLE acting as a central.

Also, I can attest to the simplicity and power of MQTT - within a matter of no time last week, I implemented a small network of three Nano 33 BLE peripherals that connect to a Raspberry Pi Central where the Central acts as a BLE receiver and an MQTT broker which sends MQTT messages to another Raspberry Pi via WiFi. Super easy and stable in terms of the BLE and MQTT connections.