Looking for some help to control spark via web

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:

Hey @bko,

I think that would work as well. The original sketch at the beginning of this thread does exactly what I need. I guess the option I’m looking for that I cannot seem to figure out is how to make a web page that would allow me to change the program times and duration so I don’t have to go into the programmer every time I want to make a change.

OK–I see and that is also on my todo list.

Hey @bko, just thought I’d see how your alarm clock tutorial was coming along. I’ll have all the parts I need tomorrow to assemble my project. It runs fine with the current code, just looking for more flexibility.

Hi @james211

Sorry I got a little busy. I will try to whip something up this week.

No problem @bko, I wasn’t trying to put pressure on you, more of a friendly reminder.

All my best…

2 Likes

On a side note, if I wanted to have a surface mount an LED to show the status of the spark core on the enclosure, just as the core itself has on it, how would I go about that? I noticed that the little blue LED is connected to pin D7, but I couldn’t find out if there is a way to push that status to another pin.

Any chance you've been able to write something up already? Your library has been running successfully ever since you released it. Would be neat if you could show us a way to set the alarms externally. (No pressure though).
Thanks in advance for all your efforts, you're a great help for the whole community. Much appreciated!

I am working on it now!

2 Likes

OK guys I have something working, but it is not quite where I wanted it to be. I wanted to have the current values automatically refresh from the core, but it is just not stable and I don’t know what is wrong. So for now, you have to hit a Refresh button to get the current time and duration from the core. I will look at publishing the current settings instead of using variables, I guess. Also I decided that the seconds field could just always be zero, but feel free to change that.

I made one other important change to the firmware. In the previous version there was no way to turn off a channel. Now if you set the duration to zero, that returns it to the “not set” state and it turns the relay off. It will show as 00:00:00*0 in the display.

Here is the updated firmware–I had to rearrange the code since I think the preprocessor for the webIDE changed with the recent update.

// 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];

// 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];
    command.toCharArray(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);
    if (duration[relay]!=0) {
        isSet[relay] = true;
    } else {  // duration zero means clear all
        isSet[relay] = false;
        startHours[relay] = 0;
        startMinutes[relay] = 0;
        startSeconds[relay] = 0;
        digitalWrite(relayPin[relay],LOW);  // turn off
    }
    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);
}

void setup()
{
   for(int relay=0;relay<4;relay++) {
       pinMode(relayPin[relay], OUTPUT);
       digitalWrite(relayPin[relay], LOW);
       strcpy(relayStr[relay], "Not set");
   }
   
   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, "pool.ntp.org");
rtc.setTimeZone(-5); // gmt offset
rtc.setUseDST(true);

}

void loop() {

unsigned long currentTime = rtc.now();

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]) {
                digitalWrite(relayPin[relay],HIGH);
                stopTime[relay] = currentTime + duration[relay];
            } // start time
    } // is set
    
    if (currentTime >= stopTime[relay]) {
        digitalWrite(relayPin[relay],LOW);
    }
    
}

delay(100);

}

Here’s the HTML file–don’t forget to add your device-id and access-token in the file before you save it! Like all these web page demos, you need to keep your access token private, so don’t go putting this on the Internet. If you need a server type solution, check out the simple PHP proxy thread.

<!DOCTYPE HTML>
<html>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript" charset="utf-8">  </script>
<body>
  <P>Relay 1: Current setting <span id="relay1">unknown</span>
    <button id="getR1" onclick="getRelay(1)">Refresh</button>
    &nbsp;&nbsp;&nbsp;&nbsp;New setting
    <select id="relay1hours">
    </select> :
    <select id="relay1minutes">
    </select>  
    Duration
    <input type="text" id="relay1duration" value="10">  seconds
    <button id="setR1" onclick="setRelay(1)">Set</button>

  <P>Relay 2: Current setting <span id="relay2">unknown</span>
    <button id="getR2" onclick="getRelay(2)">Refresh</button>
    &nbsp;&nbsp;&nbsp;&nbsp;New setting
    <select id="relay2hours">
    </select> :
    <select id="relay2minutes">
    </select>  
    Duration
    <input type="text" id="relay2duration" value="10">  seconds
    <button id="setR2" onclick="setRelay(2)">Set</button>

  <P>Relay 3: Current setting <span id="relay3">unknown</span>
    <button id="getR3" onclick="getRelay(3)">Refresh</button>
    &nbsp;&nbsp;&nbsp;&nbsp;New setting
    <select id="relay3hours">
    </select> :
    <select id="relay3minutes">
    </select>  
    Duration
    <input type="text" id="relay3duration" value="10">  seconds
    <button id="setR3" onclick="setRelay(3)">Set</button>

  <P>Relay 4: Current setting <span id="relay4">unknown</span>
    <button id="getR4" onclick="getRelay(4)">Refresh</button>
    &nbsp;&nbsp;&nbsp;&nbsp;New setting
    <select id="relay4hours">
    </select> :
    <select id="relay4minutes">
    </select>  
    Duration
    <input type="text" id="relay4duration" value="10">  seconds
    <button id="setR4" onclick="setRelay(4)">Set</button>


    <script type="text/javascript">

    for(i=0;i<24;i++) {
		      for(relay=1;relay<5;relay++) {
						   var rh = document.getElementById("relay"+relay.toString()+"hours");
						   var opt = document.createElement("OPTION");
						   opt.setAttribute("value", i.toString() );
						   var nd  = document.createTextNode(i.toString());
						   opt.appendChild(nd);
						   rh.appendChild(opt);
						   }
		      }
		
    for(i=0;i<60;i++) {
		      for(relay=1;relay<5;relay++) {
						   var rm = document.getElementById("relay"+relay.toString()+"minutes");
						   var opt = document.createElement("OPTION");
						   opt.setAttribute("value", i.toString() );
						   var nd  = document.createTextNode(i.toString());
						   opt.appendChild(nd);
						   rm.appendChild(opt);
						   }
		      }

      var deviceID    = "<<device id here>>";
      var accessToken = "<<access token here>>";
      var setFunc = "setRelay";
      var getFunc = "getRelay";

      function getRelay(relay) {
	     requestURL = "https://api.spark.io/v1/devices/" + deviceID + "/" + getFunc + relay.toString() + "/?access_token=" + accessToken;
             $.getJSON(requestURL, function(json) {
                 document.getElementById("relay"+relay.toString() ).innerHTML = json.result;
                 });
      }

      function setRelay(relay) {
        var newValue = document.getElementById("relay"+relay+"hours").value   + ":" +
                       document.getElementById("relay"+relay+"minutes").value + ":" +
                                                                         "00" + "*" +
                       document.getElementById("relay"+relay+"duration").value;
	var requestURL = "https://api.spark.io/v1/devices/" +deviceID + "/" + setFunc + relay + "/";
        $.post( requestURL, { params: newValue, access_token: accessToken });
      }

    </script>
</body>
</html>
2 Likes

@bko, thank you for starters! Second, when I compile the code, I get this error:

In file included from ../inc/spark_wiring.h:30:0,

                   from ../inc/application.h:29,
                   from /SparkTime.h:4,
                   from /SparkTime.cpp:31:
  ../../core-common-lib/SPARK_Firmware_Driver/inc/config.h:12:2: warning: #warning "Defaulting to Release Build" [-Wcpp]
   #warning  "Defaulting to Release Build"
    ^
  In file included from ../inc/spark_wiring.h:37:0,
                   from ../inc/application.h:29,
                   from /SparkTime.h:4,
                   from /SparkTime.cpp:31:
  ../inc/spark_wiring_ipaddress.h: In member function 'IPAddress::operator uint32_t()':
  ../inc/spark_wiring_ipaddress.h:53:52: warning: dereferencing 

type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

    operator uint32_t() { return *((uint32_t*)_address); };
                                                      ^
  ../inc/spark_wiring_ipaddress.h: In member function 'bool IPAddress::operator==(const IPAddress&)':
  ../inc/spark_wiring_ipaddress.h:54:72: warning: dereferencing 

type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

    bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); };
                                                                          ^
  ../inc/spark_wiring_ipaddress.h:54:105: warning: dereferencing 

type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

    bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); };
                                                                                                           ^
  In file included from ../inc/spark_wiring.h:30:0,
                   from ../inc/application.h:29,
                   from /time.cpp:2:
  ../../core-common-lib/SPARK_Firmware_Driver/inc/config.h:12:2: warning: #warning "Defaulting to Release Build" [-Wcpp]
   #warning  "Defaulting to Release Build"
    ^
  /time.cpp:2:33: fatal error: SparkTime/SparkTime.h: No such file or directory
   #include "application.h"
                                   ^
  compilation terminated.
  make: *** [/time.o] Error 1

Hi @james211

I think you need to add my SparkTime library your project.

I’m pretty sure I have it there…I just pasted the new firmware into the one I was previously using. Here is a screen shot. I’ll try it again just in case.

I figured it out…for some reason the #include statement in the beginning was changing to:

#include "SparkTime/SparkTime.h"

@bko, you are a brilliant man. Thank you for doing this.

2 Likes