{"id":41,"date":"2020-12-18T13:57:11","date_gmt":"2020-12-18T13:57:11","guid":{"rendered":"https:\/\/www.bleuio.com\/blog\/?p=41"},"modified":"2022-05-27T14:24:53","modified_gmt":"2022-05-27T14:24:53","slug":"collect-realtime-data-from-bluetooth-device","status":"publish","type":"post","link":"https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/","title":{"rendered":"Collect Realtime Air Quality Data From Bluetooth Device"},"content":{"rendered":"\n<p>This project will show how to collect Realtime Bluetooth low energy data and show it on web browser.<\/p>\n\n\n\n<p>For this project, I am using Bluetooth Low Energy USB dongle called BlueIO, which will act as a central device to retrieve data. Hibou Air Quality Monitor which will serve as a peripheral device to transmit the data. The script is simple to use and can be used for other purposes such as store the data into database or cloud.<\/p>\n\n\n\n<p>Things we need:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Google chrome version 78 or later (windows)<\/li><li><a href=\"https:\/\/www.bleuio.com\/\">BleuIO \u2014 Bluetooth Low Energy USB dongle<\/a><\/li><li><a href=\"https:\/\/www.hiboucloud.com\/\">Hibou Air Quality Monitor sensor device<\/a><\/li><\/ul>\n\n\n\n<p>Before we start<\/p>\n\n\n\n<p>The article assumes you have some general knowledge of how Bluetooth Low Energy (BLE) work. Since the Chrome Serial specification on Google Chrome is not finalized yet, you will have to go to enable the highlighted flag, and restart Chrome. open\u00a0<strong>chrome:\/\/flags\/#enable-experimental-web-platform-features<\/strong>\u00a0in chrome browser. In this example, we are going to use JavaScript + html (and some CSS for styling) to setup the\u00a0<strong>BleuIO\u00a0<\/strong>and quickly start scanning.<\/p>\n\n\n\n<p><strong>The script <\/strong><\/p>\n\n\n\n<p>The source code is available on Github. <\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/smart-sensor-devices-ab\/get_realtime_data_bleuio\">https:\/\/github.com\/smart-sensor-devices-ab\/get_realtime_data_bleuio<\/a><\/p>\n\n\n\n<p>The <strong>index.html<\/strong> file contains the layout of the script. There are two main buttons. Connect, scan and stop getting data. The connect button will use web serial to connect to BleuIO dongle. After that the scan BLE devices button will send some AT commands to the dongle and the respnse will be printed on the scree. <\/p>\n\n\n\n<p>Here is the index.html file <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;!DOCTYPE html>\r\n&lt;html lang=\"en\">\r\n  &lt;head>\r\n    &lt;title>BleuIO Web Bluetooth Example&lt;\/title>\r\n    &lt;meta charset=\"utf-8\" \/>\r\n    &lt;meta name=\"ssd\" content=\"beaconexample\" \/>\r\n    &lt;meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" \/>\r\n    &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" \/>\r\n    &lt;link rel=\"shortcut icon\" type=\"image\/png\" href=\"images\/favicon.png\" \/>\r\n\r\n    &lt;script>\r\n      \/\/ Redirect to HTTPS if HTTP is requested.\r\n      if (window.location.protocol === \"http:\") {\r\n        window.location.href = \"https:\" + window.location.href.substring(5);\r\n      }\r\n    &lt;\/script>\r\n\r\n    &lt;link rel=\"stylesheet\" href=\"style.css\" \/>\r\n    &lt;link\r\n      rel=\"stylesheet\"\r\n      href=\"https:\/\/stackpath.bootstrapcdn.com\/bootstrap\/4.5.2\/css\/bootstrap.min.css\"\r\n      integrity=\"sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z\"\r\n      crossorigin=\"anonymous\"\r\n    \/>\r\n  &lt;\/head>\r\n  &lt;body>\r\n    &lt;div class=\"container\">\r\n      &lt;div\r\n        id=\"carouselExampleFade\"\r\n        class=\"carousel slide carousel-fade\"\r\n        data-ride=\"carousel\"\r\n      >\r\n        &lt;div class=\"carousel-inner\">\r\n          &lt;div class=\"carousel-item active\">\r\n            &lt;div class=\"row\">\r\n              &lt;div class=\"col-md-9 caption\">\r\n                &lt;img src=\"images\/logo.png\" \/>\r\n                &lt;h1>Bluetooth\u00ae low energy adapter&lt;\/h1>\r\n                &lt;a\r\n                  class=\"btn btn-info btn-lg\"\r\n                  href=\"https:\/\/www.bleuio.com\/\"\r\n                  target=\"_blank\"\r\n                  >Learn More&lt;\/a\r\n                >\r\n              &lt;\/div>\r\n              &lt;div class=\"col-md-3\">\r\n                &lt;img\r\n                  src=\"images\/bleuIO_white_withlogo.png\"\r\n                  class=\"d-block w-100\"\r\n                  alt=\"...\"\r\n                \/>\r\n              &lt;\/div>\r\n            &lt;\/div>\r\n          &lt;\/div>\r\n          &lt;div class=\"carousel-item\">\r\n            &lt;div class=\"row\">\r\n              &lt;div class=\"col-md-9 caption\">\r\n                &lt;img src=\"images\/logo.png\" \/>\r\n                &lt;h1>Create your own BLE applications&lt;\/h1>\r\n                &lt;a\r\n                  class=\"btn btn-info btn-lg\"\r\n                  href=\"https:\/\/www.bleuio.com\/\"\r\n                  target=\"_blank\"\r\n                  >Learn More&lt;\/a\r\n                >\r\n              &lt;\/div>\r\n              &lt;div class=\"col-md-3\">\r\n                &lt;img\r\n                  src=\"images\/bleuIO_black_withlogo.png\"\r\n                  class=\"d-block w-100\"\r\n                  alt=\"...\"\r\n                \/>\r\n              &lt;\/div>\r\n            &lt;\/div>\r\n          &lt;\/div>\r\n          &lt;div class=\"carousel-item\">\r\n            &lt;div class=\"row\">\r\n              &lt;div class=\"col-md-9 caption\">\r\n                &lt;img src=\"images\/logo.png\" \/>\r\n                &lt;h1>Quick, Innovative, Simple&lt;\/h1>\r\n                &lt;a\r\n                  class=\"btn btn-info btn-lg\"\r\n                  href=\"https:\/\/www.bleuio.com\/\"\r\n                  target=\"_blank\"\r\n                  >Learn More&lt;\/a\r\n                >\r\n              &lt;\/div>\r\n              &lt;div class=\"col-md-3\">\r\n                &lt;img\r\n                  src=\"images\/bleuIO_black_withlogo.png\"\r\n                  class=\"d-block w-100\"\r\n                  alt=\"...\"\r\n                \/>\r\n              &lt;\/div>\r\n            &lt;\/div>\r\n          &lt;\/div>\r\n        &lt;\/div>\r\n      &lt;\/div>\r\n      &lt;!-- end carousel -->\r\n    &lt;\/div>\r\n    &lt;!-- end container -->\r\n    &lt;div class=\"codesection\">\r\n      &lt;div class=\"container\">\r\n        &lt;h1>Get realtime data from BLE device&lt;\/h1>\r\n        &lt;main class=\"main\">\r\n          &lt;div id=\"notSupported\" class=\"hidden alert alert-danger\">\r\n            Sorry, &lt;b>Web Serial&lt;\/b> is not supported on this device, make sure\r\n            you're running Chrome 78 or later and have enabled the\r\n            &lt;code>#enable-experimental-web-platform-features&lt;\/code> flag in\r\n            &lt;code>chrome:\/\/flags&lt;\/code> &lt;br \/>\r\n            Open\r\n            &lt;strong>\r\n              chrome:\/\/flags\/#enable-experimental-web-platform-features&lt;\/strong\r\n            >\r\n            in Google Chrome browser.\r\n          &lt;\/div>\r\n\r\n          &lt;br \/>\r\n          &lt;button id=\"butConnect\" type=\"button\" class=\"btn btn-success\">\r\n            Connect\r\n          &lt;\/button>\r\n          &lt;br \/>&lt;br \/>\r\n          &lt;div class=\"row\">\r\n            &lt;div class=\"col-md-3\">\r\n              &lt;button\r\n                id=\"butScan\"\r\n                type=\"button\"\r\n                disabled\r\n                class=\"btn btn-primary\"\r\n              >\r\n                Scan BLE Devices\r\n              &lt;\/button>\r\n            &lt;\/div>\r\n            &lt;div class=\"col-md-3\">\r\n              &lt;select\r\n                class=\"devices form-control\"\r\n                id=\"devices\"\r\n                onchange=\"getSelectedDevice(this)\"\r\n              >\r\n                &lt;option value=\"\">Select a Device&lt;\/option>\r\n              &lt;\/select>\r\n            &lt;\/div>\r\n            &lt;div class=\"col-md-3\">\r\n              &lt;button\r\n                id=\"butGetData\"\r\n                type=\"button\"\r\n                disabled\r\n                class=\"btn btn-primary\"\r\n              >\r\n                Get Data\r\n              &lt;\/button>\r\n            &lt;\/div>\r\n          &lt;\/div>\r\n\r\n          &lt;br \/>&lt;br \/>\r\n\r\n          &lt;pre id=\"log\" class=\"mt-5 d-none\">&lt;\/pre>\r\n          &lt;div id=\"dataIntoTable\" class=\"mt-5\">&lt;\/div>\r\n\r\n          &lt;div style=\"background: white\">&lt;\/div>\r\n        &lt;\/main>\r\n      &lt;\/div>\r\n    &lt;\/div>\r\n    &lt;div class=\"footer text-center mt-3\">\r\n      Powered by &lt;a href=\"https:\/\/www.bleuio.com\/\" target=\"_blank\">BleuIO&lt;\/a> .\r\n      A product of\r\n      &lt;a href=\"http:\/\/smartsensordevices.com\/\" target=\"_blank\"\r\n        >Smart Sensor Devices&lt;\/a\r\n      >\r\n    &lt;\/div>\r\n\r\n    &lt;!-- end container -->\r\n    &lt;!-- JS, Popper.js, and jQuery -->\r\n    &lt;script\r\n      src=\"https:\/\/code.jquery.com\/jquery-3.5.1.slim.min.js\"\r\n      integrity=\"sha384-DfXdz2htPH0lsSSs5nCTpuj\/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj\"\r\n      crossorigin=\"anonymous\"\r\n    >&lt;\/script>\r\n    &lt;script\r\n      src=\"https:\/\/cdn.jsdelivr.net\/npm\/popper.js@1.16.1\/dist\/umd\/popper.min.js\"\r\n      integrity=\"sha384-9\/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN\"\r\n      crossorigin=\"anonymous\"\r\n    >&lt;\/script>\r\n    &lt;script\r\n      src=\"https:\/\/stackpath.bootstrapcdn.com\/bootstrap\/4.5.2\/js\/bootstrap.min.js\"\r\n      integrity=\"sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8\/KUEfYiJOMMV+rV\"\r\n      crossorigin=\"anonymous\"\r\n    >&lt;\/script>\r\n\r\n    &lt;script src=\"script.js\" defer>&lt;\/script>\r\n  &lt;\/body>\r\n&lt;\/html>\n<\/code><\/pre>\n\n\n\n<p>The <strong>Script.js<\/strong> file contains all the JavaScript codes to connect to the dongle and get advertised data from the air quality monitoring device. After getting the advertised data we try to decodes it to get a meaningful format.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"use strict\";\r\n\r\nlet port;\r\nlet reader;\r\nlet inputDone;\r\nlet outputDone;\r\nlet inputStream;\r\nlet outputStream;\r\nlet isScanning = false;\r\nlet isGettingData = false;\r\nlet hibouDevices = &#91;];\r\nlet rightDevice = false;\r\nlet scannedSensorData = &#91;]\r\nconst log = document.getElementById(\"log\");\r\nconst butConnect = document.getElementById(\"butConnect\");\r\nconst butScan = document.getElementById(\"butScan\");\r\nconst butGetData = document.getElementById(\"butGetData\");\r\nconst outputTable = document.getElementById('dataIntoTable')\r\nlet outputData='';\r\ndocument.addEventListener(\"DOMContentLoaded\", () => {\r\n  butScan.addEventListener(\"click\", clickScan);\r\n  butGetData.addEventListener(\"click\", clickGetData);\r\n  butConnect.addEventListener(\"click\", clickConnect);\r\n  const notSupported = document.getElementById(\"notSupported\");\r\n  notSupported.classList.toggle(\"hidden\", \"serial\" in navigator);\r\n});\r\n\r\n\r\n\r\n\/**\r\n * @name connect\r\n * Opens a Web Serial connection to a serial device such as a Smart USB Dongle 2.0 and sets up the input and\r\n * output stream.\r\n *\/\r\nasync function connect() {\r\n  \/\/ - Request a port and open a connection.\r\n  port = await navigator.serial.requestPort();\r\n  \/\/ - Wait for the port to open.\r\n  await port.open({ baudRate: 9600 });\r\n\r\n  const encoder = new TextEncoderStream();\r\n  outputDone = encoder.readable.pipeTo(port.writable);\r\n  outputStream = encoder.writable;\r\n\r\n  let decoder = new TextDecoderStream();\r\n  inputDone = port.readable.pipeTo(decoder.writable);\r\n  inputStream = decoder.readable.pipeThrough(\r\n    new TransformStream(new LineBreakTransformer())\r\n  );\r\n\r\n  reader = inputStream.getReader();\r\n  readLoop().catch((error) => {\r\n    toggleUIConnected(false);\r\n    port = null;\r\n    log.textContent = \"Dongle Disconnected!\";\r\n  });\r\n}\r\n\r\n\/**\r\n * @name disconnect\r\n * Closes the Web Serial connection.\r\n *\/\r\nasync function disconnect() {\r\n  \/\/ Close the input stream (reader).\r\n  if (reader) {\r\n    await reader.cancel();\r\n    await inputDone.catch(() => {});\r\n    reader = null;\r\n    inputDone = null;\r\n  }\r\n  \/\/ Close the output stream.\r\n  if (outputStream) {\r\n    await outputStream.getWriter().close();\r\n    await outputDone;\r\n    outputStream = null;\r\n    outputDone = null;\r\n  }\r\n  \/\/ Close the port.\r\n  await port.close();\r\n  port = null;\r\n  log.textContent = \"Dongle Disconnected!\";\r\n}\r\n\r\n\/**\r\n * @name clickConnect\r\n * Click handler for the connect\/disconnect button.\r\n * Checks if port != null\r\n * If true: Checks if any beacons is advertising or scans are running and stops the advertsing or scan if so. Then runs disconnect() and set toggleUIConnected to false.\r\n * if false: Runs connect() then set toggleUIConnected to true.\r\n *\/\r\nasync function clickConnect() {\r\n  log.textContent = \"\";\r\n  if (port) {\r\n\r\n    \/\/ If disconnected while scanning the dongle will restart\r\n    if (isScanning) {\r\n      writeCmd(\"\\x03\");\r\n      butScan.textContent = \"Scan BLE Devices\";\r\n      isScanning = false;\r\n    }\r\n    await disconnect();\r\n    toggleUIConnected(false);\r\n    return;\r\n  }\r\n  await connect();\r\n  toggleUIConnected(true);\r\n}\r\n\r\nfunction getSelectedDevice(selectObject) {\r\n  var selectedDevice = selectObject.value;  \r\n  localStorage.setItem(\"selectedDevice\", selectedDevice);\r\n}\r\n\r\n\/**\r\n * @name clickScan\r\n * Click handler for the Scan button.\r\n * Checks if a scan is already running by checking the boolean isScanning.\r\n * If isScanning = true: Stops scanning and goes back to peripheral mode, changes the button text and shows the beacon buttons. Finally sets isScanning = false.\r\n * If isScanning = false: Goes into Central mode and starts scanning for ble devices. Also changes button text and hides the beacon buttons. Finally sets isScanning = true.\r\n *\/\r\nfunction clickScan() {\r\n  console.log(\"SCAN BUTTON PRESSED\");\r\n  if (isScanning) {\r\n    writeCmd(\"\\x03\"); \/\/ Ctrl+C to stop the scan\r\n    setTimeout(() => {\r\n      writeCmd(\"AT+PERIPHERAL\"); \/\/ Set the dongle in Peripheral mode needed for advertising.\r\n    }, 500); \/\/ Waiting half a bit to make sure each command will get through separately.\r\n    isScanning = false;\r\n    butGetData.removeAttribute(\"disabled\");\r\n    butScan.textContent = \"Scan BLE Devices\";\r\n    \r\n    return;\r\n  }\r\n  hibouDevices = &#91;];\r\n  writeCmd(\"AT+CENTRAL\"); \/\/ Set the dongle in Central mode needed for scanning.\r\n  setTimeout(() => {\r\n    writeCmd(\"AT+GAPSCAN=2\");\r\n  }, 500); \/\/ Waiting half a bit to make sure each command will get through separately.\r\n\r\n  butScan.textContent = \"Stop Scanning...\";\r\n  butGetData.setAttribute(\"disabled\", \"true\");\r\n  log.classList.toggle(\"d-none\", false);\r\n\r\n  isScanning = true;\r\n}\r\n\r\n\/**\r\n * @name clickGetData\r\n * Click handler for the 'Get Data' button.\r\n * Checks if a getData scan is already running by checking the boolean isGettingData.\r\n * If isGettingData = true: Stops scanning and goes back to peripheral mode, changes the button text and shows the scan button. Finally sets isGettingData = false.\r\n * If isGettingData = false: Goes into Central mode and starts scanning for ble devices data. Also changes button text and hides the scan button. Finally sets isGettingData = true.\r\n *\/\r\nfunction clickGetData() {\r\n  console.log(\"GET DATA BUTTON PRESSED\");\r\n  if (isGettingData) {\r\n    writeCmd(\"\\x03\"); \/\/ Ctrl+C to stop the scan\r\n    setTimeout(() => {\r\n      writeCmd(\"AT+PERIPHERAL\"); \/\/ Set the dongle in Peripheral mode needed for advertising.\r\n    }, 500); \/\/ Waiting half a bit to make sure each command will get through separately.\r\n    isGettingData = false;\r\n\r\n    butScan.removeAttribute(\"disabled\");\r\n    butGetData.textContent = \"Get Data\";\r\n    return;\r\n  }\r\n  writeCmd(\"AT+CENTRAL\"); \/\/ Set the dongle in Central mode needed for scanning.\r\n  setTimeout(() => {\r\n   writeCmd(\"AT+FINDSCANDATA=FF5B07\"); \/\/ Will just scan for adv data that contains 'FF5B07' which is the tag for Manufaturing Specific Data (FF) and our Company ID (5B07).\r\n  }, 500); \/\/ Waiting half a bit to make sure each command will get through separately.\r\n\r\n  butGetData.textContent = \"Stop Getting Data...\";\r\n  butScan.setAttribute(\"disabled\", \"true\");\r\n  log.classList.toggle(\"d-none\", false);\r\n\r\n  isGettingData = true;\r\n\r\n  \r\n}\r\n\r\n\r\n\/**\r\n * @name readLoop\r\n * Reads data from the input stream and displays it on screen.\r\n *\/\r\nasync function readLoop() {\r\n  let i=0;\r\n  while (true) {\r\n    i++;\r\n    const { value, done } = await reader.read();\r\n    if (value &amp;&amp; (!isScanning &amp;&amp; !isGettingData)) {\r\n      log.textContent += value + \"\\n\";\r\n    }\r\n    if (value &amp;&amp; isScanning) {\r\n      if(value === \"SCAN COMPLETE\") {\r\n        isScanning = false;\r\n        butScan.textContent = \"Scan BLE Devices\";\r\n        log.textContent += \"\\n\" +\"Scan Done\" + \"\\n\";\r\n        butGetData.removeAttribute(\"disabled\");\r\n        log.classList.toggle(\"d-none\", false);\r\n      }\r\n      let lineValueArray = value.split(\" \");\r\n      if (lineValueArray&#91;6] === \"(HibouAIR)\") {\r\n        if(lineValueArray&#91;2]) {\r\n          hibouDevices.push(\"&#91;\"+lineValueArray&#91;2].replace(\"&#91;1]\", \"\") +\"]\");\r\n\r\n        }\r\n        log.textContent = \"\\n\" + \"hibouDevices found: \" + hibouDevices.length + \"\\n\";\r\n      }\r\n      if(value === \"SCAN COMPLETE\") {\r\n        var select = document.getElementById(\"devices\");\r\n        hibouDevices.map(function(item){\r\n          var option = document.createElement(\"option\");\r\n          option.value = item;\r\n          option.text  = item;\r\n          select.appendChild(option)\r\n        });\r\n      }\r\n\r\n    }\r\n    if (value &amp;&amp; isGettingData) {\r\n      if(value === \"SCAN COMPLETE\") {\r\n        isGettingData = false;\r\n        butGetData.textContent = \"Get Data\";\r\n        log.textContent += \"\\n\" +\"Scan Done\" + \"\\n\";\r\n        butScan.removeAttribute(\"disabled\");\r\n        log.classList.toggle(\"d-none\", false);\r\n        \r\n      }\r\n      let lineValueArray = value.split(\" \");\r\n      \r\n        if (lineValueArray&#91;0] ===   localStorage.getItem(\"selectedDevice\") &amp;&amp; lineValueArray&#91;3] === \"&#91;ADV]:\") {\r\n\r\n          scannedSensorData = parseSensorData(lineValueArray&#91;4]);\r\n          outputData = ''\r\n          if((i%30) === 0) {\r\n\r\n            outputData += 'Time: '+new Date().getHours() + \":\" + new Date().getMinutes() + \":\" + new Date().getSeconds()+' '\r\n            outputData += 'Pressure: '+scannedSensorData.p+' '\r\n            outputData += 'Temperature: '+scannedSensorData.t+' '\r\n            outputData += 'Humidity: '+scannedSensorData.h+' '\r\n            outputData += 'ALS: '+scannedSensorData.als+' '\r\n            outputData += 'PM1.0: '+scannedSensorData.pm1+' '\r\n            outputData += 'PM2.5: '+scannedSensorData.pm25+' '\r\n            outputData += 'PM10: '+scannedSensorData.pm10+' '\r\n            \/\/log.innerHTML  += \"\\n\" + \"SensorData= \" + JSON.stringify(scannedSensorData) + \"\\n\";\r\n            log.innerHTML  += \"\\n\" +outputData\r\n          }\r\n        \r\n        }\r\n\r\n\r\n    }\r\n    if (done) {\r\n      console.log(\"&#91;readLoop] DONE\", done);\r\n      reader.releaseLock();\r\n      break;\r\n    }\r\n  }\r\n}\r\n\r\n\/**\r\n * @name writeCmd\r\n * Gets a writer from the output stream and send the command to the Smart USB Dongle 2.0.\r\n * @param  {string} cmd command to send to the Smart USB Dongle 2.0\r\n *\/\r\nfunction writeCmd(cmd) {\r\n  \/\/ Write to output stream\r\n  const writer = outputStream.getWriter();\r\n  console.log(\"&#91;SEND]\", cmd);\r\n\r\n  writer.write(cmd);\r\n  \/\/ Ignores sending carriage return if sending Ctrl+C\r\n  if (cmd !== \"\\x03\") {\r\n    writer.write(\"\\r\"); \/\/ Important to send a carriage return after a command\r\n  }\r\n  writer.releaseLock();\r\n}\r\n\r\n\/**\r\n * @name LineBreakTransformer\r\n * TransformStream to parse the stream into lines.\r\n *\/\r\nclass LineBreakTransformer {\r\n  constructor() {\r\n    \/\/ A container for holding stream data until a new line.\r\n    this.container = \"\";\r\n  }\r\n\r\n  transform(chunk, controller) {\r\n    \/\/ Handle incoming chunk\r\n    this.container += chunk;\r\n    const lines = this.container.split(\"\\r\\n\");\r\n    this.container = lines.pop();\r\n    lines.forEach((line) => controller.enqueue(line));\r\n  }\r\n\r\n  flush(controller) {\r\n    \/\/ Flush the stream.\r\n    controller.enqueue(this.container);\r\n  }\r\n}\r\n\r\n\/**\r\n * @name toggleUIConnected\r\n * Changes the text on butConnect depending on the action it actually will preform in the current state.\r\n * @param  {boolean} connected true if connected, false if disconnected.\r\n *\/\r\nfunction toggleUIConnected(connected) {\r\n  let lbl = \"Connect\";\r\n  if (connected) {\r\n    lbl = \"Disconnect\";\r\n    butGetData.removeAttribute(\"disabled\");\r\n    butScan.removeAttribute(\"disabled\");\r\n  }\r\n  butScan.classList.toggle(\"disabled\", !connected);\r\n  butGetData.classList.toggle(\"disabled\", !connected);\r\n  butConnect.textContent = lbl;\r\n}\r\n\r\n\/**\r\n * @name parseSensorData\r\n * Parse the data from advertising data string.\r\n * @param  {string} input advertising data string.\r\n * @returns {object ={sensorid:{string}, p:{int}, t:{int}, h:{int}, als:{int}, pm1:{int}, pm25:{int}, pm10:{int}}} \r\n *\/\r\nfunction parseSensorData(input) {\r\n  let counter = 13;\r\n  if (input.includes(\"5B070503\")) {\r\n    counter = 17;\r\n  }\r\n  let sensorData = {\r\n    sensorid:\r\n      input&#91;counter + 1] +\r\n      input&#91;counter + 2] +\r\n      input&#91;counter + 3] +\r\n      input&#91;counter + 4] +\r\n      input&#91;counter + 5] +\r\n      input&#91;counter + 6],\r\n    p:\r\n      parseInt(\r\n        input&#91;counter + 13] +\r\n          input&#91;counter + 14] +\r\n          input&#91;counter + 11] +\r\n          input&#91;counter + 12],\r\n        16\r\n      ) \/ 10,\r\n    t:\r\n      parseInt(\r\n        input&#91;counter + 17] +\r\n          input&#91;counter + 18] +\r\n          input&#91;counter + 15] +\r\n          input&#91;counter + 16],\r\n        16\r\n      ) \/ 10,\r\n    h:\r\n      parseInt(\r\n        input&#91;counter + 21] +\r\n          input&#91;counter + 22] +\r\n          input&#91;counter + 19] +\r\n          input&#91;counter + 20],\r\n        16\r\n      ) \/ 10,\r\n      voc:\r\n      parseInt(\r\n        input&#91;counter + 25] +\r\n          input&#91;counter + 26] +\r\n          input&#91;counter + 23] +\r\n          input&#91;counter + 24],\r\n        16\r\n      ) \/ 10,\r\n    als: parseInt(\r\n      input&#91;counter + 9] +\r\n        input&#91;counter + 10] +\r\n        input&#91;counter + 7] +\r\n        input&#91;counter + 8],\r\n      16\r\n    ),\r\n    pm1:\r\n      parseInt(\r\n        input&#91;counter + 29] +\r\n          input&#91;counter + 30] +\r\n          input&#91;counter + 27] +\r\n          input&#91;counter + 28],\r\n        16\r\n      ) \/ 10,\r\n    pm25:\r\n      parseInt(\r\n        input&#91;counter + 33] +\r\n          input&#91;counter + 34] +\r\n          input&#91;counter + 31] +\r\n          input&#91;counter + 32],\r\n        16\r\n      ) \/ 10,\r\n    pm10:\r\n      parseInt(\r\n        input&#91;counter + 37] +\r\n          input&#91;counter + 38] +\r\n          input&#91;counter + 35] +\r\n          input&#91;counter + 36],\r\n        16\r\n      ) \/ 10}\r\n  return sensorData\r\n}\r\n\r\n<\/code><\/pre>\n\n\n\n<p><strong>Steps to run the script<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Clone the git repository .git clone&nbsp;<a href=\"https:\/\/github.com\/smart-sensor-devices-ab\/get_realtime_data_bleuio\">https:\/\/github.com\/smart-sensor-devices-ab\/get_rea\u2026<\/a><\/li><li>Connect the&nbsp;<strong>Bleuio&nbsp;<\/strong>dongle to your computer.<\/li><li>Open<strong>&nbsp;index.html<\/strong>&nbsp;file<\/li><li>Click connect and wait for the device to load on your com port.<\/li><li>Select your com port.<\/li><li>Scan for BLE devices. (this script only scan for Hibou Devices . You can change the manufacturer value at script.js file)<\/li><li>Select device and start getting data. You will see real time value on the screen.<\/li><li>Click on stop getting data to stop the script.<\/li><\/ul>\n\n\n\n<p><strong>Output<\/strong><\/p>\n\n\n\n<p>Here is the output of the script.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/smartsensordevices.com\/wp-content\/uploads\/2021\/03\/get-realtime-data-from-bluetooth-device-1024x836.jpg\" alt=\"\" class=\"wp-image-1114\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>Follow the video for better understanding<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Get realtime data from Bluetooth devices\" width=\"640\" height=\"480\" src=\"https:\/\/www.youtube.com\/embed\/LqKcOVZuXlQ?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>This project will show how to collect Realtime Bluetooth low energy data and show it on web browser. For this project, I am using Bluetooth Low Energy USB dongle called BlueIO, which will act as a central device to retrieve data. Hibou Air Quality Monitor which will serve as a peripheral device to transmit the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":42,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1,2],"tags":[],"class_list":["post-41","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-bleuio","category-bleuio-tutorial"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Collect Realtime Air Quality Data From Bluetooth Device - BleuIO - Create Bluetooth Low Energy application<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Collect Realtime Air Quality Data From Bluetooth Device - BleuIO - Create Bluetooth Low Energy application\" \/>\n<meta property=\"og:description\" content=\"This project will show how to collect Realtime Bluetooth low energy data and show it on web browser. For this project, I am using Bluetooth Low Energy USB dongle called BlueIO, which will act as a central device to retrieve data. Hibou Air Quality Monitor which will serve as a peripheral device to transmit the [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/\" \/>\n<meta property=\"og:site_name\" content=\"BleuIO - Create Bluetooth Low Energy application\" \/>\n<meta property=\"article:published_time\" content=\"2020-12-18T13:57:11+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-05-27T14:24:53+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.bleuio.com\/blog\/wp-content\/uploads\/2022\/01\/collect-and-show-data.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"620\" \/>\n\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"BleuIO\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/collect-realtime-data-from-bluetooth-device\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/collect-realtime-data-from-bluetooth-device\\\/\"},\"author\":{\"name\":\"BleuIO\",\"@id\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/#\\\/schema\\\/person\\\/89bc581382d5964043f96efc54b75b80\"},\"headline\":\"Collect Realtime Air Quality Data From Bluetooth Device\",\"datePublished\":\"2020-12-18T13:57:11+00:00\",\"dateModified\":\"2022-05-27T14:24:53+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/collect-realtime-data-from-bluetooth-device\\\/\"},\"wordCount\":415,\"image\":{\"@id\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/collect-realtime-data-from-bluetooth-device\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/wp-content\\\/uploads\\\/2022\\\/01\\\/collect-and-show-data.jpg\",\"articleSection\":[\"BleuIO\",\"BleuIO tutorial\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/collect-realtime-data-from-bluetooth-device\\\/\",\"url\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/collect-realtime-data-from-bluetooth-device\\\/\",\"name\":\"Collect Realtime Air Quality Data From Bluetooth Device - BleuIO - Create Bluetooth Low Energy application\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/collect-realtime-data-from-bluetooth-device\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/collect-realtime-data-from-bluetooth-device\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/wp-content\\\/uploads\\\/2022\\\/01\\\/collect-and-show-data.jpg\",\"datePublished\":\"2020-12-18T13:57:11+00:00\",\"dateModified\":\"2022-05-27T14:24:53+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/#\\\/schema\\\/person\\\/89bc581382d5964043f96efc54b75b80\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/collect-realtime-data-from-bluetooth-device\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/collect-realtime-data-from-bluetooth-device\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/collect-realtime-data-from-bluetooth-device\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/wp-content\\\/uploads\\\/2022\\\/01\\\/collect-and-show-data.jpg\",\"contentUrl\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/wp-content\\\/uploads\\\/2022\\\/01\\\/collect-and-show-data.jpg\",\"width\":620,\"height\":350,\"caption\":\"Collect Realtime Data From Bluetooth Device\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/collect-realtime-data-from-bluetooth-device\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Collect Realtime Air Quality Data From Bluetooth Device\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/\",\"name\":\"BleuIO - Create Bluetooth Low Energy application\",\"description\":\"Learn Bluetooth Low Energy programming and build Bluetooth Low Energy Application\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/#\\\/schema\\\/person\\\/89bc581382d5964043f96efc54b75b80\",\"name\":\"BleuIO\",\"sameAs\":[\"https:\\\/\\\/www.bleuio.com\\\/blog\"],\"url\":\"https:\\\/\\\/www.bleuio.com\\\/blog\\\/author\\\/biadmin\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Collect Realtime Air Quality Data From Bluetooth Device - BleuIO - Create Bluetooth Low Energy application","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/","og_locale":"en_US","og_type":"article","og_title":"Collect Realtime Air Quality Data From Bluetooth Device - BleuIO - Create Bluetooth Low Energy application","og_description":"This project will show how to collect Realtime Bluetooth low energy data and show it on web browser. For this project, I am using Bluetooth Low Energy USB dongle called BlueIO, which will act as a central device to retrieve data. Hibou Air Quality Monitor which will serve as a peripheral device to transmit the [&hellip;]","og_url":"https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/","og_site_name":"BleuIO - Create Bluetooth Low Energy application","article_published_time":"2020-12-18T13:57:11+00:00","article_modified_time":"2022-05-27T14:24:53+00:00","og_image":[{"width":620,"height":350,"url":"https:\/\/www.bleuio.com\/blog\/wp-content\/uploads\/2022\/01\/collect-and-show-data.jpg","type":"image\/jpeg"}],"author":"BleuIO","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/#article","isPartOf":{"@id":"https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/"},"author":{"name":"BleuIO","@id":"https:\/\/www.bleuio.com\/blog\/#\/schema\/person\/89bc581382d5964043f96efc54b75b80"},"headline":"Collect Realtime Air Quality Data From Bluetooth Device","datePublished":"2020-12-18T13:57:11+00:00","dateModified":"2022-05-27T14:24:53+00:00","mainEntityOfPage":{"@id":"https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/"},"wordCount":415,"image":{"@id":"https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/#primaryimage"},"thumbnailUrl":"https:\/\/www.bleuio.com\/blog\/wp-content\/uploads\/2022\/01\/collect-and-show-data.jpg","articleSection":["BleuIO","BleuIO tutorial"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/","url":"https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/","name":"Collect Realtime Air Quality Data From Bluetooth Device - BleuIO - Create Bluetooth Low Energy application","isPartOf":{"@id":"https:\/\/www.bleuio.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/#primaryimage"},"image":{"@id":"https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/#primaryimage"},"thumbnailUrl":"https:\/\/www.bleuio.com\/blog\/wp-content\/uploads\/2022\/01\/collect-and-show-data.jpg","datePublished":"2020-12-18T13:57:11+00:00","dateModified":"2022-05-27T14:24:53+00:00","author":{"@id":"https:\/\/www.bleuio.com\/blog\/#\/schema\/person\/89bc581382d5964043f96efc54b75b80"},"breadcrumb":{"@id":"https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/#primaryimage","url":"https:\/\/www.bleuio.com\/blog\/wp-content\/uploads\/2022\/01\/collect-and-show-data.jpg","contentUrl":"https:\/\/www.bleuio.com\/blog\/wp-content\/uploads\/2022\/01\/collect-and-show-data.jpg","width":620,"height":350,"caption":"Collect Realtime Data From Bluetooth Device"},{"@type":"BreadcrumbList","@id":"https:\/\/www.bleuio.com\/blog\/collect-realtime-data-from-bluetooth-device\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.bleuio.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Collect Realtime Air Quality Data From Bluetooth Device"}]},{"@type":"WebSite","@id":"https:\/\/www.bleuio.com\/blog\/#website","url":"https:\/\/www.bleuio.com\/blog\/","name":"BleuIO - Create Bluetooth Low Energy application","description":"Learn Bluetooth Low Energy programming and build Bluetooth Low Energy Application","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.bleuio.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.bleuio.com\/blog\/#\/schema\/person\/89bc581382d5964043f96efc54b75b80","name":"BleuIO","sameAs":["https:\/\/www.bleuio.com\/blog"],"url":"https:\/\/www.bleuio.com\/blog\/author\/biadmin\/"}]}},"_links":{"self":[{"href":"https:\/\/www.bleuio.com\/blog\/wp-json\/wp\/v2\/posts\/41","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.bleuio.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bleuio.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bleuio.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bleuio.com\/blog\/wp-json\/wp\/v2\/comments?post=41"}],"version-history":[{"count":4,"href":"https:\/\/www.bleuio.com\/blog\/wp-json\/wp\/v2\/posts\/41\/revisions"}],"predecessor-version":[{"id":308,"href":"https:\/\/www.bleuio.com\/blog\/wp-json\/wp\/v2\/posts\/41\/revisions\/308"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.bleuio.com\/blog\/wp-json\/wp\/v2\/media\/42"}],"wp:attachment":[{"href":"https:\/\/www.bleuio.com\/blog\/wp-json\/wp\/v2\/media?parent=41"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bleuio.com\/blog\/wp-json\/wp\/v2\/categories?post=41"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.bleuio.com\/blog\/wp-json\/wp\/v2\/tags?post=41"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}