Spark & Spark Relay controlled Peristaltic Dosing Pumps

I dont know if calcium can be measured directly… its normally done in a reactor with CO2 or something… i think we used a syringe to draw liquid out into a reactor tube… cant remember exactly, i designed the stepper motor drivers that moved everything around and drove the pumps etc. the chemist guy would just say we need this to do that and i would make something to suit. the setup was quite elaborate, there was a 3 axis CNC like structure, 3 or 4 pumps, 5 or 6 probes… and 2 or 3 syringes. there was about 5 z-axis functions for all the different probes and stuff. and a rinse pot to clean it all between samples. it was really quite amazing to see it all working autonomously, it was like we were working in a top secret pharmaceutical lab or something.

I noticed another thread you may be interested in

Hi @james211

I was hoping to provide an elegant, general purpose solution, but tonight I just banged out some specific code for your application.

I defined the command String as hh:mm:ss*duration where hh is hours, mm is minutes, ss is seconds, and duration is in seconds. So as an example would, to run relay 1 at 6:42:00pm for 10 seconds you would do this using curl:

curl<<device id here>>/setRelay1?access_token=<<access token here>> -d "args=18:42:00*10"

To read back the value do

curl<<device id here>>/getRelay1?access_token=<<access token here>>

You have to follow this format exactly–the parser is very quick and dirty!

Let me know if you have problems.

Here is the code:

// This #include statement was automatically added by the Spark IDE.
#include "SparkTime/SparkTime.h"

UDP UDPClient;
SparkTime rtc;

int relayPin[4] = {D0,D1,D2,D3};

//By relays number
bool    isSet[4] = {false,false,false,false};
uint8_t startHours[4]   = {0,0,0,0};
uint8_t startMinutes[4] = {0,0,0,0};
uint8_t startSeconds[4] = {0,0,0,0};
unsigned int duration[4] = {0,0,0,0};

unsigned long stopTime[4] = {0,0,0,0}; 

#define NCHARS 32
char relayStr[4][NCHARS];

void setup()
   for(int relay=0;relay<4;relay++) {
       pinMode(relayPin[relay], OUTPUT);
       digitalWrite(relayPin[relay], LOW);
   Spark.function("setRelay1", setRelay1);
   Spark.function("setRelay2", setRelay2);
   Spark.function("setRelay3", setRelay3);
   Spark.function("setRelay4", setRelay4);
   Spark.variable("getRelay1", relayStr[0], STRING);
   Spark.variable("getRelay2", relayStr[1], STRING);
   Spark.variable("getRelay3", relayStr[2], STRING);
   Spark.variable("getRelay4", relayStr[3], STRING);

rtc.begin(&UDPClient, "");
rtc.setTimeZone(-5); // gmt offset


void loop() {

unsigned long currentTime =;

for(int relay=0;relay<4;relay++) {
    if (TRUE==isSet[relay]) {
        if (rtc.hour(currentTime)==startHours[relay] &&
            rtc.minute(currentTime)==startMinutes[relay] &&
            rtc.second(currentTime)==startSeconds[relay]) {
                stopTime[relay] = currentTime + duration[relay];
            } // start time
    } // is set
    if (currentTime >= stopTime[relay]) {



// Parse the format: 08:56:05*6000 or 18:59:00*10
//  hh:mm:ss*duration
int parseTimeDuration(String command, int relay) {
    char copyStr[33];
    char *p = strtok(copyStr, ":");
    startHours[relay]   = (uint8_t)atoi(p);
    p = strtok(NULL,":");
    startMinutes[relay] = (uint8_t)atoi(p);
    p = strtok(NULL,":");
    startSeconds[relay] = (uint8_t)atoi(p);
    p += 3;
    duration[relay]     = atoi(p);
    isSet[relay] = true;
    sprintf(relayStr[relay], "%02d:%02d:%02d*%d",startHours[relay],startMinutes[relay],startSeconds[relay],duration[relay]);
    return 1;

int setRelay1(String command) {
    return parseTimeDuration(command, 0);
int setRelay2(String command) {
    return parseTimeDuration(command, 1);
int setRelay3(String command) {
    return parseTimeDuration(command, 2);
int setRelay4(String command) {
    return parseTimeDuration(command, 3);


@bko - Thank you! So correct me if I’m wrong, but the two curl codes belong in an html file correct?

Hi @james211

curl is a command line tool you can use for testing. It does what a web browser does except from a command shell and is used in the all Spark.variable, Spark.function, and Spark.publish example docs since it is easy to understand how it works.

Don’t worry: I know that you still need a web page like too!

1 Like

thank you @bko, I appreciate your help. I’ll play with what you gave me with in terminal and see what happens. I’m excited to see what you come up with for a webpage.

Out of curiosity, in the code you just gave me, are you using the spark real time clock or the rtc library you wrote?

I left it using the SparkTime NTP based rtc, but it would be easy to fix up for the newer

hmmm…what might I be doing wrong?

Hi @james211

Do you have the right device ID? Did the code flash to core OK?

The error you are getting indicates that the functions and variables I wrote are not on that core.

If you do you the GET request (the second one without the -d "arg=… part), leaving off teh getRelay1 part, but leaving the access_token, the cloud will tell you what functions and variables that core has.

hmmm…not really sure whats going on at the moment. A few notes, to get my token and ID, I’m getting that from the Cores and Settings menus in the web IDE, is that correct?

Second, when I go into terminal I’m typing spark login
It then asks for my email and password. As soon as I hit return I get a message that says

Got an access token! dc5xxxxx logged in!  { '0' : 'xxx...' }

From there I am putting in your curl code with the ID and token I took from the web IDE. Does that seam correct?
(note: the access token that is shown to me in terminal is not the same as the token I see in the web IDE)

On a side note, I noticed that Relay3 is stuck in the on position and currently there is nothing attached to it. Thoughts?

So you should be able to use the device id from the core target icon in the webIDE and the access token from the gear icon on the bottom left of the webIDE. Let’s try this first to see if your core is running firmware with variables and functions:

curl<<device id here>>/?access_token=<<access token here>>

This should return a JSON that shows four functions and four variable, setRelay1 to setRelay4, and getRelay1 to getRelay4.

If that doesn’t work, try leaving off the device id to see all your cores:

curl<<access token here>>

I added the isSet[] array specifically so that times that had never been set would not go on at midnight. I can’t think of why relay 3 would be stuck on.

Ok, that worked…so did the previous curl commands you told me to try. Testing now…

  "id": "53f....",

“name”: “spark”,
  “connected”: true,
  “variables”: {
    “getRelay1”: “string”,
    “getRelay2”: “string”,
    “getRelay3”: “string”,
    “getRelay4”: “string”
  “functions”: [

Would it be worth trying a hard / complete reset of the core to see if that fixes the relay?

That’s a really good sign!

Can I ask how you know relay 3 is stuck on? Do you have something connected to it? The relay shield does have both NC and NO contacts so you might want to double check your wiring.

Right now there is nothing connected to relay 3, only relay 1 and 2. I know its on because there is a red light next to each relay which indicates if its on or not. So the red light on relay 3 is on, and if I cut power from the relay shield I can hear the relay click.

Maybe you should try a factory reset to load the Tinker firmware and see if you can turn that relay on and off from the iOS or Android app. If you can’t do that, I would try a simple app that just toggles the relay every second or something.

It doesn’t sound like a software problem, but you never know.

1 Like

Alright, fixed that. Turns out the pins on the bottom of relay3 were touching the enclosure. I trimmed them back and now all is good.

I’m getting excited by this now…I love where this is going!


Hi @james211

Were you able to get the curl commands to work to set and get the time and duration?

1 Like

Yes I was…sorry, I thought I had mentioned that. Its really exciting to see this take some shape.


I only wish I knew what to do from here on, I feel bad depending on others.


Don’t feel bad! The forums are a great place to seek advice and plan your projects! Also I’m watching this project since it may relate to the egg pumping apparatus I need to build my breakfast machine… :smile:

1 Like

Ha! Thanks @Dave. I’m curious about your breakfast machine. Is it like Peewee Herman style? I have a lot of extra pumps laying around here if you need anything. Happy to mail to you no charge.