Arduino + ESP Crashing!

Hello!
I am using an Arduino mega + ESP8266 (ESP01) to monitor and control an aquaculture system.
The system consists of three sensors (dissolved oxygen, temperature and pH) and a servo motor to control the oxygen content of the tank both manually and automatically by the value given by the user via BLYNK application. I have been encountering a problem in my control system. It crashes and requires manual resetting which is a big problem as my control system is in a remote location. According to what i understand the problem is with the esp micro controller attached to the Arduino. It freezes and stops the system from connecting to the BLYNK cloud which causes the whole system to freeze. Please be kind enough to help me out in solving this problem thank you very much!

I’ve not really heard reports of ESP-01’s freezing when being used as Wi-Fi modems for Arduinos.
The most likely causes for this type of issue is badly written code, inadequate power supply for the ESP-01 or poor wiring (is the device on a breadboard?).

I guess you could try upgrading the AT firmware of the ESP-01 if you believe that it’s none of these issues.

Pete.

Hi Pete,
I have been using the the latest firmware version as said on the BLYNK website
( AT version:1.1.0.0(May 11 2016 18:09:56)SDK version:1.5.4(baaeaebb)) on my ESP_01.
There were power issues at the start of the project and got them sorted out. But the system starts to freeze every now or then , the reason for this is unknown. I will recheck the wiring again but i’m pretty sure the wiring has nothing to do with it because one the system is reset it works for a while and then freezes because the ESP stops getting connected to the internet.
Is it possible to solve this problem using the concept of watchdogs on the esp8266 have you got any idea about this chip resetting technique.
Please be kind enough to help me out.Hoping to hear from you soon.
Thank you very much,

Moh

That doesn’t sound like the latest version. See AT in this link:

Is there any reason why you aren’t using a NodeMCU?

Pete.

Hi,
I’m not using NodeMCU because at first i was not sure about the number of sensors i wanted to add to the system and hence i decided to use the combined ESP_01 & Arduino Mega system. Do you think this is bad?
I will try updating the firmware version to the latest one. But according to what i found on BLYNK documents they suggested to use this version.
Thank you very for the quick response. Hoping to hear from you soon.

Moh

Pete.

1 Like

Thank you very much for this important piece of information regarding board selection. I will be using BLYNK for another one of my projects which will be a mushroom greenhouse monitoring and control i will be using a Wemos D1 it sounds quite interesting to me.
But for this project i have to figure out a way to solve this problem. As for what i understand from what you have told me previously. Its either something to do with power or wiring!.
I have to check them.Please guide me if i have any issues.
Thanks a lot for helping me out.

Moh

The Wemos D1 isn’t the board I recommended in the topic I linked to. It’s the Wemos D1 Mini or Wemos D1Mini Pro that I recommended.

The Wemos D1 is a very different board.

You seem to have rejected the suggestion that your issues may be caused by badly written code. Any reason for this?

Pete.

Hi Pete,

I’ll be checking my code thoroughly today and see if there are any bugs in it. And get to you soon. I have already checked my code a couple of times and could not find any major errors everything seems fine and compiles without any warnings or errors.
Noted with thanks about the micro controller Wemos D1 Mini.

Best regards,
Moh

Just because your code doesn’t have any bugs and compiles without any errors doesn’t mean that it’s written in a way that is appropriate for use with the Blynk library. The biggest error people make is having too much stuff in the void loop. A good void loop from a Blynk point of view looks like this:

void loop()
{
  Blynk.run();
  timer.run();
}

But, even with a perfect void loop, it’s still possible to create issues by having simultaneous timed functions, or functions that try to do too much and starve the Blynk library of processor time.

Pete.

1 Like

Hi Pete,

This piece of advice means a lot to me and i didn’t know this. My void loop has a lot of code!. I would like to ask if its okay to create a separate loop outside the void loop and place my code in it leaving the void loop like :void loop()
{
Blynk.run();
timer.run();
}
Will this change to the code help improve it. Thank you very much!

Best!
Moh

If you read the “keep your void loop clean” it explains how to create functions that are called using a timer.
However, you have to give some thought to how long your timed functions will take to execute, and what impact that will have on the Blynk library functions. If you need more than one timed function then ensure that you aren’t trying to call both functions simultaneously, or in a way where the two timers will attempt to overlap frequently (one every second, and another every two seconds for example).

A lot has been written about this subject in the forum, so maybe spend a bit more time reading.

Pete.

1 Like
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4);



//pH 

#define SensorPin A0            //pH meter Analog output to Arduino Analog Input 0
#define Offset 0.00            //deviation compensator 
#define LED 13
#define samplingInterval 20
#define printInterval 800
#define ArrayLenth  40    //times of collection
int pHArray[ArrayLenth];   //Store the average value of the sensor feedback
int pHArrayIndex=0;    
static unsigned long samplingTime = millis();
static unsigned long printTime = millis();
static float pHValue,voltage;



//temperature libraries

#include <OneWire.h>
#include <DallasTemperature.h>

// Signal plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

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



#include <avr/pgmspace.h>
#include <EEPROM.h>

#define DoSensorPin  A1  //dissolved oxygen sensor analog output pin to arduino mainboard
#define VREF 5000    
float doValue;      //current dissolved oxygen value, unit; mg/L
float temperature = 25; 

#define EEPROM_write(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) EEPROM.write(address+i, pp[i]);}
#define EEPROM_read(address, p)  {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp[i]=EEPROM.read(address+i);}

#define ReceivedBufferLength 20
char receivedBuffer[ReceivedBufferLength+1];    // store the serial command
byte receivedBufferIndex = 0;

#define SCOUNT  30           // sum of sample point
int analogBuffer[SCOUNT];    //store the analog value in the array, readed from ADC
int analogBufferTemp[SCOUNT];
int analogBufferIndex = 0,copyIndex = 0;

#define SaturationDoVoltageAddress 12          //the address of the Saturation Oxygen voltage stored in the EEPROM
#define SaturationDoTemperatureAddress 16      //the address of the Saturation Oxygen temperature stored in the EEPROM
float SaturationDoVoltage,SaturationDoTemperature;
float averageVoltage;

const float SaturationValueTab[41] PROGMEM = {      //saturation dissolved oxygen concentrations at various temperatures
14.46, 14.22, 13.82, 13.44, 13.09,
12.74, 12.42, 12.11, 11.81, 11.53,
11.26, 11.01, 10.77, 10.53, 10.30,
10.08, 9.86,  9.66,  9.46,  9.27,
9.08,  8.90,  8.73,  8.57,  8.41,
8.25,  8.11,  7.96,  7.82,  7.69,
7.56,  7.43,  7.30,  7.18,  7.07,
6.95,  6.84,  6.73,  6.63,  6.53,
6.41,
};





//BLYNK


/*************************************************************
  Download latest Blynk library here:
    https://github.com/blynkkk/blynk-library/releases/latest

  Blynk is a platform with iOS and Android apps to control
  Arduino, Raspberry Pi and the likes over the Internet.
  You can easily build graphic interfaces for all your
  projects by simply dragging and dropping widgets.

    Downloads, docs, tutorials: http://www.blynk.cc
    Sketch generator:           http://examples.blynk.cc
    Blynk community:            http://community.blynk.cc
    Follow us:                  http://www.fb.com/blynkapp
                                http://twitter.com/blynk_app

  Blynk library is licensed under MIT license
  This example code is in public domain.

 *************************************************************
  WARNING!
    It's very tricky to get it working. Please read this article:
    http://help.blynk.cc/hardware-and-libraries/arduino/esp8266-with-at-firmware

  This example shows how value can be pushed from Arduino to
  the Blynk App.

  NOTE:
  BlynkTimer provides SimpleTimer functionality:
    http://playground.arduino.cc/Code/SimpleTimer

  App project setup:
    Value Display widget attached to Virtual Pin V5
 *************************************************************/

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial


#include <ESP8266_Lib.h>
#include <BlynkSimpleShieldEsp8266.h>
#include <Servo.h>


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

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "OnePlus6";                          //AIS 4G Pocket Wifi_320611                          //devilman1069
char pass[] = "devilman1069";                     //36320611                                           //OnePlus6

// Hardware Serial on Mega, Leonardo, Micro...
#define EspSerial Serial1

// or Software Serial on Uno, Nano...
//#include <SoftwareSerial.h>
//SoftwareSerial EspSerial(2, 3); // RX, TX

// Your ESP8266 baud rate:
#define ESP8266_BAUD 115200

ESP8266 wifi(&EspSerial);

int a=0;
int y=0;
int x=0;
int b=0;
BLYNK_WRITE(V1)
{
  int pinValue = param.asInt(); // assigning incoming value from pin V1 to a variable
  a=pinValue;
  //required dissolved oxygen value from the user
  // process received value
}
Servo servo;

BLYNK_WRITE(V3)
{
 int servo = param.asInt(); //manual control for the servo motor to control the level of 
 b=servo;                   //oxygen in the pond
}

BlynkTimer timer;
//MILLIS
// This function sends Arduino's up time every second to Virtual Pin (5).
// In the app, Widget's reading frequency should be set to PUSH. This means
// that you define how often to send data to Blynk App.
//APP DISPLAY FUNCTIONS
//void myTimerEvent()
//{
  // You can send any value at any time.
  // Please don't send more that 10 values per second.
  //Blynk.virtualWrite(V5, millis() / 1000);
//}


//TEMPERATURE

void mytemp()
{
  // You can send any value at any time.
  // Please don't send more that 10 values per second.
  float temp=sensors.getTempCByIndex(0);
  Blynk.virtualWrite(V6,temp);
}


//DO 

void mydo()
{
  // You can send any value at any time.
  // Please don't send more that 10 values per second.
 float  do1=doValue;
  Blynk.virtualWrite(V7,do1);
}


//pH_value

void mypH()
{
  // You can send any value at any time.
  // Please don't send more that 10 values per second.
  float pH=pHValue;
  Blynk.virtualWrite(V8,pH);
}


int led_pin=12;


void setup()
{
Serial.begin(9600);
lcd.init();     
lcd.backlight();  
sensors.begin();
pinMode(LED,OUTPUT);
pinMode(led_pin,INPUT);  
pinMode(DoSensorPin,INPUT);
readDoCharacteristicValues(); 
EspSerial.begin(ESP8266_BAUD); // Set ESP8266 baud rate
delay(100);
Blynk.begin(auth, wifi, ssid, pass);
  // You can also specify server:
  //Blynk.begin(auth, wifi, ssid, pass, "blynk-cloud.com", 80);
  //Blynk.begin(auth, wifi, ssid, pass, IPAddress(192,168,1,100), 8080);

  // Setup a function to be called every second
//  timer.setInterval(1000L, myTimerEvent);
  timer.setInterval(10000L, mytemp);
  timer.setInterval(10000L, mydo);
  timer.setInterval(10000L, mypH);
  lcd.setCursor(0,0);

  servo.attach(9);
  servo.write(x);
  
//lcd.print("millis:");
// lcd.setCursor(1,7);
 //lcd.print(millis());
//
 //lcd.setCursor(0,1);
 //lcd.print("D:");
}

void loop()
{
  Blynk.run();
  timer.run();
  sensors.requestTemperatures();





  
   static unsigned long analogSampleTimepoint = millis();
   if(millis()-analogSampleTimepoint > 30U)     //every 30 milliseconds,read the analog value from the ADC
   {
     analogSampleTimepoint = millis();
     analogBuffer[analogBufferIndex] = analogRead(DoSensorPin);    //read the analog value and store into the buffer
     analogBufferIndex++;
     if(analogBufferIndex == SCOUNT) 
         analogBufferIndex = 0;
   }
   
   static unsigned long tempSampleTimepoint = millis();
   if(millis()-tempSampleTimepoint > 500U)  // every 500 milliseconds, read the temperature
   {
      tempSampleTimepoint = millis();
      //temperature = readTemperature();  // add your temperature codes here to read the temperature, unit:^C
       sensors.requestTemperatures();
      temperature =sensors.getTempCByIndex(0);
   }
   
   static unsigned long printTimepoint = millis();
   if(millis()-printTimepoint > 1000U)
   {
      printTimepoint = millis();
      for(copyIndex=0;copyIndex<SCOUNT;copyIndex++)
      {
        analogBufferTemp[copyIndex]= analogBuffer[copyIndex];
      }
      averageVoltage = getMedianNum(analogBufferTemp,SCOUNT) * (float)VREF / 1024.0; // read the value more stable by the median filtering algorithm
      //Serial.print(F("Temperature:"));
      //Serial.print(temperature,1);
      //Serial.print(F("^C"));
      doValue = pgm_read_float_near( &SaturationValueTab[0] + (int)(SaturationDoTemperature+0.5) ) * averageVoltage / SaturationDoVoltage;  //calculate the do value, doValue = Voltage / SaturationDoVoltage * SaturationDoValue(with temperature compensation)
      //Serial.print(F(",  DO Value:"));
      //Serial.print(doValue,2);
      //Serial.println(F("mg/L"));
      
  
 lcd.setCursor(0,0);
 lcd.print("tempt:");
// 
 lcd.setCursor(0,1);
  lcd.print("DO:");
lcd.setCursor(8,1);
  lcd.print("pH:");
  
   }
   
   if(serialDataAvailable() > 0)
   {
      byte modeIndex = uartParse();  //parse the uart command received
      doCalibration(modeIndex);    // If the correct calibration command is received, the calibration function should be called.
   }


//  static unsigned long samplingTime = millis();
//  static unsigned long printTime = millis();
//  static float pHValue,voltage;
  if(millis()-samplingTime > samplingInterval)
  {
      pHArray[pHArrayIndex++]=analogRead(SensorPin);
      if(pHArrayIndex==ArrayLenth)pHArrayIndex=0;
      voltage = avergearray(pHArray, ArrayLenth)*5.0/1024;
      pHValue = 3.5*voltage+Offset;
      samplingTime=millis();
  }
  if(millis() - printTime > printInterval)   //Every 800 milliseconds, print a numerical, convert the state of the LED indicator
  {
  //Serial.print("Voltage:");
       // Serial.print(voltage,2);
        //Serial.print("    pH value: ");
 // Serial.println(pHValue,2);
        digitalWrite(LED,digitalRead(LED)^1);
        printTime=millis();
  }
lcd.setCursor(7,0);
  lcd.print(sensors.getTempCByIndex(0));
// 
 lcd.setCursor(3,1);
 lcd.print(doValue,2);
 

 lcd.setCursor(11,1);
  lcd.print(pHValue);

  if (digitalRead(led_pin) == LOW)
{
  if (doValue<a-1.5 )
  {
  if(x!=0)
  
  {
    x=x-5;
    servo.write(x);
   delay (2000);
    }
    }
   
   if (doValue>a+1.5)
  {
  if( x!=90 )
  {
    x=x+5;
    servo.write(x);
    delay (2000);
    }
    }
    
   if (doValue<a+0.5 && doValue>a-0.5)
    {
     
     servo.write(x);
      }
}

     if (digitalRead(led_pin) == HIGH)
    {
        servo.write(b);
      }
Serial.print(a);
Serial.print("  ");
Serial.print(x);
Serial.print("  ");
Serial.println(doValue);

//Serial.print(void mydo());

delay (1000);
}

boolean serialDataAvailable(void)
{
  char receivedChar;
  static unsigned long receivedTimeOut = millis();
  while ( Serial.available() > 0 ) 
  {   
    if (millis() - receivedTimeOut > 500U) 
    {
      receivedBufferIndex = 0;
      memset(receivedBuffer,0,(ReceivedBufferLength+1));
    }
    receivedTimeOut = millis();
    receivedChar = Serial.read();
    if (receivedChar == '\n' || receivedBufferIndex == ReceivedBufferLength)
    {
  receivedBufferIndex = 0;
  strupr(receivedBuffer);
  return true;
    }else{
        receivedBuffer[receivedBufferIndex] = receivedChar;
        receivedBufferIndex++;
    }
  }
  return false;
}

byte uartParse()
{
    byte modeIndex = 0;
    if(strstr(receivedBuffer, "CALIBRATION") != NULL) 
        modeIndex = 1;
    else if(strstr(receivedBuffer, "EXIT") != NULL) 
        modeIndex = 3;
    else if(strstr(receivedBuffer, "SATCAL") != NULL)   
        modeIndex = 2;
    return modeIndex;
}

void doCalibration(byte mode)
{
    char *receivedBufferPtr;
    static boolean doCalibrationFinishFlag = 0,enterCalibrationFlag = 0;
    float voltageValueStore;
    switch(mode)
    {
      case 0:
      if(enterCalibrationFlag)
         Serial.println(F("Command Error"));
      break;
      
      case 1:
      enterCalibrationFlag = 1;
      doCalibrationFinishFlag = 0;
      Serial.println();
      Serial.println(F(">>>Enter Calibration Mode<<<"));
      Serial.println(F(">>>Please put the probe into the saturation oxygen water! <<<"));
      Serial.println();
      break;
     
     case 2:
      if(enterCalibrationFlag)
      {
         Serial.println();
         Serial.println(F(">>>Saturation Calibration Finish!<<<"));
         Serial.println();
         EEPROM_write(SaturationDoVoltageAddress, averageVoltage);
         EEPROM_write(SaturationDoTemperatureAddress, temperature);
         SaturationDoVoltage = averageVoltage;
         SaturationDoTemperature = temperature;
         doCalibrationFinishFlag = 1;
      }
      break;

        case 3:
        if(enterCalibrationFlag)
        {
            Serial.println();
            if(doCalibrationFinishFlag)      
               Serial.print(F(">>>Calibration Successful"));
            else 
              Serial.print(F(">>>Calibration Failed"));       
            Serial.println(F(",Exit Calibration Mode<<<"));
            Serial.println();
            doCalibrationFinishFlag = 0;
            enterCalibrationFlag = 0;
        }
        break;
    }
}

int getMedianNum(int bArray[], int iFilterLen) 
{
      int bTab[iFilterLen];
      for (byte i = 0; i<iFilterLen; i++)
      {
    bTab[i] = bArray[i];
      }
      int i, j, bTemp;
      for (j = 0; j < iFilterLen - 1; j++) 
      {
    for (i = 0; i < iFilterLen - j - 1; i++) 
          {
      if (bTab[i] > bTab[i + 1]) 
            {
    bTemp = bTab[i];
          bTab[i] = bTab[i + 1];
    bTab[i + 1] = bTemp;
       }
    }
      }
      if ((iFilterLen & 1) > 0)
  bTemp = bTab[(iFilterLen - 1) / 2];
      else
  bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
      return bTemp;
}

void readDoCharacteristicValues(void)
{
    EEPROM_read(SaturationDoVoltageAddress, SaturationDoVoltage);  
    EEPROM_read(SaturationDoTemperatureAddress, SaturationDoTemperature);
    if(EEPROM.read(SaturationDoVoltageAddress)==0xFF && EEPROM.read(SaturationDoVoltageAddress+1)==0xFF && EEPROM.read(SaturationDoVoltageAddress+2)==0xFF && EEPROM.read(SaturationDoVoltageAddress+3)==0xFF)
    {
      SaturationDoVoltage = 1127.6;   //default voltage:1127.6mv
      EEPROM_write(SaturationDoVoltageAddress, SaturationDoVoltage);
    }
    if(EEPROM.read(SaturationDoTemperatureAddress)==0xFF && EEPROM.read(SaturationDoTemperatureAddress+1)==0xFF && EEPROM.read(SaturationDoTemperatureAddress+2)==0xFF && EEPROM.read(SaturationDoTemperatureAddress+3)==0xFF)
    {
      SaturationDoTemperature = 25.0;   //default temperature is 25^C
      EEPROM_write(SaturationDoTemperatureAddress, SaturationDoTemperature);
    }    
}


//pH FUNCTION

double avergearray(int* arr, int number){
  int i;
  int max,min;
  double avg;
  long amount=0;
  if(number<=0){
    //Serial.println("Error number for the array to avraging!/n");
    return 0;
  }
  if(number<5){   //less than 5, calculated directly statistics
    for(i=0;i<number;i++){
      amount+=arr[i];
    }
    avg = amount/number;
    return avg;
  }else{
    if(arr[0]<arr[1]){
      min = arr[0];max=arr[1];
    }
    else{
      min=arr[1];max=arr[0];
    }
    for(i=2;i<number;i++){
      if(arr[i]<min){
        amount+=min;        //arr<min
        min=arr[i];
      }else {
        if(arr[i]>max){
          amount+=max;    //arr>max
          max=arr[i];
        }else{
          amount+=arr[i]; //min<=arr<=max
        }
      }//if
    }//for
    avg = (double)amount/(number-2);
  }//if
  return avg;
}

This is my current code just so you know ! it has many code in the void loop() other than just the Blynk run function .And I’m using a servo motor which i don’t know how to control other than placing it in the void loop.
Please be kind enough to help me improve my code. The code has so many delays which i placed to test if the Blynk connections crash if i add delays in a void loop but i didn’t notice any such errors.
Thanks in advance Pete!
Best!
Moh

I’m not going to re-write your code for you, and even if I did I’d have no way of testing it using your hardware.

Search the forum, there are many examples.

Also, you seem to be using EEPROM to store values, but its not clear how frequently this function is being called.
Each Arduino EEPROM memory location has a specified life of 100,000 write/erase cycles, so you should be careful how you use this. A better way would be to virtualWrite this data to Blunk then retrieve it with a Blynk.syncVirtual command when you connect/re-connect to Blynk.

Pete.

Hi Pete,
I will do my research. This control system is already installed at the remote location and its kind of far from my location i dont have the sensors with me! I can’t test the code as well Pete.
I will do more research and re write the program and upload here.
Regarding the servo motor i have two methods.

  1. Manually control using a slider widget
  2. Automatically using the particular code section in the void loop as in in the above code.

I am still struggling regarding the servo! My as for the sensors i am planning to use timer interrupts to move the code out of the void loop.
And the EEPROM is only used during calibration of the DO sensor which will not be a problem Pete.
If you have aany information which would help me please be kind enough to share with me Pete. You have helped me a lot already.

Thanks in advance!
Moh

Hello Pete,

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4);



//pH 

#define SensorPin A0            //pH meter Analog output to Arduino Analog Input 0
#define Offset 0.00            //deviation compensator 
#define LED 13
#define samplingInterval 20
#define printInterval 800
#define ArrayLenth  40    //times of collection
int pHArray[ArrayLenth];   //Store the average value of the sensor feedback
int pHArrayIndex=0;    
static unsigned long samplingTime = millis();
static unsigned long printTime = millis();
static float pHValue,voltage;



//temperature libraries

#include <OneWire.h>
#include <DallasTemperature.h>

// Signal plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

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



#include <avr/pgmspace.h>
#include <EEPROM.h>

#define DoSensorPin  A1  //dissolved oxygen sensor analog output pin to arduino mainboard
#define VREF 5000    
float doValue;      //current dissolved oxygen value, unit; mg/L
float temperature = 25; 

#define EEPROM_write(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) EEPROM.write(address+i, pp[i]);}
#define EEPROM_read(address, p)  {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp[i]=EEPROM.read(address+i);}

#define ReceivedBufferLength 20
char receivedBuffer[ReceivedBufferLength+1];    // store the serial command
byte receivedBufferIndex = 0;

#define SCOUNT  30           // sum of sample point
int analogBuffer[SCOUNT];    //store the analog value in the array, readed from ADC
int analogBufferTemp[SCOUNT];
int analogBufferIndex = 0,copyIndex = 0;

#define SaturationDoVoltageAddress 12          //the address of the Saturation Oxygen voltage stored in the EEPROM
#define SaturationDoTemperatureAddress 16      //the address of the Saturation Oxygen temperature stored in the EEPROM
float SaturationDoVoltage,SaturationDoTemperature;
float averageVoltage;

const float SaturationValueTab[41] PROGMEM = {      //saturation dissolved oxygen concentrations at various temperatures
14.46, 14.22, 13.82, 13.44, 13.09,
12.74, 12.42, 12.11, 11.81, 11.53,
11.26, 11.01, 10.77, 10.53, 10.30,
10.08, 9.86,  9.66,  9.46,  9.27,
9.08,  8.90,  8.73,  8.57,  8.41,
8.25,  8.11,  7.96,  7.82,  7.69,
7.56,  7.43,  7.30,  7.18,  7.07,
6.95,  6.84,  6.73,  6.63,  6.53,
6.41,
};





//BLYNK


/*************************************************************
  Download latest Blynk library here:
    https://github.com/blynkkk/blynk-library/releases/latest

  Blynk is a platform with iOS and Android apps to control
  Arduino, Raspberry Pi and the likes over the Internet.
  You can easily build graphic interfaces for all your
  projects by simply dragging and dropping widgets.

    Downloads, docs, tutorials: http://www.blynk.cc
    Sketch generator:           http://examples.blynk.cc
    Blynk community:            http://community.blynk.cc
    Follow us:                  http://www.fb.com/blynkapp
                                http://twitter.com/blynk_app

  Blynk library is licensed under MIT license
  This example code is in public domain.

 *************************************************************
  WARNING!
    It's very tricky to get it working. Please read this article:
    http://help.blynk.cc/hardware-and-libraries/arduino/esp8266-with-at-firmware

  This example shows how value can be pushed from Arduino to
  the Blynk App.

  NOTE:
  BlynkTimer provides SimpleTimer functionality:
    http://playground.arduino.cc/Code/SimpleTimer

  App project setup:
    Value Display widget attached to Virtual Pin V5
 *************************************************************/

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial


#include <ESP8266_Lib.h>
#include <BlynkSimpleShieldEsp8266.h>
#include <Servo.h>


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

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "OnePlus6";                          //AIS 4G Pocket Wifi_320611                          //devilman1069
char pass[] = "devilman1069";                     //36320611                                           //OnePlus6

// Hardware Serial on Mega, Leonardo, Micro...
#define EspSerial Serial1

// or Software Serial on Uno, Nano...
//#include <SoftwareSerial.h>
//SoftwareSerial EspSerial(2, 3); // RX, TX

// Your ESP8266 baud rate:
#define ESP8266_BAUD 115200

ESP8266 wifi(&EspSerial);

int a=0;
int y=0;
int x=0;
int b=0;
BLYNK_WRITE(V1)
{
  int pinValue = param.asInt(); // assigning incoming value from pin V1 to a variable
  a=pinValue;
  //required dissolved oxygen value from the user
  // process received value
}
Servo servo;

BLYNK_WRITE(V3)
{
 int servo = param.asInt(); //manual control for the servo motor to control the level of 
 b=servo;                   //oxygen in the pond
}

BlynkTimer timer;
//MILLIS
// This function sends Arduino's up time every second to Virtual Pin (5).
// In the app, Widget's reading frequency should be set to PUSH. This means
// that you define how often to send data to Blynk App.
//APP DISPLAY FUNCTIONS
//void myTimerEvent()
//{
  // You can send any value at any time.
  // Please don't send more that 10 values per second.
  //Blynk.virtualWrite(V5, millis() / 1000);
//}


//TEMPERATURE

void mytemp()
{
  
  // You can send any value at any time.
  // Please don't send more that 10 values per second.
  float temp=sensors.getTempCByIndex(0);
  Blynk.virtualWrite(V6,temp);
}


//DO 

void mydo()
{
  // You can send any value at any time.
  // Please don't send more that 10 values per second.
 float  do1=doValue;
  static unsigned long analogSampleTimepoint = millis();
   if(millis()-analogSampleTimepoint > 30U)     //every 30 milliseconds,read the analog value from the ADC
   {
     analogSampleTimepoint = millis();
     analogBuffer[analogBufferIndex] = analogRead(DoSensorPin);    //read the analog value and store into the buffer
     analogBufferIndex++;
     if(analogBufferIndex == SCOUNT) 
         analogBufferIndex = 0;
   }
   
   static unsigned long tempSampleTimepoint = millis();
   if(millis()-tempSampleTimepoint > 500U)  // every 500 milliseconds, read the temperature
   {
      tempSampleTimepoint = millis();
      //temperature = readTemperature();  // add your temperature codes here to read the temperature, unit:^C
       sensors.requestTemperatures();
      temperature =sensors.getTempCByIndex(0);
   }
   
   static unsigned long printTimepoint = millis();
   if(millis()-printTimepoint > 1000U)
   {
      printTimepoint = millis();
      for(copyIndex=0;copyIndex<SCOUNT;copyIndex++)
      {
        analogBufferTemp[copyIndex]= analogBuffer[copyIndex];
      }
      averageVoltage = getMedianNum(analogBufferTemp,SCOUNT) * (float)VREF / 1024.0; // read the value more stable by the median filtering algorithm
      //Serial.print(F("Temperature:"));
      //Serial.print(temperature,1);
      //Serial.print(F("^C"));
      doValue = pgm_read_float_near( &SaturationValueTab[0] + (int)(SaturationDoTemperature+0.5) ) * averageVoltage / SaturationDoVoltage;  //calculate the do value, doValue = Voltage / SaturationDoVoltage * SaturationDoValue(with temperature compensation)
      //Serial.print(F(",  DO Value:"));
      //Serial.print(doValue,2);
      //Serial.println(F("mg/L"));
      if(serialDataAvailable() > 0)
   {
      byte modeIndex = uartParse();  //parse the uart command received
      doCalibration(modeIndex);    // If the correct calibration command is received, the calibration function should be called.
   }
      
  Blynk.virtualWrite(V7,do1);
}
}


//pH_value

void mypH()
{
  // You can send any value at any time.
  // Please don't send more that 10 values per second.
  float pH=pHValue;


  

//  static unsigned long samplingTime = millis();
//  static unsigned long printTime = millis();
//  static float pHValue,voltage;
  if(millis()-samplingTime > samplingInterval)
  {
      pHArray[pHArrayIndex++]=analogRead(SensorPin);
      if(pHArrayIndex==ArrayLenth)pHArrayIndex=0;
      voltage = avergearray(pHArray, ArrayLenth)*5.0/1024;
      pHValue = 3.5*voltage+Offset;
      samplingTime=millis();
  }
  if(millis() - printTime > printInterval)   //Every 800 milliseconds, print a numerical, convert the state of the LED indicator
  {
  //Serial.print("Voltage:");
       // Serial.print(voltage,2);
        //Serial.print("    pH value: ");
 // Serial.println(pHValue,2);
        digitalWrite(LED,digitalRead(LED)^1);
        printTime=millis();
  }
  Blynk.virtualWrite(V8,pH);
}


void myLCD ()

{
   lcd.setCursor(0,0);
 lcd.print("tempt:");
// 
 lcd.setCursor(0,1);
  lcd.print("DO:");
lcd.setCursor(8,1);
  lcd.print("pH:");
  
   
   

lcd.setCursor(7,0);
  lcd.print(sensors.getTempCByIndex(0));
// 
 lcd.setCursor(3,1);
 lcd.print(doValue,2);
 

 lcd.setCursor(11,1);
  lcd.print(pHValue);
}
int led_pin=12;

void servoauto_manual ()
{
   if (digitalRead(led_pin) == LOW)
{
  if (doValue<a-1.5 )
  {
  if(x!=0)
  
  {
    x=x-5;
    servo.write(x);
   delay (2000);
    }
    }
   
   if (doValue>a+1.5)
  {
  if( x!=90 )
  {
    x=x+5;
    servo.write(x);
    delay (2000);
    }
    }
    
   if (doValue<a+0.5 && doValue>a-0.5)
    {
     
     servo.write(x);
      }
}

     if (digitalRead(led_pin) == HIGH)
    {
        servo.write(b);
      }
}




void setup()
{
Serial.begin(9600);
lcd.init();     
lcd.backlight();  
sensors.begin();
pinMode(LED,OUTPUT);
pinMode(led_pin,INPUT);  
pinMode(DoSensorPin,INPUT);
readDoCharacteristicValues(); 
EspSerial.begin(ESP8266_BAUD); // Set ESP8266 baud rate
delay(100);
Blynk.begin(auth, wifi, ssid, pass);
  // You can also specify server:
  //Blynk.begin(auth, wifi, ssid, pass, "blynk-cloud.com", 80);
  //Blynk.begin(auth, wifi, ssid, pass, IPAddress(192,168,1,100), 8080);

  // Setup a function to be called every second
//  timer.setInterval(1000L, myTimerEvent);
  timer.setInterval(1000L, mytemp);
  timer.setInterval(1000L, mydo);
  timer.setInterval(1000L, mypH);
  lcd.setCursor(0,0);
  timer.setInterval(1000L, myLCD);

  servo.attach(9);
  servo.write(x);
  timer.setInterval(1000L, servoauto_manual );

//lcd.print("millis:");
// lcd.setCursor(1,7);
 //lcd.print(millis());
//
 //lcd.setCursor(0,1);
 //lcd.print("D:");
}

void loop()
{
  Blynk.run();
  timer.run();
  


 
//Serial.print(a);
//Serial.print("  ");
//Serial.print(x);
//Serial.print("  ");
//Serial.println(doValue);

//Serial.print(void mydo());


}

boolean serialDataAvailable(void)
{
  char receivedChar;
  static unsigned long receivedTimeOut = millis();
  while ( Serial.available() > 0 ) 
  {   
    if (millis() - receivedTimeOut > 500U) 
    {
      receivedBufferIndex = 0;
      memset(receivedBuffer,0,(ReceivedBufferLength+1));
    }
    receivedTimeOut = millis();
    receivedChar = Serial.read();
    if (receivedChar == '\n' || receivedBufferIndex == ReceivedBufferLength)
    {
  receivedBufferIndex = 0;
  strupr(receivedBuffer);
  return true;
    }else{
        receivedBuffer[receivedBufferIndex] = receivedChar;
        receivedBufferIndex++;
    }
  }
  return false;
}

byte uartParse()
{
    byte modeIndex = 0;
    if(strstr(receivedBuffer, "CALIBRATION") != NULL) 
        modeIndex = 1;
    else if(strstr(receivedBuffer, "EXIT") != NULL) 
        modeIndex = 3;
    else if(strstr(receivedBuffer, "SATCAL") != NULL)   
        modeIndex = 2;
    return modeIndex;
}

void doCalibration(byte mode)
{
    char *receivedBufferPtr;
    static boolean doCalibrationFinishFlag = 0,enterCalibrationFlag = 0;
    float voltageValueStore;
    switch(mode)
    {
      case 0:
      if(enterCalibrationFlag)
         Serial.println(F("Command Error"));
      break;
      
      case 1:
      enterCalibrationFlag = 1;
      doCalibrationFinishFlag = 0;
      Serial.println();
      Serial.println(F(">>>Enter Calibration Mode<<<"));
      Serial.println(F(">>>Please put the probe into the saturation oxygen water! <<<"));
      Serial.println();
      break;
     
     case 2:
      if(enterCalibrationFlag)
      {
         Serial.println();
         Serial.println(F(">>>Saturation Calibration Finish!<<<"));
         Serial.println();
         EEPROM_write(SaturationDoVoltageAddress, averageVoltage);
         EEPROM_write(SaturationDoTemperatureAddress, temperature);
         SaturationDoVoltage = averageVoltage;
         SaturationDoTemperature = temperature;
         doCalibrationFinishFlag = 1;
      }
      break;

        case 3:
        if(enterCalibrationFlag)
        {
            Serial.println();
            if(doCalibrationFinishFlag)      
               Serial.print(F(">>>Calibration Successful"));
            else 
              Serial.print(F(">>>Calibration Failed"));       
            Serial.println(F(",Exit Calibration Mode<<<"));
            Serial.println();
            doCalibrationFinishFlag = 0;
            enterCalibrationFlag = 0;
        }
        break;
    }
}

int getMedianNum(int bArray[], int iFilterLen) 
{
      int bTab[iFilterLen];
      for (byte i = 0; i<iFilterLen; i++)
      {
    bTab[i] = bArray[i];
      }
      int i, j, bTemp;
      for (j = 0; j < iFilterLen - 1; j++) 
      {
    for (i = 0; i < iFilterLen - j - 1; i++) 
          {
      if (bTab[i] > bTab[i + 1]) 
            {
    bTemp = bTab[i];
          bTab[i] = bTab[i + 1];
    bTab[i + 1] = bTemp;
       }
    }
      }
      if ((iFilterLen & 1) > 0)
  bTemp = bTab[(iFilterLen - 1) / 2];
      else
  bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
      return bTemp;
}

void readDoCharacteristicValues(void)
{
    EEPROM_read(SaturationDoVoltageAddress, SaturationDoVoltage);  
    EEPROM_read(SaturationDoTemperatureAddress, SaturationDoTemperature);
    if(EEPROM.read(SaturationDoVoltageAddress)==0xFF && EEPROM.read(SaturationDoVoltageAddress+1)==0xFF && EEPROM.read(SaturationDoVoltageAddress+2)==0xFF && EEPROM.read(SaturationDoVoltageAddress+3)==0xFF)
    {
      SaturationDoVoltage = 1127.6;   //default voltage:1127.6mv
      EEPROM_write(SaturationDoVoltageAddress, SaturationDoVoltage);
    }
    if(EEPROM.read(SaturationDoTemperatureAddress)==0xFF && EEPROM.read(SaturationDoTemperatureAddress+1)==0xFF && EEPROM.read(SaturationDoTemperatureAddress+2)==0xFF && EEPROM.read(SaturationDoTemperatureAddress+3)==0xFF)
    {
      SaturationDoTemperature = 25.0;   //default temperature is 25^C
      EEPROM_write(SaturationDoTemperatureAddress, SaturationDoTemperature);
    }    
}


//pH FUNCTION

double avergearray(int* arr, int number){
  int i;
  int max,min;
  double avg;
  long amount=0;
  if(number<=0){
    //Serial.println("Error number for the array to avraging!/n");
    return 0;
  }
  if(number<5){   //less than 5, calculated directly statistics
    for(i=0;i<number;i++){
      amount+=arr[i];
    }
    avg = amount/number;
    return avg;
  }else{
    if(arr[0]<arr[1]){
      min = arr[0];max=arr[1];
    }
    else{
      min=arr[1];max=arr[0];
    }
    for(i=2;i<number;i++){
      if(arr[i]<min){
        amount+=min;        //arr<min
        min=arr[i];
      }else {
        if(arr[i]>max){
          amount+=max;    //arr>max
          max=arr[i];
        }else{
          amount+=arr[i]; //min<=arr<=max
        }
      }//if
    }//for
    avg = (double)amount/(number-2);
  }//if
  return avg;
}

I modified the code which now looks like this. Would you mind telling me if this satisfies the BLYNK requirements in terms of code?
Thanks in advance Pete! Hoping to hear from you soon!

Best!
Moh

Pete.

Hi,
Thank you very much Pete! I will make these changes to the code. And if i have any doubts i will get to you. Thanks again for guiding me.

Best,
Moh

Hi,

  timer.setInterval(1200L, mydo);
  timer.setInterval(15200L, mypH);
  lcd.setCursor(0,0);
  timer.setInterval(1500L, myLCD);

  servo.attach(9);
  servo.write(x);
  timer.setInterval(1000L, servoauto_manual );

I randomly used values which i don’t care much about the accuracy of the timely deliverance of data. I have one question to ask about is it bad if it overlaps every once or twice when as the system proceeds.Will it be a cause to freeze the system again?

Best,
Moh

Probably not, but it does rather depend how long it takes for each of these functions to execute.

Pete.