Introducing BleuIO Academy: Learn Bluetooth Low Energy from Basics to Real-World Development

Bluetooth Low Energy (BLE) has become an important part of modern connected devices. From wireless sensors and fitness trackers to industrial monitoring systems and smart home applications, BLE makes it possible for devices to communicate efficiently while keeping power consumption low.

For developers who are just getting started, however, understanding Bluetooth Low Energy can sometimes feel complicated. Terms like advertising, scanning, central and peripheral roles, GATT, services, and characteristics can be confusing at first. Even developers with programming experience may find it challenging to understand how these concepts work together in a real application.

To make learning BLE easier and more practical, we’re excited to introduce BleuIO Academy, a new learning resource designed to help anyone understand Bluetooth Low Energy and gradually move toward building real BLE applications.

Explore BleuIO Academy: https://www.bleuio.com/learn-ble/

Learning Bluetooth Low Energy, One Step at a Time

BleuIO Academy is designed around a simple idea: learning Bluetooth Low Energy should be approachable, structured, and practical.

Rather than jumping directly into complicated code or technical specifications, the Academy starts with the fundamentals. Readers can first understand what BLE is, how it differs from traditional Bluetooth, and why it is widely used in connected devices.

From there, lessons gradually introduce the different parts of BLE communication, including advertising, device discovery, connections, GATT, and data exchange.

Each lesson focuses on a specific topic and uses clear explanations, illustrations, diagrams, and practical examples to make technical concepts easier to understand.

The Academy follows a structured learning path, but readers don’t have to start from the beginning. Developers looking for information about a particular BLE topic can explore individual lessons directly.

Who Is BleuIO Academy For?

We created BleuIO Academy for people with different levels of experience.

If you’re completely new to Bluetooth Low Energy, the beginner lessons provide a starting point without requiring previous BLE knowledge. You can learn the terminology, understand how devices communicate, and become familiar with the concepts that appear throughout BLE development.

If you’re already a software developer, the Academy can help you connect your programming knowledge with Bluetooth communication. Understanding how BLE devices advertise, establish connections, and exchange data is an important foundation before developing applications with languages such as Python, JavaScript, or C#.

For embedded developers, IoT engineers, and more experienced BLE users, the learning path also includes topics such as communication architecture, device security, performance, power consumption, troubleshooting, and real-world system design.

Whether you’re a student exploring wireless technology, a hobbyist working on an electronics project, or an engineer developing a connected product, the goal is to provide useful information that you can apply to your own work.

Go Beyond Theory with Hands-On BLE Learning

Reading about Bluetooth Low Energy is useful, but observing real BLE communication makes the concepts much easier to understand.

That’s why practical learning is an important part of BleuIO Academy.

Where appropriate, lessons include Try It Yourself sections that guide readers through real BLE operations using a BleuIO USB dongle and the BleuIO Web App.

For example, when learning about BLE advertising and discovery, you can use the Web App to scan for nearby Bluetooth Low Energy devices, observe scan results, and become familiar with the information available from advertising devices.

The exercises explain what you need, which steps to follow, what to look for in the results, and how the activity relates to the topic being taught.

The BleuIO Web App provides a convenient browser-based environment for supported BLE operations, allowing developers to experiment with their dongle without first building a separate application. It requires a compatible desktop browser and computer.

Not every lesson requires hardware. Many concepts can be understood through explanations, diagrams, and interactive learning activities. When a hands-on demonstration is useful, the Academy shows how to take that next step.

From Understanding BLE to Writing Real Code

Understanding BLE concepts is only the beginning. The next challenge is applying that knowledge in software and hardware projects.

As BleuIO Academy grows, we’re expanding the learning path to cover practical BLE programming and development using technologies such as Python, JavaScript, Node.js, React, and embedded development platforms.

The goal is to help learners move naturally from understanding a concept to implementing it.

For example, someone learning about BLE scanning can eventually build a program that discovers nearby devices. Someone studying GATT services and characteristics can move on to reading sensor measurements, receiving notifications, or creating an application that displays live data.

We’ll also connect relevant lessons to existing projects available on the BleuIO real world projects, where developers can explore practical applications involving sensors, development boards, gateways, and different programming environments.

These examples provide an opportunity to see how BLE concepts are used outside a textbook and how they fit into complete applications.

A Structured Learning Path That Will Keep Growing

BleuIO Academy is organized into eight learning modules, covering the journey from introductory BLE concepts to more advanced development and troubleshooting.

The first module, Introduction to Bluetooth Low Energy, is available and covers the fundamentals, how BLE works, communication roles, comparisons with other wireless technologies, and common applications.

We’ve also started publishing lessons about BLE architecture, advertising, scanning, and device discovery.

Additional topics are already included in the learning roadmap and are marked as Coming Soon. These will be published gradually as new educational material, diagrams, code examples, and practical exercises are prepared.

We want the Academy to grow into a dependable reference that developers can return to whenever they’re learning something new or working through a Bluetooth Low Energy problem.

Start Learning with BleuIO Academy

BleuIO Academy is freely accessible through the BleuIO website. You don’t need an account to start reading the lessons, and you can explore the topics at your own pace.

If you’re new to BLE, we recommend beginning with the fundamentals and following the lessons in order. If you already have experience, you can navigate directly to the topics that interest you.

Visit the Academy here:

Explore BleuIO Academy — Learn Bluetooth Low Energy

We’re looking forward to expanding this resource with more tutorials, practical code examples, interactive explanations, and real-world BLE projects.

Our hope is that BleuIO Academy becomes a useful place for the Bluetooth developer community to learn, experiment, and build with greater confidence.

Whether you’re discovering Bluetooth Low Energy for the first time or developing your next connected application, we hope you’ll find something useful in BleuIO Academy.

Share this post on :

Build a BLE Signal Strength Analyzer with Live Charts Using BleuIO, Python and Plotly

RSSI analysis becomes much easier when you can see the signal changing instead of watching a stream of numbers in a terminal. A chart makes it possible to notice movement, sudden drops, periods of instability, and differences between devices almost immediately.

In this project, we use a BleuIO USB dongle with Python and Plotly Dash to build a live BLE signal strength analyzer. The application scans nearby BLE advertisers, lets us select a device, and follows its RSSI over time. It also provides a quick overview of every device currently being discovered.

This is intended as a starting point rather than a complete positioning or ranging system. If you already work with RSSI, the dashboard gives you a practical base for collecting observations, testing an environment, and extending the analysis for your own use case.

What the analyzer provides

The dashboard is organized around one selected BLE device. Its current RSSI, smoothed RSSI, recent trend, and signal stability appear directly above a live time-series chart. The raw readings remain visible, so the processed line never hides what the dongle actually received.

Below the main analysis, the Discovered Now section compares the latest RSSI values from nearby devices. An RSSI distribution chart shows how the selected device’s readings are spread across the recent observation window.

This combination is useful when you want to answer practical questions such as whether a signal is consistently weak, whether it is changing direction, or whether an apparently stable device is producing occasional large variations.

Hardware and software

You will need:

The application uses pySerial to communicate with BleuIO and Plotly Dash for the local dashboard. BleuIO handles the BLE radio operation, so the Python application only needs to work with its serial AT-command interface.

Download and install the project

Clone the repository and move into the project directory:


git  clone  https://github.com/smart-sensor-devices-ab/bleuio-rssi-analyzer.git

cd  bleuio-rssi-analyzer

On macOS or Linux, create a virtual environment and install the dependencies:


python3  -m  venv  .venv

source  .venv/bin/activate

python  -m  pip  install  -r  requirements.txt

On Windows PowerShell, use:


py -m venv .venv

.venv\Scripts\Activate.ps1

python -m pip install -r requirements.txt

Connect the BleuIO dongle before starting the application. BleuIO briefly exposes its bootloader after power-up, so allow approximately 15 seconds for the normal application serial port to appear.

Start the analyzer:


python  app.py

Then open http://127.0.0.1:8050 in a browser.

Start scanning

The serial-port menu only shows ports identified as BleuIO devices. On macOS, this normally looks like /dev/cu.usbmodem.... On Windows, the dongle may appear as a generic USB Serial Device (COMx), so the application also recognizes BleuIO by its USB vendor and product identifiers.

Select the dongle and click Start scan. The application places BleuIO in central role and repeatedly performs a short timed scan using AT+GAPSCAN=1. Repeating the timed scan gives the dashboard a continuing series of fresh RSSI observations instead of a single discovery result. The command behavior is documented in the BleuIO AT command reference.

As advertisements are received, nearby addresses appear in the BLE device menu. Select the device you want to examine, and the analysis area updates immediately.

Follow a selected signal

The Current RSSI card displays the most recent reading. This value is useful for immediate feedback, but normal radio variation can make it jump even when neither device has deliberately moved.

The Smoothed RSSI view makes the overall movement easier to follow. The project first applies a short median filter to reduce isolated spikes, followed by an exponentially weighted moving average that gives more importance to recent observations. The original samples remain visible as dots, while the smoothed result appears as the blue line.

This processing is deliberately lightweight. It is enough to make the live chart readable, but it is also easy to replace if your experiment needs a Kalman filter, a different smoothing window, or no filtering at all.

Read the trend and stability indicators

The Recent Trend card compares the latest smoothed value with the recent signal history. A change of at least 4 dB is described as Getting stronger or Getting weaker. Smaller changes are shown as Stable. The card also displays the measured change, making the label easy to interpret rather than presenting it as an unexplained classification.

The Signal Stability card looks at the variation among the latest raw readings. A tightly grouped signal is labeled Steady. Greater variation is reported as Variable or Unstable. Strength and stability are treated separately: a weak signal can still be steady, and a strong signal can fluctuate considerably.

These thresholds are sensible defaults for exploring a signal, not universal BLE rules. They are kept in a small analysis module so they can be adjusted for the advertising interval, environment, antenna, and behavior of the device being studied.

Compare nearby devices

The Discovered Now chart provides context for the focused analysis. It shows the latest RSSI from every address found during the scan, ordered from stronger to weaker signals. This is useful when choosing a target or checking how crowded the local BLE environment is.

The distribution beside it belongs only to the selected device. It counts how often recent readings occurred within each RSSI range. A narrow group of bars usually accompanies a steadier signal, while a wider spread reveals more variation. The chart can be especially useful when comparing two locations or antenna orientations that have a similar average RSSI but different consistency.

Try a simple observation

Choose a BLE advertiser that sends packets regularly and leave it in a fixed position. Let the analyzer collect readings for a short period, then change one condition at a time: rotate the device, move it farther away, place an obstacle between it and BleuIO, or walk through the signal path.

The raw samples show the immediate radio response. The smoothed line makes the larger movement easier to see, while the trend and stability cards provide a compact summary. The distribution shows whether the new condition changed only the average signal or also made it more variable.

The goal is not to turn RSSI into an exact ruler. Bluetooth radio measurements are affected by the environment, reflections, antenna orientation, and the human body. The Bluetooth SIG notes that newer Bluetooth Channel Sounding is more reliable for accurate ranging than approaches that use RSSI as a distance proxy. The Bluetooth Low Energy primer provides useful background on that distinction.

For this project, RSSI is used for what it does well: observing relative signal behavior, detecting meaningful changes, and building an experiment around real measurements.

Take the project further

The source is intentionally compact so it can be adapted. A next version could save readings to CSV, compare multiple selected devices, add experiment markers, calculate packet reception rates, or load a calibration profile for a known environment. The analysis functions can also be replaced without changing the BleuIO serial scanner or the dashboard structure.

You can find the complete application, installation instructions, and tests in the BleuIO RSSI Analyzer repository.

With a live view of both raw and processed RSSI, the project turns BleuIO into a useful signal exploration tool—and a practical foundation for more focused BLE research.

Share this post on :

BleuIO Firmware v2.8.0.6 Released: Enhanced MTU Control and Improved DUAL Mode Reliability

We’re pleased to announce the release of BleuIO firmware v2.8.0.6, introducing new Bluetooth Low Energy (BLE) connection controls and improvements to DUAL mode reliability.

This update gives developers greater flexibility in managing MTU (Maximum Transmission Unit) negotiation while ensuring more consistent connection behavior when operating in DUAL mode.

Let’s take a look at what’s new.

What’s New in Firmware v2.8.0.6?

1. Manual MTU Exchange with AT+REQMTU

The new AT+REQMTU command allows developers to manually initiate a GATT client (GATTC) MTU exchange at any point after establishing a BLE connection.

MTU determines the maximum size of an ATT packet exchanged between connected BLE devices. Negotiating an appropriate MTU can help improve data transfer efficiency.

New command:

AT+REQMTU

With this feature, developers can:

  • Request MTU negotiation whenever needed after connection.
  • Gain greater control over BLE communication workflows.
  • Simplify testing and debugging of MTU-related behavior.

This functionality is similar to manual MTU requests available in BLE development tools such as nRF Connect.

2. Automatic MTU Negotiation Control with AT+AUTOMTU

Firmware v2.8.0.6 also introduces AT+AUTOMTU, allowing developers to enable or disable automatic MTU negotiation during connection parameter updates.

New commands:

  • AT+AUTOMTU=1 — Enable automatic MTU negotiation.
  • AT+AUTOMTU=0 — Disable automatic MTU negotiation.

When automatic negotiation is disabled, developers can use AT+REQMTU to trigger MTU exchanges manually.

Together, these commands provide greater flexibility for applications requiring precise BLE connection management.

Improved DUAL Mode Connection Reliability

This release also resolves an intermittent issue where BleuIO could initialize into the incorrect client or server role while operating in DUAL mode.

With the latest firmware, BleuIO now correctly determines its role based on the connection type:

  • Incoming connection: BleuIO operates in the server role.
  • Outgoing connection: BleuIO switches to the client role.

This fix ensures more predictable connection behavior for applications that use both BLE central and peripheral functionality.

How to Update Your BleuIO

There are two convenient ways to update your BleuIO to firmware v2.8.0.6.

Option 1: Download and Install the Latest Firmware

You can download the BleuIO firmware and follow the firmware update instructions in our official documentation:

Download the latest BleuIO firmware and view the update guide

Option 2: Update Using the BleuIO Web App

You can also update your BleuIO directly through the BleuIO web application, which provides a convenient browser-based firmware update process.

Update BleuIO using the web app

Make sure to select the correct firmware for your BleuIO device model before updating.

Update your BleuIO to firmware v2.8.0.6 and take advantage of improved MTU management and more reliable DUAL mode connections.

Stay connected for more BleuIO updates, developer resources, and Bluetooth Low Energy tutorials at bleuio.com.

Share this post on :

BleuIO Pro Firmware v1.0.7.3 Released: Improved GATT Discovery and MTU Control

We’re pleased to announce the release of BleuIO Pro firmware v1.0.7.3, introducing new MTU negotiation commands, improved GATT discovery stability, and optimized handling of complex Bluetooth Low Energy (BLE) devices.

This update gives developers greater control over BLE connections while improving performance and reliability when working with peripherals containing large GATT databases.

New MTU Negotiation Controls

Firmware v1.0.7.3 introduces two new AT commands for managing MTU negotiation.

AT+REQMTU – Request MTU Exchange Manually

The new AT+REQMTU command allows developers to initiate a GATT client MTU exchange at any point after establishing a BLE connection.

This provides greater flexibility when testing peripheral behavior, debugging connections, or managing specific connection workflows.

AT+AUTOMTU – Control Automatic MTU Negotiation

The new AT+AUTOMTU command lets developers enable or disable automatic MTU negotiation during connection parameter updates.

  • AT+AUTOMTU=1 – Enable automatic MTU negotiation.
  • AT+AUTOMTU=0 – Disable automatic MTU negotiation.

When disabled, developers can use AT+REQMTU to trigger the exchange manually, allowing more predictable connection handling in automated scripts and applications.

Improved GATT Discovery Stability

This release addresses an issue where BleuIO Pro could unexpectedly reset while discovering services and characteristics on peripherals with exceptionally large GATT databases.

The discovery engine has been redesigned to use a sequential streaming architecture instead of memory-intensive hierarchical caching.

With this improvement, GATT attributes are processed dynamically and sent to the USB interface as they are discovered.

Key benefits include:

  • Reduced memory consumption during GATT discovery.
  • Improved connection stability with complex BLE peripherals.
  • Support for up to 165 characteristics within a single service.
  • More efficient processing of large GATT profiles.

These improvements apply to the following commands:

  • AT+GETSERVICES
  • AT+GETSERVICESONLY
  • AT+GETSERVICEDETAILS

GATT Discovery Output Changes

With the new streaming architecture, discovered GATT attributes are reported immediately as they are processed.

One small change affects the presentation order of descriptors. Previously, descriptors such as CCCDs (0x2902) appeared directly after their associated characteristics. They are now grouped at the end of the corresponding service block.

Important: All JSON fields in verbose mode and standard text-mode output strings remain unchanged. Only the order of descriptor entries has been modified.

Developers using custom parsers that depend on descriptor ordering should review their implementation to ensure compatibility.

How to Update Your Firmware

Updating your BleuIO Pro is straightforward.

You can download the latest firmware and follow the step-by-step update instructions in our official documentation:

BleuIO Pro Firmware Update Guide

Alternatively, you can update directly from your browser using the BleuIO web application:

Update Firmware Using BleuIO Web App

Both methods provide a simple way to get your BleuIO Pro running the latest firmware.

We recommend updating to v1.0.7.3 to benefit from the latest MTU controls, improved GATT discovery stability, and support for larger peripheral profiles.

Share this post on :

Scanning HibouAir Sensors with CircuitPython, BleuIO and the Cytron MOTION 2350 Pro

In this tutorial we will use CircuitPython to turn a Cytron MOTION 2350 Pro into a HibouAir scanner. The board’s RP2350 has no Bluetooth radio of its own. A BleuIO dongle in the board’s USB-A host port provides Bluetooth Low Energy, and a short CircuitPython program talks to it with ordinary AT commands.

The program scans for air quality monitoring device HibouAir advertisements, decodes them, and keeps the latest readings in global variables. One of them, the PM10 value from a HibouAir PM sensor, is ready to be used by the rest of your program. As an example, the program turns a hobby servo on one of the board’s servo ports into an analog PM10 gauge.

Everything runs on the board. No computer is needed once the code is in place, and the HibouAir sensors do not need to be paired.

Requirements

Hardware

Software

  • CircuitPython 10.x for the Cytron MOTION 2350 Pro, from circuitpython.org. The tutorial uses 10.3.1.
  • Two libraries from the Adafruit CircuitPython Library Bundle for version 10.x, copied into the lib folder on the CIRCUITPY drive:
    • asyncio (the whole folder)
    • adafruit_ticks.mpy, which asyncio needs

With circup installed on your computer, one command copies both:

circup install asyncio

Everything else the program uses is built into CircuitPython: usb_host, usb.core, json, binascii, microcontroller, pwmio and time. The servo is driven with pwmio directly, so it needs no extra library. No boot.py is needed.

What Does This Project Do?

1. The board becomes a USB host

The MOTION 2350 Pro’s USB-A port is driven by the RP2350’s PIO. CircuitPython starts it with usb_host.Port on GPIO24 and GPIO25. The board definition has no named pins for this port, so the program uses the raw pins.

2. CircuitPython finds BleuIO

The program waits until a device with vendor ID 0x2DCF and product ID 0x6002 appears, which is BleuIO. It selects the dongle’s configuration and sets DTR and RTS, so that BleuIO starts sending its output.

3. The dongle is brought into a known state

BleuIO remembers what it was doing, so a scan from an earlier run may still be going. The program first sends Ctrl-C three times to stop it. It then throws away everything the dongle sends until it has been quiet for 0.3 seconds. After that it sends:

  • ATE0, which turns echo off
  • ATV1, which turns verbose mode on, so every reply is one line of JSON

4. BleuIO scans for HibouAir only

AT+FINDSCANDATA=FF5B07

This reports only advertisements that contain FF5B07. FF is the AD type for manufacturer-specific data, and 5B 07 is HibouAir’s company ID, 0x075B, as it appears in the packet. Each result arrives as a line such as:

{"SF":127,"addr":"D9:63:8F:8E:01:0D","type":0,"data":"0201061BFF5B070504220095AE009627CF00AC014200000000000000019902"}

5. The board decodes the advertisement

The program walks the advertisement’s AD structures until it finds the HibouAir manufacturer data. This works whether or not the flags field comes first. Counting from the company ID, the sensor beacon (beacon type 0x05) holds:

OffsetFieldFormat
2Beacon type0x05 for sensor readings
3Board type0x03 is the PM sensor
4–6Sensor IDas shown in the HibouAir app, e.g. 22026A
9Pressure16-bit little-endian, tenths of hPa
11Temperature16-bit little-endian, signed, tenths of °C
13Humidity16-bit little-endian, tenths of %rh
17PM1.016-bit little-endian, tenths of µg/m³
19PM2.516-bit little-endian, tenths of µg/m³
21PM1016-bit little-endian, tenths of µg/m³
23CO216-bit big-endian, ppm

6. The readings are kept in global variables

  • pm10: the latest PM10 value in µg/m³, or None until a PM sensor has been heard
  • pm10_sensor: the ID of the sensor it came from
  • pm10_time: time.monotonic() when it arrived, so that a stale value can be recognised
  • sensors: a dictionary with everything the last beacon of every HibouAir sensor said, keyed by sensor ID

If you have more than one PM sensor, set PM_SENSOR_ID to the one pm10 should follow. If nothing has been heard for 15 seconds, the program starts the scan again.

Showing PM10 on a Servo Gauge

The MOTION 2350 Pro has eight servo ports, on GP0 to GP7, each with a PWM channel of its own. The program drives a servo on GP0 as a needle: 0 µg/m³ at 0 degrees, and 100 µg/m³ or more at 180 degrees.

With that full scale, the PM10 limits the HibouAir app uses fall at simple angles. That is where to draw the bands on a paper scale behind the servo arm:

PM10LevelNeedle
0–20 µg/m³Good0–36°
20–50 µg/m³Fair36–90°
50–100 µg/m³Poor90–180°
100 µg/m³ and aboveBad180°

The gauge is its own asyncio task, beside the reader and the command logic:

  • It sends a 50 Hz servo signal, from 500 µs at 0 degrees to 2500 µs at 180.
  • It moves the needle 2 degrees every 20 ms, so the arm swings to a new reading instead of jumping.
  • At start it sweeps once across the whole scale. A servo that is not connected is then noticed at once, instead of being taken for clean air.
  • Once the needle has been still for half a second, the pulses stop. A servo told to hold a position holds it actively, and at 0 degrees, the commonest reading of all, it pushes against its end stop and hums. Without pulses an ordinary hobby servo goes quiet and stays where it is.
  • The pulses start again when a new reading moves the needle by at least one degree, so readings of 0.0 and 0.1 µg/m³ taking turns do not wake it.

Connect the servo to the GP0 servo header, matching the servo cable to the markings next to the header. Check Cytron’s datasheet for how the servo ports are supplied before connecting a larger servo.

The settings are at the top of code.py:

  • SERVO_PIN: the port, board.GP0 to board.GP7
  • PM10_FULL_SCALE: the PM10 value at 180 degrees
  • SERVO_MIN_US and SERVO_MAX_US: the pulse widths at the ends. Narrow them if your servo strains at its end stops.
  • SERVO_STEP_DEG: how fast the needle moves
  • SERVO_REST_S and SERVO_DEADBAND_DEG: how long the needle is still before it rests, and how far a reading must move it to wake it

The board’s four DC motor drivers, on GP8 to GP15 (board.M1A to board.M4B in CircuitPython), would suit a different use of the same value, such as running a fan faster as PM10 rises.

Why the Flush After Ctrl-C Matters

Ctrl-C stops the scan, but whatever BleuIO had already queued still arrives afterwards. Often the last piece is a line cut off in the middle, sometimes with a byte that is not valid UTF-8.

In early versions of this program, a reader that tried to decode that line before removing it from its buffer stuck on it. Every later piece of data was appended behind the same broken line, and the program heard nothing more, in about half of all restarts.

The program now does two things:

  • It removes each line from the buffer before decoding it, so a broken line costs that line only.
  • It discards everything until the dongle has been quiet before sending the next command.

With both in place, the start-up worked every time in repeated tests, whether the dongle was fresh (echo on, verbose off) or left in verbose mode by an earlier run.

How to Run the Project

Step 1: Install CircuitPython

Download the CircuitPython UF2 for the Cytron MOTION 2350 Pro and put the board into its UF2 bootloader mode. On RP2350 boards this is done by holding BOOT while pressing RESET, or while connecting the USB cable. Copy the UF2 to the RP2350 drive that appears. The board restarts as a drive named CIRCUITPY.

Step 2: Add the libraries

Run circup install asyncio, or copy the asyncio folder and adafruit_ticks.mpy from the library bundle into CIRCUITPY/lib.

Step 3: Copy the program

Save the code at the end of this post as code.py on the CIRCUITPY drive. CircuitPython starts it as soon as the file is saved.

Step 4: Connect BleuIO

Insert the BleuIO dongle into the board’s USB-A port. Do not connect BleuIO to the computer for this setup.

Step 5: Connect the servo (optional)

Plug the servo into the GP0 servo header. It sweeps once from 0 to 180 degrees and back when the program starts, then follows PM10, and goes quiet whenever the needle is still.

Step 6: Watch the serial console

Open the board’s serial console at 115200 baud. Use Mu, Thonny or the CircuitPython web workflow, or on macOS and Linux:

screen /dev/cu.usbmodem2101 115200

The device name differs from computer to computer. If the console shows raw REPL; CTRL-B to exit, an editor has left it in raw REPL mode: press Ctrl-B, then Ctrl-D to start code.py.

Expected Output

BleuIO dongle found! (0x2dcf:0x6002)
CDC Control Lines (DTR/RTS) enabled.
Starting background USB reader task...
Starting the HibouAir scan...
[Sending]: ATE0
[Sending]: ATV1
[Sending]: AT+FINDSCANDATA=FF5B07
[HibouAir 22026A] PM10 0.1 ug/m3  PM2.5 0.1  PM1 0.0  21.8 C
[HibouAir 22008C] board 0x04, 21.5 C, 39.8 %rh, CO2 459 ppm
[HibouAir 220095] board 0x04, 20.8 C, 42.9 %rh, CO2 411 ppm
[HibouAir 22005A] board 0x04, 19.6 C, 44.2 %rh, CO2 721 ppm
[HibouAir 220265] board 0x09, 19.8 C, 45.5 %rh, CO2 533 ppm

Every HibouAir sensor in range appears with its ID. Lines from the PM sensor show the particle readings; the others show temperature, humidity and CO2. Each new PM line also updates pm10.

The Code

Source code is available to download from

https://github.com/smart-sensor-devices-ab/hibouair-with-circuitpython

This project is a practical example of how BleuIO can bring Bluetooth Low Energy connectivity to development boards without built-in Bluetooth support. Using the Cytron MOTION 2350 Pro and CircuitPython, we demonstrated how to scan for HibouAir sensors, read real-time data, and use that data to control a servo motor.

The complete source code is available for developers to explore, modify, and integrate into their own projects. Whether you’re building sensor monitoring systems, automation solutions, or custom IoT applications, this example provides a starting point for using BleuIO with compatible development boards.

Share this post on :

Send BLE Air Quality Data to Cloudflare D1 with Python and BleuIO

In this tutorial, we will build a simple BLE-to-cloud air quality gateway using HibouAir, BleuIO, Python, Cloudflare Workers, and Cloudflare D1.

A HibouAir sensor will advertise its air quality measurements over Bluetooth Low Energy. BleuIO, connected to a computer through USB, will scan for a specific HibouAir device and provide the BLE advertising data to a Python application through the serial port. The Python application will decode CO2, temperature, and humidity, display the measurements in the terminal, and upload them to a Cloudflare Worker. The Worker will then store the measurements in a Cloudflare D1 database.

This project is intentionally kept simple. It demonstrates how BleuIO can act as the Bluetooth interface for a desktop or gateway application without requiring the application itself to manage a Bluetooth stack.

Why Cloudflare D1?

Cloudflare D1 is a serverless SQL database built on SQLite. It works particularly well with Cloudflare Workers, allowing us to create a small HTTP API without running our own server.

For a project like this, there are several advantages:

  • No database server to install or maintain
  • No local web server required
  • HTTPS is handled automatically
  • Cloudflare Workers can communicate directly with D1
  • D1 supports regular SQL
  • A useful free tier is available
  • The database remains accessible even when the Computer running the BLE gateway is offline

This makes it convenient for prototypes, BLE gateways, environmental monitoring projects, demonstrations, and small IoT applications.

For this example, the Computer only needs to run the Python gateway application. Everything after the HTTP request is handled in the cloud.

Requirements

For this project, you will need:

Hardware

Software and services

  • Python 3
  • A free Cloudflare account
  • pyserial
  • requests

For this example, the HibouAir sensor has the board ID:

220069

and BleuIO appears on the Mac at:

/dev/cu.usbmodem4048FDEBA6D01

Your serial port depends on operating system and HibouAir board ID may be different.

Step 1: Create a Cloudflare D1 Database

First, log in to your Cloudflare account.

From the Cloudflare dashboard, go to the D1 database section and create a new database.

For this tutorial, we will call it:

hibouair-db

Once the database has been created, open its SQL Console.

Run the following SQL:

CREATE TABLE IF NOT EXISTS readings (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    board_id TEXT NOT NULL,
    measured_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
    co2 INTEGER NOT NULL,
    temperature REAL NOT NULL,
    humidity REAL NOT NULL
);

CREATE INDEX IF NOT EXISTS idx_readings_board_time
ON readings(board_id, measured_at);

This creates a simple table containing:

  • Database ID
  • HibouAir board ID
  • Timestamp
  • CO₂
  • Temperature
  • Humidity

The measured_at field is generated automatically by D1 when the reading is inserted.

A stored record will look conceptually like this:

id          1
board_id    220069
measured_at 2026-10-05 14:42:30
co2         623
temperature 24.1
humidity    43.7

Step 2: Create the Cloudflare Worker

Next, create a Cloudflare Worker.

Now go to:

Workers & Pages → Create application

Create a basic Worker. ( you can choose “Start with Hello world”)

The Worker will sit between our Python application and the D1 database.

For this project, we can name it:

hibouair-api

and then press deploy.

After creating the Worker, open the code editor and replace the default code with the following :

export default {
  async fetch(request, env) {
    const url = new URL(request.url);

    // API status
    if (url.pathname === "/" && request.method === "GET") {
      return Response.json({
        service: "HibouAir Cloud API",
        status: "online"
      });
    }

    // Store a new sensor reading
    if (url.pathname === "/api/readings" && request.method === "POST") {
      const suppliedKey = request.headers.get("X-API-Key");

      if (!suppliedKey || suppliedKey !== env.API_KEY) {
        return Response.json(
          {
            success: false,
            error: "Unauthorized"
          },
          {
            status: 401
          }
        );
      }

      let data;

      try {
        data = await request.json();
      } catch {
        return Response.json(
          {
            success: false,
            error: "Invalid JSON"
          },
          {
            status: 400
          }
        );
      }

      const boardId = String(data.board_id || "").trim();
      const co2 = Number(data.co2);
      const temperature = Number(data.temperature);
      const humidity = Number(data.humidity);

      if (!boardId) {
        return Response.json(
          {
            success: false,
            error: "board_id is required"
          },
          {
            status: 400
          }
        );
      }

      if (
        !Number.isFinite(co2) ||
        !Number.isFinite(temperature) ||
        !Number.isFinite(humidity)
      ) {
        return Response.json(
          {
            success: false,
            error: "Invalid sensor values"
          },
          {
            status: 400
          }
        );
      }

      const result = await env.DB
        .prepare(`
          INSERT INTO readings (
            board_id,
            co2,
            temperature,
            humidity
          )
          VALUES (?, ?, ?, ?)
        `)
        .bind(
          boardId,
          co2,
          temperature,
          humidity
        )
        .run();

      return Response.json({
        success: true,
        message: "Reading stored",
        board_id: boardId,
        co2: co2,
        temperature: temperature,
        humidity: humidity,
        meta: result.meta
      });
    }

    // Return the latest reading
    if (
      url.pathname === "/api/readings/latest" &&
      request.method === "GET"
    ) {
      const boardId =
        url.searchParams.get("board_id") || "220069";

      const reading = await env.DB
        .prepare(`
          SELECT
            id,
            board_id,
            measured_at,
            co2,
            temperature,
            humidity
          FROM readings
          WHERE board_id = ?
          ORDER BY id DESC
          LIMIT 1
        `)
        .bind(boardId)
        .first();

      if (!reading) {
        return Response.json(
          {
            success: false,
            error: "No readings found"
          },
          {
            status: 404
          }
        );
      }

      return Response.json({
        success: true,
        reading: reading
      });
    }

    return Response.json(
      {
        success: false,
        error: "Not found"
      },
      {
        status: 404
      }
    );
  }
};

Deploy the Worker.

At this stage, the Worker exists, but it is not yet connected to the D1 database.

Step 3: Bind the D1 Database to the Worker

Open the settings for the hibouair-api Worker.

Add a D1 database binding.

Use:

Variable name: DB
Database: hibouair-db

The variable name must be:

DB

because the Worker accesses the database through:

env.DB

For example:

await env.DB
    .prepare("SELECT * FROM readings")
    .all();

Once the binding has been added, deploy the Worker again if necessary.

Step 4: Add an API Key

Our Python application will be publicly connected to the Cloudflare Worker over HTTPS.

We therefore do not want anybody who discovers the Worker URL to be able to insert arbitrary sensor measurements.

We can protect the write endpoint using a simple API key.

On the Computer, generate a random key:

python3 -c "import secrets; print(secrets.token_hex(32))"

This will generate a long random value.

Copy it.

Now create a Worker secret environment variable named:

API_KEY

and paste the generated value as its value.

The Python application will include this key in every request using:

X-API-Key

The Worker checks:

const suppliedKey =
    request.headers.get("X-API-Key");

and compares it against:

env.API_KEY

Step 5: Test the Worker

Cloudflare will provide a Worker URL similar to:

https://hibouair-api.your-account.workers.dev

Open the base Worker URL in a browser.

You should receive something similar to:

{
  "service": "HibouAir Cloud API",
  "status": "online"
}

If you see this response, the Worker is running.

Our Python application will send measurements to:

https://hibouair-api.your-account.workers.dev/api/readings

The latest stored reading can later be retrieved from:

https://hibouair-api.your-account.workers.dev/api/readings/latest

Step 6: Download the Python Project

The source code for the BleuIO Python gateway is available on GitHub:

GitHub: https://github.com/smart-sensor-devices-ab/bleuio-cloudflare-d1-database

Clone the repository:

git clone https://github.com/smart-sensor-devices-ab/bleuio-cloudflare-d1-database

Then enter the project directory:

cd bleuio-cloudflare-d1-database

The project structure is intentionally small:

bleuio-cloudflare-d1/
│
├── main.py
├── info.example.txt
├── requirements.txt
└── .gitignore

The Python application handles:

  1. Connecting to BleuIO
  2. Sending BleuIO AT commands
  3. Searching for the HibouAir board ID
  4. Reading BLE advertising data
  5. Decoding CO2, temperature, and humidity
  6. Displaying the measurement in the terminal
  7. Sending the measurement to Cloudflare
  8. Repeating the process at a configurable interval

Step 7: Install the Python Dependencies

It is recommended to create a Python virtual environment.

Run:

python3 -m venv .venv

Activate it:

source .venv/bin/activate

Then install the required libraries:

pip install -r requirements.txt

The application only requires:

pyserial
requests

pyserial is used to communicate with BleuIO through the USB serial port.

requests is used to send the decoded measurements to the Cloudflare Worker over HTTPS.

Step 8: Configure the Project

The repository includes:

info.example.txt

Copy it:

cp info.example.txt info.txt

Then open:

info.txt

The configuration looks like this:

BLEUIO_PORT=/dev/cu.usbmodem4048FDEBA6D01
HIBOUAIR_SENSOR_ID=220069

SCAN_INTERVAL_SECONDS=30

CLOUDFLARE_API_URL=https://hibouair-api.YOUR-SUBDOMAIN.workers.dev/api/readings
CLOUDFLARE_API_KEY=YOUR_REAL_API_KEY

You need to update the values for your own environment.

BLEUIO_PORT

On our Mac, BleuIO is available at:

/dev/cu.usbmodem4048FDEBA6D01

Your port may be different.

You can normally find USB serial devices with:

ls /dev/cu.*

Look for the device corresponding to BleuIO.

On windows , look for COM port on device manager.

HIBOUAIR_SENSOR_ID

For this project, our HibouAir board ID is:

220069

Replace this with the board ID of the HibouAir device you want to monitor.

SCAN_INTERVAL_SECONDS

This determines how often the application starts a new HibouAir scan.

For this tutorial:

SCAN_INTERVAL_SECONDS=30

means approximately one scan every 30 seconds.

You can later change this without modifying the Python source code.

For example:

SCAN_INTERVAL_SECONDS=60

for approximately one reading per minute.

Or:

SCAN_INTERVAL_SECONDS=300

for approximately one reading every five minutes.

CLOUDFLARE_API_URL

Replace this with the URL of the Worker created earlier:

CLOUDFLARE_API_URL=https://hibouair-api.YOUR-SUBDOMAIN.workers.dev/api/readings

CLOUDFLARE_API_KEY

Enter the same secret that was configured in the Cloudflare Worker:

CLOUDFLARE_API_KEY=YOUR_REAL_API_KEY

The info.txt file should not be committed to GitHub because it contains the API key.

Step 9: How the HibouAir Data Is Read

BleuIO communicates with our Python application using simple AT commands over the serial port.

The application first connects to BleuIO and places it in central mode.

It then searches for our HibouAir board ID using:

AT+FINDSCANDATA=220069=5

Here:

220069

is the HibouAir board ID, and:

5

defines the scan duration.

BleuIO handles the Bluetooth Low Energy scanning and returns the matching BLE advertising information over serial.

This means the Python application does not need to directly communicate with the operating system’s native Bluetooth API.

BleuIO then returns the advertising data to Python.

Step 10: Decode the HibouAir Advertisement

The Python application searches the advertising payload for the HibouAir data section:

5B070

For the HibouAir advertisement used in this example, the application extracts the three measurements needed for this project. Temperature, Humidity and CO2. The result becomes a normal Python structure similar to:

{
    "co2": 623,
    "temperature": 24.1,
    "humidity": 43.7
}

The application also performs basic validation before uploading the measurements.

For example, obviously invalid temperature, humidity, or CO2 values are rejected instead of being stored in the database.

Step 11: Sending the Measurement to Cloudflare

Once a valid advertisement has been decoded, Python prepares a JSON request.

For example:

{
  "board_id": "220069",
  "co2": 623,
  "temperature": 24.1,
  "humidity": 43.7
}

This is sent using an HTTP POST request to:

/api/readings

The API key is included in the request header:

X-API-Key

The Cloudflare Worker validates the key and inserts the measurement into D1.

The Python application therefore never connects directly to the database.

Step 12: Run the Application

Before running the project, make sure no other program is currently using the BleuIO serial port.

For example, close any active BleuIO connection in:

  • BleuIO application
  • screen
  • serial monitor
  • terminal program
  • other Python application

Then run:

python3 main.py

The application should connect to BleuIO.

You should see output similar to:

BleuIO + HibouAir + Cloudflare D1
---------------------------------

BleuIO port : /dev/cu.usbmodem4048FDEBA6D01
HibouAir ID : 220069
Scan interval: 30 seconds

Trying BleuIO on /dev/cu.usbmodem4048FDEBA6D01 at 115200 baud...

BleuIO connected successfully.

Setting BleuIO to central mode...
Ready.

The application will then start scanning:

Scanning for HibouAir 220069...

Command: AT+FINDSCANDATA=220069=5

When a valid HibouAir advertisement is received and decoded, the terminal will display something similar to:

============================================
          HIBOUAIR AIR QUALITY
============================================

  CO2                623 ppm
  Temperature       24.1 °C
  Humidity          43.7 %RH

============================================

Uploading to Cloudflare D1...
✓ Reading stored successfully.

Next scan in 23 seconds...

The application continues running automatically.

There is no need to restart it for each measurement.

To stop the application, press:

Ctrl + C

Step 13: Check the Data in Cloudflare D1

Now return to the Cloudflare D1 database console.

Run:

SELECT *
FROM readings
ORDER BY id DESC
LIMIT 10;

You should see the measurements coming from HibouAir.

For example:

id  board_id  measured_at          co2  temperature  humidity

12  220069    2026-10-05 14:58:20  618  24.1         43.8
11  220069    2026-10-05 14:57:50  621  24.1         43.8
10  220069    2026-10-05 14:57:20  623  24.1         43.7

You can also explore the data from your database.

Step 14: Check the Latest Reading Through the API

We also created a simple read endpoint.

Open:

https://YOUR-WORKER.workers.dev/api/readings/latest

The Worker will query D1 and return the latest measurement.

For example:

{
  "success": true,
  "reading": {
    "id": 12,
    "board_id": "220069",
    "measured_at": "2026-10-05 14:58:20",
    "co2": 618,
    "temperature": 24.1,
    "humidity": 43.8
  }
}

Building a Dashboard Later

This tutorial intentionally stops at the database and API level.

The objective is to demonstrate the complete BLE-to-cloud data path while keeping the example easy to understand.

At this point, the data is already available in the cloud.

A developer could later build a dashboard showing:

Current CO₂
Current Temperature
Current Humidity

CO₂ history
Temperature history
Humidity history

A dashboard could request historical readings through additional Worker API endpoints.

It could also display thresholds, warnings, averages, minimum/maximum measurements, or other analytics.

Those features are deliberately outside the scope of this example because the main goal is to demonstrate how easily BLE data can be brought into a serverless cloud architecture using BleuIO.

We kept the project intentionally simple so that the individual parts are easy to understand and modify.

From here, the project can be expanded in many directions. Multiple HibouAir sensors could be monitored, additional air quality parameters could be stored, historical API endpoints could be created, and a complete cloud dashboard could be built on top of the existing data.

Share this post on :

Running a HibouAir BLE Air Quality Scanner on Adafruit Fruit Jam with BleuIO

In this project, we will look at how the BleuIO SSD025 Bluetooth Low Energy USB dongle can add BLE communication to an Adafruit Fruit Jam powered by the RP2350.

The project takes an unusual software approach. Instead of running the HibouAir scanner as part of the native firmware, the Fruit Jam runs a custom real-time operating system called myRTOS .

A myRTOS application module, hibouair.c, written in C, communicates with the BleuIO dongle over USB, scans for nearby HibouAir air-quality sensors, decodes their Bluetooth Low Energy advertisements and displays the latest measurements in real time in a terminal window.

The result is a compact embedded BLE air-quality gateway running on the RP2350.

Requirements

For this project, we use:

The Fruit Jam is particularly suitable for this project because it has a built-in USB hub with two exposed USB host ports.

What does this project do?

1. HibouAir broadcasts sensor data

2. BleuIO receives the BLE advertisements

3. Fruit Jam receives the data over USB

4. myRTOS decodes and displays the measurements

The HibouAir sensor periodically broadcasts its measurements using BLE advertising packets. The SSD025 receives these packets and makes the information available to the RP2350 over USB.

The myRTOS application then scans for HibouAir devices, interprets the received information and maintains a live list of detected sensors.

The terminal provides an easy way to observe the air-quality information as it arrives.

Hardware

The project is built around three main pieces of hardware.

Adafruit Fruit Jam with the BleuIO SSD025 connected directly to the USB Type-A host port.

Adafruit Fruit Jam

The Fruit Jam is a compact computer based on the RP2350B microcontroller. Adafruit provides two USB Type-A host ports through an onboard USB hub, making it possible to connect USB peripherals directly to the board.

The board provides considerably more functionality than is required for this simple gateway. In addition to the RP2350B, it includes flash storage, PSRAM, USB host capability, microSD, DVI output, audio hardware and an ESP32-C6 for wireless connectivity.

For this project, however, the important feature is the USB host interface .

BleuIO SSD025

The BleuIO SSD025 is used as the Bluetooth Low Energy interface.

This means the RP2350 application does not need to implement the Bluetooth Low Energy stack itself.

The dongle supports Bluetooth 5.2 and USB Full Speed, can operate in Bluetooth central or peripheral roles, and is controlled through its USB interface.

The application can therefore access BLE functionality through BleuIO’s USB interface while leaving the Bluetooth communication to the dongle.

HibouAir SSD002

The HibouAir SSD002 is the wireless air-quality sensor.

HibouAir’s documentation describes the SSD002/2B as a CO2 air-quality monitor using an NDIR CO2 sensor, with wireless Bluetooth connectivity. The sensor family can provide environmental parameters including CO2, temperature, humidity, particulate matter and VOC-related measurements depending on the model.

www.hibouair.com

Why use BleuIO?

The BleuIO acts as the bridge between the USB host implemented by the Fruit Jam and the Bluetooth Low Energy devices in the surrounding environment.

The application processor can concentrate on:

  • USB communication
  • RTOS scheduling
  • data parsing
  • terminal output

while the BleuIO handles the Bluetooth side.

BleuIO’s own HibouAir gateway example similarly uses BleuIO to provide BLE communication to RP2040/RP2350 development boards through USB.

The Software Architecture

The software in this project is based on myRTOS , a small real-time operating system environment running on the Fruit Jam.

The HibouAir application is started from the RTOS command interface:

myrtos:/> hibouair

Once started, the application enters scanning mode:

scanning; ctrl-C to stop

The application then continuously processes incoming BLE data.

Conceptually, the software pipeline looks like this:

HibouAir → BLE advertisements → BleuIO SSD025 → USB → Fruit Jam / myRTOS → HibouAir packet decoding → Terminal display

The important point is that this is not simply a raw BLE packet monitor.

The application turns the incoming wireless data into a human-readable sensor table .

How to Run the Project

The complete project is available on GitHub:

https://github.com/smart-sensor-devices-ab/Adafruit-Fruit-Jam-with-BleuIO

  1. Connect the board: Connect the Adafruit Fruit Jam to your computer using a USB-C cable and turn the power switch ON.
  2. Hold down Button #1 (the UF2 BOOT button located on GPIO0), press and release the reset button while continuing to hold Button #1, and release Button #1 only after the bootloader drive appears.
  3. Drag the project’s .uf2 file onto the board’s bootloader drive. The image includes myRTOS and the hibouair.c application module.
  4. Press the reset button to reboot the board.
  5. Connect the BleuIO SSD025: Plug the BleuIO SSD025 into one of the Fruit Jam’s USB Type-A host ports.
  6. Power the HibouAir sensor: Make sure one or more HibouAir sensors are powered on and within Bluetooth range of the BleuIO dongle.

Button Locations on the Adafruit Fruit Jam

To enter UF2 bootloader mode, this project uses two buttons on the Fruit Jam:

  • Button #1 (UF2 BOOT) — located on GPIO0 towards the bottom-right edge of the board.
  • Reset button — located on the left edge of the board.

The image below shows the location of both buttons.

After rebooting, open a terminal window and connect to the board.

Windows

After rebooting, open Device Manager and identify the COM port assigned to the Fruit Jam. Connect to this port using a serial terminal such as PuTTY.

macOS

To find the Fruit Jam’s serial port, open a terminal and run:

ls /dev/cu.usbmodem*

The command should return a device similar to:

/dev/cu.usbmodem2351xxxx

Connect to it using:

screen /dev/cu.usbmodem2351xxxx

Real-Time HibouAir Scanning

After connecting to the Fruit Jam, start the HibouAir application from the myRTOS command interface:

myrtos:/> hibouair
scanning; ctrl-C to stop

The program then prints a table containing the detected HibouAir devices.

This gives the user an immediate overview of all the HibouAir sensors currently being received.

Expected Output

For example, the output below shows several HibouAir devices detected during a scan. The table shows each detected device’s board identifier, Bluetooth address, sensor type and latest environmental measurements.

Where Could This Go Next?

The current application concentrates on the essential task: receiving HibouAir advertisements and presenting the decoded measurements in real time.

Logging the data to the Fruit Jam’s microSD card would also make it possible to create long-term air-quality datasets without requiring a permanently connected computer.

The Fruit Jam’s USB host capability, microSD storage and RP2350B processor make this type of expansion practical.

Conclusion

This project demonstrates how the Adafruit Fruit Jam, BleuIO SSD025 and HibouAir SSD002 can be combined to create a compact RP2350-based Bluetooth Low Energy air-quality gateway.

HibouAir sensors broadcast their environmental measurements over BLE. BleuIO receives these advertisements and transfers the data to the Fruit Jam over USB, where the myRTOS hibouair application decodes the sensor data and presents the latest measurements in real time.

The project shows how BleuIO can add BLE communication to an RP2350-based embedded system while keeping the Bluetooth interface separate from the main application.

Share this post on :

BleuIO Pro Firmware v1.0.7.1 Released

We’ve released BleuIO Pro firmware v1.0.7.1, bringing an important fix for applications that use Bluetooth Low Energy Extended Advertising.

What’s Fixed

This release resolves an issue affecting custom extended advertising instances after a connection-disconnection cycle.

In some cases, restarting a custom extended advertising instance could either fall back to the default legacy advertising mode or fail to restart altogether.

With v1.0.7.1, custom extended advertising now resumes correctly after a disconnect, making the behavior more reliable for applications that depend on repeated connection and advertising cycles.

How to Update Your Firmware

Updating your BleuIO Pro is straightforward.

You can download the latest firmware and follow the step-by-step update instructions in our official documentation:

https://www.bleuio.com/getting_started/docs/firmware_pro

Alternatively, you can update directly from your browser using the BleuIO web application:

https://bleuio.com/bleuioapp/#/fw

Both methods provide a simple way to get your BleuIO Pro running the latest firmware.

We recommend updating to v1.0.7.1 if your application uses custom Extended Advertising.

Share this post on :

Novel Bits Explores Bluetooth LE Testing with BleuIO

Novel Bits recently published an interesting article, “Testing a Bluetooth LE Device Without a Phone,” featuring BleuIO in a practical Bluetooth Low Energy testing workflow.

Novel Bits is also our US distributor, and it was great to see BleuIO used in an example that highlights a different approach to BLE development and testing.

In the article, Mohammad Afaneh discusses where smartphone-based testing works well and where a more scriptable approach can be useful. Using BleuIO, he demonstrates how Bluetooth LE operations such as scanning, advertising, connecting, and disconnecting can be controlled directly from a terminal.

This is one of the useful aspects of BleuIO’s design. BleuIO connects over USB and can be controlled using simple AT commands, making it possible to interact with Bluetooth LE from a terminal, application, or script.

For developers, this can be useful for prototyping, repeatable testing, automation, and other situations where direct programmatic control of Bluetooth LE is preferred over manually interacting with a mobile application.

The Novel Bits article includes practical examples using BleuIO dongles and explains the approach in much more detail.

Read the full article:
Testing a Bluetooth LE Device Without a Phone — Novel Bits

Share this post on :

Build a Cloud Air Quality Dashboard with HibouAir, BleuIO, and TagoIO

Air quality and environmental monitoring are common IoT use cases where Bluetooth Low Energy sensors can provide useful real-time information without requiring complex infrastructure.

In this project, we will use HibouAir as our air quality monitoring sensor, BleuIO as the Bluetooth Low Energy interface, and a Python application to collect and decode the advertised sensor data. The decoded measurements will then be sent to TagoIO, where we can store and visualize the data using an online dashboard.

The goal is to keep the project simple. There is no need to install an IoT server, MQTT broker, database, or dashboard software locally. BleuIO handles the BLE communication, the Python application processes the sensor data collected from HibouAir, and TagoIO handles the cloud side.

Why TagoIO?

TagoIO is an IoT platform that provides tools for connecting devices, storing sensor data, and creating dashboards for visualization.

For this project, one of the main reasons for choosing TagoIO is that it is easy to get started. It provides a free plan, which is suitable for experimenting with a small number of devices and building proof-of-concept IoT applications.

This makes it particularly useful for projects such as environmental monitoring where we simply want to send sensor measurements to the cloud and visualize them without setting up our own backend infrastructure.

If the project grows later, TagoIO also provides paid subscription options with additional resources and capabilities. This means we can start with the free option while developing and testing the project, and move to a larger plan later if necessary.

Another useful feature is its dashboard builder. Once our sensor variables reach TagoIO, we can create cards, displays, gauges, and time-series charts directly from the web interface.

For our HibouAir project, this allows us to visualize measurements such as:

  • Temperature
  • Relative humidity
  • CO2

Project Requirements

For this project, we need the following hardware and software.

Hardware

BleuIO

BleuIO is a USB Bluetooth Low Energy dongle that allows us to control BLE communication using simple AT commands over a serial connection.

In this project, BleuIO scans for the BLE advertisements transmitted by HibouAir and passes the received advertisement data to our Python application.

HibouAir

HibouAir is the environmental BLE sensor used in this example.

For this project, we are using a HibouAir device advertising with the board ID:

220069

Software Requirements

Install Python 3 if it is not already available.

The project uses the following Python packages:

pyserial
requests

Install them using:

python3 -m pip install pyserial requests

You will also need a free TagoIO account.

Create an account and then create a new device in the TagoIO console.

For example:

Device Name: HibouAir Air Quality Sensor

After creating the device, TagoIO generates a Device Token.

The Device Token is used by the Python application to authenticate when sending measurements to TagoIO.

Keep this token private and do not publish it in a public GitHub repository.

How the Project Works

The project consists of three main stages.

1. Collect BLE Advertisements from HibouAir

HibouAir continuously broadcasts environmental data using Bluetooth Low Energy advertisements.

BleuIO is connected to the computer through USB and appears as a serial device.

On macOS, for example, the BleuIO dongle may appear as:

/dev/cu.usbmodemxxxxxxx

The Python application opens this serial port and communicates with BleuIO.

To locate our specific HibouAir device, the application asks BleuIO to search for advertisements containing the HibouAir board ID:

220069

Conceptually, the command looks like:

AT+FINDSCANDATA=220069=3

BleuIO scans for matching BLE advertisements and returns the advertisement data to the Python application.

The data received from BleuIO contains the raw BLE advertisement in hexadecimal format.

The Python application identifies the HibouAir environmental advertisement and extracts the relevant bytes from the payload.

The values are then decoded into useful environmental measurements.

For example:

Temperature : 24.6 °C
Humidity    : 48.2 %
CO2         : 612 ppm

Sending the Data to TagoIO

Once the HibouAir advertisement has been decoded, the Python application prepares the measurements in the format expected by TagoIO.

For example:

[
  {
    "variable": "temperature",
    "value": 24.6,
    "unit": "°C"
  },
  {
    "variable": "humidity",
    "value": 48.2,
    "unit": "%"
  },
  {
    "variable": "co2",
    "value": 612,
    "unit": "ppm"
  }
]

The application then sends the data to the TagoIO API using HTTPS.

The TagoIO Device Token is included with the request so that TagoIO knows which device the measurements belong to.

After the first successful upload, the variables automatically become available for the device in TagoIO.

In this example, the variables are:

temperature
humidity
co2

The application continues scanning for new HibouAir advertisements and periodically uploads new measurements.

Creating the TagoIO Dashboard

Once the sensor data starts appearing in TagoIO, we can create a dashboard.

In the TagoIO console, go to:

Dashboards

Create a new dashboard and give it a name such as:

HibouAir Air Quality Dashboard

We can then add widgets using the variables sent by our Python application.

For example, we can create current-value widgets for:

Temperature
Humidity
CO2

We can also add line charts to display how each measurement changes over time.

Because TagoIO stores timestamps with the measurements, the line-chart widgets can display the sensor data as a time series.

This gives us a simple cloud-based air-quality monitoring dashboard without having to maintain our own database or web application.

Source Code

The complete source code for this project is available on GitHub:

GitHub:
https://github.com/smart-sensor-devices-ab/BleuIO-hibouair-tagoio

Configure the Application

Before running the application, update the configuration with your BleuIO serial port and TagoIO Device Token.

For example:

BLEUIO_PORT = "/dev/cu.usbmodem4048FDE52CF21"

HIBOUAIR_ID = "220069"

You will also need your TagoIO Device Token.

For development, the token can be supplied through the application configuration.

The TagoIO API endpoint also needs to match the region used by your TagoIO account.

Running the Application

Make sure:

  1. BleuIO is connected to the computer.
  2. HibouAir is powered on and advertising.
  3. Your computer has an Internet connection.
  4. Your TagoIO Device Token has been configured.

Then run:

python3 script.py

The application should first connect to BleuIO.

You should see output similar to:

BleuIO + HibouAir + TagoIO
==========================

BleuIO port: /dev/cu.usbmodem4048FDE52CF21
BleuIO responded OK

Looking for HibouAir 220069

When a valid HibouAir advertisement is received, the decoded sensor measurements will be displayed:

----------------------------------
HibouAir detected
----------------------------------

Temperature   : 24.6 °C
Humidity      : 48.2 %
CO2           : 612 ppm

----------------------------------

TagoIO upload: OK

The application will continue scanning and uploading new readings until it is stopped.

Use:

Ctrl + C

to stop the application.

Output

After the application has been running for a while, the sensor measurements will be available from the TagoIO device page and dashboard.

The dashboard can display the latest HibouAir measurements as well as their historical changes.

In this project, we created a simple cloud-connected environmental monitoring system using HibouAir, BleuIO, Python, and TagoIO.

This project should be considered a starting point rather than a finished monitoring product.

The code can be modified or expanded in many ways. Feel free to modify, extend, or reuse the code in your own BLE and IoT applications as needed.

Share this post on :