Skip to content

Instantly share code, notes, and snippets.

@TrevorBasinger
Created May 11, 2015 21:57
Show Gist options
  • Save TrevorBasinger/063f9a4e8a4e249e2bf9 to your computer and use it in GitHub Desktop.
Save TrevorBasinger/063f9a4e8a4e249e2bf9 to your computer and use it in GitHub Desktop.
/* jshint laxbreak: true, laxcomma: true */
(function (R, F, M, A) {
var log = function (x) { console.log (x); return x; },
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 = R.compose (R.lt (0), R.length, R.prop ('mappedto'), R.head),
notHasConstants = R.compose (R.not, R.lt (0), R.length, R.prop ('mappedto'), R.head),
getSensors = R.curry (function (unit) {
return new F (function (reject, resolve) {
$.ajax ({
method: 'GET',
url: mkSensorUrl (unit),
headers: { 'x-api-key': '7d798801e37f726fe8ab2fd36673b3a1' },
success: resolve,
error: reject,
});
}).map (R.prop ('results')) ;
}),
nest = R.flip (R.append)([]),
// getConstants :: String -> Future [Fault]
getConstants = R.curry (function (unit, c) {
return new F (function (reject, resolve) {
$.ajax ({
method: 'GET',
url: mkSensorUrl (unit) + '/' + c,
headers: { 'x-api-key': '7d798801e37f726fe8ab2fd36673b3a1' },
success: resolve,
error: reject,
});
}).map (R.prop ('results'))
// Because ramda 'toPairs' isn't working correctly... I'm sorry future me. For everything.
.map (function (xs) { var x = {}; x[c] = xs; return x; });
}),
// 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.constants = null;
$s.getConstVal = function (c, n) {
var cs = R.filter (R.compose (R.eq (n), R.prop ('code')), $s.constants[c]);
return cs[0].description;
};
$s.joinUnit = function (unit) {
getSensors (unit).fork (log, function (xs) {
$s.sensors = xs;
LD.join ('scada#'+ 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);
$s.constTups = R.filter (hasConstants, values);
var f = R.compose (getConstants (m.unit), R.prop ('mappedto'), R.head);
if (!$s.constants) {
var futures = R.map (f, $s.constTups);
var ff = M.sequence (F, futures);
ff.fork (log, function (xs) { $s.constants = log (R.mergeAll (xs)); $s.$apply(); });
}
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, Future, Monads, angular);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment