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
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);
}
}
}