From 28d3717c7b80e53ba7fa8745895ff4ecaecfe5e2 Mon Sep 17 00:00:00 2001 From: grant523 Date: Mon, 4 Jun 2018 18:27:59 -0700 Subject: [PATCH 1/7] live data --- seadssite/static/css/myapp.css | 3 +- seadssite/static/js/areaspline.js | 18 +- seadssite/static/js/bar.js | 62 +- seadssite/static/js/device.js | 1528 +++++++++++++++-------------- seadssite/templates/device.html | 3 + 5 files changed, 844 insertions(+), 770 deletions(-) diff --git a/seadssite/static/css/myapp.css b/seadssite/static/css/myapp.css index 9bdd65f..b86835d 100644 --- a/seadssite/static/css/myapp.css +++ b/seadssite/static/css/myapp.css @@ -201,7 +201,8 @@ body { height: 473px; } .module-wrap .module3 { - width: 31%; + margin-right: -20px; + width: 34%; height: 473px; } diff --git a/seadssite/static/js/areaspline.js b/seadssite/static/js/areaspline.js index 660152d..19b3409 100644 --- a/seadssite/static/js/areaspline.js +++ b/seadssite/static/js/areaspline.js @@ -1,4 +1,10 @@ -var areaspline = function (room, mod_i, payload) { +var areaspline = function (room, mod_i) { + Highcharts.setOptions({ + global: { + useUTC: false + } + }) + room.modules[mod_i].chart = Highcharts.chart(room.modules[mod_i].el_id, { chart: { type: 'areaspline', @@ -20,7 +26,8 @@ var areaspline = function (room, mod_i, payload) { xAxis: { type: 'datetime', dateTimeLabelFormats: { - day: '%b %e' + day: '%b %e', + hour: '%I:%M' } }, yAxis: { @@ -30,7 +37,7 @@ var areaspline = function (room, mod_i, payload) { }, tooltip: { valueSuffix: ' kWh', - valueDecimals: 3, + //valueDecimals: 3, shared: true }, credits: { @@ -38,9 +45,10 @@ var areaspline = function (room, mod_i, payload) { }, plotOptions: { areaspline: { - fillOpacity: 0.8 + fillOpacity: 0.6 } }, - series: payload + series: {} }); + room.modules[mod_i].chart.showLoading(); } diff --git a/seadssite/static/js/bar.js b/seadssite/static/js/bar.js index 1082f9c..b4c68f1 100644 --- a/seadssite/static/js/bar.js +++ b/seadssite/static/js/bar.js @@ -1,4 +1,10 @@ -var bar = function(room, mod_i, categories, payload) { +var bar = function (room, mod_i) { + var categories = []; + var month = moment().month() + 1; + for (var i = 0; i < 12; i++) { + categories.push(moment().month(month).format('MMMM')); + month = (month + 1) % 12; + } room.modules[mod_i].chart = Highcharts.chart(room.modules[mod_i].el_id, { chart: { type: 'column', @@ -14,7 +20,7 @@ var bar = function(room, mod_i, categories, payload) { yAxis: { min: 0, title: { - text: 'Electricity (kWh)' + text: 'kWh' } }, tooltip: { @@ -28,55 +34,7 @@ var bar = function(room, mod_i, categories, payload) { borderWidth: 0 } }, - series: payload, - // exporting: { - // buttons: { - // customButton: { - // x: 0, - // onclick: function() { - // this.update({ - // chart: { - // inverted: false, - // polar: false, - // }, - // subtitle: {} - // }); - // }, - // symbol: 'circle', - // text: 'Standard', - // }, - // customButton1: { - // x: 0, - // y: 30, - // onclick: function() { - // this.update({ - // chart: { - // inverted: true, - // polar: false, - // }, - // subtitle: {} - // }); - // }, - // symbol: 'circle', - // text: 'Inverted', - // }, - // customButton2: { - // x: 0, - // y: 60, - // onclick: function() { - // this.update({ - // chart: { - // inverted: false, - // polar: true, - // }, - // subtitle: {} - // }); - // }, - // symbol: 'circle', - // text: 'Polar', - // }, - // } - // - // } + series: {} }); + room.modules[mod_i].chart.showLoading(); } diff --git a/seadssite/static/js/device.js b/seadssite/static/js/device.js index 85c3640..c130d9d 100644 --- a/seadssite/static/js/device.js +++ b/seadssite/static/js/device.js @@ -1,659 +1,753 @@ +var liveTimer; + var app = function () { - var self = {}; + var self = {}; - Vue.config.silent = false; // show all warnings + Vue.config.silent = false; // show all warnings - var enumerate = function (v) { - var k = 0; - return v.map(function (e) { - e._idx = k++; - }); - }; + var enumerate = function (v) { + var k = 0; + return v.map(function (e) { + e._idx = k++; + }); + }; - var new_id = function () { - self.vue.id_tracker += 1; - return String(self.vue.id_tracker); - }; + var new_id = function () { + self.vue.id_tracker += 1; + return String(self.vue.id_tracker); + }; - var editing_room = function () { - self.vue.modal_room_name = self.vue.rooms[self.vue.action_room].name; - self.vue.modal_chosen_icon_path = self.vue.rooms[self.vue.action_room].icon_path; - }; + var editing_room = function () { + self.vue.modal_room_name = self.vue.rooms[self.vue.action_room].name; + self.vue.modal_chosen_icon_path = self.vue.rooms[self.vue.action_room].icon_path; + }; - var default_room_name = function (path) { - var dirname = path.substring(path.lastIndexOf("/") + 1); - dirname = dirname.substring(0, dirname.lastIndexOf(".")).capitalize(); - return dirname; - }; + var default_room_name = function (path) { + var dirname = path.substring(path.lastIndexOf("/") + 1); + dirname = dirname.substring(0, dirname.lastIndexOf(".")).capitalize(); + return dirname; + }; - String.prototype.capitalize = function () { - return this.charAt(0).toUpperCase() + this.slice(1); - }; + String.prototype.capitalize = function () { + return this.charAt(0).toUpperCase() + this.slice(1); + }; - //-----------------init----------------- - var modal_event_init = function () { - console.log("modal event inited"); - $(function () { // after all dom elements are loaded + //-----------------init----------------- + var modal_event_init = function () { + console.log("modal event inited"); + $(function () { // after all dom elements are loaded - var add_room_modal = $("#add-room-modal"); + var add_room_modal = $("#add-room-modal"); - add_room_modal.on("shown.bs.modal", function (w) { - $("#modal-input").focus(); - }); + add_room_modal.on("shown.bs.modal", function (w) { + $("#modal-input").focus(); + }); - add_room_modal.on("hidden.bs.modal", function (e) { - self.modal_reinit(); - }); + add_room_modal.on("hidden.bs.modal", function (e) { + self.modal_reinit(); + }); - var del_room_modal = $("#del-room-modal"); - // console.log(del_room_modal); - del_room_modal.on("show.bs.modal", function (w) { - console.log("modal2"); - $('.del-room-list').first().addClass('disabled'); + var del_room_modal = $("#del-room-modal"); + // console.log(del_room_modal); + del_room_modal.on("show.bs.modal", function (w) { + console.log("modal2"); + $('.del-room-list').first().addClass('disabled'); + }); }); - }); - }; - - function date_picker() { - var start = moment().subtract(7, 'days'); - var end = moment(); - - function cb(start, end) { - $('#reportrange span').html(start.format('MMMM D, YYYY') + ' - ' + end.format('MMMM D, YYYY')); - self.vue.start_date = Math.floor(start / 1000); - self.vue.end_date = Math.floor(end / 1000); - console.log(moment.unix(self.vue.start_date).format("MM/DD/YYYY h:mm a") + " to " + moment.unix(self.vue.end_date).format("MM/DD/YYYY h:mm a")); - refresh_data(); - self.create_chart(self.vue.action_room, 0); - } + }; - $('#reportrange').daterangepicker({ - dateLimit: { - "months": 1, - }, - startDate: start, - endDate: end, - ranges: { - 'Today': [moment(), moment()], - 'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')], - 'Last 7 Days': [moment().subtract(6, 'days'), moment()], - 'Last 30 Days': [moment().subtract(29, 'days'), moment()], - 'This Month': [moment().startOf('month'), moment()], - 'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')] + function date_picker() { + var start = moment().subtract(7, 'days'); + var end = moment(); + + function cb(start, end) { + $('#reportrange span').html(start.format('MMMM D, YYYY') + ' - ' + end.format('MMMM D, YYYY')); + self.vue.start_date = Math.floor(start / 1000); + self.vue.end_date = Math.floor(end / 1000); + console.log(moment.unix(self.vue.start_date).format("MM/DD/YYYY h:mm a") + " to " + moment.unix(self.vue.end_date).format("MM/DD/YYYY h:mm a")); + refresh_data(); + self.create_chart(self.vue.action_room, 0); } - }, cb); - cb(start, end); - } + $('#reportrange').daterangepicker({ + dateLimit: { + "months": 1, + }, + startDate: start, + endDate: end, + ranges: { + 'Today': [moment(), moment()], + 'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')], + 'Last 7 Days': [moment().subtract(6, 'days'), moment()], + 'Last 30 Days': [moment().subtract(29, 'days'), moment()], + 'This Month': [moment().startOf('month'), moment()], + 'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')] + } + }, cb); - // Generates a power data structure and generates monthly power usage data for each appliance - function init_data() { - Object.keys(device.rooms).forEach(function (room) { - Object.keys(device.rooms[room].appliances).forEach(function (appliance) { - var appl_id = device.rooms[room].appliances[appliance].id; - self.vue.power_data[appl_id] = { - name: appliance, - monthly_data: gen_monthly_appl_data(self.vue.device_id, appliance, appl_id), - data: undefined, - }; - }); - }); - } + cb(start, end); + } - // Refreshes saved power data based on current start and end date - function refresh_data() { - console.log("refresh_data"); - Object.keys(self.vue.power_data).forEach(function (appl_id) { - self.vue.power_data[appl_id].data = gen_cont_appl_data(self.vue.device_id, self.vue.power_data[appl_id].name, - appl_id, self.vue.start_date, self.vue.end_date, 30); - }); - } + // Generates a power data structure and generates monthly power usage data for each appliance + function init_data() { + Object.keys(device.rooms).forEach(function (room) { + Object.keys(device.rooms[room].appliances).forEach(function (appliance) { + var appl_id = device.rooms[room].appliances[appliance].id; + self.vue.power_data[appl_id] = { + name: appliance, + monthly_data: gen_monthly_appl_data(self.vue.device_id, appliance, appl_id), + data: undefined, + }; + }); + }); + } - var init_home = function () { - for (var i = 0; i < self.vue.rooms[0].modules.length; i++) { - self.create_chart(0, i); + // Refreshes saved power data based on current start and end date + function refresh_data() { + console.log("refresh_data"); + Object.keys(self.vue.power_data).forEach(function (appl_id) { + self.vue.power_data[appl_id].data = gen_cont_appl_data(self.vue.device_id, self.vue.power_data[appl_id].name, + appl_id, self.vue.start_date, self.vue.end_date, 30); + }); } - } - var init_rooms = function () { - var rooms = self.vue.room_structure.rooms; - Object.keys(rooms).forEach(function (room_name) { - var room = rooms[room_name]; - self.vue.modal_chosen_icon_path = img_path + "/" + room.icon + ".png"; - self.vue.modal_room_name = room_name; - self.vue.modal_appliances = room.appliances; - self.vue.add_room(); + var init_rooms = function () { + var rooms = self.vue.room_structure.rooms; + Object.keys(rooms).forEach(function (room_name) { + var room = rooms[room_name]; + self.vue.modal_chosen_icon_path = img_path + "/" + room.icon + ".png"; + self.vue.modal_room_name = room_name; + self.vue.modal_appliances = room.appliances; + self.vue.add_room(); + self.modal_reinit(); + }); + enumerate(self.vue.rooms); self.modal_reinit(); - }); - enumerate(self.vue.rooms); - self.modal_reinit(); - self.manage_btn_toggle(0); - self.vue.isInitialized = true; - } + self.manage_btn_toggle(0); + self.vue.isInitialized = true; + } - // Generates monthly usage of specified panel for the last 12 months - function gen_monthly_appl_data(device_id, appl_name, appl_id) { - var result = []; + // Creates empty charts for the specified room + var init_charts = function (room_i) { + for (var i = 0; i < self.vue.rooms[room_i].modules.length; i++) { + self.create_chart(room_i, i); + } + self.vue.rooms[room_i].initialized = true; + } + + + //function gen_series_data() + + // Returns a request URL + // Overloaded such that if only two arguments are provided, it creates a URL for requesting cumulative usage + // up to a specified time - this is used for calculating power usage over a period of time + // Otherwise it creates a URL for requesting continuous usage data over a specified period of time, with ~data_points + // number of data points + function create_url(appliance_id, start, end, data_points) { + var url = "http://db.sead.systems:8080/" + device_id + "?type=P" + "&device=" + appliance_id + "&start_time=" + start; + if (arguments.length == 2) + url += "&end_time=" + start; + else + url += "&end_time=" + end + "&list_format=energy&granularity=" + Math.floor((end - start) / data_points); + return url; + } - var points = []; - var start = moment().subtract(12, "months").startOf("month"); - var end = moment().subtract(5, "minutes"); - var time; - for (var i = 0; i <= 12; i++) { - time = Math.floor(start / 1000); + // Performs GET request for specified API call + function fetch_data(url, callback) { + console.log(url); $.ajax({ - url: "http://db.sead.systems:8080/" + device_id + "?start_time=" + time + "&end_time=" + time + "&device=" + appl_id + "&type=P", + url: url, dataType: 'json', - async: false, - success: function (data_test) { - points.push(data_test[1]); + success: function (response) { + callback(response); } }); - if (i >= 11) - start = end; - else - start.add(1, "month"); - } - - for (var i = 1; i < points.length; i++) { - if (points[i] !== undefined && points[i - 1] !== undefined) { - result.push( - Math.abs((points[i - 1][1] - points[i][1]) / 3600000) - ) - } else - result.push(null); } - return result; - } - - // Generates continous power usage data for the specified parameters - function gen_cont_appl_data(device_id, name, appliance_id, start, end, data_points) { - var granularity = Math.floor((end - start) / data_points); - - var result = []; - $.ajax({ - url: "http://db.sead.systems:8080/" + device_id + "?start_time=" + start + "&end_time=" + end + - "&list_format=energy&type=P&device=" + appliance_id + "&granularity=" + granularity, - dataType: 'json', - async: false, - success: function (response) { - result = Object.keys(response.data).reverse().map(function (key) { - return [moment(response.data[key]["time"], "YYYY-MM-DD HH:mm:ss").valueOf(), parseFloat(response.data[key]["energy"])]; - }) - } - }); - return result; - } - - // Generates areaspline graph for the specified room - function gen_line_chart(room_i, mod_i) { - var payload = []; - var appliances; - var temp = []; - if (room_i == 0) { - var appl_data; - for (var i = 1; i < self.vue.rooms.length; i++) { - appliances = self.vue.rooms[i].appliances; - Object.keys(appliances).forEach(function (key, index) { - appl_data = self.vue.power_data[appliances[key].id].data; - for (var j = 0; j < appl_data.length; j++) { - if (index == 0) - temp[j] = appl_data[j].slice(0); - else - temp[j][1] = temp[j][1] + appl_data[j][1]; - } - }); - payload.push({ - name: self.vue.rooms[i].name, - data: temp - }); - temp = []; - } - } else { + // Creates empty series for the appliances of the specified room and chart + function create_series(room_i, mod_i) { + var chart = self.vue.rooms[room_i].modules[mod_i].chart; + var appliances; + + // if (room_i == 0) { + // for (var i = 1; i < self.vue.rooms.length; i++) { + // chart.addSeries({ + // id: self.vue.rooms[i].name, + // name: self.vue.rooms[i].name, + // data: [1, 2, 3] + // }) + // } + // } else { appliances = self.vue.rooms[room_i].appliances; Object.keys(appliances).forEach(function (key) { - payload.push({ + chart.addSeries({ + id: appliances[key].id, name: key, - data: self.vue.power_data[appliances[key].id].data, + data: [] }); }); + // } + } + + function update_areaspline(room_i, mod_i, start, end, data_points) { + var chart = self.vue.rooms[room_i].modules[mod_i].chart; + chart.series.forEach(function (series) { + fetch_data(create_url(series.options.id, start, end, data_points), function (response) { + var temp = Object.keys(response.data).reverse().map(function (key) { + return [moment(response.data[key].time, "YYYY-MM-DD HH:mm:ss").valueOf(), parseFloat(response.data[key].energy) * 1000]; + }); + chart.get(series.options.id).update({ + data: temp + }) + }); + }); + chart.hideLoading(); } - areaspline(self.vue.rooms[room_i], mod_i, payload); - } - // Generates bar chart for specified room - function gen_bar_chart(room_i, mod_i) { - var categories = []; - var month = moment().month() + 1; - for (var i = 0; i < 12; i++) { - categories.push(moment().month(month).format('MMMM')); - month = (month + 1) % 12; + function helper(appliances, index, start, end, data_points, data) { + fetch_data(create_url(appliances[index].id, start, end, data_points), function (response) { + var temp = Object.keys(response.data).reverse().map(function (key) { + return [moment(response.data[key].time, "YYYY-MM-DD HH:mm:ss").valueOf(), parseFloat(response.data[key].energy)]; + }); + console.log(appliances[index].id, temp); + if (data.length == 0) { + console.log("empty"); + for (var j = 0; j < temp.length; j++) { + data.push(temp[j].slice(0)); + } + } else { + console.log("not empty", data, temp); + for (var j = 0; j < temp.length; j++) { + data[j][1] = data[j][1] + temp[j][1]; + } + } + console.log("updated to", data); + if (index != appliances.length - 1) + helper(appliances, index + 1, start, end, data_points, temp, data); + else + return data; + }); } - var payload = []; - var appliances; - if (room_i == 0) { - var temp = []; - var appl_data; + + function update_areaspline_home(room_i, mod_i, start, end, data_points) { + var chart = self.vue.rooms[room_i].modules[mod_i].chart; + var appliances = self.vue.rooms[room_i].appliances; + console.log("areaspline"); + var data = []; for (var i = 1; i < self.vue.rooms.length; i++) { - appliances = self.vue.rooms[i].appliances; - Object.keys(appliances).forEach(function (key, index) { - appl_data = self.vue.power_data[appliances[key].id].monthly_data; - if (index == 0) - temp = appl_data.slice(); - else { - for (var j = 0; j < appl_data.length; j++) { - if (appl_data[j] != null) - temp[j] += appl_data[j]; - } + console.log("helper", self.vue.rooms[i].name); + var test = helper(Object.values(appliances), 0, start, end, data_points, data); + console.log(test); + + } + + chart.hideLoading(); + } + + function live_data(room_i, mod_i) { + liveTimer = setInterval(function x() { + console.log("updating chart"); + var end = Math.floor(Date.now() / 1000); + var start = end - 600; + update_areaspline(room_i, mod_i, start, end, 60); + return x; + }(), 20000); + } + +// Generates monthly usage of specified panel for the last 12 months + function gen_monthly_appl_data(device_id, appl_name, appl_id) { + var result = []; + + var points = []; + var start = moment().subtract(12, "months").startOf("month"); + var end = moment().subtract(5, "minutes"); + var time; + for (var i = 0; i <= 12; i++) { + time = Math.floor(start / 1000); + $.ajax({ + url: "http://db.sead.systems:8080/" + device_id + "?start_time=" + time + "&end_time=" + time + "&device=" + appl_id + "&type=P", + dataType: 'json', + async: false, + success: function (data_test) { + points.push(data_test[1]); } }); - payload.push({ - name: self.vue.rooms[i].name, - data: temp - }) + if (i >= 11) + start = end; + else + start.add(1, "month"); } - } else { - appliances = self.vue.rooms[room_i].appliances; - Object.keys(appliances).forEach(function (key) { - payload.push({ - name: key, - data: self.vue.power_data[appliances[key].id].monthly_data - }); + + for (var i = 1; i < points.length; i++) { + if (points[i] !== undefined && points[i - 1] !== undefined) { + result.push( + Math.abs((points[i - 1][1] - points[i][1]) / 3600000) + ) + } else + result.push(null); + } + return result; + } + +// Generates continous power usage data for the specified parameters + function gen_cont_appl_data(device_id, name, appliance_id, start, end, data_points) { + var granularity = Math.floor((end - start) / data_points); + + console.log("http://db.sead.systems:8080/" + device_id + "?start_time=" + start + "&end_time=" + end + + "&list_format=energy&type=P&device=" + appliance_id + "&granularity=" + granularity); + + var result = []; + $.ajax({ + url: "http://db.sead.systems:8080/" + device_id + "?start_time=" + start + "&end_time=" + end + + "&list_format=energy&type=P&device=" + appliance_id + "&granularity=" + granularity, + dataType: 'json', + async: false, + success: function (response) { + result = Object.keys(response.data).reverse().map(function (key) { + return [moment(response.data[key]["time"], "YYYY-MM-DD HH:mm:ss").valueOf(), parseFloat(response.data[key]["energy"])]; + }) + } }); + console.log(result); + return result; } - bar(self.vue.rooms[room_i], mod_i, categories, payload); - } - self.modal_reinit = function () { - self.vue.modal_room_name = ''; - self.vue.modal_chosen_icon_path = self.vue.default_icon_path; - } - self.adding_editing_room = function (action) { - // console.log('adding_editing_room'); - if (action == 'edit') { - self.vue.adding_room = false; - editing_room(); - } else if (action == 'add') { - self.vue.adding_room = true; - } else { - console.log('error adding_editing_room'); +// Generates bar chart for specified room + function gen_bar_chart(room_i, mod_i) { + var categories = []; + var month = moment().month() + 1; + for (var i = 0; i < 12; i++) { + categories.push(moment().month(month).format('MMMM')); + month = (month + 1) % 12; + } + + var payload = []; + var appliances; + if (room_i == 0) { + var temp = []; + var appl_data; + for (var i = 1; i < self.vue.rooms.length; i++) { + appliances = self.vue.rooms[i].appliances; + Object.keys(appliances).forEach(function (key, index) { + appl_data = self.vue.power_data[appliances[key].id].monthly_data; + if (index == 0) + temp = appl_data.slice(); + else { + for (var j = 0; j < appl_data.length; j++) { + if (appl_data[j] != null) + temp[j] += appl_data[j]; + } + } + }); + payload.push({ + name: self.vue.rooms[i].name, + data: temp + }) + } + } else { + appliances = self.vue.rooms[room_i].appliances; + Object.keys(appliances).forEach(function (key) { + payload.push({ + name: key, + data: self.vue.power_data[appliances[key].id].monthly_data + }); + }); + } + bar(self.vue.rooms[room_i], mod_i, categories, payload); + } + + self.modal_reinit = function () { + self.vue.modal_room_name = ''; + self.vue.modal_chosen_icon_path = self.vue.default_icon_path; } - } - self.add_edit_room_enter = function (action) { - // console.log('adding_editing_room'); - if (self.vue.adding_room) { - self.add_room(); - } else if (!self.vue.adding_room) { - self.edit_room(); - } else { - console.log('error adding_editing_room'); + self.adding_editing_room = function (action) { + // console.log('adding_editing_room'); + if (action == 'edit') { + self.vue.adding_room = false; + editing_room(); + } else if (action == 'add') { + self.vue.adding_room = true; + } else { + console.log('error adding_editing_room'); + } } - $('#add-room-modal').modal('hide'); - }; - - self.edit_room = function () { - // console.log('edit_room'); - var room = self.vue.rooms[self.vue.action_room]; - room.name = self.vue.modal_room_name; - room.icon_path = self.vue.modal_chosen_icon_path; - self.vue.icon_path = room.icon_path; - - // re-initialize - self.modal_reinit(); - } - self.add_room = function () { - var name = (self.vue.modal_room_name ? self.vue.modal_room_name : default_room_name(self.vue.modal_chosen_icon_path)); - var new_room = { - 'name': name, - '_idx': self.vue.rooms.length, - 'notice': 0, - 'data': [], - 'appliances': self.vue.modal_appliances, - 'modules': [], - 'isActive': false, - 'icon_path': self.vue.modal_chosen_icon_path, + self.add_edit_room_enter = function (action) { + // console.log('adding_editing_room'); + if (self.vue.adding_room) { + self.add_room(); + } else if (!self.vue.adding_room) { + self.edit_room(); + } else { + console.log('error adding_editing_room'); + } + $('#add-room-modal').modal('hide'); }; - var add_room_action = function () { - self.vue.rooms.push(new_room); - self.vue.action_room = self.vue.rooms.length - 1; - self.add_module(1, 'activity'); // number refers to module type - //self.add_module(3, 'devices'); - self.add_module(2, 'graph'); - self.add_module(3, 'consumption'); - //self.add_module(2, 'notification'); - if (self.vue.isInitialized) { - self.manage_btn_toggle(self.vue.rooms.length - 1); //set this to active (jump to this page) - } - enumerate(self.vue.rooms); + self.edit_room = function () { + // console.log('edit_room'); + var room = self.vue.rooms[self.vue.action_room]; + room.name = self.vue.modal_room_name; + room.icon_path = self.vue.modal_chosen_icon_path; + self.vue.icon_path = room.icon_path; + + // re-initialize + self.modal_reinit(); } - if (self.vue.isInitialized) { - var icon = self.vue.modal_chosen_icon_path.split('\\').pop().split('/').pop(); - icon = icon.substring(0, icon.length - 4); - console.log(icon); - self.vue.room_structure.rooms[name] = { - icon: icon + self.add_room = function () { + var name = (self.vue.modal_room_name ? self.vue.modal_room_name : default_room_name(self.vue.modal_chosen_icon_path)); + var new_room = { + 'name': name, + '_idx': self.vue.rooms.length, + 'notice': 0, + 'initialized': false, + 'data': [], + 'appliances': self.vue.modal_appliances, + 'modules': [], + 'isActive': false, + 'icon_path': self.vue.modal_chosen_icon_path, }; - $.post("/update_info/", - { - csrfmiddlewaretoken: self.vue.csrf_token, - device_id: self.vue.device_id, - data: JSON.stringify(self.vue.room_structure) - }, function () { - console.log('add room success'); - add_room_action(); - setTimeout(function () { - self.reload_room(new_room._idx); - }, 2); - } - ).fail( - function (response) { - alert('Error: ' + response.responseText); + + var add_room_action = function () { + self.vue.rooms.push(new_room); + self.vue.action_room = self.vue.rooms.length - 1; + self.add_module(1, 'activity'); // number refers to module type + //self.add_module(3, 'devices'); + self.add_module(2, 'graph'); + self.add_module(3, 'consumption'); + //self.add_module(2, 'notification'); + if (self.vue.isInitialized) { + self.manage_btn_toggle(self.vue.rooms.length - 1); //set this to active (jump to this page) } - ); - } else { - add_room_action(); - } + enumerate(self.vue.rooms); + } + + if (self.vue.isInitialized) { + var icon = self.vue.modal_chosen_icon_path.split('\\').pop().split('/').pop(); + icon = icon.substring(0, icon.length - 4); + console.log(icon); + self.vue.room_structure.rooms[name] = { + icon: icon + }; + $.post("/update_info/", + { + csrfmiddlewaretoken: self.vue.csrf_token, + device_id: self.vue.device_id, + data: JSON.stringify(self.vue.room_structure) + }, function () { + console.log('add room success'); + add_room_action(); + setTimeout(function () { + self.reload_room(new_room._idx); + }, 2); + } + ).fail( + function (response) { + alert('Error: ' + response.responseText); + } + ); + } else { + add_room_action(); + } - enumerate(self.vue.rooms); //just for check + enumerate(self.vue.rooms); //just for check - // re-initialize ( clear modal ) - self.modal_reinit(); - }; + // re-initialize ( clear modal ) + self.modal_reinit(); + }; - self.reload_house = function () { - console.log(self.vue.rooms.length) - for (var i = 0; i < self.vue.rooms.length; i++) { - console.log('here'); - self.reload_room(i); + self.reload_house = function () { + console.log(self.vue.rooms.length) + for (var i = 0; i < self.vue.rooms.length; i++) { + console.log('here'); + self.reload_room(i); + } } - } - self.reload_room = function (room_i) { - var room = self.vue.rooms[room_i]; - console.log('Reload Room ' + room.name); - for (var i = 0; i < room.modules.length; i++) { - self.reload_mod(room_i, i); + self.reload_room = function (room_i) { + var room = self.vue.rooms[room_i]; + console.log('Reload Room ' + room.name); + for (var i = 0; i < room.modules.length; i++) { + self.reload_mod(room_i, i); + } } - } - self.reload_mod = function (room_i, mod_i) { - var mod = self.vue.rooms[room_i].modules[mod_i]; - if (mod.chart != "") { - mod.chart.destroy(); - } else if (mod.header == "devices") { - $('#' + mod.el_id).empty(); + self.reload_mod = function (room_i, mod_i) { + var mod = self.vue.rooms[room_i].modules[mod_i]; + if (mod.chart != "") { + mod.chart.destroy(); + } else if (mod.header == "devices") { + $('#' + mod.el_id).empty(); + } + self.create_chart(room_i, mod_i); } - self.create_chart(room_i, mod_i); - } - var isSortInitialized = false; - - self.create_chart = function (room_i, mod_i) { - var mod = self.vue.rooms[room_i].modules[mod_i]; - if (mod.header == "activity") { - gen_line_chart(room_i, mod_i); - } else if (mod.header == "devices") { - $('#' + mod.el_id).empty(); - htmltag = gen_dev_list(room_i); - tmp = self.vue.rooms[room_i].modules[mod_i]; - $('#' + tmp.el_id).append("\ + var isSortInitialized = false; + + self.create_chart = function (room_i, mod_i) { + var mod = self.vue.rooms[room_i].modules[mod_i]; + if (mod.header == "activity") { + areaspline(self.vue.rooms[room_i], mod_i); + create_series(room_i, mod_i); + } else if (mod.header == "devices") { + $('#' + mod.el_id).empty(); + htmltag = gen_dev_list(room_i); + tmp = self.vue.rooms[room_i].modules[mod_i]; + $('#' + tmp.el_id).append("\
\
" - + htmltag + - "
\ -
\ - "); - } else if (mod.header == "graph") { - gen_bar_chart(room_i, mod_i); - } else if (mod.header == "consumption") { - gauge(self.vue.rooms[room_i], mod_i, self.vue.device_id); - } else if (mod.header == "notification") { - //gauge(self.vue.rooms[room_i], mod_i, self.vue.device_id); - } else if (mod.header == "Sort appliances") { - console.log("sort appliances"); - tmp = self.vue.rooms[room_i].modules[mod_i]; - console.log("tmpelid"); - console.log($('#' + tmp.el_id)); - if (!isSortInitialized) { - // construct string to contain individual divs - var sortAppliancesString = gen_application_sort_string(); - - $('#' + tmp.el_id).append(sortAppliancesString); - - isSortInitialized = true; + + htmltag + + "\ + \ + "); + } else if (mod.header == "graph") { + bar(self.vue.rooms[room_i], mod_i); + create_series(room_i, mod_i); + } else if (mod.header == "consumption") { + gauge(self.vue.rooms[room_i], mod_i, self.vue.device_id); + } else if (mod.header == "notification") { + //gauge(self.vue.rooms[room_i], mod_i, self.vue.device_id); + } else if (mod.header == "Sort appliances") { + tmp = self.vue.rooms[room_i].modules[mod_i]; + if (!isSortInitialized) { + // construct string to contain individual divs + var sortAppliancesString = gen_application_sort_string(); + + $('#' + tmp.el_id).append(sortAppliancesString); + + isSortInitialized = true; + } + } else { + console.log("create_chart() error: " + mod.header); } - } else { - console.log("create_chart() error: " + mod.header); } - } - // gen_application_sort_string() - // generates html to display the Sort Application module on the homepage - var gen_application_sort_string = function () { - - var sortAppliancesString = '
' + - ' ' + - ' '; - curDevice = self.vue.device_id; - - var rooms = device.rooms; - var roomIds = Object.keys(rooms); - var idIndex = 0; - for (var i = 0; i < roomIds.length; i++) { - var roomName = roomIds[i]; - var room = rooms[roomName]; - var appliancesKeys = Object.keys(room.appliances); // array of names of the appliances as shown to the user - var appliancesValues = Object.values(room.appliances); // array of objects containing id's of the appliances which is used to communicate with the SEADS db - console.log('---------'); - console.log(roomName); - // In this loop, inject the new div for another room-column container - sortAppliancesString = sortAppliancesString + - ' ' + - '
' + - '
' + - '
' + - '

' + roomName + '

' + - '
'; - - for (var appliancesIndex = 0; appliancesIndex < appliancesKeys.length; appliancesIndex++) { - idIndex++; +// gen_application_sort_string() +// generates html to display the Sort Application module on the homepage + var gen_application_sort_string = function () { + + var sortAppliancesString = '
' + + ' ' + + ' '; + curDevice = self.vue.device_id; + + var rooms = device.rooms; + var roomIds = Object.keys(rooms); + var idIndex = 0; + for (var i = 0; i < roomIds.length; i++) { + var roomName = roomIds[i]; + var room = rooms[roomName]; + var appliancesKeys = Object.keys(room.appliances); // array of names of the appliances as shown to the user + var appliancesValues = Object.values(room.appliances); // array of objects containing id's of the appliances which is used to communicate with the SEADS db + console.log('---------'); + console.log(roomName); + // In this loop, inject the new div for another room-column container + sortAppliancesString = sortAppliancesString + + ' '; } - // close the room-column-container and room-column div sortAppliancesString = sortAppliancesString + - ' ' + - ' ' + - ' '; + ' ' + + '
' + + '
' + + '
' + + '

' + roomName + '

' + + '
'; + + for (var appliancesIndex = 0; appliancesIndex < appliancesKeys.length; appliancesIndex++) { + idIndex++; + sortAppliancesString = sortAppliancesString + + '

' + appliancesKeys[appliancesIndex] + '

'; + } + // close the room-column-container and room-column div sortAppliancesString = sortAppliancesString + - '

' + appliancesKeys[appliancesIndex] + '

'; + '
' + + '
' + + '
' + + '
'; + return sortAppliancesString; + }; + + var gen_dev_list = function (room_i) { + appliances = self.vue.rooms[room_i].appliances; + + htmltag = ''; + for (var key in appliances) { + if (!appliances.hasOwnProperty(key)) + continue; + htmltag += '
  • '; + htmltag += '' + key + ''; + htmltag += '
  • '; + } + htmltag += '
    '; + return htmltag; } - sortAppliancesString = sortAppliancesString + - '
    ' + - '
    '; - return sortAppliancesString; - }; - - var gen_dev_list = function (room_i) { - appliances = self.vue.rooms[room_i].appliances; - - htmltag = ''; - for (var key in appliances) { - if (!appliances.hasOwnProperty(key)) - continue; - htmltag += '
  • '; - htmltag += '' + key + ''; - htmltag += '
  • '; + + self.add_module = function (type, header) { + // console.log('add_module'); + var room = self.vue.rooms[self.vue.action_room]; + var id_name = room.name.replace(/ /g, "_") + "_"; + var modType = 'module1'; //default + if (type == 2) { + modType = 'module2'; + } else if (type == 3) { + modType = 'module3'; + } + var id = new_id(); + var new_module = { + 'header': header, + '_idx': room.modules.length, + 'modType': modType, + 'el_id': id_name + "el_" + id, + 'id': id_name + id, + 'chart': "", + }; + room.modules.push(new_module); + if (self.vue.isInitialized) { + setTimeout(function () { + self.create_chart(self.vue.action_room, new_module._idx); + $("html, body").animate({scrollTop: $(document).height()}, 1000); + }, 100); + } + enumerate(room.modules); } - htmltag += '
    '; - return htmltag; - } - self.add_module = function (type, header) { - // console.log('add_module'); - var room = self.vue.rooms[self.vue.action_room]; - var id_name = room.name.replace(/ /g, "_") + "_"; - var modType = 'module1'; //default - if (type == 2) { - modType = 'module2'; - } else if (type == 3) { - modType = 'module3'; + self.modal_choose_icon = function (path) { + console.log('modal_choose_icon'); + self.vue.modal_chosen_icon_path = path; + $('#modal-input').focus(); } - var id = new_id(); - var new_module = { - 'header': header, - '_idx': room.modules.length, - 'modType': modType, - 'el_id': id_name + "el_" + id, - 'id': id_name + id, - 'chart': "", - }; - room.modules.push(new_module); - if (self.vue.isInitialized) { + + self.del_room = function (_idx) { + console.log('in del_room'); + if (_idx == 0) { //cannot delete room + console.log('Cannot delete Home'); + } else if (_idx == self.vue.action_room) { //currently using that room + console.log('del1 for ' + self.vue.rooms[_idx].name); + // for (i = 0; i < self.vue.rooms[_idx].modules.length; i++) { + // console.log("room: " + _idx + ", mod: " + i); + // $("#" + self.vue.rooms[_idx].modules[i].id).empty(); + // } + // self.vue.rooms[_idx].modules = []; + $('#del-room-modal').modal('hide'); + // jump to home + self.manage_btn_toggle(0); + } else { + console.log('del2 for ' + self.vue.rooms[_idx].name); + // for (i = 0; i < self.vue.rooms[_idx].modules.length; i++) { + // console.log("room: " + _idx + ", mod: " + i); + // $("#" + self.vue.rooms[_idx].modules[i].id).empty(); + // } + // self.vue.rooms[_idx].modules = []; + $('#del-room-modal').modal('hide'); + } + // self.vue.rooms.splice(_idx, 1); //Only work outside of this call setTimeout(function () { - self.create_chart(self.vue.action_room, new_module._idx); - $("html, body").animate({scrollTop: $(document).height()}, 1000); - }, 100); - } - enumerate(room.modules); - } + self.vue.rooms.splice(_idx, 1); + }, 200); + enumerate(self.vue.rooms); + }; - self.modal_choose_icon = function (path) { - console.log('modal_choose_icon'); - self.vue.modal_chosen_icon_path = path; - $('#modal-input').focus(); - } - self.del_room = function (_idx) { - console.log('in del_room'); - if (_idx == 0) { //cannot delete room - console.log('Cannot delete Home'); - } else if (_idx == self.vue.action_room) { //currently using that room - console.log('del1 for ' + self.vue.rooms[_idx].name); - // for (i = 0; i < self.vue.rooms[_idx].modules.length; i++) { - // console.log("room: " + _idx + ", mod: " + i); - // $("#" + self.vue.rooms[_idx].modules[i].id).empty(); - // } - // self.vue.rooms[_idx].modules = []; - $('#del-room-modal').modal('hide'); - // jump to home - self.manage_btn_toggle(0); - } else { - console.log('del2 for ' + self.vue.rooms[_idx].name); - // for (i = 0; i < self.vue.rooms[_idx].modules.length; i++) { - // console.log("room: " + _idx + ", mod: " + i); - // $("#" + self.vue.rooms[_idx].modules[i].id).empty(); + self.del_module = function (r_idx, mod) { + console.log('del_module : ' + self.vue.rooms[r_idx].name + "-" + mod.header); + var wrap = $("#" + mod.id); + var mod_element = $("#" + mod.el_id); + $.when(wrap.fadeOut(200)).done(function () { + $.when(wrap.css('display', '')).done( + function () { + // console.log('here'); + // remove_svg("#" + mod.el_id + "svg"); + var room = self.vue.rooms[r_idx]; + // if (mod.header == 'Activity' || mod.header == 'Devices') { + // remove_el("#" + "highcharts-0"); + // $("#" + "highcharts-0").children().unwrap(); + // mod.chart.destroy(); + // } + // console.log(room.modules.splice(mod._idx, 1)); + // setTimeout(function() { + // console.log(room.modules.splice(mod._idx, 1)); + // }, 500); + // self.reload_room(r_idx); + room.modules.splice(mod._idx, 1); + enumerate(self.vue.rooms[r_idx].modules); + setTimeout(function () { + console.log('reloading'); + self.reload_room(r_idx); + }, 5); + }); + }); + // console.log('here'); + // remove_svg("#" + mod.el_id + "svg"); + // var room = self.vue.rooms[r_idx]; + // if (mod.header == 'Activity' || mod.header == 'Devices') { + // remove_el("#" + "highcharts-0"); + // $("#" + "highcharts-0").children().unwrap(); + // mod.chart.destroy(); // } - // self.vue.rooms[_idx].modules = []; - $('#del-room-modal').modal('hide'); - } - // self.vue.rooms.splice(_idx, 1); //Only work outside of this call - setTimeout(function () { - self.vue.rooms.splice(_idx, 1); - }, 200); - enumerate(self.vue.rooms); - }; - - - self.del_module = function (r_idx, mod) { - console.log('del_module : ' + self.vue.rooms[r_idx].name + "-" + mod.header); - var wrap = $("#" + mod.id); - var mod_element = $("#" + mod.el_id); - $.when(wrap.fadeOut(200)).done(function () { - $.when(wrap.css('display', '')).done( - function () { - // console.log('here'); - // remove_svg("#" + mod.el_id + "svg"); - var room = self.vue.rooms[r_idx]; - // if (mod.header == 'Activity' || mod.header == 'Devices') { - // remove_el("#" + "highcharts-0"); - // $("#" + "highcharts-0").children().unwrap(); - // mod.chart.destroy(); - // } - // console.log(room.modules.splice(mod._idx, 1)); - // setTimeout(function() { - // console.log(room.modules.splice(mod._idx, 1)); - // }, 500); - // self.reload_room(r_idx); - room.modules.splice(mod._idx, 1); - enumerate(self.vue.rooms[r_idx].modules); - setTimeout(function () { - console.log('reloading'); - self.reload_room(r_idx); - }, 5); - }); - }); - // console.log('here'); - // remove_svg("#" + mod.el_id + "svg"); - // var room = self.vue.rooms[r_idx]; - // if (mod.header == 'Activity' || mod.header == 'Devices') { - // remove_el("#" + "highcharts-0"); - // $("#" + "highcharts-0").children().unwrap(); - // mod.chart.destroy(); - // } - // mod_element.empty(); - // console.log(room.modules.splice(mod._idx, 1)); - // setTimeout(function() { - // console.log(room.modules.splice(mod._idx, 1)); - // }, 500); - - // enumerate(self.vue.rooms[r_idx].modules); - }; - - - self.manage_btn_toggle = function (_idx) { - // console.log('manage_btn_toggle'); - for (var i = 0; i < self.vue.rooms.length; i++) { - if (_idx == self.vue.rooms[i]._idx) { - // console.log('Click on ' + self.vue.rooms[i].name); - self.vue.rooms[i].isActive = true; - self.vue.icon_path = self.vue.rooms[i].icon_path; - self.vue.action_room = i; + // mod_element.empty(); + // console.log(room.modules.splice(mod._idx, 1)); + // setTimeout(function() { + // console.log(room.modules.splice(mod._idx, 1)); + // }, 500); + + // enumerate(self.vue.rooms[r_idx].modules); + }; + + + self.manage_btn_toggle = function (_idx) { + clearInterval(liveTimer); + for (var i = 0; i < self.vue.rooms.length; i++) { + if (_idx == self.vue.rooms[i]._idx) { + self.vue.rooms[i].isActive = true; + self.vue.icon_path = self.vue.rooms[i].icon_path; + self.vue.action_room = i; + } else { + self.vue.rooms[i].isActive = false; + } + } + // + if (self.vue.isInitialized) { + setTimeout(function () { + if (!self.vue.rooms[_idx].initialized) { + init_charts(_idx); + } + live_data(_idx, 0); + }, 1); + } + }; + + self.top_manage_bar_toggle = function () { + // console.log('top_manage_bar_toggle'); + var bar = $("#top-manage-bar"); + self.vue.op_manage_bar_display = !self.vue.op_manage_bar_display; + $("html, body").animate({scrollTop: 0}, 400); + if (self.vue.op_manage_bar_display) { + bar.hide().slideDown(); } else { - self.vue.rooms[i].isActive = false; + bar.slideUp(); } - } - // This should refresh the action room's graph (delete and re-add.) - if (self.vue.isInitialized) { - setTimeout(function () { - self.reload_room(_idx); - }, 1); - } - }; - - self.top_manage_bar_toggle = function () { - // console.log('top_manage_bar_toggle'); - var bar = $("#top-manage-bar"); - self.vue.op_manage_bar_display = !self.vue.op_manage_bar_display; - $("html, body").animate({scrollTop: 0}, 400); - if (self.vue.op_manage_bar_display) { - bar.hide().slideDown(); - } else { - bar.slideUp(); - } - }; + }; - // Vue.component('panel-icon', { - // props: ['icon', ], - // template: ' \ - // \ - // ' - // }); // ***the delimiter in template does not change +// Vue.component('panel-icon', { +// props: ['icon', ], +// template: ' \ +// \ +// ' +// }); // ***the delimiter in template does not change - // device-list - Vue.component('device-list', { - props: ['room'], - template: '
  • \ +// device-list + Vue.component('device-list', { + props: ['room'], + template: '
  • \ Device-1\ \ \
  • ' - }); // ***the delimiter in template does not change + }); // ***the delimiter in template does not change - // manage-bar => manage-list - Vue.component('manage-item', { - props: ['room', 'manage_btn_toggle'], - template: ' manage-list + Vue.component('manage-item', { + props: ['room', 'manage_btn_toggle'], + template: ' \ {{room.name}}\ ' - }); // ***the delimiter in template does not change + }); // ***the delimiter in template does not change - // manage-bar => manage-list - Vue.component('top-manage-item', { - props: ['room', 'manage_btn_toggle', 'top_manage_bar_toggle'], - template: ' manage-list + Vue.component('top-manage-item', { + props: ['room', 'manage_btn_toggle', 'top_manage_bar_toggle'], + template: ' \ {{room.name}}\ ' - }); // ***the delimiter in template does not change + }); // ***the delimiter in template does not change - // page-wrap => module-wrap - Vue.component('module', { - props: ['mod', 'room', 'del_module'], - template: '
    \ +// page-wrap => module-wrap + Vue.component('module', { + props: ['mod', 'room', 'del_module'], + template: '
    \
    \
    \
    \ @@ -705,140 +799,150 @@ var app = function () {
    \
    \
    ' - }); // ***the delimiter in template does not change - - - // Complete as needed. - self.vue = new Vue({ - el: "#vue-div", - delimiters: ['${', '}'], - unsafeDelimiters: ['!{', '}'], - data: { - csrf_token: function () { - var csrf_token = null; - if (document.cookie && document.cookie !== '') { - var cookies = document.cookie.split(';'); - for (var i = 0; i < cookies.length; i++) { - var cookie = jQuery.trim(cookies[i]); - if (cookie.substring(0, 10) === ('csrftoken=')) { - csrf_token = decodeURIComponent(cookie.substring(10)); - break; + }); // ***the delimiter in template does not change + + +// Complete as needed. + self.vue = new Vue({ + el: "#vue-div", + delimiters: ['${', '}'], + unsafeDelimiters: ['!{', '}'], + data: { + csrf_token: function () { + var csrf_token = null; + if (document.cookie && document.cookie !== '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + if (cookie.substring(0, 10) === ('csrftoken=')) { + csrf_token = decodeURIComponent(cookie.substring(10)); + break; + } } } - } - return csrf_token; - }, - house_id: 99, // Not sure, from query file - user_id: 0, // from query file - device_id: device_id, - room_structure: device, - power_data: {}, - rooms: [{ - 'name': 'Home', // or possibly separated from room - '_idx': 0, // index of local manage-list - 'notice': 0, - 'data': [], - 'appliances': [], - 'icon_path': img_path + "/home.png", - 'isActive': true, - 'modules': [{ - 'header': 'activity', - '_idx': 0, - 'modType': 'module1', // type of module (1-3, css differ) - 'el_id': 'Home_el_0', //for plot use( the inner el box ) - 'id': 'Home_0', // this should be computed and assigned at the insertion - 'chart': '', - } - // , - // { - // 'header': 'devices', - // '_idx': 1, - // 'modType': 'module3', - // 'el_id': 'Home_el_1', - // 'id': 'Home_1', - // 'chart': '', - // } - , { - 'header': 'graph', - '_idx': 2, - 'modType': 'module2', - 'el_id': 'Home_el_2', - 'id': 'Home_2', - 'chart': '', - }, { - 'header': 'consumption', - '_idx': 3, - 'modType': 'module3', - 'el_id': 'Home_el_3', - 'id': 'Home_3', - 'chart': '', + return csrf_token; + }, + house_id: 99, // Not sure, from query file + user_id: 0, // from query file + device_id: device_id, + room_structure: device, + power_data: {}, + rooms: [{ + 'name': 'Home', // or possibly separated from room + '_idx': 0, // index of local manage-list + 'notice': 0, + 'data': [], + 'appliances': { + 'Testbed': { + 'id': 'Grid' + } }, - // { - // 'header': 'notification', - // '_idx': 4, - // 'modType': 'module2', - // 'el_id': 'Home_el_4', - // 'id': 'Home_4', - // 'chart': '', - // }, - { - 'header': 'Sort appliances', - '_idx': 5, - 'modType': 'module1', - 'el_id': 'Home_el_5', - 'id': 'Home_5', + 'icon_path': img_path + "/home.png", + 'isActive': true, + 'initialized': false, + 'modules': [{ + 'header': 'activity', + '_idx': 0, + 'modType': 'module1', // type of module (1-3, css differ) + 'el_id': 'Home_el_0', //for plot use( the inner el box ) + 'id': 'Home_0', // this should be computed and assigned at the insertion 'chart': '', - }], - },], - id_tracker: 4, //according to that last Home_(id) - search_bar_input_val: '', - top_manage_bar_display: false, - icon_path: img_path + "/home.png", - icons: [img_path + "/bedroom.png", - img_path + "/bedroom2.png", - img_path + "/office.png", - img_path + "/kitchen.png", - img_path + "/bathroom.png", - img_path + "/livingroom.png" - ], - modal_chosen_icon_path: img_path + "/home.png", - default_icon_path: img_path + "/home.png", - modal_room_name: '', - modal_appliances: [], - action_room: 0, //_idx of room, 0 refers to Home - adding_room: true, // modal is for editng or adding - isInitialized: false, - start_date: moment().utc().unix() - (7 * 86400), - end_date: moment().utc().unix(), - }, - methods: { - manage_btn_toggle: self.manage_btn_toggle, - top_manage_bar_toggle: self.top_manage_bar_toggle, - del_module: self.del_module, - add_module: self.add_module, - modal_choose_icon: self.modal_choose_icon, - add_room: self.add_room, - del_room: self.del_room, - adding_editing_room: self.adding_editing_room, - add_edit_room_enter: self.add_edit_room_enter, - edit_room: self.edit_room, - modal_reinit: self.modal_reinit, - }, - }); - - - modal_event_init(); - init_rooms(); - - init_data(); - date_picker(); - - init_home(); - - $("#vue-div").show(); - console.log('Vue initialized'); - return self; -}; + } + // , + // { + // 'header': 'devices', + // '_idx': 1, + // 'modType': 'module3', + // 'el_id': 'Home_el_1', + // 'id': 'Home_1', + // 'chart': '', + // } + , { + 'header': 'graph', + '_idx': 2, + 'modType': 'module2', + 'el_id': 'Home_el_2', + 'id': 'Home_2', + 'chart': '', + }, { + 'header': 'consumption', + '_idx': 3, + 'modType': 'module3', + 'el_id': 'Home_el_3', + 'id': 'Home_3', + 'chart': '', + }, + // { + // 'header': 'notification', + // '_idx': 4, + // 'modType': 'module2', + // 'el_id': 'Home_el_4', + // 'id': 'Home_4', + // 'chart': '', + // }, + { + 'header': 'Sort appliances', + '_idx': 5, + 'modType': 'module1', + 'el_id': 'Home_el_5', + 'id': 'Home_5', + 'chart': '', + }], + },], + id_tracker: 4, //according to that last Home_(id) + search_bar_input_val: '', + top_manage_bar_display: false, + icon_path: img_path + "/home.png", + icons: [img_path + "/bedroom.png", + img_path + "/bedroom2.png", + img_path + "/office.png", + img_path + "/kitchen.png", + img_path + "/bathroom.png", + img_path + "/livingroom.png" + ], + modal_chosen_icon_path: img_path + "/home.png", + default_icon_path: img_path + "/home.png", + modal_room_name: '', + modal_appliances: [], + action_room: 0, //_idx of room, 0 refers to Home + adding_room: true, // modal is for editng or adding + isInitialized: false, + start_date: moment().utc().unix() - (7 * 86400), + end_date: moment().utc().unix(), + }, + methods: { + manage_btn_toggle: self.manage_btn_toggle, + top_manage_bar_toggle: self.top_manage_bar_toggle, + del_module: self.del_module, + add_module: self.add_module, + modal_choose_icon: self.modal_choose_icon, + add_room: self.add_room, + del_room: self.del_room, + adding_editing_room: self.adding_editing_room, + add_edit_room_enter: self.add_edit_room_enter, + edit_room: self.edit_room, + modal_reinit: self.modal_reinit, + }, + }); + + modal_event_init(); + init_rooms(); + init_charts(self.vue.action_room); + + live_data(0, 0); + // update_areaspline_home(0, 0, 1528093000, 1528093579, 20); +//live_data(0, 0); +//init_data(); +//date_picker(); + +//init_home(); + + $("#vue-div").show(); + console.log('Vue initialized'); + return self; + } +; + var APP = null; diff --git a/seadssite/templates/device.html b/seadssite/templates/device.html index 21edba5..c0776f5 100644 --- a/seadssite/templates/device.html +++ b/seadssite/templates/device.html @@ -64,6 +64,9 @@

    Please sign in to continue

     
    +
    Date: Mon, 4 Jun 2018 23:38:37 -0700 Subject: [PATCH 2/7] Minor changes --- seadssite/static/css/myapp.css | 2 +- seadssite/static/js/areaspline.js | 4 ++-- seadssite/templates/device.html | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/seadssite/static/css/myapp.css b/seadssite/static/css/myapp.css index b86835d..9aa9ca4 100644 --- a/seadssite/static/css/myapp.css +++ b/seadssite/static/css/myapp.css @@ -14,7 +14,7 @@ body { } #space-for-search-bar { - margin-top: 80px; + margin-top: 60px; padding: 10px; wdith: 300px; } diff --git a/seadssite/static/js/areaspline.js b/seadssite/static/js/areaspline.js index 19b3409..587a752 100644 --- a/seadssite/static/js/areaspline.js +++ b/seadssite/static/js/areaspline.js @@ -32,11 +32,11 @@ var areaspline = function (room, mod_i) { }, yAxis: { title: { - text: 'kWh' + text: 'Wh' }, }, tooltip: { - valueSuffix: ' kWh', + valueSuffix: ' Wh', //valueDecimals: 3, shared: true }, diff --git a/seadssite/templates/device.html b/seadssite/templates/device.html index c0776f5..697fa1e 100644 --- a/seadssite/templates/device.html +++ b/seadssite/templates/device.html @@ -59,14 +59,14 @@

    Please sign in to continue

    Date: Sat, 9 Jun 2018 17:49:11 -0700 Subject: [PATCH 3/7] Rewrite for areaspline with promises/callbacks --- seadssite/static/js/areaspline.js | 2 +- seadssite/static/js/device.js | 235 ++++++++++++------------------ 2 files changed, 98 insertions(+), 139 deletions(-) diff --git a/seadssite/static/js/areaspline.js b/seadssite/static/js/areaspline.js index 587a752..4f57dea 100644 --- a/seadssite/static/js/areaspline.js +++ b/seadssite/static/js/areaspline.js @@ -3,7 +3,7 @@ var areaspline = function (room, mod_i) { global: { useUTC: false } - }) + }); room.modules[mod_i].chart = Highcharts.chart(room.modules[mod_i].el_id, { chart: { diff --git a/seadssite/static/js/device.js b/seadssite/static/js/device.js index c130d9d..d816480 100644 --- a/seadssite/static/js/device.js +++ b/seadssite/static/js/device.js @@ -89,28 +89,6 @@ var app = function () { cb(start, end); } - // Generates a power data structure and generates monthly power usage data for each appliance - function init_data() { - Object.keys(device.rooms).forEach(function (room) { - Object.keys(device.rooms[room].appliances).forEach(function (appliance) { - var appl_id = device.rooms[room].appliances[appliance].id; - self.vue.power_data[appl_id] = { - name: appliance, - monthly_data: gen_monthly_appl_data(self.vue.device_id, appliance, appl_id), - data: undefined, - }; - }); - }); - } - - // Refreshes saved power data based on current start and end date - function refresh_data() { - console.log("refresh_data"); - Object.keys(self.vue.power_data).forEach(function (appl_id) { - self.vue.power_data[appl_id].data = gen_cont_appl_data(self.vue.device_id, self.vue.power_data[appl_id].name, - appl_id, self.vue.start_date, self.vue.end_date, 30); - }); - } var init_rooms = function () { var rooms = self.vue.room_structure.rooms; @@ -136,16 +114,37 @@ var app = function () { self.vue.rooms[room_i].initialized = true; } + // Creates empty series for the appliances of the specified room and chart + function create_series(room_i, mod_i) { + var chart = self.vue.rooms[room_i].modules[mod_i].chart; - //function gen_series_data() + if (room_i == 0) { + for (var i = 1; i < self.vue.rooms.length; i++) { + chart.addSeries({ + id: self.vue.rooms[i].name, + name: self.vue.rooms[i].name, + data: [] + }) + } + } else { + var appliances = self.vue.rooms[room_i].appliances; + Object.keys(appliances).forEach(function (key) { + chart.addSeries({ + id: appliances[key].id, + name: key, + data: [] + }); + }); + } + } // Returns a request URL // Overloaded such that if only two arguments are provided, it creates a URL for requesting cumulative usage - // up to a specified time - this is used for calculating power usage over a period of time + // up to a specified time - this is used for calculating power usage over a period of time, i.e. for monthly usage // Otherwise it creates a URL for requesting continuous usage data over a specified period of time, with ~data_points // number of data points function create_url(appliance_id, start, end, data_points) { - var url = "http://db.sead.systems:8080/" + device_id + "?type=P" + "&device=" + appliance_id + "&start_time=" + start; + var url = "http://db.sead.systems:8080/" + self.vue.device_id + "?type=P&list_format=energy&device=" + appliance_id + "&start_time=" + start; if (arguments.length == 2) url += "&end_time=" + start; else @@ -156,102 +155,97 @@ var app = function () { // Performs GET request for specified API call function fetch_data(url, callback) { console.log(url); - $.ajax({ + return $.ajax({ url: url, dataType: 'json', + dataFilter: function (response, type) { + var data = []; + $.map(JSON.parse(response).data, function (value, key) { + data.push([moment(value.time, "YYYY-MM-DD HH:mm:ss").valueOf(), parseFloat(value.energy)]); + }); + data.reverse(); + return JSON.stringify(data); + }, success: function (response) { callback(response); } }); } - // Creates empty series for the appliances of the specified room and chart - function create_series(room_i, mod_i) { - var chart = self.vue.rooms[room_i].modules[mod_i].chart; - var appliances; - - // if (room_i == 0) { - // for (var i = 1; i < self.vue.rooms.length; i++) { - // chart.addSeries({ - // id: self.vue.rooms[i].name, - // name: self.vue.rooms[i].name, - // data: [1, 2, 3] - // }) - // } - // } else { - appliances = self.vue.rooms[room_i].appliances; - Object.keys(appliances).forEach(function (key) { - chart.addSeries({ - id: appliances[key].id, - name: key, - data: [] - }); - }); - // } + // Updates continuous power data for all appliances registered with specified parameters + // Should probably be merged with update_room_data + function update_home_data(start, end, data_points, callback) { + var c = self.vue.rooms.length - 1; + for (var i = 1; i < self.vue.rooms.length; i++) { + update_room_data(i, start, end, data_points, function () { + c--; + if (c == 0) { + console.log("all appliances update"); + callback(0); + } + }) + } } - function update_areaspline(room_i, mod_i, start, end, data_points) { - var chart = self.vue.rooms[room_i].modules[mod_i].chart; - chart.series.forEach(function (series) { - fetch_data(create_url(series.options.id, start, end, data_points), function (response) { - var temp = Object.keys(response.data).reverse().map(function (key) { - return [moment(response.data[key].time, "YYYY-MM-DD HH:mm:ss").valueOf(), parseFloat(response.data[key].energy) * 1000]; - }); - chart.get(series.options.id).update({ - data: temp - }) + // Updates continuous power data for all appliances in specified room with specified parameters + // Does not work for home room (index 0) as it has no appliances associated + function update_room_data(room_i, start, end, data_points, callback) { + console.log("updating room", room_i); + if (self.vue.rooms[room_i].hasOwnProperty('appliances')) { + var appliances = self.vue.rooms[room_i].appliances; + var promises = []; + Object.keys(appliances).forEach(function (appl) { + promises.push(fetch_data(create_url(appliances[appl].id, start, end, data_points), function (response) { + self.vue.appliances[appliances[appl].id] = response; + })); }); - }); - chart.hideLoading(); - } - - function helper(appliances, index, start, end, data_points, data) { - fetch_data(create_url(appliances[index].id, start, end, data_points), function (response) { - var temp = Object.keys(response.data).reverse().map(function (key) { - return [moment(response.data[key].time, "YYYY-MM-DD HH:mm:ss").valueOf(), parseFloat(response.data[key].energy)]; + $.when.apply(this, promises).done(function () { + callback(room_i); }); - console.log(appliances[index].id, temp); - if (data.length == 0) { - console.log("empty"); - for (var j = 0; j < temp.length; j++) { - data.push(temp[j].slice(0)); - } - } else { - console.log("not empty", data, temp); - for (var j = 0; j < temp.length; j++) { - data[j][1] = data[j][1] + temp[j][1]; - } - } - console.log("updated to", data); - if (index != appliances.length - 1) - helper(appliances, index + 1, start, end, data_points, temp, data); - else - return data; - }); + } } + // Updates areaspline chart for specified room with data from buffered data at self.vue.appliances + function update_areaspline(room_i) { + var chart = self.vue.rooms[room_i].modules[0].chart; - function update_areaspline_home(room_i, mod_i, start, end, data_points) { - var chart = self.vue.rooms[room_i].modules[mod_i].chart; - var appliances = self.vue.rooms[room_i].appliances; - console.log("areaspline"); - var data = []; - for (var i = 1; i < self.vue.rooms.length; i++) { - console.log("helper", self.vue.rooms[i].name); - var test = helper(Object.values(appliances), 0, start, end, data_points, data); - console.log(test); - + if (room_i == 0) { + for (var i = 1; i < self.vue.rooms.length; i++) { + var appliances = self.vue.rooms[i].appliances; + var aggregate = []; + Object.keys(appliances).forEach(function (key, index) { + var data = self.vue.appliances[appliances[key].id]; + for (var j = 0; j < data.length; j++) { + if (index == 0) + aggregate[j] = data[j].slice(0); + else + aggregate[j][1] = aggregate[j][1] + data[j][1]; + } + }); + chart.get(self.vue.rooms[i].name).update({ + data: aggregate + }); + } + } else { + chart.series.forEach(function (series) { + chart.get(series.options.id).update({ + data: self.vue.appliances[series.options.id] + }); + }); } - chart.hideLoading(); } - function live_data(room_i, mod_i) { + function live_data(room_i) { liveTimer = setInterval(function x() { console.log("updating chart"); var end = Math.floor(Date.now() / 1000); var start = end - 600; - update_areaspline(room_i, mod_i, start, end, 60); + if (room_i == 0) { + update_home_data(start, end, 60, update_areaspline); + } else { + update_room_data(room_i, start, end, 60, update_areaspline); + } return x; }(), 20000); } @@ -291,29 +285,6 @@ var app = function () { return result; } -// Generates continous power usage data for the specified parameters - function gen_cont_appl_data(device_id, name, appliance_id, start, end, data_points) { - var granularity = Math.floor((end - start) / data_points); - - console.log("http://db.sead.systems:8080/" + device_id + "?start_time=" + start + "&end_time=" + end + - "&list_format=energy&type=P&device=" + appliance_id + "&granularity=" + granularity); - - var result = []; - $.ajax({ - url: "http://db.sead.systems:8080/" + device_id + "?start_time=" + start + "&end_time=" + end + - "&list_format=energy&type=P&device=" + appliance_id + "&granularity=" + granularity, - dataType: 'json', - async: false, - success: function (response) { - result = Object.keys(response.data).reverse().map(function (key) { - return [moment(response.data[key]["time"], "YYYY-MM-DD HH:mm:ss").valueOf(), parseFloat(response.data[key]["energy"])]; - }) - } - }); - console.log(result); - return result; - } - // Generates bar chart for specified room function gen_bar_chart(room_i, mod_i) { @@ -528,8 +499,8 @@ var app = function () { } -// gen_application_sort_string() -// generates html to display the Sort Application module on the homepage + // gen_application_sort_string() + // generates html to display the Sort Application module on the homepage var gen_application_sort_string = function () { var sortAppliancesString = '
    ' + @@ -713,7 +684,6 @@ var app = function () { self.vue.rooms[i].isActive = false; } } - // if (self.vue.isInitialized) { setTimeout(function () { if (!self.vue.rooms[_idx].initialized) { @@ -826,17 +796,11 @@ var app = function () { user_id: 0, // from query file device_id: device_id, room_structure: device, - power_data: {}, + appliances: {}, rooms: [{ 'name': 'Home', // or possibly separated from room '_idx': 0, // index of local manage-list 'notice': 0, - 'data': [], - 'appliances': { - 'Testbed': { - 'id': 'Grid' - } - }, 'icon_path': img_path + "/home.png", 'isActive': true, 'initialized': false, @@ -927,15 +891,10 @@ var app = function () { modal_event_init(); init_rooms(); - init_charts(self.vue.action_room); - live_data(0, 0); - // update_areaspline_home(0, 0, 1528093000, 1528093579, 20); -//live_data(0, 0); -//init_data(); -//date_picker(); + init_charts(self.vue.action_room); -//init_home(); + live_data(self.vue.action_room); $("#vue-div").show(); console.log('Vue initialized'); From bbbe5f846bcde59dcffd72d2142556293d07b502 Mon Sep 17 00:00:00 2001 From: grant523 Date: Sat, 9 Jun 2018 20:01:49 -0700 Subject: [PATCH 4/7] Added live data streaming option --- seadssite/static/css/myapp.css | 8 +++++++ seadssite/static/js/areaspline.js | 4 ++-- seadssite/static/js/device.js | 40 ++++++++++++++++++++++--------- seadssite/templates/device.html | 17 ++++++------- 4 files changed, 48 insertions(+), 21 deletions(-) diff --git a/seadssite/static/css/myapp.css b/seadssite/static/css/myapp.css index 9aa9ca4..5052f74 100644 --- a/seadssite/static/css/myapp.css +++ b/seadssite/static/css/myapp.css @@ -4,6 +4,14 @@ color: #bb8833; } +#reportrange { + margin-right: 10px; +} + +#live-data-toggle { + margin-top: -50px; +} + body { over-flow-x: hidden; margin: 0px; diff --git a/seadssite/static/js/areaspline.js b/seadssite/static/js/areaspline.js index 4f57dea..c683be3 100644 --- a/seadssite/static/js/areaspline.js +++ b/seadssite/static/js/areaspline.js @@ -32,11 +32,11 @@ var areaspline = function (room, mod_i) { }, yAxis: { title: { - text: 'Wh' + text: 'kWh' }, }, tooltip: { - valueSuffix: ' Wh', + valueSuffix: ' kWh', //valueDecimals: 3, shared: true }, diff --git a/seadssite/static/js/device.js b/seadssite/static/js/device.js index d816480..aade54c 100644 --- a/seadssite/static/js/device.js +++ b/seadssite/static/js/device.js @@ -1,5 +1,3 @@ -var liveTimer; - var app = function () { var self = {}; @@ -66,8 +64,15 @@ var app = function () { self.vue.start_date = Math.floor(start / 1000); self.vue.end_date = Math.floor(end / 1000); console.log(moment.unix(self.vue.start_date).format("MM/DD/YYYY h:mm a") + " to " + moment.unix(self.vue.end_date).format("MM/DD/YYYY h:mm a")); - refresh_data(); - self.create_chart(self.vue.action_room, 0); + if(self.vue.live_data) { + self.vue.live_data = false; + clearInterval(self.vue.live_timer); + } + self.vue.rooms[self.vue.action_room].modules[0].chart.showLoading(); + if(self.vue.action_room == 0) + update_home_data(self.vue.start_date, self.vue.end_date, 30, update_areaspline); + else + update_room_data(self.vue.action_room, self.vue.start_date, self.vue.end_date, 30, update_areaspline); } $('#reportrange').daterangepicker({ @@ -237,7 +242,7 @@ var app = function () { } function live_data(room_i) { - liveTimer = setInterval(function x() { + self.vue.live_timer = setInterval(function x() { console.log("updating chart"); var end = Math.floor(Date.now() / 1000); var start = end - 600; @@ -286,7 +291,7 @@ var app = function () { } -// Generates bar chart for specified room + // Generates bar chart for specified room function gen_bar_chart(room_i, mod_i) { var categories = []; var month = moment().month() + 1; @@ -499,8 +504,8 @@ var app = function () { } - // gen_application_sort_string() - // generates html to display the Sort Application module on the homepage + // gen_application_sort_string() + // generates html to display the Sort Application module on the homepage var gen_application_sort_string = function () { var sortAppliancesString = '
    ' + @@ -674,7 +679,7 @@ var app = function () { self.manage_btn_toggle = function (_idx) { - clearInterval(liveTimer); + clearInterval(self.vue.live_timer); for (var i = 0; i < self.vue.rooms.length; i++) { if (_idx == self.vue.rooms[i]._idx) { self.vue.rooms[i].isActive = true; @@ -689,7 +694,10 @@ var app = function () { if (!self.vue.rooms[_idx].initialized) { init_charts(_idx); } - live_data(_idx, 0); + if(self.vue.live_timer != false) { + clearInterval(self.vue.live_timer); + live_data(_idx, 0); + } }, 1); } }; @@ -792,12 +800,15 @@ var app = function () { } return csrf_token; }, + live_timer: false, + live_data: false, house_id: 99, // Not sure, from query file user_id: 0, // from query file device_id: device_id, room_structure: device, appliances: {}, rooms: [{ + 'checked': false, 'name': 'Home', // or possibly separated from room '_idx': 0, // index of local manage-list 'notice': 0, @@ -886,6 +897,12 @@ var app = function () { add_edit_room_enter: self.add_edit_room_enter, edit_room: self.edit_room, modal_reinit: self.modal_reinit, + toggle_live_data: function () { + if(this.live_data) + clearInterval(this.live_timer); + else + live_data(this.action_room); + } }, }); @@ -894,7 +911,8 @@ var app = function () { init_charts(self.vue.action_room); - live_data(self.vue.action_room); + date_picker(); + $("#vue-div").show(); console.log('Vue initialized'); diff --git a/seadssite/templates/device.html b/seadssite/templates/device.html index 697fa1e..63d0954 100644 --- a/seadssite/templates/device.html +++ b/seadssite/templates/device.html @@ -14,6 +14,9 @@ + + +