mdot_server/app/js/mdot.js

515 lines
14 KiB
JavaScript
Raw Normal View History

2016-08-08 10:46:31 +00:00
'use strict';
2016-08-15 11:16:11 +00:00
/* global Backbone, _, $, AmCharts */
2016-08-08 10:46:31 +00:00
/* global mainview */
/* jshint browser: true , devel: true*/
(function($) {
2016-08-16 15:03:58 +00:00
var GraphView;
2016-08-08 10:46:31 +00:00
var mqttConfig = {
orgId: 'qz0da4',
userName: 'a-qz0da4-dfwwdkmkzr',
appKey: '9txJEf3Cjy7hkSOvkv',
prefix: 'iot-2/type/mDot/id/'
};
var sendAuthentication = function(xhr) {
var user = 'a-qz0da4-dfwwdkmkzr'; // Your actual username
var pass = '9txJEf3Cjy7hkSOvkv'; // Your actual password
var token = user.concat(':', pass);
xhr.setRequestHeader('Authorization', ('Basic '.concat(btoa(token))));
console.log('Auth:', ('Basic '.concat(btoa(token))));
};
var EventsModel = Backbone.Model.extend({
initialize: function() {
_.bindAll(this, 'processAdded');
2016-08-15 15:25:08 +00:00
this.on('all', function(d) {
console.log('model:all', d);
this.temporal = {low: 0, high: 0};
2016-08-08 10:46:31 +00:00
});
2016-08-15 15:25:08 +00:00
this.on('remove', function() {
2016-08-15 14:32:21 +00:00
$('#output').empty();
});
2016-08-08 10:46:31 +00:00
2016-08-15 15:25:08 +00:00
this.on('add', function() {
2016-08-08 10:46:31 +00:00
this.processAdded();
});
2016-08-19 15:20:51 +00:00
},
splitOccupancy: function(item) {
var start = new Date(item.start);
var msStart = ~~(start.getTime() / 300000);
2016-08-08 10:46:31 +00:00
2016-08-19 15:20:51 +00:00
var end = new Date(item.end);
var msEnd = ~~(end.getTime() / 300000);
var newArray = [];
for (var t = 0; t < (msEnd - msStart);t++) {
newArray.push({date: new Date((msStart * (300000)) + (t * 300000)), count: item.count});
}
return newArray;
},
2016-08-23 12:52:52 +00:00
findOccupancy: function(ts, occupancy) {
/*
Get a branch from the date tree and see if the reduced set of records has a matching timestamp..
*/
let count = 0;
let tsDate = new Date(ts);
let tsMS = tsDate.getTime();
let branch = this.dateTree[tsDate.getFullYear().toString()][tsDate.getMonth().toString()][tsDate.getDate().toString()];
if (typeof branch === 'undefined') return count;
_(branch).each(function(item) {
if ((tsMS >= new Date(item.start).getTime()) && (tsMS <= new Date(item.end).getTime())) {
count = item.count;
return count;
}
}, this);
return count;
},
buildSpeedDateTree: function(occupancy) {
/*
Builds a tree to help speed up occupancy searching
*/
var _tree = {};
_(occupancy).each(function(item) {
let day, month,year;
let _date = new Date(item.start);
day = _date.getDate().toString();
month = _date.getMonth().toString();
year = _date.getFullYear().toString();
if (!_tree.hasOwnProperty(year)) {
_tree[year] = {};
}
if (_tree.hasOwnProperty(year)) {
if (!_tree[year].hasOwnProperty(month)) {
_tree[year][month] = {};
}
if (_tree[year].hasOwnProperty(month)) {
if (!_tree[year][month].hasOwnProperty(day)) {
_tree[year][month][day] = [];
}
_tree[year][month][day].push(item);
}
}
}, this);
return _tree;
},
2016-08-19 15:20:51 +00:00
processAdded: function() {
console.log('Model:ProcessAdded');
var self = this;
2016-08-23 12:52:52 +00:00
var skipOccupancy = false;
2016-08-08 10:46:31 +00:00
var tempCollection = new Backbone.Collection();
2016-08-19 15:20:51 +00:00
var events;
2016-08-08 10:46:31 +00:00
_.invoke(DeviceCollection.toArray(), 'destroy');
2016-08-19 15:20:51 +00:00
events = this.get('events');
2016-08-23 12:52:52 +00:00
this.dateTree = this.buildSpeedDateTree(events.occupancy);
if (Object.keys(this.dateTree).length === 0) {
skipOccupancy = true;
}
2016-08-19 15:20:51 +00:00
_(events.data).each(function(i) {
2016-08-23 12:52:52 +00:00
let _occupancy;
if (!skipOccupancy) {
_occupancy = this.findOccupancy(i.timestamp, events.occupancy);
}
2016-08-15 15:25:08 +00:00
tempCollection.add({
2016-08-22 10:02:17 +00:00
dt: Date.create(i.timestamp).addHours(1),
2016-08-15 15:25:08 +00:00
lux: i.lux,
temp: i.temp,
co2: i.co2,
humid: i.humidity,
2016-08-23 12:52:52 +00:00
noise: i.sound,
occupancy: _occupancy
2016-08-15 15:25:08 +00:00
});
2016-08-08 10:46:31 +00:00
}, this);
DeviceCollection.models = tempCollection.models;
2016-08-19 15:20:51 +00:00
2016-08-23 12:52:52 +00:00
2016-08-08 10:46:31 +00:00
DeviceCollection.trigger('update');
2016-08-23 12:52:52 +00:00
notification.notify('success', 'Data loaded');
2016-08-15 15:25:08 +00:00
}, decoder: function(data) {
2016-08-08 10:46:31 +00:00
var _obj = {};
var _data = window.atob(data).split('');
var bytes = _data.map(i => i.charCodeAt());
2016-08-15 15:25:08 +00:00
_obj.light = parseInt('0x' + ('0' + bytes[0]).substr(-2) + ('0' + bytes[1]).substr(
-2));
_obj.co2 = parseInt(_data[2] + _data[3] + _data[4] + _data[5] + _data[6],
10);
_obj.temp = (parseInt(_data[7] + _data[8] + _data[9] + _data[10] + _data[11],
10) - 1000) / 10;
_obj.humid = (parseInt(_data[12] + _data[13] + _data[14] + _data[15] + _data[16],
10) / 10);
_obj.noise = parseInt('0x' + ('0' + bytes[17]).substr(-2) + ('0' + bytes[18]).substr(
-2));
2016-08-08 10:46:31 +00:00
_obj.binData = bytes;
return _obj;
2016-08-15 15:25:08 +00:00
}, dateTime: function($date) {
2016-08-08 10:46:31 +00:00
var dateTime = new Date.create($date);
var date = dateTime.format('{yyyy}-{MM}-{dd}');
var time = dateTime.format('{HH}:{mm}:{ss}');
2016-08-15 15:25:08 +00:00
return {
dateTime: dateTime.format('{yyyy}-{MM}-{dd} {HH}:{mm}:{ss}'),
date: date,
time: time
};
2016-08-08 10:46:31 +00:00
}
});
var mDotCollection = Backbone.Collection.extend({
model: EventsModel,
url: 'https://qz0da4.internetofthings.ibmcloud.com/api/v0002/historian/types/mDot/devices/',
initialize: function() {
this.on('update', function() {
2016-08-22 10:02:17 +00:00
2016-08-08 10:46:31 +00:00
});
}
});
var ItemView = Backbone.View.extend({
tagName: 'div', className: 'item mui-container', initialize: function() {
this.template = _.template($('#item-template').html());
console.log('ItemView:Init');
}, render: function() {
2016-08-08 10:46:31 +00:00
console.log('ItemView:Render');
_(this.model.events).each(function(i) {
this.$el.append(this.template({item: i}));
}, this);
return this;
}
});
var MDOT = Backbone.View.extend({
model: EventsModel, el: $('#output'),
events: {
'click button#refresh': 'refresh'
}, initialize: function() {
_.bindAll(this, 'render', 'refresh', 'update');
this.collection.bind('change reset add remove', this.render, this);
2016-08-15 14:32:21 +00:00
this.template = _.template($('#loaded-template').html());
2016-08-08 10:46:31 +00:00
}, refresh: function() {
}, update: function() {
console.log('MDOT:update');
this.collection.each(function(model) {
});
}, render: function() {
2016-08-22 10:02:17 +00:00
var that = this;
2016-08-08 10:46:31 +00:00
console.log('MDOT:render');
2016-08-15 14:32:21 +00:00
$('#output').empty();
2016-08-08 10:46:31 +00:00
return this;
}
});
var MainModel = Backbone.Model.extend({});
var MainView = Backbone.View.extend({
2016-08-15 15:25:08 +00:00
el: $('#main'), template: _.template($('#main-template').html()), events: {
'change select#device': 'changeDevice',
'click button#refresh': 'updateDevice',
submit: function(event) {}
2016-08-08 10:46:31 +00:00
2016-08-15 15:25:08 +00:00
}, initialize: function() {
_.bindAll(this, 'render', 'changeDevice', 'updateDevice');
2016-08-08 10:46:31 +00:00
2016-08-15 15:25:08 +00:00
this.model.on('change', this.updateDevice);
console.log('MainView:', this);
this.render();
}, render: function() {
2016-08-08 10:46:31 +00:00
$(this.el).html(this.template());
return this;
2016-08-15 15:25:08 +00:00
}, changeDevice: function() {
2016-08-08 10:46:31 +00:00
var newDevice;
console.log('MainView:ChangeDevice');
newDevice = this.$el.find('#device')[0].value;
this.model.set('device', newDevice);
2016-08-15 15:25:08 +00:00
}, updateDevice: function() {
2016-08-08 10:46:31 +00:00
var fetchObj = {beforeSend: sendAuthentication};
console.log('MainView:Updatedevice');
2016-08-19 16:04:01 +00:00
notification.clearAll();
2016-08-08 10:46:31 +00:00
if (this.model.has('device')) {
2016-08-15 15:25:08 +00:00
this.collection.url = '/apiv2/mdot/' + this.model.get('device');
2016-08-15 14:32:21 +00:00
2016-08-15 15:25:08 +00:00
$('#output').empty();
2016-08-23 12:52:52 +00:00
notification.notify('info', 'Loading...');
2016-08-08 10:46:31 +00:00
this.collection.fetch(fetchObj);
} else {
console.error('Nothing to get!');
}
}
});
2016-08-16 15:03:58 +00:00
GraphView = Backbone.View.extend({
2016-08-19 15:20:51 +00:00
el: $('#graph'), initialize: function() {
2016-08-15 15:25:08 +00:00
this.modes = ['', 'lux', 'temp', 'co2', 'humid', 'noise'];
2016-08-16 15:03:58 +00:00
this.titles = [
'', 'Light Levels', 'Temperature', 'Co2 Levels', 'Humidity', 'Sound'
];
2016-08-19 15:20:51 +00:00
2016-08-15 15:25:08 +00:00
this.mode = 0;
// Config AMChart
2016-08-19 15:20:51 +00:00
this.chart = {};
2016-08-15 15:25:08 +00:00
this.categoryAxesSettings = new AmCharts.CategoryAxesSettings();
this.dataSet = new AmCharts.DataSet();
console.log('GraphView!');
2016-08-22 10:02:17 +00:00
_.bindAll(this, 'render', 'updateGraphV2', 'setupChart');
2016-08-15 15:25:08 +00:00
this.collection.on('update', function(d) {
2016-08-19 15:20:51 +00:00
console.log('GraphView Collection update trigger!!');
this.updateGraphV2();
2016-08-15 15:25:08 +00:00
}, this);
2016-08-19 15:20:51 +00:00
}, events: {
2016-08-15 15:25:08 +00:00
'change select#displaymode': 'changeMode'
2016-08-19 15:20:51 +00:00
}, setupChart: function() {
2016-08-12 08:48:56 +00:00
console.log('chart:SetupChart');
this.categoryAxesSettings.minPeriod = 'mm';
this.chart.categoryAxesSettings = this.categoryAxesSettings;
this.dataSet.color = '#b0de09';
this.chart.dataSets = [this.dataSet];
},
2016-08-17 10:21:53 +00:00
doChartV2: function(chartData) {
var self = this;
self.chart = AmCharts.makeChart('chartdiv', {
2016-08-19 15:20:51 +00:00
type: 'serial',
theme: 'light',
dataSets: [
],
legend: {
2016-08-22 10:02:17 +00:00
useGraphSettings: true,
color: '#fff',
switchColor: '#556374'
2016-08-19 15:20:51 +00:00
},
color: '#ffffff',
dataProvider: chartData,
dataDateFormat: 'YYYY-MM-DDTHH:NN:SS.QQQ',
synchronizeGrid: true,
valueAxes: [
{
id: 'lux',
axisColor: '#FFC802',
axisThickness: 2,
axisAlpha: 1,
2016-08-22 10:02:17 +00:00
position: 'left',
gridColor: '#556374'
2016-08-19 15:20:51 +00:00
},
{
id: 'co2',
axisColor: 'rgba(0,191,255,1)',
axisThickness: 2,
axisAlpha: 1,
2016-08-22 10:02:17 +00:00
position: 'right',
gridColor: '#556374'
2016-08-19 15:20:51 +00:00
},
{
id: 'temp',
axisColor: 'rgba(46,255,0,1)',
axisThickness: 2,
gridAlpha: 0,
offset: 50,
axisAlpha: 1,
2016-08-22 10:02:17 +00:00
position: 'left',
gridColor: '#556374'
2016-08-19 15:20:51 +00:00
},
{
id: 'humid',
axisColor: 'rgba(255,0,99,1)',
axisThickness: 2,
axisAlpha: 1,
2016-08-17 10:28:00 +00:00
offset: 50,
2016-08-22 10:02:17 +00:00
position: 'right',
gridColor: '#556374'
2016-08-23 12:52:52 +00:00
}/*,
2016-08-19 15:20:51 +00:00
{
id: 'noise',
axisColor: 'rgb(99, 157, 189)',
axisThickness: 2,
gridAlpha: 0,
offset: 100,
axisAlpha: 1,
2016-08-22 10:02:17 +00:00
position: 'left',
gridColor: '#556374'
2016-08-23 12:52:52 +00:00
}*/
,{
id: 'occupancy',
axisColor: '#aaaaaa',
axisThickness: 2,
gridAlpha: 0,
offset: 100,
axisAlpha: 1,
position: 'right',
gridColor: '#556374'
}
2016-08-19 15:20:51 +00:00
],
2016-08-23 12:52:52 +00:00
graphs: [{id:'occ',
valueAxis: 'occupancy',
"type": "column",
"clustered":true,
"columnWidth":1,
lineColor: '#aaaaaa',
title: 'Occupancy',
valueField: 'occupancy',
fillColor: '#888888',
fillAlphas: 0.2,
fillToAxis: 'x'
},
2016-08-19 15:20:51 +00:00
{
valueAxis: 'lux',
lineColor: '#FFC802',
title: 'Light Level',
valueField: 'lux',
fillAlphas: 0
},
{
valueAxis: 'co2',
lineColor: 'rgba(0,191,255,1)',
title: 'Co2',
valueField: 'co2',
fillAlphas: 0
},
{
valueAxis: 'temp',
lineColor: 'rgba(46,255,0,1)',
title: 'Temperature',
valueField: 'temp',
fillAlphas: 0
},
{
valueAxis: 'humid',
lineColor: 'rgba(255,0,99,1)',
title: 'Humidity',
valueField: 'humid',
fillAlphas: 0
2016-08-23 12:52:52 +00:00
}/*,
2016-08-19 15:20:51 +00:00
{
valueAxis: 'noise',
lineColor: 'rgb(99, 157, 189)',
title: 'Sound',
valueField: 'noise',
fillAlphas: 0
2016-08-23 12:52:52 +00:00
}*/
2016-08-19 15:20:51 +00:00
],
2016-08-23 12:52:52 +00:00
chartScrollbar: {
graph:'occ',"oppositeAxis":false,
"offset":30,
"scrollbarHeight": 80,
"backgroundAlpha": 0,
"selectedBackgroundAlpha": 0.1,
"selectedBackgroundColor": "#888888",
"graphFillAlpha": 0,
"graphLineAlpha": 0.5,
"selectedGraphFillAlpha": 0,
"selectedGraphLineAlpha": 1,
"autoGridCount":true,
"color":"#AAAAAA"
},
2016-08-19 15:20:51 +00:00
chartCursor: {
2016-08-22 10:02:17 +00:00
cursorPosition: 'mouse',
cursorColor: '#14bfff',
color: '#000'
2016-08-19 15:20:51 +00:00
},
categoryField: 'date',
categoryAxis: {
2016-08-23 12:52:52 +00:00
minPeriod: '15mm',
2016-08-19 15:20:51 +00:00
parseDates: true,
2016-08-22 10:02:17 +00:00
axisColor: 'rgba(255,255,255,0.8)',
minorGridEnabled: true,
gridColor: '#556374'
2016-08-19 15:20:51 +00:00
},
export: {
enabled: true, position: 'bottom-right'
}
2016-08-16 15:03:58 +00:00
});
2016-08-15 15:25:08 +00:00
2016-08-15 11:16:11 +00:00
$('#chartdiv').empty();
2016-08-15 15:25:08 +00:00
self.chart.write('chartdiv');
2016-08-19 15:20:51 +00:00
}, updateGraphV2: function() {
2016-08-17 10:21:53 +00:00
var self = this;
var chartData = [];
_(this.collection.models).each(function(i) {
chartData.push({
date: i.get('dt'),
co2: i.get('co2'),
humid: i.get('humid'),
lux: i.get('lux'),
noise: i.get('noise'),
2016-08-23 12:52:52 +00:00
temp: i.get('temp'),
occupancy: i.get('occupancy')
2016-08-17 10:21:53 +00:00
});
});
2016-08-23 12:52:52 +00:00
// Console.log(chartData);
2016-08-17 10:21:53 +00:00
self.doChartV2(chartData);
2016-08-15 15:25:08 +00:00
}
2016-08-08 10:46:31 +00:00
});
2016-08-23 12:52:52 +00:00
notification.configProfile('global', {
stacking: false
});
2016-08-08 10:46:31 +00:00
var DeviceCollection = new Backbone.Collection;
2016-08-19 15:20:51 +00:00
var OccupancyCollection = new Backbone.Collection;
2016-08-08 10:46:31 +00:00
var mdotCollection = new mDotCollection();
var mainSettings = new MainModel();
2016-08-15 15:25:08 +00:00
var mainview = new MainView({
2016-08-19 15:20:51 +00:00
collection: mdotCollection, model: mainSettings
2016-08-15 15:25:08 +00:00
});
2016-08-08 10:46:31 +00:00
var mdot = new MDOT({collection: mdotCollection});
var grapher = new GraphView({collection: DeviceCollection});
})(jQuery);