In our previous blog post, we showed you how to collect and publish realtime temperature and humidity data using the Tessel Climate module. Now it’s time to do something with that data.
In this blog post, we’re going to use the Tessel Climate module, AngularJS, the NVD3 library, and PubNub to graph realtime temperature and humidity data over a WiFi network.
We’ll get something that looks like this:
This tutorial picks up where we left off in our last post. If you haven’t yet, start with part one, where we show you how to set up your module and start publishing data. Then come back to this point.
Displaying the Realtime Climate Data on a Graph
In an HTML file, we’ll create the view for the data.
First, we’ll have to include all of the special libraries to help us.
<!-- Include the PubNub libraries -->
<script src="https://cdn.pubnub.com/pubnub.min.js"></script>
<script src="https://cdn.pubnub.com/pubnub-crypto.min.js"></script>
<!-- Include Angular -->
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<!-- Include PubNub Angular -->
<script src="http://pubnub.github.io/pubnub-angular/lib/pubnub-angular.js"></script>
Include nvd3 CSS to style the graph:
<link href="nv.d3.css" rel="stylesheet" type="text/css">
Include the D3.js library:
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
Include nvd3:
<script src="nv.d3.js"></script>
Include the legend file from nvd3:
<script src="legend.js"></script>
Include the line file from nvd3:
<script src="line.js"></script>
Include the utils file from nvd3:
<script src="utils.js"></script>
Add scrolling to the body:
<style>
body {
overflow-y:scroll;
}
</style>
In the view, include the SVG we’ll be creating in the JavaScript.
<svg id="graph"></svg>
Declare the Angular app and controller.
<div class="container" ng-app="PubNubAngularApp" ng-controller="ChatCtrl">
We’re all set up, now let’s get to the interesting part!
The Angular Magic
We’ll build a controller with the PubNub Angular dependency so we can listen to the PubNub channels.
<script>
angular.module('PubNubAngularApp', ["pubnub.angular.service"])
.controller('ChatCtrl', function($rootScope, $scope, $location, PubNub) {
$scope.devices = {};
We must subscribe to the same channel as our Tessel sensor is publishing. In this case, we’ve named it tesselclimate.
$scope.channel = 'tesselclimate';
Next, we initialize the PubNub service. You’ll need your publish/subscribe keys, available in the PubNub Admin Dashboard.
if (!$rootScope.initialized) {
// Initialize the PubNub service
PubNub.init({
subscribe_key: 'subscribe_key',
publish_key: 'publish_key'
});
$rootScope.initialized = true;
}
The NVD3 will be expecting arrays of data that we can grab from the PubNub channel, so let’s set those up in preparation for receiving that data.
var times_now = [];
var temperatures = [];
var humidities = [];
Finally, our Angular app can subscribe to the tesselclimate channel and register for new message events — the messages are the most recent climate data as the sensor reads it! So neat!
PubNub.ngSubscribe({ channel: $scope.channel });
$rootScope.$on(PubNub.ngMsgEv($scope.channel), function(ngEvent, payload) {
$scope.$apply(function() {
if (payload.message.uuid) {
Each message will contain the data at the time the sensor takes the reading, temperature, and humidity.
$scope.devices[payload.message.uuid] = payload.message;
$scope.time_now = Date.now();
times_now.push($scope.time_now)
$scope.temperature = payload.message.temperature[1];
temperatures.push($scope.temperature)
$scope.humidity = payload.message.humidity[1];
humidities.push($scope.humidity)
We need to draw the graph, so we use NVD3 to assist us. In this case, we’re going to draw a line graph.
nv.addGraph({
generate: function() {
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40;
var chart = nv.models.line()
.width(width)
.height(height)
.margin({top: 20, right: 20, bottom: 20, left: 20})
d3.select('#graph')
.attr('width', width)
.attr('height', height)
.datum(climateData())
.call(chart);
return chart;
},
callback: function(graph) {
window.onresize = function() {
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40,
margin = graph.margin();
if (width < margin.left + margin.right + 20)
width = margin.left + margin.right + 20;
if (height < margin.top + margin.bottom + 20)
height = margin.top + margin.bottom + 20;
graph
.width(width)
.height(height);
d3.select('#graph')
.attr('width', width)
.attr('height', height)
.call(graph);
};
}
});
The addGraph
function draws the graph with the data from the climateData
function. For each data point taken, we gather the current time, temperature, and humidity. The x-coordinate for each temperature and humidity is the time when the corresponding climate reading is taken.
The y-coordinate is the temperature or humidity reading. In this way, we’re graphing two lines (temperature, humidity) vs. time. Feel free to change the colors of the lines!
function climateData() {
var temp = [],
humid = [];
for (var i = 0; i < 500; i++) {
temp.push({x: times_now[i], y: temperatures[i]});
humid.push({x: times_now[i], y: humidities[i]});
}
return [
{
values: temp,
key: "Temperature",
color: "red"
},
{
values: humid,
key: "Humidity",
color: "blue"
}
];
}
// end nvd3
}
});
});
PubNub.ngHistory({
channel: $scope.channel,
count: 500
});
});
With the Tessel already running, start a server locally and view the Angular file in your browser. Do you see a graph of temperature and humidity over time?
Temperature and Humidity vs. Time:
As you can see, our readings stayed pretty consistent. Try covering and uncovering the sensor and watch the graph change! You could really do a lot with this data, how would you use it?
Wrapping Up Tessel
In this blog post, we had fun showing you a how to graph realtime Tessel Climate module data with PubNub. We hope you find this information to be useful — it is really cool to see the Internet of Things grow!
Dani Dewitt

Comments