BangleApps/apps/awairmonitor/awair_to_bangle.html

674 lines
27 KiB
HTML
Raw Normal View History

2021-12-11 04:26:38 +00:00
<!DOCTYPE HTML>
<html>
<head>
2021-12-26 21:22:30 +00:00
<script src="https://puck-js.com/puck.js"></script>
<script type="text/javascript">
2021-12-26 20:33:39 +00:00
2021-12-26 21:22:30 +00:00
// Don't forget to enable the Local API on your Awair before using this
// https://support.getawair.com/hc/en-us/articles/360049221014-Awair-Local-API-Feature
2021-12-26 20:33:39 +00:00
2021-12-26 21:22:30 +00:00
const awair_name_1 = "Awair";
2021-12-26 20:33:39 +00:00
2021-12-26 21:22:30 +00:00
var bt_connection;
var is_connected = false;
var reconnect_counter = 5;
var reconnect_attempt_counter = 1;
var is_chart_started = false;
2021-12-26 20:33:39 +00:00
2021-12-26 21:22:30 +00:00
function initChart() {
var chart_co2;
var chart_voc;
var chart_pm;
var chart_temperature;
var chart_humidity;
var dataPoints_1 = [];
var posx = 0;
2021-12-26 20:33:39 +00:00
2021-12-26 21:22:30 +00:00
var awair_ip_1 = document.getElementById('inputawairip').value;
$.getJSON("http://"+awair_ip_1+"/air-data/latest", function(data) {
$.each(data, function(key, value){
if (dataPoints_1[key] === undefined) { dataPoints_1[key] = []; }
if (key === "temp" || key === "humid") { dataPoints_1[key].push({x: posx, y: parseFloat(value)}); }
else { dataPoints_1[key].push({x: posx, y: parseInt(value)}); }
});
2021-12-26 20:33:39 +00:00
2021-12-26 21:22:30 +00:00
posx++;
chart_co2 = new CanvasJS.Chart("chartContainer_co2",{
title:{ text:"CO2", fontFamily: "helvetica", fontColor: "#F7FAFC", fontSize: 16, horizontalAlign: "left", padding: { left: 30 } },
axisX:{ labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
axisY:{ minimum: 0, labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
legend: { fontColor: "#F7FAFC", horizontalAlign: "center", verticalAlign: "bottom" },
data: [ { type: "line", lineColor: "#6648FF", showInLegend: true, legendText: awair_name_1, dataPoints : dataPoints_1.co2 }]
});
chart_voc = new CanvasJS.Chart("chartContainer_voc",{
title:{ text:"VOC", fontFamily: "helvetica", fontColor: "#F7FAFC", fontSize: 16, horizontalAlign: "left", padding: { left: 30 } },
axisX:{ labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
axisY:{ minimum: 0, labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
legend: { fontColor: "#F7FAFC", horizontalAlign: "center", verticalAlign: "bottom" },
data: [ { type: "line", lineColor: "#6648FF", showInLegend: true, legendText: awair_name_1, dataPoints : dataPoints_1.voc }]
});
chart_pm = new CanvasJS.Chart("chartContainer_pm",{
title:{ text:"PM", fontFamily: "helvetica", fontColor: "#F7FAFC", fontSize: 16, horizontalAlign: "left", padding: { left: 30 } },
axisX:{ labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
axisY:{ minimum: 0, labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
legend: { fontColor: "#F7FAFC", horizontalAlign: "center", verticalAlign: "bottom" },
data: [ { type: "line", lineColor: "#6648FF", showInLegend: true, legendText: awair_name_1, dataPoints : dataPoints_1.pm25 }]
});
chart_humidity = new CanvasJS.Chart("chartContainer_humidity",{
title:{ text:"Humidity", fontFamily: "helvetica", fontColor: "#F7FAFC", fontSize: 16, horizontalAlign: "left", padding: { left: 30 } },
axisX:{ labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
axisY:{ labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
legend: { fontColor: "#F7FAFC", horizontalAlign: "center", verticalAlign: "bottom" },
data: [ { type: "line", lineColor: "#6648FF", showInLegend: true, legendText: awair_name_1, dataPoints : dataPoints_1.humid }]
});
chart_temperature = new CanvasJS.Chart("chartContainer_temperature",{
title:{ text:"Temperature", fontFamily: "helvetica", fontColor: "#F7FAFC", fontSize: 16, horizontalAlign: "left", padding: { left: 30 } },
axisX:{ labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
axisY:{ labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
legend: { fontColor: "#F7FAFC", horizontalAlign: "center", verticalAlign: "bottom" },
data: [ { type: "line", lineColor: "#6648FF", showInLegend: true, legendText: awair_name_1, dataPoints : dataPoints_1.temp }]
});
2021-12-26 20:33:39 +00:00
2021-12-26 21:22:30 +00:00
chart_co2.set("backgroundColor", "#1A202C");
chart_voc.set("backgroundColor", "#1A202C");
chart_pm.set("backgroundColor", "#1A202C");
chart_humidity.set("backgroundColor", "#1A202C");
chart_temperature.set("backgroundColor", "#1A202C");
2021-12-26 20:33:39 +00:00
2021-12-26 21:22:30 +00:00
updateChart();
});
2021-12-26 20:33:39 +00:00
2021-12-26 21:22:30 +00:00
function updateChart() {
$.getJSON("http://"+awair_ip_1+"/air-data/latest", function(data) {
$.each(data, function(key, value){
if (dataPoints_1[key] === undefined) { dataPoints_1[key] = []; }
if (key === "temp" || key === "humid") { dataPoints_1[key].push({x: posx, y: parseFloat(value)}); }
else { dataPoints_1[key].push({x: posx, y: parseInt(value)}); }
});
2021-12-26 20:33:39 +00:00
2021-12-26 21:22:30 +00:00
posx++;
chart_co2.render();
chart_voc.render();
chart_pm.render();
chart_temperature.render();
chart_humidity.render();
chart_co2.title.set("text", "CO2 level (ppm)");
chart_voc.title.set("text", "VOC level (ppb)");
chart_pm.title.set("text", "PM2.5 level (ug/m³)");
chart_humidity.title.set("text", "Humidity level (%)");
chart_temperature.title.set("text", "Temperature level (°C)");
let current_co2 = dataPoints_1['co2'][dataPoints_1['co2'].length-1].y;
let current_voc = dataPoints_1['voc'][dataPoints_1['voc'].length-1].y;
let current_pm25 = dataPoints_1['pm25'][dataPoints_1['pm25'].length-1].y;
let current_humi = dataPoints_1['humid'][dataPoints_1['humid'].length-1].y;
let current_temp = dataPoints_1['temp'][dataPoints_1['temp'].length-1].y;
let last_update = dataPoints_1['temp'].length-1;
2021-12-26 20:33:39 +00:00
2021-12-26 21:22:30 +00:00
if (is_connected && bt_connection && bt_connection.isOpen) {
bt_connection.write('\x10bt_current_co2='+current_co2+';bt_current_voc='+current_voc+';bt_current_pm25='+current_pm25+';bt_current_humi='+current_humi+';bt_current_temp='+current_temp+';bt_last_update='+last_update+';\n');
2021-12-26 20:33:39 +00:00
2021-12-26 21:22:30 +00:00
console.log("Sent data through Bluetooth");
} else if (is_connected && bt_connection && !bt_connection.isOpen) {
console.log("Disconnected - Next attempt to reconnect in " + reconnect_counter);
reconnect_counter--;
2021-12-26 20:33:39 +00:00
2021-12-26 21:22:30 +00:00
if (reconnect_counter <= 0) {
reconnect_counter = 10 * reconnect_attempt_counter;
reconnect_attempt_counter++;
2021-12-26 20:33:39 +00:00
2021-12-26 21:22:30 +00:00
console.log("Trying to reconnect");
bt_connection.reconnect(function(c) {
console.log("Reconnect callback");
if (!c) {
console.log("Couldn't reconnect");
return;
}
bt_connection = c;
is_connected = true;
reconnect_attempt_counter = 1;
});
}
}
setTimeout(function(){updateChart()}, 1000);
});
}
}
2021-12-26 20:33:39 +00:00
2021-12-26 21:22:30 +00:00
function connectBT() {
console.log("Connect BT");
Puck.connect(function(c) {
console.log("Connect callback");
if (!c) {
console.log("Couldn't connect");
return;
}
bt_connection = c;
is_connected = true;
reconnect_attempt_counter = 1;
if (!is_chart_started) {
initChart();
is_chart_started = true;
}
});
}
function disconnectBT() {
console.log("Disconnect Bluetooth button pressed. bt_connection value below.")
console.log(bt_connection);
if (is_connected && bt_connection) {
bt_connection.close();
is_connected = false;
console.log("Closed Bluetooth connection");
}
}
</script>
<script type="text/javascript" src="https://canvasjs.com/assets/script/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
</head>
<body style="background-color:#1A202C;">
<p style="color: #F7FAFC">
<b>How to use</b>
<br><br>
Step 1: Enable the Local API on your Awair: https://support.getawair.com/hc/en-us/articles/360049221014-Awair-Local-API-Feature
<br><br>
Step 2: Launch the Awair Monitor app on your BangleJS
<br><br>
Step 3: Input your Awair IP address and click the Connect button:
<input type="text" id="inputawairip" value="192.168.2.1">
<input type="button" value="Connect BangleJS" onclick="connectBT();">
<br><br>
Step 4: Optionally, open the web inspector's console (Right click &gt; Inspector &gt; Console) to read the Bluetooth logs
<br><br>
Step 5: Once you are done, click the Disconnect button to properly close the Blutooth connection
<center><button onclick="disconnectBT();">Disconnect BangleJS</button></center>
</p>
<br/><br/>
<div id="chartContainer_co2" style="height: 300px; max-width: 920px; margin: 0px auto; margin-bottom: 64px;"></div>
<div id="chartContainer_voc" style="height: 300px; max-width: 920px; margin: 0px auto; margin-bottom: 64px;"></div>
<div id="chartContainer_pm" style="height: 300px; max-width: 920px; margin: 0px auto; margin-bottom: 64px;"></div>
<div id="chartContainer_humidity" style="height: 300px; max-width: 920px; margin: 0px auto; margin-bottom: 64px;"></div>
<div id="chartContainer_temperature" style="height: 300px; max-width: 920px; margin: 0px auto; margin-bottom: 64px;"></div>
</body>
</html>(buf));
2021-12-26 20:33:39 +00:00
}
function str2ab(str) {
var buf = new ArrayBuffer(str.length);
var bufView = new Uint8Array(buf);
for (var i=0, strLen=str.length; i<strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
function handleQueue() {
if (!queue.length) return;
var q = queue.shift();
log(3,"Executing "+JSON.stringify(q)+" from queue");
if (q.type == "write") puck.write(q.data, q.callback, q.callbackNewline);
else log(1,"Unknown queue item "+JSON.stringify(q));
}
function connect(callback) {
if (!checkIfSupported()) return;
var connection = {
on : function(evt,cb) { this["on"+evt]=cb; },
emit : function(evt,data) { if (this["on"+evt]) this["on"+evt](data); },
isOpen : false,
isOpening : true,
txInProgress : false
};
var btServer = undefined;
var btService;
var connectionDisconnectCallback;
var txCharacteristic;
var rxCharacteristic;
var txDataQueue = [];
var flowControlXOFF = false;
var chunkSize = DEFAULT_CHUNKSIZE;
connection.close = function() {
connection.isOpening = false;
if (connection.isOpen) {
connection.isOpen = false;
connection.emit('close');
} else {
if (callback) callback(null);
}
if (btServer) {
btServer.disconnect();
btServer = undefined;
txCharacteristic = undefined;
rxCharacteristic = undefined;
chunkSize = DEFAULT_CHUNKSIZE;
}
};
connection.write = function(data, callback) {
if (data) txDataQueue.push({data:data,callback:callback,maxLength:data.length});
if (connection.isOpen && !connection.txInProgress) writeChunk();
function writeChunk() {
if (flowControlXOFF) { // flow control - try again later
setTimeout(writeChunk, 50);
return;
}
var chunk;
if (!txDataQueue.length) {
puck.writeProgress();
return;
}
var txItem = txDataQueue[0];
puck.writeProgress(txItem.maxLength - txItem.data.length, txItem.maxLength);
if (txItem.data.length <= chunkSize) {
chunk = txItem.data;
txItem.data = undefined;
} else {
chunk = txItem.data.substr(0,chunkSize);
txItem.data = txItem.data.substr(chunkSize);
}
connection.txInProgress = true;
log(2, "Sending "+ JSON.stringify(chunk));
txCharacteristic.writeValue(str2ab(chunk)).then(function() {
log(3, "Sent");
if (!txItem.data) {
txDataQueue.shift(); // remove this element
if (txItem.callback)
txItem.callback();
}
connection.txInProgress = false;
writeChunk();
}).catch(function(error) {
log(1, 'SEND ERROR: ' + error);
txDataQueue = [];
connection.close();
});
}
};
navigator.bluetooth.requestDevice({
filters:[
{ namePrefix: 'Puck.js' },
{ namePrefix: 'Pixl.js' },
{ namePrefix: 'MDBT42Q' },
{ namePrefix: 'RuuviTag' },
{ namePrefix: 'iTracker' },
{ namePrefix: 'Thingy' },
{ namePrefix: 'Espruino' },
{ services: [ NORDIC_SERVICE ] }
], optionalServices: [ NORDIC_SERVICE ]}).then(function(device) {
log(1, 'Device Name: ' + device.name);
log(1, 'Device ID: ' + device.id);
// Was deprecated: Should use getPrimaryServices for this in future
//log('BT> Device UUIDs: ' + device.uuids.join('\n' + ' '.repeat(21)));
device.addEventListener('gattserverdisconnected', function() {
log(1, "Disconnected (gattserverdisconnected)");
connection.close();
});
connection.device = device;
connection.reconnect(callback);
}).catch(function(error) {
log(1, 'ERROR: ' + error);
connection.close();
});
connection.reconnect = function(callback) {
connection.device.gatt.connect().then(function(server) {
log(1, "Connected");
btServer = server;
return server.getPrimaryService(NORDIC_SERVICE);
}).then(function(service) {
log(2, "Got service");
btService = service;
return btService.getCharacteristic(NORDIC_RX);
}).then(function (characteristic) {
rxCharacteristic = characteristic;
log(2, "RX characteristic:"+JSON.stringify(rxCharacteristic));
rxCharacteristic.addEventListener('characteristicvaluechanged', function(event) {
var dataview = event.target.value;
var data = ab2str(dataview.buffer);
if (data.length > chunkSize) {
log(2, "Received packet of length "+data.length+", increasing chunk size");
chunkSize = data.length;
}
if (puck.flowControl) {
for (var i=0;i<data.length;i++) {
var ch = data.charCodeAt(i);
var remove = true;
if (ch==19) {// XOFF
log(2,"XOFF received => pause upload");
flowControlXOFF = true;
} else if (ch==17) {// XON
log(2,"XON received => resume upload");
flowControlXOFF = false;
} else
remove = false;
if (remove) { // remove character
data = data.substr(0,i-1)+data.substr(i+1);
i--;
}
}
}
log(3, "Received "+JSON.stringify(data));
connection.emit('data', data);
});
return rxCharacteristic.startNotifications();
}).then(function() {
return btService.getCharacteristic(NORDIC_TX);
}).then(function (characteristic) {
txCharacteristic = characteristic;
log(2, "TX characteristic:"+JSON.stringify(txCharacteristic));
}).then(function() {
connection.txInProgress = false;
connection.isOpen = true;
connection.isOpening = false;
isBusy = false;
queue = [];
callback(connection);
connection.emit('open');
// if we had any writes queued, do them now
connection.write();
}).catch(function(error) {
log(1, 'ERROR: ' + error);
connection.close();
});
};
return connection;
};
// ----------------------------------------------------------
var connection;
/* convenience function... Write data, call the callback with data:
callbackNewline = false => if no new data received for ~0.2 sec
callbackNewline = true => after a newline */
function write(data, callback, callbackNewline) {
if (!checkIfSupported()) return;
let result;
/// If there wasn't a callback function, then promisify
if (typeof callback !== 'function') {
callbackNewline = callback;
result = new Promise((resolve, reject) => callback = (value, err) => {
if (err) reject(err);
else resolve(value);
});
}
if (isBusy) {
log(3, "Busy - adding Puck.write to queue");
queue.push({type:"write", data:data, callback:callback, callbackNewline:callbackNewline});
return result;
}
var cbTimeout;
function onWritten() {
if (callbackNewline) {
connection.cb = function(d) {
var newLineIdx = connection.received.indexOf("\n");
if (newLineIdx>=0) {
var l = connection.received.substr(0,newLineIdx);
connection.received = connection.received.substr(newLineIdx+1);
connection.cb = undefined;
if (cbTimeout) clearTimeout(cbTimeout);
cbTimeout = undefined;
if (callback)
callback(l);
isBusy = false;
handleQueue();
}
};
}
// wait for any received data if we have a callback...
var maxTime = 300; // 30 sec - Max time we wait in total, even if getting data
var dataWaitTime = callbackNewline ? 100/*10 sec if waiting for newline*/ : 3/*300ms*/;
var maxDataTime = dataWaitTime; // max time we wait after having received data
cbTimeout = setTimeout(function timeout() {
cbTimeout = undefined;
if (maxTime) maxTime--;
if (maxDataTime) maxDataTime--;
if (connection.hadData) maxDataTime=dataWaitTime;
if (maxDataTime && maxTime) {
cbTimeout = setTimeout(timeout, 100);
} else {
connection.cb = undefined;
if (callback)
callback(connection.received);
isBusy = false;
handleQueue();
connection.received = "";
}
connection.hadData = false;
}, 100);
}
if (connection && (connection.isOpen || connection.isOpening)) {
if (!connection.txInProgress) connection.received = "";
isBusy = true;
connection.write(data, onWritten);
return result
}
connection = connect(function(puck) {
if (!puck) {
connection = undefined;
if (callback) callback(null);
return;
}
connection.received = "";
connection.on('data', function(d) {
connection.received += d;
connection.hadData = true;
if (connection.cb) connection.cb(d);
});
connection.on('close', function(d) {
connection = undefined;
});
isBusy = true;
connection.write(data, onWritten);
});
return result
}
// ----------------------------------------------------------
var puck = {
/// Are we writing debug information? 0 is no, 1 is some, 2 is more, 3 is all.
debug : 1,
/// Should we use flow control? Default is true
flowControl : true,
/// Used internally to write log information - you can replace this with your own function
log : function(level, s) { if (level <= this.debug) console.log("<BLE> "+s)},
/// Called with the current send progress or undefined when done - you can replace this with your own function
writeProgress : function (charsSent, charsTotal) {
//console.log(charsSent + "/" + charsTotal);
},
/** Connect to a new device - this creates a separate
connection to the one `write` and `eval` use. */
connect : connect,
/// Write to Puck.js and call back when the data is written. Creates a connection if it doesn't exist
write : write,
/// Evaluate an expression and call cb with the result. Creates a connection if it doesn't exist
eval : function(expr, cb) {
const response = write('\x10Bluetooth.println(JSON.stringify(' + expr + '))\n', true)
.then(function (d) {
try {
return JSON.parse(d);
} catch (e) {
log(1, "Unable to decode " + JSON.stringify(d) + ", got " + e.toString());
return Promise.reject(d);
}
});
if (cb) {
return void response.then(cb, (err) => cb(null, err));
} else {
return response;
}
},
/// Write the current time to the Puck
setTime : function(cb) {
var d = new Date();
var cmd = 'setTime('+(d.getTime()/1000)+');';
// in 1v93 we have timezones too
cmd += 'if (E.setTimeZone) E.setTimeZone('+d.getTimezoneOffset()/-60+');\n';
write(cmd, cb);
},
/// Did `write` and `eval` manage to create a connection?
isConnected : function() {
return connection!==undefined;
},
/// get the connection used by `write` and `eval`
getConnection : function() {
return connection;
},
/// Close the connection used by `write` and `eval`
close : function() {
if (connection)
connection.close();
},
/** Utility function to fade out everything on the webpage and display
a window saying 'Click to continue'. When clicked it'll disappear and
'callback' will be called. This is useful because you can't initialise
Web Bluetooth unless you're doing so in response to a user input.*/
modal : function(callback) {
var e = document.createElement('div');
e.style = 'position:absolute;top:0px;left:0px;right:0px;bottom:0px;opacity:0.5;z-index:100;background:black;';
e.innerHTML = '<div style="position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);font-family: Sans-Serif;font-size:400%;color:white;">Click to Continue...</div>';
e.onclick = function(evt) {
callback();
evt.preventDefault();
document.body.removeChild(e);
};
document.body.appendChild(e);
}
};
return puck;
}));
</script>
2021-12-11 04:26:38 +00:00
<script type="text/javascript">
// Don't forget to enable the Local API on your Awair before using this
// https://support.getawair.com/hc/en-us/articles/360049221014-Awair-Local-API-Feature
const awair_name_1 = "Awair";
var bt_connection;
var is_connected = false;
var reconnect_counter = 5;
var reconnect_attempt_counter = 1;
2021-12-26 20:33:39 +00:00
var is_chart_started = false;
2021-12-11 04:26:38 +00:00
2021-12-26 20:00:22 +00:00
function initChart() {
2021-12-11 04:26:38 +00:00
var chart_co2;
var chart_voc;
var chart_pm;
var chart_temperature;
var chart_humidity;
var dataPoints_1 = [];
var posx = 0;
2021-12-26 20:00:22 +00:00
var awair_ip_1 = document.getElementById('inputawairip').value;
2021-12-11 04:26:38 +00:00
$.getJSON("http://"+awair_ip_1+"/air-data/latest", function(data) {
$.each(data, function(key, value){
if (dataPoints_1[key] === undefined) { dataPoints_1[key] = []; }
if (key === "temp" || key === "humid") { dataPoints_1[key].push({x: posx, y: parseFloat(value)}); }
else { dataPoints_1[key].push({x: posx, y: parseInt(value)}); }
});
posx++;
chart_co2 = new CanvasJS.Chart("chartContainer_co2",{
title:{ text:"CO2", fontFamily: "helvetica", fontColor: "#F7FAFC", fontSize: 16, horizontalAlign: "left", padding: { left: 30 } },
axisX:{ labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
axisY:{ minimum: 0, labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
legend: { fontColor: "#F7FAFC", horizontalAlign: "center", verticalAlign: "bottom" },
data: [ { type: "line", lineColor: "#6648FF", showInLegend: true, legendText: awair_name_1, dataPoints : dataPoints_1.co2 }]
});
chart_voc = new CanvasJS.Chart("chartContainer_voc",{
title:{ text:"VOC", fontFamily: "helvetica", fontColor: "#F7FAFC", fontSize: 16, horizontalAlign: "left", padding: { left: 30 } },
axisX:{ labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
axisY:{ minimum: 0, labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
legend: { fontColor: "#F7FAFC", horizontalAlign: "center", verticalAlign: "bottom" },
data: [ { type: "line", lineColor: "#6648FF", showInLegend: true, legendText: awair_name_1, dataPoints : dataPoints_1.voc }]
});
chart_pm = new CanvasJS.Chart("chartContainer_pm",{
title:{ text:"PM", fontFamily: "helvetica", fontColor: "#F7FAFC", fontSize: 16, horizontalAlign: "left", padding: { left: 30 } },
axisX:{ labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
axisY:{ minimum: 0, labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
legend: { fontColor: "#F7FAFC", horizontalAlign: "center", verticalAlign: "bottom" },
data: [ { type: "line", lineColor: "#6648FF", showInLegend: true, legendText: awair_name_1, dataPoints : dataPoints_1.pm25 }]
});
chart_humidity = new CanvasJS.Chart("chartContainer_humidity",{
title:{ text:"Humidity", fontFamily: "helvetica", fontColor: "#F7FAFC", fontSize: 16, horizontalAlign: "left", padding: { left: 30 } },
axisX:{ labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
axisY:{ labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
legend: { fontColor: "#F7FAFC", horizontalAlign: "center", verticalAlign: "bottom" },
data: [ { type: "line", lineColor: "#6648FF", showInLegend: true, legendText: awair_name_1, dataPoints : dataPoints_1.humid }]
});
chart_temperature = new CanvasJS.Chart("chartContainer_temperature",{
title:{ text:"Temperature", fontFamily: "helvetica", fontColor: "#F7FAFC", fontSize: 16, horizontalAlign: "left", padding: { left: 30 } },
axisX:{ labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
axisY:{ labelFontColor: "#F7FAFC", gridColor: "#2D3748", lineColor: "#2D3748", tickColor: "#2D3748" },
legend: { fontColor: "#F7FAFC", horizontalAlign: "center", verticalAlign: "bottom" },
data: [ { type: "line", lineColor: "#6648FF", showInLegend: true, legendText: awair_name_1, dataPoints : dataPoints_1.temp }]
});
chart_co2.set("backgroundColor", "#1A202C");
chart_voc.set("backgroundColor", "#1A202C");
chart_pm.set("backgroundColor", "#1A202C");
chart_humidity.set("backgroundColor", "#1A202C");
chart_temperature.set("backgroundColor", "#1A202C");
updateChart();
});
function updateChart() {
$.getJSON("http://"+awair_ip_1+"/air-data/latest", function(data) {
$.each(data, function(key, value){
if (dataPoints_1[key] === undefined) { dataPoints_1[key] = []; }
if (key === "temp" || key === "humid") { dataPoints_1[key].push({x: posx, y: parseFloat(value)}); }
else { dataPoints_1[key].push({x: posx, y: parseInt(value)}); }
});
posx++;
chart_co2.render();
chart_voc.render();
chart_pm.render();
chart_temperature.render();
chart_humidity.render();
chart_co2.title.set("text", "CO2 level (ppm)");
chart_voc.title.set("text", "VOC level (ppb)");
chart_pm.title.set("text", "PM2.5 level (ug/m³)");
chart_humidity.title.set("text", "Humidity level (%)");
chart_temperature.title.set("text", "Temperature level (°C)");
let current_co2 = dataPoints_1['co2'][dataPoints_1['co2'].length-1].y;
let current_voc = dataPoints_1['voc'][dataPoints_1['voc'].length-1].y;
let current_pm25 = dataPoints_1['pm25'][dataPoints_1['pm25'].length-1].y;
let current_humi = dataPoints_1['humid'][dataPoints_1['humid'].length-1].y;
let current_temp = dataPoints_1['temp'][dataPoints_1['temp'].length-1].y;
let last_update = dataPoints_1['temp'].length-1;
2021-12-26 20:33:39 +00:00
2021-12-26 20:00:22 +00:00
if (is_connected && bt_connection && bt_connection.isOpen) {
2021-12-26 21:22:30 +00:00
bt_connection.write('\x10bt_current_co2='+current_co2+';bt_current_voc='+current_voc+';bt_current_pm25='+current_pm25+';bt_current_humi='+current_humi+';bt_current_temp='+current_temp+';bt_