Create an Ambient-Adaptive real-time CO2 Bar
2025-10-22 | By Sheikh Shuhad
License: GNU Lesser General Public License Air Quality Bluetooth / BLE
This tutorial walks you through a tiny, privacy-first web app that reads only the advertised CO₂ level from a nearby HibouAir sensor using a BleuIO USB BLE dongle. There’s no pairing, cloud, or backend—just your browser, the dongle, and a page that decodes a numeric CO₂ value broadcast in BLE advertisements and renders it as a color bar (default window 400–2000 ppm) with a simple “High CO₂” warning when your threshold is crossed.
What you’ll build
A single HTML file that talks to BleuIO over the Web Serial API. The page puts BleuIO in the central role, periodically runs a targeted scan for your HibouAir Board ID, and parses the Manufacturer Specific Data (MSD) bytes in each advertisement to extract CO₂ (ppm). The value drives a horizontal gradient bar; cross the threshold, and a warning banner appears. Everything runs locally in the browser.
Code: GitHub repository
Try it now: Live demo on GitHub Pages — Plug in BleuIO, and press Connect. Make sure to pass the correct HibouAir Board ID
Why a CO2-only, browser-based monitor?
CO₂ is a practical proxy for ventilation. Elevated levels are associated with stale air, drowsiness, and reduced productivity. Many spaces—meeting rooms, classrooms, offices, homes—benefit from quick visual feedback so people know when to air out the room. Reading only a single, device-computed number from BLE advertisements keeps the design simple, fast, and privacy-preserving.
Hardware & software
How it works (at a glance)
BLE devices periodically broadcast short advertisement packets with real-time CO₂ values. We can read them without pairing.
This page filters to a specific Board ID, captures the advertisement line, extracts the longest hex payload, and then decodes CO₂ from a fixed position inside the MSD. The result is mapped to a 0–100% fill of the bar (for a display window of 400–2000 ppm), and we show a banner when CO₂ ≥ threshold (default 1000 ppm).
Below is the exact function used in this project:
function decodeCo2FromAdv(hex) { // sanitize → bytes hex = (hex || '').replace(/[^0-9A-F]/gi, ''); if (hex.length % 2) hex = hex.slice(0, -1); const b = new Uint8Array(hex.length / 2); for (let i = 0; i < b.length; i++) b[i] = parseInt(hex.substr(i*2,2), 16); // locate MSD anchor and read CO2 at fixed offset (big-endian) for (let i = 0; i <= b.length - 5; i++) { if (b[i] === 0x5B && b[i+1] === 0x07 && b[i+2] === 0x05) { const idx = i + 23; // CO2 MSB position in this layout if (idx + 1 < b.length) { return (b[idx] << 8) | b[idx+1]; // ppm } } } return null; }
The BLE flow
When you click Connect, the page opens a serial session to BleuIO and sends:
AT+CENTRAL
once, to enter scanning modeAT+FINDSCANDATA=<BOARD_ID>=3
every cycle to run a 3-second targeted scanThe reader consumes lines until BleuIO prints
SCAN COMPLETE
, then waits and repeats
Each time an advertisement arrives, the page extracts the hex payload, decodes CO₂, updates the bar, and toggles the High CO₂ banner if the threshold is exceeded.
Output
You’ll see a horizontal color bar labeled with the current CO₂ ppm. The bar fills from left to right as values rise within the 400–2000 ppm window. A bold High CO₂ banner appears when the reading crosses your threshold (default 1000 ppm), serving as a polite nudge to improve ventilation.
Use cases
This simple CO₂ bar works well anywhere people gather and the air can get stale. In meeting rooms and classrooms, it provides a live cue to crack a window or switch on ventilation as occupancy rises. In open offices, it nudges teams toward timely air exchanges, helping reduce stuffiness and afternoon dips in alertness. At home, it’s a lightweight way to keep bedrooms and living spaces fresh during gatherings or winter months with closed windows. Shared studios and makerspaces also benefit from quick, ambient feedback without the overhead of dashboards or wall displays.
Because the app reads only a single numeric value that HibouAir already broadcasts, it avoids handling personal data and is easy to deploy in privacy-sensitive environments.
Accuracy & practical notes
This is a lightweight indicator, not a calibration tool. CO₂ readings in advertisements update periodically and represent the sensor’s current value. Placement matters: keep your HibouAir within a reasonable range of BleuIO to reduce missed packets. If your environment regularly exceeds the default window, you can adjust the display range and threshold in the code.
Extend the project
You can grow this prototype in several practical directions. Start by logging readings to CSV or IndexedDB for simple trend analysis over days or weeks. If you have multiple sensors, add a multi-device view that scans several board IDs and presents compact tiles on one page. For automation, trigger a webhook or send a serial command to control a fan or relay whenever CO₂ exceeds your threshold. You can also pair it with the earlier Noise Bar and show Noise and CO₂ side-by-side for a fuller picture of comfort and productivity.