Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add chart functionality to show sensors values for the past hour #18

Merged
merged 14 commits into from
Mar 31, 2022
13 changes: 13 additions & 0 deletions dashboard/chart.min.js

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions dashboard/chartjs-adapter-moment.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

142 changes: 142 additions & 0 deletions dashboard/dash-charts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
var tempChart = null;
var VOCChart = null;
var CO2Chart = null;
var PMChart = null;

function updateCharts(tempData, humidityData, VOCData, CO2Data, PM1Data, PM25Data, PM4Data, PM10Data) {
if (tempChart !== null && tempChart.ctx !== null) {
tempChart.data.datasets[0].data = tempData;
tempChart.data.datasets[1].data = humidityData;
tempChart.update();
}
if (VOCChart !== null && VOCChart.ctx !== null) {
VOCChart.data.datasets[0].data = VOCData;
VOCChart.update();
}
if (CO2Chart !== null && CO2Chart.ctx !== null) {
CO2Chart.data.datasets[0].data = CO2Data;
CO2Chart.update();
}
if (PMChart !== null && PMChart.ctx !== null) {
PMChart.data.datasets[0].data = PM1Data;
PMChart.data.datasets[1].data = PM25Data;
PMChart.data.datasets[2].data = PM4Data;
PMChart.data.datasets[3].data = PM10Data;
PMChart.update();
}
}

function showTempChart(tempData, humidityData) {
var datasets = [
{
label: 'Temperature (°C)',
data: tempData,
borderColor: 'orange',
backgroundColor: 'orange',
pointRadius: 0
},
{
label: 'Humidity (%)',
data: humidityData,
borderColor: '#608dc4',
backgroundColor: '#608dc4',
pointRadius: 0
}
]

tempChart = createChart($("#temperatureChart"), datasets);
}

function showVOCChart(VOCData) {
var datasets = [
{
label: 'Volatile Organic Compounds',
data: VOCData,
borderColor: 'green',
backgroundColor: 'green',
pointRadius: 0
}
]

VOCChart = createChart($("#VOCChart"), datasets);
}

function showCO2Chart(CO2Data) {
var datasets = [
{
label: 'CO2',
data: CO2Data,
borderColor: '#3d426b',
backgroundColor: '#3d426b',
pointRadius: 0
}
]

CO2Chart = createChart($("#CO2Chart"), datasets);
}

function showPMChart(PM1Data, PM25Data, PM4Data, PM10Data) {
var datasets = [
{
label: 'PM 1.0',
data: PM1Data,
borderColor: '#22eaaa',
backgroundColor: '#22eaaa',
pointRadius: 0
},
{
label: 'PM 2.5',
data: PM25Data,
borderColor: '#ffb174',
backgroundColor: '#ffb174',
pointRadius: 0
},
{
label: 'PM 4.0',
data: PM4Data,
borderColor: '#ee5a5a',
backgroundColor: '#ee5a5a',
pointRadius: 0
},
{
label: 'PM 10',
data: PM10Data,
borderColor: '#b31e6f',
backgroundColor: '#b31e6f',
pointRadius: 0
}
]

PMChart = createChart($("#PMChart"), datasets);
}

function createChart(chartElem, ds) {
return new Chart($(chartElem), {
type: 'line',
data: {
datasets: ds
},
options: {
scales: {
x: {
type: 'time',
time: {
unit: 'minute'
}
},
y: {
beginAtZero: true
}
}
}
});
}

function trimData(dataset, maxAge) {
let now = Date.now();
dataset.forEach(data => {
if(now - data[0].x > maxAge) {
data.shift();
}
});
}
122 changes: 82 additions & 40 deletions dashboard/dash.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
<link href="bootstrap.min.css" rel="stylesheet">

<script src="chroma.min.js"></script>
<script src="jquery.min.js"></script>
<script src="moment.min.js"></script>
<script src="chart.min.js"></script>
<script src="chartjs-adapter-moment.min.js"></script>
<script src="dash-charts.js"></script>

<style>
* {
Expand All @@ -34,87 +39,124 @@
background-color: #bbb;
border-radius: 10px;
}

#summary {
width: 100%;
height: 100%;
}

#temperatureChart, #VOCChart, #CO2Chart, #PMChart {
display: none;
}
</style>

<script type="text/javascript">
var vocColourScale = chroma.scale(['green', 'red']).domain([100, 500]).mode('lrgb').correctLightness();
var co2ColourScale = chroma.scale(['green', 'red']).domain([0, 2000]).mode('lrgb').correctLightness();

var tempData = [];
var humidityData = [];
var VOCData = [];
var CO2Data = [];
var PM1Data = [];
var PM25Data = [];
var PM4Data = [];
var PM10Data = [];

let socket = new WebSocket("ws://airquality:8765");

socket.onmessage = function(event) {
console.log(event.data);
dataObj = JSON.parse(event.data);
let time = Date.now();

// Populate temperature
if(dataObj.hasOwnProperty('thv')) {
document.getElementById("tempText").innerHTML = dataObj['thv']['temperature'];
$("#tempText").html(dataObj['thv']['temperature']);
tempData.push({'x': time, 'y': dataObj['thv']['temperature']});
} else {
document.getElementById("tempText").innerHTML = "--";
$("#tempText").html('--');
}

// Populate humidity
if(dataObj.hasOwnProperty('thv')) {
document.getElementById("humidityText").innerHTML = dataObj['thv']['humidity'];
$("#humidityText").html(dataObj['thv']['humidity']);
humidityData.push({'x': time, 'y': dataObj['thv']['humidity']});
} else {
document.getElementById("humidityText").innerHTML = "--";
$("#humidityText").html('--');
}

// Populate and colour VOC index
if(dataObj.hasOwnProperty('thv')) {
document.getElementById("vocText").innerHTML = dataObj['thv']['vocIndex'];
document.getElementById("vocMetric").style.backgroundColor = vocColourScale(dataObj['thv']['vocIndex']).hex();
$("#vocText").html(dataObj['thv']['vocIndex']);
$("#vocMetric").css('background-color', vocColourScale(dataObj['thv']['vocIndex']).hex());
VOCData.push({'x': time, 'y': dataObj['thv']['vocIndex']});
} else {
document.getElementById("vocText").innerHTML = "--";
document.getElementById("vocMetric").style.backgroundColor = '#bbb';
$("#vocText").html('--');
$("#vocMetric").css('background-color', '#bbb');
}

// Populate and colour CO2
if(dataObj.hasOwnProperty('co2')) {
document.getElementById("co2Text").innerHTML = dataObj['co2']['co2'];
document.getElementById("co2Metric").style.backgroundColor = co2ColourScale(dataObj['co2']['co2']).hex();
$("#co2Text").html(dataObj['co2']['co2']);
$("#co2Metric").css('background-color', co2ColourScale(dataObj['co2']['co2']).hex());
CO2Data.push({'x': time, 'y': dataObj['co2']['co2']});
} else {
document.getElementById("co2Text").innerHTML = "--";
document.getElementById("co2Metric").style.backgroundColor = '#bbb';
$("#co2Text").html("--");
$("#co2Metric").css('background-color', '#bbb');
}

if(dataObj.hasOwnProperty('pm')) {
document.getElementById("pm1Text").innerHTML = dataObj['pm']['pm1.0'];
document.getElementById("pm25Text").innerHTML = dataObj['pm']['pm2.5'];
document.getElementById("pm4Text").innerHTML = dataObj['pm']['pm4.0'];
document.getElementById("pm10Text").innerHTML = dataObj['pm']['pm10'];
$("#pm1Text").html(dataObj['pm']['pm1.0']);
$("#pm25Text").html(dataObj['pm']['pm2.5']);
$("#pm4Text").html(dataObj['pm']['pm4.0']);
$("#pm10Text").html(dataObj['pm']['pm10']);
PM1Data.push({'x': time, 'y': dataObj['pm']['pm1.0']});
PM25Data.push({'x': time, 'y': dataObj['pm']['pm2.5']});
PM4Data.push({'x': time, 'y': dataObj['pm']['pm4.0']});
PM10Data.push({'x': time, 'y': dataObj['pm']['pm10']});
} else {
document.getElementById("pm1Text").innerHTML = "--";
document.getElementById("pm25Text").innerHTML = "--";
document.getElementById("pm4Text").innerHTML = "--";
document.getElementById("pm10Text").innerHTML = "--";
$("#pm1Text").html('--');
$("#pm25Text").html('--');
$("#pm4Text").html('--');
$("#pm10Text").html('--');
}

// Keep only the last 1 hour of data
trimData([tempData, humidityData, VOCData, CO2Data, PM1Data, PM25Data, PM4Data, PM10Data], 3600000);

updateCharts(tempData, humidityData, VOCData, CO2Data, PM1Data, PM25Data, PM4Data, PM10Data);
}
</script>

<title>Websocket Data Test</title>
</head>
<body>
<div class="metric" id="tempRhMetric">
<h5>T & RH</h5>
<h1><span id="tempText"></span><small>°C</small></h1>
<h1><span id="humidityText"></span><small>%</small></h1>
</div>
<div class="metric" id="vocMetric">
<h5>VOC</h5>
<h1 id="vocText"></h1>
</div>
<div class="metric" id="co2Metric">
<h5>CO<sub>2</sub></h5>
<h1><span id="co2Text"></span><small>ppm</small></h1>
</div>
<div class="metric" id="pmMetric">
<h5><small>PM1.0</small> <span id="pm1Text"></span></h5>
<h5><small>PM2.5</small> <span id="pm25Text"></span></h5>
<h5><small>PM4.0</small> <span id="pm4Text"></span></h5>
<h5><small>PM10</small> <span id="pm10Text"></span></h5>
<div id='summary'>
<div onclick="$('#summary').hide(0); showTempChart(tempData, humidityData);" class="metric" id="tempRhMetric">
<h5>T & RH</h5>
<h1><span id="tempText"></span><small>°C</small></h1>
<h1><span id="humidityText"></span><small>%</small></h1>
</div>
<div onclick="$('#summary').hide(0); showVOCChart(VOCData);" class="metric" id="vocMetric">
<h5>VOC</h5>
<h1 id="vocText"></h1>
</div>
<div onclick="$('#summary').hide(0); showCO2Chart(CO2Data);" class="metric" id="co2Metric">
<h5>CO<sub>2</sub></h5>
<h1><span id="co2Text"></span><small>ppm</small></h1>
</div>
<div onclick="$('#summary').hide(0); showPMChart(PM1Data, PM25Data, PM4Data, PM10Data);" class="metric" id="pmMetric">
<h5><small>PM1.0</small> <span id="pm1Text"></span></h5>
<h5><small>PM2.5</small> <span id="pm25Text"></span></h5>
<h5><small>PM4.0</small> <span id="pm4Text"></span></h5>
<h5><small>PM10</small> <span id="pm10Text"></span></h5>
</div>
</div>
<canvas id='temperatureChart' width='320' height='240' onclick="$('#temperatureChart').hide(); tempChart.destroy(); $('#summary').fadeIn(250);"></canvas>
<canvas id='VOCChart' width='320' height='240' onclick="$('#VOCChart').hide(); VOCChart.destroy(); $('#summary').fadeIn(250);"></canvas>
<canvas id='CO2Chart' width='320' height='240' onclick="$('#CO2Chart').hide(); CO2Chart.destroy(); $('#summary').fadeIn(250);"></canvas>
<canvas id='PMChart' width='320' height='240' onclick="$('#PMChart').hide(); PMChart.destroy(); $('#summary').fadeIn(250);"></canvas>
<!-- Leave this at the bottom -->
<script src="bootstrap.bundle.min.js"></script>
</body>
</html>
</html>
17 changes: 9 additions & 8 deletions dashboard/debug.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<link href="bootstrap.min.css" rel="stylesheet">

<script src="chroma.min.js"></script>
<script src="jquery.min.js"></script>

<style>
* {
Expand Down Expand Up @@ -39,39 +40,39 @@
dataObj = JSON.parse(event.data);

if(dataObj.hasOwnProperty('hardwareId')) {
document.getElementById("hwid").innerHTML = dataObj['hardwareId'];
$("#hwid").html(dataObj['hardwareId']);
}

if(dataObj.hasOwnProperty('geohash')) {
document.getElementById("geohash").innerHTML = dataObj['geohash'];
$("#geohash").html(dataObj['geohash']);
}

debugData = dataObj['debug']

if(debugData.hasOwnProperty('appVersion')) {
document.getElementById("appVersion").innerHTML =debugData['appVersion'];
$("#appVersion").html(debugData['appVersion']);
}

if(debugData.hasOwnProperty('moduleVersion')) {
document.getElementById("moduleVersion").innerHTML = debugData['moduleVersion'];
$("#moduleVersion").html(debugData['moduleVersion']);
}

if(debugData.hasOwnProperty('throttle_state')) {
throttleData = debugData['throttle_state'];
document.getElementById("throttleState").innerHTML = throttleData['code'];
$("#throttleState").html(throttleData['code']);
if(throttleData.hasOwnProperty('status_strings')) {
document.getElementById("throttleStrings").innerHTML = throttleData['status_strings'];
$("#throttleStrings").html(throttleData['status_strings']);
}
}

if(debugData.hasOwnProperty('gpsStatus')) {
gpsData = debugData['gpsStatus'];
if(gpsData.hasOwnProperty('mode')) {
document.getElementById("gpsMode").innerHTML = gpsData['mode'];
$("#gpsMode").html(gpsData['mode']);
}

if(gpsData.hasOwnProperty('satellitesUsed')) {
document.getElementById("gpsSatellites").innerHTML = gpsData['satellitesUsed'];
$("#gpsSatellites").html(gpsData['satellitesUsed']);
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions dashboard/jquery.min.js

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions dashboard/moment.min.js

Large diffs are not rendered by default.