Tutorial: Getting Started with Spark.publish()

Here’s a tutorial to get you started using Spark.publish().

Let’s imagine you want to monitor your core’s uptime, that is, how many hours, minutes, and seconds since the last time the core was reset or powered-up and view it on a web page that you can leave open all the time.

You can use the millis() function to measure time and for this example, you can ignore the fact that it can wrap-around back to zero after many days. So you need two things, code for your Spark core and code for a web page on your PC.

So you will format the time the core has been up as a string with hours:minutes:seconds and publish that with an event name of “Uptime”. As you shall see, the event name needs to match in the core and on the web page. You also need a C string to hold that published time value and a little bit of math the convert to hours, minutes and seconds. Time can never be a negative number, so you can use unsigned types to hold the values.

You will want to be good to your Spark neighbors, so you will only publish every 15 seconds. Every minute or even every 5 minutes would work great here, but for this example, you want to see the values reloading on the web page.

The Spark Firmware

Here is the Spark Core firmware you need to cut and past into the webIDE. I called it “publishme.ino” but you can call it what you like:

// publishme.ino -- Spark Publishing Example 
unsigned long lastTime = 0UL;
char publishString[40];

void setup() {
}

void loop() {
    unsigned long now = millis();
    //Every 15 seconds publish uptime
    if (now-lastTime>15000UL) {
        lastTime = now;
        // now is in milliseconds
        unsigned nowSec = now/1000UL;
        unsigned sec = nowSec%60;
        unsigned min = (nowSec%3600)/60;
        unsigned hours = (nowSec%86400)/3600;
        sprintf(publishString,"%u:%u:%u",hours,min,sec);
        Spark.publish("Uptime",publishString);
    }
}

Notice how the Spark.publish function takes two strings. The first one is the name of the event and that has to match the web page you will work on below.

The second string is the data and this case, you can create that with sprintf to print the unsigned hours, minutes, and seconds nicely into the string. This can be anything–go wild!

The Web Page

Now you need a web page to listen to these events from your core. The web page HTML/Javascript is written so that you have to click a button to start, just to make it easier to debug. When you click the “Connect” button, a SSE event stream is opened and the web browser starts listening for events in that stream. Events have names and you want to listen to your events so you need to edit the the html file to have your Core ID and Access Token as hex numbers. Also notice that you have to listen for the event name “Uptime” that we define in the Spark firmware.

Here’s the html for the web page. Cut and paste this into a local file on your computer using your favorite text editor and then add your personal core id and access token, replacing the entire “<< here >>” part for each one. Save it as “Uptime.html” on your hard drive.

Safety Note!

Because you put your access token in this file, you should never put it where other people can read it. Do not put it on a public webserver or in a public area like on Dropbox. This is private stuff just for you!

<!DOCTYPE HTML>
<html>
<body>
    <span id="uptime"></span><br>
    <span id="tstamp"></span>
     
    <br><br>
    <button onclick="start()">Connect</button>
 
    <script type="text/javascript">
    function start() {

        document.getElementById("uptime").innerHTML = "Waiting for data...";
        var deviceID = "<<hex device id here>>";
        var accessToken = "<<hex access token here>>";
        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("uptime");
            var tsSpan   = document.getElementById("tstamp");
            tempSpan.innerHTML = "Core: " + parsedData.coreid + " uptime: " + 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, you are almost there. Open up Chrome or other recent browser on your PC and type this in the URL box, replacing the “<< >>” parts as to match you system:

For Windows: file:///C:/<<your path>>/Uptime.html

For Mac: file:///users/<<your mac user name>>/<<your path>>/Uptime.html

You should see screen like this:

Click the “Connect” button and you should see this with a “Waiting for data…” message. Don’t click “Connect” more than once please.

Then in 15 seconds or less, you should see this:

Notice at the bottom, the Spark cloud gives you a timestamp that tell you when you last got data from the cloud. You see the Core ID and the “Uptime” event data of 0:39:30, which says that this core has been up for zero hours, 39 minutes and 30 seconds.

Every 15 seconds you see the web page update with a new value for the Uptime and the timestamp.

If things go wrong

Most browsers support SSE well, but some don’t. If you can’t get it work in your favorite browser, try Chrome, it is very reliable.

If you don’t see any events in Chrome after 15 seconds and your core is breathing cyan, try typing control-shift-J on PC or command-option-J on Mac to bring up the Javascript console. You should see the line “Opened!” meaning the stream was opened with out error. If you see “Errored!” something went wrong and you should check the HTML file.

If you have the Javascript console open, can click on the Network tab at the top of the console and see the bytes coming on the event stream. If you hover your mouse on the yellow stream bar, you can get statistics.

Go Play!

Now you need to get out there and make your own events. Check the temperature in the basement. Report when the lights go on. Have fun.

You can also save your Uptime.html file to a service like Dropbox. Then on your phone, you can use the Dropbox app to open this file as a web page and see how your core is doing. Remember, do not put the Uptime.html file in a public spot!

41 Likes

@bko Thanks so much for putting this together. I’ll try this soon and report back :smile:

Thanks bko!!

Forgive my ignorance but I think I’m still missing why I would use “publish” over “variable”. If I wanted to send a measured temperature what’s the benefit of “publish”?

Thanks,
Col

@Bradders Spark.publish allows you push data out from the core as opposed to Spark.variable which you’d have to poll for. So for example, instead of polling your core every 30 seconds to see if a motion sensor has been triggered, you can instead use Spark.publish to trigger the event the moment the motion sensor goes off.

1 Like

@bko This is awesome! Thanks for putting this together!

1 Like

bko, thanks this was a great help.

1 Like

bko, Good work… Working very fine…

I’m stuck. Clicked on “Connect”, got “Waiting for data”. Using Chrome. Javascript console says “Opened!”. I’m at 5 minutes or more, but still “Waiting for data.” Spark breathing cyan. Any suggestions? Problem solved, just reflashed Spark Core and webpage responded immediately.

Well done tutorial. Thank you!

1 Like

I am glad you got it working! There is a follow-on tutorial doing a similar thing but using a JSON from the core to web, to show how to return multiple values that are easily parsed on the web page.

@bko Can you post Spark Publish example with PHP proxy, it is not working for me. Help Appreciated!

Are you using @wgbartley PHP proxy from here?

You then have to change your URLs to be more like in this example:

$.get('/proxy.php?'+CORE_ID+'/variable_name', function(response) {
        console.log(response);
});

Hi @bko, what argument would one use to pass in a string rather than an int or a double? looks like I can’t pass in a string or char through %u, %f, or %e. Thought I would ask you before I try every letter of the alphabet!
Thank you!

Hi @jkkim93

If the char array string already completely formed, you can just publish it. If you want to use sprintf() to add some formatting, the %s is how to say that.

1 Like

@bko , if I pass the array in without sprintf(), how would I call to print it on the html side? Right now I’m parsing json, but it is coming out as null (json.data)- wondering if you could do a short explanation of how to read in arrays to print on the html side. thanks!

In this example, the parsedData.data should be the string that you are sending. If you are getting a null, something is wrong on one end or the other.

Awesome tutorial @bko Thank you very much for taking the time to put it together. I’ve been pulling my hair out trying to get this to work.

1 Like

Thank you very much for this tutorial.
I think, this is what I need for the development I’m doing.

However: I have copied and pasted you sample INO and did the same with the HTML, replacing the Device_ID and AccessToken.
However: When I click the ‘connect’ button, nothing happens.
I see ‘Errored’, in the Ctrl-Shft-J info.

For sure I checked both, and found everything in order, as far as I’m concerned…

What could be wrong?
I have no clue where to look.

Hi @RensD

Can I ask what browser you are using? The event stuff does not work Internet Explorer. Try Chrome for best results.

The device_id and access_token hex strings need to be in double-quotes.

You can also use curl to see your event on the command line. That way you can make sure the core is sending events.

Thanks for the reply.

(I’m using Chrome)
By sending the http-request manually, I got the full error message:
{ “code”: 400, “error”: “invalid_grant”, “error_description”: “The access token provided has expired.” }

So, after renewing the token, all worls fine. :slight_smile:

3 Likes

Excellent, thanks so much!

2 Likes