If you have seen my Spark.publish() tutorials, you know that I like to have private web pages (since if it was public, your access token would be exposed) that read and even graph data from my Spark core. Well, you can do similar things with Spark.variables() and here’s how.
Declare Yourself
Let’s say you have a Spark.variable declared and you want to read it. In my case, it is a temperature variable from a DS18B20 temperature sensor and I have converted the value to a double-precision floating-point value. My declaration in setup() looks like this:
Spark.variable("temperature", &sparkTempF, DOUBLE);
Be Safe!
OK, so how do we read this variable on a web page? Easy. First a word of warning! We are going to be putting an access token in this file so it cannot be public. You can have it on your local computer and access it via a file:///path/to/file/name.html
URL, or you can do like I do and put the file on a service like Dropbox so that I can access it from any computer or phone or iPad that I use Dropbox on. If you need a public way to do this, I would look at using a PHP proxy or other intermediary to hide your token.
Web Magic
We need one little magic ingredient and that is a dash of AJAX and jquery! AJAX is a way to use Javascript to do things asynchronously on a web page. If you have ever watched a web page of a “live blog” for an event like a product announcement where someone is updating a blog in real-time and you are seeing the updates in near real-time, that is AJAX. There are lots and lots of examples and ways to use it, but we need the simplest way, an HTTP GET request.
Normally your browser does not allow a web page to fetch data from another web source and show it to you. What would happen if those awful spammers could send you a link to their bogus web page for your bank, but it could connect to the real web page for your bank and listen in as it showed you their site? You would lose a lot of money, that’s what! So to prevent that, your browser does not allow a page on web site A to fetch URLs from web site B, but that is exactly what we need to do in this case! The solution is AJAX and a safe way to fetch only certain data in JSON format. Luckily for us, the Spark team understood this and all Spark variables return their data in JSON format. The Spark cloud is also setup for this type of access using tokens (instead of cookies) to identify users.
Here’s the first example. Set your device ID and access token and variable name (if it is not “Temperature”) and load this up in a browser and click the “Read Temp” button. Here is what that looks like (I have covered over part of the URL here–just fill in from there):
Every time you click the "Read Temp" button, you will get a new variable value from your core and a new timestamp. It is interactive at your command.
The HTML Code
Here is the code for that–don’t forget to replace the deviceID and access_token values with yours and keep this private.
<!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>
<span id="temp"></span><br>
<span id="tstamp"></span><br>
<button id="connectbutton" onclick="start()">Read Temp</button>
<script type="text/javascript">
function start(objButton) {
document.getElementById("temp").innerHTML = "Waiting for data...";
document.getElementById("tstamp").innerHTML ="";
var deviceID = "<< device id >>";
var accessToken = "<< access token >>";
var varName = "temperature";
requestURL = "https://api.spark.io/v1/devices/" + deviceID + "/" + varName + "/?access_token=" + accessToken;
$.getJSON(requestURL, function(json) {
document.getElementById("temp").innerHTML = json.result + "° F";
document.getElementById("temp").style.fontSize = "28px";
document.getElementById("tstamp").innerHTML = json.coreInfo.last_heard;
});
}
</script>
</body>
</html>
Ok, so the magic is using the AJAX jquery api and then using the getJSON
function to do the work. Since the Spark variable data is already in JSON format, in the callback function we can just use the function argument like a struct to access the different fields. We access the result field, which is the published data and we also use the last_heard field in the coreInfo field, which is a GMT timestamp for the variable read that is supplied by the Spark cloud.
Blurring the Lines
Ok, so you are still not satisfied, are you? Remember that live-blog example above where AJAX can be used to update a web page you are viewing in near real-time? We can do that do!
So we can make a web page that automatically reloads the variable and we can set the number of seconds between updates. Now we have a polling loop that is somewhat like publish, but you want to be careful here. We need to be good neighbors on the Spark cloud and not poll too often. Your temperature sensor really can’t change quickly and polling every 10 seconds is plenty fast. In fact, polling every 15 minutes would probably be better for the cloud and not really any different for you, but I want you to see the time stamp update and know it is working.
Here is the a screenshot:
Now here is the code:
<!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>
<span id="temp">Waiting for data...</span><br>
<span id="tstamp"></span><br>
<script type="text/javascript">
window.setInterval(function() {
var deviceID = "<< device id >>";
var accessToken = "<< access token >>";
var varName = "temperature";
requestURL = "https://api.spark.io/v1/devices/" + deviceID + "/" + varName + "/?access_token=" + accessToken;
$.getJSON(requestURL, function(json) {
document.getElementById("temp").innerHTML = json.result + "° F";
document.getElementById("temp").style.fontSize = "28px";
document.getElementById("tstamp").innerHTML = json.coreInfo.last_heard;
});
}, 10000);
</script>
</body>
</html>
We got rid of the button and we just run the Javascript when the page loads now, but we have wrapped the getJSON code from the above example with a window.setInterval()
wrapper that calls that Javascript every 10,000 ms or every 10 seconds.
Final Thoughts
Ok, so the Spark core can push data using publish and the web can pull data using AJAX and jquery. Which is better? I think if you want to receive periodic data from the core, push is better. If you want more interactivity then polling to pull data might be the way to go. But just polling on a schedule, as in the second example here is probably not the best way.
Just remember to be a good Spark cloud neighbor and not go crazy trying to pull data too fast. I know, for instance, that my house is about 140 ms away from the Spark cloud, up and back, so trying to poll for data faster than every second or two just does not make sense. Plus the sensor cannot change meaningfully in that short a time.
So go have fun and read your variables where ever you want now! Just remember to stay safe with that access token!