Green Ketonix SDK Examples
- Ketonix Green Software Development Kit
- USB - Simple Gauge Measure - Gauge
- USB - Gauge and Chart Measure - Gauge and Chart
- Bluetooth - Simple Gauge Measure - Gauge
- Bluetooth - Gauge and Chart Measure - Gauge and Chart
- WiFi - Gauge and Chart Measure - Gauge and Chart
Ketonix Green is built on a new platform with capabilities like USB, WiFi and Bluetooth connectivity.
We developed the firmware to be easy to interface and integrate with other systems.
In the different tabs on this page we have small examples of how to interface the device.
The examples use Web-USB, Web-Bluetooth technologies which is implemented in the Chrome browser. It makes it easy to create and distribute apps for the Ketonix using standard HTML.
To use the examples, one must first enable the features:
- To enable the features you type chrome://flags in the Chrome URL field and press enter.
- Search in flags for USB and enable the flag Automatic detection of WebUSB-compatible devices.
- Search in flags for Bluetooth and enable the flag Use the new permissions backend for Web Bluetooth.
Use the examples as they are, or download and modify the source as you like!
Enjoy!
Web-USB Simple Gauge
Click on the image to view a live example!
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://www.ketonix.com/sdk/js/ketonixDraw.js"></script>
</head>
<body>
<title>Ketonix Green Web-USB Gauge Example</title>
<center>
<p>Ketonix Green - Web-USB example Measure Breath Ketones.</b>
<p id="status"></p>
<form>
<table width="500" border="0">
<tr>
<td colspan="3" width="50%" align="center">
<canvas id="gauge-ppm"></canvas><br/>
<p id="display-value"></p><br/>
</td>
</tr>
<tr>
<td align="center">
<button id='startNotifications'>Connect</button>
</td>
<td align="center">
<button id='blink'>Blink</button>
</td>
<td align="center">
<button id="stopNotifications">Disconnect</button>
</td>
</tr>
</table>
</form>
</center>
<script>
var gauge = null;
var myPort = null;
var myReader = null;
var myReadableStreamClosed = null;
var isConnected = false;
var commandVerification = "OK";
var commandCallback = function(v) {};
var commandErrorCallback = function(v) {};
// Add eventhandlers
window.addEventListener('DOMContentLoaded', function() {
createGauge();
checkBrowser();
setButtonDisabled('startNotifications',false);
setButtonDisabled('blink',true);
setButtonDisabled('stopNotifications',true);
});
// Setup a callback when user clicks on "Connect"
document.querySelector('#startNotifications').addEventListener('click', function(event) {
event.stopPropagation();
event.preventDefault();
onStartButtonClick();
});
// Setup a callback when user clicks on "Disconnect"
document.querySelector('#stopNotifications').addEventListener('click', function(event) {
event.stopPropagation();
event.preventDefault();
onStopButtonClick();
});
document.querySelector('#blink').addEventListener('click', function(event) {
event.stopPropagation();
event.preventDefault();
writeToDevice("BLINK!","OK", function(v) {}, function(v) {});
});
function displayValue(v)
{
document.getElementById('display-value').innerHTML = v + " PPM";
}
// Check that browser is compatible, e.g Chrome
function checkBrowser()
{
var isChromium = window.chrome;
var winNav = window.navigator;
var vendorName = winNav.vendor;
var isOpera = typeof window.opr !== "undefined";
var isIEedge = winNav.userAgent.indexOf("Edge") > -1;
var isIOSChrome = winNav.userAgent.match("CriOS");
if (isIOSChrome) {
alert("Chrome on iOS is not supported");
} else if(isChromium !== null &&
typeof isChromium !== "undefined" &&
vendorName === "Google Inc." &&
isOpera === false &&
isIEedge === false
)
isChrome=true;
} else {
isChrome=false;
alert("You need to use the Chrome browser.");
}
if (/Chrome\/(\d+\.\d+.\d+.\d+)/.test(navigator.userAgent)){
if (48 > parseInt(RegExp.$1)) {
alert('Warning! Keep in mind this sample has been tested with Chrome ' + 48 + '.');
}
}
}
async function writeToDevice(command,success,cb_success,cb_error)
{
const textEncoder = new TextEncoderStream();
const writableStreamClosed = textEncoder.readable.pipeTo(myPort.writable);
const writer = textEncoder.writable.getWriter();
await writer.write(command);
await writer.close();
await writer.releaseLock();
commandVerification = success;
commandCallback = cb_success;
commandErrorCallback = cb_error;
}
// Enable/disable button
function setButtonDisabled(id,state)
{
document.getElementById(id).disabled = state;
}
class LineBreakTransformer {
constructor() {
this.container = '';
}
transform(chunk, controller) {
this.container += chunk;
const lines = this.container.split('\r\n');
this.container = lines.pop();
lines.forEach(line => controller.enqueue(line));
}
flush(controller) {
controller.enqueue(this.container);
}
}
function status(text)
{
document.getElementById("status").innerHTML = text;
}
// Called when user clicks on "Connect"
async function onStartButtonClick()
{
setButtonDisabled('startNotifications',true);
setButtonDisabled('stopNotifications',false);
setButtonDisabled('blink',false);
status("connecting to device ...");
myPort = await navigator.serial.requestPort();
try {
await myPort.open({ baudRate: 9600 });
} catch (excep) {
status(excep);
setButtonDisabled('startNotifications',false);
setButtonDisabled('stopNotifications',true);
return;
}
const textDecoder = new TextDecoderStream();
myReadableStreamClosed = myPort.readable.pipeTo(textDecoder.writable);
myReader = textDecoder.readable.pipeThrough(new TransformStream(new LineBreakTransformer())).getReader();
isConnected = true;
status("Connected to device ...");
while (isConnected) {
const { value, done } = await myReader.read();
if (done) {
myReader.releaseLock();
break;
}
var varr0 = value.split("\n");
var varr = varr0[0].split(",");
if( varr.length != 2 ) continue;
if( varr[0] != 1 ) {
status("Wait, sensor not ready ...");
varr[1] = 0;
} else {
status("Ready");
}
var ppm = parseInt(varr[1]);
gauge.set(ppm);
displayValue(ppm);
}
setButtonDisabled('startNotifications',false);
setButtonDisabled('stopNotifications',true);
gauge.set(0);
displayValue(0);
}
async function onStopButtonClick() {
isConnected = false;
myReader.cancel();
myReadableStreamClosed.catch(() => { myPort.close(); });
setButtonDisabled('startNotifications',false);
setButtonDisabled('stopNotifications',true);
setButtonDisabled('blink',true);
status("Disconnected");
}
// Create a gauge with a logarithmic scale.
function createGauge()
{
var target = document.getElementById("gauge-ppm");
gauge = new Gauge(target, 500);
}
</script>
</body>
</html>
Web-USB Gauge and Chart
Click on the image to view a live example!
<html>
<head>
<script src = "https://www.ketonix.com/sdk/js/ketonixDraw.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
</head>
<body>
<center>
<canvas id="gauge-canvas"></canvas>
<div style="position:relative; top:0px;" >
<p id="status"></p>
<table>
<tr>
<td><button id="connect">Connect</button></td>
<td><button id="disConnect">Disconnect</button></td>
</tr>
</table>
</div>
<div id="chartdiv" style="position:relative; top:0px; right:0px; width:400px;" >
<canvas id="chart" height="300"></canvas>
</div>
</center>
<script>
var isConnected = false;
var showData = [];
var stretchData = new Array();
var newdata = new Array();
var theChart = null;
var gauge = null;
function createGauge(el)
{
var target = document.getElementById(el);
var aGauge = new Gauge(target,500);
return(aGauge);
}
function setButtonDisabled(id,state)
{
document.getElementById(id).disabled = state;
}
function DataSet(name,data)
{
this.name = name;
this.data = data;
return(this);
}
function DataPoint(x,y)
{
this.x = x;
this.y = y;
return(this);
}
function nowMinusOneMinute()
{
var n = moment().subtract(1,'minute');
return(n.format('YYYY-MM-DD hh:mm:ss'));
}
function rightNow()
{
var n = moment();
return(n.format('YYYY-MM-DD hh:mm:ss'));
}
function addSample(val)
{
removeData(theChart);
var start = nowMinusOneMinute();
var end = rightNow();
showData = [];
stretchData[0] = new DataPoint(nowMinusOneMinute(),0);
stretchData[1] = new DataPoint(rightNow(),0);
if( val == 0 ) val = 0.0;
if( newdata.length > 100 ) {
for(var i=0;i<newdata.length-1;i++) {
newdata[i] = newdata[i+1];
}
newdata[newdata.length-1] = new DataPoint(rightNow(),val);
} else {
newdata.push(new DataPoint(rightNow(),val));
}
showData.push(new DataSet("stretch",stretchData));
showData.push(new DataSet("data",newdata));
theChart = new brAceChart("chartdiv","chart",showData);
}
async function disConnect()
{
isConnected = false;
myReader.cancel();
myReadableStreamClosed.catch(() => { myPort.close(); });
setButtonDisabled('connect',false);
setButtonDisabled('disConnect',true);
}
class LineBreakTransformer {
constructor() {
this.container = '';
}
transform(chunk, controller) {
this.container += chunk;
const lines = this.container.split('\r\n');
this.container = lines.pop();
lines.forEach(line => controller.enqueue(line));
}
flush(controller) {
controller.enqueue(this.container);
}
}
async function connect()
{
setButtonDisabled('connect',true);
setButtonDisabled('disConnect',false);
myPort = await navigator.serial.requestPort();
try {
await myPort.open({ baudRate: 9600 });
} catch (excep) {
console.log(excep);
setButtonDisabled('connect',false);
setButtonDisabled('disConnect',true);
return;
}
const textDecoder = new TextDecoderStream();
myReadableStreamClosed = myPort.readable.pipeTo(textDecoder.writable);
myReader = textDecoder.readable.pipeThrough(new TransformStream(new LineBreakTransformer())).getReader();
isConnected = true;
while (isConnected) {
const { value, done } = await myReader.read();
if (done) {
myReader.releaseLock();
break;
}
var varr0 = value.split("\n");
var varr = varr0[0].split(",");
if( varr.length != 2 ) continue;
if( varr[0] != 1 ) {
document.getElementById("status").innerHTML = "Wait, sensor not ready ...";
varr[1] = 0;
} else {
document.getElementById("status").innerHTML = "Ready";
}
var ppm = parseInt(varr[1]);
addSample(ppm);
setGaugeValue(ppm);
}
setButtonDisabled('connect',false);
setButtonDisabled('disConnect',true);
}
function setGaugeValue(ppm)
{
document.getElementById('status').innerHTML = ppm+" ppm";
gauge.set(ppm);
}
function init()
{
stretchData[0] = new DataPoint(nowMinusOneMinute(),0);
stretchData[1] = new DataPoint(rightNow(),0);
showData.push(new DataSet("stretch",stretchData));
theChart = new brAceChart("chartdiv","chart",showData);
gauge = createGauge('gauge-canvas');
}
function checkBrowser()
{
//console.log("check browser");
}
window.addEventListener('DOMContentLoaded', function() {
init();
setButtonDisabled('connect',false);
setButtonDisabled('disConnect',true);
});
document.querySelector('#connect').addEventListener('click', function(event) {
event.stopPropagation();
event.preventDefault();
connect();
});
document.querySelector('#disConnect').addEventListener('click', function(event) {
event.stopPropagation();
event.preventDefault();
disConnect();
});
</script>
</body>
</html>
Web-Bluetooth Simple Gauge
Click on the image to view a live example!
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://www.ketonix.com/sdk/js/ketonixDraw.js"></script>
</head>
<body>
<title>Ketonix Green WebBluetooth Example Gauge</title>
<center>
<p>Ketonix Green - Example WebBluetooth Measure Breath Ketones</b>
<p>This works when using Chrome browser (on most platforms except iOS).</p>
<p id="status"></p>
<form>
<input id="service" type="hidden" list="services" autofocus value="092cb9a1-4cbe-475e-9f56-d29404dd29f1">
<input id="characteristic" type="hidden" list="characteristics" value="092cb9a1-4cbe-475e-9f56-d29404dd0003">
<table width="500" border="0">
<tr>
<td colspan="2" width="50%" align="center">
<canvas id="gauge-ppm"></canvas><br/>
<p id="gauge-value"></p>
</td>
</tr>
<tr>
<td align="center"><button id="startNotifications">Connect</button></td>
<td align="center"><button id="stopNotifications">Disconnect</button></td>
</tr>
</table>
</form>
</center>
<script>
var gauge = null;
var myCharacteristic = null;
// Setup event listeners
// DOMContentLoaded - do some initialization
window.addEventListener('DOMContentLoaded', function() {
createGauge();
checkBrowser();
setButtonDisabled('#startNotifications',false);
setButtonDisabled('#stopNotifications',true);
});
// Add callback to button "Connect"
document.querySelector('#startNotifications').addEventListener('click', function(event) {
event.stopPropagation();
event.preventDefault();
if (navigator.bluetooth) {
onStartButtonClick();
}
});
// Add callback to button "Disconnect"
document.querySelector('#stopNotifications').addEventListener('click', function(event) {
event.stopPropagation();
event.preventDefault();
if (navigator.bluetooth) {
onStopButtonClick();
}
});
// Misc functions
function setStatus(s)
{
document.getElementById('status').innerHTML = s;
}
// Check of browser is compatible ... e.g Chrome
function checkBrowser()
{
var isChromium = window.chrome;
var winNav = window.navigator;
var vendorName = winNav.vendor;
var isOpera = typeof window.opr !== "undefined";
var isIEedge = winNav.userAgent.indexOf("Edge") > -1;
var isIOSChrome = winNav.userAgent.match("CriOS");
if (isIOSChrome) {
alert("Chrome on iOS is not supported");
} else if(
isChromium !== null &&
typeof isChromium !== "undefined" &&
vendorName === "Google Inc." &&
isOpera === false &&
isIEedge === false
) {
isChrome=true;
} else {
isChrome=false;
alert('You need to use the Chrome browser');
}
if (/Chrome\/(\d+\.\d+.\d+.\d+)/.test(navigator.userAgent)){
if (48 > parseInt(RegExp.$1)) {
alert('Warning! This code has been tested with Chrome ' + 48 + '.');
}
}
}
// Disable/Enable button
function setButtonDisabled(name,state)
{
document.querySelector(name).disabled = state;
}
// Called when user clicks on "Connect"
function onStartButtonClick() {
setStatus("connecting to device ...");
setButtonDisabled('#startNotifications',true);
let serviceUuid = document.querySelector('#service').value;
if (serviceUuid.startsWith('0x')) {
serviceUuid = parseInt(serviceUuid);
}
let characteristicUuid = document.querySelector('#characteristic').value;
if (characteristicUuid.startsWith('0x')) {
characteristicUuid = parseInt(characteristicUuid);
}
navigator.bluetooth.requestDevice({filters: [{services: [serviceUuid]}]})
.then(device => {
setStatus("connect ...");
return device.gatt.connect();
})
.then(server => {
setStatus("get service ...");
return server.getPrimaryService(serviceUuid);
})
.then(service => {
setStatus("get characteristic ...");
return service.getCharacteristic(characteristicUuid);
})
.then(characteristic => {
return characteristic.startNotifications().then(_ => {
setButtonDisabled('#stopNotifications',false);
myCharacteristic = characteristic;
characteristic.addEventListener('characteristicvaluechanged', handleNotifications);
});
}).catch(error => {
setStatus("error");
setButtonDisabled('#startNotifications',false);
setButtonDisabled('#stopNotifications',true);
});
}
function setGaugeValue(v)
{
console.log("setGaugeValue("+v+")");
gauge.set(v);
document.getElementById('gauge-value').innerHTML = v + " PPM";
}
// Called when user clicks on "Disconnect"
function onStopButtonClick() {
myCharacteristic.stopNotifications();
setButtonDisabled('#startNotifications',false);
setButtonDisabled('#stopNotifications',true);
setTimeout(function() { setGaugeValue(0); },1200);
}
// Called when received data from device
function handleNotifications(event) {
let value = event.target.value;
// Extract ready and ppm from notification
var ready = value.getUint8(2) + (value.getUint8(3) << 8);
var ppm = value.getUint8(4) + (value.getUint8(5) << 8);
setStatus( ready ? "Ready": "Sensor not ready yet");
if(gauge != null ) {
setGaugeValue(ppm);
} else {
console.log("gauge is null");
}
}
// Create a gauge with a logarithmic scale.
function createGauge()
{
var target = document.getElementById('gauge-ppm');
gauge = new Gauge(target, 500);
}
</script>
</body>
</html>
Web-Bluetooth Simple Gauge
Click on the image to view a live example!
<html> | |
<head> | |
<script src = "https://www.ketonix.com/sdk/js/ketonixDraw.js"></script> | |
<script src = "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script> | |
</head> | |
<body> | |
<center> | |
<h2>Web-Bluetooth Ketonix Bluetooth/Green Pro and Basic</h2> | |
<small>You need to use the Chrome browser.</small><br> | |
<canvas id="gauge-canvas"></canvas> | |
<div style="position:relative; top:0px;" > | |
<p id="gauge-value"></p> | |
<p id="status"></p> | |
<form> | |
<input id="service" type="hidden" list="services" autofocus value="092cb9a1-4cbe-475e-9f56-d29404dd29f1"> | |
<input id="characteristic" type="hidden" list="characteristics" value="092cb9a1-4cbe-475e-9f56-d29404dd0003"> | |
<table> | |
<tr><td><button id="connect">Connect</button></td><td><button id="disConnect">Disconnect</button></td></tr> | |
</table> | |
</form> | |
</div> | |
<div id="chartdiv" style="position:relative; top:0px; right:0px; width:400px;" > | |
<canvas id="chart" height="300"></canvas> | |
</div> | |
<div id="commonchartdiv" style="position:relative; top:0px; right:0px; width:400px; visibility: hidden;" > | |
<canvas id="commonchart" height="300"></canvas> | |
</div> | |
</center> | |
<script> | |
var isConnected = false; | |
var showData = []; | |
var stretchData = new Array(); | |
var newdata = new Array(); | |
var theChart = null; | |
var theCommonChart = null; | |
var gauge = null; | |
var myCharacteristic = null; | |
var bluetoothDevice = null; | |
function setStatus(s) | |
{ | |
document.getElementById('status').innerHTML = s; | |
} | |
function createGauge(el) | |
{ | |
var target = document.getElementById(el); | |
var aGauge = new Gauge(target,500); | |
return(aGauge); | |
} | |
function setButtonDisabled(id,state) | |
{ | |
console.log("setDisabled("+id+","+state+")"); | |
document.getElementById(id).disabled = state; | |
} | |
function DataSet(name,data) | |
{ | |
this.name = name; | |
this.data = data; | |
return(this); | |
} | |
function DataPoint(x,y) | |
{ | |
this.x = x; | |
this.y = y; | |
return(this); | |
} | |
function nowMinusOneMinute() | |
{ | |
var n = moment().subtract(1,'minute'); | |
return(n.format('YYYY-MM-DD hh:mm:ss')); | |
} | |
function rightNow() | |
{ | |
var n = moment(); | |
return(n.format('YYYY-MM-DD hh:mm:ss')); | |
} | |
function addSample(val) | |
{ | |
removeData(theChart); | |
removeData(theCommonChart); | |
var start = nowMinusOneMinute(); | |
var end = rightNow(); | |
showData = []; | |
stretchData[0] = new DataPoint(nowMinusOneMinute(),0); | |
stretchData[1] = new DataPoint(rightNow(),0); | |
if( val == 0 ) val = 0.1; | |
if( newdata.length > 100 ) { | |
for(var i=0;i<newdata.length-1;i++) { | |
newdata[i] = newdata[i+1]; | |
} | |
newdata[newdata.length-1] = new DataPoint(rightNow(),val); | |
} else { | |
newdata.push(new DataPoint(rightNow(),val)); | |
} | |
showData.push(new DataSet("stretch",stretchData)); | |
showData.push(new DataSet("data",newdata)); | |
theChart = new brAceChart("chartdiv","chart",showData); | |
theCommonChart = new commonChart("commonchartdiv","commonchart",showData); | |
} | |
async function disConnect() | |
{ | |
isConnected = false; | |
setButtonDisabled('connect',false); | |
setButtonDisabled('disConnect',true); | |
if (!bluetoothDevice) { return; } console.log('Disconnecting from Bluetooth Device...'); if (bluetoothDevice.gatt.connected) { bluetoothDevice.gatt.disconnect(); } else { console.log('> Bluetooth Device is already disconnected'); } |
|
} | |
function handleNotifications(event) { | |
let value = event.target.value; | |
// Extract ready and ppm from notification | |
var ready = value.getUint8(2) + (value.getUint8(3) << 8); | |
var ppm = value.getUint8(4) + (value.getUint8(5) << 8); | |
setStatus( ready ? "Ready": "Sensor not ready yet"); | |
if(gauge != null ) { | |
addSample(ppm); | |
setGaugeValue(ppm); | |
} else { | |
console.log("gauge is null"); | |
} | |
} | |
async function connect() | |
{ | |
setButtonDisabled('connect',true); | |
setButtonDisabled('disConnect',false); | |
let serviceUuid = document.querySelector('#service').value; | |
if (serviceUuid.startsWith('0x')) { | |
serviceUuid = parseInt(serviceUuid); | |
} | |
let characteristicUuid = document.querySelector('#characteristic').value; | |
if (characteristicUuid.startsWith('0x')) { | |
characteristicUuid = parseInt(characteristicUuid); | |
} | |
navigator.bluetooth.requestDevice({filters: [{services: [serviceUuid]}]}) | |
.then(device => { | |
setStatus("connect ..."); bluetoothDevice = device; |
|
return device.gatt.connect(); | |
}) | |
.then(server => { | |
setStatus("get service ..."); | |
return server.getPrimaryService(serviceUuid); | |
}) | |
.then(service => { | |
setStatus("get characteristic ..."); | |
return service.getCharacteristic(characteristicUuid); | |
}) | |
.then(characteristic => { | |
return characteristic.startNotifications().then(_ => { | |
setButtonDisabled('disConnect',false); | |
myCharacteristic = characteristic; | |
characteristic.addEventListener('characteristicvaluechanged', handleNotifications); | |
}); | |
}).catch(error => { | |
setStatus("error"); | |
setButtonDisabled('connect',false); | |
setButtonDisabled('disConnect',true); | |
}); | |
} | |
function setGaugeValue(ppm) | |
{ | |
document.getElementById('gauge-value').innerHTML = ppm+" ppm"; | |
gauge.set(ppm); | |
} | |
function init() | |
{ | |
stretchData[0] = new DataPoint(nowMinusOneMinute(),0); | |
stretchData[1] = new DataPoint(rightNow(),0); | |
showData.push(new DataSet("stretch",stretchData)); | |
theCommonChart = new commonChart("commonchartdiv","commonchart",showData); | |
theChart = new brAceChart("chartdiv","chart",showData); | |
gauge = createGauge('gauge-canvas'); | |
setTimeout(function() { setGaugeValue(0); } ,1); | |
} | |
function checkBrowser() | |
{ | |
console.log("check browser"); // Add code to check that browser can handle web-bluetooth |
|
} | |
window.addEventListener('DOMContentLoaded', function() { | |
checkBrowser(); | |
init(); | |
setButtonDisabled('connect',false); | |
setButtonDisabled('disConnect',true); | |
}); | |
document.querySelector('#connect').addEventListener('click', function(event) { | |
event.stopPropagation(); | |
event.preventDefault(); | |
connect(); | |
}); | |
document.querySelector('#disConnect').addEventListener('click', function(event) { | |
event.stopPropagation(); | |
event.preventDefault(); | |
disConnect(); | |
}); | |
</script> | |
</body> | |
</html> |
WiFi Gauge and Chart
Click on the image to view a live example!
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script src = "https://www.ketonix.com/sdk/js/ketonixDraw.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
</head>
<body>
<center>
<p>This works in a browser (with javascript enabled) on most platforms.</p>
<canvas id="gauge-canvas" height="550" width="1100" style="width: 500px; height: 250px;"></canvas>
<div style="position:relative; top:0px;">
<p id="status"></p>
<table>
<tr>
<td>Ketonix IP</td>
<td><input type="text" id="ip"></td>
<tr>
<td><button id="connect">Connect</button></td>
<td><button id="disconnect">Disconnect</button></td>
</tr>
</table>
</div>
<div id="chartdiv" style="position:relative; top:0px; right:0px; width:400px;">
<canvas id="chart" height="660" width="880" style="display: block; box-sizing: border-box; height: 300px; width: 400px;"></canvas>
</div>
</center>
<script>
var isConnected = false;
var showData = [];
var stretchData = new Array();
var newdata = new Array();
var theChart = null;
var gauge = null;
function createGauge(el)
{
var target = document.getElementById(el);
var aGauge = new Gauge(target,500);
aGauge.set(0);
return(aGauge);
}
function setButtonDisabled(id,state)
{
document.getElementById(id).disabled = state;
}
function DataSet(name,data)
{
this.name = name;
this.data = data;
return(this);
}
function DataPoint(x,y)
{
this.x = x;
this.y = y;
return(this);
}
function nowMinusOneMinute()
{
var n = moment().subtract(1,'minute');
return(n.format('YYYY-MM-DD hh:mm:ss'));
}
function rightNow()
{
var n = moment();
return(n.format('YYYY-MM-DD hh:mm:ss'));
}
function addSample(val)
{
removeData(theChart);
var start = nowMinusOneMinute();
var end = rightNow();
showData = [];
stretchData[0] = new DataPoint(nowMinusOneMinute(),0);
stretchData[1] = new DataPoint(rightNow(),0);
if( val == 0 ) val = 0.1;
if( newdata.length > 100 ) {
for(var i=0;i<newdata.length-1;i++) {
newdata[i] = newdata[i+1];
}
newdata[newdata.length-1] = new DataPoint(rightNow(),val);
} else {
newdata.push(new DataPoint(rightNow(),val));
}
showData.push(new DataSet("stretch",stretchData));
showData.push(new DataSet("data",newdata));
theChart = new brAceChart("chartdiv","chart",showData);
}
async function disConnect()
{
isConnected = false;
setGaugeValue(0);
setStatus("Disconnected");
setButtonDisabled('connect',false);
setButtonDisabled('disconnect',true);
}
async function connect()
{
isConnected = true;
setButtonDisabled('connect',true);
setButtonDisabled('disconnect',false);
getValues();
}
async function getValues()
{
if( isConnected == false ) return;
var ip = document.getElementById("ip").value;
const url = "http://"+ip+"/data.json";
// console.log(url);
const myResponse = await fetch(url).then(function(response) { return(response.json()); }).then(function(data) {
if( isConnected ) {
if( data.ketonix.ready == 1 ) {
var ppm = parseInt(data.ketonix.ppm);
addSample(ppm);
setGaugeValue(ppm);
} else {
setStatus("Initializing the sensor ...");
}
}
});
setTimeout( function() { getValues(); }, 2000);
}
function setStatus(txt)
{
document.getElementById('status').innerHTML = txt;
}
function setGaugeValue(ppm)
{
document.getElementById('status').innerHTML = ppm+" ppm";
gauge.set(ppm);
}
function init()
{
stretchData[0] = new DataPoint(nowMinusOneMinute(),0);
stretchData[1] = new DataPoint(rightNow(),0);
showData.push(new DataSet("stretch",stretchData));
theChart = new brAceChart("chartdiv","chart",showData);
gauge = createGauge('gauge-canvas');
}
window.addEventListener('DOMContentLoaded', function() {
init();
setButtonDisabled('connect',false);
setButtonDisabled('disconnect',true);
});
document.querySelector('#connect').addEventListener('click', function(event) {
event.stopPropagation();
event.preventDefault();
connect();
});
document.querySelector('#disconnect').addEventListener('click', function(event) {
event.stopPropagation();
event.preventDefault();
disConnect();
});
</script>
</body>
</html>