Looking for some help to control spark via web

So I have the program written to control the relay shield the way I want. Now I’d like to be able to control the time variables via a web page. The problem is, I honestly have no clue what I’m doing. I understand parts of code, but that’s about it.

The project I’m working on is a two channel peristaltic dosing pump to pump additives into my coral reef aquarium. Some times the amount of the additives needs to change based on the aquariums needs and I’d like to be able to easily change the dosing times.

Is it too much to ask for someone to help me port this over to be web accessible?

Here is the code:

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


UDP UDPClient;
SparkTime rtc;

int RELAY1 = D0;
int RELAY2 = D1;
int RELAY3 = D2;
int RELAY4 = D3;

void setup()
{
   //Initilize the relay control pins as output
   pinMode(RELAY1, OUTPUT);
   pinMode(RELAY2, OUTPUT);
   pinMode(RELAY3, OUTPUT);
   pinMode(RELAY4, OUTPUT);
   // Initialize all relays to an OFF state
   digitalWrite(RELAY1, LOW);
   digitalWrite(RELAY2, LOW);
   digitalWrite(RELAY3, LOW);
   digitalWrite(RELAY4, LOW);

rtc.begin(&UDPClient, "pool.ntp.org");
rtc.setTimeZone(-5); // gmt offset
rtc.setUseDST(true);

}

void loop() {

unsigned long currentTime = rtc.now();
static unsigned long stopTime = 0;

if (rtc.hour(currentTime)==0 && rtc.minute(currentTime)==17 && rtc.second(currentTime)==00) {
    digitalWrite(RELAY1,HIGH);
    stopTime = currentTime + (2);  //one minute and ten seconds
}

if (currentTime >= stopTime) {
    digitalWrite(RELAY1,LOW);
}
if (rtc.hour(currentTime)==0 && rtc.minute(currentTime)==17 && rtc.second(currentTime)==03) {
    digitalWrite(RELAY2,HIGH);
    stopTime = currentTime + (2);  //one minute and ten seconds
}

if (currentTime >= stopTime) {
    digitalWrite(RELAY2,LOW);
}

delay(100);

}
1 Like

Check out some tutorials by @BDub and @wgbartley in the Tutorial category.

I wished I could post the links but we are all out for the weekend! :slight_smile:

I have not forgotten about this either! I have on my todo list some kind of “alarm clock” set over the web. I just have some sketches but I am thinking about how to do this.

1 Like

Thank you both for taking the time to respond. I’ve been trying really hard to learn some more of this stuff. I spent about two hours on Lynda.com last night, but I didn’t get far enough to do what I want to do. I found a basic arduino sketch for web control, but I don’t have a clue how I would integrate it.

Also, one of the things I’m confused about is adding additional sketches to a current one. So for instance I have the sketch for the timing, but now I want to add one for the web code, etc. Do I just hit the plus sign on the right? Or is there another way? Again, these are all questions going through my head.

Thank you all for taking the time to reply.

Web code?

Like code on a server?

You can paste code in the main source file on the Spark Web IDE if it’s for the core firmware.

Other web stuff has to be on a local machine or server :slight_smile:

Also, have you seen this tutorial yet? This is one way to answer the web status and control using Spark variables and functions.

I’ll check it out. I don’t have the kit so I’ve kind of avoided it. Maybe I’ll go to radio shack and see if they have any stepper motors there to play with.

In terms of the website, I was under the impression the web server was hosted by the sparkcore. At one point I built a water level sensor that another guy had built, I followed his write up and it worked well. In that case wrote the code so the arduino acted as the server. So that doesn’t work in this case?

HI @james211

I didn’t for you to copy that tutorial, just read it and get the ideas. It shows how you can send a value to a core from the internet (a web page that you write) and get a value back the same way.

A Spark core can be a web server (a tiny one) but then it is behind your ISP’s router typically. This means that it is not easy to get to from the general internet since you don’t know the address of your ISP’s router typically. There is a way around this called dynamic DNS, but you have to set that up. Inside your house, this method works OK.

A Spark core can also talk to the Spark cloud service which acts a gateway or bridge between your core and the internet at large. This is what that tutorial shows how to do. The Spark team has made it really easy to talk to and from your core in way that you don’t need to worry about the details.

There are other cloud services like Xively and Pushingbox and many, many more that you can use with a Spark core, depending on what you want to do.

Ok, I get what you’re saying now. In terms of what I need, I have no need to access it from outside my house. I already have dynamic dns setup for a few file servers in my house for my work. But with this project, I would never adjust anything without doing a series of water tests first, so accessing from home is just fine. If it would run faster running from my Qnap server, I’d be fine with that as well.

So I’ve been going through the @bko tutorial on spark publish. I’d like to start by just being able to see the time that each relay is set at. What I’m gathering is that some where in my code I need to declare the current time, and the set time of the two relays. Is that correct? I’m looking at the tutorial and there is a piece of code that says “unsigned” and “unsigned long”. What does that mean and where do I go from here?

Okay, forgive me for this being amateur hour, but here is where I stand, and it doesn’t work.

SparkCode:

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


UDP UDPClient;
SparkTime rtc;
char publishString[40];

int RELAY1 = D0;
int RELAY2 = D1;
int RELAY3 = D2;
int RELAY4 = D3;

void setup()
{
   //Initilize the relay control pins as output
   pinMode(RELAY1, OUTPUT);
   pinMode(RELAY2, OUTPUT);
   pinMode(RELAY3, OUTPUT);
   pinMode(RELAY4, OUTPUT);
   // Initialize all relays to an OFF state
   digitalWrite(RELAY1, LOW);
   digitalWrite(RELAY2, LOW);
   digitalWrite(RELAY3, LOW);
   digitalWrite(RELAY4, LOW);

rtc.begin(&UDPClient, "pool.ntp.org");
rtc.setTimeZone(-5); // gmt offset
rtc.setUseDST(true);

}

void loop() {

unsigned long currentTime = rtc.now();
static unsigned long stopTime = 0;

if (rtc.hour(currentTime)==0 && rtc.minute(currentTime)==17 && rtc.second(currentTime)==00) {
    digitalWrite(RELAY1,HIGH);
    stopTime = currentTime + (2);  //one minute and ten seconds
}

if (currentTime >= stopTime) {
    digitalWrite(RELAY1,LOW);
}
if (rtc.hour(currentTime)==0 && rtc.minute(currentTime)==17 && rtc.second(currentTime)==03) {
    digitalWrite(RELAY2,HIGH);
    stopTime = currentTime + (2);  //one minute and ten seconds
}

if (currentTime >= stopTime) {
    digitalWrite(RELAY2,LOW);
    
    sprintf(publishString,"%u:%u:%u",rtc.hour(currentTime),rtc.minute(currentTime),rtc.second(currentTime));
        Spark.publish("RELAY1",publishString);
}

delay(100);

}

And the HTML

<!DOCTYPE HTML>
<html>
<body>
    <span id="RELAY1"></span><br>
    <span id="currentTime"></span>

    <br><br>
    <button onclick="start()">Connect</button>

    <script type="text/javascript">
    function start() {

        document.getElementById("RELAY1").innerHTML = "Waiting for data...";
        var deviceID = "53ff6f065075535155281687";
        var accessToken = "1...0";
        var eventSource = new EventSource("https://api.spark.io/v1/devices/" + deviceID + "/events/?access_token=" + accessToken);

         eventSource.addEventListener('open', function(e) {
            console.log("Opened!"); },false);

        eventSource.addEventListener('error', function(e) {
            console.log("Errored!"); },false);

        eventSource.addEventListener('Uptime', function(e) {
            var parsedData = JSON.parse(e.data);
            var tempSpan = document.getElementById("RELAY1");
            var tsSpan   = document.getElementById("rtc.hour(currentTime),rtc.minute(currentTime),rtc.second(currentTime)");
            tempSpan.innerHTML = "Core: " + parsedData.coreid + " currentTime: " + parsedData.data + " (h:m:s)";
            tempSpan.style.fontSize = "28px";
            tsSpan.innerHTML = "At timestamp " + parsedData.published_at;
            tsSpan.style.fontSize = "9px";
        }, false);
    }
    </script>
</body>
</html>

OK, so when relay2 is turned off, you want to publish an event called RELAY1 with the current time. Sounds like a good start. I don’t see your event in the public event stream, but it might just not be time for it.

First off in the HTML, don’t post your access_token here–that is private for you. I did a quick edit there but you probably want to reset your token via the webIDE just in case.

You need to change one more “Uptime” to “RELAY1” here:

        eventSource.addEventListener('RELAY1', function(e) {
            var parsedData = JSON.parse(e.data);
            var tempSpan = document.getElementById("RELAY1");
            var tsSpan   = 
...

Oops…rookie mistake, good to know about the token. Second, what I’m hoping to accomplish at the moment is for the html page to show the times and duration both relays are set to turn on, not to just publish when they come on. What part of my code states that it will post only when relay2 is turned off? You also mentioned you don’t see the event in the public event stream…I’m not sure what that means.

Ideally this is how I’d like the page to look right now, just for reference.

Current Time: 21:00:00
Alkalinity On: 21:10:00 Duration: 00:01:10
Calcium On: 21:20:00 Duration: 00:01:10

OK try this, it is not exactly what you want but close and maybe you can take it from here. I am not sure I see why you want the times displayed so I used the published time from the cloud instead of time from the core.

There are rate limits as to how fast you can publish and one per second is a good place to be.

First the HTML:

<!DOCTYPE HTML>
<html>
<body>
    <span id="currentTime"></span><br>
    <span id="RELAY1"></span><br>
    <span id="RELAY2"></span><br>    
    <br><br>
    <button onclick="start()">Connect</button>

    <script type="text/javascript">
    function start() {

        document.getElementById("currentTime").innerHTML = "Waiting for data...";
        var deviceID = "53ff6f065075535155281687";
        var accessToken = "1...0";
        var eventSource = new EventSource("https://api.spark.io/v1/devices/" + deviceID + "/events/?access_token=" + accessToken);

         eventSource.addEventListener('open', function(e) {
            console.log("Opened!"); },false);

        eventSource.addEventListener('error', function(e) {
            console.log("Errored!"); },false);

        eventSource.addEventListener('RELAYTIME', function(e) {
            var parsedData = JSON.parse(e.data);
            var tempSpan = document.getElementById("currentTime");
            tempSpan.style.fontSize = "28px";
            tempSpan.innerHTML = "Current time: " + parsedData.data;
        }, false);
        eventSource.addEventListener('RELAY1', function(e) {
            var parsedData = JSON.parse(e.data);
            var tempSpan = document.getElementById("RELAY1");
            tempSpan.style.fontSize = "28px";
            tempSpan.innerHTML = "Alkalinty Status: " + parsedData.data + " as of " + parsedData.published_at;
        }, false);
        eventSource.addEventListener('RELAY2', function(e) {
            var parsedData = JSON.parse(e.data);
            var tempSpan = document.getElementById("RELAY2");
            tempSpan.style.fontSize = "28px";
            tempSpan.innerHTML = "Calcium Status: " + parsedData.data + " as of " + parsedData.published_at;
        }, false);

    }
    </script>
</body>
</html>

And now the core firmware:

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


UDP UDPClient;
SparkTime rtc;
char publishString[40];

int RELAY1 = D0;
int RELAY2 = D1;
int RELAY3 = D2;
int RELAY4 = D3;

void setup()
{
   //Initilize the relay control pins as output
   pinMode(RELAY1, OUTPUT);
   pinMode(RELAY2, OUTPUT);
   pinMode(RELAY3, OUTPUT);
   pinMode(RELAY4, OUTPUT);
   // Initialize all relays to an OFF state
   digitalWrite(RELAY1, LOW);
   digitalWrite(RELAY2, LOW);
   digitalWrite(RELAY3, LOW);
   digitalWrite(RELAY4, LOW);

rtc.begin(&UDPClient, "pool.ntp.org");
rtc.setTimeZone(-5); // gmt offset
rtc.setUseDST(true);

}

void loop() {

unsigned long currentTime = rtc.now();
static unsigned long stopTime = 0;
static unsigned long lastTime = 0;

if (currentTime > lastTime) {	// only check every second
  lastTime = currentTime;

  sprintf(publishString,"%u:%u:%u",rtc.hour(currentTime),rtc.minute(currentTime),rtc.second(currentTime));
  Spark.publish("RELAYTIME",publishString);

if (rtc.hour(currentTime)==0 && rtc.minute(currentTime)==17 && rtc.second(currentTime)==00) {
    digitalWrite(RELAY1,HIGH);
    Spark.publish("RELAY1","ON");
    stopTime = currentTime + (2);  //one minute and ten seconds
}

if (currentTime >= stopTime) {
    digitalWrite(RELAY1,LOW);
    Spark.publish("RELAY1","OFF");
}
if (rtc.hour(currentTime)==0 && rtc.minute(currentTime)==17 && rtc.second(currentTime)==03) {
    digitalWrite(RELAY2,HIGH);
    Spark.publish("RELAY2","ON");
    stopTime = currentTime + (2);  //one minute and ten seconds
}

if (currentTime >= stopTime) {
    digitalWrite(RELAY2,LOW);
    Spark.publish("RELAY2","OFF");
}

delay(100);

}
1 Like

Ahh…The reason I want the times, is just a starting point, to help learn this stuff. I figure it will help me to understand how the publish aspect works in relation to my specific code. Its all baby steps in my mind. Every little bit of help is good for me. Eventually I’ll get to my final goal, which is to be able to see the current set times in the code, but also be able to change them.

Also, I’m not exactly sure I understand the data that the webpage is showing. Here is what I’m seeing. I’m not sure where the date is coming from, I don’t see that in either the spark or html code. Second, I don’t understand what that 03:35:04.880Z means.

I’ll have to look into this a bit closer tomorrow evening. I’m not seeing what I want quite yet, but it all takes time.

Thank you @bko

1 Like

Hi @james211

Current time is being published by the core every second.

The status lines are being published at every turn on or turn off for the relays. The time is the cloud timestamp that is added automatically in the Spark cloud for you and tells you when the event reached the Spark cloud.

This is an ISO standard format for timestamps and is GMT or zulu time. You can read it like this:

2014-05-19T03:35:04.880Z

The 2014-05-19 is the data in year-month-day format. The ‘T’ transitions from date to time. The time of the timestamp is 03:35:04 in hours:minutes:seconds and 0.880 of fraction second in GMT aka Greenwich Mean Time aka Zulu time, hence the final Z in the timestamp.

Ok, that makes some sense, I guess I would have expected to show my current time zone, but that doesn’t matter at the moment.

Lets look at this piece of code below. This states that the relay will turn on at 12:15am and run for one minute and ten seconds. How would I adjust spark.publish to publish that time so I could see it on the web as:

Alkalinity on: 12:15 am Duration: 70 seconds

if (rtc.hour(currentTime)==0 && rtc.minute(currentTime)==15 && rtc.second(currentTime)==00) {
    digitalWrite(RELAY1,HIGH);
    Spark.publish("RELAY1","ON");
    stopTime = currentTime + (60+10);  //one minute and ten seconds
}

if (currentTime >= stopTime) {
    digitalWrite(RELAY1,LOW);
    Spark.publish("RELAY1","OFF");
// This #include statement was automatically added by the Spark IDE.
#include "SparkTime.h"


UDP UDPClient;
SparkTime rtc;
char publishString[40];

int RELAY1 = D0;
int RELAY2 = D1;
int RELAY3 = D2;
int RELAY4 = D3;

void setup()
{
   //Initilize the relay control pins as output
   pinMode(RELAY1, OUTPUT);
   pinMode(RELAY2, OUTPUT);
   pinMode(RELAY3, OUTPUT);
   pinMode(RELAY4, OUTPUT);
   // Initialize all relays to an OFF state
   digitalWrite(RELAY1, LOW);
   digitalWrite(RELAY2, LOW);
   digitalWrite(RELAY3, LOW);
   digitalWrite(RELAY4, LOW);

rtc.begin(&UDPClient, "pool.ntp.org");
rtc.setTimeZone(-5); // gmt offset
rtc.setUseDST(true);

}

void loop() {

unsigned long currentTime = rtc.now();
static unsigned long stopTime = 0;
static unsigned long lastTime = 0;
unsigned long stopTimeIncrement;

if (currentTime > lastTime) {    // only check every second
  lastTime = currentTime;

  sprintf(publishString,"%u:%u:%u",rtc.hour(currentTime),rtc.minute(currentTime),rtc.second(currentTime));
  Spark.publish("RELAYTIME",publishString);

if (rtc.hour(currentTime)==0 && rtc.minute(currentTime)==17 && rtc.second(currentTime)==00) {
    digitalWrite(RELAY1,HIGH);
    stopTimeIncrement = 2;
    stopTime = currentTime + stopTimeIncrement;
    sprintf(publishString,"%u:%u:%u Duration: %u ",
            rtc.hour(currentTime),rtc.minute(currentTime),rtc.second(currentTime),
            stopTimeIncrement);
    Spark.publish("RELAY1",publishString);
}

if (currentTime >= stopTime) {
    digitalWrite(RELAY1,LOW);
    //Spark.publish("RELAY1","OFF");
}
if (rtc.hour(currentTime)==0 && rtc.minute(currentTime)==17 && rtc.second(currentTime)==03) {
    digitalWrite(RELAY2,HIGH);
    stopTimeIncrement = 2;
    stopTime = currentTime + stopTimeIncrement;
    sprintf(publishString,"%u:%u:%u Duration: %u ",
            rtc.hour(currentTime),rtc.minute(currentTime),rtc.second(currentTime),
            stopTimeIncrement);
    Spark.publish("RELAY2",publishString);
}

if (currentTime >= stopTime) {
    digitalWrite(RELAY2,LOW);
    //Spark.publish("RELAY2","OFF");
}

delay(100);

}

Well after playing around with this a lot, it seems I just don’t have the knowledge to do what I need to do. I think I’ll wait until @bko releases his alarm clock tutorial he mentioned and hopefully that will get me just far enough.

@bko, I really appreciate your help. My project will run with the original code, it just won’t be as easy to update in the meantime.

hi @james211

I have been working on (and have almost finished) porting the TimeAlarms library described here:

http://www.pjrc.com/teensy/td_libs_TimeAlarms.html

Why don’t you have a look at that and see if that is going to work for you–I think it probably will.

There is another thread on that here: