2016-01-24 17:37:32 +01:00
|
|
|
///////////////////////////////// Autostart
|
|
|
|
|
$(function(){
|
|
|
|
|
$(".toggle-switch").bootstrapSwitch();
|
|
|
|
|
|
|
|
|
|
$(".timestamp").relTimestamp();
|
|
|
|
|
});
|
2016-01-22 15:46:09 +01:00
|
|
|
|
2017-03-16 17:01:49 +01:00
|
|
|
////////////////////////////////////// JQuery helper functions
|
2016-01-24 17:37:32 +01:00
|
|
|
|
|
|
|
|
// $.attr() # returns all attributes of an element
|
2016-01-18 13:09:28 +01:00
|
|
|
(function(old) {
|
|
|
|
|
$.fn.attr = function() {
|
|
|
|
|
if(arguments.length === 0) {
|
|
|
|
|
if(this.length === 0) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var obj = {};
|
|
|
|
|
$.each(this[0].attributes, function() {
|
|
|
|
|
if(this.specified) {
|
|
|
|
|
obj[this.name] = this.value;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return old.apply(this, arguments);
|
|
|
|
|
};
|
2016-01-22 15:46:09 +01:00
|
|
|
})($.fn.attr);
|
|
|
|
|
|
2016-05-25 20:30:40 +02:00
|
|
|
// converts all timestamps to human readable time and date
|
2016-01-24 17:37:32 +01:00
|
|
|
$.fn.relTimestamp = function() {
|
|
|
|
|
return this.each(function() {
|
|
|
|
|
var timestamp = parseInt($(this).text());
|
|
|
|
|
var timestampNow = Date.now();
|
|
|
|
|
var timeDiff = timestampNow - timestamp;
|
2016-01-22 15:46:09 +01:00
|
|
|
|
2016-01-25 16:20:16 +01:00
|
|
|
if(timeDiff < 10 * 60 * 1000) // less than 10 min
|
|
|
|
|
$(this).text(moment(timestamp).fromNow());
|
|
|
|
|
else if(timeDiff < 24 * 60 * 60 * 1000) // less than 24 hours
|
2016-01-25 09:54:57 +01:00
|
|
|
$(this).text(moment(timestamp).fromNow() + " ("+moment(timestamp).format("HH:mm")+")");
|
2016-01-24 17:37:32 +01:00
|
|
|
else
|
|
|
|
|
$(this).text(moment(timestamp).format("YYYY-MM-DD HH:mm"));
|
|
|
|
|
return this;
|
|
|
|
|
});
|
|
|
|
|
};
|
2016-11-28 17:11:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////// Hal functions
|
|
|
|
|
|
|
|
|
|
////////////// Chart functions
|
|
|
|
|
function createChart(elementId, url, updateTime=-1){
|
|
|
|
|
var tickConf = {count: 20};
|
|
|
|
|
if (updateTime < 60*60*1000)
|
|
|
|
|
tickConf['format'] = '%H:%M';
|
|
|
|
|
else if (updateTime < 24*60*60*1000)
|
|
|
|
|
tickConf['format'] = '%Y-%m-%d %H:%M';
|
|
|
|
|
else
|
|
|
|
|
tickConf['format'] = '%Y-%m-%d';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var chart = c3.generate({
|
|
|
|
|
bindto: elementId,
|
|
|
|
|
data: {json: []}, // set empty data, data will be loaded later
|
|
|
|
|
axis : {
|
|
|
|
|
x : {
|
|
|
|
|
type : 'timeseries',
|
|
|
|
|
label: 'Timestamp',
|
|
|
|
|
tick: tickConf,
|
|
|
|
|
},
|
|
|
|
|
y: {
|
|
|
|
|
label: 'Power (kWh)',
|
|
|
|
|
min: 0,
|
|
|
|
|
},
|
|
|
|
|
y2: {
|
|
|
|
|
show: true,
|
|
|
|
|
label: 'Temperature (C)',
|
|
|
|
|
min: 0,
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
grid: {
|
|
|
|
|
y: {show: true}
|
|
|
|
|
},
|
|
|
|
|
point: {
|
|
|
|
|
show: false
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2017-07-29 20:44:55 +02:00
|
|
|
updateChart(chart, url, updateTime);
|
|
|
|
|
$(window).focus(function(e) {
|
|
|
|
|
updateChart(chart, url);
|
|
|
|
|
});
|
2016-11-28 17:11:17 +01:00
|
|
|
}
|
2017-07-29 20:44:55 +02:00
|
|
|
function updateChart(chart, url, updateTime=-1){
|
|
|
|
|
console.log('Updating chart: '+chart.element.id);
|
2016-11-28 17:11:17 +01:00
|
|
|
$.getJSON(url, function(json){
|
|
|
|
|
chart.load(getChartData(json));
|
|
|
|
|
});
|
|
|
|
|
if (updateTime > 0)
|
|
|
|
|
setTimeout(function(){ updateChart(chart, url, updateTime); }, updateTime);
|
|
|
|
|
}
|
|
|
|
|
function getChartData(json){
|
|
|
|
|
var dataXaxis = {};
|
|
|
|
|
var dataYaxis = {};
|
|
|
|
|
var data = [];
|
|
|
|
|
var labels = [];
|
|
|
|
|
json.forEach(function(sensor, i) {
|
|
|
|
|
var index = 'data'+i;
|
|
|
|
|
labels[index] = sensor.user +": "+ sensor.name;
|
|
|
|
|
dataXaxis[index] = 'data'+i+'x';
|
|
|
|
|
data.push([index+'x'].concat(sensor.timestamps));
|
|
|
|
|
data.push([index].concat(sensor.data));
|
|
|
|
|
|
|
|
|
|
if (sensor.type == "PowerConsumptionSensorData")
|
|
|
|
|
dataYaxis[index] = 'y';
|
|
|
|
|
else //if (sensor.type == "TemperatureSensorData")
|
|
|
|
|
dataYaxis[index] = 'y2';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
xs: dataXaxis,
|
|
|
|
|
columns: data,
|
|
|
|
|
names: labels,
|
|
|
|
|
type: 'spline',
|
|
|
|
|
axes: dataYaxis,
|
2016-12-01 12:57:59 +01:00
|
|
|
unload: true,
|
2016-11-28 17:11:17 +01:00
|
|
|
};
|
2017-03-16 17:01:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////// Dynamic forms
|
|
|
|
|
var dynamicConf = {};
|
|
|
|
|
|
|
|
|
|
function initDynamicModalForm(modalId, formTemplateId, templateID){
|
|
|
|
|
// read in all configurations into global variable (to skip naming issues)
|
|
|
|
|
dynamicConf[formTemplateId] = [];
|
|
|
|
|
$("#"+templateID+" div").each(function(){
|
|
|
|
|
dynamicConf[formTemplateId][$(this).attr("id")] = $(this).html();
|
|
|
|
|
});
|
|
|
|
|
// Update dynamic inputs
|
|
|
|
|
$("#"+modalId+" select[name=type]").change(function(){
|
|
|
|
|
$("#"+modalId+" #"+formTemplateId).html(dynamicConf[formTemplateId][$(this).val()]);
|
|
|
|
|
});
|
|
|
|
|
// click event
|
|
|
|
|
$("#"+modalId).on('show.bs.modal', function (event) {
|
|
|
|
|
var button = $(event.relatedTarget);
|
|
|
|
|
var modal = $(this);
|
|
|
|
|
// Reset all inputs
|
|
|
|
|
modal.find("#"+formTemplateId).empty(); // clear form div
|
|
|
|
|
|
|
|
|
|
// select dynamic form
|
|
|
|
|
var selector = modal.find("select[name=type]");
|
|
|
|
|
selector.val(button.data("type"));
|
|
|
|
|
selector.change(); // Update dynamic inputs
|
|
|
|
|
// set dynamic form data
|
|
|
|
|
$.each(button.attr(), function(fieldName, value) {
|
|
|
|
|
if(fieldName.startsWith("data-")) {
|
|
|
|
|
fieldName = fieldName.substring(5);
|
|
|
|
|
// case insensitive search
|
|
|
|
|
input = modal.find("input").filter(function() {
|
|
|
|
|
return this.name.toLowerCase() == fieldName;
|
|
|
|
|
});
|
|
|
|
|
if (input.attr("type") == "checkbox") { // special handling for checkboxes
|
2017-04-01 00:19:18 +02:00
|
|
|
input.attr("value", "true");
|
2017-03-16 17:01:49 +01:00
|
|
|
if (value=="true") input.attr("checked", "true");
|
|
|
|
|
else input.removeAttr("checked");
|
|
|
|
|
// Add default false value as a unchecked checkbox is not included in the post
|
|
|
|
|
input.parent().prepend("<input type='hidden' name='"+input.attr("name")+"' value='false' />");
|
|
|
|
|
} else {
|
|
|
|
|
input.val(value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
2016-11-28 17:11:17 +01:00
|
|
|
}
|