Select Git revision
airqmon.js 6.47 KiB
var gauge = new Gauge($('#gauge')[0]);
var websock;
var timeseries = {};
var charts = {};
$(document).ready(function(event) {
setupGauge('staticZones');
//setupGauge('percentColors');
startWebsocket();
});
var metrics = {
"iaq": {name: "IAQ", has_accuracy: true, decimals: 0},
"siaq": {name: "Static IAQ", has_accuracy: true, decimals: 0},
"eco2": {name: "CO2", unit: " ppm", has_accuracy: true, decimals: 0},
"bvoc": {name: "Breath VOC", unit: " ppm", has_accuracy: true, decimals: 3},
"pm1": {name: "PM ≤1.0µm", unit: " μg/m³"},
"pm2p5": {name: "PM ≤2.5µm", unit: " μg/m³"},
"pm10": {name: "PM ≤10µm", unit: " μg/m³"},
"nc0p3": {name: "NC ≥0.3µm", unit: "/100cm³"},
"nc1": {name: "NC ≥0.5µm", unit: "/100cm³"},
"nc2p5": {name: "NC ≥1.0µm", unit: "/100cm³"},
"nc5": {name: "NC ≥5.0µm", unit: "/100cm³"},
"nc10": {name: "NC ≥10µm", unit: "/100cm³"},
"temperature": {name: "Temperature", unit: " °C", decimals: 1},
"humidity": {name: "Humidity", unit: "%", decimals: 1},
"pressure": {name: "Pressure", unit: " hPa", decimals: 0}
}
var accuracyStatus = {
0: {name: "Stabilizing", class: "danger"},
1: {name: "Uncertain", class: "warning"},
2: {name: "Calibrating", class: "primary"},
3: {name: "Calibrated", class: "success"}
}
var gaugeOptions = {
angle: 0, // The span of the gauge arc
lineWidth: 0.45, // The line thickness
radiusScale: 1, // Relative radius
pointer: {
length: 0.5, // // Relative to gauge radius
strokeWidth: 0.100, // The thickness
color: '#000000' // Fill color
},
colorStart: '#6F6EA0', // Colors
colorStop: '#C0C0DB', // just experiment with them
strokeColor: '#EEEEEE', // to see which ones work best for you
generateGradient: true,
highDpiSupport: true, // High resolution support
staticLabels: {
font: "10px sans-serif", // Specifies font
labels: [50, 100, 150, 200, 250, 350, 500], // Print labels at these values
color: "#000000", // Optional: Label text color
fractionDigits: 0 // Optional: Numerical precision. 0=round off.
}
};
var gaugeModes = {
staticZones: [
{strokeStyle: "#01E400", min: 0, max: 50}, // Bright Green
{strokeStyle: "#92D050", min: 51, max: 100}, // Green
{strokeStyle: "#FFFF00", min: 101, max: 150}, // Yellow
{strokeStyle: "#FF7E00", min: 151, max: 200}, // Orange
{strokeStyle: "#FF0000", min: 201, max: 250}, // Red
{strokeStyle: "#99004C", min: 251, max: 350}, // Violet
{strokeStyle: "#663300", min: 351, max: 500} // Brown
],
percentColors: [
[0.0, "#01E400" ],
[0.1, "#92D050" ],
[0.2, "#FFFF00"],
[0.3, "#FF7E00"],
[0.4, "#FF0000"],
[0.5, "#99004C"],
[0.7, "#663300"]
]
}
var chartOptions = {
responsive: true,
millisPerPixel: 100,
grid: {
fillStyle:'rgba(255,255,255, 1)',
strokeStyle:'rgba(128,128,128, 0.10)',
verticalSections: 5
},
labels: {
fillStyle:'rgba(0,0,0,0.75)'
}
}
var lineOptions = {
lineWidth: 2,
strokeStyle:'#00ff00'
}
function setupGauge(mode) {
var objColor = {}
objColor[mode] = gaugeModes[mode];
var opt = Object.assign(gaugeOptions, objColor);
gauge.setOptions(opt);
gauge.setMinValue(0);
gauge.maxValue = 500;
gauge.animationSpeed = 128;
gauge.set(0);
}
function startWebsocket() {
websock = new WebSocket('ws://' + window.location.hostname + ':81/');
websock.onopen = function(evt) {
console.log('websock open');
$('#wsSpinner').invisible();
};
websock.onclose = function(evt) {
console.log('websock close');
websock = null;
$('#wsSpinner').visible();
setTimeout(startWebsocket, 1000);
};
websock.onerror = function(evt) {
console.log(evt);
};
websock.onmessage = function(evt) {
data = JSON.parse(evt.data);
//console.log(data);
if (data !== null) {
handleWebsocketMessage(data);
}
};
}
function handleWebsocketMessage(data) {
if ('siaq' in data) {
gauge.set(data.siaq);
}
$.each(metrics, function(name, sensor) {
if ('has_accuracy' in metrics[name]) {
updateMetric(name, data[name], data[name+'_acc']);
} else {
updateMetric(name, data[name], false);
}
});
}
function updateMetric(name, value, accuracy) {
var numericValue = value;
if ('decimals' in metrics[name]) {
value = value.toFixed(metrics[name].decimals);
}
if ('unit' in metrics[name]) {
value += metrics[name].unit;
}
if (accuracy !== false && accuracy < 3) {
value = '<span class="badge bg-'+accuracyStatus[accuracy].class+'">'+accuracyStatus[accuracy].name+'</span> '+value;
}
if(!$('#metric_'+name).length && name in metrics) {
timeseries[name] = new TimeSeries();
timeseries[name].append(new Date().getTime(), numericValue);
var metric = $('<li class="list-group-item list-group-item-action" id="metric_'+name+'">'+
'<div class="row rowMetric">'+
'<div class="d-flex w-100 justify-content-between">'+
'<div class="sensorName">'+metrics[name].name+'</div>'+
'<div class="sensorValue">'+value+'</div>'+
'</div>'+
'</div>'+
'</li>)');
metric.find('.rowMetric').on('click', function() {
toggleChart(name);
});
$('#metrics').append(metric);
} else {
$('#metric_'+name+' .sensorValue').html(value);
timeseries[name].append(new Date().getTime(), numericValue);
}
}
function toggleChart(name) {
if(!$('#chart_'+name).length) {
charts[name] = new SmoothieChart(chartOptions);
charts[name].addTimeSeries(timeseries[name], lineOptions);
$('#metric_'+name).append($('<div class="row rowChart">'+
'<div class="chart mt-2"><canvas id="chart_'+name+'"></canvas></div>'+
'</div>'));
charts[name].streamTo(document.getElementById("chart_"+name), 1000);
} else {
charts[name].removeTimeSeries(timeseries[name]);
charts[name].stop();
delete charts[name];
$('#metric_'+name+' .rowChart').remove();
}
}
jQuery.fn.visible = function() {
return this.css('visibility', 'visible');
};
jQuery.fn.invisible = function() {
return this.css('visibility', 'hidden');
};