var poconsole = angular.module('poconsole', ['ngJustGage', 'n3-line-chart', "ngQuickDate", "ngSails"]); function isValidDate(d) { if ( Object.prototype.toString.call(d) !== "[object Date]" ) return false; return !isNaN(d.getTime()); } var colors = ['#d7191c','#fdae61','#abdda4','#2b83ba']; poconsole.config(function(ngQuickDateDefaultsProvider) { // Configure with icons from font-awesome return ngQuickDateDefaultsProvider.set({ closeButtonHtml: "", buttonIconHtml: "", nextLinkHtml: "", prevLinkHtml: "", // Take advantage of Sugar.js date parsing parseDateFunction: function(str) { d = Date.create(str); return d.isValid() ? d : null; } }); }); var dString_to_sqlite = function(dString){ /** * Takes a date string in the form YYYYMMDD_HHmmSS and returns it in SQLite format (YYYY-MM-DD HH:mm:SS) * @param {String} dString * @return {String} sqliteString */ var re = /(\d{4})(\d{2})(\d{2})_(\d{2})(\d{2})(\d{2})/; var fd = re.exec(dString); if (fd){ var sqliteString = ""; return sqliteString.concat(fd[1], "-", fd[2], "-", fd[3], " ", fd[4], ":", fd[5], ":", fd[6]); } else { return null; } }; var sqlite_to_dString = function(sqliteDate){ /** * Takes a sqlite date string in the form YYYY-MM-DD HH:mm:SS and returns it in format YYYYMMDD_HHmmSS * @param {String} sqliteDate * @return {String} dString */ var re = /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/; var fd = re.exec(sqliteDate); if (fd){ var dString = ""; return dString.concat(fd[1], fd[2], fd[3], "_", fd[4], fd[5], fd[6]); } else { return null; } }; var date_to_dString = function(inpDate){ var year = inpDate.getFullYear().pad(4); var month = (inpDate.getMonth() + 1).pad(2); var day = inpDate.getDate().pad(2); var hour = inpDate.getHours().pad(2); var min = inpDate.getMinutes().pad(2); var sec = inpDate.getSeconds().pad(2); return "".concat(year, month, day, "_", hour, min, sec); }; var mysqlDate = function(d){ var year = d.getFullYear().pad(4); var month = (d.getMonth() + 1).pad(2); var day = d.getDate().pad(2); var hour = d.getHours().pad(2); var min = d.getMinutes().pad(2); var sec = d.getSeconds().pad(2); return "".concat(year, "-", month, "-", day, " ", hour, ":", min, ":", sec); }; poconsole.factory('Page', function($log) { var title = 'default'; var page = 'default'; return { title: function() { return title; }, setTitle: function(newTitle) { title = newTitle; }, page: function() { return page; }, setPage: function(newPage) { page = newPage; } }; }); poconsole.factory('tags',function($q, $http, $log){ var getTag = function(id) { var deferred = $q.defer(); var w ={"where":{"id":id}}; $http.get('/tag', {params:w}).success(function(data) { deferred.resolve({ tag:data }); }); return deferred.promise; }; var getTagList = function() { var deferred = $q.defer(); $http.get('/tag').success(function(data) { deferred.resolve({ tags:data }); }); return deferred.promise; }; var getDataTypes = function() { var deferred = $q.defer(); $http.get('/data_type').success(function(data) { deferred.resolve({ data_types:data }); }); return deferred.promise; }; var getTagHistoryBetween = function(id, start, end){ var deferred = $q.defer(); var w = {'where':{'tagID': id, 'createdAt': {">":mysqlDate(start), "<": mysqlDate(end)}}}; $http.get("/tag_val", {params:w}).success(function(data) { deferred.resolve({ vals:data }); }); return deferred.promise; }; var getCurrentValues = function(){ var deferred = $q.defer(); $http.get('/tag_val/latest').success(function(data) { deferred.resolve({ vals:data }); }); return deferred.promise; }; var createTag = function(tag){ $http.post('/tag/create', { tag: tag.tag, name: tag.name, tag_class:5, deviceID: tag.deviceID, units: tag.units, minExpected: tag.minExpected, maxExpected: tag.maxExpected, guarantee_sec: tag.guarantee_sec, change_threshold: tag.change_threshold, description: tag.description, data_type: tag.data_type }).success(function(data){ return data; }); }; var updateTag = function(tag){ $log.info("updateTag called with "+ JSON.stringify(tag)); $http.post('/tag/update/'+ tag.id, { tag: tag.tag, name: tag.name, tag_class:5, deviceID: tag.deviceID, units: tag.units, minExpected: tag.minExpected, maxExpected: tag.maxExpected, guarantee_sec: tag.guarantee_sec, change_threshold: tag.change_threshold, description: tag.description, data_type: tag.data_type }).success(function(data){ return data; }).error(function(err){ $log.warn("updateTag Error: " + err); }); }; var deleteTag = function(id){ var deferred = $q.defer(); var url = '/tag/' + id; $http.delete(url).success(function(data) { deferred.resolve({ data: data }); }); return deferred.promise; }; var clearSingleTagData = function(id){ var deferred = $q.defer(); var url = '/tag_val/clear/' + id; $http.get(url).success(function(data) { deferred.resolve({ status: data.status }); }); return deferred.promise; }; var clearAllTagData = function(){ var deferred = $q.defer(); var url = '/tag_val/clear/all'; $http.get(url).success(function(data) { deferred.resolve({ status: data.status }); }); return deferred.promise; }; return { getTag: getTag, getTagList: getTagList, getDataTypes: getDataTypes, getTagHistoryBetween: getTagHistoryBetween, getCurrentValues: getCurrentValues, createTag: createTag, updateTag: updateTag, deleteTag: deleteTag, clearSingleTagData: clearSingleTagData, clearAllTagData: clearAllTagData }; }); poconsole.factory('devices', function($q, $http, $log){ var getAllDevices = function(){ var deferred = $q.defer(); $http.get('/device').success(function(data) { deferred.resolve({ devices:data }); }); return deferred.promise; }; var getDevice = function(id){ var deferred = $q.defer(); $http.get('/device/'+ id).success(function(data) { deferred.resolve({ devices:data }); }); return deferred.promise; }; var addDevice = function(d){ $log.info(d); $http.post('/device/create', { address: d.address, device_type: d.device_type.id }).success(function(data){ return data; }); }; var updateDevice = function(d){ $http.post('/device/update/' + d.id, { address: d.address, device_type: d.device_type.id }).success(function(data){ return data; }); }; var deleteDevice = function(id){ var deferred = $q.defer(); var url = '/device/' + id; $http.delete(url).success(function(data) { deferred.resolve({ data:data }); }); return deferred.promise; }; var getDeviceTypes = function(){ var deferred = $q.defer(); $http.get('/device_type').success(function(data) { deferred.resolve({ device_types:data }); }); return deferred.promise; }; return { getAllDevices : getAllDevices, getDevice: getDevice, addDevice: addDevice, deleteDevice: deleteDevice, updateDevice: updateDevice, getDeviceTypes: getDeviceTypes }; }); poconsole.factory('config',function($q, $http, $log){ var getConfig = function(){ var deferred = $q.defer(); $http.get('/config').success(function(data) { deferred.resolve({ config:data }); }); return deferred.promise; }; var submitParameter = function(entry){ $http.post('/config', { parameter: entry.parameter, val: entry.val }).success(function(data){ return data; }); }; var updateParameter = function(entry){ $http.post('/config/update/' + entry.id, { parameter: entry.parameter, val: entry.val }).success(function(data){ return data; }); }; var deleteParameter = function(id){ $http.delete('/config/' + id).success(function(data){ return data; }); }; var getLoggerStatus = function(){ var deferred = $q.defer(); $http.get('/json/logger/status').success(function(data) { if(data.status == "OK"){ deferred.resolve({ running:data.running, status: data.status }); } else { deferred.resolve({ status:data.status, message: data.message, }); } }); return deferred.promise; }; var restartLogger = function(){ var deferred = $q.defer(); $http.get('/json/logger/restart').success(function(data) { if(data.status == "OK"){ deferred.resolve({ status: data.status }); } else { deferred.resolve({ status:data.status, message: data.message }); } }); return deferred.promise; }; return { getConfig:getConfig, submitParameter: submitParameter, getLoggerStatus: getLoggerStatus, restartLogger: restartLogger, updateParameter: updateParameter, deleteParameter: deleteParameter }; }); poconsole.controller('mainCtrl', function($scope, Page) { $scope.Page = Page; }); poconsole.controller('dashboardCtrl', function($scope, $route, $http, $sails, Page, $log, tags) { Page.setTitle('Dashboard'); Page.setPage('dashboard'); $scope.loadDashboard = function(){ $scope.loading = true; var getCurrentValues = tags.getCurrentValues(); getCurrentValues.then(function(data) { $scope.loading = false; $scope.vals = data.vals; $log.info($scope.vals); }); }; $scope.loadDashboard(); $sails.get("/tag_val").success(function(data, status, headers, jwr){ $log.info(data); }); var valHandler = $sails.on('tag_val', function(message){ if (message.verb === "created"){ $log.info(message.data); for(var i = 0; i < $scope.vals.length; i++){ if(message.data.tagID == $scope.vals[i].t_id){ $scope.vals[i].val = message.data.val; $scope.vals[i].dtime = message.data.createdAt; } } } }); $scope.$on('$destroy', function() { $sails.off('tag_val', valHandler); }); }); poconsole.controller('tagsCtrl', function($scope, $route, $http, $routeParams, Page, $log, tags, devices) { Page.setTitle('Tags'); Page.setPage('tags'); $scope.loadTagList = function(){ $scope.loading = true; var getTagList = tags.getTagList(); getTagList.then(function(data) { $scope.loading = false; $scope.tags = data.tags; }); }; $scope.loadTagList(); var getDataTypes = tags.getDataTypes(); getDataTypes.then(function(d){ $scope.data_types = d.data_types; }); var getAllDevices = devices.getAllDevices(); getAllDevices.then(function(d){ $scope.devices = d.devices; }); $scope.submitAddTag = function(){ var createStatus = tags.createTag($scope.newTag); $scope.createStatus = createStatus.status; $scope.loadTagList(); }; $scope.openDeleteTag = function(id){ var getTag = tags.getTag(id); getTag.then(function(data){ $scope.error = false; $scope.dTag = data.tag; $log.info("Thinking about deleting tag with parameters: "+ JSON.stringify($scope.dTag)); }); }; $scope.deleteTag = function(id){ var deleteTag = tags.deleteTag(id); deleteTag.then(function(data){ $log.info("deleting tag "+ id + " status: " + data.status); $scope.error = false; $scope.loadTagList(); }); }; $scope.openClearTagData = function(id){ var getTag = tags.getTag(id); getTag.then(function(data){ $scope.error = false; $scope.dTagValues = data.tag; $log.info("Thinking about deleting tag data with parameters: "+ JSON.stringify($scope.dTagValues)); }); }; $scope.deleteTagValues = function(id){ var clearSingleTagData = tags.clearSingleTagData(id); clearSingleTagData.then(function(data){ $log.info("deleting tag "+ id + " status: " + data.status); $scope.error = false; $scope.loadTagList(); }); }; $scope.openEditTag = function(id){ var getTag = tags.getTag(id); getTag.then(function(data){ $scope.error = false; $scope.editTag = data.tag[0]; $log.info("Started editing tag with parameters: "+ JSON.stringify($scope.editTag)); }); }; $scope.submitEditTag = function(){ var editStatus = tags.updateTag($scope.editTag); $log.info(editStatus); $scope.editStatus = editStatus.status; $scope.loadTagList(); }; $scope.getPlotTags = function(){ var tags_to_plot = []; for(var i =0; i<$scope.tags.length; i ++){ if ($scope.tags[i].selectedForPlot){ tags_to_plot.push($scope.tags[i].id); } } $scope.tags_to_plot = tags_to_plot.join(); }; }); poconsole.controller('tagValsCtrl', function($scope, $route, $http, $routeParams, Page, $log, tags) { Page.setTitle('Tag Series'); Page.setPage('tags'); if ($routeParams.endDatetime){ $scope.endDatetime = Date.parse(dString_to_sqlite($routeParams.endDatetime)); } else { $scope.endDatetime = new Date(); } if ($routeParams.startDatetime){ $scope.startDatetime = Date.parse(dString_to_sqlite($routeParams.startDatetime)); } else { $scope.startDatetime = new Date(); $scope.startDatetime.setHours($scope.endDatetime.getHours() - 2); } $log.info({start: $scope.startDatetime, end:$scope.endDatetime}); $scope.loadTagVals = function(sDTime, eDTime){ $scope.loading = true; var tags_to_get = $routeParams.tagID.split(","); var getTag = tags.getTag(tags_to_get); $scope.tags_to_get = tags_to_get.toString(); getTag.then(function(tagData){ $scope.tag = tagData.tag; var getTagHistoryBetween = tags.getTagHistoryBetween(tags_to_get, sDTime, eDTime); getTagHistoryBetween.then(function(data) { $scope.loading = false; $scope.data = data; $scope.table_vals = $scope.data.vals.map(function(x){ var ob = {id: x.id, tagID: x.tagID, dtime: new Date(x.createdAt)}; for(var t = 0; t< $scope.tag.length; t++){ if ($scope.tag[t].name === x.tagID.name){ ob[$scope.tag[t].name] = x.val; } else { ob[$scope.tag[t].name] = null; } } return ob; }); var split_vals = {}; var all_datetimes = []; for(var t=0; t< $scope.tag.length; t++){ split_vals[$scope.tag[t].name] = {}; split_vals[$scope.tag[t].name].dtimes = []; split_vals[$scope.tag[t].name].vals = []; split_vals[$scope.tag[t].name].ob = {}; } for (var i = 0; i< data.vals.length; i++){ split_vals[data.vals[i].tagID.name].ob[data.vals[i].createdAt]= data.vals[i].val; split_vals[data.vals[i].tagID.name].dtimes.push(data.vals[i].createdAt); split_vals[data.vals[i].tagID.name].vals.push(data.vals[i].val); if (all_datetimes.indexOf(data.vals[i].createdAt) == -1){ all_datetimes.push(data.vals[i].createdAt); } } $scope.data.vals = [{dtime:new Date(all_datetimes[0])}]; for (var ta in split_vals){ $scope.data.vals[0][ta] = split_vals[ta].vals[0]; } for (var j = 0; j < all_datetimes.length; j++){ var newOb = {dtime: new Date(all_datetimes[j])}; for(var tag in split_vals){ if(split_vals[tag].ob[all_datetimes[j]] === undefined){ newOb[tag] = $scope.data.vals[j][tag]; } else { newOb[tag] = split_vals[tag].ob[all_datetimes[j]]; } } $scope.data.vals.push(newOb); } $scope.error = false; $scope.options = { series: [ ], axes: { x: { key: "dtime", type: "date" } } }; for(var i2 = 0; i2< $scope.tag.length; i2++){ $scope.options.series.push({ axis: "y", dataset: "vals", key: $scope.tag[i2].name, label: $scope.tag[i2].name, // color: "#1f77b4", color: colors[i2 % colors.length], type: ['line'], drawDots:false }); } }); }); }; $scope.loadTagVals($scope.startDatetime, $scope.endDatetime); }); poconsole.controller('configCtrl', function($scope, Page, $log, config, devices) { Page.setTitle('Configuration'); Page.setPage('configuration'); $scope.loadConfig = function(){ $scope.loading = true; var getConfig = config.getConfig(); getConfig.then(function(data) { $scope.loading = false; $scope.config = data.config; }); }; $scope.loadConfig(); $scope.paramError = null; var selString = "Select a parameter..."; $scope.newParam = { pSelected: selString, parameter: null, val: null }; $scope.addParameter = function(){ if ($scope.newParam.pSelected == selString){ $scope.paramError = "No parameter selected"; } else { if ($scope.newParam.pSelected == "other") { $scope.newParam.parameter = $scope.newParam.pEntry; } else { $scope.newParam.parameter = $scope.newParam.pSelected; } config.submitParameter($scope.newParam); $scope.loadConfig(); } }; $scope.checkLogger = function(){ $scope.loggerLoading = true; var checkLoggerStatus = config.getLoggerStatus(); checkLoggerStatus.then(function(data){ $scope.loggerLoading = false; if (data.status == "OK"){ $scope.loggerRunning = data.running; $scope.error = false; } else { $scope.error = data.message; } }); }; // $scope.checkLogger(); $scope.restartLogger = function(){ var restartLogger = config.restartLogger(); restartLogger.then(function(data){ if (data.status == "OK"){ $scope.error = false; $scope.checkLogger(); } else { $scope.error = data.message; } }); }; $scope.getDevices = function(){ var getDevices = devices.getAllDevices(); getDevices.then(function(d){ $scope.devices = d.devices; }); }; $scope.getDevices(); $scope.addDevice = function(dev){ var addDevice = devices.addDevice(dev); getDevices.then(function(d){ $scope.getDevices(); }); }; var getDeviceTypes = devices.getDeviceTypes(); getDeviceTypes.then(function(d){ $scope.device_types = d.device_types; }); }); //*---- FILTERS -----*// poconsole.filter('dString', function myDateFormat($filter){ return function(text){ var tempdate= new Date(text); return $filter('date')(tempdate, "yyyyMMdd'_'HHmmss"); }; }); poconsole.filter('sqlite_to_local', function sqliteformat($filter){ return function(text){ var utcdate= new Date(text + " UTC"); return $filter('date')(utcdate, "yyyy-MM-dd hh:mm:ss a"); }; });