(function () {
'use strict';
angular
.module('hyperion')
.controller('system.DashboardController', ['$http', '$state', '$stateParams', '$rootScope', '$scope', '$timeout', '$sessionStorage', '$location', '$filter', 'timerange', 'sysClock', 'CONFIG', '$q', 'authService', function($http, $state, $stateParams, $rootScope, $scope, $timeout, $sessionStorage, $location, $filter, timerange, sysClock, CONFIG, $q, authService){
$rootScope.$watch('project', function (newValue, oldValue, scope) {
if(newValue!==oldValue){
load_data().catch(error => { // dashboard data
console.warn(error);
});
}
});
// set #content div margin
if($sessionStorage.currentUser !== undefined) {
if($sessionStorage.currentUser.smallMenu) {
$("#content").css('margin-left', 50);
}
}
var scopeIsActive = true;
$scope.$on('$destroy', function() {
scopeIsActive = false;
});
// Charts Loading
$scope.loading_top_charts = true; // combination of chart_powertemp + chart_powertemp_pie
$scope.loading_modules = true;
var time = timerange.calc($sessionStorage.currentUser.timerange);
$scope.$on('trUpdate', function(event, payload) { // time range update event
console.log('trUpdate event: ' + $sessionStorage.currentUser.timerange);
time = timerange.calc($sessionStorage.currentUser.timerange);
load_data().catch(error => { // dashboard data
console.warn(error);
});
});
function load_data() {
return new Promise((resolve, reject) => {
$scope.isLoading = true; // show ajax loader (global)
$scope.loading_top_charts = true; // loading top charts
$scope.loading_modules = true; // loading modules information
// show ajax loaders
$scope.project = {
locations_total: null,
equipment_total: null,
events_total: null,
events_warning: null,
events_alert: null,
power_consumption: null,
co2_emission: null
};
let time_start = moment(time.start).format('YYYY-MM-DDTHH:mm:ss');
let time_end = moment(time.today).format('YYYY-MM-DDTHH:mm:ss');
console.log('date_start: ' + time_start);
console.log('date_end: ' + time_end);
console.log('$rootScope.project: ', $rootScope.project);
const promise_project = new Promise((resolve, reject) => {
authService.getJWTAuth().then(authHeader => {
var request = {'query':
'query { ' +
'projects(id:"' + $rootScope.project + '", time_start:"' + time_start + '", time_end:"' + time_end + '", timezone:"' + sysClock.getTimeZone() + '") { ' +
'id ' +
'name ' +
'locations_total ' +
'equipment_total ' +
'events_notice ' +
'events_warning ' +
'events_alert ' +
'power_consumption ' +
'co2_emission ' +
'} ' +
'}'
};
$http({
method: 'POST',
url: CONFIG.APP_API,
data: request,
headers: authHeader
}).then(
function(response){ // resolve
$scope.project = response.data.data.projects[0];
$scope.project.events_total = parseInt($scope.project.events_notice?$scope.project.events_notice:0) + parseInt($scope.project.events_warning?$scope.project.events_warning:0) + parseInt($scope.project.events_alert?$scope.project.events_alert:0);
$scope.project.events_notice = $scope.project.events_notice?$scope.project.events_notice:0;
$scope.project.events_warning = $scope.project.events_warning?$scope.project.events_warning:0;
$scope.project.events_alert = $scope.project.events_alert?$scope.project.events_alert:0;
$scope.project.power_consumption = $scope.project.power_consumption?$scope.project.power_consumption:0;
$scope.project.co2_emission = $scope.project.co2_emission?$scope.project.co2_emission:0;
console.log($scope.project);
resolve(null);
},function(error) { // failure
console.error(error);
reject();
}
);
});
});
const promise_modules = new Promise((resolve, reject) => {
authService.getJWTAuth().then(authHeader => {
var request = {'query':
'query { ' +
'module_event_daily(project:"' + $rootScope.project + '", time_start:"' + time_start + '", time_end:"' + time_end + '", timezone:"' + sysClock.getTimeZone() + '") { ' +
'id ' +
'name ' +
'icon ' +
'type_ids ' +
'devices ' +
'events_total ' +
'events_notice ' +
'events_warning ' +
'events_alert ' +
'events ' +
'} ' +
'}'
};
$http({
method: 'POST',
url: CONFIG.APP_API,
data: request,
headers: authHeader
}).then(
function(response){ // resolve
$scope.modules = response.data.data.module_event_daily;
$scope.loading_modules = false;
resolve(null);
},function(error) { // failure
console.error(error);
reject(null);
}
);
});
});
Promise.all([
promise_project,
promise_modules
])
.then(() => {
console.log('Promise.all');
$scope.isLoading = false; // hide ajax loader
$scope.modules.forEach(module => {
let chart_data = [];
module.events.forEach(element => {
chart_data.push({x: element.epoch, y: element.total});
})
new Highcharts.Chart({
chart: {
type: 'column',
renderTo: 'chart_' + module.name + '_events',
height: 55,
borderWidth: 0,
marginTop: 0,
marginRight: 10,
marginLeft: 10,
marginBottom: 0,
spacingLeft: 0,
spacingRight: 0,
spacingBottom: 0,
spacingTop: 0,
backgroundColor: 'transparent'
},
time: { useUTC: true},
title: { text: null },
subtitle: { text: null },
exporting: { enabled: false },
credits: { enabled: false },
legend: { enabled:false },
tooltip: {
outside: true,
useHTML: true,
backgroundColor: '#fff',
borderWidth: 0,
formatter: function () {
return '
'+moment(this.point.x).format('ll') + '
' + this.point.y + ' events
';
}
},
xAxis: {
labels: {
enabled: false
},
type: 'datetime',
tickInterval: 86400000, // 24 * 3600 * 1000 = 1 day
},
yAxis: {
labels: {
enabled: false
},
gridLineWidth: 0
},
plotOptions: {
column: {
stacking: 'normal',
pointPadding: 0,
borderWidth: 0,
dataLabels: {
enabled: false
}
},
series: {
name: 'Events',
minPointLength: 3,
borderWidth: 0,
dataLabels: {
enabled: false
},
marker: {
enabled: false
}
}
},
series: [{
data: chart_data
}]
}, function(chart){ });
});
create_chart_objects(); // create charts & load data
resolve(null);
});
});
}
$timeout(() => {
load_data()
.catch(error => {
console.warn(error);
});
}, 100);
$scope.viewLocation = function(location_id) {
$location.path('/system/locations/view/'+location_id);
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HIGHCHARTS CONFIG
Highcharts.setOptions({
time: {
timezone: sysClock.getTimeZone()
}
});
Highcharts.dateFormats = {
'Z': () => {
return moment.tz(sysClock.getTimeZone()).format('Z');
}
};
const chart_power_consumption_pie_colors = Highcharts.getOptions().colors.map((c, i) =>
// Start out with a darkened base color (negative brighten), and end up with a much brighter color
Highcharts.color('#0197FE')
.brighten((i - 3) / 7)
.get()
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// GLOBAL Chart Data Functions
const chart_clean = (chart) => { // remove data servies (empty graph)
while(chart.series.length) {
chart.series[0].remove();
}
}
const load_daily_data = () => { // prepare loading 1d aggregation data to graph
return new Promise((resolve) => {
$scope.chart_drilldown = false; // mark drolldown false
$scope.chart_drilldown_timestamp = null; // remove drilldown timestamp
chart_clean(chart_powertemp_consumption); // remove data servies (empty graph)
//$scope.chart_consumption_title = 'Last ' + $sessionStorage.currentUser.timerange + ' Days Power Consumption'; // set graph title
/*
let tickInterval = 86400000; // 3600 * 24 * 1000 = 1 day (tickInterval = 1d in milliseconds)
let time_start_truncated = moment.utc(time.start).startOf('day').valueOf(); // round up to beginning of the 1st day
let time_end_truncated = moment.utc(time.today).add(1, 'days').startOf('day').subtract(1, 'seconds').valueOf(); // round down to end of the last day
console.log('>> time_start_truncated:', time_start_truncated);
console.log('>> time_end_truncated:', time_end_truncated);
chart_powertemp_consumption.xAxis.forEach((xaxis, i) => { // set graph X Axis (time:days) display range
xaxis.options.tickInterval = tickInterval;
xaxis.setExtremes(time_start_truncated, time_end_truncated, true);
});
chart_events_heatmap.xAxis.forEach((xaxis, i) => { // set graph X Axis (time:days) display range
xaxis.options.tickInterval = tickInterval;
xaxis.setExtremes(time_start_truncated, time_end_truncated, true);
});
let time_start = moment.utc(time_start_truncated).format('YYYY-MM-DDTHH:mm:ss');
let time_end = moment.utc(time_end_truncated).format('YYYY-MM-DDTHH:mm:ss');
*/
let time_start = moment.utc(time.start).format('YYYY-MM-DDTHH:mm:ss');
let time_end = moment.utc(time.today).format('YYYY-MM-DDTHH:mm:ss');
console.log('>> time_start:', time_start);
console.log('>> time_end:', time_end);
console.log('**** ' + moment.tz(sysClock.getTimeZone()).format('YYYY-MM-DDTHH:mm:ss'));
Promise.all([
chart_add_power_daily(time_start, time_end),
chart_add_power_module(time_start, time_end),
chart_add_events(time_start, time_end)
])
.then(() => {
console.log('Promise.all');
resolve(null);
});
});
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
const chart_add_power_daily = (time_start, time_end) => {
console.log('chart_add_power_daily');
return new Promise((resolve) => {
let power_series = {
name: "Power Consumption",
type: "column",
marker: {
symbol: 'circle'
},
yAxis: 0,
zIndex: 1,
tooltip: {
valueSuffix: 'kWh'
},
color: '#0197fe',
data: []
};
authService.getJWTAuth().then(authHeader => {
var request = {'query':
'query { ' +
'power_daily(object:"' + $rootScope.project + '", time_start:"' + time_start + '", time_end:"' + time_end + '", timezone:"' + sysClock.getTimeZone() + '") { ' +
'step ' +
'epoch ' +
'p_avg ' +
'} ' +
'}'
};
$http({
method: 'POST',
url: CONFIG.APP_API,
data: request,
headers: authHeader
}).then(
(response) => { // resolve
response.data.data.power_daily.forEach(day => {
power_series.data.push({
x: parseInt(day.epoch, 10),
y: (day.p_avg?day.p_avg:0)
});
});
chart_powertemp_consumption.addSeries(power_series);
console.log(power_series.data);
resolve(null);
},(error) => { // failure
console.error(error);
}
);
});
});
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
const chart_add_power_module = (time_start, time_end) => {
console.log('chart_add_power_module');
return new Promise((resolve) => {
let power_module = {
name: "Power Consumption",
data: []
};
let total = 0;
authService.getJWTAuth().then(authHeader => {
var request = {'query':
'query { ' +
'power_module(object:"' + $rootScope.project + '", time_start:"' + time_start + '", time_end:"' + time_end + '", timezone:"' + sysClock.getTimeZone() + '") { ' +
'module ' +
'p_avg ' +
'} ' +
'}'
};
$http({
method: 'POST',
url: CONFIG.APP_API,
data: request,
headers: authHeader
}).then(
(response) => { // resolve
response.data.data.power_module.forEach(module => {
total += (module.p_avg?module.p_avg:0);
});
console.log(total);
if(total) {
response.data.data.power_module.forEach(module => {
power_module.data.push({
name: module.module,
value: (module.p_avg?module.p_avg:0),
y: ((module.p_avg?(module.p_avg/total):0))*100
});
});
} else {
power_module.data.push({name: 'none',y: 100});
}
console.log(power_module.data);
chart_power_pie.addSeries(power_module);
console.log('resp');
resolve(null);
},(error) => { // failure
console.error(error);
}
);
});
});
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
const chart_add_events = (time_start, time_end) => {
console.log('chart_add_events');
return new Promise((resolve) => {
let event_series = {
name: 'events data',
borderWidth: 0.2,
borderColor: '#ffffff',
colsize: 86400000, // one day
data: [],
dataLabels: {
enabled: false, // <-- show number of events
}
};
authService.getJWTAuth().then(authHeader => {
var request = {'query':
'query { ' +
'event_daily(object:"' + $rootScope.project + '", time_start:"' + time_start + '", time_end:"' + time_end + '", timezone:"' + sysClock.getTimeZone() + '") { ' +
'step ' +
'epoch ' +
'total ' +
'notice ' +
'warning ' +
'alert ' +
'} ' +
'}'
};
$http({
method: 'POST',
url: CONFIG.APP_API,
data: request,
headers: authHeader
}).then(
(response) => { // resolve
console.log('response', response);
let total = 0;
let max_total = 0;
response.data.data.event_daily.forEach(day => {
total = (day.total?day.total:0);
console.log('total: ' + total);
max_total = total>max_total?total:max_total;
event_series.data.push([
parseInt(day.epoch),
0,
total
]);
});
chart_events_heatmap.addSeries(event_series);
console.log('max_total: ' + max_total);
console.log(chart_events_heatmap.colorAxis)
if(max_total == 0) {
chart_events_heatmap.colorAxis[0].update({
min: 0,
minColor: 'transparent',
maxColor: 'transparent'
});
}
resolve(null);
},(error) => { // failure
console.error(error);
}
);
});
});
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CHARTS: Power Consumption + Pie
var chart_powertemp_consumption = null; // chart object
var chart_power_pie = null; // chart object
var chart_events_heatmap = null; // chart object
const create_chart_objects = () => {
const obj_chart_powertemp = new Promise((resolve, reject) => {
new Highcharts.Chart({
chart: {
renderTo: 'chart_powertemp',
height: 200,
minHeight: 200,
borderWidth: 0,
marginTop: 0,
marginRight: 0,
marginLeft: 0,
marginBottom: 0,
spacingLeft: 0,
spacingRight: 0,
spacingBottom: 0,
spacingTop: 0,
backgroundColor: 'transparent',
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
},
time: {
useUTC: true
},
title: {
text: null
},
subtitle: {
text: null
},
exporting: {
enabled: false
},
credits: {
enabled: false
},
legend: {
enabled: false
},
accessibility: {
announceNewData: {
enabled: true
}
},
xAxis: {
type: 'datetime',
tickInterval: 86400000, // 24 * 3600 * 1000 = 1 day
},
yAxis: [{ // Power Consumption
labels: {
format: '{value}kWh',
style: {
color: Highcharts.getOptions().colors[0]
}
},
title: {
text: 'Power Consumption',
style: {
color: Highcharts.getOptions().colors[0]
}
},
gridLineWidth: 0,
min: 0,
minRange: 2
}],
tooltip: {
shared: true,
outside: true,
useHTML: true,
backgroundColor: '#fff',
borderWidth: 0
},
plotOptions: {
column: {
stacking: 'normal',
pointPadding: 0,
borderWidth: 0,
dataLabels: {
enabled: false
}
},
series: {
cursor: 'pointer',
pointPadding: 0.07,
groupPadding: 0.07,
borderWidth: 0.07,
minPointLength: 3,
shadow: false,
dataLabels: {
enabled: false
},
marker: {
enabled: false
},
}
},
series: []
}, (chart) => {
chart_powertemp_consumption = chart;
resolve();
});
});
const obj_chart_power_pie = new Promise((resolve, reject) => {
new Highcharts.Chart({
chart: {
type: 'pie',
renderTo: 'chart_power_pie',
height: 200,
borderWidth: 0,
marginTop: 0,
marginRight: 0,
marginLeft: 0,
marginBottom: 0,
spacingLeft: 0,
spacingRight: 0,
spacingBottom: 0,
spacingTop: 0,
backgroundColor: 'transparent',
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
},
time: {useUTC: true},
title: {text: null},
subtitle: {text: null},
legend: {enabled: true},
exporting: {enabled: false},
credits: {enabled: false},
plotOptions: {
pie: {
borderRadius: 5,
borderWidth: 0,
colors: chart_power_consumption_pie_colors,
dataLabels: {
enabled: false,
},
center: ['50%', '50%']
},
series: {
dataSorting: {
enabled: true
},
innerSize: '50%',
dataLabels: {
enabled: false,
format: '{point.name}: {point.y:.1f}%'
}
}
},
tooltip: {
//pointFormat: '{series.name}: {point.percentage:.1f}%'
headerFormat: null,
pointFormat: '{point.name}: {point.y:.2f}% of total Energy Consumption
',
backgroundColor: '#fff'
},
series: []
}, function(chart){
chart_power_pie = chart;
resolve();
});
});
const obj_chart_events_heatmap = new Promise((resolve, reject) => {
new Highcharts.Chart({
chart: {
type: 'heatmap',
renderTo: 'chart_events',
height: 15,
borderWidth: 0,
marginTop: 0,
marginRight: 0,
marginLeft: 0,
marginBottom: 0,
spacingLeft: 0,
spacingRight: 0,
spacingBottom: 0,
spacingTop: 0,
backgroundColor: 'transparent',
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
events: {
addSeries: function () {
/*
var label = this.renderer.label('A series was added, about to redraw chart', 100, 120)
.attr({
fill: Highcharts.getOptions().colors[0],
padding: 10,
r: 5,
zIndex: 8
})
.css({
color: '#FFFFFF'
})
.add();
setTimeout(function () {
label.fadeOut();
}, 1000);
*/
}/*
addSeries: function() {
console.log('----------------------------------------------');
console.log('chart_events_heatmap fn:addSeries:');
console.log('series count:', this.series.length);
if(this.series.length) {
this.series[0].data.forEach(element => {
console.log(element.value);
if(element.value == 0) {
element.update({color: 'transparent'});
}
});
}
}
*/
}
},
time: {
useUTC: true
},
title: {
text: null
},
subtitle: {
text: null
},
tooltip: {
enabled: false
},
exporting: {
enabled: false
},
credits: {
enabled: false
},
legend: {
enabled: false
},
accessibility: {
announceNewData: {
enabled: true
}
},
xAxis: {
type: 'datetime',
tickInterval: 86400000, // 24 * 3600 * 1000 = 1 day
},
yAxis: {
categories: ['POWER'],
title: null,
minPadding: 0,
maxPadding: 0,
startOnTick: false,
endOnTick: false,
tickWidth: 1,
gridLineWidth: 0
},
colorAxis: {
min: 0,
stops: [
[0, '#27ae60'],
[0.0001, '#ffc312'],
[1, '#ea2027']
]
},
legend: {
enabled: false
},
plotOptions: {
heatmap: {
dataLabels: {
enabled: false
},
},
series: {
dataLabels: {
enabled: false
},
point: {
events: {
click: function(event) {
//link.redirect('#!/system/events', '/system/events/' + moment(this.x).format('YYYY-MM-DD'));
}
}
}
}
},
tooltip: {
outside: true,
useHTML: true,
backgroundColor: '#fff',
borderWidth: 0,
formatter: function () {
return ''+moment(this.point.x).format('ll') + '
' + this.point.value + ' events
';
}
},
series: []
}, function(chart){
chart_events_heatmap = chart;
resolve();
});
});
Promise.all([
obj_chart_powertemp,
obj_chart_power_pie,
obj_chart_events_heatmap
])
.then(() => {
console.log('Promise.all');
load_daily_data()
.then(() => {
$scope.loading_top_charts = false;
});
});
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////
}])
})();