Run 8 Pumps From Blynk

I am trying to put together an Arduino sketch to control a peristaltic pump. One block is giving me grief, well one line in particular. The “if” test proves true as the Step Widget value is reset to 0, and also the terminalPrint posts to the terminal. However, the command to reset the button widget to 0 (OFF) does not execute. The use of syncVirtual in the BLYNK_WRITE block lead me to believe that maybe there was a conflict. Is there a conflict? I also have the same 3 statements in the setup to begin the sketch in the 0 position, but still, after Blynk reconnects, the Step returns to 0, the button does not.

Any ideas?

BLYNK_WRITE(V1) {                   // button
  button = param.asInt();      // a button press triggers the code into action
  Blynk.syncVirtual(V1);            // trigger V1 function below to set current stepValue from widget
}

BLYNK_WRITE(V0) {                   // step
  stepValue = param.asFloat();      // 0.00-80,00\0.25 per step.  Once desired value is set, press button on V1
}

    if (running == true)
    {
      terminal.print("ResetButton");
      terminal.flush();
      //Blynk.virtualWrite(button, 0);
      Blynk.syncVirtual(V1);
      Blynk.virtualWrite(stepValue, 0);
    }

whole sketch

/*
  This is to be a sketch to run a peristaltic pump with Arduino and Blynk.  The circuit is an Ethernet Shield on a Mega
  with an LED connected to D3\GND.  Somewhere on the internet, Blynk runs an Android\iPhone app.  On my app, I have a button
  rendered as a switch (on/off) and a step value incrementer\decrementer.  A value between 0.00-80.00 in 0.25 steps is dialed
  in according to human preference.  Once at desired value, button is pressed and the rest of the sketch can run.

  With a seperate sketch, I was able to run each (of 8) pumps till 100ml of koolaid was dispensed while millis was being
  counted.  I did this 3 times and averaged the millis count per each motor, then divided that by 100 to derive the multiplier.
  When the multiplier is multiplied with the step value, the total amount of milliseconds to produce the desired amount of
  ml is known.
*/
#include <SPI.h>                           //Used by Blynk
#include <Ethernet.h>                      //Used by Blynk
#include <BlynkSimpleEthernet.h>           //Used by Blynk
#include <SimpleTimer.h>
#define BLYNK_PRINT Serial
char auth[] = "AuthCode";       //Paste code that app emailed you between "quotes"

int button = 0;                       //expecting 0 or 1
int oldButtonState = 0;
boolean running = false;
float stepValue;                           //expecting 0.00-80.00
const byte pump = 3;                             //Pump connected @ D3
uint32_t runCount;                            //Step Widget to determine amount of ml/Output 0-80/Step 0.2                              //
uint32_t startCount;                       //Millis reference used to calculate stopCount
uint32_t stopCount;
uint32_t multiplier = 858;                 //Number of milliseconds for motor to produce 1ml of liquid
SimpleTimer timer;                         // SimpleTimer instance named timer
WidgetTerminal terminal(V2);

BLYNK_WRITE(V1) {                   // button
  button = param.asInt();      // a button press triggers the code into action
  Blynk.syncVirtual(V1);            // trigger V1 function below to set current stepValue from widget
}

BLYNK_WRITE(V0) {                   // step
  stepValue = param.asFloat();      // 0.00-80,00\0.25 per step.  Once desired value is set, press button on V1
}

void setup()
{
  Serial.begin(9600);
  Blynk.begin(auth);
  while (Blynk.connect() == false) {}
  timer.setInterval(1500L, checkPump);
  Blynk.syncVirtual(V1);
  pinMode(pump, OUTPUT);
  //Blynk.virtualWrite(button, 0);
  Blynk.syncVirtual(V1);
  Blynk.virtualWrite(stepValue, 0);
}

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

void checkPump()
{
  runCount = stepValue * multiplier;
  if (running == false && button != oldButtonState
      && button == 1) // launch!
  {
    button = oldButtonState;
    startCount = millis();
    running = true; // launched
    digitalWrite(pump, HIGH);
    terminal.print("stepValue is:");
    terminal.println(stepValue);
    terminal.print("runCount:");
    terminal.println(runCount);
    terminal.print("startCount is:");
    terminal.println(startCount);
    terminal.flush();

    if (running == true)
    {
      terminal.print("ResetButton");
      terminal.flush();
      //Blynk.virtualWrite(button, 0);
      Blynk.syncVirtual(V1);
      Blynk.virtualWrite(stepValue, 0);
    }
  }

  if (millis() - startCount > runCount)
  {
    digitalWrite(pump, LOW);
    running = false; // done
    terminal.println("DONE");
    terminal.flush();
  }
}


This part in setup is confusing and unnecessary:

Blynk.syncVirtual(V1);
Blynk.virtualWrite(stepValue, 0);

You are asking the hardware to pull the latest value from the app, but then right afterwards you set the value to 0 anyway. So first line is redundant.

Also you don’t need a button (V1) to “send the value to the hardware” as the moment you make a change to your step widget, it updates anyway. So unless your button is doing something else. its pointless.

1 Like

The button is intended to halt any execution of all following code until the press is detected. The reason this is important is because once functional, I intend to duplicate for 7 more pumps totaling 8 and I would like the ability to adjust each, then possibly readjust and tweak. Once I’m satisfied, I can tick each respective button at will and trigger the respective pump(s) into action. I will remove the syncVirtual call from the setup. That was just me winging it as some of the descriptive language in the docs section is somewhat abbreviated, and lack of coding skills makes some stuff difficult to fill in the blanks. Thank you for the suggestions Jamin, you are very helpful!

Edit - BTW, the button stays in the ON position regardless of what I tried. I have it set to switch, but only because I wish that it remain in state and readjusted in code.

Short reply on the button incase it’s unclear

You have two modes
Push, means you tap to use, it goes from one state to another and reverts to the first after you let go.
Every state change calls for a
BLYNK_WRITE event in the hardware.

When it is pushed it sends a 1, as soon as you release it sends a 0.

Switch works the same but it requires taps to change states. This is most likely what you want to use.

To change the button state from hardware you need to push data to the app.

Blynk.virtualWrite(V0, 1) //maybe a string “1”, can’t remember at the moment.

in case you want to switch stuff with the button its basically this. You can keep it simple, assign values to variables
or do more complex code. But in your program it seems that this should just toggle a value to control the pumps so
you can use SimpleTimer library for your pumpcode and have this button code simply enable / disable timers

BLYNK_WRITE(V0) // Pin assigned to button
{
   int pinState = param.asInt(); //1 is On, 0 is Off
   if (pinState == 1)
   {
      //Do On code
   }
   else
   {
      //Do Off Code
   }
}

Thank you both! I have made a few changes and for the most part, I have a functional sketch now, but but it’s slightly buggy atm. I am yet to adjust the code to get all my “on” code inside, but part of the on code is resetting V0 to 0. To my knowledge, I can’t put the BLYNK_WRITE block for stepValue inside another BLYNK_WRITE, and I fear doing so would be major regression from where it’s at now.

Here’s what I have so far,

/*
  This is to be a sketch to run a peristaltic pump with Arduino and Blynk.  The circuit is an Ethernet Shield on a Mega
  with an LED connected to D3\GND.  Somewhere on the internet, Blynk runs an Android\iPhone app.  On my app, I have a button
  rendered as a switch (on/off) and a step value incrementer\decrementer.  A value between 0.00-80.00 in 0.25 steps is dialed
  in according to human preference.  Once at desired value, button is pressed and the rest of the sketch can run.

  With a seperate sketch, I was able to run each (of 8) pumps till 100ml of koolaid was dispensed while millis was being
  counted.  I did this 3 times and averaged the millis count per each motor, then divided that by 100 to derive the multiplier.
  When the multiplier is multiplied with the step value, the total amount of milliseconds to produce the desired amount of
  ml is known.
*/
#include <SPI.h>                           //Used by Blynk
#include <Ethernet.h>                      //Used by Blynk
#include <BlynkSimpleEthernet.h>           //Used by Blynk
#include <SimpleTimer.h>
#define BLYNK_PRINT Serial
char auth[] = "PasteAuthCodeHere";       //Paste code that app emailed you between "quotes"

int button = 0;                       //expecting 0 or 1
int oldButtonState = 0;
boolean pumping = false;
float stepValue;                           //expecting 0.00-80.00
const byte pump = 3;                             //Pump connected @ D3
uint32_t runCount;                            //Step Widget to determine amount of ml/Output 0-80/Step 0.2
uint32_t startCount;                       //Millis reference used to calculate stopCount
uint32_t stopCount;
uint32_t multiplier = 858;                 //Number of milliseconds for motor to produce 1ml of liquid
SimpleTimer timer;                         // SimpleTimer instance named timer
WidgetTerminal terminal(V2);

BLYNK_WRITE(V1) {                   // button
  button = param.asInt();      // a button press triggers the code into action
  Blynk.syncVirtual(V1);            // trigger V1 function below to set current stepValue from widget
}

BLYNK_WRITE(V0) {                   // step
  stepValue = param.asFloat();      // 0.00-80,00\0.25 per step.  Once desired value is set, press button on V1
}

void setup()
{
  Serial.begin(9600);
  Blynk.begin(auth);
  while (Blynk.connect() == false) {}
  timer.setInterval(1500L, checkPump);
  pinMode(pump, OUTPUT);
  Blynk.virtualWrite(V1, 0);
  //Blynk.virtualWrite(V0, 0);
}

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

void checkPump()
{
  runCount = stepValue * multiplier;
  if (pumping == false && button != oldButtonState
      && button == 1) // launch!
  {
    button = oldButtonState;
    startCount = millis();
    pumping = true; // launched
    digitalWrite(pump, HIGH);
    terminal.print("stepValue is:");
    terminal.println(stepValue);
    terminal.print("runCount:");
    terminal.println(runCount);
    terminal.print("startCount is:");
    terminal.println(startCount);
    terminal.flush();
  }
  if (pumping == true)
  {
    Blynk.virtualWrite(V0, 0);
    terminal.println("Pumping");
    terminal.flush();
  }
  stopCount = startCount + runCount;
  if (millis() - startCount > millis() - stopCount)
  {
    terminal.print("stopCount:");
    terminal.println(stopCount);
    digitalWrite(pump, LOW);
    pumping = false; // done
    Blynk.virtualWrite(V1, 0);
    terminal.println("ResetButton");
    terminal.flush();
  }
}


Remove the sync, it’s basically calling itself in a forever loop,
syncVirtual calls BLYNK_WRITE

1 Like

My last contribution for this day, read up a little on simpletimer.

If you use a global variable
int timerIndex;

Then when you set an internal
Do like this
timerIndex = setInterval(1500L, checkPump);

This saves the timers index so that you can enable and disable

timer.enable(timerIndex);
timer.disable(timerIndex);

1 Like

Thank you very much! It works perfectly now. I just need to connect to an actual pump and verify milliliters produced, but calibration adjustments will be much easier.

Thanks again!
Mike

Good study leads are always appreciated. I like the way you share info! Thanks again Fettkeewl!

1 Like

Dial-a-Dose :grinning:

Do you think Switch Case is a viable option to account for other pumps? I do hope I don’t need to duplicate all the variables because I think I’ll run out of memory.

Assuming you have put in some work to your code since your last post, can you update this thread with the latest code?

Also Im not to familiar with your hardware, does it perhaps have 8 avalible GPIOs that are in the same interval?
1-9
2-10
3-11
or similar to that? Would open up usage for cleaner code with arrays

Thanks again for all the feedback and help Fettkeewl.

My board is an EtherMega from Freetronics. For the 8 pumps, I use pins D2-D9 and a GND a few pins over. The circuitry is a simple TIP120 circuit with diode and resistor between the transistor and Dpin. DB9 cable connect the 2 enclosures.

Wanting to get a jump on things before you replied, I started migrating Switch Case code into the 1 pump Blynk sketch, but thankfully I separated them into 2 sketches. I have a beginners level understanding with arrays, so I can jump right in to some reference material and see if I can make them apply.

Here’s the code that runs sketch in the video;

/*

*/
#include <SPI.h>                      //Used by Blynk
#include <Ethernet.h>                 //Used by Blynk
#include <BlynkSimpleEthernet.h>      //Used by Blynk
#include <SimpleTimer.h>
#define BLYNK_PRINT Serial
char auth[] = "PasteAuthCodeHere";       //Paste code that app emailed you between "quotes"

int button = 0;                       //expecting 0 or 1
int oldButtonState = 0;
boolean pumping = false;
float stepValue;                      //expecting 0.00-80.00
const byte pump = 2;                  //Pump connected @ D2
uint32_t runCount;                    //Step Widget to determine amount of ml/Output 0-80/Step 0.2
uint32_t startCount;                  //Millis reference used to calculate stopCount
uint32_t stopCount;                   //
uint32_t multiplier = 858;            //Number of milliseconds for motor to produce 1ml of liquid
SimpleTimer timer;                    // SimpleTimer instance named timer
WidgetTerminal terminal(V2);

BLYNK_WRITE(V1) {                     // button
  button = param.asInt();             // a button press triggers the code into action
}

BLYNK_WRITE(V0) {                     // step
  stepValue = param.asFloat();        // 0.00-80,00\0.25 per step.  Once desired value is set, press button on V1
}

void setup()
{
  Serial.begin(9600);
  Blynk.begin(auth);
  while (Blynk.connect() == false) {}
  timer.setInterval(1500L, checkPump);
  pinMode(pump, OUTPUT);
  Blynk.virtualWrite(V1, 0);
  Blynk.virtualWrite(V0, 0);
}

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

void checkPump()
{
  runCount = stepValue * multiplier;
  if (pumping == false && button != oldButtonState
      && button == 1) // launch!
  {
    button = oldButtonState;
    startCount = millis();
    pumping = true; // launched
    digitalWrite(pump, HIGH);
    terminal.print("Milliliters:");
    terminal.println(stepValue);
    terminal.print("runCount:");
    terminal.println(runCount);
    terminal.print("startCount is:");
    terminal.println(startCount);
    terminal.flush();
  }
  if (pumping == true)
  {
    Blynk.virtualWrite(V0, 0);
    terminal.println("Pumping");
    terminal.flush();
  }
  stopCount = startCount + runCount;
  if (millis() - startCount > millis() - stopCount)
  {
    terminal.print("stopCount:");
    terminal.println(stopCount);
    digitalWrite(pump, LOW);
    pumping = false; // done
    Blynk.virtualWrite(V1, 0);
    terminal.println("ResetButton");
    terminal.flush();
  }
}

Edit - I still need to locate a smaller measuring cup to verify output, I hope later today.

Alright looks good now. So here is what im thinking,

you declare an array of the physical pins used for pumpcontrol

int pumpPin[8] = { 2, 3, 4, 5, 6, 7, 8, 9 };
int pumpState[8]  = { 0, 0, 0, 0, 0, 0, 0, 0 }; //1 is on 0 is off 
int stepValues[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; // some defaults..?

Now your pins are accesible through using positioning of the array
so pumpPin[0] = 2
pumpPin[1] = 3
pumpPin[2] = 4

and so on.

There is a Default BLYNK_WRITE function that is called when you write to virtual pins
that dont have specific BLYNK_WRITE code written, looks like this and can we used for all 8 pump
buttons and sliders.

BLYNK_WRITE_DEFAULT()
{
 /// code
}

Furthermore every virtual pin is defined with a correspondig number
V0 = 0
V1 = 1
V2 = 2 and so on.

This could be used to access your array of pumpinformation or stepValues, so reserve a range of virtual pins for your buttons. For simplicty lets say V0-V7 are your button widgets. Lets say V10-V17 are each corresponding steppper/slider widget you want tied to a button.

Now use this to simplify your writes, do not make any BLYNK_WRITE definitions for you button and slider/stepper pins

BLYNK_WRITE_DEFAULT()
{
    int vPin = request.pin();  // gives you what Virtual pin got triggered
    
    if (vPin <= 7)  // Button was pressed
         pumpState[vPin] = param.asInt(); // save button state to array at correct position
    if (vPin>=10 && vPin <= 17)  // stepper/Slider adjusted
         stepValue[vPin-10] = param.asInt(); // notice subtraction of 10 to get array position
}

Now should follow modification of your timers and pumpcode to use array logic so that you dont have to copy paste every function call 8 times :stuck_out_tongue:

basically a for loop from 0 to 7 to cover all pumps
check each pumpState[i] if its 0 or 1, to see wether or not to enable the pump
use stepValue[i] to get the slider/stepper value
and use pumpPin[i] to controll the pump.

void checkPump()
{
   for (int i = 0; i < 7; i++)
   {
        if ( pumpState[i] == 1) 
        {
             //do pumpcode
        }
    }
}

Hope its clear enough :slight_smile:

A way of defaulting your widgets

for (int i = 0; i < 7; i++) 
{
    Blynk.virtualWrite(i, pumpState[i]);
    Blynk.virtualWrite(i+10, stepValue[i]);
} 

Thank you for all of this info! Seriously!!!

When I was mentally putting pieces together last night, I figured I could do it all with just one more step widget to select between the elements that I call pumpNumber. I figure it’s just another variable to add to the existing sentences. Do you see any reason why another step widget couldn’t be used to toggle between array elements?

Lets see if I get this correct,

instead of 8 different buttons and steppers you want

1 on/off button, 1 stepper widget for your stepValue and 1 more for selecting the pump?

If that’s possible, yes. Can the channel that is selected apply the respective values (pin # and multiplier value) to the variables used in the above posted sketch?

Sure but then it defeats the purpose of the default code.
V0 pump selector
V1 steppvalue selector
V2 on off button

Simply do three BLYNK_WRITE functions to handle the entire user interface for controlling pumps
In your pump selector widget use the min max of 1-8 for a more understandable user interface.
Account for it in hardware

int i = 0 // global value for tracking pump index

// updates pump index called i, sends the saved values back to the app
BLYNK_WRITE(V0) // index selector
{
    i = param.asInt() - 1; // Accounts for user interface values 1-8 -> 0-7
    Blynk.virtualWrite(V1, stepValue[i]);
    Blynk.virtualWrite(V2, pumpState[i]);
}

BLYNK_WRITE(V1) { stepValue[i] = param.asInt(); }

BLYNK_WRITE(V2) { pumpState[i] = param.asInt(); }


2 Likes

Must be your lucky day, I felt like giving this to you, it’s untested but I think I got it nailed down.

Since you work with 8 pumps, it might sometimes be nice to just jump between those that are “on”.
If you add another stepwidget, set minmax 1-8. Step = 1, Send step = yes, loop values = off

This only works if I understood the step sending part. I haven’t tested the stepper widget yet. But, if when using step = 1, left/down arrow will send -1, right/up arrow will send 1, then this should work.

BLYNK_WRITE(V4) // index selector
{ 
	int direction = param.asInt(); // 1 = Check for Next pump that is On, -1 = Check for Previous pump that is on
	int j = i;	// save current index
	if (direction == 1)
        {
		if (j + 1 > 7) j = 0; else j++;	// if j + 1 is out of arrays last position, loop back to 0 else increment
		for (j; j != i; j++)				// loops all indexes except current
		{
			if (pumpState[j] == 1) goto indexFound;  // When the next active pump is found, leave for loop
			if (j == 7) j = -1;		// loop back, 7 is last array pos, set to -1 so next loop is -1 + 1 = 0, back to pos 0
		}		
	}
	else // same logic here except in reverse
	{
		if (j - 1 < 0) j = 7; else j--; // if j - 1 is below first position 0, loop back to 7 else decrement
		for (j; j != i; j--)
		{
			if (pumpState[j] == 1) goto indexFound; 
			if (j == 0) j = 8;
		}
	}
	return;  // code gets to this line, end function, no running pumps found
	
	:indexFound
	i = j;
	Blynk.virtualWrite(V0, j+1);
	Blynk.virtualWrite(V1, stepValue[j]);
	Blynk.virtualWrite(V2, pumpState[j]);
	Blynk.virtualWrite(V4, j+1);
}

edit typo

2 Likes