BLYNK
HOME       📲 GETTING STARTED       📗 DOCS       ❓HELP CENTER       👉 SKETCH BUILDER

How to make an I2C LCD Display work independently even when BLYNK not connected

I am making a control system using BLYNK as my IoT platform to view data over the mobile.I have to monitor and control a fish pond’s environment. I take sensor readings such as Temperature, Dissolved Oxygen , pH , and a servo motor to control the dissolved oxygen of the system as required by the user.
Problem - I am using an LCD display (I2C 16*2) to view data at the remote location itself. But i noticed that when the esp_01 module is not connected to the internet (when the system is not connected to BLYNK) the LCD display is not updating for some reason and i’m having a hard time figuring out how to do this. This LCD display should work independently even if there are issues in connecting to the BLYNK network. Please be kind enough to help me how to do this. Thanks in advance.

Best,
Moh

#include <LiquidCrystal_I2C.h>      //LCD Library headers
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;


int reset_pin=29;   //pin to reset the ESP module

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

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


void espreset()   //TIMELY ESP  RESET
{
digitalWrite (reset_pin,LOW) ;
delay(1000);
digitalWrite (reset_pin,HIGH) ;
}


void setup()
{
Serial.begin(9600);
lcd.init();     
lcd.backlight(); 
 lcd.setCursor(0,0);
sensors.begin();
pinMode(LED,OUTPUT);
pinMode(led_pin,INPUT);  
pinMode(DoSensorPin,INPUT);
pinMode(reset_pin,OUTPUT);
  digitalWrite (reset_pin,HIGH) ;
readDoCharacteristicValues();

timer.setInterval(1500L, myLCD);
 
EspSerial.begin(ESP8266_BAUD); // Set ESP8266 baud rate
delay(10);
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(2630L, mytemp);
  timer.setInterval(3110L, mydo);
  timer.setInterval(5210L, mypH);

  
  
  servo.attach(9);
  servo.write(x);




   timer.setInterval(300000L, espreset);
//  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’ve explained the issue when I answered your post in this topic:

Pete.

1 Like

On the other hand,
Blynk.connect() is a blocking function when trying to connect to local server if it is down, about 30 sec blocking time.
There is no way to workaround :thinking:

Pete.

Yes Peter, I tried to change the timing, but it’s still the same !
Blynk.connect(1000);

Not 30 sec, but 18
2019-10-30_201904

Hi Pete,
Thank you very much for your quick response, As you can see in the code i have used Blynk.begin() which is a blocking function. And you have asked me to change it to either Blynk.config() or Blynk.connect() i am having a hard time in doing this programming part as i’m not familiar with Blynk.config and how to use it inorder to activate my auth and ssid etc…
Please be kind enough to explain me the changes I’ve got to do in order to get this done. Thanks in advance.

Best,
Moh

Hi Moh, You need to add code to set-up your network connection, then use Blynk.config to specify the Blynk parameters (auth token, server address, port etc), then call Blynk.connect to initialise that connection.

It appears that you’re using an Arduino and ESP-01, which is a hardware combination don’t use, so I don’t have any “off the shelf” code to share. However, if you search the forum for “Blynk.config” then you’ll find lots of discussion on running code without an internet connection and I’m sure you’ll find examples you can use.

Pete.

1 Like

You can try the following code (replacing your setup() and loop()) . It’s not using blocking Blynk.begin() and also trying to reconnect WiFi and/or Blynk if connection is lost. I believe your LCD display is working OK then.

bool connectBlynk()
{
  Blynk.config(wifi, auth);
  
  // You can also specify server:
  //Blynk.config(wifi, auth, "blynk-cloud.com");
  //Blynk.config(wifi, auth, "192.168.1.100", 8080);
  
  if (Blynk.connectWiFi(ssid, pass))
    Serial.println("\nWiFi connected. Try Blynk");

  int i = 0;
  while ((i++ < 20) && !Blynk.connect()) 
  {
      BlynkDelay(500);
  }
  
  return Blynk.connected();
}

void setup()
{
  Serial.begin(9600);
  EspSerial.begin(ESP8266_BAUD); // Set ESP8266 baud rate
  
  lcd.init();     
  lcd.backlight(); 
  lcd.setCursor(0,0);
  sensors.begin();
  pinMode(LED,OUTPUT);
  pinMode(led_pin,INPUT);  
  pinMode(DoSensorPin,INPUT);
  pinMode(reset_pin,OUTPUT);
  digitalWrite (reset_pin,HIGH) ;
  readDoCharacteristicValues();
  
  if (connectBlynk())
  {
    Serial.println("\nBlynk connected");
  }
  else
  {
    Serial.println("\nBlynk not connected");
  }

  // Setup a function to be called every second
  //timer.setInterval(1000L, myTimerEvent);
  
  timer.setInterval(2630L, mytemp);
  timer.setInterval(3110L, mydo);
  timer.setInterval(5210L, mypH);
  timer.setInterval(1500L, myLCD);
  timer.setInterval(300000L, espreset);
  
  servo.attach(9);
  servo.write(x);
}

void loop()
{
  if (Blynk.connected())
  {
    Blynk.run();
    timer.run();
  }
  else
  {
    Serial.println("No Blynk connection. Trying to connect");  
    connectBlynk();
  }
}

1 Like

Thank you very much for the information that you’ve provided here … i will use this code on my system and will let you know if it solved the problem.