Nano 33 BLE Crashes in dense environments

Hello Guys,

I am having an issue with my Nano 33 BLE and hoping you can give me some hand with solving it.
The idea is a something like super simple "keyless access" as cars do.
Arduino scans for devices and if it finds a BLE Tag- you got a green light, system is unlocked.

For that I am doing a scan every 3 seconds.
If I find a key- corresponding flag is set

If key was not found during last 3 scans (no one is perfect)- system goes to lock state

Everything works perfectly until I'm going to some big streets with lots of cars and people around
Arduino then crashes and freezes (I can see it on OLED display, so it's not like just no key)

Here's the sources of scanning code:

#include <ArduinoBLE.h>

String keyUUID = "00ff";
String keyAddress[2];
String keyName = "Tile";
double rescanTime = 3.0; // Seconds
int rescanTries = 0;
int rescanLimit = 3;    
bool keyFound = false;    // Key found during current scan session
unsigned long lastScan = 0;
bool scanExpired = false;

bool scanActive = false;
bool rescanRequired = false;
double rescanTimeout = 1;  // Sec, time between scans
unsigned long rescanStopped = 0;

void securitySetup() {
   // begin initialization
  keyAddress[0] = "59:9e:c7:22:45:38";
  keyAddress[1] = "4c:1f:20:37:b5:0d";
  // Lock status LED
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
   
  Serial.begin(9600);
  //while (!Serial);
  
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }

  Serial.println("BLE Central scan");
  BLE.scanForUuid(keyUUID);
  scanActive = true;
  lastScan = millis();
}

void rescanRequest(){
  BLE.stopScan();

  scanActive = false;
  rescanStopped = millis();
  lastScan = millis();
}

void rescan(){
  //Serial.println("Rescan");
  keyFound = false;
  scanExpired = false;
  BLE.scanForUuid(keyUUID);
  //BLE.scanForAddress(keyAddress[0]);
  scanActive = true;
  lastScan = millis();
}

void rescanManager(){
  if(!scanActive){
    if(millis() - rescanStopped >= (rescanTimeout * 1000)){
      rescan();
    }
  }
}

void securityLoop() {
    // put your main code here, to run repeatedly:
    BLEDevice peripheral = BLE.available();
  
    if (peripheral) { // Devices discovered
      if (peripheral.hasAdvertisedServiceUuid()) {
        for (int i = 0; i < peripheral.advertisedServiceUuidCount(); i++) {
          if(peripheral.advertisedServiceUuid(i) == keyUUID && peripheral.localName() == keyName && (peripheral.address() == keyAddress[0] || peripheral.address() == keyAddress[1])){
            //Serial.print("Key found in ");
            //Serial.print(millis() - lastScan);
            //Serial.println("ms");
            if(!unlocked){
              Serial.println("Key found");
            }
            rescanTries = 0;
            unlocked = true;
            keyFound = true;
          }
        }
      }
    }
  
    scanExpired = (millis() - lastScan) > (1000 * rescanTime);
  
    if(scanExpired){  // Time for rescan to check if key is still there
      if(!keyFound){
        rescanTries += 1;
        Serial.print("No key, retry, att. ");
        Serial.println(rescanTries);
        if(rescanTries >= rescanLimit){
          unlocked = false;
          rescanTries = rescanLimit;
          Serial.println("No key, lock");
        }
      }
      rescanRequest();
    }

    rescanManager();
}

I am thinking maybe about some overflowing that occurs for too much peripherals results.
But that is why I am using scanForUUID, just to filter results and only read useful tags.
Has any of you saw something like that?
Would be super cool to solve that issue

Thanks

The problem is most likely in the code you did not post.

Everything that has something to do with Bluetooth is there (except for init, with is not something interesting)
Other stuff is other stuff
Problem is always coming when I go places with lots happening around.
Like city centre.
And never happens in open spaces or at home.
So I am 100% sure it's all about Bluetooth

Please read and follow the directions in the "How to use the forum" post.

Variable declarations have extremely wide ranging consequences, and you have failed to show us ANY of those.

Good luck with your project.

Sorry, original post code was updated
Picture should be complete now

Here are a few things I noted in your code.

Why did you rename setup() and loop()?

The millis() function uses unsigned long. There is no need to introduce a double floating-point type number for the rescanTime and rescanTimeout variables. Just define a constant and use that in your code. Makes the code easier to read, saves RAM and potentially Flash memory by not linking the FP library.

#define SCAN_INTERVALL 3000

if ( (millis() - lastScan) > SCAN_INTERVALL )

or

if ( (millis() - lastScanMillis) > SCAN_INTERVALL ) // better variable name

You can do the same for the keyAddress, rescanLimit.

Global variables you use only in one function can be replaced by static local variables. This will reduce the number of global variables and allows you to copy code easier without searching for all the global variable declarations. e.g.

loop()
{
static int rescanTries = 0; // only initialized first time

rescanTries++; // new value every time trough loop

}

UUIDs should be ether 16-bit when and as defined by the Bluetooth SiG or random 128-bit for your own services and characteristics. So, your UUID should be 128-bit long. You can look up the official 16-bit UUIDs here.

You have the rescan function. You might as well call that in setup instead of having the same code there again.

You did not use delay(). Well done :slight_smile:

The Arduino BLE is not very robust when it comes to BLE. For instance, it does not like disconnects. This is not the case for your app right now, but there might be similar issues with scanning. You should investigate using a watchdog. Have a look around the board specific forum.

Nano Boards (NEW types)

If you have an Arduino Nano 33 IoT. You can use that for some additional experiments. It uses the same API for the ArduinoBLE library, but it does not use mbedOS.

Additionally, BLE has been designed for low power and not reliability. It tries to survive in the 2.4 GHz ISM band, but your application should be designed to work with an unreliable connection.