Strange behavior in my project

@Dmitriy @vshymanskyy
Dear Sirs,
I have observed a strange behavior in one of my projects. More precisely, my project (that has the latest 0.4.3 library) and I use the latest Android app (I did not test it with the very new released a few hours ago), I running as it should for many hours 3-5 and then it seems freezed and stay in this stage. If I stop running this project (using the appropriate way in the Android app) and leave it “offline” for let say one minute, then if I run it again (from Android app) it behave again correctly…!
What do you think?
Of course, the sketch and project at Android app is at your disposal if you need it.

Thanks and Best Regards,
Mike Kranidis

Hello. You have to find out where exactly problem. Is that hardware? Is that connection? Etc.

Dear @Dmitriy,
For sure it is not hardware problem because I tested 3 different same type hardware. It is ESP8266 based standard 4MB. The Internet connection is fairly stable and the other two running projects seems to be running fine.
Now regarding the software (sketch), if you want to see it I can copy and paste here (when I will have access to the source file).
I treat me as non newbie (at least for BLYNK) so I think there are not mistakes in the sketch.

For these reasons I drop this note to you to let you know for possible App bug (or library bug). The very strange thing is, if I stop the project wait for a minute and run it again, everything seems normal…
I don’t know…

Thanks and Best Regards,
Mike Kranidis

Does your app always opened and active?

You mean the BLYNK Android app? if yes, YES it is running constantly in both of my smartphones.

It is launched for hours?

The BLYNK Android app is running all the time to my both smartphones.
The projects sketch is running (from the last update) about 11 hours but I have tested in the past days leaving to run for many hours observing the reported problem.
Just to clarify that starting the hardware from power off to on the “problem” is coming after 4-5 hours…

What do you think?

Thanks and Best Regards,
Mike Kranidis

Any chance to reproduce with local server?

The problem is that I haven’t setup local server. I have to plan this for various reasons…
Dmitriy, after the last update on the Android app, (I think two hours ago) the reported problem didn’t appear (at least yet). I will record a video when / if the problem reappear to show you exactly the problem. Till then need patience…

Thanks and Best Regards,
Mike Kranidis

Ok. Cause I still do not understand what exactly stop working - app or hard.

Dmitriy, first of all I thank you for the time spend in this reported problem.
I really believe that this is not hardware related for two reasons:

  1. I tested 3 same hardwares with the reported problem in all 3 !
  2. I think, the stop running / 1 minute stay at stop / start running (all of these at Android app not at the hardware) and then having working fine, this indicate only app or general speaking, software related problem.

Thanks and Best Regards,
Mike Kranidis

We have 3 ways to go. Build with log or local server or both :slight_smile:. By the way do you have iPhone to test?

@BlynkAndroidDev could you please provide latest log build?

(Still running without the reported problem in the new Android app…)
no iPhone available sorry…
If it is necessary I can setup (with your help) local server, I have a couple RPi3 hanging around :wink:

Thanks and Best Regards,
Mike Kranidis

I have a video showing the problem.
Please see it.
ONLY one comment, it needs more than one minutes (two or three) at not running in order to get back at normal work. I did not touch anything on the hardware side…

https://drive.google.com/file/d/0B2CF9DJ_Dc8dSHVGdWh4Qy1SQVE/view?usp=drivesdk

You comments are very welcome!

Thanks and Best Regards,
Mike Kranidis

But there are clear message that your device was disconnected :slight_smile:.

yes, that is true, but how can explain the fact that after 2-3 minutes the project go off running and back on and started again ( this will last for another 2-3-4 hours and back the problem)…

I don’t know

See also this video

https://drive.google.com/file/d/0B2CF9DJ_Dc8dakktakx6c3pzUjQ/view?usp=drivesdk

On video I see that hour hardware tries to connect and drops connection few times during this attempts (due to repeated “Device offline” messages). Why this happen - I don’t know. It could be hardware, code, weak wireless signal. You have to investigate/debug your code :wink:.

Are you trying to make too many virtualWrite calls at once on the poor little ESP8266?

I get these same issues on the same hardware if I make more than 8 virtualWrites without spacing them out 100ms apart.

Could we look at your code?

@Dmitriy

Yes sure you can see my sketch.
It is here: The sketch is running at ESP8266 Based on ESP-12F from this little device { http://www.electrodragon.com/product/wifi-iot-relay-board-based-esp8266/ }
Thanks in advance.

/// PRE-RELEASE Need some more testing / checking finalising etc ///
/// #define BLYNK_DEBUG // Optional, this enables lots of prints ///
#define WellcomeLine2 "Ver. d0.7"
#define Author "Mike Kranidis"
#define Project "V LAB Oven Control"
/// Vermantia LAB Full Oven Control ///
/// (C) 2016-2017 Mike Kranidis ///
/// Latest change at 03/01/2017 ///
/// #define BLYNK_PRINT Serial ///
/// GPIO14 <==> DS18B20 ///
/// GPIO13 <==> Relay1 ///
/// GPIO12 <==> Relay2 ///
/// WeMos ESP-12E matching ///
/// D0 <==> GPIO16 /// HARDWARE_LED 16
/// D1 <==> GPIO05 /// ( SCL )
/// D2 <==> GPIO04 /// ( SDA )
/// D3 <==> GPIO00 /// ( 10k Pull-up )
/// D4 <==> GPIO02 /// ( WeMos 10k Pull-up, BUILTIN_LED )
/// D5 <==> GPIO14 /// ( SCK ) 4 X DS18B20
/// D6 <==> GPIO12 /// ( MISO ) Relay2 Lower Heater activate on HIGH
/// D7 <==> GPIO13 /// ( MOSI ) Relay1 Upper Heater activate on HIGH
/// D8 <==> GPIO15 /// ( 10k Pull-down ) 
/// All IO have interrupt/pwm/I2C/one-wire supported(except D0)

/// Blynk related setup ///
/// Blynk color definition
/// http://www.rapidtables.com/web/color/RGB_Color.htm ///
#define GREEN     "#23C48E"
#define BLUE      "#04C0F8"
#define YELLOW    "#ED9D00"
#define RED       "#D3435C"
#define DARK_BLUE "#5F7CD8"
#define BLACK     "#000000"
#define WHITE     "#FFFFFF"

/// Blynk related setup ///
/*
 * V0 terminal widget with "Display" label
 * 
 * V1 virtual switch for activate (start) or deactivate (stop) the Oven and the  LED's V1
 * 
 * V2 virtual switch for activate ESP diagnostics and printing @ rerminal screen
 * 
 * V3 virtual led1 widget showing the status of upper heater (resistor). When lit the heater is in action V3
 *
 * V4 virtual led2 widget showing the status of lower heater (resistor). When lit the heater is in action V4
 *
 * V11 Probe01 DS18B20 temperature sensor on History Graph widget on V11
 * 
 * V12 Probe02 DS18B20 temperature sensor on History Graph widget on V12
 * 
 * V13 Probe03 DS18B20 temperature sensor on History Graph widget on V13
 * 
 * V14 Probe04 DS18B20 temperature sensor on History Graph widget on V14
 * 
 * NO THIS BUTTON REMOVED V20 virtual button for terminal printing on if true or off if false 
 * 
 * V21 RUNning virtual LED
 * 
 * V22 Slider Widget for setting Oven temperature in the range of 25 ~ 65 Celsius degrees   V22 
 * 
 * V23 Value Display Widget to show the selected temperature V23
 *
 * V24 Slider Widget for setting Oven EMERGENCYTEMP (for testing, can removed then) V24
 * 
 * V25 Used to keep timeZone value and to have it across restart ( due to Blynk.syncAll() ) 
 * 
 * V26 PIN_UPTIME UPTIME on Value Display widget on V26
 * 
 *  V27 Value Display Widget to show the selected temperature V27
 */

#include <ESP8266WiFi.h>

/// OTA dependencies ///
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

/// WiFiManager dependencies ///
#include <DNSServer.h>            //Local DNS Server used for redirecting all requests to the configuration portal
#include <ESP8266WebServer.h>     //Local WebServer used to serve the configuration portal
#include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager WiFi Configuration Magic

/// blynk dependencies ///
#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space
/// it is used above /// #include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h> 

/// NTP dependencies and declarations///
#include <TimeLib.h>
/// it is used above /// #include <ESP8266WiFi.h>
/// it is used above /// #include <WiFiUdp.h>
// NTP Servers:
static const char ntpServerName[] = "gr.pool.ntp.org";
int timeZone = 2;     /// Greek European Time
WiFiUDP Udp;
unsigned int localPort = 8888;  // local port to listen for UDP packets
time_t getNtpTime();

/// DS18B20 temperature sensor dependencies and declarations///
/*-----( Import needed libraries )-----*/
// Get 1-wire Library here: http://www.pjrc.com/teensy/td_libs_OneWire.html
#include <OneWire.h>

//Get DallasTemperature Library here:  http://milesburton.com/Main_Page?title=Dallas_Temperature_Control_Library
#include <DallasTemperature.h>

/*-----( Declare Constants and Pin Numbers )-----*/
#define ONE_WIRE_BUS_PIN 14

/*-----( Declare objects )-----*/
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS_PIN);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

/*-----( Declare Variables )-----*/
// Assign the addresses of your 1-Wire temp sensors.
// See the tutorial on how to obtain these addresses:
// http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html
/// lab temperature sensores 1 - 4 ///
DeviceAddress Probe01 =   { 0x28, 0xFF, 0xCF, 0xD7, 0x61, 0x16, 0x03, 0x28 }; /// in the format: 0x28, 0xFF, 0x05, 0x40, 0x51, 0x16, 0x04, 0x8D

DeviceAddress Probe02 =   { 0x28, 0xFF, 0xE0, 0x8A, 0x61, 0x16, 0x03, 0xFA };

DeviceAddress Probe03 =   { 0x28, 0xFF, 0x9E, 0x1D, 0x62, 0x16, 0x03, 0xB6 };

DeviceAddress Probe04 =   { 0x28, 0xFF, 0xA4, 0xFB, 0x61, 0x16, 0x03, 0x2B };

/// Variables to hold the temperatures you retrieve via temperature sensors Probe01 .. Probe04
float tempC1, tempC2, tempC3, tempC4, tempC5; 
float tempC1old = 40.0, tempC2old = 40.0, tempC3old = 40.0, tempC4old = 40.0;

/// Variables that hold the slider value and the converted to float value ( tempSetting = tempSlider/10 )
int tempSlider;
float tempSetting;

/// Variables that hold the tempoffset in Celsius degrees that the temeperature can overpass the tempSetting
float tempOffset = 0.60;

/// ovenStatus boolean variable true means we need Oven to get action false means no Oven action ///
bool ovenStatus;

/// EMERGENCYTEMP is the maximum allowed temperature that the oven can reach. When this temperature was reached 
/// it will shut down the heaters due to deactivation of the Relay1 & Relay2.
float EMERGENCYTEMP = 70.0;

/// Relays 1,2 and initialization activated on 0 false ///
#define Relay1 13
#define Relay2 12

/// define hardware led to GPIO16
#define HARDWARE_LED 16

/// variable to control blinking at hardware led ///
boolean ledBlink = true;

/// Use Virtual pin 26 for uptime display
#define PIN_UPTIME V26

/// totalTemp keeps the mean value for all four sensors like (temp1+temp2+temp3+temp4) / 4
float totalTemp = 0;

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "AUTH CODE";

WidgetLED led0(V21); /// RUN? LED
WidgetLED led1(V3); /// Upper Heater LED
WidgetLED led2(V4); /// Lower Heater LED

/// Attach virtual serial terminal to Virtual Pin V0
WidgetTerminal terminal(V0);

/// replace with your channel's thingspeak API key,
/// String apiKey = "080ZWB36ISHGDBXG";
/// const char* server = "api.thingspeak.com";
/// WiFiClient client;

SimpleTimer timer;

/// start of WiFiManager Global Start here...  ////
WiFiManager wifiManager;

/// switch value to control if the terminal printing will be on or off if false ///
boolean termPrint = false;

/// timestamp variable to keep track of millis() unsigned long ticks = millis() / 1000;  That is for debugging printings ///
/// unsigned long timestamp;

/*
/// SimpleTimer timer function, check each 5 minutes for the connection. If you lost it then it is doing ESP.reset() ///
void connCheck() {
  if(!wifiManager.autoConnect("AutoConnectAP")) {
    Serial.println("failed to connect and hit timeout");
    delay(1000);
    //reset and try again, or maybe put it to deep sleep
    ESP.reset();
    delay(5000);
  }   
}
*/

/// START of SimpleTimer timer activating function blinkLedWidget ///
void blinkLedWidget()
{
  if (led0.getValue()) {
    led0.off();
    ///BLYNK_LOG("LED1: off");
  } else {
    if(WiFi.RSSI() < -83){
    Blynk.setProperty(V21, "color", RED);
    }
  else if(WiFi.RSSI() > -57){
    Blynk.setProperty(V21, "color", GREEN);
    }
  else{
    Blynk.setProperty(V21, "color", YELLOW);
    }
    led0.on();
    ///BLYNK_LOG("LED0: on");
  }

/// put the routine here to blink HARDWARE_LED gp 16 each second ///
  if (ledBlink) { 
    digitalWrite(HARDWARE_LED, !(digitalRead(HARDWARE_LED))); 
    }
}
/// END of SimpleTimer timer activating function blinkLedWidget ///

/// START of diagnostics function ///
void diagnostics()
{
   /// diagnostics print here ///
      /// termPrint=false; /// shall I implement in this sketch ???
      terminal.printf("\nBlynk %s / %s / %s\n%s\n", BLYNK_VERSION, Author, WellcomeLine2, Project);
      /// terminal.println(WellcomeLine2);
      // terminal.println(Version);
      /// terminal.println(Project);
      terminal.print("Last RST?: ");
      terminal.println (ESP.getResetReason());
      /// not working /// terminal.printf("Last RST?: %s \n", ESP.getResetReason());
      String chipID = String(ESP.getChipId(), HEX);
      char charChipID[10];
      chipID.toCharArray(charChipID, sizeof(charChipID));
      terminal.printf("ESP ID: %d / in HEX: %s\n", ESP.getChipId(),charChipID);
      terminal.printf("ESP free heap? : %d \n", ESP.getFreeHeap());
      terminal.printf("WiFi Signal:%ddBm / IP:", WiFi.RSSI());
      terminal.println(WiFi.localIP());

      ///terminal.print("ESP flash chip frequency? : ");
      ///terminal.println(ESP.getFlashChipSpeed()); /// returns the flash chip frequency, in Hz.
      // Ensure everything is sent
      terminal.flush();
}
/// END of diagnostics function ///

/// START of clock (RTC) function with printing ///
void clockDisplay()
{
  // You can call hour(), minute(), ... at any time
  // Please see Time library examples for details

  /// String currentTime = String(hour()) + ":" + minute() + ":" + second();
  /// String currentDate = String(day()) + "/" + month() + "/" + year();


  /// s for second, m for minute, h for hour, d for day, M for month ///
  String s, m, h, d, M;

  if (second() < 10) { s = "0" + String(second()); } 
  else { s = String(second()); }

  if (minute() < 10) { m = "0" + String(minute()); } 
  else { m = String(minute()); }

  if (hour() < 10) { h = "0" + String(hour()); } 
  else { h = String(hour()); }

  if (day() < 10) { d = "0" + String(day()); } 
  else { d = String(day()); }

  if (month() < 10) { M = "0" + String(month()); } 
  else { M = String(month()); }

  String currentTime = String(h) + ":" + m + ":" + s;
  String currentDate = String(d) + "/" + M + "/" + year();

  ///terminal.print("Current time: ");
  if(termPrint) terminal.print(currentDate);
  if(termPrint) terminal.print(" ");
  ///terminal.println();
  if(termPrint) terminal.println(currentTime);
  ///terminal.print(" ");
  // Ensure everything is sent
  if(termPrint) terminal.flush();
}
/// END of clock (RTC) function with printing ///

void sendNTPpacket(IPAddress &address);

/// START of  DS18B20 temperature sensors printing Function printTemperature ///
void printTemperature(DeviceAddress deviceAddress, int Vpin)
{

float tempC = sensors.getTempC(deviceAddress);
   if (tempC == -127.00) 
   {
   ///Serial.print("Error getting temperature  ");
   terminal.println("Error getting temperature  ");
   terminal.flush();
   } 
   else
   {
   ///Serial.print(tempC);
   ///Serial.println(" °C");
   /// Send it to the server and to history widget 
   Blynk.virtualWrite(Vpin, tempC);
   if(termPrint) {
   ///terminal.printf("",);  
   ///terminal.print("Vpin:"); 
   terminal.print(Vpin); 
   terminal.print(" => T="); 
   terminal.print(tempC); 
   terminal.println("°C");
   terminal.flush();
    }
   ///Serial.print(" F: ");
   ///Serial.print(DallasTemperature::toFahrenheit(tempC));
   }
}
/// END of DS18B20 temperature sensors printing Function printTemperature ///

/// START of DS18B20 temperature sensors process Function reportTemperature() this will be running using simpletimer each ex 5 seconds 
/// also be used to update PIN_UPTIME V26 for ESP's up time also update the totalTemp value ///
void reportTemperature()
{
  clockDisplay();
  ///Serial.println();
  ///Serial.print("Number of Devices found on bus = ");  
  ///Serial.println(sensors.getDeviceCount());   
  ///Serial.print("Getting temperatures... ");  
  ///Serial.println();   
  
  // Command all devices on bus to read temperature  
  sensors.requestTemperatures();  
  ///Serial.print("Probe 01 temperature is:   ");
  printTemperature(Probe01,11); /// Probe01 holds the temperature in C for 1sr DS18B20 temperature sensor ///
  ///Serial.println();
  
  ///Serial.print("Probe 02 temperature is:   ");
  printTemperature(Probe02,12); /// Probe02 holds the temperature in C for 2nd DS18B20 temperature sensor ///
  ///Serial.println();
  
  ///Serial.print("Probe 03 temperature is:   ");
  printTemperature(Probe03,13); /// Probe03 holds the temperature in C for 3rd DS18B20 temperature sensor ///
  ///Serial.println();
  
  ///Serial.print("Probe 04 temperature is:   ");
  printTemperature(Probe04,14); /// Probe04 holds the temperature in C for 4th DS18B20 temperature sensor ///
  ///Serial.println();

/// put this inside the reportTemperature function that is simpletimer activated each 5 seconds
  // This command writes ESP's uptime in seconds to Virtual Pin (V26) PIN_UPTIME
  unsigned long ticks = millis() / 1000;
  /// presentation value reset (moduled %) each day = 86400  , week = 604800 so put this value on module ///
  ticks = ticks % 1209600;  /// modulo each 2 weeks ///
  Blynk.virtualWrite(PIN_UPTIME, ticks);

  totalTemp = (tempC1 + tempC2 + tempC3 + tempC4) / 4;
  Blynk.virtualWrite(V27, totalTemp); /// send the totalTemp value to Value Display Widget ///
 }
 /// END of DS18B20 temperature sensors process Function reportTemperature() ///


 /// START of actionOnTemperature Function take action acording the temperature this will be running using simpletimer each ex 1.5 seconds ///
 /// measure all the sensors and compare the measured value with the demanded value then start or stop the heater accordingly ///
 /// the related variables are: Relay1 with V3 LED, Relay2 with V4 LED demanting temerature tempSetting
 void actionOnTemperature()
 {
  /// Command all devices on bus to read temperature  
  sensors.requestTemperatures();
  tempC1 = sensors.getTempC(Probe01); 
  if (tempC1 == -127.00) 
   {
   tempC1 = tempC1old; /// if the measure is failed then use the old value ///
   if(termPrint) {
   terminal.println("temp1 faild ");
   terminal.flush();
   }
   } 
   else
   {
   tempC1old = tempC1;
   }
  tempC2 = sensors.getTempC(Probe02); /// if the measure is failed then use the old value ///
  if (tempC2 == -127.00) 
   {
   tempC2 = tempC2old;
   if(termPrint) {
   terminal.println("temp2 faild ");
   terminal.flush();
     }
   } 
   else
   {
   tempC2old = tempC2;
   }
  tempC3 = sensors.getTempC(Probe03); /// if the measure is failed then use the old value ///
  if (tempC3 == -127.00) 
   {
   tempC3 = tempC3old;
   if(termPrint) {
   terminal.println("temp3 faild ");
   terminal.flush();
     }
   } 
   else
   {
   tempC3old = tempC3;
   }
  tempC4 = sensors.getTempC(Probe04); /// if the measure is failed then use the old value ///
  if (tempC4 == -127.00) 
   {
   tempC4 = tempC4old;
   if(termPrint) {
   terminal.println("temp4 faild ");
   terminal.flush();
     }
   } 
   else
   {
   tempC4old = tempC4;
   }
   if(tempC1 > EMERGENCYTEMP || tempC2 > EMERGENCYTEMP || tempC3 > EMERGENCYTEMP || tempC4 > EMERGENCYTEMP) 
  {
  ovenStatus = false;
    digitalWrite(HARDWARE_LED, LOW); /// switch off the internal LED
    /// switch off Relay1, Relay2, led1, led2 ///
    digitalWrite(Relay1, LOW); /// deactivate the Relay1
    digitalWrite(Relay2, LOW); /// deactivate the Relay2
    led1.off(); led2.off();
  /// termPrint=false;
  Blynk.virtualWrite(V1, 0);
  terminal.println("*********************");
  terminal.println("* SOS TEMP. SHUTOFF *");
  terminal.println("*********************");
  terminal.println("* reactivate PWR/sw *");
  terminal.println("*********************");
    terminal.flush();
  Blynk.syncVirtual(V1);
  }
  
  if(ovenStatus == true) {
  float offsetHigh = tempSetting + tempOffset;
  float offsetLow = tempSetting - tempOffset;
   if(tempC1 > offsetHigh || tempC2 > offsetHigh) 
    {
    /// we have bigger temperature that the demanded on the upper part of the oven, switch off Relay1 and LED V3 ///
    digitalWrite(Relay1, LOW); /// deactivate the Relay1
    /// LED V3 Upper Heater off
    led1.off();  
    }
  else 
    { /// we have lower temperature that the demanded on the upper part of the oven, switch on Relay1 and LED V3 ///
   if(tempC1 < offsetLow || tempC2 < offsetLow) 
    {
    digitalWrite(Relay1, HIGH); /// activate the Relay1
    /// LED V3 Upper Heater on
    ///Blynk.virtualWrite(V3, HIGH);
    led1.on();
    }
    }
   
     if(tempC3 > offsetHigh || tempC4 > offsetHigh)
      {
    /// we have bigger temperature that the demanded on the lower part of the oven, switch off Relay2 and LED V4 ///
    digitalWrite(Relay2, LOW); /// deactivate the Relay2 
    /// LED V4 lower Heater off
    ///Blynk.virtualWrite(V4, 0);  
    led2.off();
      }
  else 
    /// we have lower temperature that the demanded on the lower part of the oven, switch on Relay2 and LED V4 ///
    {
   if(tempC3 < offsetLow || tempC4 < offsetLow) 
    {
     digitalWrite(Relay2, HIGH); /// activate the Relay2
     /// LED V4 lower Heater on
     ///Blynk.virtualWrite(V4, HIGH);
     led2.on();
    }
    }
  } /// end of if(ovenStatus == true)
 } /// END of actionOnTemperature Function take action acording the temperature this will be running using simpletimer each ex 2 seconds ///


/// ===> START OF SETUP <=== ///
void setup() {
  Serial.begin(115200);
  Serial.println("Booting...");
  
  //WiFiManager
  //Local initialization. Once its business is done, there is no need to keep it around
  /// WiFiManager wifiManager;
  /// wifiManager.setConfigPortalTimeout(180);
  //fetches ssid and pass from eeprom and tries to connect
  //if it does not connect it starts an access point with the specified name
  //here  "AutoConnectAP"
  //and goes into a blocking loop awaiting configuration
  wifiManager.autoConnect("AutoConnectAP");

  //if you get here you have connected to the WiFi
  Serial.println("connected...yesss! :)");

   // Port defaults to 8266
  // ArduinoOTA.setPort(8266);

  // Hostname defaults to esp8266-[ChipID]
  // ArduinoOTA.setHostname("myesp8266");

  // No authentication by default
  // ArduinoOTA.setPassword((const char *)"123");

  ArduinoOTA.onStart([]() {
    Serial.println("Start");
  });

  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });

  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });

  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });

  ArduinoOTA.begin();
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  /// consider to use Blynk.config(auth); that is now ssid, password hard code specific ///
  /// due to WiFiManager framework the bellow credentials are not needed anymore... ///
  /// Blynk.begin(auth, ssid, password);
  Blynk.config(auth);

  while (Blynk.connect() == false) {
    // Wait until connected
    }

/// START of SimpleTimer timer Functions 

  // Check the connection  every 5 minutes (300 seconds). If not connected run 
/// TEMPORARY (?) DISABLED ///  timer.setInterval(300000L, connCheck);

  /// This blink LED function be called every 2 seconds
  timer.setInterval(2000L, blinkLedWidget);

  /// This call reportTemperature() function every 5 seconds also be used to update PIN_UPTIME V26 for ESP's up time also update the totalTemp value
  timer.setInterval(5000L, reportTemperature);
  
   /// This call actionOnTemperature() function every 1.5 seconds
  timer.setInterval(1500L, actionOnTemperature);

  /// END of SimpleTimer timer Functions

/*
  terminal.println(" "); 
  terminal.println(Author);
  terminal.println(WellcomeLine2);
  terminal.println(Project);
  terminal.print("Last RST?: ");
  terminal.println (ESP.getResetReason());
  terminal.print("ESP ID? : ");
  terminal.println (ESP.getChipId());
  // Ensure everything is sent
  terminal.flush();
*/

/// NTP related ///
  Serial.println("Starting UDP");
  Udp.begin(localPort);
  Serial.print("Local port: ");
  Serial.println(Udp.localPort());
  Serial.println("waiting for sync");
  setSyncProvider(getNtpTime);
  setSyncInterval(300);  /// set sync timer at 300 seconds = 5 minutes

  /// DS18B20 temperature sensors section ///
  Serial.print("Initializing Temperature Control Library Version ");
  Serial.println(DALLASTEMPLIBVERSION);
  
  // Initialize the Temperature measurement library
  sensors.begin();
  
 /// set the resolution to ANY bit  you like - Valid values are 9, 10, 11 or 12 bit.
/*  Resolution  Increment Time
9 bit 0.5 degrees C 93.75 mSec
10 bit  0.25 degrees C  187.5 mSec
11 bit  0.125 degrees C 375 mSec
12 bit  0.0625 degrees C  750 mSec
*/
  sensors.setResolution(Probe01, 10);
  sensors.setResolution(Probe02, 10);
  sensors.setResolution(Probe03, 10);
  sensors.setResolution(Probe04, 10);

/*
  // confirm that we set that resolution by asking the DS18B20 to repeat it back
  Serial.print("Sensor 1 Resolution: ");
  Serial.println(sensors.getResolution(Probe01), DEC); 
  Serial.println();
  Serial.print("Sensor 2 Resolution: ");
  Serial.println(sensors.getResolution(Probe02), DEC); 
  Serial.println();
  Serial.print("Sensor 3 Resolution: ");
  Serial.println(sensors.getResolution(Probe03), DEC); 
  Serial.println();
  Serial.print("Sensor 4 Resolution: ");
  Serial.println(sensors.getResolution(Probe04), DEC); 
  Serial.println();
*/

  /// initialization of Upper Heater virtual LED (V3) and 
  /// Lower Heater virtual LED (V4) virtual leds ( switch both OFF )
  ///Blynk.virtualWrite(V3, 0); Blynk.virtualWrite(V4, 0);
  led1.off(); led2.off();
  
  /// initialization of Relay1, Relay2 activate on HIGH, so we putt them on LOW
  pinMode(Relay1, OUTPUT);  /// Upper Heater Relay ///
  pinMode(Relay2, OUTPUT);  /// Lower Heater Relay ///
  digitalWrite(Relay1, LOW); /// deactivate the Relay1
  digitalWrite(Relay2, LOW); /// deactivate the Relay2
  pinMode(HARDWARE_LED, OUTPUT); /// set the hardware led GPIO pin as output
  digitalWrite(HARDWARE_LED, LOW); /// deactivate (switch off) the hardware led

  /// initialization of ovenStatus
  ovenStatus = true;
}
/// ===> END OF SETUP <=== ///

/// START of clearScreen function ///
void clearScreen() /// LCD & terinal clear ///
{
    for(int i=1; i<8; i++) {
    terminal.println();
    }
    terminal.flush();
}
/// END of crearScreen function ///

// You can send commands from Terminal to your hardware. Just use
// the same Virtual Pin as your Terminal Widget
  BLYNK_WRITE(V0)
  {
  // if you type "Marco" into Terminal Widget - it will respond: "Polo:"
  String getString = param.asStr();
  getString.trim(); /// cut off the blank spece(s) at the end of the string ///
  ///getString.toUpperCase();
  if (getString.equalsIgnoreCase("MARCO")) {
    terminal.println("You said: 'Marco'") ;
    terminal.println("I said: 'Polo'") ;
    return;
  } else if (getString.equalsIgnoreCase("Clear") || getString.equalsIgnoreCase("Cls")) {
    clearScreen();
    return;
  } else if (getString.startsWith("tz")) {
    timeZone = (getString.substring(2)).toInt();
    Blynk.virtualWrite(V25, timeZone);
    setSyncProvider(getNtpTime); /// this acting as "syncNow" !
    return;
  } else if (getString.equalsIgnoreCase("restart")) {
    terminal.println("OK I do restart !");
    terminal.flush();
    yield(); yield(); delay(500);
    ESP.restart();  
  } else if (getString.equalsIgnoreCase("Diags")) {
    ///terminal.println("You said: Diags , OK!");
    diagnostics();
    return;
  } else if (getString.equalsIgnoreCase("tpoff")) {
    terminal.println("terminal print off...");
    terminal.flush();
    termPrint = false;
    return;
  } else if (getString.equalsIgnoreCase("tpon")) {
    terminal.println("terminal print on...");
    terminal.flush();
    termPrint = true;
    return;
  } else if (getString.equalsIgnoreCase("?") || getString.equalsIgnoreCase("help")) {
    terminal.println("The regognised commands are: ");
    terminal.println("clear/cls, diags, tpoff, tpon, tz2/tz3 restart");
    terminal.flush();
    return;
  } else {
    // Send it back
    terminal.print("You said (getString): ");
    terminal.println(getString);
    terminal.print("You said : ");
    terminal.write(param.asStr(), param.getLength());
    terminal.println();
  }
  // Ensure everything is sent
  terminal.flush();
}

/// start routine for V1 virtual switch for activate (start) or deactivate (stop) the Oven ///
  BLYNK_WRITE(V1)
  {
    if (param.asInt()) {
    ovenStatus = true;
    digitalWrite(HARDWARE_LED, HIGH); /// switch on the internal LED
  termPrint=true;
    } 
    else {
    ovenStatus = false;
    digitalWrite(HARDWARE_LED, LOW); /// switch off the internal LED
    /// switch off Relay1, Relay2, led1, led2 ///
    digitalWrite(Relay1, LOW); /// deactivate the Relay1
    digitalWrite(Relay2, LOW); /// deactivate the Relay2
    led1.off(); led2.off();
  termPrint=false;
      }
  }
/// end routine for V1 virtual switch for activate (start) or deactivate (stop) the Oven ///

/*
/// start routine for terminal printing control using the termPrint boolean value  ///
  BLYNK_WRITE(V20)
  {
    if (param.asInt()) {
      termPrint=true;
      } 
    else {
    /// do nothing ///
    termPrint=false;
     }
  }
/// end of routine for manual (on demand) requesting OTA The Virtual Button SW V20 is used ///
*/

/// start routine for terminal printing control using the termPrint boolean value  ///
  BLYNK_WRITE(V2)
  {
    if (param.asInt()) {
    termPrint=false;
    diagnostics();
    } 
    else 
    {
    termPrint=true;
     }
  }
/// end of routine for manual (on demand) requesting OTA The Virtual Button SW V20 is used ///

// Every time we connect to the cloud synchronize some of the values from Widgets...
/*
BLYNK_CONNECTED() {
///  Blynk.syncVirtual(V10);
  Blynk.syncVirtual(V1); Blynk.syncVirtual(V2); Blynk.syncVirtual(V3); Blynk.syncVirtual(V4); Blynk.syncVirtual(V5); Blynk.syncVirtual(V6); Blynk.syncVirtual(V7); Blynk.syncVirtual(V8);
  Blynk.syncVirtual(V11); Blynk.syncVirtual(V12); Blynk.syncVirtual(V13); Blynk.syncVirtual(V14); Blynk.syncVirtual(V15); Blynk.syncVirtual(V16); Blynk.syncVirtual(V17); Blynk.syncVirtual(V18);
}
*/

// This function will run every time Blynk connection is established
BLYNK_CONNECTED() {
  ///if (isFirstConnect) {
    // Request Blynk server to re-send latest values for all pins
    Blynk.syncAll();

    // You can also update an individual Virtual pin like this:
    //Blynk.syncVirtual(V0);

   /// isFirstConnect = false;
  ///}
}
 
/// START of temperature SLIDER reading ///
BLYNK_WRITE(V22)
{
  tempSlider = param.asInt(); // assigning incoming value from pin V22 to a variable
  tempSetting = tempSlider / 10.0;
  Blynk.virtualWrite(V23, tempSetting); /// send the tempSetting value to TEMP SET Value Display Widget ///
  // You can also use:
  // String i = param.asStr();
  // double d = param.asDouble();
}
/// END of temperature SLIDER reading ///

/// START of EMERGENCYTEMP SLIDER reading (for testing, can removed then) ///
BLYNK_WRITE(V24)
{
  int sliderValue = param.asInt(); // assigning incoming value from pin V22 to a variable
  EMERGENCYTEMP = sliderValue / 10.0;
}
/// END of EMERGENCYTEMP SLIDER reading (for testing, can removed then) ///

// START of restoring timeZone value from server
BLYNK_WRITE(V25)
{
  timeZone = param.asInt();
  setSyncProvider(getNtpTime); /// this acting as "syncNow" !
}
// END of restoring timeZone value from server

/// ===> START OF LOOP <=== ///
void loop() {
  /// just as reminder here: mySwitch.switchOn(syscode, outletA) ; ///
  ///                        mySwitch.switchOff(syscode, outletA); ///
  ArduinoOTA.handle();
  Blynk.run();
  timer.run();
}
/// ===> END OF LOOP <=== ///

/*-------- START of NTP code ----------*/
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets

time_t getNtpTime()
{
  IPAddress ntpServerIP; // NTP server's ip address

  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  Serial.println("Transmit NTP Request");
  // get a random server from the pool
  WiFi.hostByName(ntpServerName, ntpServerIP);
  Serial.print("ntp Server Name: ");
  Serial.print(ntpServerName);
  Serial.print("  IP: ");
  Serial.println(ntpServerIP);
  sendNTPpacket(ntpServerIP);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {
      Serial.println("Receive NTP Response");
      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
    }
  }
  Serial.println("No NTP Response :-(");
  return 0; // return 0 if unable to get the time
}

// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12] = 49;
  packetBuffer[13] = 0x4E;
  packetBuffer[14] = 49;
  packetBuffer[15] = 52;
  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}
/*-------- END of NTP code ----------*/