Subscribe with two Nano 33 BLE Central Device to one Nano 33 BLE Peripheral Device

Makes sense. Every time I've done a project with Nano 33 BLE and thought that
NOW I should use the Bluetooth function on them, I've had to abandon the project with them and go back to a regular Nano with HC-05 or RF24 module.
I just have to say that either the Arduino designer has not provided the correct data about this model, or the Nano 33 BLE is so difficult to use that it is not suitable for hobbyists. My 2 BLEs have never been used, and I've had them for 4 years now, and made over 20 different large projects in that time.

In the same periode I have used over 8 Mega's, 12 Nano's, and 3 bluepills (to run LCD touch color screens)

So I'm very disappointed with these modules, which have promised more than they could keep, but have in no way been used :roll_eyes:

I'm glad all is well, but the root cause of the improved performance could not have been to place if(central.connected()) inside of another conditional which begins with

@cattledog - I know what you mean, but it solves the problem.

Shame on me! Yesterday I tried it at least ten times. I commented out the if-command added it again and only made this change. Each time the same result.
Today I tried the same thing and it works without the if query. Believe me, I am at a loss!

I tried to move the post #10 that I wrote in the wrong topic, but I could only mark it with "It's Off-Topic" and I think, I have set myself a negative point with this action.

I know you dont believe me.
I wouldn't believe it either if I couldn't see it.
I played around with some other code on the IoT.
On the BLE I did nothing.
After that I uploaded the working code from this morning to the IoT.
Believe or believe it not - it did not work anymore.
I uploaded It several times, restarted all devices. No luck.
I enabled the if-statement, uploaded the code - it works.
I disabled the if-statement, uploaded the code - it does no more work.
Once more, enable the if-statment, upload - it works
20 minutes later - upload without if-statement - no luck :hot_face:

One more detail:
I forgot to mention it,
The connection works, but the attributes cannot be found.

What is motivating you to switch from the quite simple solution of reading the manufacturer data? It appeared to be working properly for several days.

My intended solution is now running.
I have started from scratch and wrote new code.
First I had the same problem as before.
I was then able to slowly approach the error.
The main reason was in the readAnemometer() function.
I deactivated the function, without this call, both Nano 33 BLE were able to find the attributes.
When I activated the function again, the attributes could'nt longer found.
The additional command "if(central.connected())" solved the problem.
Result:
Everything works as expected.
The Arduino Nano 33 IoT works as a peripheral device.
The two Nano 33 BLE as central devices. Both can connect and can now also receive the changed values.
I'm happy now.
Below my code.
Thank you very much for your help and support.

Code for peripheral device

#include <Arduino.h>
#include <ArduinoBLE.h>

#define serviceUUID "181A"  // Service         - Environmental Sensing Service  
#define charactUUID "2A70"  // Characteristics - True Wind Speed 

const char* d_service_Name = serviceUUID;          // Service         - Environmental Sensing Service
const char* d_characteristics_Name = charactUUID;  // Characteristics - True Wind Speed

BLEService environmentalService(d_service_Name); // Bluetoothยฎ Low Energy Binary Sensor Service 
BLECharCharacteristic wspch(d_characteristics_Name, BLERead | BLENotify); 
BLEDevice central;

int  oldWindSpeedLevel          = 0;           // last Wind Speed level reading from Anemometer
long previousMillis             = 0;           // last Wind Speed level was checked in before x millis
const int mds                   = 5;           // measure duration in seconds
const float mts                 = 2.5;         // max Anemometer turns per second
const int pinReedSensor         = 8 ;          // REED Sensorport (Anemometer)
const int bleConnectStatusLED   = 7;
int numberOfConnectedCentral    = 0;
//int pauseAfterWindMeasure       = 30 * 1000;   // Pause after wind measurement in millis (sec * 1000= msec)
//unsigned long startMeasurePause = millis();
//unsigned long endMeasurePause   = startMeasurePause + pauseAfterWindMeasure;

//โ•โ•โ•โ•โ• Function declarations โ•โ•โ•โ•โ•
float  readAnemometer();
String iif(bool check, String rString1, String rString2);
int    iif(bool check, int value1, int value2);
void   blePeripheralConnectHandler( BLEDevice central );
void   blePeripheralDisconnectHandler( BLEDevice central );
void   characteristicsUpdated(BLEDevice central, BLECharacteristic changedChar);
String timeSinceStart();

void setup() {
  unsigned long sMillis = millis();               // sMillis = startMillis
  Serial.begin(115200);                           // Start communication with serial interface
  while (!Serial && millis() < (sMillis + 5000)); // When running on battery, serial communication is not possible

  pinMode(bleConnectStatusLED,OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);                   // initialize the built-in LED pin to indicate when a central is connected
  pinMode(pinReedSensor, INPUT_PULLDOWN);

  Serial.println("Peripheral");
  Serial.println("    ____           _       _                    _  ");
  Serial.println("   |  _ \\ ___ _ __(_)_ __ | |__   ___ _ __ __ _| | ");
  Serial.println("   | |_) / _ \\ '__| | '_ \\| '_ \\ / _ \\ '__/ _` | | ");
  Serial.println("   |  __/  __/ |  | | |_) | | | |  __/ | | (_| | | ");
  Serial.println("   |_|   \\___|_|  |_| .__/|_| |_|\\___|_|  \\__,_|_| ");
  Serial.println("                    |_|                            ");

  while (!BLE.begin()) 
  {
    digitalWrite(LED_BUILTIN,HIGH); delay(200);
    digitalWrite(LED_BUILTIN,LOW);  delay(200);
  }

  BLE.setEventHandler( BLEConnected, blePeripheralConnectHandler);
  BLE.setEventHandler( BLEDisconnected, blePeripheralDisconnectHandler);

  BLE.setLocalName("Anemometer");
  BLE.setAdvertisedService(environmentalService);                  // add the service UUID
  environmentalService.addCharacteristic(wspch); // add the windLevel characteristic
  BLE.addService(environmentalService);                            // Add the Enviromental service
  wspch.writeValue(oldWindSpeedLevel);           // set initial value for this characteristic 

  Serial.println("Bluetoothยฎ device active, waiting for connections...");
  BLE.advertise();  // start advertising
}

void loop() 
{
  static int windLevel = 0;
  static int oldWindLevel = 0;
  BLE.advertise();  // start advertising

  central = BLE.central();  // wait for a Bluetoothยฎ Low Energy central
  delay(500);   // important

  if(central.connected()) 
  {
    delay(300);
    long currentMillis = millis();
    // check the wind level evey 5 seconds:
    if (currentMillis - previousMillis >= 5000) {
      previousMillis = currentMillis;
      windLevel = readAnemometer();
      if(oldWindLevel != windLevel)
      {
        wspch.writeValue(windLevel);
        oldWindLevel = windLevel;
      }
    }
  } 
}

float readAnemometer()
{
  int newState    = 0;
  int oldState    = 0;
  int windCounter = 0;
  float windSpeedLevel = 0;  // or HIGH
  unsigned long endTime ;

  endTime = millis() + (mds * 1000);
  digitalWrite(LED_BUILTIN, HIGH); delay(100);
  digitalWrite(LED_BUILTIN, LOW); delay(100);
  digitalWrite(LED_BUILTIN, HIGH); delay(100);
  digitalWrite(LED_BUILTIN, LOW); delay(100);

  if(central.connected())        // <โ•โ•โ•โ•โ•โ• after inserted the if-command, it works โ•โ•โ•โ•
  {
    while (endTime > millis() )  // Query the anemometer mds seconds
    {
      newState = digitalRead(pinReedSensor);
      if(oldState == 0 && newState == 1)  // With each revolution, newState is set to HIGH when the REED sensor is activated.
      { windCounter++; }
      oldState = newState;
    }
    windSpeedLevel = iif(windCounter > (mts * mds),1,0);
    Serial.print(windCounter); Serial.print(") Wind Speed is ");Serial.println(iif(windSpeedLevel == 1,"HIGH","LOW"));
  }
  return windSpeedLevel;
}

String iif(bool check, String rString1, String rString2)
{
  String rValue = rString2;
  if (check)
  {
    rValue = rString1;
  }
  return rValue;
}

int iif(bool check, int value1, int value2)
{
  int rValue = value2;
  if (check)
  {
    rValue = value1;
  }
  return rValue;
}

void blePeripheralConnectHandler( BLEDevice central )
{
  digitalWrite(bleConnectStatusLED,HIGH);

  numberOfConnectedCentral++;
  Serial.print( F ( " Connected to central: " ) );
  Serial.println( central.address() );
}

void blePeripheralDisconnectHandler( BLEDevice central )
{
  // digitalWrite( LED_BUILTIN, LOW );
  numberOfConnectedCentral--;
  if(numberOfConnectedCentral < 1)
  {
    digitalWrite(bleConnectStatusLED,LOW);
  }
  Serial.print( F( " Disconnected from central: " ) );
  Serial.println( central.address() );
}

void characteristicsUpdated(BLEDevice central, BLECharacteristic changedChar)
{
  Serial.print("Characteristic updated. UUID: ");
  Serial.print(changedChar.uuid());
  Serial.print("   value: ");
  byte incoming = 0;
  changedChar.readValue(incoming);
  Serial.println(incoming);
}

String timeSinceStart()
{
  char text[20];
  unsigned int secondsSinceStart = millis()/1000;
  // Serial.println("currentMillis");Serial.println(secondsSinceStart);
  unsigned int seconds = secondsSinceStart % 60;
  unsigned int minutes = (secondsSinceStart - seconds) / 60;
  sprintf(text, "%d:%02d", minutes,seconds);
  return text;
}


Code for central device

#include <Arduino.h>
#include <ArduinoBLE.h>               // Bluetooth-Library laden

#include <Wire.h>
/* The Reason for adding Wire.h was this error message
 * *************************************************** 
 * #include "Wire.h"
 *           ^~~~~~~~
 * compilation terminated.
 * *** [.pio\build\nano33ble\libd80\Arduino_BMI270_BMM150\BMI270.cpp.o] Error 1
 */

#define RGBLedOn  LOW       // this LED's are inverted
#define RGBLedOff HIGH      // this LED's are inverted

// โ•โ•โ•โ•โ• BlueTooth โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
#define serviceName BLESrvUuidBat     // BLE_Service_UUID_Battery
#define charactName BLEChrUuidBatLvl  // BLE_Characteristics_UUDI_BatteryLevel 
#define serviceUUID "181A"            // 181A Service    - Environmental Sensing Service  
#define charactUUID "2A70"            // Characteristics - True Wind Speed 

const char* serviceName = serviceUUID;  // Service         - Environmental Sensing Service
const char* charactName = charactUUID;  // Characteristics - True Wind Speed

BLEDevice         peripheral;
BLECharacteristic wspch;

//โ•โ•โ•โ•โ• Function declarations โ•โ•โ•โ•โ•
void startBLE();
void searchPeripheral();
void searchAttribute();
void hourGlass();

void setup()
{ 
  pinMode(LED_BUILTIN, OUTPUT);
  unsigned long sMillis = millis();   // sMillis = startMillis

  Serial.begin(115200);                             // Start communication with serial interface
  while (!Serial && millis() < (sMillis + 5000)); // When running on battery, serial communication is not possible

  Serial.print("BlueTooth ");
  startBLE();
  searchPeripheral();
  searchAttribute();

  Serial.println("Arduino Nano 33 BLE (Central Device)");
}

void loop() 
{
  // static char oldCommand;
  // byte command;
  static byte oldWindState = 0;
  static byte newWindState = 0;
  static unsigned long isFound = 0;

  if (!peripheral.connected()) 
  {
    Serial.println("NO PERIPHERAL");
    BLE.stopScan();delay(1000);
    startBLE();
    searchPeripheral();
    searchAttribute();
  }

  if (wspch.canRead())
  {
    digitalWrite(LED_GREEN,RGBLedOn);delay(400);digitalWrite(LED_GREEN,RGBLedOff);delay(400);
    if (peripheral)
    {
      isFound = millis();
    }
  } else 
  {
    digitalWrite(LED_RED,RGBLedOn) ;delay(200);digitalWrite(LED_RED,RGBLedOff) ;delay(200);
    digitalWrite(LED_BLUE,RGBLedOn);delay(200);digitalWrite(LED_BLUE,RGBLedOff);delay(200);
  
    if (millis() - isFound >= 60000) //one minute since last isFound
    {
      Serial.println("Timed out finding peripheral--reset central");
      isFound = millis();//reset time out
      BLE.end(); //reset BLE
      delay(100);
      startBLE();
      searchPeripheral();
      searchAttribute();
    }
  }

  if (wspch.valueUpdated()) 
  { 
    wspch.readValue(newWindState);
    if (oldWindState != newWindState) 
    {
      digitalWrite(LED_BUILTIN, HIGH); delay(500);
      digitalWrite(LED_BUILTIN, LOW);
      Serial.print(" Command Updated New Value: ");
      Serial.println(newWindState);
      oldWindState = newWindState;
    }
  }
}

void startBLE()
{
  digitalWrite(LED_BLUE,RGBLedOn);delay(500);
  if (!BLE.begin()) 
  {   // Initialise Bluetooth
    Serial.println("start failed!");
    while (1);
  } else {
    Serial.println("is started");
  }
  digitalWrite(LED_BLUE,RGBLedOff);delay(500);
}

void searchPeripheral()
{
  digitalWrite(LED_RED,RGBLedOn);delay(500);
  do
  {
    hourGlass();
    BLE.scanForUuid(serviceName);
    peripheral = BLE.available();
  } while (!peripheral);

  Serial.println();
  
  if (peripheral) {
    Serial.print("Found . . . . . . . . . . . . . : ["); Serial.print(peripheral.address());               Serial.println("] ");
    Serial.print("Local name: . . . . . . . . . . : '"); Serial.print(peripheral.localName());             Serial.println("' ");
    Serial.print("Advertised service UUID:. . . . : {"); Serial.print(peripheral.advertisedServiceUuid()); Serial.println("}");
    BLE.stopScan();    // stop scanning
  } else {
    Serial.print("โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ Peripheral not found after "); 
  }

  if (peripheral.connect()) {
    Serial.println("+ + + + + + Connected");
  } else {
    Serial.println("โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ Failed to connect! ");
  }
  digitalWrite(LED_RED,RGBLedOff);delay(500);
}
 
void searchAttribute()
{
  digitalWrite(LED_RED,RGBLedOn);
  digitalWrite(LED_GREEN,RGBLedOn);delay(500);
  static bool attributeFound = false;
  attributeFound = peripheral.discoverAttributes();

  if (attributeFound) 
  {
    Serial.println("+ + + + + + Attributes discovered");
    wspch = peripheral.characteristic(charactName);
  } else {
    Serial.println("โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ Attribute discovery failed!");
  }
  Serial.println("Wait 500 mseconds ");
  delay(500);
  if(wspch.subscribe())
  {
    Serial.println("โ• โ• โ• โ• Subscribed โ• โ• โ• โ• ");
  } else 
  {
    Serial.println(" Subscription failed ");
  }
  digitalWrite(LED_RED,RGBLedOff);
  digitalWrite(LED_GREEN,RGBLedOff);delay(500);
}

void hourGlass()
{
  static int n = 0;
  String dispChar[4] = {"/","โ”€","\\","โ”‚"};  // ,"/","โ”€","\\"
  Serial.print(dispChar[n++]);
  delay(50);
  Serial.write(8);  // -backspace
  if(n > 3) n = 0;
}


I'm glad all is well, but the root cause of the improved performance could not have been to place if(central.connected()) inside of another conditional which begins with

if(central.connected()) 
  {
    delay(300);
    long currentMillis = millis();
    // check the wind level evey 5 seconds:
    if (currentMillis - previousMillis >= 5000) {
      previousMillis = currentMillis;
      windLevel = readAnemometer();

Where readAnemometer()

float readAnemometer()
{
  int newState    = 0;
  int oldState    = 0;
  int windCounter = 0;
  float windSpeedLevel = 0;  // or HIGH
  unsigned long endTime ;

  endTime = millis() + (mds * 1000);
  digitalWrite(LED_BUILTIN, HIGH); delay(100);
  digitalWrite(LED_BUILTIN, LOW); delay(100);
  digitalWrite(LED_BUILTIN, HIGH); delay(100);
  digitalWrite(LED_BUILTIN, LOW); delay(100);

  if(central.connected())        // <โ•โ•โ•โ•โ•โ• after inserted the if-command, it works โ•โ•โ•โ•

Good that you got it working!! :+1:

Just a few friendly remarks/observations to share:

I found while playing around with 1 peripheral and 2 centrals that a startAdvertising() was needed after the first central had connected for the 2nd central being able to see the peripheral and connect too. Not a second call to central.connected()

I see you use the callback functions that are called after a BLE event. AFAIK these are thought of to be setup when the poll() function is used. You use it to count the number of connected centrals and if none connected turn off a LED. As far as I know central.Connected() returns False after the last central disconnected. No need to count IMHO.

I would structure the Central code differently, more like in the examples that come with the ArduinoBLE library. Maybe personal taste but I found these examples easier to read and understand. Well yeah, apologies, early in my professional career I programmed in COBOL before moving into other IT roles. That might explain :joy: :rofl:

Cheers,
Huib

By the way @gene54,

could you asked a moderator to move this latest part of the thread to the thread you started. It doesn't belong more there than here.

Thanks,
Huib

Thank you @hfjesmeets.
A command like startAdvertising() results in my code with curled underline.
I was happy, that it works, I know I've a lot to do to optimise the code.

Sorry I didn't realise that this was a different post.
This is my first forum contribution - How can I ask the moderator?

How can I ask the moderator?

There is a little flag icon underneath the post where you can give a message to a forum moderator,

Topic split / merged as requested (I hope! If I made a mess then it wasn't me, honest guv!)

1 Like

Your solution is still the preferred option because it works.

However, it is curiosity that drives me to see if I can still manage to get the originally intended solution to work and if so, then I can compare the power consumption.

Thanks for moving and correcting my mistake.

1 Like

Are there power issues for the centrals, or just the peripheral? I think that power at the peripherall can be reduced by changing the advertising frequency. The default is every 30ms. And that could be reduced to something like 200 ms in your application.

Yes, it is only for the peripheral device. The two BLE are supplied with a power supply.