jQuery & JSON Enabled Google Gauges

After struggling with how to get a Google Gauge to update itself with new data that I’m posting every minute I finally found the easiest way to do it. I was amazed how hard it was to get a decent set of instructions. There are 115,000 hits if you Google this page title, and I don’t have that kind of time, and we don’t need it. Our buddies at Thingspeak have a plugin creator that lays the foundation for using Gauges with their service. It masks a lot of the technical needs so most people can create one with little fuss. However, if you really look at the code they provide it tips you off to a few things, namely the jQuery call to retrieve the JSON data. Ahhh, remember that? JSON is the common way all of the IoT platforms I use return data from a query.

These are real examples using each public IoT platform

Http iframes are not shown in https pages in many major browsers. Please read this post for details.

Open.Sen.Se JSON
Http iframes are not shown in https pages in many major browsers. Please read this post for details.

Xively JSON
Http iframes are not shown in https pages in many major browsers. Please read this post for details.

Thingspeak JSON

So a little trial and error with URL’s and I had something to work with. Here is the info you need to know:

The ThingSpeak.com JSON Method

Thingspeak organizes all of your sensor data into fields, up to 8 per channel. You assign a name to a field, in this case, I’ll use field1 which is my downstairs temperature.
Thingspeak queries are formatted like this:

https://api.thingspeak.com/channels/(channel_id)/field/(field_id)/last.(format)

That gets you close but there’s more. You need to replace the (channel_id), (field_id) and (format) with the Thingspeak channel ID from the channels page (duh!), the ID number of the field to query, your read API key (make one if you haven’t) and JSON as the format. It should look like this:

https://api.thingspeak.com/channels/7367/field/1/last.json?apikey=D01ZZNBQX10X10IH

If you paste this URL in a browser you will see the JSON return data, and that’s the next clue. You’re looking for the label associated with the value, in this case field1 (it isn’t always this easy).

{
"created_at":"2013-09-27T20:30:56Z",
"entry_id":16264,
"field1":"78.35"
}

Putting It Together

So now you have the URL syntax and know the name of the data field. Time to plug it in to the gauge code. Change the following lines accordingly:

  • Change line 27 to change the gauge label
  • Change line 36 to contain your channel ID, field ID, API (read only) key
  • Change line 39 to read data.field__ where __ is the field number
  • Change lines 56-75 to modify the gauge UI
  • Change line 81 to control the refresh interval in milliseconds (15000 = 15 seconds)
<html>
<head>
<title>Google Gauge - ThingSpeak</title>
</head>
<body>
<div id='chart_div'></div>
</body>
</html>	
<style type="text/css">
/*body { background-color: #ddd; }*/
</style>
<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js'></script> 
<script type='text/javascript' src='https://www.google.com/jsapi'></script>
<script type='text/javascript'>
var chart; 
var charts;
var data;
google.load('visualization', '1', {packages:['gauge']});
google.setOnLoadCallback(initChart);
function displayData(point) {
data.setValue(0, 0, 'Backyard');
data.setValue(0, 1, point);
chart.draw(data, options);
}
function loadData() {
// variable for the data point
var p;
$.getJSON('https://api.thingspeak.com/channels/7367/field/5/last.json?apikey=EPQ400EHDNU7DVLE&callback=?', function(data) { //Thingspeak
// get the data point
p = data.field5; //Thingspeak
if (p) {
p = (p/1);
displayData(p);
}
});
}
function initChart() {
data = new google.visualization.DataTable();
data.addColumn('string', 'Label');
data.addColumn('number', 'Value');
data.addRows(1);
chart = new google.visualization.Gauge(document.getElementById('chart_div'));
options = {
width: 175, 
height: 175, 
redFrom: 90, 
redTo: 110,
yellowFrom: 80, 
yellowTo: 90, 
greenFrom: 70, 
greenTo: 80, 
minorTicks: 10,
min: 30, 
max: 110, 
animation: {
duration: 400, 
easing: 'out',
},
};
loadData();
setInterval('loadData()', 15000);
}
</script>

The Xively.com JSON Method

Xively organizes all of your sensor data into datastream names. You create the name yourself, in this case, I’ll use Downstairs which is my downstairs temperature.
Xively queries are formatted like this:

https://api.xively.com/v2/feeds/FEED_ID_HERE/datastreams/DATASTREAM_ID.(FORMAT)

That gets you close but there’s more. You need to replace the FEED_ID_HERE, (DATASTREAM_ID) and (FORMAT) with the Xively feed ID from the channels page, the name of the datastream to query, your read API key (make one if you haven’t) and JSON as the format. It should look like this:

https://api.xively.com/v2/feeds/459777482/datastreams/Downstairs.json?&key=nIUvh0MztrrnF4gbmS9yHFKpyueXiewJW5nuUuQjSN83m0P4

If you paste this URL in a browser you will see the JSON return data, and that’s the next clue. You’re looking for the label associated with the value, in this case current_value.

{
"id":"Downstairs",
"current_value":"79.47",
"at":"2013-09-27T21:02:57.465432Z",
"max_value":"85.21",
"min_value":"62.15",
"tags":["Downstairs"],
"unit":{
"symbol":"F",
"label":"Degrees"
},
"version":"1.0.0"
}

Putting It Together

So now you have the URL syntax and know the name of the data field. Time to plug it in to the gauge code. Change the following lines accordingly:

  • Change line 27 to change the gauge label
  • Change line 36 to contain your feed ID, datastream name, API (read only) key
  • Change line 39 to read data.current_value
  • Change lines 56-75 to modify the gauge UI
  • Change line 81 to control the refresh interval in milliseconds (15000 = 15 seconds)
<html>
<head>
<title>Google Gauge - Xively</title>
</head>
<body>
<div id='chart_div'></div>
</body>
</html>	
<style type="text/css">
/*body { background-color: #ddd; }*/
</style>
<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js'></script> 
<script type='text/javascript' src='https://www.google.com/jsapi'></script>
<script type='text/javascript'>
var chart; 
var charts;
var data;
google.load('visualization', '1', {packages:['gauge']});
google.setOnLoadCallback(initChart);
function displayData(point) {
data.setValue(0, 0, 'Refrigerator');
data.setValue(0, 1, point);
chart.draw(data, options);
}
function loadData() {
// variable for the data point
var p;
$.getJSON('https://api.xively.com/v2/feeds/459777482/datastreams/Black_Refrigerator.json?&key=USz8MXsOMwmlPJW6EitGVTAGZ7CTzJaSonpnB2qqrLC76yaM&callback=?', function(data) { //Xively
// get the data point
p = data.current_value; //Xively
if (p) {
p = (p/1);
displayData(p);
}
});
}
function initChart() {
data = new google.visualization.DataTable();
data.addColumn('string', 'Label');
data.addColumn('number', 'Value');
data.addRows(1);
chart = new google.visualization.Gauge(document.getElementById('chart_div'));
options = {
width: 175, 
height: 175, 
redFrom: 50, 
redTo: 60,
yellowFrom: 40, 
yellowTo: 50, 
greenFrom: 30, 
greenTo: 40, 
minorTicks: 10,
min: 30, 
max: 60, 
animation: {
duration: 400, 
easing: 'out',
},
};
loadData();
setInterval('loadData()', 15000);
}
</script>

The Open.Sen.Se JSON Method

Open.Sen.Se organizes all of your sensor data into feed numbers. You correlate the feed ID to a relevant name elsewhere in your code. In this case, I’ll use 42673 which is my downstairs temperature.
Open.Sen.Se queries are formatted like this:

http://open.sen.se/feeds/__feed_id__/last_event/

That gets you close but there’s more. You need to replace the __feed_id__ with the Open.Sen.Se feed ID from the devices >> recap page, your API key (they aren’t read-only, keep it private!). It should look like this:

http://api.sen.se/feeds/42673/last_event/?sense_key=cbkY1dMYOZ03sMlFkN6944 << not my real API, may not work

If you could paste this URL in a browser you will see the JSON return data, and that’s the next clue. You’re looking for the label associated with the value, in this case current_value.

{
"publish_id": "004e763fe297b1e",
"value": "79.81",
"timetag": "2013-09-27T21:15:58+00:00",
"feed_id": 42673,
"id": 1329429634,
"unit": "°F"
}

Putting It Together

So now you have the URL syntax and know the name of the data field. Time to plug it in to the gauge code. Change the following lines accordingly:

  • Change line 27 to change the gauge label
  • Change line 36 to contain your feed ID and API key
  • Change line 38 to read data.value
  • Change lines 55-74 to modify the gauge UI
  • Change line 80 to control the refresh interval in milliseconds (15000 = 15 seconds)
<html>
<head>
<title>Google Gauge - Open.Sen.Se</title>
</head>
<body>
<div id='chart_div'></div>
</body>
</html>	
<style type="text/css">
/*body { background-color: #ddd; }*/
</style>
<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js'></script> 
<script type='text/javascript' src='https://www.google.com/jsapi'></script>
<script type='text/javascript'>
var chart; 
var charts;
var data;
google.load('visualization', '1', {packages:['gauge']});
google.setOnLoadCallback(initChart);
function displayData(point) {
data.setValue(0, 0, 'kWh');
data.setValue(0, 1, point);
chart.draw(data, options);
}
function loadData() {
// variable for the data point
var p;
$.getJSON('http://api.sen.se/feeds/42677/last_event/?sense_key=cbkY1dMR8Ysja7861mzAlFkN694w&callback=?', function(data) {    //used for Open.Sen.Se
// get the data point
p = data.value;	
if (p) {
p = (p/1);
displayData(p);
}
});
}
function initChart() {
data = new google.visualization.DataTable();
data.addColumn('string', 'Label');
data.addColumn('number', 'Value');
data.addRows(1);
chart = new google.visualization.Gauge(document.getElementById('chart_div'));
options = {
width: 175, 
height: 175, 
redFrom: 2, 
redTo: 3,
yellowFrom: 1, 
yellowTo: 2, 
greenFrom: 0, 
greenTo: 1, 
minorTicks: 13,
min: 0, 
max: 3, 
animation: {
duration: 400, 
easing: 'out',
},
};
loadData();
setInterval('loadData()', 15000);
}
</script>

8 Comments

  1. Hi,

    Thanks for your explanations and codes. These were really helpful.
    I am very interested in the ThingSpeak method.
    Your example with one gauge works very well.
    Could you give me also an example code how to display 2 gauges,
    for example temperature and humidity, (2 feeds) on one web page?

    Thanks a lot.
    Regards, Sam

    • Jason

      Sam, see if this helps. You just need to replace the channel ID in the ‘file_get_contents‘ lines at the top. Of course the CSS file link will be broken. Code is here: http://pastebin.com/SRFjRLQz

    • Whoops. Check that. That’s code that does what you asked BUT I suspect you also want the jQuery refreshing to work. I think I have some code for that but I moved away from Google Gauges so some of those files are not around any longer. There are more elegant gauges, like these and these, you know? I’m not doing multiple gauges on one doc with these either, iframe embeds seem to be the way to go.

  2. Andy Cox

    I have been looking everywhere for such a clear explanation! Thanks very much for taking the time to make this fantastic post.

    • I’m happy it helped you out! I put this together at first as a personal note to keep it handy as a reference. I’m glad I decided to share it.

  3. I was a bit surprised to see you use a JSON for Thingspeak that is channels/channelID/field/fieldno
    The original Gauge example in Thingspeak uses channels/’ + channel_id + ‘/feed
    I am sure yours work and my use of feed works too, so I just wondered if th eone is better than the other

  4. Id appreciate it if someone can steer me in the right direction.
    I have a page with Google gauges and charts that is pulling data from Sparkfun’s IOT site.
    Their server tends to be slow so I would like to pull data from my ThingSpeak channel instead.
    The page I currently have is here:
    http://denvercircuits.com/Google%20Chart%20-%20GK-RadMon%20Plus.html
    (You can view the source there.)

    If I got the JSON data in the same array as I’m using, I think I can handle any differences.
    You can probably tell this isn’t my strong suite but I’d appreciate any help.
    John

  5. Thank you so much for your explain!

Leave a Comment

Your email address will not be published. Required fields are marked *