Looking for some help to control spark via web

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