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.
Post number 16. Clearly knows how to post code using code tags but ... no code to be found anywhere. 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.
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.
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()
/*
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;
}
}
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.