Blynk or project issue? Performance

Hello,

My hardware:

  • Arduino MKR 1400 GSM
  • DS18B20
  • BLE Module HM-10

I recently codded some system to detect a temperature in a small room, calculate the avg. temp and detect objects places on a seat. It works pretty well until Blynk connects, e.g. before Blynk is connected the logs are printed extremely fast, when Blynk connects they visibly slow down. Additionally, the longer the app works the less stable it becomes. Finally entire device and Blynk require restart, usually up to 1h is enough.

I also would like to ask for advice of how I would be able to handle timers better, as I notice some of timers interrupt each other and the sequence of execution gets irregular over time. In general, I noticed that keeping some of functions I run under timers directly in loop() makes the function better and faster that within timers, like the timers would slow things down.

Here is the sketch code:

#include "StdAfx.h"
#include "Defines.h"

/*** TODO
- Clean up and optimize code
***/

// Author: xxxxxxxxxxx
// IMEI: xxxxxxxxxxxxx
/****************************
 *  Globals                 *
 ***************************/
// General
volatile bool g_setupStatus = false;          // setup() status, completed?
volatile bool g_doorState = DoorStates::LOCK; // door state, as per enum
volatile uint8_t g_htSensorsCount = 0;        // number of detected heat sensors
volatile bool g_rLedState = false;            // leds state, on/off
volatile bool g_yLedState = false;
volatile bool g_bLedState = false;

// display change button stuff
volatile bool g_btnState = LOW;                           // current state of the display change button
volatile uint8_t g_prevBtnState = HIGH;                   // previous state of the display change button
unsigned long g_prevDebounceTime = 0UL;                   // the last time button state was toggled
unsigned long g_debounceDelay = 75UL;                     // the debounce time increase if the output flickers
volatile int8_t g_tempDisplayNum = -1;                    // initial temp display number, 0-2
volatile uint8_t g_tempAlarmWarn = AlarmStatus::NO_ALARM; // true indicates general alarm raised what triggers further actions

// press pad stuff
volatile bool g_fsrStateChange = false;            // press pad status, pushed?
volatile unsigned long g_fsrStateChangeTime = 0UL; // time since last g_fsrStateChange change

// temperature stuff
uint8_t *g_tempSensors[3] = {0};                               // array of pointers to the sensors
volatile float g_tempSensorRead[3] = {0.0};                    // actual temperatures read array
int g_tempSensorAlarms[3][2] = {{15, 28}, {15, 28}, {15, 28}}; // array of sensors' temp alarm values, LOW/HIGH
float g_MinTemp = 10000.0F;
float g_MaxTemp = 0.0F;

// miscellaneous
volatile bool g_printBeat = false; // just fun heart beating
volatile unsigned long g_lastBeatPrint = 0UL;

// GSM/GPRS
char g_PINNUMBER[] = "";        // Sim Pin number
char g_GPRS_APN[] = "internet"; // mobile internet APN name
char g_GPRS_LOGIN[] = "";       // login for APN
char g_GPRS_PASSWORD[] = "";    // Password for APN

String g_GPRSlatitude = "0.000000";  // Latitude
String g_GPRSlongitude = "0.000000"; // Longitude
bool g_gsmConnStatus = false;        // GSM Connection status
bool g_connectInSetup = true;       // Connects GSM/GPRS in setup()
#ifdef VM_DEBUG
long g_locAccuracy = 1000000L;       // Debug value
#else
long g_locAccuracy = 1001L;          // Best location accuracy achaived, replace GPRS with GPS in future
#endif
bool g_gsmConnRetry = false;         // 
bool g_smsSendRetry = false;

unsigned long g_ActionStart = 0UL;    // 
bool g_ActionState = false;           //

/************************************
 *  Class object/library instances  *
 ************************************/


// One wire bus
OneWire bus(heatSensorBus);
DallasTemperature htSensors(&bus);

// Timer class instances..
MillisTimers tmFsrState(3000UL), smsReSend(30000);
BlynkTimer timer;

WidgetMap Map(V6);
WidgetLED yLed(V1);
WidgetLED bLed(V4);

// arrays to hold temp. device addresses
DeviceAddress internalThermometer, peripheralThermometer1, peripheralThermometer2;

// GSM stuff
GPRS gprs;
GSM gsm;
GSM_SMS sms;
GSMLocation location;
GSMScanner network;

void setup()
{             // g_setupStatus is false here
  PinsInit(); // assign pins and set modes

#ifdef VM_DEBUG
  Serial.begin(baudrate);
  while (!Serial); // The USB connection to be established? wait, so can see setup logs in monitor
#endif
  //g_Lcd.init();      // LCD start
  lcd.begin(20, 4);
  lcd.createChar(0, hori_line_3);
  lcd.createChar(1, heart_f);
  lcd.createChar(2, gsm_network);
  lcd.createChar(3, signal_str_1);
  lcd.createChar(4, signal_str_2);
  lcd.createChar(5, signal_str_3);
  lcd.createChar(6, man);
  lcd.createChar(7, thermometer);
  lcd.home();
  char buff[20];
  sprintf_P(buff, "%c       %c:      %c  ", char(2), char(6), char(7));
  lcd.print(buff);

  if (g_connectInSetup)
  {
    ConnGsmNetwork();
    location.begin();
  }
  
  htSensors.begin(); // hello DS18S20

  // Fill the sensors arrays with temp. device address
  g_tempSensors[0] = *&internalThermometer;
  g_tempSensors[1] = *&peripheralThermometer1;
  g_tempSensors[2] = *&peripheralThermometer2;

  GetSensorsVerify(); // faulty? tell more about it..

// show the addresses we found on the bus
#ifdef VM_DEBUG
  for (uint8_t i = 0; i < MAX_TEMP_DEVICE; i++)
  {
    PrintBusDevicesAddress(&*g_tempSensors[i]);
  }
  Serial.println("Setting alarm temps.");
#endif

  SetTemperatureAlarms(); // set alarm values on devices

#ifdef VM_DEBUG
  PrintAlarms();
#endif
  //htSensors.setAlarmHandler(&AlarmHandler); // the one to trigger the alarms! It is slow! handled it own way..
 
  BLELink.begin(baudrate);  // say hello to HM-10
  while (!BLELink);
  //HM10Reset();

  Blynk.config(BLELink, auth);
  Blynk.connect();  // Start talking to Blynk app

  timer.setInterval(10000UL, GetGsmSignalStrength);
  timer.setInterval(10000UL, GetGRPSLocation);
  timer.setInterval(10000UL, smsInfoReply);
  timer.setInterval(1000UL, UpdateTemperaturesReading); // do not bother temp. sensors too often
  timer.setInterval(1000UL, GetDoorStateChange);  // check for door open and trigger action
  timer.setInterval(1200UL, yLedBlink);
  timer.setInterval(1200UL, rLedBlink);
  timer.setInterval(1100UL, DisplayTemperature);
  timer.setInterval(1000UL, AlarmHandler);
  timer.setInterval(100UL, HeartBeatPrint);
  timer.setInterval(30UL, ButtonPressDebounce);
  timer.setInterval(5000UL, GsmConnectFlagUpdate);

#ifdef VM_DEBUG
  Serial.println("Waiting for connections..."); // BLE
#endif
  g_setupStatus = true;

  if (g_setupStatus) // shut off leds when setup is completed
  {
    digitalWrite(rLedPin, LOW);
    digitalWrite(yLedPin, LOW);
    digitalWrite(bLedPin, LOW);
  }
}

// ### Main loop start
void loop()
{
  timer.run();
  
  if (g_gsmConnRetry){
    ConnGsmNetwork();
    if (!location.available())
      location.begin();
    g_gsmConnRetry = false;
  }
  GetFsrState();      // Move to timer maybe?
  DoAction();         // Priority action, tobe kept in loop() always
  Blynk.run();
}

// ### GSM connection flag periodical update, false is set only when !gsm.ready()
void GsmConnectFlagUpdate() {
  g_gsmConnRetry = true;
}

// ### Handle physical button press debounce
void ButtonPressDebounce()
{
  uint8_t _btnStateRead = digitalRead(btnPin); // grab the button hit

  // if switch changed, due to noise or pressing
  if (_btnStateRead != g_prevBtnState)
    // reset the debouncing timer
    g_prevDebounceTime = millis();

  if (millis() - g_prevDebounceTime > g_debounceDelay)
  { // if button state changed
    if (_btnStateRead != g_btnState)
    {
      g_btnState = _btnStateRead;
      virtualWrite(V2, g_btnState);

      // toggle trigger screen change
      if (g_btnState == HIGH)
        ChangeDisplayNumber();
    }
  }
  g_prevBtnState = _btnStateRead;
}

// Display unit temp. in LCD
void DisplayTemperature()
{
  bool _isError = false;
  char _result[5] = {""};
  char _buff[8];
 
  for (uint8_t i = MAX_TEMP_DEVICE - 1; i >= 0; i--) // Decreament to init display with g_tempSensorRead[0]
  {
    if (g_tempDisplayNum == i)
    {
      dtostrf(g_tempSensorRead[i], 3, 1, _result);

      if (atoi(_result) == DEVICE_DISCONNECTED)
        _isError = true;
      break;
    }
  }

  sprintf_P(_buff, "%s%cC", _result, _degrees);
  if (_isError)
    memcpy_P(_buff + 3, _error, sizeof(_error));

  lcd.setCursor(14, 1);
  lcd.print(_buff);
}

// ### Change temp unit display in LCD
void ChangeDisplayNumber()
{
    g_tempDisplayNum += 1;
    if (g_tempDisplayNum > 2)
      g_tempDisplayNum = 0;

    char _num = 0;
    switch (g_tempDisplayNum)
    {
    case 0: _num = char(95); break;
    case 1: _num = char(61); break;
    case 2: _num = char(8); break;
    }

  lcd.setCursor(17, 0);
  lcd.print(_num);
  return;
}

// ### Check for door state
void GetDoorStateChange()
{
  volatile bool _doorStateReading = digitalRead(doorPin); // so opened.. or not?
  if (_doorStateReading == DoorStates::OPEN)              // opened!
  {
    g_doorState = true;
#ifdef VM_DEBUG
    Serial.println("Door: OPEN");
#endif
  }
  else // door locked
  {
    g_doorState = false;
#ifdef VM_DEBUG
    Serial.println("Door: LOCKED");
#endif
  }
}

// ### Blink yellow if door opened
void yLedBlink()
{
  if (g_doorState)
  {
    bool _val = (g_yLedState) ? HIGH : LOW;
    digitalWrite(yLedPin, _val); // start blinking with led
    //virtualWrite(V1, _val);   // why not in Blynk too?
    if (g_yLedState == LOW)
      yLed.off();
    if (g_yLedState == HIGH)
      yLed.on();
    g_yLedState = !g_yLedState;
#ifdef VM_DEBUG
    Serial.println("Door: OPEN");
#endif
  }
  else {                             // door locked
    digitalWrite(yLedPin, LOW); // shut off the led
    //virtualWrite(V1, LOW);
    yLed.off();
#ifdef VM_DEBUG
    Serial.println("Door: LOCKED");
#endif
  }
}

// ### Read force pad pressure
void GetFsrState()
{
  volatile uint16_t _fsrReading = analogRead(fsrPin);
  _fsrReading *= fsrCf; // let us calibrate

  if (_fsrReading > 100)
  {
    digitalWrite(bLedPin, HIGH);
    bLed.on();
    #ifdef VM_DEBUG
    Serial.println(_fsrReading);
    #endif
    lcd.setCursor(3, 4);
    lcd.print("Baby On Seat!");
    //PlayNoiseAlarm();
    g_fsrStateChange = true;
    g_fsrStateChangeTime = millis();
  }
  else
  {
    digitalWrite(bLedPin, LOW);
    bLed.off();
    if (g_fsrStateChange)
    {
      if (tmFsrState.LastPeriod(g_fsrStateChangeTime))
      {
        lcd.setCursor(3, 4);
        lcd.print(LcdSpaceCombine(13));
        lcd.setCursor(5, 4);
        lcd.print("Seat Empty");
      }
      else
      {
        lcd.setCursor(3, 4);
        lcd.print(LcdSpaceCombine(13));
        g_fsrStateChange = false;
      }
    }
  }
}

// ### Light on the red led when having temp. alarm
void rLedBlink()
{
  if (g_tempAlarmWarn > 0)
  {
    digitalWrite(rLedPin, HIGH);
    Blynk.virtualWrite(V5, ON);
  }
  else
  {
    digitalWrite(rLedPin, LOW);
    Blynk.virtualWrite(V5, OFF);
  }
}

void DoAction()
{
  if (g_doorState && g_fsrStateChange)
  {
    if (g_ActionState) {
      g_ActionStart = millis();
      g_ActionState = false;
    }

    if (BlynkNotify("Get your child out of the seat!") == true)
    {
      // Keep sending notifications for next 10 seconds..
    }

    if (g_tempAlarmWarn > 0)
    {
      if (smsReSend.LastPeriod(millis()))
      #ifdef VM_DEBUG
         Serial.println("SMS_1 Sent");
      #else
        smsSend("Temperature alarm is active and pressure on seat pad detected, return vehicale now!");
      #endif
    }
  }
  else if (!g_doorState && g_tempAlarmWarn > 0)
  {
    if (BlynkNotify("Get your child out of the seat!"))
    {
    }
    
    lcd.setCursor(2, 2);
    lcd.print("Temp Alarm is ON");
  }
  else if (g_doorState && g_tempAlarmWarn > 0)
  {
    if (smsReSend.LastPeriod(millis()))
    #ifdef VM_DEBUG
      Serial.println("SMS_2 Sent");
    #else
        smsSend("Temperature alarm is active and pressure on seat pad detected, return vehicale now!");
    #endif
  }
  else if (!g_doorState && g_tempAlarmWarn == 0)
  {
    lcd.setCursor(0, 2);
    lcd.print("                    ");
    g_ActionStart = 0UL;
    g_ActionStart = true;
  }
}

// ### Check for GPRS location
void GetGRPSLocation()
{
  if (location.available())
  {
    long _readLocAccuracy = location.accuracy(); // ~meters
    #ifdef VM_DEBUG
    SerialPrint("GPRS Accuracy: %d\n", _readLocAccuracy);
    #endif
    if (_readLocAccuracy < g_locAccuracy)
    {
      g_locAccuracy = _readLocAccuracy;
      g_GPRSlatitude = String(location.latitude(), 6);
      g_GPRSlongitude = String(location.longitude(), 6);
    #ifdef VM_DEBUG
      SerialPrint("Lat. %s, Lon. %s\n", g_GPRSlatitude.c_str(), g_GPRSlongitude.c_str());
    #endif
      Map.location(1, g_GPRSlatitude, g_GPRSlongitude, "Vehicale Position");
    }
  }
}

// ### GPS connect function
void ConnGsmNetwork()
{
  gprs.setTimeout(18000);
  gsm.setTimeout(18000);

  if (!gsm.ready())
    g_gsmConnStatus = false;

  // Start GSM connection
  if (g_gsmConnStatus == false)
  {
    if (gsm.begin(g_PINNUMBER) == GSM_READY && (gprs.attachGPRS(g_GPRS_APN, g_GPRS_LOGIN, g_GPRS_PASSWORD) == GPRS_READY))
    {
      network.begin();
      g_gsmConnStatus = true;
#ifdef VM_DEBUG
      Serial.println("GSM START SUCCESS!");
#endif
    }
    else
    {
#ifdef VM_DEBUG
      Serial.println("GSM CONNECT FAIL!");
#endif
      //delay(200);
    }
  }
}

// ### Check for GSM signal power and display in LCD
void GetGsmSignalStrength()
{
  if (g_gsmConnStatus)
  {
    uint8_t _signalPwr = network.getSignalStrength().toInt();
    lcd.setCursor(1, 0);

#ifdef VM_DEBUG
    SerialPrint("Signal Power: %d\n", _signalPwr);
#endif

    if (_signalPwr >= 2 && _signalPwr <= 10)
      lcd.print(char(3));
    else if (_signalPwr >= 11 && _signalPwr <= 20)
      lcd.print(char(4));
    else if (_signalPwr >= 21 && _signalPwr <= 31)
      lcd.print(char(5));
    else
      lcd.print("x");
  }
}

// ### Send SMS function
void smsSend(String input)
{
  if (sms.available())
  { //check for SMS available
    char senderNumber[20] = {"xxxxxxxxxxx"};

    String message = input + " Approx car location: https://www.google.com/maps/place/" + g_GPRSlatitude + "," + g_GPRSlongitude;
    smsSend(senderNumber, message);
    return;
  }
}

// ### Send "I" to the device to get replied with info
void smsInfoReply()
{
  if (!g_gsmConnStatus)
    return;

  if (!sms.available()) // do we have any new message
    return;

  char senderNumber[20] = {"0"};
  sms.remoteNumber(senderNumber, 20); // get remote number
  int c = sms.read();

  if (c != 73) // "I"
  {
    sms.flush();  // wipe out the message if it does not start with "I"
    return;
  }

  char _minTemp[5], _maxTemp[5], _avgTemp[5] = {""};
  dtostrf(GetLowestUnitTemp(), 3, 1, _minTemp);
  dtostrf(GetHighestUnitTemp(), 3, 1, _maxTemp);
  dtostrf(GetTemperatureAverage(), 3, 1, _avgTemp);

  char buff[128];
  sprintf_P(buff, "Temp. (Min/Max/Avg): %sC / %sC / %sC, Seat Pad Status: %d, Alarm Level: %d",
            _minTemp, _maxTemp, _avgTemp, g_fsrStateChange, g_tempAlarmWarn);
  smsSend(senderNumber, buff);
}

void smsSend(char *phoneNum, String message)
{
  sms.beginSMS(phoneNum);
  sms.print(message);
  sms.endSMS();
}

// ### Keep updating temp. reading array
void UpdateTemperaturesReading()
{
    htSensors.setResolution(TEMP_DEVICE_RESOLUTION); // xxx.yy
    htSensors.setWaitForConversion(false);           // async conversion, save up to 750 ms each loop
    htSensors.requestTemperatures();                 // request temp. conversion

    for (uint8_t i = 0; i < MAX_TEMP_DEVICE; i++)
      g_tempSensorRead[i] = htSensors.getTempCByIndex(i);
}

// ### Get unit temperature
float GetTemperatureUnit(uint8_t deviceIndex)
{
  float _unitTemp = 0.0F;
  if (lround(g_tempSensorRead[deviceIndex]) != DEVICE_DISCONNECTED)
  {
    _unitTemp = g_tempSensorRead[deviceIndex];
    return _unitTemp;
  }
  return DEVICE_DISCONNECTED;
}

// ### Calculate average temp. of available temp. units
float GetTemperatureAverage()
{
  float _tempSum = 0.0F;
  for (uint8_t i = 0; i < MAX_TEMP_DEVICE; i++)
  {
    if (lround(g_tempSensorRead[i]) != DEVICE_DISCONNECTED)
      _tempSum += g_tempSensorRead[i];
  }

  _tempSum = _tempSum / (float)g_htSensorsCount;
  return _tempSum;
}

// ### Debug, print temp. mem alloc address
void PrintBusDevicesAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < MAX_TEMP_DEVICE_ADDR; i++)
  {
    if (deviceAddress[i] < 16)
      Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
  Serial.println();
}

// ### Set LOW/HIGH temperatures for temp. units
void SetTemperatureAlarms()
{
  for (uint8_t i = 0; i < MAX_TEMP_DEVICE; i++)
  {
    htSensors.setLowAlarmTemp(&*g_tempSensors[i], g_tempSensorAlarms[i][0]);
    htSensors.setHighAlarmTemp(&*g_tempSensors[i], g_tempSensorAlarms[i][1]);
  }
}

int8_t GetTemperatureAlarmLow(uint8_t deviceIndex)
{
  uint8_t _idx = deviceIndex;
  return htSensors.getLowAlarmTemp(&*g_tempSensors[_idx]);
}

int8_t GetTemperatureAlarmHigh(uint8_t deviceIndex)
{
  uint8_t _idx = deviceIndex;
  return htSensors.getHighAlarmTemp(&*g_tempSensors[_idx]);
}

void PrintAlarms()
{
  for (uint8_t i = 0; i < MAX_TEMP_DEVICE; i++)
  {
    uint8_t tempHigh = htSensors.getHighAlarmTemp(&*g_tempSensors[i]);
    uint8_t tempLow = htSensors.getLowAlarmTemp(&*g_tempSensors[i]);
    SerialPrint("Temp Sensor %d alarms (Min/High): %dC/%dC\n", i + 1, tempLow, tempHigh);
  }
}

// ### Action to take for temp. alarm
void AlarmHandler()
{
  uint8_t _deviceAlarmCnt = 0;
  if (GetAlarmDevice() > -1)
    _deviceAlarmCnt++;

  if (_deviceAlarmCnt > 0)
  {
    if (GetTemperatureAverage() >= g_tempSensorAlarms[0][1] - 1)
    {
      g_tempAlarmWarn = AlarmStatus::HIGH_ALARM;
#ifdef VM_DEBUG
      SerialPrint("HIGH ALARM: %d: %f\n", g_tempAlarmWarn, GetTemperatureAverage());
#endif
      return;
    }

    if (GetTemperatureAverage() <= g_tempSensorAlarms[0][0] + 1.0)
    {
      g_tempAlarmWarn = AlarmStatus::LOW_ALARM;
#ifdef VM_DEBUG
      SerialPrint("LOW ALARM: %d: %f\n", g_tempAlarmWarn, GetTemperatureAverage());
#endif
      return;
    }
  }
  else
  {
    g_tempAlarmWarn = AlarmStatus::NO_ALARM;
    digitalWrite(rLedPin, LOW);
    //virtualWrite(V5, LOW);
  }
}

float GetHighestUnitTemp()
{
  for (uint8_t i = 0; i < MAX_TEMP_DEVICE; i++)
  {
    float _unitTemp = GetTemperatureUnit(i);
    if (_unitTemp > g_MaxTemp)
      g_MaxTemp = _unitTemp;
  }
  return g_MaxTemp;
}

float GetLowestUnitTemp()
{
  for (uint8_t i = 0; i < MAX_TEMP_DEVICE; i++)
  {
    float _unitTemp = GetTemperatureUnit(i);
    if (_unitTemp < g_MinTemp)
      g_MinTemp = _unitTemp;
  }
  return g_MinTemp;
}

int8_t GetAlarmDevice()
{
  for (uint8_t i = 0; i < MAX_TEMP_DEVICE; i++)
  {
    uint8_t *_deviceIndexAddr = &*g_tempSensors[i];
    if (htSensors.hasAlarm(_deviceIndexAddr))
      return i;
  }
  
  return -1;
}

void HeartBeatPrint()
{
  if (millis() - g_lastBeatPrint >= 750UL) // beep beep.., timer set to 100, total 850
  {
    lcd.setCursor(10, 0);
    g_lastBeatPrint = millis();

    char _heartSymbol = char(1);
    if (g_printBeat)
      lcd.print(_heartSymbol);
    else
      lcd.print(char(32));

    g_printBeat = !g_printBeat;
  }
}

void PinsInit()
{
  //setup door simulation pin
  pinMode(doorPin, INPUT_PULLUP);

  pinMode(fsrPin, INPUT);

  // set LED pin to output mode
  pinMode(rLedPin, OUTPUT);
  pinMode(yLedPin, OUTPUT);
  pinMode(bLedPin, OUTPUT);

  pinMode(btnPin, INPUT);

  // all LED indicator on startup
  digitalWrite(rLedPin, HIGH);
  digitalWrite(yLedPin, HIGH);
  digitalWrite(bLedPin, HIGH);

  // setup motion sensor
  pinMode(motionPin, INPUT);
  digitalWrite(motionPin, LOW);

  // setup buzzer
  pinMode(buzzerPin, OUTPUT);
}

void GetSensorsVerify()
{
  g_htSensorsCount = htSensors.getDeviceCount();
  /*if (g_htSensorsCount == MAX_TEMP_DEVICE)
    return; */
  for (uint8_t i = 0; i < MAX_TEMP_DEVICE; i++)
  {
    if (!htSensors.getAddress(&*g_tempSensors[i], i))
    {
      uint8_t _rowNum = i + 1;
      if (i > 0)
        lcd.setCursor(0, _rowNum);

      char _buff[21];
      sprintf_P(_buff, "Temp. Sensor %d fault", _rowNum);
      lcd.print(_buff);
      delay(3000);
      lcd.clear();

#ifdef VM_DEBUG
      Serial.print(_buff);
#endif
    }
  }
}

BLYNK_CONNECTED() // runs every time Blynk connection is established
{
  Blynk.notify("Blynk connected with Child Rescue device!");
}

BLYNK_DISCONNECTED() // runs every time Blynk connection is lost
{
  Blynk.notify("Blynk is gone, reconnecting..");
}

void Blynk_Delay(unsigned long milli)
{
  unsigned long end_time = millis() + milli;
  while (millis() < end_time)
  {
    if (Blynk.connected())
    {
      Blynk.run();
    }
    yield();
  }
}

void virtualWrite(uint8_t virtualPin, uint8_t val)
{
  uint8_t _val = val == 0x01 ? ON : OFF;
  Blynk.virtualWrite(virtualPin, _val);
}

bool BlynkNotify(const char* input)
{
  if (!Blynk.connected())
    return false;

  Blynk.notify(input);
  return true;
}

BLYNK_READ(V0) // Avergae Temp. Data
{
  float _avg = GetTemperatureAverage();
  Blynk.virtualWrite(V0, _avg);
}

BLYNK_WRITE(V2) { // Temp. Display Button
  g_btnState = param.asInt();
  Blynk.virtualWrite(V2, g_btnState);
}

BLYNK_READ(V3) // Unit Temp. Display
{
  uint8_t _num = g_tempDisplayNum;
  char buff[64];
  sprintf_P(buff, "                             Temp. Unit %d", _num + 1);
  Blynk.setProperty(V3, "label", buff);
  Blynk.virtualWrite(V3, GetTemperatureUnit(_num));
}

void HM10Reset()
{
#ifdef VM_DEBUG
  Serial.print("AT+RESET");
#endif
  BLELink.print("AT+RESET");
#ifdef VM_DEBUG
  Serial.print(BLELink.read());
#endif
  delay(300);
}

void PlayNoiseAlarm()
{
  // Whoop up
  for (int hz = 400; hz < 1000; hz++)
  {
    tone(buzzerPin, hz, 50);
    //delay(5); // TODO: fix to no delay later
  }
  noTone(buzzerPin);

  // Whoop down
  for (int hz = 1000; hz > 400; hz--)
  {
    tone(buzzerPin, hz, 50);
    //delay(5); // TODO: fix to no delay later
  }
  noTone(buzzerPin);
  #ifdef VM_DEBUG
  Serial.println("PLAYED!");
  #endif
}

I think you should have to stage timers because you can’t start more than one call at same time.

Tried, did not help to resolve the main problem. it helped to sort problem or irregular timers interrupting each other, however it worked well in general before. Main problem begins when Blynk connects. before it connects the log prints super fast, when it connects it slows down so much I can count number of printed logs.

Anyone?