Wemos water project Timers?

Hey guys and gals, working on an interesting project but am currently stumped. I realize this may not be a specific Blynk issue, but i’ve found the most help so far from this community, so ill come here first if that makes sense.
I’m using a Wemos D1 Mini and a few sensors with the IOS app and the newest Blynk libraries to the Blynk server, hoping to eventually move to a self hosted server.

The premise of the project isn’t too complicated. I have an outdoor faucet that i need to control the water temperature and flow of. I have a Wemos D1 Mini running the processes controlling a motor controller board that moves two separate motorized ball valves. they unfortunately are not stepper based, so I am using times of pins being high to run them for distinct periods. eg: set d8 high for 250ms then return low. they take 5 seconds to open fully or close fully. I have one on the hot water line and one on the cold line that T together and pass through a flow sensor and right afterwards a Temperature sensor on the pipe. seems pretty straight forward yes? The functions i hope to perform are the following: Water temperature regulation, Flow monitoring, Disable flow after x time (eg: pipe burst), disable hot water after x time (eg: finished with need for hot water and forgot to turn it back to cold), and logging of Flow and Temp to Blynk.

Currently the main issue I’m having is that my board seems to be restarting itself somewhat randomly. I do have a function here that should restart it once a day when the day resets, but it’s happening fairly sporadically. I fear i’m asking to much of this little ESP. I am using a few timers that get run and deleted pretty often which also might cause a problem, unfortunately I’m not sure. I’ve tried debug the situation, but seem to have missed something.

The other issue I have is with temperature regulation. this may be a bigger issue than a code problem, but essentially i think it takes so long to heat up the copper pipe that the water temp swings back and forth if that makes sense. Maybe a thermowell would solve the issue? thoughts?

a small photo of the project.

I’m also not a super advanced coder so I may have some simple mistakes to resolve. I’ll post the code below (sorry its a lot) and maybe someone can see that I’ve missed something simple? I have the code split into 3 tabs ill list them as such.

Main Tab and Main FXN

#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <DHT.h>
#include <ArduinoOTA.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <TimeLib.h>
#include <WidgetRTC.h>

char auth[] = "xxxxxxx";
char ssid[] = "xxxxxxx";
char pass[] = "xxxxxxx";
WidgetRTC rtc;

BLYNK_CONNECTED() {
  Blynk.syncAll();
  Blynk.virtualWrite(V9, 0);
  Blynk.virtualWrite(V5, 1);
  Blynk.virtualWrite(V101, 0);
  Serial.println("BLYNK CONNECTED. Begining Water Operations.");
}

//#define ONE_WIRE_BUS D6
#define TEMP D6
#define HOpen D1
#define HClose D2
#define COpen D3
#define CClose D5
#define FLOW D7
#define SWITCHPIN D0
#define LED D4
int virtualpin1;      //water hot or cold
int virtualpin2 = 85; //goal water temp
int virtualpin3 ;     //current water temp
int virtualpin4 ;     //Flow Rate of water
int virtualpin5 ;     //ALERT ON WATERr
int virtualpin7 = 1;  //time of water
int virtualpin9;      //water on or off
int virtualpin10;     //Overall flow timeout
int virtualpin11;     //overall Flow timer trigger
float virtualpin12; //Water disable timer
float virtualpin13;
float virtualpin14;
float virtualpin15;
int virtualpin16;
int virtualpin101 = 0;
int Override = 0;
int disconnectCount = 0;
String Day;
float ALLFLOW;
float TotalFlow;
float TotalFlow2;
float flowMilliLitres;
int CycleTemp = 0;
int timerNo;
int FlowTimer;
int ColdTimer;
int HotTimer;
int RegulateTimer;
int buttonState = 0;         // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin
int LedHigh = 1020;           //led high val to roll through
int LedCyc = 1; // used for LED wifi status 
int LastStep = 0; //used to regulate temp up or down when temperaure based does not work. 
int WaterStatus; //what it sounds like
float EverFlow; // total amount of water flow
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time;
unsigned long hMovetime = 0;  //suposed to be the total time of movement for Hot valve(not working appropriately)
unsigned long cMovetime = 0; //suposed to be the total time of movement for Cold valve (not working appropriately)
int flowPin = 2;    //This is the input pin on the Arduino
double flowRate;    //This is the value we intend to calculate.
int flowCyc = 0;  //used to determine when waterflow has stopped for a cycle. 
unsigned long  oldTime           = 0;
unsigned long flowStart = 0;

volatile int count;

OneWire oneWire(TEMP);
DallasTemperature sensors(&oneWire);

DeviceAddress tempSensor = { 0x28, 0xFF, 0x4B, 0x21, 0xC1, 0x17, 0x02, 0xE8 };
float tempC;   //Temp from sensor
float currentTemp = 0;

BlynkTimer timer;

void setup()
{
  // Debug console
  Serial.begin(9600);

  Blynk.begin(auth, ssid, pass);
  rtc.begin();
  // MoveValve(0,1,5000);


  FlowTimer = timer.setInterval(1000, sendFlow);//interupt for flow sensor 
  timer.setInterval(20000, CheckConnection); // check if still connected
  timer.setInterval(3600000, ResetVs);// reset daily flow counter
  timer.setInterval(100, Sent_serial);//send serial updates to blynk for debug
  timer.setInterval(50, WIFILed);//show wifi status on actual box. 
  timer.setInterval(750, sendTemps);// update pipe temp, need to get thermowell i think. 
  //set defaults for post-boot operation. 
  Blynk.virtualWrite(V1, 0);
  Blynk.virtualWrite(V12, 0);
  Blynk.virtualWrite(V0, 20);
  Blynk.virtualWrite(V101, 0);

  sensors.begin();
  sensors.setResolution(tempSensor, 10);
  if (!sensors.isConnected(tempSensor)) {
    Serial.println("issue with sensor");
  }

  pinMode(HOpen, OUTPUT);
  pinMode(HClose, OUTPUT);
  pinMode(COpen, OUTPUT);
  pinMode(CClose, OUTPUT);
  pinMode(BUILTIN_LED, OUTPUT);
  pinMode(TEMP, INPUT_PULLUP);
  pinMode(FLOW, INPUT);
  attachInterrupt(13, Flow, RISING);
  pinMode(SWITCHPIN, INPUT_PULLUP);

  WiFi.hostname("Water_Shop");
  ArduinoOTA.setHostname((const char*)"Water_Shop");
  ArduinoOTA.setPassword((const char *)"xxxxxxx");
  ArduinoOTA.begin();

  digitalWrite(HClose, HIGH);
  digitalWrite(CClose, HIGH);
  digitalWrite(HOpen, LOW);
  digitalWrite(COpen, LOW);
  //delay(6000);

}



void ResetVs() { // used to reset the amount of flow that has passed today. logging only not super important

  String tday = String(day());
  if (Day != tday) {
    TotalFlow = 0;
    ALLFLOW = 0;
    Blynk.virtualWrite(V12, 0);
    Day = tday;
    Serial.print("Day:Reset");
  } else {
    if (virtualpin101) {
      Serial.print("Day: ");
      Serial.println(Day);
    }
  }
}

void MoveValve(int Hot, int Cold, int HTime = 500, int CTime = 500, String note = "----------")///the actual function to open or close a valve
{
  Serial.println("----MoveValve Called----");
  Serial.println(note);
  Serial.println(Hot);
  Serial.println(Cold);
  Serial.println(HTime);
  Serial.println(CTime);
  Serial.println("------------------------");
  if (Hot == 1) {
    digitalWrite(HOpen, HIGH);
    digitalWrite(HClose, LOW);
    HotTimer = timer.setTimeout(HTime, StopValveH);
    hMovetime = hMovetime + HTime;
    Serial.print("Hot MoveTime "); Serial.println(hMovetime);
  } else if (Hot == 2) {
    digitalWrite(HOpen, LOW);
    digitalWrite(HClose, HIGH);
    HotTimer = timer.setTimeout(HTime, StopValveH);
    hMovetime = hMovetime - HTime;
    Serial.print("Hot MoveTime "); Serial.println(hMovetime);
  }
  if (Cold == 1) {
    digitalWrite(COpen, HIGH);
    digitalWrite(CClose, LOW);
    ColdTimer = timer.setTimeout(CTime, StopValveC);
    cMovetime = cMovetime + CTime;
    Serial.print("Cold MoveTime "); Serial.println(cMovetime);
  } else if (Cold == 2) {
    digitalWrite(COpen, LOW);
    digitalWrite(CClose, HIGH);
    ColdTimer = timer.setTimeout(CTime, StopValveC);
    cMovetime = cMovetime - CTime;
    Serial.print("Cold MoveTime "); Serial.println(cMovetime);
  }

}

void TemperatureRegulate() {//--------------------------------------------------THE MAGIC------------------------
  int Goal = virtualpin2;
  int GoalH = Goal + 2;
  int GoalL = Goal - 2;
  Serial.print("CycleTemp:"); Serial.println(CycleTemp);
  Serial.print("currentTemp:"); Serial.println(currentTemp);

  if (Override == 1 && currentTemp > GoalH && CycleTemp == 2) {
    MoveValve(0, 1, 0, 150, "Temp Regulate: Open Cold for 150ms"); //opencold
    CycleTemp = 0;
  } else if (Override == 1 && currentTemp > GoalH && CycleTemp != 2) {
    ++CycleTemp;
  } else if (Override == 1 && currentTemp < GoalH && CycleTemp != 2) {
    ++CycleTemp;
  } else if (Override == 1 && currentTemp < GoalL && CycleTemp == 2) {
    MoveValve(0, 2, 0, 150, "Temp Regulate: Close Cold for 150ms"); //closecold
    CycleTemp = 0;
  } else {
    MoveValve(0, 0, 0, 0, "TempOK."); //do nada, but call some stuff.

  }
}

void sendTemps() //Send the temps to Blynk
{
  sensors.requestTemperatures(); // Polls the sensors
  float tempWaterLine = sensors.getTemp(tempSensor); // Gets first probe on wire in lieu of by address
  currentTemp = sensors.rawToFahrenheit(tempWaterLine);
  Blynk.virtualWrite(V3, currentTemp);
  if (virtualpin101) {
    Serial.print("Temp: ");
    Serial.println(currentTemp);
  }
}

BLYNK_WRITE(V0) // hot or cold Stepped water regulation
{
  if (Override != 0) {
    int PinValV0 = param.asInt();
    Serial.print("LastStep: "); Serial.println(LastStep);
    Serial.print("PinVal V0: "); Serial.println(PinValV0);
    if (Override == 1) {
      if (PinValV0 == 19) {
        MoveValve(0, 1, 0, 1100, "Stepped Regulate");
        Serial.print("Step DOWN. STEP="); Serial.println(LastStep);
        LastStep = PinValV0;
      } else if (PinValV0 > LastStep) {  // if Button sends +
        MoveValve(0, 2, 0, 500, "Stepped Regulate");
        LastStep = PinValV0;
        Serial.print("Step UP. STEP="); Serial.println(LastStep);

      } else {
        MoveValve(0, 1, 0, 250, "Stepped Regulate");
        Serial.print("Step DOWN. STEP="); Serial.println(LastStep);
        LastStep = PinValV0;
      }
    }
  }
}
BLYNK_WRITE(V1) // hot or cold basic. this "enables" hot water to flow. 
{
  if (param.asInt()) {    // if Button sends 1
    DisableTimers();
    WaterStatus = 1;
    Blynk.virtualWrite(V9, WaterStatus);
    hMovetime = 0;
    cMovetime = 0;
    OpenHot();
    Serial.print("Button Sent 1, Manual on for "); Serial.print(virtualpin7 / 60000); Serial.println("Mins");
    Override = 1;
    timer.setTimeout(20000, OpenCold);
    timerNo = timer.setTimeout(virtualpin7, OverrideCountdown);
    RegulateTimer = timer.setInterval(20000, TemperatureRegulate);
    Serial.print("Timer Begins. Override Time= "); Serial.println(Override);

  } else {
    Serial.println("Button Sent 0, Turning Off");
    Blynk.virtualWrite(V0, 20);
    Blynk.setProperty(V1, "color", "#0099ff");
    if (Override == 1) {
      Serial.println("Manual Off. Disable Timer(s).");
      DisableTimers();
      MoveValve(2, 1, 50000, 50000, "Manual Hot OFF");
      Override = 0;
    } else {
      MoveValve(2, 1, 50000, 50000, "Confused Hot OFF");
      Override = 0;
    }
  }
}

BLYNK_WRITE(V2) //Goal Water Temp
{
  int pinValue = param.asInt(); // read incoming value from pin 
  virtualpin2 = pinValue; // assign pin value to its own variable
  Serial.print("Goal Water Temp Updated to " ); Serial.print(virtualpin2); Serial.println();
}
BLYNK_WRITE(V5) //If Blynk alerts should be on. 
{
  int pinValue = param.asInt(); // read incoming value from pin 
  virtualpin5 = pinValue; // assign pin value to its own variable
  Serial.print("Alerts Value changed to " ); Serial.print(virtualpin5); Serial.println();
}
BLYNK_WRITE(V7)//time of hot water before disable
{
  int pinValue = param.asInt(); // read incoming value from pin 
  virtualpin7 = pinValue * 60000; // assign pin value to its own variable
  if (timer.isEnabled(timerNo)) {
    timer.disable(timerNo);
    timerNo = timer.setTimeout(virtualpin7, OverrideCountdown);
  }
  Serial.print("Hot Timer Updated to " ); Serial.print(virtualpin7); Serial.println();
}
BLYNK_WRITE(V9)//turn all water on or off.
{
  Serial.println("Water Master-------");

  int pinValue = param.asInt(); // read incoming value from pin 
  virtualpin9 = pinValue; // assign pin value to its own variable
  if (virtualpin9 == 0) {
    DisableTimers();
    MoveValve(2, 2, 7000, 7000, "MANUAL WATER DISABLE");
    WaterStatus = 0;
    Blynk.virtualWrite(V1, WaterStatus);
    Serial.println("Water DISABLED");

  }   else if (virtualpin9 == 1) {
    WaterStatus = 1;
    MoveValve(0, 1, 0, 6000, "MANUAL WATER ENABLE");
    Serial.println("Water ENABLED");

  }
}
BLYNK_WRITE(V10)//time of All water on before disable
{
  int pinValue = param.asInt(); // read incoming value from pin 
  virtualpin10 = pinValue * 60000; // assign pin value to its own variable
  if (timer.isEnabled(timerNo)) {
    // timer.disable(timerNo);
    // timerNo = timer.setTimeout(virtualpin7, OverrideCountdown);
  }
  Serial.print("Water Timer Updated to " ); Serial.print(virtualpin10); Serial.println();
}
BLYNK_WRITE(V11) //Water disable timer
{
  int pinValue = param.asInt(); // read incoming value from pin 
  virtualpin11 = pinValue; // assign pin value to its own variable
  if (virtualpin11) {
    Serial.println("Overall Flow Timer Enabled " );
  } else {
    Serial.println("Overall Flow Timer Disabled " );
  }
}
BLYNK_WRITE(V12) //Water disable timer
{
  int pinValue = param.asFloat(); // read incoming value from pin 
  virtualpin12 = pinValue; // assign pin value to its own variable
}
BLYNK_WRITE(V13) //EverFlow
{
  int pinValue = param.asFloat(); // read incoming value from pin 
  virtualpin13 = pinValue; // assign pin value to its own variable
  EverFlow = virtualpin13;
  Serial.print("EverFlow set to :"); Serial.println(EverFlow);
}
BLYNK_WRITE(V14) //HoldTotalFlow
{
  int pinValue = param.asFloat(); // read incoming value from pin 
  virtualpin14 = pinValue; // assign pin value to its own variable
  TotalFlow2 = virtualpin14;
  Serial.print("TotalFlow2 set to :"); Serial.println(TotalFlow2);
}
BLYNK_WRITE(V15)
{
  float pinValue = param.asFloat(); // read incoming value from pin 
  virtualpin15 = pinValue; // assign pin value to its own variable
  EverFlow = virtualpin15;
  Serial.print("EverFlow set to :"); Serial.println(EverFlow);
}
BLYNK_WRITE(V16) //Reset Daily Water consumption
{
  int pinValue = param.asFloat(); // read incoming value from pin 
  virtualpin16 = pinValue; // assign pin value to its own variable
  if (virtualpin16 == 1) {
    TotalFlow = 0;
    ALLFLOW = 0;
    Blynk.virtualWrite(V12, 0);
    Serial.print("Reset Daily Water Now. ALLFLOW:"); Serial.println(ALLFLOW);
  }
}
BLYNK_WRITE(V100)//Reset the Board--------------------------------
{
  Serial.println("Reboot Called. We shall reboot now.");

  int pinValue = param.asInt(); // read incoming value from pin 
  if (pinValue == 1) {
    //We will reset here
    ESP.restart();
  }
} BLYNK_WRITE(V101) //Debug Trigger--------------------------------
{

  int pinValue = param.asInt(); // read incoming value from pin 
  virtualpin101 = pinValue;
  if (pinValue == 1) {
    Serial.println("Debug Enabled. Verbose Logging on.");
  } else {
    Serial.println("Debug Disabled. Verbose Logging off.");
  }
}

void loop()
{
  Blynk.run();
  ArduinoOTA.handle();
  timer.run();
  interrupts();
}

Second Tab Useful fxns

void CheckConnection() {   // check every 11s if connected to Blynk server
    if (!Blynk.connected()) {
    ++disconnectCount;
    if (virtualpin101) {
      Serial.println("Not connected to Blynk server");
      Serial.print("Disconnect Count: "); Serial.println(disconnectCount);
    }
    if (disconnectCount <= 20) {
      Blynk.connect();  // try to connect to server with default timeout
    } else if (disconnectCount > 20) {
      ESP.restart();
    }
  }
  else {
    disconnectCount = 0;
    if (virtualpin101) {
      Serial.println("Connected to Blynk server");
    }
  }
}


void WIFILed() {  //make the onboard LED fade if connected else off.
  if (LedHigh <= 100) {
    LedHigh = LedHigh + 15;
    LedCyc = 0;
  } else if (LedHigh >= 1020) {
    LedHigh = LedHigh - 15;
    LedCyc = 1;
  } else if (LedHigh >= 100 && LedHigh <= 1020 && LedCyc == 1) {
    LedHigh = LedHigh - 15;
  } else if (LedHigh >= 100 && LedHigh <= 1020 && LedCyc == 0) {
    LedHigh = LedHigh + 15;
  }
  if (WiFi.status() == 3) {
    analogWrite(LED, LedHigh);
  } else {
    analogWrite(LED, 1023);
  }

}


void Sent_serial() {  // Sent serial data to Blynk terminal - Unlimited string readed
  String content = "";  //null string constant ( an empty string )
  char character;
  while (Serial.available()) {
    character = Serial.read();
    content.concat(character);

  }
  if (content != "") {
    Blynk.virtualWrite (V99, content);
  }
}


void readSwitch() { //does nothing currently, there is no switch. 
  if (0 == 1) {
    int reading = digitalRead(SWITCHPIN);
    // If the switch changed, due to noise or pressing:
    if (reading != lastButtonState) {
      // reset the debouncing timer
      lastDebounceTime = millis();
    }

    if ((millis() - lastDebounceTime) > debounceDelay) {
      // whatever the reading is at, it's been there for longer than the debounce
      // delay, so take it as the actual current state:

      // if the button state has changed:
      if (reading != buttonState && Override != 1) {
        buttonState = reading;
        OpenHot();
        Serial.print("hardware button. Manual on for "); Serial.print(virtualpin7 / 60000); Serial.println("Mins");
        Override = 1;
        timerNo = timer.setTimeout(virtualpin7, OverrideCountdown);
        Serial.print("Timer Begins. Override Time= "); Serial.println(Override);
      } else if (reading != buttonState && Override == 1) {
        buttonState = reading;
        MoveValve(2, 1, 5000, 0, "Switch Called");
        Serial.println("Hardware Button. Turning Off");
        Serial.println("Manual Off. Disable Timer.");
        timer.disable(timerNo);
      } else if (reading == buttonState && Override == 1) {
        //do nothing for now
      }
    }
    lastButtonState = reading;
  }
}

Third tab with more of the water functions :slight_smile:

void OverrideCountdown() //stops the flow of hot water and moves back to cold only. 
{
  Override = 0;//sets back to normal operation after a Manual Switch
  MoveValve(2, 1, 50000, 50000, "Override Complete. Close Hot, Open Cold.");
  //Blynk.virtualWrite(V0, 20);
  Blynk.virtualWrite(V1, 0);
  Blynk.setProperty(V1, "color", "#0099ff");
  Serial.println("Hot Water timer finished. Back to cold.");
  String currentTime = String(hour()) + ":" + minute() + ":" + second();

  Serial.print("at");  Serial.println(currentTime);
  DisableTimers();
}

void DisableTimers() { //used to disable timers when various things happen like a new time is set for a timer, or water temp is changed manually etc. 

  if (timer.isEnabled(timerNo)) {
    timer.disable(timerNo);
  }
  if (timer.isEnabled(RegulateTimer)) {
    timer.disable(RegulateTimer);
  }
  if (timer.isEnabled(HotTimer)) {
    timer.disable(HotTimer);
  }
  if (timer.isEnabled(ColdTimer)) {
    timer.disable(ColdTimer);
  }
  if (virtualpin101) {
    Serial.println("All Timers Disabled.");
  }
}
void Flow() //Used for flow sensor interrupt. 
{
  count++; //Every time this function is called, increment "count" by 1
}


void StopValve() //stops movement of all valves
{
  StopValveH();
  StopValveC();
}
void StopValveH()//stops movement of HOT valve
{
  digitalWrite(HOpen, LOW);
  digitalWrite(HClose, LOW);
}
void StopValveC()//stops movement of COLDvalve
{
  digitalWrite(CClose, LOW);
  digitalWrite(COpen, LOW);
}


void OpenHot()//just a shortcut, probably not needed, but useful for calling in a function without params.
{
  MoveValve(1, 2, 10000, 10000, "OpenHot() Called.");
  Blynk.virtualWrite(V0, 20);
  Blynk.virtualWrite(V1, 1);
  Blynk.setProperty(V1, "color", "#ff0000");

}
void OpenCold() //just a shortcut, probably not needed, but useful for calling in a function without params.
{
  MoveValve(0, 1, 0, 300, "OpenCold() Called");
}
void sendFlow()  ///what it sounds like, this sends the flow to blynk
{
  //Serial.println("Flow - - - - - - - ");
  if (virtualpin101) {
    Serial.print("Flow Count: ");
    Serial.println(count);
    
    Serial.print("ALLFLOW: ");
    Serial.println(ALLFLOW);
    Serial.print("EverFlow: ");
    Serial.println(EverFlow);
  }

  if (count > 1) {
    detachInterrupt(13);
    if (virtualpin101) {
      Serial.print("Count: ");
      Serial.println(count);
    }
    flowRate = ((count * (1000.0 / (millis() - oldTime))) / 7.5);
    oldTime = millis();
    flowMilliLitres = (flowRate / 60) * 1000;
    TotalFlow = TotalFlow + flowMilliLitres;
    TotalFlow2 = TotalFlow2 + flowMilliLitres;
    if (virtualpin101) {
      Serial.print("Flow: ");
      Serial.println(flowRate);
      Serial.print("FlowML: ");
      Serial.println(flowMilliLitres);
      Serial.print("TotalFlow: ");
      Serial.println(TotalFlow);
      Serial.print("TotalFlow2: ");
      Serial.println(TotalFlow2);
    }
    Blynk.virtualWrite(V4, flowMilliLitres);

    if (flowCyc == 0) {
      if (virtualpin5) {
        Blynk.notify("WATER FLOW STARTED");
      }
      flowCyc = 1;
      flowStart = millis();
    }
    count = 0;
    flowMilliLitres = 0;
    attachInterrupt(13, Flow, RISING);
  }
  else {
    Blynk.virtualWrite(V4, count);
    if (flowCyc == 1) {
      if (virtualpin5) {
        Blynk.notify("WATER FLOW STOPPED");
      }
      flowCyc = 0;
      //flowStart = millis();
      ALLFLOW = TotalFlow / 3785.41;
      EverFlow = TotalFlow2 / 3785.41;
      //float FlALLFLOW=ALLFLOW/3785.41;
      //EverFlow = EverFlow+flowMilliLitres;
      Blynk.virtualWrite(V12, ALLFLOW);
      Blynk.virtualWrite(V13, EverFlow);
      Blynk.virtualWrite(V14, TotalFlow2);
      Blynk.virtualWrite(V15, EverFlow);
    }
    //TotalFlow = 0;
  }
  count = 0;
  //Serial.println("No Flow, Bro.");

  unsigned long currentMillis = millis();
  unsigned long dumb = currentMillis - flowStart;
  if ( (virtualpin11 == 1) && (flowCyc == 1) && ((currentMillis - flowStart) > virtualpin10)) {
    Serial.print("dumb:"); Serial.println(dumb);
    Serial.println("ON TOO LONG ");
    MoveValve(2, 2, 10000, 10000, "OVERALL Flow Timer Expired.");
    WaterStatus = 0;
    int timeoff = virtualpin10 / 60000;

    Blynk.virtualWrite(V1, WaterStatus);
    Blynk.virtualWrite(V9, WaterStatus);
    if (virtualpin101) {
      Serial.println("Water DISABLED passed: ");
      Serial.println(timeoff);
    }
    Blynk.notify("{DEVICE_NAME} FLOW DISABLED. Passed Threshold!");

    DisableTimers();
  }
  else {
    if (virtualpin101 && flowCyc == 1) {
      Serial.print("Flow timer counting. Total:"); Serial.println(ALLFLOW);
      Serial.print("Timedif:"); Serial.print(dumb); Serial.print(" vs "); Serial.println(virtualpin10);
      // Serial.print("Current:");Serial.print(currentMillis); Serial.print(" vs "); Serial.println(flowStart);
    }
  }
}

These three timers are happening way to quickly, And prone to clashing multiples times a second…

1 Like

Copy that Gunner, I can probably afford to ditch the WIFI LED status and just have it on or off, do you think sending the serial output would need to change as well?

Edit:
Is there a best practice for how many timers you can run in a given time period? this project will definitely be using them.

im also open to any feedback you might have about my code in general. am I muuxing it up? Iknow my commenting is pretty lax, oops.

Read here about timers… including staggering the timers…

1 Like

Thanks for that! that page is a treasure trove of information. Thank you for sharing it with the world.

I’ve modified the timers to be as below, hopefully I comprehended what you were telling me :slight_smile:
I’ll run this for a bit and see what happens.

Still trying to think of a way to regulate the temperature more effectively, but without having a more accurate temperature I don’t know that i’m going to be able to, got any thoughts on that Great Sensei Gunner?

FlowTimer = timer.setInterval(1000L, sendFlow);//interupt for flow sensor 
  timer.setInterval(20021L, CheckConnection); // check if still connected
  timer.setInterval(3599999L, ResetVs);// reset daily flow counter
  timer.setInterval(300L, Sent_serial);//send serial updates to blynk for debug
  timer.setInterval(5003L, WIFILed);//show wifi status on actual box. 
  timer.setInterval(755L, sendTemps);// update pipe temp,

so that seemed to break the flow sensor data. I’m not sure quite why exactly, as the only thing i changed were the times for other timers. ill dig in a bit and see what i can figure out, but if anyone has any thoughts id love to hear em.

Your two longest timers where probably fine as was… they would not interact with each other or other timers that often, and clearly leave plenty of “time” to complete their actions.

But the Sent_serial() and sendTemps() are still quick. Do they really need to run so many times a second, and is there enough time for their respective functions to complete the job before the timer kicks in again?

You are running the Sent_serial() function 2.5+ times in between each send Temp() function, and probably trying to run both simultaneously more often than not.

I guess I misunderstood how the timers worked, I thought that for some reason they would run right after each other if they were on the same time slot. Thanks for steering me correctly.

its weird though, because it seems like my interrupt isn’t working now. I’ve only changed the times of the timers and i can only get it to work in the first code I sent. I currently have it as follows and it is not functional. its reading the flow count variable as 0 even though I know its passing water and the sensor works if i upload the old code so thats not it…
hmmmmm

  FlowTimer = timer.setInterval(1000, sendFlow);//interupt for flow sensor 
  timer.setInterval(300000L, CheckConnection); // check if still connected
  timer.setInterval(3600000L, ResetVs);// reset daily flow counter
  timer.setInterval(200L, Sent_serial);//send serial updates to blynk for debug
 // timer.setInterval(50, WIFILed);//show wifi status on actual box. 
  timer.setInterval(1502L, sendTemps);// update pipe temp, need to get thermowell i think

I haven’t gone through your code… i just don’t have the focus for that :stuck_out_tongue: Nor can I say I have used interrupts much… but I think interrupts, by their nature, shouldn’t need timers for polling… but can disrupt timing of code (based on what little I have read about them).

Try commenting out the serial debug and see what happens.

Also, I do not see any pinMode() for this pin 13

Try looking at this document… is seems to mention a few things about interrupts that I don’t think I see in your code… so far…

Thanks ! I did miss that pin mode, and reading that doc was definitely enlightening, it seems that the digitalPinToInterrupt function they referred to is only needed when using the referenced pin name, not the actual pin assignment, so I shouldn’t need that, (i may be wrong so ill try it both ways.)

I’ll try removing the serial debug and see what happens.

Thanks so much for your help so far.

i added the pinMode for that and commented out the serial debug timer, and unfortunately this had no affect on the functionality… i saw a spike in flow once, but it went straight back to zero.

was I just getting lucky when this was (half) working before? :tired_face:

At this point you may need to block out large sections of your code and start working with one piece at a time, adding in another as you confirm the first is working and so on.

One quick note… as per another topic, try adding in…

#define BLYNK_NO_BUILTIN  // Disable built-in analog & digital pin operations

…to your code. If you do not use any direct pin reading or control in your App (and you shouldn’t if you are using virtual pins) then this will disable that internal function and may help with timing.

Is your ESP resetting when the water is flowing, or just randomly?
Interrupts are great, and the only way to deal with flow sensors like this, but they take priority over everything else, so can disrupt your code flow if an interrupt occurs at an unwanted/unexpected time.
It’s normal practice to either disable the interrupt, or use the nointerrupts command to ensure that the interrupts don’t mess up your processing. Of course this means that you could miss some pulses from your flow meter.
If the ESP is resetting when no interrupt pulses are being generated than this isn’t where your problem lies.

You may also find that the flow sensor produces some unwanted noise when each pulse is generated - in effect switch bounce from the internal mechanism that generates the pulses. I have a rain gauge that uses a tipping bucket mechanism where a magnet triggers a reed switch when a certain amount of water has Ben collected in the little bucket. The reed switch produces several pulses per tip of the bucket, so to get an accurate reading I have to use a switch denouncing routine to filter out the noise. This may not be an issue with your sensor, and you may not even care if you get inaccurate readings, but it’s something to be aware of.

Pete.

Can’t say Much about the code but the control to sensor response lags your seeing are the basis of a whole branch of engineering.
Look up “PID controllers”.

Unfortunately its randomly. I have started by letting the changes sit for a day to see what happens, so far same result, except that i’m seeing it throw “Confused Hot OFF” which is only called in this section of code: a BLYNK_WRITE(), but its only if the button doesn’t send a 1 or 0 which doesn’t make sense to me. its also only happening when the app isnt open on my phone. Is it possible blynk is sending something else? im going to have it serial print whatever the param is there. ill report back soon.

BLYNK_WRITE(V1) // hot or cold
{
  if (param.asInt()) {    // if Button sends 1
    DisableTimers();
    WaterStatus = 1;
    Blynk.virtualWrite(V9, WaterStatus);
    hMovetime = 0;
    cMovetime = 0;
    OpenHot();
    Serial.print("Button Sent 1, Manual on for "); Serial.print(virtualpin7 / 60000); Serial.println("Mins");
    Override = 1;
    timer.setTimeout(20000, OpenCold);
    timerNo = timer.setTimeout(virtualpin7, OverrideCountdown);
    RegulateTimer = timer.setInterval(20000, TemperatureRegulate);
    Serial.print("Timer Begins. Override Time= "); Serial.println(Override);

  } else {
    Serial.println("Button Sent 0, Turning Off");
    Blynk.virtualWrite(V0, 20);
    Blynk.setProperty(V1, "color", "#0099ff");
    if (Override == 1) {
      Serial.println("Manual Off. Disable Timer(s).");
      DisableTimers();
      MoveValve(2, 1, 50000, 50000, "Manual Hot OFF");
      Override = 0;
    } else {
      MoveValve(2, 1, 50000, 50000, "Confused Hot OFF");
      Override = 0;
    }
  }
}

but also unfortunately I have a work trip this weekend and wont be able to spend much time on it till Sunday.

Interesting, seems like a pretty in-depth subject. Ill fix my current rebooting issues and dive into this a little deeper.

I’m getting those same responses more now on that if statement which is unusual.
But it’s printing a zero for what the parameter of the Blynk_Write is sending. I’m confused why this function is even being called, as no one is in the app and nothing is changing.

The serial print back looks like this:

Confused Hot OFF
0

----MoveValve Called----
Confused Hot OFF
2
1
50000
50000
------------------------
Hot MoveTime 4294877296
Cold MoveTime 90300
Button Sent 0, Turning Off
Confused Hot OFF
0

----MoveValve Called----
Confused Hot OFF
2
1
50000
50000
------------------------
Hot MoveTime 4294827296
Cold MoveTime 140300
Button Sent 0, Turning Off
Confused Hot OFF
0

----MoveValve Called----
Confused Hot OFF
2
1
50000
50000
------------------------
Hot MoveTime 4294777296
Cold MoveTime 190300

Do you have anything connected to the 5v or 3.3v pins on the Wemos D1 Mini?
I’ve had a situation before where I was powering a Wemos via the USB connector and powering a sensor via the 5v pin. The Wemos would randomly reset itself and the problem was solved (eventually) by powering the Wemos and the sensor separately.

The other thing is, I personally try to avoid this type of coding:

in favour of:

int x = param.asInt() {    // Store button value in local variable x
Serial.println(x);         // print the value from the button
if (x) {                   // could also be written as if x == 1

Both approaches work, it’s just a bit more transparent and it’s then easier to to do an explicit if (x==0) test rather than use an else statement.

Pete.

1 Like

hope this could help you

1 Like