Global Variable "angle" not incrementing properly depending on where it is declared outside loop() and setup()

I have an integer variable I declared before loop() and setup() and tried to increment it inside loop.

edit: If I use the given code here, two ble devices connect. Angle prints out as 5 every 6 seconds, instead of incrementing by +=5.
If I move the angle declaration up one line, then it works.

Why is this happening?

ble_server_dht

/*
    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
    Ported to Arduino ESP32 by Evandro Copercini
    updates by chegewara
*/
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>
#include <ESP32Servo.h>

#define bleServerName "DHT22_ESP32"

#include <DHT.h>
#define DHTPIN 21 // Defines pin number to which the sensor is connected
#define DHTVCC 4 // Defines pin number to which the sensor VCC is connected
DHT dht(DHTPIN, DHT22);
long myTime;
// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 6000;
bool deviceConnected = false;
Servo myServo;  // create a servo object
int servoPin = 12;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "5106ba9c-a085-4bea-b210-0272d8cd40dd"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
BLECharacteristic tempCharacteristic("cba1d466-344c-4be3-ab3f-189f80dd7518", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor tempCharacteristicDescriptor(BLEUUID((uint16_t)0x2902));
BLECharacteristic humidityCharacteristic("ca73b3ba-39f6-4ab3-91ae-186dc9577d99", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor humidityCharacteristicDescriptor(BLEUUID((uint16_t)0x2903));
int angle = 0;

//Setup callbacks onConnect and onDisconnect
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };
    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};


void setup() {
  pinMode (DHTVCC, OUTPUT); //VCC for DHT22
  Serial.begin(115200);
  Serial.println(F("DHTxx test!"));
  digitalWrite(DHTVCC, HIGH);
  dht.begin();
  delay(1000);
  
  // Allow allocation of all timers
  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  myServo.setPeriodHertz(50);    // standard 50 hz servo
  myServo.attach(servoPin, 1000, 2000); // attaches the servo on pin 18 to the servo obje
  //myServo.attach(servoPin, 500, 2400); // attaches the servo on pin 18 to the servo obje

  BLEDevice::init(bleServerName);
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks()); //new

  BLEService *pService = pServer->createService(SERVICE_UUID);
  /*
    BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE
                                       );

    pCharacteristic->setValue("Hello World says Neil");
  */
  pService->addCharacteristic(&tempCharacteristic);//new
  tempCharacteristicDescriptor.setValue("temperature Celsius");
  tempCharacteristic.addDescriptor(&tempCharacteristicDescriptor);
  pService->addCharacteristic(&humidityCharacteristic);
  humidityCharacteristicDescriptor.setValue("humidity");
  humidityCharacteristic.addDescriptor(&humidityCharacteristicDescriptor);
  //humidityCharacteristic.addDescriptor(new BLE2902());

  pService->start();
  // BLEAdvertising *pAdvertising = pServer->getAdvertising();  // this still is working for backward compatibility
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();

}
void loop() { 
  myTime = float(millis());

  if (deviceConnected) {
    if ((millis() - lastTime) > timerDelay) {
      // Reading temperature or humidity takes about 250 milliseconds!
      // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
      float h = dht.readHumidity();
      // Read temperature as Celsius (the default)
      float t = dht.readTemperature();
      // Read temperature as Fahrenheit (isFahrenheit = true)
      float f = dht.readTemperature(true);

      // Check if any reads failed and exit early (to try again).
      if (isnan(h) || isnan(t) || isnan(f)) {
        if (isnan(h)) {
          Serial.println(F("Failed to read from DHT sensor! h"));
        } else if(isnan(t)) {
          Serial.println(F("Failed to read from DHT sensor! t"));
        } else {
        Serial.println(F("Failed to read from DHT sensor! f"));
        }
        digitalWrite(DHTVCC, LOW);
        delay(1000);
        digitalWrite(DHTVCC, HIGH);
        dht.begin();
        delay(1000);
        return;
      }
      Serial.print("time:"); Serial.print(myTime); Serial.print(", ");
      Serial.print("humidity:"); Serial.print(h); Serial.print(", ");
      Serial.print("tempC:"); Serial.print(t); Serial.print(", ");
      Serial.println();
      static char temperatureCTemp[6];
      dtostrf(t, 6, 2, temperatureCTemp);
      tempCharacteristic.setValue(temperatureCTemp);
      tempCharacteristic.notify();

      static char humidity[6];
      dtostrf(h, 6, 2, humidity);
      humidityCharacteristic.setValue(humidity);
      humidityCharacteristic.notify();
      lastTime = millis();
      
      angle = angle + 5;
         
      // set the servo position
      myServo.write(angle%181);
      Serial.println(angle%181);
    }
  }
}

ble_client_dht

/*********
  Rui Santos
  Complete instructions at https://RandomNerdTutorials.com/esp32-ble-server-client/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/
float myTime;
#include "BLEDevice.h"
#include <DHT.h>
#define DHTPIN 21 // Defines pin number to which the sensor is connected
#define DHTVCC 4 // Defines pin number to which the sensor VCC is connected
DHT dht(DHTPIN, DHT22);

//BLE Server name (the other ESP32 name running the server sketch)
#define bleServerName "DHT22_ESP32"

/* UUID's of the service, characteristic that we want to read*/
// BLE Service
static BLEUUID dhtServiceUUID("5106ba9c-a085-4bea-b210-0272d8cd40dd");

// BLE Characteristics
//Temperature Celsius Characteristic
static BLEUUID temperatureCharacteristicUUID("cba1d466-344c-4be3-ab3f-189f80dd7518");

// Humidity Characteristic
static BLEUUID humidityCharacteristicUUID("ca73b3ba-39f6-4ab3-91ae-186dc9577d99");

//Flags stating if should begin connecting and if the connection is up
static boolean doConnect = false;
static boolean connected = false;

//Address of the peripheral device. Address will be found during scanning...
static BLEAddress *pServerAddress;

//Characteristicd that we want to read
static BLERemoteCharacteristic* temperatureCharacteristic;
static BLERemoteCharacteristic* humidityCharacteristic;

//Activate notify
const uint8_t notificationOn[] = {0x1, 0x0};
const uint8_t notificationOff[] = {0x0, 0x0};


//Variables to store temperature and humidity
char* temperatureChar;
char* humidityChar;

//Flags to check whether new temperature and humidity readings are available
boolean newTemperature = false;
boolean newHumidity = false;

//Connect to the BLE Server that has the name, Service, and Characteristics
bool connectToServer(BLEAddress pAddress) {
  BLEClient* pClient = BLEDevice::createClient();

  // Connect to the remove BLE Server.
  pClient->connect(pAddress);
  Serial.println(" - Connected to server");

  // Obtain a reference to the service we are after in the remote BLE server.
  BLERemoteService* pRemoteService = pClient->getService(dhtServiceUUID);
  if (pRemoteService == nullptr) {
    Serial.print("Failed to find our service UUID: ");
    Serial.println(dhtServiceUUID.toString().c_str());
    return (false);
  }

  // Obtain a reference to the characteristics in the service of the remote BLE server.
  temperatureCharacteristic = pRemoteService->getCharacteristic(temperatureCharacteristicUUID);
  humidityCharacteristic = pRemoteService->getCharacteristic(humidityCharacteristicUUID);

  if (temperatureCharacteristic == nullptr || humidityCharacteristic == nullptr) {
    Serial.print("Failed to find our characteristic UUID");
    return false;
  }
  Serial.println(" - Found our characteristics");

  //Assign callback functions for the Characteristics
  temperatureCharacteristic->registerForNotify(temperatureNotifyCallback);
  humidityCharacteristic->registerForNotify(humidityNotifyCallback);
  return true;
}

//Callback function that gets called, when another device's advertisement has been received
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
    void onResult(BLEAdvertisedDevice advertisedDevice) {
      if (advertisedDevice.getName() == bleServerName) { //Check if the name of the advertiser matches
        advertisedDevice.getScan()->stop(); //Scan can be stopped, we found what we are looking for
        pServerAddress = new BLEAddress(advertisedDevice.getAddress()); //Address of advertiser is the one we need
        doConnect = true; //Set indicator, stating that we are ready to connect
        Serial.println("Device found. Connecting!");
      }
    }
};

//When the BLE Server sends a new temperature reading with the notify property
static void temperatureNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,
                                      uint8_t* pData, size_t length, bool isNotify) {
  //store temperature value
  temperatureChar = (char*)pData;
  newTemperature = true;
}

//When the BLE Server sends a new humidity reading with the notify property
static void humidityNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,
                                   uint8_t* pData, size_t length, bool isNotify) {
  //store humidity value
  humidityChar = (char*)pData;
  newHumidity = true;
  //Serial.print(newHumidity);
}

//function that prints the latest sensor readings in the OLED display
void printReadings() {
  myTime = float(millis());
  Serial.print("time:"); Serial.print(myTime / 1000 / 60 / 60 / 24, 6); Serial.print(", ");
  Serial.print("humidity_Server:"); Serial.print(humidityChar); Serial.print(", ");
  Serial.print("tempC_Server:"); Serial.print(temperatureChar); Serial.print(", ");
  Serial.println();
}

void setup() {
  pinMode (DHTVCC, OUTPUT); //VCC for DHT22
  //Start serial communication
  Serial.begin(115200);
  Serial.println(F("DHTxx test!"));

  digitalWrite(DHTVCC, HIGH);
  dht.begin();
  delay(1000);

  Serial.println("Starting Arduino BLE Client application...");

  //Init BLE device
  BLEDevice::init("");

  // Retrieve a Scanner and set the callback we want to use to be informed when we
  // have detected a new device.  Specify that we want active scanning and start the
  // scan to run for 30 seconds.
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);
  pBLEScan->start(30);
}

void loop() {
  // If the flag "doConnect" is true then we have scanned for and found the desired
  // BLE Server with which we wish to connect.  Now we connect to it.  Once we are
  // connected we set the connected flag to be true.
  if (doConnect == true) {
    if (connectToServer(*pServerAddress)) {
      Serial.println("We are now connected to the BLE Server.");
      //Activate the Notify property of each Characteristic
      temperatureCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);
      humidityCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2903))->writeValue((uint8_t*)notificationOn, 2, true);
      connected = true;
    } else {
      Serial.println("We have failed to connect to the server; Restart your device to scan for nearby BLE server again.");
    }
    doConnect = false;
  }
  //if new temperature readings are available, print in the OLED
  if (newTemperature && newHumidity) {
    // Reading temperature or humidity takes about 250 milliseconds!
    // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
    float h = dht.readHumidity();
    // Read temperature as Celsius (the default)
    float t = dht.readTemperature();
    // Read temperature as Fahrenheit (isFahrenheit = true)
    float f = dht.readTemperature(true);

    // Check if any reads failed and exit early (to try again).
    if (isnan(h) || isnan(t) || isnan(f)) {
      Serial.println(F("Failed to read from DHT sensor!"));
      digitalWrite(DHTVCC, LOW);
      delay(1000);
      digitalWrite(DHTVCC, HIGH);
      dht.begin();
    } else {
      Serial.print("time:"); Serial.print(myTime / 1000 / 60 / 60 / 24, 6); Serial.print(", ");
      Serial.print("humidity_Client:"); Serial.print(h); Serial.print(", ");
      Serial.print("tempC_Client:"); Serial.print(t); Serial.print(", ");
      printReadings();
    }
    newTemperature = false;
    newHumidity = false;
  }
  delay(1000); // Delay a second between loops.
}

Hello my friend
Which comment do you mean?

Right above "void setup()", the commented out line "int angle = 0".
That version doesn't work properly.

Because there is a function before this comment that changes the process inside the loop

Could you explain why the external function/code matters? I actually just moved it up one line at a time.

Does not work here still:

#define SERVICE_UUID "5106ba9c-a085-4bea-b210-0272d8cd40dd"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
BLECharacteristic tempCharacteristic("cba1d466-344c-4be3-ab3f-189f80dd7518", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor tempCharacteristicDescriptor(BLEUUID((uint16_t)0x2902));
BLECharacteristic humidityCharacteristic("ca73b3ba-39f6-4ab3-91ae-186dc9577d99", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor humidityCharacteristicDescriptor(BLEUUID((uint16_t)0x2903));
int angle = 0;

//Setup callbacks onConnect and onDisconnect
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };
    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};




Works here:

#define SERVICE_UUID "5106ba9c-a085-4bea-b210-0272d8cd40dd"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
BLECharacteristic tempCharacteristic("cba1d466-344c-4be3-ab3f-189f80dd7518", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor tempCharacteristicDescriptor(BLEUUID((uint16_t)0x2902));
BLECharacteristic humidityCharacteristic("ca73b3ba-39f6-4ab3-91ae-186dc9577d99", BLECharacteristic::PROPERTY_NOTIFY);
int angle = 0;
BLEDescriptor humidityCharacteristicDescriptor(BLEUUID((uint16_t)0x2903));

//Setup callbacks onConnect and onDisconnect
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };
    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};



That explains nothing.

In the code you first posted, "angle" is declared and initialized here:

Servo myServo;  // create a servo object
int angle = 0;
int servoPin = 12;

So a second global declaration would have been an error.

Yes, in the first code I posted, I meant to say it doesn't work if I comment out the first one, and uncomment the second one. "Doesn't work" as in it compiles, but then prints "5" every time.

Post the code actually giving the problem.

Do NOT assume that we will modify and compile something else.

Here is code that doesn't work:
ble_server_dht

/*
    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
    Ported to Arduino ESP32 by Evandro Copercini
    updates by chegewara
*/
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>
#include <ESP32Servo.h>

#define bleServerName "DHT22_ESP32"

#include <DHT.h>
#define DHTPIN 21 // Defines pin number to which the sensor is connected
#define DHTVCC 4 // Defines pin number to which the sensor VCC is connected
DHT dht(DHTPIN, DHT22);
long myTime;
// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 6000;
bool deviceConnected = false;
Servo myServo;  // create a servo object
int servoPin = 12;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "5106ba9c-a085-4bea-b210-0272d8cd40dd"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
BLECharacteristic tempCharacteristic("cba1d466-344c-4be3-ab3f-189f80dd7518", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor tempCharacteristicDescriptor(BLEUUID((uint16_t)0x2902));
BLECharacteristic humidityCharacteristic("ca73b3ba-39f6-4ab3-91ae-186dc9577d99", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor humidityCharacteristicDescriptor(BLEUUID((uint16_t)0x2903));
int angle = 0;

//Setup callbacks onConnect and onDisconnect
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };
    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};


void setup() {
  pinMode (DHTVCC, OUTPUT); //VCC for DHT22
  Serial.begin(115200);
  Serial.println(F("DHTxx test!"));
  digitalWrite(DHTVCC, HIGH);
  dht.begin();
  delay(1000);
  
  // Allow allocation of all timers
  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  myServo.setPeriodHertz(50);    // standard 50 hz servo
  myServo.attach(servoPin, 1000, 2000); // attaches the servo on pin 18 to the servo obje
  //myServo.attach(servoPin, 500, 2400); // attaches the servo on pin 18 to the servo obje

  BLEDevice::init(bleServerName);
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks()); //new

  BLEService *pService = pServer->createService(SERVICE_UUID);
  /*
    BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE
                                       );

    pCharacteristic->setValue("Hello World says Neil");
  */
  pService->addCharacteristic(&tempCharacteristic);//new
  tempCharacteristicDescriptor.setValue("temperature Celsius");
  tempCharacteristic.addDescriptor(&tempCharacteristicDescriptor);
  pService->addCharacteristic(&humidityCharacteristic);
  humidityCharacteristicDescriptor.setValue("humidity");
  humidityCharacteristic.addDescriptor(&humidityCharacteristicDescriptor);
  //humidityCharacteristic.addDescriptor(new BLE2902());

  pService->start();
  // BLEAdvertising *pAdvertising = pServer->getAdvertising();  // this still is working for backward compatibility
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();

}
void loop() { 
  myTime = float(millis());

  if (deviceConnected) {
    if ((millis() - lastTime) > timerDelay) {
      // Reading temperature or humidity takes about 250 milliseconds!
      // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
      float h = dht.readHumidity();
      // Read temperature as Celsius (the default)
      float t = dht.readTemperature();
      // Read temperature as Fahrenheit (isFahrenheit = true)
      float f = dht.readTemperature(true);

      // Check if any reads failed and exit early (to try again).
      if (isnan(h) || isnan(t) || isnan(f)) {
        if (isnan(h)) {
          Serial.println(F("Failed to read from DHT sensor! h"));
        } else if(isnan(t)) {
          Serial.println(F("Failed to read from DHT sensor! t"));
        } else {
        Serial.println(F("Failed to read from DHT sensor! f"));
        }
        digitalWrite(DHTVCC, LOW);
        delay(1000);
        digitalWrite(DHTVCC, HIGH);
        dht.begin();
        delay(1000);
        return;
      }
      Serial.print("time:"); Serial.print(myTime); Serial.print(", ");
      Serial.print("humidity:"); Serial.print(h); Serial.print(", ");
      Serial.print("tempC:"); Serial.print(t); Serial.print(", ");
      Serial.println();
      static char temperatureCTemp[6];
      dtostrf(t, 6, 2, temperatureCTemp);
      tempCharacteristic.setValue(temperatureCTemp);
      tempCharacteristic.notify();

      static char humidity[6];
      dtostrf(h, 6, 2, humidity);
      humidityCharacteristic.setValue(humidity);
      humidityCharacteristic.notify();
      lastTime = millis();
      
      angle = angle + 5;
         
      // set the servo position
      myServo.write(angle%181);
      Serial.println(angle%181);
    }
  }
}

Code from other device since it doesn't run until it connects to another ESP32:
ble_client_dht

/*********
  Rui Santos
  Complete instructions at https://RandomNerdTutorials.com/esp32-ble-server-client/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/
float myTime;
#include "BLEDevice.h"
#include <DHT.h>
#define DHTPIN 21 // Defines pin number to which the sensor is connected
#define DHTVCC 4 // Defines pin number to which the sensor VCC is connected
DHT dht(DHTPIN, DHT22);

//BLE Server name (the other ESP32 name running the server sketch)
#define bleServerName "DHT22_ESP32"

/* UUID's of the service, characteristic that we want to read*/
// BLE Service
static BLEUUID dhtServiceUUID("5106ba9c-a085-4bea-b210-0272d8cd40dd");

// BLE Characteristics
//Temperature Celsius Characteristic
static BLEUUID temperatureCharacteristicUUID("cba1d466-344c-4be3-ab3f-189f80dd7518");

// Humidity Characteristic
static BLEUUID humidityCharacteristicUUID("ca73b3ba-39f6-4ab3-91ae-186dc9577d99");

//Flags stating if should begin connecting and if the connection is up
static boolean doConnect = false;
static boolean connected = false;

//Address of the peripheral device. Address will be found during scanning...
static BLEAddress *pServerAddress;

//Characteristicd that we want to read
static BLERemoteCharacteristic* temperatureCharacteristic;
static BLERemoteCharacteristic* humidityCharacteristic;

//Activate notify
const uint8_t notificationOn[] = {0x1, 0x0};
const uint8_t notificationOff[] = {0x0, 0x0};


//Variables to store temperature and humidity
char* temperatureChar;
char* humidityChar;

//Flags to check whether new temperature and humidity readings are available
boolean newTemperature = false;
boolean newHumidity = false;

//Connect to the BLE Server that has the name, Service, and Characteristics
bool connectToServer(BLEAddress pAddress) {
  BLEClient* pClient = BLEDevice::createClient();

  // Connect to the remove BLE Server.
  pClient->connect(pAddress);
  Serial.println(" - Connected to server");

  // Obtain a reference to the service we are after in the remote BLE server.
  BLERemoteService* pRemoteService = pClient->getService(dhtServiceUUID);
  if (pRemoteService == nullptr) {
    Serial.print("Failed to find our service UUID: ");
    Serial.println(dhtServiceUUID.toString().c_str());
    return (false);
  }

  // Obtain a reference to the characteristics in the service of the remote BLE server.
  temperatureCharacteristic = pRemoteService->getCharacteristic(temperatureCharacteristicUUID);
  humidityCharacteristic = pRemoteService->getCharacteristic(humidityCharacteristicUUID);

  if (temperatureCharacteristic == nullptr || humidityCharacteristic == nullptr) {
    Serial.print("Failed to find our characteristic UUID");
    return false;
  }
  Serial.println(" - Found our characteristics");

  //Assign callback functions for the Characteristics
  temperatureCharacteristic->registerForNotify(temperatureNotifyCallback);
  humidityCharacteristic->registerForNotify(humidityNotifyCallback);
  return true;
}

//Callback function that gets called, when another device's advertisement has been received
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
    void onResult(BLEAdvertisedDevice advertisedDevice) {
      if (advertisedDevice.getName() == bleServerName) { //Check if the name of the advertiser matches
        advertisedDevice.getScan()->stop(); //Scan can be stopped, we found what we are looking for
        pServerAddress = new BLEAddress(advertisedDevice.getAddress()); //Address of advertiser is the one we need
        doConnect = true; //Set indicator, stating that we are ready to connect
        Serial.println("Device found. Connecting!");
      }
    }
};

//When the BLE Server sends a new temperature reading with the notify property
static void temperatureNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,
                                      uint8_t* pData, size_t length, bool isNotify) {
  //store temperature value
  temperatureChar = (char*)pData;
  newTemperature = true;
}

//When the BLE Server sends a new humidity reading with the notify property
static void humidityNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,
                                   uint8_t* pData, size_t length, bool isNotify) {
  //store humidity value
  humidityChar = (char*)pData;
  newHumidity = true;
  //Serial.print(newHumidity);
}

//function that prints the latest sensor readings in the OLED display
void printReadings() {
  myTime = float(millis());
  Serial.print("time:"); Serial.print(myTime / 1000 / 60 / 60 / 24, 6); Serial.print(", ");
  Serial.print("humidity_Server:"); Serial.print(humidityChar); Serial.print(", ");
  Serial.print("tempC_Server:"); Serial.print(temperatureChar); Serial.print(", ");
  Serial.println();
}

void setup() {
  pinMode (DHTVCC, OUTPUT); //VCC for DHT22
  //Start serial communication
  Serial.begin(115200);
  Serial.println(F("DHTxx test!"));

  digitalWrite(DHTVCC, HIGH);
  dht.begin();
  delay(1000);

  Serial.println("Starting Arduino BLE Client application...");

  //Init BLE device
  BLEDevice::init("");

  // Retrieve a Scanner and set the callback we want to use to be informed when we
  // have detected a new device.  Specify that we want active scanning and start the
  // scan to run for 30 seconds.
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);
  pBLEScan->start(30);
}

void loop() {
  // If the flag "doConnect" is true then we have scanned for and found the desired
  // BLE Server with which we wish to connect.  Now we connect to it.  Once we are
  // connected we set the connected flag to be true.
  if (doConnect == true) {
    if (connectToServer(*pServerAddress)) {
      Serial.println("We are now connected to the BLE Server.");
      //Activate the Notify property of each Characteristic
      temperatureCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);
      humidityCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2903))->writeValue((uint8_t*)notificationOn, 2, true);
      connected = true;
    } else {
      Serial.println("We have failed to connect to the server; Restart your device to scan for nearby BLE server again.");
    }
    doConnect = false;
  }
  //if new temperature readings are available, print in the OLED
  if (newTemperature && newHumidity) {
    // Reading temperature or humidity takes about 250 milliseconds!
    // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
    float h = dht.readHumidity();
    // Read temperature as Celsius (the default)
    float t = dht.readTemperature();
    // Read temperature as Fahrenheit (isFahrenheit = true)
    float f = dht.readTemperature(true);

    // Check if any reads failed and exit early (to try again).
    if (isnan(h) || isnan(t) || isnan(f)) {
      Serial.println(F("Failed to read from DHT sensor!"));
      digitalWrite(DHTVCC, LOW);
      delay(1000);
      digitalWrite(DHTVCC, HIGH);
      dht.begin();
    } else {
      Serial.print("time:"); Serial.print(myTime / 1000 / 60 / 60 / 24, 6); Serial.print(", ");
      Serial.print("humidity_Client:"); Serial.print(h); Serial.print(", ");
      Serial.print("tempC_Client:"); Serial.print(t); Serial.print(", ");
      printReadings();
    }
    newTemperature = false;
    newHumidity = false;
  }
  delay(1000); // Delay a second between loops.
}

Now, for the most recently posted code, explain exactly what you mean by "doesn't work".

State what you expect to happen, and what happens instead.

Please remove the second code example posted in the above reply. To avoid confusion discuss ONLY ONE PROBLEM AT A TIME.

To be clear, the problem occurs when I have two devices connected. One using code example 1 from post 10, and a 2nd device using code example 2.
Nothing happens if there is no connection.

Once connected:
I expect that device 1, the server, will, every 6 seconds, notify device 2, the client, with new humidity and temp data. Then, increment "angle" by +5.

However, angle gets set to 5 each time.

Tough problem, and it won't be solved on this thread, given the meager information you have provided so far.

Start by putting in some print statements to monitor the device to device information exchange, and match that with expectations.

1 Like

I can not confirm your issue with the incrementing of angle.
I run the peripheral code you posted and connect with nrfConnect or a terminal program and I see this in the Serial monitor. I have commented out the code failure with NAN because I do not have a DHT connected.

18:22:21.017 -> DHTxx test!
18:22:29.469 -> time:8191, humidity:nan, tempC:nan,
18:22:29.469 -> 5
18:22:35.721 -> time:14462, humidity:nan, tempC:nan,
18:22:35.721 -> 10
18:22:42.001 -> time:20732, humidity:nan, tempC:nan,
18:22:42.001 -> 15
18:22:48.291 -> time:27004, humidity:nan, tempC:nan,
18:22:48.291 -> 20
18:22:54.544 -> time:33275, humidity:nan, tempC:nan,
18:22:54.544 -> 25

Do you mean I should dig into the ble code and it might be in there? I do have another problem, and I'm not sure if it related. I send temp and humidity data from the server, but sometimes client receives temp data that is humidity instead.

I just tried printing "herex : " + "angle"
It is getting reset to 0 after "here 4". But I can't figure out why dtostrf() would cause this problem.

/*
    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
    Ported to Arduino ESP32 by Evandro Copercini
    updates by chegewara
*/
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>
#include <ESP32Servo.h>

#define bleServerName "DHT22_ESP32"

#include <DHT.h>
#define DHTPIN 21 // Defines pin number to which the sensor is connected
#define DHTVCC 4 // Defines pin number to which the sensor VCC is connected
DHT dht(DHTPIN, DHT22);
long myTime;
// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 6000;
bool deviceConnected = false;
Servo myServo;  // create a servo object
int servoPin = 12;

int battery_shunt_p = 14;
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "5106ba9c-a085-4bea-b210-0272d8cd40dd"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
BLECharacteristic tempCharacteristic("cba1d466-344c-4be3-ab3f-189f80dd7518", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor tempCharacteristicDescriptor(BLEUUID((uint16_t)0x2902));
BLECharacteristic humidityCharacteristic("ca73b3ba-39f6-4ab3-91ae-186dc9577d99", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor humidityCharacteristicDescriptor(BLEUUID((uint16_t)0x2903));
int angle = 0;

//Setup callbacks onConnect and onDisconnect
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };
    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};


void setup() {
  pinMode (DHTVCC, OUTPUT); //VCC for DHT22
  Serial.begin(115200);
  Serial.println(F("DHTxx test!"));
  digitalWrite(DHTVCC, HIGH);
  dht.begin();
  delay(1000);
  
  // Allow allocation of all timers
  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  myServo.setPeriodHertz(50);    // standard 50 hz servo
  myServo.attach(servoPin, 1000, 2000); // attaches the servo on pin 18 to the servo obje
  //myServo.attach(servoPin, 500, 2400); // attaches the servo on pin 18 to the servo obje

  BLEDevice::init(bleServerName);
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks()); //new

  BLEService *pService = pServer->createService(SERVICE_UUID);
  /*
    BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE
                                       );

    pCharacteristic->setValue("Hello World says Neil");
  */
  pService->addCharacteristic(&tempCharacteristic);//new
  tempCharacteristicDescriptor.setValue("temperature Celsius");
  tempCharacteristic.addDescriptor(&tempCharacteristicDescriptor);
  pService->addCharacteristic(&humidityCharacteristic);
  humidityCharacteristicDescriptor.setValue("humidity");
  humidityCharacteristic.addDescriptor(&humidityCharacteristicDescriptor);
  //humidityCharacteristic.addDescriptor(new BLE2902());

  pService->start();
  // BLEAdvertising *pAdvertising = pServer->getAdvertising();  // this still is working for backward compatibility
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();

}
void loop() { 
  myTime = float(millis());

  if (deviceConnected) {
    if ((millis() - lastTime) > timerDelay) {
      Serial.print("here1 :");
      Serial.println(angle);
      // Reading temperature or humidity takes about 250 milliseconds!
      // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
      float h = dht.readHumidity();
      // Read temperature as Celsius (the default)
      float t = dht.readTemperature();
      // Read temperature as Fahrenheit (isFahrenheit = true)
      float f = dht.readTemperature(true);
      Serial.print("here2 :");
      Serial.println(angle);

      // Check if any reads failed and exit early (to try again).
      if (isnan(h) || isnan(t) || isnan(f)) {
        if (isnan(h)) {
          Serial.println(F("Failed to read from DHT sensor! h"));
        } else if(isnan(t)) {
          Serial.println(F("Failed to read from DHT sensor! t"));
        } else {
        Serial.println(F("Failed to read from DHT sensor! f"));
        }
        digitalWrite(DHTVCC, LOW);
        delay(1000);
        digitalWrite(DHTVCC, HIGH);
        dht.begin();
        delay(1000);
        return;
      }
      Serial.print("here3 :");
      Serial.println(angle);
      //Serial.print("time:"); Serial.print(myTime / 1000 / 60 / 60 / 24, 6); Serial.print(", ");
      Serial.print("time:"); Serial.print(myTime); Serial.print(", ");
      Serial.print("humidity:"); Serial.print(h); Serial.print(", ");
      Serial.print("tempC:"); Serial.print(t); Serial.print(", ");
      Serial.println();
      static char temperatureCTemp[6];
      Serial.print("here4 :");
      Serial.println(angle);
      dtostrf(t, 6, 2, temperatureCTemp);
      Serial.print("here5 :");
      Serial.println(angle);
      if (angle == 0) {
        angle=5;
      }
      tempCharacteristic.setValue(temperatureCTemp);
      Serial.print("here6 :");
      Serial.println(angle);
      tempCharacteristic.notify();
      Serial.print("here7 :");
      Serial.println(angle);
      static char humidity[6];
      Serial.print("here8 :");
      Serial.println(angle);
      dtostrf(h, 6, 2, humidity);
      Serial.print("here9 :");
      Serial.println(angle);
      humidityCharacteristic.setValue(humidity);
      Serial.print("here10 :");
      Serial.println(angle);
      humidityCharacteristic.notify();
      Serial.print("here11 :");
      Serial.println(angle);
      lastTime = millis();
      
      angle = angle + 5;
         
      // set the servo position
      myServo.write(angle%181);
      Serial.println(angle);
    }
  }
}

Commenting out dtostrf() and hardcoding a value, angle increments properly now.

/*
    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
    Ported to Arduino ESP32 by Evandro Copercini
    updates by chegewara
*/
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>
#include <ESP32Servo.h>

#define bleServerName "DHT22_ESP32"

#include <DHT.h>
#define DHTPIN 21 // Defines pin number to which the sensor is connected
#define DHTVCC 4 // Defines pin number to which the sensor VCC is connected
DHT dht(DHTPIN, DHT22);
long myTime;
// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 6000;
bool deviceConnected = false;
Servo myServo;  // create a servo object
int servoPin = 12;

int battery_shunt_p = 14;
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "5106ba9c-a085-4bea-b210-0272d8cd40dd"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
BLECharacteristic tempCharacteristic("cba1d466-344c-4be3-ab3f-189f80dd7518", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor tempCharacteristicDescriptor(BLEUUID((uint16_t)0x2902));
BLECharacteristic humidityCharacteristic("ca73b3ba-39f6-4ab3-91ae-186dc9577d99", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor humidityCharacteristicDescriptor(BLEUUID((uint16_t)0x2903));
int angle = 0;

//Setup callbacks onConnect and onDisconnect
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };
    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};


void setup() {
  pinMode (DHTVCC, OUTPUT); //VCC for DHT22
  Serial.begin(115200);
  Serial.println(F("DHTxx test!"));
  digitalWrite(DHTVCC, HIGH);
  dht.begin();
  delay(1000);
  
  // Allow allocation of all timers
  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  myServo.setPeriodHertz(50);    // standard 50 hz servo
  myServo.attach(servoPin, 1000, 2000); // attaches the servo on pin 18 to the servo obje
  //myServo.attach(servoPin, 500, 2400); // attaches the servo on pin 18 to the servo obje

  BLEDevice::init(bleServerName);
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks()); //new

  BLEService *pService = pServer->createService(SERVICE_UUID);
  /*
    BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE
                                       );

    pCharacteristic->setValue("Hello World says Neil");
  */
  pService->addCharacteristic(&tempCharacteristic);//new
  tempCharacteristicDescriptor.setValue("temperature Celsius");
  tempCharacteristic.addDescriptor(&tempCharacteristicDescriptor);
  pService->addCharacteristic(&humidityCharacteristic);
  humidityCharacteristicDescriptor.setValue("humidity");
  humidityCharacteristic.addDescriptor(&humidityCharacteristicDescriptor);
  //humidityCharacteristic.addDescriptor(new BLE2902());

  pService->start();
  // BLEAdvertising *pAdvertising = pServer->getAdvertising();  // this still is working for backward compatibility
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();

}
void loop() { 
  myTime = float(millis());

  if (deviceConnected) {
    if ((millis() - lastTime) > timerDelay) {
      Serial.print("here1 :");
      Serial.println(angle);
      // Reading temperature or humidity takes about 250 milliseconds!
      // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
      float h = dht.readHumidity();
      // Read temperature as Celsius (the default)
      float t = dht.readTemperature();
      // Read temperature as Fahrenheit (isFahrenheit = true)
      float f = dht.readTemperature(true);
      Serial.print("here2 :");
      Serial.println(angle);

      // Check if any reads failed and exit early (to try again).
      if (isnan(h) || isnan(t) || isnan(f)) {
        if (isnan(h)) {
          Serial.println(F("Failed to read from DHT sensor! h"));
        } else if(isnan(t)) {
          Serial.println(F("Failed to read from DHT sensor! t"));
        } else {
        Serial.println(F("Failed to read from DHT sensor! f"));
        }
        digitalWrite(DHTVCC, LOW);
        delay(1000);
        digitalWrite(DHTVCC, HIGH);
        dht.begin();
        delay(1000);
        return;
      }
      Serial.print("here3 :");
      Serial.println(angle);
      //Serial.print("time:"); Serial.print(myTime / 1000 / 60 / 60 / 24, 6); Serial.print(", ");
      Serial.print("time:"); Serial.print(myTime); Serial.print(", ");
      Serial.print("humidity:"); Serial.print(h); Serial.print(", ");
      Serial.print("tempC:"); Serial.print(t); Serial.print(", ");
      Serial.println();
      //static char temperatureCTemp[6];
      Serial.print("here4 :");
      Serial.println(angle);
      //dtostrf(t, 6, 2, temperatureCTemp);
      Serial.print("here5 :");
      Serial.println(angle);
      if (angle == 0) {
        angle=5;
      }
      //tempCharacteristic.setValue(temperatureCTemp);
      tempCharacteristic.setValue("999");
      Serial.print("here6 :");
      Serial.println(angle);
      tempCharacteristic.notify();
      Serial.print("here7 :");
      Serial.println(angle);
      static char humidity[6];
      Serial.print("here8 :");
      Serial.println(angle);
      dtostrf(h, 6, 2, humidity);
      Serial.print("here9 :");
      Serial.println(angle);
      humidityCharacteristic.setValue(humidity);
      Serial.print("here10 :");
      Serial.println(angle);
      humidityCharacteristic.notify();
      Serial.print("here11 :");
      Serial.println(angle);
      lastTime = millis();
      
      angle = angle + 5;
         
      // set the servo position
      myServo.write(angle%181);
      Serial.println(angle);
    }
  }
}

*edit, I see what you meant. You commented out the failure prints and also the "return"

So, dtostrf now tries to convert nan to a string, and this doesn't cause the angle incrementing problem. Only if dtostrf converts a number and stores it in temperatureCTemp, does the angle problem happen.

Kolban's examples were wrote a long time ago using an earlier version of the ESP32's API. As an FYI.

What are the different float numbers you are converting to character strings with dtostrf?

I don't think you are sizing the buffer for the character array large enough to hold the number, the dp and the null terminator and are overwriting some memory causing a crash.
https://www.programmingelectronics.com/dtostrf/

 static char temperatureCTemp[6];
      Serial.print("here4 :");
      Serial.println(angle);
      dtostrf(t, 6, 2, temperatureCTemp);

Try making temperatureCTemp[ ] larger.
Try for a quick test

static char temperatureCTemp[12];

1 Like

The '6' in your call to dtostrf() is the MINIMUM field width. For values under 100.00 the field will be padded to the minimum with leading spaces.

The buffer needs to be at least 7 characters long to fit the (minimum) 6 characters and a terminating null.

For values over 999.99 you would need even more space in the buffer since 1000.00 is 7 characters and you still need another for the null.

2 Likes

Thank you, cattledog and johnwasser! That makes sense; I should allow for a larger char buffer. The angle incrementation works now!

I have another issue, should I make a new thread?
When the client gets notified of temperature then humidity, after I print them, they are both humidity.

I also tried printing the address of temperatureChar and humidityChar on the client, and they seem to be the same. I set them to *pdata in their respective callback functions.