Programmed device restarting after uploading code

Hi

I have an issue with the below code as if I program it and then check it on serial monitor I see that it keeps restarting.

It also says ISR not in IRAM!
User exception (panic/abort/assert)
Abort called

Any solution as I just cant seemed to get it working.

Widgets Pins
V0-Display
V1-Display
V3-Button(clear)
V4-Button(pump)
V5-Menu
V6-RTC
V7-LCD
V10-Table
*/        
#define BLYNK_DEBUG           // Comment this out to disable debug and save space
#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>  // For OTA with ESP8266
#include <WiFiUdp.h>  // For OTA
#include <ArduinoOTA.h>  // For OTA
#include <SimpleTimer.h>
#include <TimeLib.h>
#include <WidgetRTC.h>
#include <Ticker.h>              //for LED status
Ticker ticker;


char auth[] = "xxx";
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] ="xxx";
char pass[] ="xxx";

SimpleTimer timer;
WidgetRTC rtc;         
//BLYNK_ATTACH_WIDGET(rtc, V6)
WidgetTerminal terminal(V2);
WidgetLCD lcd(V7);
bool simulation = false;     

byte sensorInterrupt = 4;   // WeMos & NodeMCU D2
byte sensorPin       = 4;   // WeMos & NodeMCU D2
byte pumpInterrupt   = 5; //2;  //5;   // WeMos D1 ModeMCU D3
byte pumpPin         = 5; //2;  //5;   // WeMos D1 ModeMCU D3

// The hall-effect flow sensor outputs approximately 0.066 pulses per second per litre/minute of flow.
float calibrationFactor = 0.066;
volatile byte pulseCount;  
float flowRate;
unsigned int flowMilliLitres;
unsigned long totalMilliLitres;
unsigned long oldTime;

#define averageperiod 5         // currently set to average the flow every 5 seconds
int countseconds = 0;           // count up to averageperiod
int averageflow = 0;            // used for averaging flow over averageperiod
bool notificationsent = false;  // to ensure just one message for each flow start
bool pumpState = false;         // pump is OFF on start up
bool masterState = false;       // 
bool flowoffprintonce = false;  // to ensure just one serial and terminal print for each flow stop
int rowIndex = 0;                //Saurabh
String currentDate  ;
String daybefore;
int rtctimer = 1; //check if RTC is OK and then disable / delete this #1 timer
int currentDatesi = 0;         //Saurabh simulation
int daybeforesi=currentDatesi;
int menu=0;
int s;


void setup()
{

  Serial.begin(115200);
    Blynk.begin(AUTH, WIFI_SSID, WIFI_PASS, SERVER, PORT);
  ArduinoOTA.begin();  // For OTA
  Serial.println();
 pinMode(sensorPin, INPUT);
 digitalWrite(sensorPin, HIGH);
  pinMode(pumpPin, OUTPUT);
  digitalWrite(pumpPin, LOW);  // ACTIVE HIGH, pump relay set to OFF on restart
  
  flowMilliLitres   = 0;
  totalMilliLitres  = 0;
  oldTime           = 0;
  flowRate          = 0.0;
  if(simulation == true){
    pulseCount        = 47;
  }
  else{
    pulseCount        = 0;
  }

  // Configured to trigger on a FALLING state change (transition from HIGH state to LOW state)
  //attachInterrupt(sensorInterrupt, PulseCounter, FALLING);//FALLING

  // Configured to trigger on a CHANGE state change LOW to HIGH or HIGH to LOW
  attachInterrupt(pumpInterrupt, pumpToggle, CHANGE);
  Blynk.begin(auth, ssid, pass);
  rtc.begin();
  terminal.println("Connected to Blynk");
  terminal.println(WiFi.localIP());
  terminal.flush(); 
  timer.setInterval(1000L, showFlow);
  timer.setInterval(100L, pumpControl);  // check if pump needs to be switched ON or OFF every 0.1s
  rtctimer = timer.setInterval(2000L, checkRTC);   // check every 2s if RTC is correct
}
BLYNK_CONNECTED() {
Blynk.syncVirtual(V5);
Blynk.syncVirtual(V4);
}
void showFlow()  // average the flow over averageperiod
{  
    detachInterrupt(sensorInterrupt);  // Disable the interrupt while calculating flow rate and sending the value to the host        
    // Because this loop may not complete in exactly 1 second intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output. We also apply the calibrationFactor to scale the output
    // based on the number of pulses per second per units of measure (litres/minute in
    // this case) coming from the sensor.
    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
    // Note the time this processing pass was executed. Note that because we've
    // disabled interrupts the millis() function won't actually be incrementing right
    // at this point, but it will still return the value it was set to just before
    // interrupts went away.
    oldTime = millis();
    
    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in this 1 second interval, then multiply by 1000 to
    // convert to millilitres.
    flowMilliLitres = (flowRate / 60) * 1000;
    
    // Add the ml passed in this second to the cumulative total
    totalMilliLitres += flowMilliLitres;
    
    // Print the flow rate for this second in litres / minute
    Serial.print("Flow rate: ");
    Serial.print(int(flowRate));  // Print the integer part of the variable
    Serial.print("L/min");
    Serial.print("\t");          // Print tab space
    // Print the cumulative total of litres flowed since starting
    Serial.print("Output Liquid Quantity: ");        
    Serial.print(totalMilliLitres);
    Serial.print("mL"); 
    Serial.print("\t");       // Print tab space
    Serial.print(totalMilliLitres/1000);
    Serial.println("L");
    if(simulation != true){  
      pulseCount = 0; // Reset the pulse counter so we can start incrementing again
    }
    countseconds++;
    if(countseconds > 0){    // used to skip the first rogue data flow reading
      averageflow = averageflow + flowRate;   // used to calculate the average flow over averageperiod cycles
    }
    if(countseconds == averageperiod){
      Serial.print("Average water flow in litres / M is ");
      Serial.println(averageflow / averageperiod);
      Blynk.virtualWrite(V0, int(averageflow) / averageperiod);
      Blynk.virtualWrite(V1, totalMilliLitres/1000);
      countseconds = 0;  // reset the counter
      chkFlow();           
      averageflow = 0;     // reset the average but only after chkFlow() function
    }
    //attachInterrupt(sensorInterrupt, PulseCounter, FALLING);  // Enable the interrupt again now that we've finished sending output
}

void chkFlow(){
  if((averageflow > 3) && (notificationsent == false)){  // guess of a decent water pressure
    Serial.println("Water IS flowing.");
    lcd.clear();
    lcd.print(0,0,"Water is flowing");
    Blynk.email("Water Flow Sensor", "Water IS flowing.");
    Blynk.notify("Sensor: Water IS flowing.");
    notificationsent = true;         // stop getting messages until water stops flowing and starts again
    flowoffprintonce = false;        // when water stops flowing again we can restart serial and terminal print (once)
    
  }
  if((averageflow <= 3)&& (flowoffprintonce == false)){
    Serial.println("Water is NOT flowing.");
    lcd.clear();
    lcd.print(1,0,"Water is NOT");
    lcd.print(4,1,"flowing");
    notificationsent = false;  // when water starts flowing again we can send another notification
    flowoffprintonce = true;      // stop serial and terminal prints after first pass of water stopping
    s=0;
  }
 if(averageflow <= 3){
     digitalWrite(pumpPin, LOW);   // turn off pump //s*
   }
if(averageflow>3 && menu == 1){
    digitalWrite(pumpPin, HIGH);   // turn on pump //s*
    Blynk.virtualWrite(V8, "ON");
    Blynk.virtualWrite(V4, 1);     // update app button on V4  COSTAS//s*
   }

}
void  ICACHE_RAM_ATTR pulseCounter()

{
  pulseCount++;  // Increment the pulse counter
}

void pumpToggle(){                // toggle just pumpState OFF and ON from pin interrupt
  pumpState = !pumpState;         // don't do anything else in this function or the system will crash
  //Serial.println(pumpState);      // for debugging only  TODO comment this out later     
}

void  pumpControl()                // toggle pump OFF and ON
{
  detachInterrupt(pumpInterrupt);  // disable interrupt
  if(pumpState == masterState){
    // do nothing
  }
  else{  
    masterState = pumpState;
    if(pumpState == true){
    Blynk.virtualWrite(V4, 1);
    Blynk.virtualWrite(V8, "ON");
    // Blynk.setProperty(V8, "color","#48E06B");
    Serial.println("Pump turned ON"); 
    }
    else{
      Blynk.virtualWrite(V4, 0);
      Blynk.virtualWrite(V8, "OFF");
   //   Blynk.setProperty(V8, "color","#04C0F8");
      Serial.println("Pump turned OFF"); 
    }
  }
  terminal.flush();
  attachInterrupt(pumpInterrupt, pumpToggle, CHANGE);   // enable pump pin interrupt
}
void checkRTC(){
  if(year() != 1970){
    timer.disable(rtctimer);  // disable rtctimer now RTC is ok
    //rtcupdated = true; // can be commented out as checkRTC will stop when RTC is ok
    currentDate = String(day()) + "/" + month() + "/" + year();   // etc
    terminal.println("RTC started");
    daybefore=currentDate;
    timer.setInterval(60000L, table);   //start table() now RTC is OK
  }
}
void table()                               //Saurabh
{
  currentDate = String(day()) + "/" + month() + "/" + year();  // etc
   if(currentDate != daybefore)
    {
    //currentDate = String(day()) + "/" + month() + "/" + year();
    Blynk.virtualWrite(V10, "add", rowIndex,daybefore,totalMilliLitres/1000+String(" litre")); //Saurabh
    Blynk.virtualWrite(V1, 0);
    Serial.println("working");
    flowMilliLitres = 0;
    totalMilliLitres = 0;
    daybefore=currentDate; 
    }
}
BLYNK_WRITE(V3){   // reset with button in PUSH mode on virtual pin 3
  int resetdata = param.asInt();
  if(resetdata == 1){
    Serial.println("Clearing data");
    Blynk.virtualWrite(V0, 0);
    Blynk.virtualWrite(V1, 0);
    averageflow = 0;
    countseconds = 0;
    flowMilliLitres = 0;
    totalMilliLitres = 0;
  }
}
BLYNK_WRITE(V20){   // reset with button in PUSH mode on virtual pin 20
  int resetdata = param.asInt();
  if(resetdata == 1){
    Serial.println("Clearing table data");
    Blynk.virtualWrite(V10, "clr");
   
  }
}
BLYNK_WRITE(V4){   // Button in SWITCH mode on virtual pin 4 to control relay
  int controlRelay = param.asInt();
  if(controlRelay == 1){
    digitalWrite(pumpPin, HIGH);  // turn relay ON
   // Blynk.virtualWrite(V8, "ON"); 
  }
  else{
    digitalWrite(pumpPin, LOW);  // turn relay OFF 
     //Blynk.virtualWrite(V8, "OFF"); 
  }
  pumpControl();
}
BLYNK_WRITE(V5)
{
 switch(param.asInt()){
  case 1:{
     lcd.clear();
    lcd.print(1,0,"Automatic Mode");
    lcd.print(5,1,"Selected");
    menu=1;
    break;
  }
  case 2:{
    lcd.clear();
    lcd.print(3,0,"Manual Mode");
    lcd.print(5,1,"Selected");
    menu=0;
    break;
  }
 }
}
void loop(){
  Blynk.run();
  timer.run();
}

Well, you seem to have figured-out that you need to add the ICACHE_RAM_ATTR attribute to the void definition for one of your interrupt service routines:

but then you don’t actually attach an interrupt to that ISR…

The one attachInterrupt command that is not commented-out is this:

But the pumpToggle ISR doesn’t have the ICACHE_RAM_ATTR attribute added to it…

It should look like this:

void ICACHE_RAM_ATTR pumpToggle(){

Earlier versions of the Arduino core allowed you to get away with defining IRS’s without the ICACHE_RAM_ATTR attribute, but more recent versions don’t like it.

Pete.

Thank you Pete and will try it out.

Appreciated the fast and accurate response.

Hi Pete

I have carried you suggestion and amended the code (below) however now I notice in serial monitor that it keeps resetting a lot faster now. Please see below copy from serial monitor when running the program as mentioned below

ets Jan 8 2013,rst cause:2, boot mode:(3,6)

load 0x4010f000, len 1392, room 16
tail 0
chksum 0xd0
csum 0xd0
v3d128e5c
~ld

ISR not in IRAM!

User exception (panic/abort/assert)
Abort called

stack>>>

ctx: cont
sp: 3ffffee0 end: 3fffffc0 offset: 0000
3ffffee0: feefeffe feefeffe feefeffe 00000100
3ffffef0: 000000fe 00000000 00000000 00000000
3fffff00: 00000000 00000000 00000000 00ff0000
3fffff10: 5ffffe00 5ffffe00 3ffefe54 00000000
3fffff20: 00000003 00000005 3ffeeed8 40206186
3fffff30: 40100656 40207299 ffffffff 4020619c
3fffff40: feefeffe 00000001 3ffeeed8 402066d5
3fffff50: 00000000 3ffeeed8 3ffe89a1 40204e30
3fffff60: 40204e24 3ffeeed8 3ffe89a1 3ffef004
3fffff70: 3fffdad0 3ffeeed8 3ffeeed8 40206784
3fffff80: 3fffdad0 3ffe84d4 3ffeeed8 4020306a
3fffff90: feefeffe feefeffe feefeffe feefeffe
3fffffa0: 3fffdad0 00000000 3ffeefc4 40205d78
3fffffb0: feefeffe feefeffe 3ffe8538 40100f61
<<<stack<<<

Widgets setvPins
V0-Display
V1-Display
V3-Button(clear)
V4-Button(pump)
V5-Menu
V6-RTC
V7-LCD
V10-Table
*/
#define BLYNK_DEBUG           // Comment this out to disable debug and save space
#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space
#include <ESP8266WiFi.h>

#include <Blynk.h>
#include <BlynkSimpleEsp8266.h>
#include <ESP8266WebServer.h>
#include <SimpleTimer.h>
#include <TimeLib.h>
#include <Time.h>
#include <SPI.h>
#include <WidgetRTC.h>
#include <Ticker.h>              //for LED status
Ticker ticker;

char auth[] = "xxx";
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] ="xxx";
char pass[] ="xxx";

SimpleTimer timer;
WidgetRTC rtc;         
//BLYNK_ATTACH_WIDGET(rtc, V6)
WidgetTerminal terminal(V2);
WidgetLCD lcd(V7);

bool simulation = false;     

byte sensorInterrupt = 4;   // WeMos & NodeMCU D2
byte sensorPin       = 4;   // WeMos & NodeMCU D2
byte pumpInterrupt   = 5; //2;  //5;   // WeMos D1 ModeMCU D3
byte pumpPin         = 5; //2;  //5;   // WeMos D1 ModeMCU D3

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per litre/minute of flow.
float calibrationFactor = 4.5;
volatile byte pulseCount;  
float flowRate;
unsigned int flowMilliLitres;
unsigned long totalMilliLitres;
unsigned long oldTime;

#define averageperiod 5         // currently set to average the flow every 5 seconds
int countseconds = 0;           // count up to averageperiod
int averageflow = 0;            // used for averaging flow over averageperiod
bool notificationsent = false;  // to ensure just one message for each flow start
bool pumpState = false;         // pump is OFF on start up
bool masterState = false;       // 
bool flowoffprintonce = false;  // to ensure just one serial and terminal print for each flow stop
int rowIndex = 0;                //Saurabh
String currentDate  ;
String daybefore;
int rtctimer = 1; //check if RTC is OK and then disable / delete this #1 timer
int currentDatesi = 0;         //Saurabh simulation
int daybeforesi=currentDatesi;
int menu=0;
int s;


void setup()
{

  Serial.begin(115200);
  Serial.println();
 pinMode(sensorPin, INPUT);
 digitalWrite(sensorPin, HIGH);
  pinMode(pumpPin, OUTPUT);
  digitalWrite(pumpPin, LOW);  // ACTIVE HIGH, pump relay set to OFF on restart
  
  flowMilliLitres   = 0;
  totalMilliLitres  = 0;
  oldTime           = 0;
  flowRate          = 0.0;
  if(simulation == true){
    pulseCount        = 47;
  }
  else{
    pulseCount        = 0;
  }

  // Configured to trigger on a FALLING state change (transition from HIGH state to LOW state)
  //attachInterrupt(sensorInterrupt, pulseCounter, FALLING);//FALLING

  // Configured to trigger on a CHANGE state change LOW to HIGH or HIGH to LOW
  attachInterrupt(pumpInterrupt, pumpToggle, CHANGE);
  Blynk.begin(auth, ssid, pass);
  rtc.begin();
  terminal.println("Connected to Blynk");
  terminal.println(WiFi.localIP());
  terminal.flush(); 
  timer.setInterval(1000L, showFlow);
  //timer.setInterval(100L, pumpControl);  // check if pump needs to be switched ON or OFF every 0.1s
  rtctimer = timer.setInterval(2000L, checkRTC);   // check every 2s if RTC is correct
}
BLYNK_CONNECTED() {
Blynk.syncVirtual(V5);
Blynk.syncVirtual(V4);
}
void showFlow()  // average the flow over averageperiod
{  
    detachInterrupt(sensorInterrupt);  // Disable the interrupt while calculating flow rate and sending the value to the host        
    // Because this loop may not complete in exactly 1 second intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output. We also apply the calibrationFactor to scale the output
    // based on the number of pulses per second per units of measure (litres/minute in
    // this case) coming from the sensor.
    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
    // Note the time this processing pass was executed. Note that because we've
    // disabled interrupts the millis() function won't actually be incrementing right
    // at this point, but it will still return the value it was set to just before
    // interrupts went away.
    oldTime = millis();
    
    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in this 1 second interval, then multiply by 1000 to
    // convert to millilitres.
    flowMilliLitres = (flowRate / 60) * 1000;
    
    // Add the ml passed in this second to the cumulative total
    totalMilliLitres += flowMilliLitres;
    
    // Print the flow rate for this second in litres / minute
    Serial.print("Flow rate: ");
    Serial.print(int(flowRate));  // Print the integer part of the variable
    Serial.print("L/min");
    Serial.print("\t");          // Print tab space
    // Print the cumulative total of litres flowed since starting
    Serial.print("Output Liquid Quantity: ");        
    Serial.print(totalMilliLitres);
    Serial.print("mL"); 
    Serial.print("\t");       // Print tab space
    Serial.print(totalMilliLitres/1000);
    Serial.println("L");
    if(simulation != true){  
      pulseCount = 0; // Reset the pulse counter so we can start incrementing again
    }
    countseconds++;
    if(countseconds > 0){    // used to skip the first rogue data flow reading
      averageflow = averageflow + flowRate;   // used to calculate the average flow over averageperiod cycles
    }
    if(countseconds == averageperiod){
      Serial.print("Average water flow in litres / M is ");
      Serial.println(averageflow / averageperiod);
      Blynk.virtualWrite(V0, int(averageflow) / averageperiod);
      Blynk.virtualWrite(V1, totalMilliLitres/1000);
      countseconds = 0;  // reset the counter
      chkFlow();           
      averageflow = 0;     // reset the average but only after chkFlow() function
    }
    //attachInterrupt(sensorInterrupt, pulseCounter, FALLING);  // Enable the interrupt again now that we've finished sending output
}

void chkFlow(){
  if((averageflow > 3) && (notificationsent == false)){  // guess of a decent water pressure
    Serial.println("Water IS flowing.");
    lcd.clear();
    lcd.print(0,0,"Water is flowing");
    Blynk.email("Water Flow Sensor", "Water IS flowing.");
    Blynk.notify("Sensor: Water IS flowing.");
    notificationsent = true;         // stop getting messages until water stops flowing and starts again
    flowoffprintonce = false;        // when water stops flowing again we can restart serial and terminal print (once)
    
  }
  if((averageflow <= 3)&& (flowoffprintonce == false)){
    Serial.println("Water is NOT flowing.");
    lcd.clear();
    lcd.print(1,0,"Water is NOT");
    lcd.print(4,1,"flowing");
    notificationsent = false;  // when water starts flowing again we can send another notification
    flowoffprintonce = true;      // stop serial and terminal prints after first pass of water stopping
    s=0;
  }
 if(averageflow <= 3){
     digitalWrite(pumpPin, LOW);   // turn off pump //s*
   }
if(averageflow>3 && menu == 1){
    digitalWrite(pumpPin, HIGH);   // turn on pump //s*
    Blynk.virtualWrite(V8, "ON");
    Blynk.virtualWrite(V4, 1);     // update app button on V4  COSTAS//s*
   }

}
void ICACHE_RAM_ATTR pulseCounter()
{
  pulseCount++;  // Increment the pulse counter
}

void pumpToggle(){                // toggle just pumpState OFF and ON from pin interrupt
  pumpState = !pumpState;         // don't do anything else in this function or the system will crash
  //Serial.println(pumpState);      // for debugging only  TODO comment this out later     
}

void ICACHE_RAM_ATTR pumpControl()                // toggle pump OFF and ON
{
  detachInterrupt(pumpInterrupt);  // disable interrupt
  if(pumpState == masterState){
    // do nothing
  }
  else{  
    masterState = pumpState;
    if(pumpState == true){
    Blynk.virtualWrite(V4, 1);
    Blynk.virtualWrite(V8, "ON");
    // Blynk.setProperty(V8, "color","#48E06B");
    Serial.println("Pump turned ON"); 
    }
    else{
      Blynk.virtualWrite(V4, 0);
      Blynk.virtualWrite(V8, "OFF");
   //   Blynk.setProperty(V8, "color","#04C0F8");
      Serial.println("Pump turned OFF"); 
    }
  }
  terminal.flush();
  attachInterrupt(pumpInterrupt, pumpToggle, CHANGE);   // enable pump pin interrupt
}
void checkRTC(){
  if(year() != 1970){
    timer.disable(rtctimer);  // disable rtctimer now RTC is ok
    //rtcupdated = true; // can be commented out as checkRTC will stop when RTC is ok
    currentDate = String(day()) + "/" + month() + "/" + year();   // etc
    terminal.println("RTC started");
    daybefore=currentDate;
    timer.setInterval(60000L, table);   //start table() now RTC is OK
  }
}
void table()                               //Saurabh
{
  currentDate = String(day()) + "/" + month() + "/" + year();  // etc
   if(currentDate != daybefore)
    {
    //currentDate = String(day()) + "/" + month() + "/" + year();
    Blynk.virtualWrite(V10, "add", rowIndex,daybefore,totalMilliLitres/1000+String(" litre")); //Saurabh
    Blynk.virtualWrite(V1, 0);
    Serial.println("working");
    flowMilliLitres = 0;
    totalMilliLitres = 0;
    daybefore=currentDate; 
    }
}
BLYNK_WRITE(V3){   // reset with button in PUSH mode on virtual pin 3
  int resetdata = param.asInt();
  if(resetdata == 1){
    Serial.println("Clearing data");
    Blynk.virtualWrite(V0, 0);
    Blynk.virtualWrite(V1, 0);
    averageflow = 0;
    countseconds = 0;
    flowMilliLitres = 0;
    totalMilliLitres = 0;
  }
}
BLYNK_WRITE(V20){   // reset with button in PUSH mode on virtual pin 20
  int resetdata = param.asInt();
  if(resetdata == 1){
    Serial.println("Clearing table data");
    Blynk.virtualWrite(V10, "clr");
   
  }
}
BLYNK_WRITE(V4){   // Button in SWITCH mode on virtual pin 4 to control relay
  int controlRelay = param.asInt();
  if(controlRelay == 1){
    digitalWrite(pumpPin, HIGH);  // turn relay ON
   // Blynk.virtualWrite(V8, "ON"); 
  }
  else{
    digitalWrite(pumpPin, LOW);  // turn relay OFF 
     //Blynk.virtualWrite(V8, "OFF"); 
  }
  pumpControl();
}
BLYNK_WRITE(V5)
{
 switch(param.asInt()){
  case 1:{
     lcd.clear();
    lcd.print(1,0,"Automatic Mode");
    lcd.print(5,1,"Selected");
    menu=1;
    break;
  }
  case 2:{
    lcd.clear();
    lcd.print(3,0,"Manual Mode");
    lcd.print(5,1,"Selected");
    menu=0;
    break;
  }
 }
}
void loop(){
  Blynk.run();
  timer.run();
}

Sorry Pete I forgot to comment out the //attachInterrupt(pumpInterrupt, pumpToggle, CHANGE)

My bad but good news is that the code is working

I don’t understand that comment at all. With that line commented-out you don’t have any interrupts attached.

Pete.

Hi Pete

You are right however if our comment it back in then I get this error " ‘pumpToggle’ was not declared in this scope when compiling".

I’d suggest that you post your full latest code, along with some sort of overview of what you’re ultimately trying to achieve.

Pete.

Hi Pete

The idea of this project is measure the flow of water using a hall-effect water sensor and nodemcu. at the same time it will display the total water usage as well. This will be monitored and controlled from a blynk app.

Please see below full length of code

Widgets setvPins
V0-Display
V1-Display
V3-Button(clear)
V4-Button(pump)
V5-Menu
V6-RTC
V7-LCD
V10-Table
*/
#define BLYNK_DEBUG           // Comment this out to disable debug and save space
#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space
#include <ESP8266WiFi.h>
#include "settings.h"           
#include "secret.h"                   // <<--- UNCOMMENT this before you use and change values on config.h t
#include <Blynk.h>
#include <BlynkSimpleEsp8266.h>
#include <ESP8266WebServer.h>
#include <SimpleTimer.h>
#include <TimeLib.h>
#include <Time.h>
#include <SPI.h>
#include <WidgetRTC.h>
#include <Ticker.h>              //for LED status
Ticker ticker;

BlynkTimer timer;

char auth[] = "OLm_2Yz41vqIrwbXLM8FxfYoUAhBB5G4";
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] ="Sykstus_guest";
char pass[] ="Mai@2013";

//SimpleTimer timer;
WidgetRTC rtc;         
//BLYNK_ATTACH_WIDGET(rtc, V6)
WidgetTerminal terminal(V2);
WidgetLCD lcd(V7);

bool simulation = false;     

byte sensorInterrupt = 4;   // WeMos & NodeMCU D2
byte sensorPin       = 4;   // WeMos & NodeMCU D2
byte pumpInterrupt   = 5; //2;  //5;   // WeMos D1 ModeMCU D3
byte pumpPin         = 5; //2;  //5;   // WeMos D1 ModeMCU D3

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per litre/minute of flow.
float calibrationFactor = 0.066;
volatile byte pulseCount;  
float flowRate;
unsigned int flowMilliLitres;
unsigned long totalMilliLitres;
unsigned long oldTime;

#define averageperiod 5         // currently set to average the flow every 5 seconds
int countseconds = 0;           // count up to averageperiod
int averageflow = 0;            // used for averaging flow over averageperiod
bool notificationsent = false;  // to ensure just one message for each flow start
bool pumpState = false;         // pump is OFF on start up
bool masterState = false;       // 
bool flowoffprintonce = false;  // to ensure just one serial and terminal print for each flow stop
int rowIndex = 0;                //Saurabh
String currentDate  ;
String daybefore;
int rtctimer = 1; //check if RTC is OK and then disable / delete this #1 timer
int currentDatesi = 0;         //Saurabh simulation
int daybeforesi=currentDatesi;
int menu=0;
int s;


void setup()
{

  Serial.begin(115200);
  Serial.println();
 pinMode(sensorPin, INPUT);
 digitalWrite(sensorPin, HIGH);
  pinMode(pumpPin, OUTPUT);
  digitalWrite(pumpPin, LOW);  // ACTIVE HIGH, pump relay set to OFF on restart
  
  flowMilliLitres   = 0;
  totalMilliLitres  = 0;
  oldTime           = 0;
  flowRate          = 0.0;
  if(simulation == true){
    pulseCount        = 47;
  }
  else{
    pulseCount        = 0;
  }

  // Configured to trigger on a FALLING state change (transition from HIGH state to LOW state)
  //attachInterrupt(sensorInterrupt, pulseCounter, FALLING);//FALLING

  // Configured to trigger on a CHANGE state change LOW to HIGH or HIGH to LOW
  //attachInterrupt(pumpInterrupt, pumpToggle, CHANGE);
  Blynk.begin(auth, ssid, pass);
  rtc.begin();
  terminal.println("Connected to Blynk");
  terminal.println(WiFi.localIP());
  terminal.flush(); 
  timer.setInterval(1000L, showFlow);
  //timer.setInterval(100L, pumpControl);  // check if pump needs to be switched ON or OFF every 0.1s
  rtctimer = timer.setInterval(2000L, checkRTC);   // check every 2s if RTC is correct
}
BLYNK_CONNECTED() {
Blynk.syncVirtual(V5);
Blynk.syncVirtual(V4);
}
void showFlow()  // average the flow over averageperiod
{  
    detachInterrupt(sensorInterrupt);  // Disable the interrupt while calculating flow rate and sending the value to the host        
    // Because this loop may not complete in exactly 1 second intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output. We also apply the calibrationFactor to scale the output
    // based on the number of pulses per second per units of measure (litres/minute in
    // this case) coming from the sensor.
    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
    // Note the time this processing pass was executed. Note that because we've
    // disabled interrupts the millis() function won't actually be incrementing right
    // at this point, but it will still return the value it was set to just before
    // interrupts went away.
    oldTime = millis();
    
    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in this 1 second interval, then multiply by 1000 to
    // convert to millilitres.
    flowMilliLitres = (flowRate / 60) * 1000;
    
    // Add the ml passed in this second to the cumulative total
    totalMilliLitres += flowMilliLitres;
    
    // Print the flow rate for this second in litres / minute
    Serial.print("Flow rate: ");
    Serial.print(int(flowRate));  // Print the integer part of the variable
    Serial.print("L/min");
    Serial.print("\t");          // Print tab space
    // Print the cumulative total of litres flowed since starting
    Serial.print("Output Liquid Quantity: ");        
    Serial.print(totalMilliLitres);
    Serial.print("mL"); 
    Serial.print("\t");       // Print tab space
    Serial.print(totalMilliLitres/1000);
    Serial.println("L");
    if(simulation != true){  
      pulseCount = 0; // Reset the pulse counter so we can start incrementing again
    }
    countseconds++;
    if(countseconds > 0){    // used to skip the first rogue data flow reading
      averageflow = averageflow + flowRate;   // used to calculate the average flow over averageperiod cycles
    }
    if(countseconds == averageperiod){
      Serial.print("Average water flow in litres / M is ");
      Serial.println(averageflow / averageperiod);
      Blynk.virtualWrite(V0, int(averageflow) / averageperiod);
      Blynk.virtualWrite(V1, totalMilliLitres/1000);
      countseconds = 0;  // reset the counter
      chkFlow();           
      averageflow = 0;     // reset the average but only after chkFlow() function
    }
    //attachInterrupt(sensorInterrupt, pulseCounter, FALLING);  // Enable the interrupt again now that we've finished sending output
}

void chkFlow(){
  if((averageflow > 3) && (notificationsent == false)){  // guess of a decent water pressure
    Serial.println("Water IS flowing.");
    lcd.clear();
    lcd.print(0,0,"Water is flowing");
    Blynk.email("Water Flow Sensor", "Water IS flowing.");
    Blynk.notify("Sensor: Water IS flowing.");
    notificationsent = true;         // stop getting messages until water stops flowing and starts again
    flowoffprintonce = false;        // when water stops flowing again we can restart serial and terminal print (once)
    
  }
  if((averageflow <= 3)&& (flowoffprintonce == false)){
    Serial.println("Water is NOT flowing.");
    lcd.clear();
    lcd.print(1,0,"Water is NOT");
    lcd.print(4,1,"flowing");
    notificationsent = false;  // when water starts flowing again we can send another notification
    flowoffprintonce = true;      // stop serial and terminal prints after first pass of water stopping
    s=0;
  }
 if(averageflow <= 3){
     digitalWrite(pumpPin, LOW);   // turn off pump //s*
   }
if(averageflow>3 && menu == 1){
    digitalWrite(pumpPin, HIGH);   // turn on pump //s*
    Blynk.virtualWrite(V8, "ON");
    Blynk.virtualWrite(V4, 1);     // update app button on V4  COSTAS//s*
   }

}
void ICACHE_RAM_ATTR pulseCounter()
{
  pulseCount++;  // Increment the pulse counter
}

void ICACHE_RAM_ATTR pumpToggle(){                // toggle just pumpState OFF and ON from pin interrupt
  pumpState = !pumpState;         // don't do anything else in this function or the system will crash
  //Serial.println(pumpState);      // for debugging only  TODO comment this out later     
}

void ICACHE_RAM_ATTR pumpControl()                // toggle pump OFF and ON
{
  detachInterrupt(pumpInterrupt);  // disable interrupt
  if(pumpState == masterState){
    // do nothing
  }
  else{  
    masterState = pumpState;
    if(pumpState == true){
    Blynk.virtualWrite(V4, 1);
    Blynk.virtualWrite(V8, "ON");
    // Blynk.setProperty(V8, "color","#48E06B");
    Serial.println("Pump turned ON"); 
    }
    else{
      Blynk.virtualWrite(V4, 0);
      Blynk.virtualWrite(V8, "OFF");
   //   Blynk.setProperty(V8, "color","#04C0F8");
      Serial.println("Pump turned OFF"); 
    }
  }
  terminal.flush();
  //attachInterrupt(pumpInterrupt, pumpToggle, CHANGE);   // enable pump pin interrupt
}
void checkRTC(){
  if(year() != 1970){
    timer.disable(rtctimer);  // disable rtctimer now RTC is ok
    //rtcupdated = true; // can be commented out as checkRTC will stop when RTC is ok
    currentDate = String(day()) + "/" + month() + "/" + year();   // etc
    terminal.println("RTC started");
    daybefore=currentDate;
    timer.setInterval(60000L, table);   //start table() now RTC is OK
  }
}
void table()                               //Saurabh
{
  currentDate = String(day()) + "/" + month() + "/" + year();  // etc
   if(currentDate != daybefore)
    {
    //currentDate = String(day()) + "/" + month() + "/" + year();
    Blynk.virtualWrite(V10, "add", rowIndex,daybefore,totalMilliLitres/1000+String(" litre")); //Saurabh
    Blynk.virtualWrite(V1, 0);
    Serial.println("working");
    flowMilliLitres = 0;
    totalMilliLitres = 0;
    daybefore=currentDate; 
    }
}
BLYNK_WRITE(V3){   // reset with button in PUSH mode on virtual pin 3
  int resetdata = param.asInt();
  if(resetdata == 1){
    Serial.println("Clearing data");
    Blynk.virtualWrite(V0, 0);
    Blynk.virtualWrite(V1, 0);
    averageflow = 0;
    countseconds = 0;
    flowMilliLitres = 0;
    totalMilliLitres = 0;
  }
}
BLYNK_WRITE(V20){   // reset with button in PUSH mode on virtual pin 20
  int resetdata = param.asInt();
  if(resetdata == 1){
    Serial.println("Clearing table data");
    Blynk.virtualWrite(V10, "clr");
   
  }
}
BLYNK_WRITE(V4){   // Button in SWITCH mode on virtual pin 4 to control relay
  int controlRelay = param.asInt();
  if(controlRelay == 1){
    digitalWrite(pumpPin, HIGH);  // turn relay ON
   // Blynk.virtualWrite(V8, "ON"); 
  }
  else{
    digitalWrite(pumpPin, LOW);  // turn relay OFF 
     //Blynk.virtualWrite(V8, "OFF"); 
  }
  pumpControl();
}
BLYNK_WRITE(V5)
{
 switch(param.asInt()){
  case 1:{
     lcd.clear();
    lcd.print(1,0,"Automatic Mode");
    lcd.print(5,1,"Selected");
    menu=1;
    break;
  }
  case 2:{
    lcd.clear();
    lcd.print(3,0,"Manual Mode");
    lcd.print(5,1,"Selected");
    menu=0;
    break;
  }
 }
}
void loop(){
  Blynk.run();
  timer.run();
}

You appear to have lots of redundant code, including 3 ISRs and no attachInterrupt commands.
Can you explain some of this, or tidy-up your code please?

Pete.

Hi Pete

The code use to work perfectly on esp8266 board arduino load software 2.5.2 but now on 2.6.2 it seems constantly to give errors.

To force the program to compile, upload and not restart all the time then I need to comment out all the attachinterrupt and 3 ISR.

Also the app doesnt get any values since i have done all the comments out.

I have tried various ways to clean the code up but then it just doesn’t want to work at all.

In that case, you need to explain in much more detail what the code is supposed to achieve, if you want forum members to chip-in with assistance.

Pete.

Your code has some problem with using ISRs correctly leading to crash. It also has a lot of redundancy and unnecessary code.
You can start experimenting this code, based on yours and compiled / run without any crash on ESP8266 2.6.3 core.
I still haven’t check the logic of the code yet, as this is yours to have all the excitement.
Notes
It’s currently using Blynk_WM library to make my test easy. Give it an easy try or you can modify this line from
#define USE_BLYNK_WM true
to
#define USE_BLYNK_WM false

/************************************************************
 * Water-Flow-Sersor.ino
 * Blynk Widgets and vPins
 * BLYNK_VPIN_WATER_FLOW           : V0 Display
 * BLYNK_VPIN_TOTAL_WATER_FLOW     : V1-Display
 * BLYNK_VPIN_CLEAR_DATA           : V3-Button(clear)
 * BLYNK_VPIN_PUMP_CONTROL         : V4-Button(pump)
 * BLYNK_VPIN_AUTO_MANUAL_MENU     : V5-Menu
 * BLYNK_VPIN_RTC                  : V6-RTC
 * BLYNK_VPIN_LCD                  : V7-LCD
 * BLYNK_VPIN_TABLE                : V10-Table
 ************************************************************/

#ifndef ESP8266
#error This code is intended to run on the ESP8266 platform! Please check your Tools->Board setting.
#endif

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

// Not use #define USE_SPIFFS  => using EEPROM for configuration data in WiFiManager
// #define USE_SPIFFS    false => using EEPROM for configuration data in WiFiManager
// #define USE_SPIFFS    true  => using SPIFFS for configuration data in WiFiManager
// Be sure to define USE_SPIFFS before #include <BlynkSimpleEsp8266_WM.h>

#define USE_SPIFFS                  true

// Those above #define's must be placed before #include <BlynkSimpleEsp8266_WM.h>
// Install Blynk_WM library from Arduino Library Manager to use Blynk_WM library, 
#define USE_BLYNK_WM      true

#if (USE_BLYNK_WM)
#include <BlynkSimpleEsp8266_WM.h>        //https://github.com/khoih-prog/Blynk_WM
#else
#include <BlynkSimpleEsp8266.h>

char blynk_server[] = "account.duckdns.org";

#define BLYNK_HARDWARE_PORT     8080

char auth[] = "****";
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "****";
char pass[] = "****";
#endif

// Remember to add RTC widget in APP
#include <WidgetRTC.h>

BlynkTimer timer;

int tableTimer;
int rtctimer;

#define BLYNK_VPIN_WATER_FLOW           V0
#define BLYNK_VPIN_TOTAL_WATER_FLOW     V1
#define BLYNK_VPIN_CLEAR_DATA           V3
#define BLYNK_VPIN_PUMP_CONTROL         V4
#define BLYNK_VPIN_AUTO_MANUAL_MENU     V5
#define BLYNK_VPIN_RTC                  V6
#define BLYNK_VPIN_LCD                  V7
#define BLYNK_VPIN_TABLE                V10

WidgetRTC rtc;
WidgetTerminal terminal(V2);
WidgetLCD lcd(BLYNK_VPIN_LCD);

bool simulation = false;

byte sensorInterrupt = D2;   // Pin D2 mapped to pin GPIO4 of ESP8266
byte pumpInterrupt   = D1;   // Pin D1 mapped to pin GPIO5 of ESP8266


// The hall-effect flow sensor outputs approximately 4.5 pulses per second per litre/minute of flow.
float calibrationFactor = 4.5;

volatile uint16_t pulseCount;
volatile bool     pumpState = false;         // pump is OFF on start up

float flowRate;

unsigned int  flowMilliLitres;
unsigned long totalMilliLitres;
unsigned long oldTime;

#define averageperiod     5         // currently set to average the flow every 5 seconds

int   countseconds  = 0;            // count up to averageperiod
int   averageflow   = 0;            // used for averaging flow over averageperiod
bool  notificationsent = false;     // to ensure just one message for each flow start

bool masterState = false;
bool flowoffprintonce = false;      // to ensure just one serial and terminal print for each flow stop
int rowIndex = 0;                   //Saurabh

String currentDate;
String daybefore;

int currentDatesi = 0;              //Saurabh simulation
int daybeforesi = currentDatesi;
int menu = 0;
int s;

void ICACHE_RAM_ATTR pulseCounter();

void ICACHE_RAM_ATTR pumpToggle();

BLYNK_CONNECTED()
{
  rtc.begin();
  Blynk.syncVirtual(BLYNK_VPIN_AUTO_MANUAL_MENU);
  Blynk.syncVirtual(BLYNK_VPIN_PUMP_CONTROL);
}

void showFlow()  // average the flow over averageperiod
{
  static uint16_t localPulseCount;

  noInterrupts();

  localPulseCount = pulseCount;

  if (simulation != true)
  {
    pulseCount = 0; // Reset the pulse counter so we can start incrementing again
  }

  interrupts();

  // Because this loop may not complete in exactly 1 second intervals we calculate
  // the number of milliseconds that have passed since the last execution and use
  // that to scale the output. We also apply the calibrationFactor to scale the output
  // based on the number of pulses per second per units of measure (litres/minute in
  // this case) coming from the sensor.
  flowRate = ((1000.0 / (millis() - oldTime)) * localPulseCount) / calibrationFactor;

  // Note the time this processing pass was executed. Note that because we've
  // disabled interrupts the millis() function won't actually be incrementing right
  // at this point, but it will still return the value it was set to just before
  // interrupts went away.
  oldTime = millis();

  // Divide the flow rate in litres/minute by 60 to determine how many litres have
  // passed through the sensor in this 1 second interval, then multiply by 1000 to
  // convert to millilitres.
  flowMilliLitres = (flowRate / 60) * 1000;

  // Add the ml passed in this second to the cumulative total
  totalMilliLitres += flowMilliLitres;

  // Print the flow rate for this second in litres / minute
  Serial.print("Flow rate: ");
  Serial.print(int(flowRate));  // Print the integer part of the variable
  Serial.print("L/min");
  Serial.print("\t");          // Print tab space
  // Print the cumulative total of litres flowed since starting
  Serial.print("Output Liquid Quantity: ");
  Serial.print(totalMilliLitres);
  Serial.print("mL");
  Serial.print("\t");       // Print tab space
  Serial.print(totalMilliLitres / 1000);
  Serial.println("L");

  countseconds++;
  if (countseconds > 0)
  {
    // used to skip the first rogue data flow reading
    averageflow = averageflow + flowRate;   // used to calculate the average flow over averageperiod cycles
  }

  if (countseconds == averageperiod)
  {
    Serial.print("Average water flow in litres / M is ");
    Serial.println(averageflow / averageperiod);
    Blynk.virtualWrite(BLYNK_VPIN_WATER_FLOW, int(averageflow) / averageperiod);
    Blynk.virtualWrite(BLYNK_VPIN_TOTAL_WATER_FLOW, totalMilliLitres / 1000);
    countseconds = 0;  // reset the counter
    chkFlow();
    averageflow = 0;     // reset the average but only after chkFlow() function
  }
}

void chkFlow()
{
  if ((averageflow > 3) && (notificationsent == false))
  {
    // guess of a decent water pressure
    Serial.println("Water IS flowing.");
    lcd.clear();
    lcd.print(0, 0, "Water is flowing");
    Blynk.email("Water Flow Sensor", "Water IS flowing.");
    Blynk.notify("Sensor: Water IS flowing.");
    notificationsent = true;         // stop getting messages until water stops flowing and starts again
    flowoffprintonce = false;        // when water stops flowing again we can restart serial and terminal print (once)

  }

  if ((averageflow <= 3) && (flowoffprintonce == false))
  {
    Serial.println("Water is NOT flowing.");
    lcd.clear();
    lcd.print(1, 0, "Water is NOT");
    lcd.print(4, 1, "flowing");
    notificationsent = false;  // when water starts flowing again we can send another notification
    flowoffprintonce = true;      // stop serial and terminal prints after first pass of water stopping
    s = 0;
  }
  if (averageflow <= 3)
  {
    digitalWrite(pumpInterrupt, LOW);   // turn off pump //s*
  }
  if (averageflow > 3 && menu == 1)
  {
    digitalWrite(pumpInterrupt, HIGH);   // turn on pump //s*
    Blynk.virtualWrite(V8, "ON");
    Blynk.virtualWrite(BLYNK_VPIN_PUMP_CONTROL, 1);     // update app button on V4  COSTAS//s*
  }

}

void ICACHE_RAM_ATTR pulseCounter()
{
  pulseCount++;  // Increment the pulse counter
}

void ICACHE_RAM_ATTR pumpToggle()
{
  // toggle just pumpState OFF and ON from pin interrupt
  pumpState = !pumpState;         // don't do anything else in this function or the system will crash
  //Serial.println(pumpState);      // for debugging only  TODO comment this out later
}

void pumpControl()                // toggle pump OFF and ON
{
  static bool localPumpState;

  noInterrupts();   // disable interrupt
  localPumpState = pumpState;
  interrupts();     // enable interrupt

  if (localPumpState != masterState)
  {
    masterState = localPumpState;

    if (localPumpState)
    {
      Blynk.virtualWrite(BLYNK_VPIN_PUMP_CONTROL, 1);
      Blynk.virtualWrite(V8, "ON");
      // Blynk.setProperty(V8, "color","#48E06B");
      Serial.println("Pump turned ON");
    }
    else
    {
      Blynk.virtualWrite(BLYNK_VPIN_PUMP_CONTROL, 0);
      Blynk.virtualWrite(V8, "OFF");
      //   Blynk.setProperty(V8, "color","#04C0F8");
      Serial.println("Pump turned OFF");
    }
  }
  //terminal.flush();
}

void checkRTC()
{
  if (year() != 1970)
  {
    timer.disable(rtctimer);  // disable rtctimer now RTC is ok
    //rtcupdated = true;      // can be commented out as checkRTC will stop when RTC is ok
    currentDate = String(day()) + "/" + month() + "/" + year();   // etc
    terminal.println("RTC started");
    daybefore = currentDate;
    timer.enable(tableTimer);
  }
  else
  {
    timer.enable(rtctimer);  // reenable rtctimer
    timer.disable(tableTimer);
  }
}

void table()                               //Saurabh
{
  currentDate = String(day()) + "/" + month() + "/" + year();  // etc

  if (currentDate != daybefore)
  {
    //currentDate = String(day()) + "/" + month() + "/" + year();
    Blynk.virtualWrite(BLYNK_VPIN_TABLE, "add", rowIndex, daybefore, totalMilliLitres / 1000 + String(" litre")); //Saurabh
    Blynk.virtualWrite(BLYNK_VPIN_TOTAL_WATER_FLOW, 0);
    Serial.println("working");
    flowMilliLitres = 0;
    totalMilliLitres = 0;
    daybefore = currentDate;
  }
}

BLYNK_WRITE(BLYNK_VPIN_CLEAR_DATA)
{
  // reset with button in PUSH mode on virtual pin 3
  int resetdata = param.asInt();

  if (resetdata == 1)
  {
    Serial.println("Clearing data");
    Blynk.virtualWrite(BLYNK_VPIN_WATER_FLOW, 0);
    Blynk.virtualWrite(BLYNK_VPIN_TOTAL_WATER_FLOW, 0);
    averageflow = 0;
    countseconds = 0;
    flowMilliLitres = 0;
    totalMilliLitres = 0;
  }
}

BLYNK_WRITE(V20)
{
  // reset with button in PUSH mode on virtual pin 20

  int resetdata = param.asInt();

  if (resetdata == 1)
  {
    Serial.println("Clearing table data");
    Blynk.virtualWrite(BLYNK_VPIN_TABLE, "clr");

  }
}

BLYNK_WRITE(BLYNK_VPIN_PUMP_CONTROL)
{
  // Button in SWITCH mode on virtual pin 4 to control relay
  int controlRelay = param.asInt();

  if (controlRelay == 1)
  {
    digitalWrite(pumpInterrupt, HIGH);  // turn relay ON
    // Blynk.virtualWrite(V8, "ON");
  }
  else
  {
    digitalWrite(pumpInterrupt, LOW);  // turn relay OFF
    //Blynk.virtualWrite(V8, "OFF");
  }

  pumpControl();
}

BLYNK_WRITE(BLYNK_VPIN_AUTO_MANUAL_MENU)
{
  switch (param.asInt())
  {
    case 1:
      {
        lcd.clear();
        lcd.print(1, 0, "Automatic Mode");
        lcd.print(5, 1, "Selected");
        menu = 1;
        break;
      }
    case 2:
      {
        lcd.clear();
        lcd.print(3, 0, "Manual Mode");
        lcd.print(5, 1, "Selected");
        menu = 0;
        break;
      }
  }
}

void setup()
{

  Serial.begin(115200);
  Serial.println("\nStarting Water Flow Sensor");

  pinMode(sensorInterrupt, INPUT);
  digitalWrite(sensorInterrupt, HIGH);
  pinMode(pumpInterrupt, OUTPUT);
  digitalWrite(pumpInterrupt, LOW);  // ACTIVE HIGH, pump relay set to OFF on restart

  flowMilliLitres   = 0;
  totalMilliLitres  = 0;
  flowRate          = 0.0;

  if (simulation == true)
  {
    pulseCount        = 47;
  }
  else
  {
    pulseCount        = 0;
  }

  // Configured to trigger on a FALLING state change (transition from HIGH state to LOW state)
  attachInterrupt(sensorInterrupt, pulseCounter, FALLING);    //FALLING

  // Configured to trigger on a CHANGE state change LOW to HIGH or HIGH to LOW
  attachInterrupt(pumpInterrupt, pumpToggle, CHANGE);

#if (USE_BLYNK_WM)
  // Use this to default DHCP hostname to ESP8266-XXXXXX or ESP32-XXXXXX
  //Blynk.begin();
  // Use this to personalize DHCP hostname (RFC952 conformed)
  // 24 chars max,- only a..z A..Z 0..9 '-' and no '-' as last char
  Blynk.begin("Water-Flow-Control");
#else
  // For "blynk-cloud.com" server
  //Blynk.begin(auth, ssid, pass);
  // Use for local server
  Blynk.begin(auth, ssid, pass, blynk_server, BLYNK_HARDWARE_PORT);
#endif

  if  (Blynk.connected() )
  {
    Serial.print("Connected to Blynk: IP = ");
    Serial.println(WiFi.localIP());
    terminal.println("Connected to Blynk");
    terminal.println(WiFi.localIP());
    terminal.flush();
  }

  timer.setInterval(5000L, showFlow);                   // show flow every 5s
  timer.setInterval(1000L, pumpControl);                // check if pump needs to be switched ON or OFF every 1s
  rtctimer = timer.setInterval(10000L, checkRTC);       // check every 10s if RTC is correct

  tableTimer = timer.setInterval(60000L, table);        //start table() when RTC is OK
  timer.disable(tableTimer);

  oldTime = millis();
}

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

Please post the results of your test if it’s OK or not.

Thank you Khoih, efforts mush appreciated.

Have been cleaning the code up bit will also try yours thank you

Thanks Khoih, it works perfect

Hi Khoih

One last request, I want setup a VPIN_table that it adds the daily values for that month so that I can record the total value per month for the 12 months of the year. However I just cant seem to find a code relating to this exercise and I cant seem to write one that even comes close to working. Its a mess and embarrassment to even post it on the forum.

Any Idea?

I think you have to do it yourself and be better thu that trial-and-error process of learning / coding.
We can only give some suggestions based on what you’ve done to give you some kind of pointer and guide you.

This is some pointer for you to start the work, based on the project

to calculate RainFall in 1 day.

void RainCalc()
{
  static float totalRainAmount;
  
  // Reset within 10s after boot or at around beginning of every day (12AM), have 60 s to do
  if ( !dayStart && ( (millis() < 10000 ) || ( (hour() == 0) && (minute() == 0) ) ) )
  {
    dayStart      = true;

    noInterrupts();
    totalAmount   = 0;   
    interrupts();
  }

  // Prepare for next day at 1AM
  if ( dayStart && (hour() == 1) )
  {
     dayStart = false; 
  }

  noInterrupts();
  totalRainAmount = totalAmount;
  interrupts();
  
  Blynk.virtualWrite(BLYNK_VPIN_RAIN_AMOUNT, totalRainAmount); // Rain amount
}

Good luck,

Hi Khoih

Thanks you were awesome help, much appreciated.

Last question.

In the blynk app, under “table settings”. It does not want to add additional rows as at the moment it keeps overwriting the row which I dont want. playing with various codes inputs is unsuccessful.

Any suggestions?

Below is a section fo the code:

void table()                               //Saurabh
{
  currentDate = String(day()) + "/" + month() + "/" + year();  // etc

  if (currentDate != daybefore)
  {
    //currentDate = String(day()) + "/" + month() + "/" + year();
    Blynk.virtualWrite(BLYNK_VPIN_TABLE, "add", rowIndex, daybefore, totalMilliLitres / 1000 + String(" litre")); //Saurabh
    Blynk.virtualWrite(BLYNK_VPIN_TOTAL_WATER_FLOW, 0);
    Blynk.virtualWrite(BLYNK_VPIN_TABLE, "pick", rowIndex);        //HighLighting latest added row in table
    Serial.println("working");
    flowMilliLitres = 0;
    totalMilliLitres = 0;
    daybefore = currentDate;

How many rows does the table currently have?
The maximum is 100 with the cloud servers, but this can be changed if you have a local server.
Once you reach the maximum it will revert to FIFO mode and the oldest entry will be overwritten (also known as the Homer Simpson effect) :laughing::

Pete.