Skip to content

Instantly share code, notes, and snippets.

@TrevorBasinger
Created May 11, 2015 18:42
Show Gist options
  • Save TrevorBasinger/01c3a34db4657a391dda to your computer and use it in GitHub Desktop.
Save TrevorBasinger/01c3a34db4657a391dda to your computer and use it in GitHub Desktop.
/* jshint laxbreak: true, laxcomma: true */
(function (R, A) {
var mkSensorUrl = function (unit) { return 'http://10.50.2.213:8080/v2/units/' + unit + '/sensors'; },
mkChart = R.curry (function (el, label) {
return new Highcharts.Chart({ chart: { renderTo: el
, defaultSeriesType: 'line' }
, title: { text: 'Live '+label+' data' }
, xAxis: { type: 'datetime'
, tickLength: 1 }
, yAxis: { minPadding: 0.2
, maxPadding: 0.2
, title: { text: 'Readings'
, margin: 80 } }
, plotOptions: { series: { showCheckbox: false
, visible: false
, events: { show: function () {
var chart = this.chart,
series = chart.series,
i = series.length,
otherSeries;
while (i--) {
otherSeries = series[i];
if (otherSeries != this && otherSeries.visible) {
otherSeries.hide();
}
}
},
legendItemClick: function () {
if (this.visible) {
return false;
}
}}}}
, series: []});
}),
// hasConstants :: [Tuple (Sensor, Int)] -> Bool
hasConstants = R.compose (R.lt (0), R.length, R.prop ('mappedto'), R.head),
// notHasConstants :: [Tuple (Sensor, Int)] -> Bool
notHasConstants = R.compose (R.not, R.lt (0), R.length, R.prop ('mappedto'), R.head),
getSensors = R.curry (function (cb, unit) {
$.ajax ({
method: 'GET',
url: mkSensorUrl (unit),
headers: { 'x-api-key': '7d798801e37f726fe8ab2fd36673b3a1' },
success: function (data, s, xhr) { cb (R.prop ('results', data)); },
});
}),
// updateSeriesWithMaxLen :: Time -> Int -> SeriesRecord -> Tuple (Sensor, Int) -> SeriesRecord
updateSeriesWithMaxLen = R.curry (function (dt, maxLen, acc, tup) {
var name = R.replace (' ', '-', R.toLower (tup[0].sensorname));
var label = tup[0].sensorname;
if (!acc[name]) { acc[name] = {name: label, data: []}; }
acc[name].data = R.append ([dt, tup[1]], acc[name].data);
if (acc[name].length > maxLen) {
acc[name].data = R.slice (acc[name].data.length - maxLen, acc[name].data.length, acc[name].data);
}
return acc;
}),
nil = null;
var FloFlo = A.module ('FloFlo', []);
FloFlo.factory ('LiveData', ['$rootScope', function ($rootScope) {
var socket = io ();
socket.on ('message', function (msg) { $rootScope.$broadcast ('message', msg); });
return { join: function (channel) { socket.emit ('join', channel); }
, leave: function (channel) { socket.emit ('leave', channel); } };
}]);
FloFlo.controller ('FloTroller', ['$rootScope', '$scope', 'LiveData', function ($rs, $s, LD) {
$s.seriesRecord = {};
$s.sensors = [];
$s.joinUnit = function (unit) {
getSensors (function (xs) {
$s.sensors = R.sort (function (a, b) { return a.address - b.address; }, xs);
LD.join ('scada#'+ unit +'#');
}, unit);
};
$s.leaveUnit = function (unit) { LD.leave ('scada#'+ unit +'#'); $s.seriesRecord = {}; };
$s.$on ('message', function (e, m) {
var dt = new Date (m.date).getTime(),
values = R.map(function (s) { return [s, R.nth (s.address, m.values)]; }, $s.sensors),
rangeTups = R.filter (notHasConstants, values),
constTups = R.filter (hasConstants, values);
R.reduce (updateSeriesWithMaxLen (dt, 20), $s.seriesRecord, rangeTups);
$s.$apply(); // Why? Cause fuck angular, that's why!
if (!$s.chart) { $s.chart = mkChart ('floChart', m.unit); }
if ($s.chart.series.length !== R.length (R.keys ($s.seriesRecord)))
{ R.mapObj (function (x) { $s.chart.addSeries (x); }, $s.seriesRecord); }
R.mapIndexed (function (x, i, o) {
var shift = $s.chart.series[i].data.length > 20;
$s.chart.series[i].addPoint (R.last (x[1].data), true, shift);
}, R.toPairs ($s.seriesRecord));
});
}]);
FloFlo.directive ('floUnitInput', function () {
return {
restrict: 'E',
templateUrl: 'unitinput.html',
controller: 'FloTroller'
};
});
})(R, angular);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment