Green Ketonix SDK Examples

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:

  1. To enable the features you type chrome://flags  in the Chrome URL field and press enter.
  2. Search in flags for USB and enable the flag Automatic detection of WebUSB-compatible devices.
  3. 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!

Ketonix Green Simple Gauge Screenshot

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>

Live example
Ketonix Green Simple Gauge Screenshot

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>

 

 

Live example
Ketonix Green Simple Gauge Screenshot

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>

Live example
Ketonix Green Simple Gauge Screenshot

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>
Live example
Ketonix Green Simple Gauge Screenshot

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>



Live example

KETONIX® - Breath Ketone Analyzer - The Original Biohackers Choice Since 2013
MADE IN SWEDEN, COPYRIGHT KETONIX AB 2013-2023

​ KETONIX® is a Non-Invasive Class I Medical Device, registered at Läkemedelsverket (SE).
KETONIX® is a Registered Trademark in the US, Australia, Europe, and other countries.
Ketonix AB is a Swedish Registered Company - VAT SE556443379401

© 2023 Ketonix AB. All Rights Reserved.