Tutorial: Getting Started with Spark.publish()

OK here is the scenario for the PHP server. Let’s say you have a web server running Apache on a host somewhere. On that web server you want to serve up an HTML page that has data from a Spark core via publish or variable or even a control function that does something on the core, but you don’t want your access token to be visible. What do you do?

You set up @wgbartley 's PHP script and .htaccess on your server so that URLs in your HTML page are automatically rewritten to include your access token.

The proxy takes relative URLs and adds all the stuff to make it a api.spark.io URL as I recall. Your event source URL needs to be rewritten, so you just write it relative with this PHP script, I believe.

1 Like

Ok, still confused here, not necessarily with what is going on here, but how one does it. It took me a while to look at the javascript and php to see what was happening, but I think I got it. I’m writing some test code:

<!DOCTYPE HTML>
<html>
	<head>
		<title>test</title>
		<style>
			body { margin: 0; }
			canvas { width: 100%; height: 100% }
		</style>
		<meta charset="utf-8">
	</head>
	<body>
		<div align = "center" id="div">DIV</div>
		<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript" charset="utf-8"></script>
		<script>

		var CORE_ID = '########################';

		test();

		function test(){

			var div = document.getElementById("div");

			div.innerHTML = "MAKING REQUEST";
			
			$.get('/proxy.php?'+CORE_ID+'/variable_name', function(response) {
        		console.log(response);
        		div.innerHTML=response;
			});
		}
		</script>
	</body>
</html>

So from the requesting HTML page, an ajax request is made to proxy.php using the GET method, and in this request, the core ID is sent along with what resource. It used to be a variable name, but I put events in there because I want to subscribe.

Here’s wgbartley’s PHP proxy script I copied from his gist here:

https://gist.github.com/wgbartley/11337650

<?
// Set your access token here
define('ACCESS_TOKEN', 'your_access_token_here');

// All responses should be JSON
header('Content-type: application/json');

// Build the URL.  Since it's possible to accidentally have an
// extra / or two in $_SERVER['QUERY_STRING], replace "//" with "/"
// using str_replace().  This also appends the access token to the URL.
$url = 'https://'.str_replace('//', '/', 'api.spark.io/v1/devices/'.$_SERVER['QUERY_STRING'].'?access_token='.ACCESS_TOKEN);


// HTTP GET requests are easy!
if(strtoupper($_SERVER['REQUEST_METHOD'])=='GET')
        echo file_get_contents($url);

// HTTP POST requires the use of cURL
elseif (strtoupper($_SERVER['REQUEST_METHOD'])=='POST') {
        $c = curl_init();
        
        curl_setopt_array($c, array(
                // Set the URL to access
                CURLOPT_URL => $url,
                // Tell cURL it's an HTTP POST request
                CURLOPT_POST => TRUE,
                // Include the POST data
                // $HTTP_RAW_POST_DATA may work on some servers, but it's deprecated in favor of php://input
                CURLOPT_POSTFIELDS => file_get_contents('php://input'),
                // Return the output to a variable instead of automagically echoing it (probably a little redundant)
                CURLOPT_RETURNTRANSFER => TRUE
        ));

        // Make the cURL call and echo the response
        echo curl_exec($c);

        // Close the cURL resource
        curl_close($c);
}
?>

What I was mistaken about is what happens next. I now (correctly?) think that PHP takes the information in the GET method and puts it into the $url variable in the right spot so you have a well formed URL for requesting a variable from a spark core with the access token also put in.

Now here’s where my greatest amount of confusion lies: In the subscribe tutorial, a URL is created in the HTML page and is passed to the page’s eventSource() constructor. If I don’t want the access token to be in the HTML file, use a proxy, but the proxy does not return the URL, it returns the contents of that URL. If I were looking for a spark variable, the value is what would be echoed back, not it’s location. So I don’t have a URL to give to the eventSource() constructor to subscribe to.

The PHP script probably won’t work for the eventSource stuff. When it proxies the request, it makes the call to the Spark API and doesn’t return anything until the HTTP connection to the Spark API is closed. I may be able to do the eventSource stuff in the same script, but mileage may vary drastically from server to server. Apache and PHP max execution times may prematurely kill an eventSource connection. That, and output buffering and flushing can also behave differently from server to server (IIS has always been a pain, but I’m pretty sure Apache and nginx play nicely).

If the kids go to bed at a reasonable hour tonight, I may be able to give it a try!

2 Likes

That would be awesome! So there’s no current method of securely subscribing to spark SSE’s? (remotely, not on a local machine)

Another “lateral thinking” idea that might help you is to ask to join the IFTTT beta since it can handle published events.

So it can be done for events, but it might not be as simple as a PHP proxy.

1 Like

Thanks @bko, that’s a great suggestion!

Not without something like a proxy (to my knowledge anyways). If it's not for the general public but still accessible anywhere on the Internet, you could set up a VPN or hide it behind some form of authentication on an SSL-secured site.

I've made a little headway with the update to the proxy script but need to mentally shut down for the evening. I'll wrap it all up tomorrow at work (shhh.. don't tell my boss).

2 Likes

My proxy.php gist has been updated to support proxying for SSE. It works on my laptop, but output buffering in PHP can be a tricky thing on some server configs, so your mileage may vary.

Take note that the update is not backwards-compatible. The original proxy used to automagically add /v1/devices/ to the URL. Since the SSE stuff may also use /v1/events/ or /v1/devices/, I had to take it out. Now when you use the proxy, you will need to specify the full API path (after the domain name) to include /v1/devices/... or /v1/events/....

I hope this helps!

2 Likes

Thank you god good tutorial.
Access token expires after 90 days or so, is it possible by any way to request a new one by JavaScript, otherwise the HTM file need to be edited with new one.

Hi @zerous

You can start here:

http://docs.spark.io/api/#authentication-generate-a-new-access-token

You will need to write Javascript to take the username and password instead and use the API above to get a token. If you look around the forum, I think you can find some examples from others nodejs etc.

The Spark team has also said they would like to offer more choices for access token expiration in the future.

wow, this is wonderful, thanks! so the php script subscribes to the event and passes the data to the html page. awesome! i threw this up on my server. not getting any errors in the console, but i’m also not getting any data back…yet…and thanks @bko for the IFTTT info. that’s pretty awesome as well. i’ve laos started playing around with node-red on a pi to get data from the core. gotta find some time to sit down with php and javascript and see what the issue is…

1 Like

With this example, how can I modify the format of the timestamp variable?
Ex: I want to add +6h to the data of the timestamp (timezone)
I want to display only the hours:min:sec of the timestamp (not the variable uptime).

Thanks!

Hi @jmspark

The Spark cloud automatically supplies the timestamp but you can display it on a web page any way you want. I would use Javascript Date.parse() to get the number of milliseconds since Jan 1, 1970. You can then add 66060*1000 (the number of millisecond in six hours) to that to get the local time and date. You then convert it back with your own math, or date conversion functions like toLocaleString(), but be aware that browser implementation differ. I found this link helpful:

1 Like

Thanks for your help @bko ! I will publish my code when it’s working!

1 Like

I made some cosmetic changes to your example code:

==========The web page==============

<!DOCTYPE HTML>
<html>
<body>
    <p>
    <button onclick="start()"><b>Connect</b></button>
    <br><br>
    <span id="uptime"></span><br>
    <span id="tstamp"></span>

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

        document.getElementById("uptime").innerHTML = "Waiting for data...";
        var deviceID = "id...";
        var deviceName = "my-core";
        var accessToken = "ac...";
        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");
            if(parsedData.coreid != deviceID) deviceName = "???";
            tempSpan.innerHTML = "Core: " + deviceName + " uptime: " + parsedData.data + " (h:m:s)";
            tempSpan.style.fontSize = "18px";
            tsSpan.innerHTML = "At timestamp " + parsedData.published_at;
            tsSpan.style.fontSize = "12px";
        }, false);
    }
    </script>
</body>
</html>

============The Spark Sketch==============

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

void setup() {
    pinMode(led, OUTPUT);
}

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,"%2u:%02u:%02u",hours,min,sec);
        Spark.publish("Uptime",publishString);
    }
}

Would it be possible to use publish to access an ASP.Net page and send the data via a POST request? If that is the case what would C#/VB.Net command need to be to read the data that is sent via the publish command?

Take a look at Webhooks documentation

Hi @kennethlimcp,
I did before posting here but it is a bit too technical for me. I have the page set up and it accepts Form parameters using something like the line below in a .Net handler called receiver.ashx:

String DataStack = context.Request.Form[“DataStack”];

But I don’t understand how to set the webhook using CLI (the command to enter) and how to use the publish command to send the data.

I am trying to read from a photo resistor at A1 on the Sparkcore board then publish it every 15 sec in a custom variable call “Light”. Can any one help so I can see what a basic ino app would look like?! (I think I might be having string char issues.

I then want to read the A1 resistor value like this…
https://api.spark.io/v1/devices/“DeviceID”/events/light?access_token="***"

Never mind I think I got something working…

unsigned long lastTime = 0UL;
char publishString[40];
char lightValue[64];

void setup() {
    Spark.variable("lightSensor", lightValue, STRING);
}

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(lightValue,"%d",analogRead(A1));
        Spark.publish("lightSensor",lightValue);
    }
}
1 Like