Run 8 Pumps From Blynk

I’ve been staring at your code (thank you for it BTW) for the past 2 days as coding is still new to me and some sketches take a little time for me to be able to read my way through and grasp what is happening. That said, I think what I seek and what have given differ slightly. Your code calculates which pump is to be selected, but there is also at least one other variable value that must accompany each pump. When I initially tested each, I ran each pump for as long as needed to produce 100 ml of water and my Arduino counted how many millis. I performed this test on each pump 3 times. I then added the 3 results and divided the sum of each by 100 to derive the amount of millis it takes for each pump to produce 1ml. In my sketch above, this number is expressed as “multiplier”.

When approaching this project, I knew I needed to get the code to work from Blynk and to control the output of a single pump(LED). The length of this thread is just the finish of the grief I went through to get this far on this particular project. That said, I know I must endure more grief (mostly due to my lack of ability to learn quicker) and continue to learn as much as I can soak up per day.

I need the Sketch to receive the pump# from Blynk, assign which of 8 values is to be pair to which of 8 digital pins, and the math listed above in my sketch to be applied to those constant values. Currently, because I only have a 2amp 12v power supply, I don’t want to run more than 2 pumps at once just to be safe. I can limit the usage by not pressing buttons until a pump is finished. I will keep staring at your code some more as I get a little excited the more of it I comprehend, but I feel it is only the start of what I need to get this project to where I want it to be.

Thanks again for the assistance!

I’ve been playing around with the code, trying to expand it and here is what I am trying. I’m fairly certain it won’t compile, but I wanted to ask if an array can be created inside of a BLYNK_WRITE function?

BLYNK_WRITE(V1) {               //array to bundle pump# with respective multiplier                 
  pumpNum = param.asInt();                          //name of array
  int a = param[1].asInt() {pump1, multiplier1};    //D2, 858 (millis)
  int b = param[2].asInt() {pump2, multiplier2};    //D3, 827 (millis)
  int c = param[3].asInt() {pump3, multiplier3};    //D4, 872 (millis)
  int d = param[4].asInt() {pump4, multiplier4};    //D5, 865 (millis)
  int e = param[5].asInt() {pump5, multiplier5};    //D6, 887 (millis)
  int f = param[6].asInt() {pump6, multiplier6};    //D7, 895 (millis)
  int g = param[7].asInt() {pump7, multiplier7};    //D8, 913 (millis)
  int h = param[8].asInt() {pump8, multiplier8};    //D9, 843 (millis)
}

Someone on the arduino forum suggested that I learn how to use “struct” for this, but what I’ve read so far is not at all easy to comprehend. I’ve actually began to learn arrays months ago and will be easier for me to work with and learn from, so I hope I can go with Fettkeewl’s original suggestion in post 14.

See answer in bold :slight_smile:

By keeping every array consistent its easy to track which pump you are working with. You can do as many arrays as you want. When you comprehend it you can simplify by using two or multi dimensional arrays but for now lets keep it simple
as stated previously, setup your arrays like this.

// from left to right position every array hold values for 
// your pumps 1-8, by using index 0-7
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..?
int multiplier[8] =  { 800, 812, 842, 800, 996, 0, 0, 0 }; // your measured values
int pumpRunning[8]  = { 0, 0, 0, 0, 0, 0, 0, 0 }; //1 is on 0 is off 
int pumpStartTime[8]  = { 0, 0, 0, 0, 0, 0, 0, 0 }; // when millis - starttime >  (stepvalue * multiplier) stop pump

Just by reading your checkpump code this should maybe cover it all? Lets modify your checkpump code.’
Notice its only the essentials, throw in your terminal prints where you see fit.
Study and understand below, ask questions if need be :slight_smile:

Lets keep arrays for now untill you are ready for structs

void checkPump()
{
	for (int x = 0; x < 7; x++) // Loop all pump indexes
	{	
		if (pumpState[x] == 1 && pumpRunning[x] != 1) // Pump should run but isn't running = Start pump
		{
			pumpRunning[x] = 1; // pump is now running
			digitalWrite(pumpPin[x], HIGH); // gets the physical pin and sets it high
			Blynk.virtualWrite(V2, HIGH); // updates app button
			pumpStartTime[x] = millis(); // saves start time
		}
		if (pumpRunning[x] == 1 && millis() - pumpStartTime[x] >  stepValues[x] * multiplier[x]) 
		{
			digitalWrite(pumpPin[x], LOW); // stop pump			
			pumpRunning[x] = 0; // pump is now done running, can be started again
			if (x == i)
			    Blynk.virtualWrite(V2, LOW);// update app if current pump is displayed in app
		}
	}
}

1 Like

I’m not really sure what you are trying to accomplish here… But that won’t work to the best of my knowledge.

Edit: you can create arrays inside BLYNK_WRITE but not in that way

Do you want to be able to change your multiplier from the app?

Just add another step widget?

1 Like

If you are on android you should try this app out. I’m using it myself since I’m more of a C# guy than C++.

1 Like

Here is a hint on using struct

cout is equivalent to Serial.print
Study it :slight_smile:

Edit :slight_smile:
Struct as array

Wow man, I just can’t thank you enough for all of this excellent info you’re sharing with me. When I said I was playing around with the code, I literally meant playing around with it as I really don’t know what I’m doing with arrays or BLYNK_WRITE, so when making that block of code, I had 2 tabs open on my browser, first to the Blynk docs sections, the other to Arduino.cc/reference/arrays and gathered what I could to piece that thing together. I had a feeling it was wrong, but sometimes mistakes made leads me to the knowledge needed to ask better refined questions.

I will start adjusting my sketch to include your most recent code donations and try to work out any compile errors. Thank you again, very much!

Edit - Forgot to mention that the motors are all the same as far as I can tell, but for whatever reason(s), it takes different lengths of averaged time for each pump to produce 100ml. This is the purpose of the multiplier and actually, I will LINK you to the youtube video that this project was to emulate. Except this project will run 8 pumps, and instead of physical buttons and an LCD, I will use Blynk over the web for the blatantly obvious reasons! Blynk just makes the microcontrollers sooooo much better!

1 Like

@Fettkeewl, When using the blocks you shared in post #23, the output doesn’t produce favorably. When reading through the code, I am unable to see how the values that are given from Blynk are associated with the variables in the code. When using BLYNK_WRITE to make these associations, I get compile errors from associating the array(s) of int variables with param.asInt. I commented out the BLYNK_WRITE lines, and the sketch compiles and uploads, but doesn’t produce.

HERE is a short video of the sketch running the hardware and what’s happening in my app.

Update with your code, there might be something there for me to look at. Also your video wasn’t available, privacy setting?

Also tell me what your setup is for each widget used, with regards to the min max values just so that there isnt something colliding there

I updated the video to PUBLIC, HERE is another link for convenience.

V0 = Step Widget to select between pumps 1-8
V1 = Step Widget to dial in the value preset at 0.25 per step
V2 = Button Widget set to Switch. When button is “0”, do nothing, when button is “1”, receive values from V0 & V1
Edit - Both Step Widgets are set to “Send Step” = NO, “Loop Values” = ON

#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[] = "PasteAuthCodeBetweenQuotes";       //Paste code that app emailed you between "quotes"

SimpleTimer timer; 
WidgetTerminal terminal(V3);
// from left to right position every array hold values for 
// your pumps 1-8, by using index 0-7
int pumpPin[8] = { 2, 3, 4, 5, 6, 7, 8, 9 };      //Digital pins used
int pumpNumber[9]  = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };  //V0 (1 - 8)
float stepValues[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; //V1 (0.25 per step)
int multiplier[8] =  { 858, 827, 872, 865, 887, 895, 913, 843 }; //ms per ml
int pumpRunning[8]  = { 0, 0, 0, 0, 0, 0, 0, 0 }; //1 is on 0 is off 
int pumpStartTime[8]  = { 0, 0, 0, 0, 0, 0, 0, 0 }; // when millis - starttime >  (stepvalue * multiplier) stop pump
//BLYNK_WRITE(V0) {                 // Step Widget
//  pumpPin = param.asInt();}       // selects between D2-D9
//BLYNK_WRITE(V1) {                 // Step Widget
//  stepValues = param.asFloat();}  // 0.00-80,00\0.25 per step.  Once desired value is set, press button on V1
//BLYNK_WRITE(V2) {                 // Button Widget set to switch
//  pumpNumber = param.asInt();}     // a button press triggers the code into action

void setup()
{
  Serial.begin(9600);
  Blynk.begin(auth);
  while (Blynk.connect() == false) {}
  timer.setInterval(1500L, checkPump);
   for(int p = 2; p <= 9; p++)
   {
       pinMode(pumpPin[p], OUTPUT);
   }
  Blynk.virtualWrite(V1, 0);
  Blynk.virtualWrite(V0, 0);
}

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

void checkPump()
{
  for (int x = 0; x < 8; x++) // Loop all pump indexes
  { 
    if (pumpNumber[x] == 1 && pumpRunning[x] != 1) // Pump should run but isn't running = Start pump
    {
      pumpRunning[x] = 1;             // pump is now running
      digitalWrite(pumpPin[x], HIGH); // gets the physical pin and sets it high
      Blynk.virtualWrite(V2, HIGH);   // updates app button
      pumpStartTime[x] = millis();    // saves start time
    }
    if (pumpRunning[x] == 1 && millis() - pumpStartTime[x] >  stepValues[x] * multiplier[x]) 
    {
      digitalWrite(pumpPin[x], LOW);  // stop pump     
      pumpRunning[x] = 0;             // pump is now done running, can be started again
      if (x == 1)
          Blynk.virtualWrite(V2, LOW);// update app if current pump is displayed in app
    }
  }
}

I also changed the name of a variable so I can better comprehend the flow of code as I read through it. Also, I tried augmenting the first if statement to read as follows;

void checkPump()
{
  for (int x = 0; x < 8; x++) // Loop all pump indexes
  { 
    if (pumpNumber[x] != 0 && pumpRunning[x] != 1) // Pump should run but isn't running = Start pump
    {

This at least triggered several of the pumps to run at the same time in what appeared to be a blink example manner (on for 1000, off for 1000). Still a ways to go I imagine.

You are forgetting to use the variables as arrays, you need to use the brackets after variable name.
And you are missing a global index variable for tracking which pump is set.
Remember your pumpselector only keeps track of what index of the array to access when saving
your other two variables, step and on/off. Also remember that your arrays index is from 0-7 but interface is 1-8
so you need to account for it by subtracting 1.

int pumpIndex = 0;

BLYNK_WRITE(V0) {                 // Step Widget
  pumpIndex = param.asInt() - 1;}       // selects between D2-D9
BLYNK_WRITE(V1) {                 // Step Widget
  stepValues[pumpIndex] = param.asFloat();}  // 0.00-80,00\0.25 per step.  Once desired value is set, press button on V1
BLYNK_WRITE(V2) {                 // Button Widget set to switch
  pumpNumber[pumpIndex] = param.asInt();}     // a button press triggers the code into action

In your setup the foor loop is not using the array properly to access your pump pins.
Again, when working with arrays you need to use their INDEX to get the VALUE which is saved

for(int p = 0; p <= 7; p++)
{
    pinMode(pumpPin[p], OUTPUT);
}

when you access pumpPin at index 0 you get the value 2
pumpPin[0] gives 2
pumpPin[1] gives 3
pumpPin[2] gives 4 and so on

Try the edits

Just to clarify

if you have an array say pumpNumber

everytime your variable is followed by the equals sign = you are assigning values to an indexed spot,
in every other case you are fetching values from an index

Assings
pumpNumber[0] = 2;
pumpNumber[1] = 3;
pumpNumber[2] = 4;

Get value
int i = pumpNumber[0];
Serial.println(“This is pump #” + pumpNumber[2]);

This was the initial code I gave you for the pump Selector widget. Notice the virtual writes, they are there to update your app interface with the correct numbers for the selected pump, you forgot it in your code :slight_smile:

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

Any luck @myggle?

Because stepValue (which I renamed to DOSEml) is a float. Blynk.virtualWrite(V1, [i]) is causing an error because i is an int and DOSEml is a float. Perhaps moving the virtualWrite somewhere down the sketch after a succession of affirmative if statements? In the previous sketch, the float was converted into a uint32_t after being multiplied by the multiplier value and stored in “runCount” which is also a uInt32_t.

Question, would BLYNK_WRITE and/or Blynk.virtualWrite function if declared as uInts?

Blynk.virtualWrite is overloaded for the common data types

Blynk.virtualWrite(pin, “abc”);
Blynk.virtualWrite(pin, 123);
Blynk.virtualWrite(pin, 12.34);
Blynk.virtualWrite(pin, “hello”, 123, 12.34);

All work.

If this is the way you use it
Blynk.virtualWrite(V1, [i])

then your [i] is your error, what is “[i]” would the compiler ask…
try
Blynk.virtualWrite(V1, stepValue[i]);
and you should not get errors

Here you need to check x against the global variable for pump index, not a static value.
Else it wont work properly
use i or pumpIndex or what ever you call it :slight_smile:

1 Like

you can even get the lessons, exercises etc from desktop computer pointing at: https://www.sololearn.com/

my two cents!

2 Likes

@MikeKGR, I signed up and will work in some study time beginning this weekend.

@Fettkeewl, I am making some headway, the sketch compiled and uploaded, but I adjusted for some arbitrary values and only pump 1 ran the Blink pattern, but this is likely something to do with 1500L interval. I have to run for work, but will get right back to it as soon as I get home! Thanks again for all the help! You’re a God send!

1 Like

After the hours and days reading through the code and starting to grasp the concepts you’ve shared, I began to see the relations and how things are changed. That said, I reverted the code back to a more familiar layout, and I tried to use variables with descriptive names with the exception of “x”. In the process of changing things and testing with every change, I was able to identify some things. The for loop in the function was causing the activation of every pump number above what I selected, so when I selected 3, 3-8 activated. I presume the incrementing caused that, so I removed it and focused onto the “i”. In the beginning it was achieving the same end result as the for loop and it was useless, but since I removed the for loop, the -1 became relevant again, but since most of the arrays already had an [x], I dropped the “i” as well and made x a global to equal pumpNumber-1. I also honed in on the use of arrays and after much thought, I really believe I only need two arrays, possibly three. Correct me if I am wrong, but isn’t the “pumpNumber” Step Widget on V0 only going to be passing along an int? Does the compiler need to comprehend that this is just one of a series, or can it manage just fine when it receives a single value?

The way I want it to run is to only utilize a single pump at any one given time. Later on I will explore opening that up to multiple pumps at the same time when I have an adequate power supply to source enough current should all running pumps miraculously seize up and pull stall current. But for now, I am just wanting to select one pump, associate it with the corresponding positions in 2 arrays, then execute the math, as my previous sketch did well.

Still, if you feel I should add back in some/all of the arrays, I will and change what I need to till it compiles again, but in the current structure, at least the pumpNumber[8] {…} won’t compile.

All of that said, my sketch in it’s current state produces nothing.:laughing: I suppose the proper thing to do is insert a terminal.print into each of the levels of if statements, but just looking at the code and how I was able to spell it out in verbiage/syntax I comprehend, and can read through it till the end, I still can’t figure out what I am doing wrong. It compiles and uploads, but when the values are entered and button is ticked, pumps do nothing and Vpin states do not reset. Perhaps a fresh set of eyes in the morning is what I need? Here’s the sketch;

#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"

SimpleTimer timer;
WidgetTerminal terminal(V3);
// from left to right position every array hold values for
// your pumps 1-8, by using index 0-7

int pumpPin[8] = { 2, 3, 4, 5, 6, 7, 8, 9 };         //Digital pins used
uint32_t multiplier[8] =  { 858, 827, 872, 865, 887, 895, 913, 843 }; //ms per ml
uint32_t startPump = 0;
uint32_t stopPump = 0;
uint32_t runCount;
int pumpNumber;         //V0 Step Widget (1.0 per step, send step/NO, loop values ON)
float DOSEml;           //V1 Step Widget (0.25 per step, send step/NO, loop values ON)
int button = 0;         //V2 Button Widget set to Switch
bool pumpRunning = false;
int zero = 0;
int x = pumpNumber - 1;   //Zero indexing

BLYNK_WRITE(V0) {                 // Choose Pump
  pumpNumber = param.asInt();
}
BLYNK_WRITE(V1) {                 // Adjust Dosage
  DOSEml = param.asFloat();
}
BLYNK_WRITE(V2) {                 // Activate Chosen Pump
  button = param.asInt();
}

void setup()
{
  Serial.begin(9600);
  Blynk.begin(auth);
  while (Blynk.connect() == false) {}
  timer.setInterval(500L, checkPump);
  for (int p = 2; p <= 9; p++)
  {
    pinMode(pumpPin[p], OUTPUT);
  }
  Blynk.virtualWrite(V0, 0);
  Blynk.virtualWrite(V1, 0);
  Blynk.virtualWrite(V2, 0);
}

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

void checkPump()
{
  if (button != zero && button == 1 && pumpRunning == false)    //if NO, do nothing! If YES, proceed.
  {
    pumpRunning = true;  // pump is now running
    digitalWrite(pumpPin[x], HIGH); // sets selected pin HIGH
    startPump = millis();           // saves start time to calculate from
    runCount = DOSEml * multiplier[x];
    stopPump = startPump + runCount;
    
    if (millis() - startPump > millis() - stopPump)
    {
      digitalWrite(pumpPin[x], LOW); 
      pumpRunning = false;
      Blynk.virtualWrite(V0, 0);
      Blynk.virtualWrite(V1, 0);
      Blynk.virtualWrite(V2, 0);
    }
  }
}