Design Help: Implementing Reset Sliders

Hello all!

I am trying to figure out the below problem and am looking for some advice:

I have flow sensors connected to my arduino and they are tracking and sending “tankquantitiy” values to to gauge widgets I have.

I have created a slider widget with the intent that occasionally I will refill my tank and want to reset my “tankquantity” values.

I am using the syncAll() feature so that in the event of my arduino being unplugged I can recover the quantity where it was last. However I am not sure how to have my sliders values only update my “tankquantity” when I want reset. I was thinking about something like adding a button widget that only when pressed I write “tankquantity” to the value of the slider but I am not sure you can have a BLYNK_WRITE nested below another BLYNK_READ.

Yes a button with a bool variable will work. Then in the BLYNK function start with an if statement and don’t do anything if bool is false.

Thanks for the quick response.

Within the if statement what would the syntax of the BLYNK_WRITE be to input value. Is there a better way to write it than below?

> BLYNK_WRITE(V0) {

> int reset=param.asInt();
> If (reset == 1) {
> BLYNK_WRITE(V1)
   {
>   tankquantity = param.asInt()
>   }
> }
> }

Where V0 is the button and V1 is the slider

I am actually thinking a menu widget to be able to select out of three tanks which to reset:

> //Manual Reset
> BLYNK_WRITE(V15) {
>   switch (param.asInt())
>   {
>     case 1: // Item 1
>       BLYNK_WRITE(V12)
>       {
>       keg1Quantity = param.asInt();
>       }  
>       break;
>     case 2: // Item 2
>       BLYNK_WRITE(V13)
>       {
>       keg2Quantity = param.asInt();
>       }  
>       break;
>     case 3: // Item 3
>       BLYNK_WRITE(V14)
>       {
>       keg3Quantity = param.asInt();
>       }  
>       break;
>   }
> }

I would like to see more use of the < / > button Phil :slight_smile:

Pretty sure BLYNK functions are not allowed inside BLYNK functions.

Inside the function just do a Blynk.virtualWrite(Vx 0 or 1). Blynk stuff is ok inside a function but not BLYNK stuff.

Sorry was hitting the block quote button instead of the the code format one my bad!

Yeah it isnt working for me the way I have it. That is something I didnt realize, but BLYNK functions cant be inside anything else right? But the Blynk “actions” can be inside anything. This should work but wonder if I can make this code more efficient:

> int resetKeg;
> //Manual Reset Variable Set
> BLYNK_WRITE(V15) {
>   switch (param.asInt())
>   {
>     case 1: // Item 1
>       resetKeg=1;
>       break;
>     case 2: // Item 2
>       resetKeg=2; 
>       break;
>     case 3: // Item 3
>       resetKeg=3;
>       break;
>   }
> }

> //Manual Reset
> BLYNK_WRITE(V12)
>  {
>   if (resetKeg == 1) {
>     keg1Quantity = param.asInt();
>   }
>  } 
> BLYNK_WRITE(V13)
>  {
>   if (resetKeg == 2) {
>     keg2Quantity = param.asInt();
>   } 
>  } 
> BLYNK_WRITE(V14)
>  {
>   if (resetKeg == 3) {
>     keg3Quantity = param.asInt();
>   }
>  }

Not sure what IDE you are using but with all this stuff it means I can’t copy and paste it into the Arduino IDE for testing / validation.

>
>
>
>

The bool I referred to would be:

 int resetKeg;
 bool oktoproceed = false;

 //Manual Reset Variable Set
 BLYNK_WRITE(V15) {
  if(oktoproceed == true){
   switch (param.asInt())
   {
     case 1: // Item 1
       resetKeg=1;
       break;
     case 2: // Item 2
       resetKeg=2; 
       break;
     case 3: // Item 3
       resetKeg=3;
       break;
   }
  }
 }

V12, V13 and V14 are sliders to pick the amount you are topping up the keg by or the actual volume currently in the keg?

Please explain a little more and I’ll think about the code.

The keg1quantity is the current amount of liquid. So when I fill the keg to the top I need to reset that keg’s gauge to 5 gallons (however I need a slider because sometimes I will only fill 2 or 3 gallons so I need the reset amount to be variable).

As I drink the keg, my flow sensors mark off how much has been drank and display that to the gauge.

I need to use Sync because I may sometimes unplug, reset, lose WiFi connection my arduino hardware or the Blynk App and I would need to recover the last known keg1Quantity upon restart.

In summary:
Gauges display current liquid left
Sliders set the amount of reset (i.e. how much liquid I am putting into the keg initially)

Can you tie your last post to V12 to V15, what is what?

You understand the use of a button to set the bool and then use the bool in your BLYNK functions, right?

Sliders are V12,V13,V14
Menu is V15
Menu options are 1 for Keg1 Reset (to then trigger setting variable Keg1quantity=slide V12 value) and same for the other two kegs

Interface I want is:
Gauges display current kegQuantity (liquid level) at all times.
I fill up a keg to __ gallons
I go to the corresponding slider and set it to ___ value to match the number of gallons I filled the keg with
I go to menu and select corresponding menu option to initiate the reset of the kegQuantity variable
Gauge displays updated kegQuantity value
As I drink gauge continues to show current kegQunatity Value

If I am using a Menu Widget do I need the button w/ boolean variable? Or is it that once I select something in the menu then that index number will be synced and thus when I turn the hardware back on it will think I am trying to reset the keg that I reset? If thats the case I can add a 4th menu option called : No Reset and then it would be index 4 and nothing would happen, and I would leave the menu on option 4 until I need to reset, then switch the selection for a moment and then move the selection back to option 4

OK I think I understand now. I thought the keg top up was automated but perhaps you do this manually.

Are you holding the volume of each keg in V12, V13 & V14 or are you only using these sliders just for the (manual) top up volume?

If the sliders are just for top up volume I think one slider would be enough as the V15 menu then decides which keg you are referring to.

If the sliders are not holding current keg volume where do you hold these variables?

Out of interest how many gallons do the kegs hold and what is the typical top up volume?

Correct; I top up the kegs manually and they hold about 5.5 gallons max, I usually pour in 5 gallons (whether its homebrewed beer or water to make seltzer)

Correct again, I am using the sliders for JUST the manual top up volume

That is a good idea I didn’t think of, basically your saying instead of three 1 option IF statements just use one slide with 3 IF statements inside of it?

I hold the current volume of liquid in virtual pins V0,V1,V2 which are displayed by three gauge widgets.

Full code as it stands:

//All pin settings
#define tempHum_pin D2 //Humidity & top temp location
const int fans = D3;
byte sensorInterrupt1 = D5;
byte sensorPin1       = D5;
byte sensorInterrupt2 = D6;
byte sensorPin2       = D6;
byte sensorInterrupt3 = D7;
byte sensorPin3       = D7;

////Sensors Initialization
#include "DHT.h"
#define DHTTYPE DHT11   // DHT 11
DHT dht(tempHum_pin, DHTTYPE);
//#include <PlainTMP0x.h>
//PlainTMP0x TMP;
const uint32_t _interval = 2000;
int32_t _now, _lastTime;

//////////////////////BLYNK CODE
//#define BLYNK_PRINT Serial 
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
bool isFirstConnect = true;
#include <SimpleTimer.h>
SimpleTimer timerHum;
SimpleTimer timerKeg1;
SimpleTimer timerKeg2;
SimpleTimer timerKeg3;
const char* ssid = "Phlex";
const char* password = "N1ghtm4n";
char auth[] = "ad4554b9faff43d5b34856c93b08bdf5";

//float bottomTemp;
float topTemp;
float humidity;
int emailTime;
int keg1Quantity;
int keg2Quantity;
int keg3Quantity;
volatile byte pulseCount1;
unsigned long totalGallons1;
volatile byte pulseCount2;
unsigned long totalGallons2;
volatile byte pulseCount3;
unsigned long totalGallons3;
int resetKeg;
// This function will run every time Blynk connection is established
BLYNK_CONNECTED() {
  if (isFirstConnect) {
    Blynk.syncAll();
    isFirstConnect = false;  
  }

}

//Manual Reset Variable
BLYNK_WRITE(V15) {
  switch (param.asInt())
  {
    case 1: // Item 1
      resetKeg=1;
      break;
    case 2: // Item 2
      resetKeg=2; 
      break;
    case 3: // Item 3
      resetKeg=3;
      break;
  }
}

//Manual Reset
BLYNK_WRITE(V12)
 {
  if (resetKeg == 1) {
    keg1Quantity = param.asInt();
  }
 } 
BLYNK_WRITE(V13)
 {
  if (resetKeg == 2) {
    keg2Quantity = param.asInt();
  } 
 } 
BLYNK_WRITE(V14)
 {
  if (resetKeg == 3) {
    keg3Quantity = param.asInt();
  }
 } 


// Sync Values From Server
BLYNK_WRITE(V0)
{
  keg1Quantity = param.asInt();
}

BLYNK_WRITE(V1)
{
  keg2Quantity = param.asInt();
}

BLYNK_WRITE(V2)
{
  keg3Quantity = param.asInt();
}


void tempHum(){
  humidity = dht.readHumidity();
  topTemp = dht.readTemperature(true);
  Blynk.virtualWrite(V11,topTemp);
  Blynk.virtualWrite(V4,humidity);
  
  //do {
    //_now = millis();
  //} while ((_now - _lastTime) < _interval);
  //_lastTime = _now;
  //* run measurement */
  //bottomTemp = TMP.Temperature();
  //Blynk.virtualWrite(V3,bottomTemp);
 //if ((abs(bottomTemp - topTemp))> 4) { //controlling keezer fans
  //digitalWrite(fans,HIGH);
  //}
  //else {
  //digitalWrite(fans,LOW);
  //}
 
 if (humidity>90 && ((millis()-emailTime)>86400000)) {
  Blynk.email("phillipmurphy47@gmail.com", "Keezer Issue", "There is high humidity in the keezer, dry out condensation trap");
  emailTime = millis();
  }
}


void keg1(){

if (pulseCount1 >0){ 
    detachInterrupt(sensorInterrupt1);
    totalGallons1=(pulseCount1/3800);
    keg1Quantity = keg1Quantity - totalGallons1;
    Blynk.virtualWrite(V0,keg1Quantity);
    pulseCount1 = 0;
    attachInterrupt(sensorInterrupt1, pulseCounter1, FALLING);
    }
 }

void pulseCounter1(){
  pulseCount1++;
}

void keg2(){
if (pulseCount2 >0) {
    detachInterrupt(sensorInterrupt2);
    totalGallons2 = (pulseCount2/3800);
    keg2Quantity = keg2Quantity - totalGallons2;
    Blynk.virtualWrite(V1,keg2Quantity);
    pulseCount2 = 0;
    attachInterrupt(sensorInterrupt2, pulseCounter2, FALLING);
    }
  }

void pulseCounter2(){
  pulseCount2++;
}

void keg3(){
if (pulseCount3 > 0){
    detachInterrupt(sensorInterrupt3);
    totalGallons3 = (pulseCount3/3800);
    keg3Quantity = keg3Quantity - totalGallons3;
    Blynk.virtualWrite(V2,keg3Quantity);
    pulseCount3 = 0;
    attachInterrupt(sensorInterrupt3, pulseCounter3, FALLING);
    }
  }

void pulseCounter3(){
  pulseCount3++;
}



void setup() 
{
  Serial.begin(115200);
  Blynk.begin(auth,ssid,password);
  timerHum.setInterval(3000, tempHum);
  timerKeg1.setInterval(500, keg1);
  timerKeg2.setInterval(500, keg2);
  timerKeg3.setInterval(500, keg3);
  //TMP.InitializeTMP(TMP_MOD_TMP04,&PORTD, PIND1 , TMP_UNI_FAHRENHEIT, 8);
  _lastTime = millis();
  dht.begin();
  pinMode(sensorPin1, INPUT);
  digitalWrite(sensorPin1, HIGH);
  attachInterrupt(sensorInterrupt1, pulseCounter1, FALLING);
  pinMode(sensorPin2, INPUT);
  digitalWrite(sensorPin2, HIGH);
  attachInterrupt(sensorInterrupt2, pulseCounter2, FALLING);
  pinMode(sensorPin3, INPUT);
  digitalWrite(sensorPin3, HIGH);
  attachInterrupt(sensorInterrupt3, pulseCounter3, FALLING);

}

void loop() 
{
  Blynk.run();
  timerHum.run();
  timerKeg1.run();
  timerKeg2.run();
  timerKeg3.run();
  
}

EDIT: One Slider approach:

//Manual Reset Variable
BLYNK_WRITE(V15) {
  switch (param.asInt())
  {
    case 1: // Item 1
      resetKeg=1;
      break;
    case 2: // Item 2
      resetKeg=2; 
      break;
    case 3: // Item 3
      resetKeg=3;
      break;
  }
}

//Manual Reset
BLYNK_WRITE(V12)
 {
  if (resetKeg == 1) {
    keg1Quantity = param.asInt();
  }
  else if (resetKeg == 2) {
    keg2Quantity = param.asInt();
  }
  else if (resetKeg == 3) {
    keg3Quantity = param.asInt();
  }
 }

Nearly, if you are using the slider before the menu then simply one slider as:

 int topupGallons;

 BLYNK_WRITE(V12){  
  topupGallons = param.asInt();  
 }

Then use topupGallons in the menu etc.
Sample code extract to follow.

Menu perhaps something like this:

 //Manual Reset Variable Set
 BLYNK_WRITE(V15) {
   switch (param.asInt())
   {
     case 1: // Item 1 for Keg1
       keg1Quantity = keg1Quantity + topupGallons;
       Blynk.virtualWrite(V0, keg1Quantity);
       break;
     case 2: // Item 2 for Keg2
       keg2Quantity = keg2Quantity + topupGallons; 
       Blynk.virtualWrite(V1, keg2Quantity);
       break;
     case 3: // Item 3 for Keg3
       keg3Quantity = keg3Quantity + topupGallons;
       Blynk.virtualWrite(V2, keg3Quantity);
       break;
   }
 }

Code looks to work OK (one gauge shown for Keg1) and code modified to cover resetting the volume to zero (could be coded better).

int topupGallons;
int keg1Quantity;
int keg2Quantity;
int keg3Quantity;

BLYNK_WRITE(V12){   // vertical slider for top up gallons
  topupGallons = param.asInt();
  Serial.println(topupGallons);  
}

 //Manual Reset Variable Set   MENU Widget
 BLYNK_WRITE(V15) {  // V1 and V2 gauges not yet in app
   switch (param.asInt())
   {
     case 1: // Item 1 for Keg1
       if(topupGallons == 0){
        keg1Quantity = 0;
       }
       else{
        keg1Quantity = keg1Quantity + topupGallons; 
       }     
       Blynk.virtualWrite(V0, keg1Quantity);
       break;
     case 2: // Item 2 for Keg2
       if(topupGallons == 0){
        keg2Quantity = 0;
       }
       else{
        keg2Quantity = keg2Quantity + topupGallons; 
       }  
       Blynk.virtualWrite(V1, keg2Quantity);
       break;
     case 3: // Item 3 for Keg3
       if(topupGallons == 0){
        keg3Quantity = 0;
       }
       else{
        keg3Quantity = keg3Quantity + topupGallons; 
       }  
       Blynk.virtualWrite(V2, keg3Quantity);
       break;
   }
 }

Sweet thats pretty clean. I was originally hoping to do this with one widget but it doesnt seem possible and this is an easy enough solution.

Do I need a Fourth menu option as “No Reset” as kind of a null value so that when it syncs after hardware reset it doesnt pull the latest value as one of the keg items?

Also, instead of doing keg2Quantity + topupGallons I will just make keg2Quantity = topupGallons so that I dont have to do the math. SO when I do a full refill I make tupupGallons = 5, then keg2Quantity =5 no matter how much liquid was in the keg prior to top off; I just need the final volume not how much was added etc.

Can be done with 1 widget (menu with more options, keg1 + 1 gallon, keg1 +2 gallons etc).

Yes if you are using syncAll but I never use that. I just sync the pins I need and I would exclude the menu virtual pin.

Your easier maths looks ok.

Yeah I did think about the long menu options I will play around and see which way is easier; I am not going to be doing this every day its most likely at best once a week (depends how much I drink :slight_smile: )

I have updated the Sync to only do V0,V1,V2

Thanks for the help with this! Love this community such a useful resource for fun and solutions.

As you have removed syncAll then it would only be 15 items in the menu (3 kegs X 1 to 5 gallon top ups).

When using syncVirtual I am having problems with the code.

I get an error when using this:

Blynk.syncVirtual(V0, V1, V2);

But using this split out I do not get an error; I cannot find many example of the syntax of how to use syncVirtual so not sure if I am just writing it out wrong:

    Blynk.syncVirtual(V0);
    Blynk.syncVirtual(V1);
    Blynk.syncVirtual(V2);

The second syntax is correct.