Arduino Nano 33 BLE Sense as peripheral and Arduino MKR Wifi1010 as central

What a nightmare!

Very simple use case. Arduino 33 BLE Sense outside on the balcony measuring temperature and making it available as BLE peripheral. Arduino MKR Wifi 1010 in the livingroom reading as BLE Central temperature caracheristic and uploading data via Wifi on Thingspeak web site.

I've used all the examples and codeline provided by the community and at the end I'managed to succeed. But.

But the only way to make Nano 33 BLE Sense not get stucked after 4 reading cycles is to implement a watchdog. That means to force the **system **to stop and restart every 6 seconds (in my example the convenient time frame has bees defined together with inovation services

Again it works but is crazy from the code design stand point!!

Any idea how to make MKR wifi1010 a really working BLE Central? Honestly I'm pretty sick and tired reading high level "far from the point" answers to similar questions, on BLE Central deployed on Arduino MKR 1010 and NOT on Raspberry or my mobile phone.

After couple of weeks running in circle I started thinking Arduino 33 BLE sense is the wrong board from my case, but then I'm wondering in which cases it is worth to.

Thank you

Andrea

What a nightmare!

Post number 16. Clearly knows how to post code using code tags but ... no code to be found anywhere. :slight_smile: Just kidding.

Could you please post your code (for both devices), so I can have a look?

I suspect you are using the Nano 33 BLE on-board sensors. If not please provide a link to the datasheet and let me know which exact library you are using e.g. a GitHub link.

Hi Klaus_K,

I didn’t post the code since I think that there isn’t so much to do with it.

I built it starting from your past contribution (thanks for that, by the way :)) and the work of other contributors to this community.

Anyway I’ll try to post it even though it’ really full of comments in Italian (sorry for that) and “serial.print” statements for debugging purposes. That means should you consider it’s too difficult to understand it I will see your point:)

As i said, it works. But as soon as you get rid of the watchdog, it starts behaving as I’ve already described: after 4/5 iteractions the BLE Peripheral doesn’t recognize BLE Central has been disconnected, so the BLE peripheral stays connected, the famous yellow pin is steadly ON and BLE Central can’t connect again to run an additional reading to BLE Peripheral caracteristics.

I’ll provide the code in following messages, since for the previous message was too long.

Thanks

Andrea

BLE central code here below. It functions will be provided separately. For obvious reasons I won’t provide secrets.h

/*
  This example creates a BLE central that scans for a peripheral with a
  Environmental Sensing Service (ESS). If that contains temperature and humidity
  characteristics the values are displayed.

  The circuit:
  - Arduino Nano 33 BLE or Arduino Nano 33 IoT board.

  This example code is in the public domain.
  Original provided by Klaus_K here
  https://forum.arduino.cc/index.php?topic=699488.0
*/
// file name BLESenseComboSensorCentral07
// versione 07 con tab per le funzioni
// la versione 06 ridotte le rilevazioni nell'array a 3 per velocizzare debug
// la versione 06 aggiunte righe USBDevice.detach();//aggiunto dopo ricerca
// https://github.com/arduino-libraries/ArduinoLowPower/issues/7
// e USBDevice.attach(); adesso se si spegne il serial monitor e lo si fa
// ripartire riesce a tornare in visualizzazione
// non riesce a farlo autonomamente
// la versione 04 contiene anche il collegamento a Wifi e a ThingSpeak preso da
// ** WiFiWriteThingSpeakTempDS18B20** versione con letture salvate in array e
// calcolo della media funziona in abbinata con ComboSensorNOSERIAL lato
// peripheral senza problemi aspetto più complesso da capire la funzione bool e
// sopratutto che cosa se ne fa dei ritorni aggiunte righe di debug
// la chiave è stata resettare e far ripartire quando non trova il peripheral
// con:
/*
    BLE.end();//aggiunto per resettare
    delay(1000);// unsecondo di pausa per prendere il fiato
    BLE.begin();//aggiunto per riprendere

    BLE.scanForUuid( BLE_UUID_ENVIRONMENTAL_SENSING_SERVICE );
*/
/*invece per switch tra ble e wifi è stato necessario
   #include "utility/wifi_drv.h" //non chiaro da dove viene ma serve e funziona
   e poi nel momento dello spegnimento del ble anche il reset del driver fatto
  con
   // This is currently necessary to switch from BLE to WiFi
      wiFiDrv.wifiDriverDeinit();//righetta che fa la differenza
      Serial.println("Wifi driver de init");
      wiFiDrv.wifiDriverInit();// righetta che fa la differenza
      Serial.println("Wifi driver init");
      delay(5000);
      Serial.println("fine pausetta");
  a
*/
// ahime al momento non si riesce a far ripartire il serial monitor

//*****************wifi e ThingSpeak****************************
#include "ThingSpeak.h"
#include "secrets.h"
#include <WiFiNINA.h>
#include "utility/wifi_drv.h" //non chiaro da dove viene ma serve e funziona
#include <ArduinoLowPower.h>


char ssid[] = SECRET_SSID; //  your network SSID (name)
char pass[] = SECRET_PASS; // your network password
int keyIndex = 0; // your network key Index number (needed only for WEP)
WiFiClient client;

unsigned long myChannelNumber = SECRET_CH_ID;
const char *myWriteAPIKey = SECRET_WRITE_APIKEY;

#include <ArduinoBLE.h>

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

// https://www.bluetooth.com/specifications/assigned-numbers/environmental-sensing-service-characteristics/

#define BLE_UUID_ENVIRONMENTAL_SENSING_SERVICE "181A"
#define BLE_UUID_TEMPERATURE "2A6E"
#define BLE_UUID_HUMIDITY "2A6F"

static long previousMillis = 0;
long interval = 5000; // 5 sec interval between readinds
float tempArray[3]; // in C l'array può contenere diversi tipi di variabili ma
                    // bisogna definire in anticipo quanti elementi contiene
float humArray[3];
int numRilevazioni = 0; // numero di rilevazioni prima di calcolare la media
float mediaCalcolata = 0;
float mediaTemp = 0;
float mediaCalcolataHum = 0;
float mediaHum = 0;

void setup() {
  Serial.begin(9600);
  // while ( !Serial );
  //*****************wifi e ThingSpeak****************************
  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true)
      ;
  }
  Serial.print("WifiStatus= ");
  Serial.println(WiFi.status());
  String fv = WiFi.firmwareVersion();
  if (fv != "1.0.0") {
    Serial.println("Please upgrade the firmware");
  }
  ThingSpeak.begin(client); // Initialize ThingSpeak

  //*****************BLE****************************
  BLE.begin();
  BLE.scanForUuid(BLE_UUID_ENVIRONMENTAL_SENSING_SERVICE);
}

void loop() {
  unsigned long currentMillis = millis();
  unsigned long delta = (currentMillis - previousMillis); // debug andrea

  if (currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;

    BLEDevice peripheral = BLE.available();
    Serial.print("Delta: ");                // debug andrea
    Serial.println(delta);                  // debug andrea
    Serial.print("peripheral: ");           // debug andrea
    Serial.println(peripheral);             // debug andrea
    Serial.print("peripheral name: ");      // debug andrea
    Serial.println(peripheral.localName()); // debug andrea
    if (peripheral) {
      if (peripheral.localName() !=
          "ArduinoNano33BLESense") // modified and entered same name as in
                                   // BLESenseComboSensor
      {
        previousMillis =
            0; //***modifica di logica APAG se non trova quello giusto fai finta
               //che devi ricercare subito senza aspettare
        Serial.println("*****resettato contatore****"); // debug andrea
        return;
      }
      BLE.stopScan();

      explorePeripheral(peripheral);

      BLE.end();   // aggiunto per resettare
      delay(1000); // unsecondo di pausa per prendere il fiato
      BLE.begin(); // aggiunto per riprendere
      BLE.scanForUuid(BLE_UUID_ENVIRONMENTAL_SENSING_SERVICE);
    }
    Serial.println("****non trovo il peripheral***"); // debug andrea
    BLE.end();                                        // aggiunto per resettare
    delay(1000); // unsecondo di pausa per prendere il fiato
    BLE.begin(); // aggiunto per riprendere
    BLE.scanForUuid(BLE_UUID_ENVIRONMENTAL_SENSING_SERVICE);
  }
}

And now here below all functions belonging to the previous BLE Central

float calcolaMedia() {
  for (int i = 0; i <= 2; i++) {
    mediaCalcolata = mediaCalcolata + tempArray[i];
  }//end of for
  float temperaturaFinale = mediaCalcolata / 3; //3 per il numero degli addendi e 100 per divisione
  mediaCalcolata = 0; //resetta il valore prima di uscire
  return temperaturaFinale;
}//end of calcolaMedia()
float calcolaMediaHum() {
  for (int i = 0; i <= 2; i++) {
    mediaCalcolataHum = mediaCalcolataHum + humArray[i];
  }//end of for
  float humidityFinale = mediaCalcolataHum / 3; //3 per il numero degli addendi e 100 per divisione
  mediaCalcolata = 0; //resetta il valore prima di uscire
  return humidityFinale;
}//end of calcolaMediaHum()
void collegaWiFi() {
  Serial.println("***Sono arrivato in collega Wifi");
  //*****************wifi****************************
  // Connect or reconnect to WiFi
  BLE.disconnect();
  Serial.println("BLE disconnect");
  BLE.end();
  Serial.println("BLE end");
  // Re-initialize the WiFi driver
  // This is currently necessary to switch from BLE to WiFi
  wiFiDrv.wifiDriverDeinit();//righetta che fa la differenza
  Serial.println("Wifi driver de init");
  wiFiDrv.wifiDriverInit();// righetta che fa la differenza
  Serial.println("Wifi driver init");
  delay(5000);
  Serial.println("fine pausetta");
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(SECRET_SSID);
    while (WiFi.status() != WL_CONNECTED) {
      WiFi.begin(ssid, pass); // Connect to WPA/WPA2 network. Change this line if using open or WEP network
      Serial.print(".");
      delay(5000);
    }
    Serial.println("\nConnected.");
  }
  //*******************
}//end of collegaWifi()
bool explorePeripheral( BLEDevice peripheral )
{
  Serial.println( "****entro nella routine***" );//debug andrea
  if ( !peripheral.connect() )
  {
    Serial.println( "****il peripheral non è connesso***" );//debug andrea
    return false;
  }

  if ( !peripheral.discoverAttributes() )
  {
    Serial.println( "****non trovo gli attributi***" );//debug andrea
    peripheral.disconnect();
    return false;
  }

  BLECharacteristic temperatureCharacterisic = peripheral.characteristic( BLE_UUID_TEMPERATURE );
  Serial.print("---> temperatureCharacteristic= ");//debug andrea
  Serial.println(temperatureCharacterisic);//debug andrea
  if ( temperatureCharacterisic )
  {
    int16_t temperature;
    temperatureCharacterisic.readValue( temperature );
    tempArray[numRilevazioni] = (temperature / 100.0);
    numRilevazioni = numRilevazioni + 1;
    Serial.print( "Temperature: " );
    Serial.print( temperature / 100.0 );
    Serial.println( "°C" );
    for (int i = 0; i <= 2; i++) {
      Serial.print( "rilevazione " );
      Serial.print(i);
      Serial.print("= ");
      Serial.println(tempArray[i]);
    }// end of for di stampa
  }//end of if

  BLECharacteristic humidityCharacterisic = peripheral.characteristic( BLE_UUID_HUMIDITY );
  Serial.print("---> humidityCharacterisic= ");//debug andrea
  Serial.println(humidityCharacterisic);//debug andrea
  if ( humidityCharacterisic )
  {
    uint16_t humidity;
    numRilevazioni = numRilevazioni - 1 ;
    humidityCharacterisic.readValue( humidity );
    humArray[numRilevazioni] = (humidity / 100);
    numRilevazioni = numRilevazioni + 1 ;
    Serial.print( "Humidity: " );
    Serial.print( humidity / 100.0 );
    Serial.println( "%" );
    for (int i = 0; i <= 2; i++) {
      Serial.print( "rilevazione hum " );
      Serial.print(i);
      Serial.print("= ");
      Serial.println(humArray[i]);
    }// end of for di stampa
  }
  if (numRilevazioni == 3) {
    mediaTemp = calcolaMedia(); //vai al calcolo della media
    mediaHum = calcolaMediaHum();
    Serial.print( "********* ecco la media di 3 rilevazioni= " );
    Serial.println(mediaTemp);
    collegaWiFi();
    scriviThingspeak();
    resettaVettore();
    //*********wifi disconnessione e ritardo prima di ripartire************************
    WiFi.disconnect();
    WiFi.end();
    USBDevice.detach();//aggiunto dopo ricerca https://github.com/arduino-libraries/ArduinoLowPower/issues/7
    // LowPower.sleep(60000); //aggiunto per tenere spento 1 minuto 60.000 millisecondi
    LowPower.sleep(1800000); //aggiunto per tenere spento 30 minuti 1.800.000 millisecondi
    USBDevice.attach();//aggiunto dopo ricerca
    Serial.begin( 9600 );//fa ripartire il monitor dopo la nanna
    BLE.begin();//aggiunto per ripendere anche se viene resettato appena esce dall funzione e ritorna nel loop
  }//end of if di numRilevazioni
  peripheral.disconnect();
  Serial.println( "****arrivato in fondo***" );//debug andrea
  return true;
}
void resettaVettore() {
  for (int i = 0; i <= 2; i++) {
    tempArray[i] = 0;
    humArray[i] = 0;
  }//end of for
  numRilevazioni = 0;

}//end of resettaVettore
void scriviThingspeak() {
  //*****************ThingSpeak*multiple fields Temperature*and*Light************
  // set the fields with the values
  ThingSpeak.setField(5, mediaTemp);
  ThingSpeak.setField(6, mediaHum);
  // ThingSpeak.setField(3, t);
  // ThingSpeak.setField(4, h);

  int x = ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
  if (x == 200) {
    Serial.println("Channel update successful.");
  }
  else {
    Serial.println("Problem updating channel. HTTP error code " + String(x));
  }
}//end of scriviThigspeak()

And eventually the code for BLE Peripheral

/*
  Description: Transmits Arduino Nano 33 BLE Sense sensor readings over BLE,
               including temperature, humidity, barometric pressure, and color,
               using the Bluetooth Generic Attribute Profile (GATT) Specification
  Author: Gary Stafford
  Reference: Source code adapted from `Nano 33 BLE Sense Getting Started`
  Adapted from Arduino BatteryMonitor example by Peter Milne
*/
// filename: BLESensorPeripheral03
// attempt with watchdog got from https://github.com/arduino-libraries/ArduinoBLE/issues/45
// caricata su BLE per fare da peripheral con BLESenseComboSensorCentral06 caricato su MKR wifi 1010 funziona senza problemi
// febbraio 2020
/*
  Generic Attribute Profile (GATT) Specifications
  GATT Service: Environmental Sensing Service (ESS) Characteristics
  Temperature
  sint16 (decimalexponent -2)
  Unit is in degrees Celsius with a resolution of 0.01 degrees Celsius
  https://www.bluetooth.com/xml-viewer/?src=https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Characteristics/org.bluetooth.characteristic.temperature.xml
  Humidity
  uint16 (decimalexponent -2)
  Unit is in percent with a resolution of 0.01 percent
  https://www.bluetooth.com/xml-viewer/?src=https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Characteristics/org.bluetooth.characteristic.humidity.xml
  Barometric Pressure
  uint32 (decimalexponent -1)
  Unit is in pascals with a resolution of 0.1 Pa
  https://www.bluetooth.com/xml-viewer/?src=https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Characteristics/org.bluetooth.characteristic.pressure.xml
*/

#include <ArduinoBLE.h>
#include <Arduino_HTS221.h>
#include <Arduino_LPS22HB.h>
#include <Arduino_APDS9960.h>

const int UPDATE_FREQUENCY = 3000;     // Update frequency in ms
const float CALIBRATION_FACTOR = -4.0; // Temperature calibration factor (Celsius)

int previousTemperature = 0;
unsigned int previousHumidity = 0;
unsigned int previousPressure = 0;
long previousMillis = 0; // last time readings were checked, in ms
long timeConnectedCounter = 0;


BLEService environmentService("181A"); // Standard Environmental Sensing service

BLEIntCharacteristic tempCharacteristic("2A6E",               // Standard 16-bit Temperature characteristic
                                        BLERead | BLENotify); // Remote clients can read and get updates

BLEUnsignedIntCharacteristic humidCharacteristic("2A6F", // Unsigned 16-bit Humidity characteristic
    BLERead | BLENotify);

BLEUnsignedIntCharacteristic pressureCharacteristic("2A6D",               // Unsigned 32-bit Pressure characteristic
    BLERead | BLENotify); // Remote clients can read and get updates

void setup() {
  //Configure WDT. Let's give a try to the watchdog
  NRF_WDT->CONFIG         = 0x01;             // Configure WDT to run when CPU is asleep
  NRF_WDT->CRV            = 6 * 32768;        // Set timeout for 6 seconds
  NRF_WDT->RREN           = 0x01;             // Enable the RR[0] reload register
  NRF_WDT->TASKS_START    = 1;                // Start WDT


  Serial.begin(9600); // Initialize serial communication COMMENTED SINCE LAPTOP CAN BE NOT USED
  //while (!Serial); // only when connected to laptop

  if (!HTS.begin()) { // Initialize HTS221 sensor
    //    Serial.println("Failed to initialize humidity temperature sensor!");
    while (1);
  }

  if (!BARO.begin()) { // Initialize LPS22HB sensor
    //Serial.println("Failed to initialize pressure sensor!");
    while (1);
  }

  // Avoid bad readings to start bug
  // https://forum.arduino.cc/index.php?topic=660360.0
  BARO.readPressure();
  delay(1000);

  pinMode(LED_BUILTIN, OUTPUT); // Initialize the built-in LED pin

  if (!BLE.begin()) { // Initialize NINA B306 BLE
    // Serial.println("starting BLE failed!");
    while (1);
  }

  BLE.setLocalName("ArduinoNano33BLESense");    // Set name for connection
  BLE.setAdvertisedService(environmentService); // Advertise environment service

  environmentService.addCharacteristic(tempCharacteristic);     // Add temperature characteristic
  environmentService.addCharacteristic(humidCharacteristic);    // Add humidity characteristic
  environmentService.addCharacteristic(pressureCharacteristic); // Add pressure characteristic
  BLE.addService(environmentService); // Add environment service

  tempCharacteristic.setValue(0);     // Set initial temperature value
  humidCharacteristic.setValue(0);    // Set initial humidity value
  pressureCharacteristic.setValue(0); // Set initial pressure value

  BLE.advertise(); // Start advertising
  Serial.print("Peripheral device MAC: ");
  Serial.println(BLE.address());
  Serial.println("Waiting for connections...");
}

void loop() {
  BLEDevice central = BLE.central(); // Wait for a BLE central to connect

  // If central is connected to peripheral
  if (central) {
    Serial.print("Connected to central MAC: ");
    Serial.println(central.address()); // Central's BT address:

    digitalWrite(LED_BUILTIN, HIGH); // Turn on the LED to indicate the connection

    if (central.connected()) {//finchè central è connesso aggiorna le letture ogni minuto
      long currentMillis = millis();
      // After UPDATE_FREQUENCY ms have passed, check temperature & humidity
      if (currentMillis - previousMillis >= UPDATE_FREQUENCY) {
        previousMillis = currentMillis;
        updateReadings();
      }
    }
    digitalWrite(LED_BUILTIN, LOW); // When the central disconnects, turn off the LED
    Serial.print("Disconnected from central MAC: ");
    Serial.println(central.address());
  }
  if (!central) {
    //resetta il watchdog e ferma i 6 secondi
    NRF_WDT->RR[0] = WDT_RR_RR_Reload;
    Serial.println("**Watchdogreset**");
  }

}

int getTemperature(float calibration) {
  // Get calibrated temperature as signed 16-bit int for BLE characteristic
  return (int) (HTS.readTemperature() * 100) + (int) (calibration * 100);
}

unsigned int getHumidity() {
  // Get humidity as unsigned 16-bit int for BLE characteristic
  return (unsigned int) (HTS.readHumidity() * 100);
}

unsigned int getPressure() {
  // Get humidity as unsigned 32-bit int for BLE characteristic
  return (unsigned int) (BARO.readPressure() * 1000 * 10);
}

void updateReadings() {
  int temperature = getTemperature(CALIBRATION_FACTOR);
  unsigned int humidity = getHumidity();
  unsigned int pressure = getPressure();

  if (temperature != previousTemperature) { // If reading has changed
    Serial.print("Temperature: ");
    Serial.println(temperature);
    Serial.print("Peripheral Arduino  device MAC: "); //added to get mac address can be erased
    Serial.println(BLE.address());//added to get mac address can be erased
    tempCharacteristic.writeValue(temperature); // Update characteristic
    previousTemperature = temperature;          // Save value
  }

  if (humidity != previousHumidity) { // If reading has changed
    Serial.print("Humidity: ");
    Serial.println(humidity);
    humidCharacteristic.writeValue(humidity);
    previousHumidity = humidity;
  }

  if (pressure != previousPressure) { // If reading has changed
    Serial.print("Pressure: ");
    Serial.println(pressure);
    pressureCharacteristic.writeValue(pressure);
    previousPressure = pressure;
  }
}

Some references I found and studied but unfortunately not fixing the point:

In the end the request is very simple: how is it possible to make MKR Wifi1010 act properly as BLE Central? Properly means that BLE Peripheral always understand when BLE Central is disconnected and then the BLE peripheral DON'T keep ON the yelllow light, preventing BLE Central to connect again to BLE peripheral.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.