Build a BLE Environmental RSS Feed with BleuIO

Monitoring environmental data in real time is becoming increasingly important, whether you are tracking air quality in an office, monitoring home conditions, or running a smart city project. With the BleuIO dongle and a BLE-enabled sensor like the HibouAir, it is remarkably simple to gather this data and share it with the world in a format that is open, accessible, and easy to consume.

This project demonstrates how you can turn BLE advertisement data into a live-updating RSS feed. The result is a transparent, shareable, and continuously updated stream of environmental measurements that anyone can subscribe to, whether they are using a standard RSS reader, a smart home dashboard, or an industrial system.

Project Overview

At its core, this project uses the BleuIO dongle to scan for BLE advertising packets from a HibouAir environmental sensor. The HibouAir broadcasts valuable metrics such as temperature, humidity, pressure, and CO2 levels over BLE advertisements. Instead of relying on a local desktop application or complicated server-side setups, this project leverages the power of modern browsers using the Web Serial API to connect directly to the BleuIO dongle over the USB port.

Once connected, the user can trigger BLE scans from within the browser. The scan runs every 30 seconds, decoding the broadcasted data in real time. Each new data point is sent to a lightweight PHP script on the server, which stores and appends the data in an RSS feed (rss.xml). This RSS file is immediately accessible to any subscriber or reader, allowing people to see live updates on the environmental conditions around the sensor.

The entire system is designed to be simple and easy to maintain. The frontend is styled with Tailwind CSS to ensure a responsive, polished interface. The user can connect, start scanning, stop scanning, and instantly visualize decoded data in a clear, scrollable log area.

Requirements

To build and run this project, you will need the following:

How It Works

The project flow is straightforward. First, the user plugs the BleuIO dongle into their machine. Using the Web Serial API, the web page establishes a secure, permission-based connection with the dongle, sending standard AT commands to initiate scanning. The page decodes the advertising data using JavaScript, translating raw BLE packets into readable environmental measurements.

Every 30 seconds, a scan command is sent, retrieving the most recent advertising broadcasts. When a valid HibouAir packet is detected, the temperature, humidity, pressure, and CO2 values are extracted, timestamped, and then posted to the server using a simple JSON POST request. The PHP script running on the server receives these decoded values and appends them to the existing RSS feed. The result is a continually growing XML feed that any RSS reader can parse and display.

This approach removes the need for any heavy backend logic or traditional data pipelines. With the combination of the BLE advertisement protocol, the Web Serial API, and the simple power of RSS, the system remains robust, efficient, and fully open-standard.

Real-World Use Cases

There are many practical applications for this type of BLE-to-RSS feed system. In a smart building, it can provide real-time updates on air quality for facilities managers. Research labs can monitor and record environmental changes over time, sharing data with collaborators instantly. Homeowners could integrate the feed with smart thermostats or ventilation systems, optimizing air quality dynamically based on conditions broadcast by the HibouAir.

This approach is also perfect for educational settings, where students can learn about BLE communication, environmental sensors, and open-standard data sharing in a single, hands-on project. For communities or public-facing projects, the RSS feed provides a transparent, shareable view of conditions in a local area, encouraging citizen science or public environmental monitoring.

Why This Matters

Traditionally, BLE data collection has required local scripts, drivers, and other installation-heavy methods. Thanks to the Web Serial API, this entire solution can run in the browser, with no software to install apart from a modern web browser. The user grants permission to the serial port, connects the dongle, and can immediately start scanning, decoding, and sharing data.

By pushing this data into a simple RSS format, you gain compatibility with a huge ecosystem of readers and dashboards without reinventing the wheel. RSS is universal, easy to parse, and instantly shareable. This means a single HibouAir board and a BleuIO dongle can power an environmental feed accessible to anyone, anywhere.

Getting Started

This project is easy to set up. You only need a BleuIO dongle, a HibouAir board, a standard PHP-capable web server, and a modern web browser such as Chrome. The HTML page includes everything needed to connect to the dongle, issue scan commands, and decode results using JavaScript. Tailwind CSS ensures the user interface is polished and responsive.

After decoding, the environmental data is posted to a PHP script which appends it to an RSS feed file. From there, any visitor or RSS reader can subscribe to see the latest measurements. There is no complex backend, no cloud account, and no paid services — just a clean, standards-based solution that you can host yourself.

Source Code

The full project source code — including the HTML, JavaScript, PHP, and Tailwind-powered frontend — is available on GitHub. You can download, modify, or extend it as needed for your use case.

GitHub Repository

Feel free to clone the repository, fork it, and contribute improvements or suggestions.

Output

This project shows how BleuIO, in combination with Web Serial and simple RSS technology, can deliver an impressive, real-time environmental data feed. With minimal setup and a truly modern web-first architecture, you can build a robust, transparent, and shareable monitoring system in just a few hours.

If you are looking to explore BLE scanning, build a real-time environmental monitor, or simply share sensor data with the world in an open way, this project is a perfect starting point. Give it a try, and transform your local BLE sensors into a globally available data feed that anyone can use.

Share this post on :

Introducing the BleuIO Script Generator – Build BLE Applications with AI in Seconds

At Smart Sensor Devices, we are proud to introduce the BleuIO Script Generator – an AI-powered assistant that enables developers to instantly create valid BLE scripts using official BleuIO AT commands. Whether you’re a seasoned BLE expert or just getting started, this intelligent tool dramatically accelerates your workflow and minimizes errors.

What Is the BleuIO Script Generator?

The BleuIO Script Generator is a custom GPT (Generative Pre-trained Transformer) built using OpenAI’s advanced language model, trained and fine-tuned with the full BleuIO command reference. It understands how the BleuIO USB dongle works, including:

  • All AT commands
  • Syntax structures
  • Command usage examples
  • Valid output formats

With this AI assistant, you can now generate working scripts in Python, JavaScript, Shell, or any other language using real BleuIO commands—no more guessing or checking documentation line by line.

How Does It Help Developers?

The BleuIO Script Generator transforms the BLE development experience by offering intelligent, real-time support tailored to the needs of developers at all levels. One of its greatest strengths lies in rapid prototyping. You can simply describe your desired behavior in natural language—for example, “Create a script that connects to BleuIO and then scans for BLE devices for 5 seconds.”—and the generator instantly returns a ready-to-run script. It uses official AT commands like AT+CENTRAL, AT+GAPSCAN=5, correctly formatted and accompanied by helpful explanations.

Another major benefit is its language flexibility. Whether you’re working in Python, JavaScript, or even shell scripting, the Script Generator adapts the output to your preferred programming language, making integration seamless regardless of your tech stack. In addition to generating code, it promotes error-free development by relying solely on verified, up-to-date BleuIO AT commands. This minimizes the chance of sending unsupported or invalid instructions to your dongle, ensuring smoother workflows and reduced debugging time.

What sets this tool further apart is its built-in learning support. It doesn’t just produce scripts—it educates. You can ask the assistant questions like “What does AT+GAPSCAN=5 do?” or “How can I start advertising in extended mode?” and receive clear, example-based responses grounded in real command behavior. Whether you’re debugging, experimenting, or trying to better understand BLE communication, the BleuIO Script Generator acts as both tutor and tool.

How to Access the BleuIO AI Script Generator

You can use the Script Generator via ChatGPT’s Custom GPTs platform:

  1. Go to chat.openai.com/gpts
  2. Search for “BleuIO Script Generator” by Smart Sensor Devices
  3. Start chatting with it like a BLE expert assistant

Once you’re in, simply describe your task, and the generator will respond with code, documentation, and suggestions.

Why This Matters

At Smart Sensor Devices, we built the BleuIO dongle to make BLE development simpler, faster, and more accessible. Now, with AI as your development partner, you’re no longer bound by manuals or guesswork.

The BleuIO Script Generator removes friction from your workflow, so you can:

  • Focus on building real BLE solutions faster
  • Prototype smarter IoT and automation systems
  • Support team members with varied skill levels

Whether you’re building a hobby project, an enterprise product, or teaching BLE concepts, this AI tool accelerates learning and development.

Ready to Start?

Visit bleuio.com and get your BleuIO dongle today. Pair it with the BleuIO Script Generator, and you’ll be writing powerful BLE scripts with ease—no matter your programming experience.

Share this post on :

BLE Device Proximity Alert System Using BleuIO

Looking to detect nearby Bluetooth devices based on how close they are? With the BleuIO USB dongle and a simple Python script, you can create a BLE proximity alert system that triggers a sound when a specific device is within signal range. This setup filters devices based on signal strength (RSSI), allowing you to monitor only those within a defined proximity.

This project is ideal for anyone exploring BLE applications such as access control, IoT automation, or even security demos.

Use Cases

The BLE Proximity Alert System can serve various real-world scenarios:

  • Secure Zone Monitoring
    By defining a signal strength threshold, the system only responds to devices that are physically close—perfect for protecting sensitive areas like server rooms or restricted workspaces.
  • Proximity-Based Device Interactions
    Trigger actions such as pairing or unlocking devices only when a known BLE tag or smartphone comes within a defined range, improving both UX and security.
  • Awareness and Educational Demos
    Demonstrate proximity-based alerts in classrooms or public exhibits to show how BLE technology can be used for social distancing or presence detection.
  • Smart Home or Office Automation
    Use proximity as a trigger to automate actions—such as turning on lights, sending notifications, or logging user presence—without needing additional sensors.

Requirements

To run this BLE proximity alert system, you’ll need:

  • BleuIO Dongle
    A USB Bluetooth Low Energy dongle that supports AT command communication and works with macOS, Windows, and Linux. This dongle will be used to scan for nearby BLE devices and filter based on signal strength.
  • Close Beacon Device
    In this project, we use a Close Beacon as the target BLE device. These compact beacons broadcast Bluetooth advertisements, making them ideal for proximity detection demos.
  • Python 3.x
    Ensure Python is installed on your system. The script uses Python to handle serial communication and control logic.
  • Sound File
    A short .wav or .mp3 audio file (e.g., beep.wav) placed in the same directory as the script. This sound will be played when the target BLE device is detected within the defined proximity.

Required Python Library

Only one external Python library is needed:

  • pyserial – for handling communication with the BleuIO dongle via the serial port.

You can install it using:

pip install pyserial

No additional audio libraries are required on macOS or Windows; the script uses the built-in afplay tool for macOS and winsound for Windows to play audio.

How It Works

When you launch the script, it establishes a serial connection with the BleuIO dongle. It then sets an RSSI filter using the AT+FRSSI command, which limits scan results to only those devices whose signal strength is above a certain threshold (i.e., closer in physical distance). For example, setting a filter of -76 means the scan will ignore devices with weaker signals (further away) and only show those nearby.

Every 30 seconds, the script initiates a BLE scan using AT+GAPSCAN=3. It parses the output in real time, looking for a specific MAC address. If the device is detected, the system immediately plays a sound to alert the user. This process repeats continuously, offering reliable detection based on proximity rather than just presence.

Important Notes

  • Serial Port
    Update the SERIAL_PORT variable in the script to match your operating system:
    • macOS: Typically /dev/cu.usbmodemXXXX
    • Windows: Usually COM3, COM4, etc.
  • MAC Address
    Replace the default value with the MAC address of your target BLE device.
  • RSSI Threshold
    Modify RSSI_FILTER_THRESHOLD at the top of the script to define how close the device must be to trigger the alert. Acceptable values range from -1 (very strong signal) to -99 (very weak).
  • Sound File
    Make sure the beep sound file (e.g., beep.wav) is present in the same folder as the script.

Source Code

The source code is available at

https://github.com/smart-sensor-devices-ab/ble-proximity-alert.git

You can find the complete Python script with configuration options and logic here:

import platform
import serial
import time
import subprocess
if platform.system() == "Windows":
    import winsound

# ==== CONFIGURATION ====
SERIAL_PORT = '/dev/cu.usbmodem4048FDEBA6D01'  # Update as needed
#SERIAL_PORT = "COM8"  # Update as needed
BAUD_RATE = 9600
TARGET_DEVICE_MAC = "D0:76:50:80:15:32"
SOUND_FILE = "beep.wav"  # Must exist in the same folder

# RSSI filter threshold: Acceptable range is -1 to -99
RSSI_FILTER_THRESHOLD = "60"  # You can input without '-' sign
# ========================


def play_beep():
    try:
        if platform.system() == "Windows":
            winsound.PlaySound(SOUND_FILE, winsound.SND_FILENAME)
        else:
            subprocess.call(["afplay", SOUND_FILE])
    except Exception as e:
        print(f"Failed to play sound: {e}")


def connect_to_bleuio():
    try:
        ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
        time.sleep(2)

        # Send basic AT to wake up
        ser.write(b"AT\r\n")
        time.sleep(0.5)

        # Ensure threshold has leading '-'
        rssi_value = RSSI_FILTER_THRESHOLD
        if not rssi_value.startswith("-"):
            rssi_value = "-" + rssi_value

        command = f"AT+CENTRAL\r\n".encode()
        ser.write(command)
        print(f"BleuIO set to central role\n")
        time.sleep(0.5)

        # Send AT+FRSSI command
        command = f"AT+FRSSI={rssi_value}\r\n".encode()
        ser.write(command)
        print(f"RSSI filter set to {rssi_value} dBm\n")
        time.sleep(0.5)

        return ser
    except Exception as e:
        print(f"Error connecting to BleuIO: {e}")
        return None


def scan_for_device(ser):
    ser.write(b"AT+GAPSCAN=3\r\n")
    end_time = time.time() + 5

    while time.time() < end_time:
        if ser.in_waiting:
            line = ser.readline().decode(errors="ignore").strip()
            print(line)
            if TARGET_DEVICE_MAC in line:
                print("Target device found! Triggering alert...")
                play_beep()

    print("Scan complete.\n")


def main():
    ser = connect_to_bleuio()
    if not ser:
        return

    print("Connected to BleuIO. Starting periodic scan...\n")

    while True:
        scan_for_device(ser)
        time.sleep(30)


if __name__ == "__main__":
    main()

Conclusion

This BLE proximity alert system is a great example of using signal strength (RSSI) to filter and detect nearby Bluetooth devices. It’s a lightweight, effective solution that can be easily customized for different applications—from home automation to enterprise access control. The source code is entirely open and flexible, allowing anyone to adapt it for their own use cases and expand it with additional features such as logging, notifications, or integration with cloud services.

This is an example project—but the building blocks can easily become part of something much bigger.

Share this post on :

BLE Star Topology Visualizer Using BleuIO

Monitoring nearby Bluetooth Low Energy (BLE) devices is essential for developers, testers, and engineers working with IoT, smart sensors, or proximity-based applications. To simplify this process, we’ve developed a visual tool—BLE Star Topology Visualizer—that connects to a BleuIO USB dongle and graphically maps nearby advertising BLE devices using RSSI-based distance estimation. This project not only provides a live BLE scan but also visualizes the proximity of devices in a central-node star topology.

What This Tool Does

The BLE Star Topology Visualizer is a web-based application that:

  • Connects to a BleuIO USB dongle via Web Serial API.
  • Performs a BLE GAP scan using AT+GAPSCAN=x to detect nearby BLE devices.
  • Displays detected devices as nodes around the central BleuIO dongle.
  • Uses RSSI (Received Signal Strength Indicator) to:
    • Color-code devices (green = strong signal, red = weak signal).
    • Adjust the visual distance from the center (closer = stronger signal).
  • Shows device MAC address, RSSI, and name (if available) in a tooltip on hover.

Requirements

To use this BLE Star Topology Visualizer, you’ll need a BleuIO USB dongle, which acts as the central scanning device. The dongle is responsible for performing GAP scans and returning nearby Bluetooth advertising data, including RSSI values and device names. No additional drivers or installations are needed—just plug in the BleuIO dongle, open the web app in a supported browser, and you’re ready to start scanning and visualizing.

Why This is Useful

BLE developers often depend on terminal-based command outputs to monitor advertising packets from nearby devices. While functional, this raw data can quickly become difficult to interpret—especially in environments with dozens of concurrent BLE signals. The BLE Star Topology Visualizer simplifies this challenge by transforming complex scan results into an interactive graphical map. It offers an immediate visual representation of proximity, density, and signal strength, helping developers, testers, and engineers better understand their BLE environment at a glance. Whether it’s estimating coverage, validating signal strength, or analyzing deployment patterns, this tool bridges the gap between data and insight.

Use Cases

This visualizer can serve many real-world needs. In a smart office or industrial IoT setup, it helps pinpoint where BLE beacons or sensors are broadcasting from, enabling better device placement and coverage optimization. During security audits, it offers a quick way to detect and identify all BLE devices within range, helping spot unauthorized transmitters. In educational settings, instructors can use it to demonstrate how RSSI reflects signal strength and how Bluetooth devices advertise themselves. Additionally, developers working on new BLE-enabled hardware can use this tool for field testing, validating how their products behave under various proximity and interference conditions.

How It Works

1. BLEUIO Setup

The script utilizes BleuIO AT commands. Once connected, the script sends the following:

  • AT+CENTRAL to switch to scanning mode.
  • AT+SHOWRSSI=1 to prepare BLEUIO to show RSSI in output.
  • AT+GAPSCAN=5 to scan for 5 seconds and return a list of advertising devices.

2. GAP Scan Output Parsing

The GAP scan output is parsed using a regex pattern that extracts:

  • RSSI value
  • MAC address
  • Optional device name (e.g., “(HibouAIR)”)

If the same MAC appears multiple times (with and without name), the version with the name is prioritized and stored.

3. Visualization with D3.js

Using D3.js, the central node (BleuIO) is placed in the center. Each nearby device:

  • Appears as a circle node around it.
  • Is connected with a line whose length is proportional to the RSSI (inverted and scaled).
  • Shows color-coded signal strength:
    • Green: Strong RSSI ≥ -50
    • Yellow: Medium RSSI > -70
    • Red: Weak RSSI ≤ -70

A tooltip displays full device info (MAC, RSSI, and name) when hovered.

How to Try

  1. Plug in your BleuIO dongle.
  2. visit this site to access the live script https://smart-sensor-devices-ab.github.io/ble-rssi-map/
  3. Click Connect and allow access to the BleuIO serial port.
  4. Click Scan to begin GAP scan.
  5. Watch as nearby BLE devices are discovered and plotted dynamically.

Output

Code Access

The full script is available at Github.

The BLE Star Topology Visualizer is a powerful yet simple tool that turns your BLE scan into an interactive experience. Whether you’re debugging, teaching, or optimizing device placement, this script offers a real-time glimpse into the invisible world of Bluetooth communication.

Share this post on :

Understanding BLE Advertising and How BleuIO Makes It Easy

Bluetooth Low Energy (BLE) has become the backbone of modern wireless communication for low-power IoT devices. One of its core features — advertising — allows BLE devices to broadcast information without the need for pairing or a connection. From contact tracing to proximity marketing and sensor broadcasting, BLE advertising powers many real-world applications.

What Is BLE Advertising?

BLE advertising is a mechanism where a device sends out small packets of data at regular intervals to announce its presence. These packets are picked up by nearby BLE-capable central devices (e.g., smartphones, gateways, computers).

A typical BLE advertisement packet contains:

  • Flags: Indicating capabilities like discoverability
  • Local Name: Device name (optional)
  • Service UUIDs: Describing the services the device supports
  • Manufacturer Specific Data: Custom payload defined by the manufacturer
  • Other fields: e.g., TX Power, service data, etc.

The total payload size is limited to 31 bytes, which includes all AD (advertising data) fields. Crafting this data properly is crucial to avoid errors and ensure compatibility with BLE scanners.

BLE Advertising with BleuIO and AT Commands

Traditionally, crafting BLE advertising packets required working with complex SDKs or embedded C libraries. But with BleuIO, things are much simpler — thanks to its powerful AT command set.

Here are two useful AT commands for advertising:

  • AT+ADVDATA= sets the advertising payload using a colon-separated hex format
  • AT+ADVSTART starts broadcasting the advertising packet

Example:

AT+ADVDATA=07:FF:5B:07:01:02:03:04
AT+ADVSTART

This advertises a Manufacturer Specific Data block:

  • 07: Total length of this AD field
  • FF: Type = Manufacturer Specific
  • 5B07: Manufacturer ID (Smart Sensor Devices)
  • 01020304: Custom payload

Using this simple format, you can test different advertising payloads, simulate sensor broadcasts, or even debug BLE scanning applications.

A Web Tool for BLE Advertising

To make things even easier, we’ve created a web-based BLE advertising builder that works right inside your browser.

Try it here:
https://smart-sensor-devices-ab.github.io/ble_advertising_payload/

What It Can Do:

  • Lets you connect to your BleuIO dongle directly from the browser
  • Offers two modes:
    • Builder Mode: Enter data by field — length, type, manufacturer ID, and custom payload
    • Raw Mode: Paste a full, colon-separated advertising packet directly
  • Automatically sends AT+ADVDATA and AT+ADVSTART commands
  • Displays real-time feedback from BleuIO (e.g., OK, INVALID PARAMETER)
  • Includes built-in validation so you don’t exceed the 31-byte BLE limit

Use Cases

Whether you’re a developer, educator, or BLE hobbyist, this tool is perfect for:

  • ✅ Rapid testing of advertising formats
  • ✅ Simulating BLE sensor outputs (like HibouAir)
  • ✅ Learning how BLE advertising packets are structured
  • ✅ Teaching BLE fundamentals without needing mobile apps or complex tools

BLE advertising is a critical piece of the Bluetooth ecosystem, and mastering it opens up a world of possibilities. With BleuIO’s simple AT interface and our new browser-based payload builder, creating, testing, and learning BLE advertising has never been easier.

So plug in your BleuIO dongle, open the tool in your browser, and start crafting BLE packets — one byte at a time.

Share this post on :

Understanding BLE Extended Advertising: Why We Need It and How BleuIO Pro Supports It

Bluetooth Low Energy (BLE) has become the backbone of modern wireless devices, powering everything from fitness trackers and smart home devices to environmental sensors and industrial monitors. One of the most important enhancements to BLE came with the introduction of Bluetooth 5.0: extended advertising. While legacy BLE advertising served many applications well, it had limitations that became apparent as developers tried to broadcast richer and larger amounts of data. With extended advertising, BLE has unlocked a new level of flexibility and power.

In this blog, we will explore what BLE extended advertising is, why it is important, how it differs from legacy advertising, and what types of use cases it enables. We will then show how the BleuIO Pro USB dongle supports extended advertising, and we will walk through two real-world experiments: first, using a Google Pixel 7 to advertise extended packets and scanning them with BleuIO Pro, and second, using BleuIO Pro itself to advertise extended packets. This hands-on approach will help illustrate how extended advertising works in practice.

What Is BLE Extended Advertising?

BLE devices advertise their presence and capabilities through short packets called advertising packets. Prior to Bluetooth 5.0, these packets were limited to a maximum of 31 bytes and were transmitted over three primary advertising channels (37, 38, and 39). While this was adequate for broadcasting a device name, some flags, and perhaps a small amount of service or manufacturer data, it quickly became insufficient for more advanced use cases.

Bluetooth 5.0 introduced extended advertising, it increases the maximum data payload from 31 bytes to up to 255 bytes in a single extended packet, and with chained packets, it can go up to approximately 1650 bytes. This innovation allows devices to broadcast richer datasets without needing to establish a BLE connection, saving power and improving efficiency.

Why Do We Need Extended Advertising?

As BLE has matured, the demand for more capable broadcasting has increased. Environmental sensors often need to transmit multiple data points, such as temperature, humidity, CO2 levels, and battery status. Asset trackers may need to include an identifier, timestamp, status code, and other metadata. Legacy BLE advertising simply cannot fit this level of information into its small packet size.

Extended advertising solves this problem by allowing significantly larger payloads, making BLE suitable for use cases where connectionless communication is preferred. It also helps reduce interference on the crowded 2.4 GHz band by moving much of the advertising traffic to secondary channels. Overall, extended advertising expands the potential of BLE in both consumer and industrial applications.

What Is the Difference Between Legacy and Extended Advertising?

Legacy BLE advertising uses 31-byte packets on the three primary advertising channels. It is supported on almost all BLE devices, making it extremely compatible but also quite limited. Extended advertising, on the other hand, allows devices to broadcast on secondary channels and increases the maximum payload size to 255 bytes per packet, or even over 1600 bytes when chaining is used. Extended advertising is only available on devices with Bluetooth 5.0 or later.

Where legacy advertising only offers basic modes like connectable, scannable, and non-connectable, extended advertising introduces advanced modes, including periodic advertising. This flexibility allows developers to optimize their broadcasts for speed, range, or robustness.

Real-World Use Cases

Extended advertising opens the door to many exciting applications. Smart environmental sensors can broadcast detailed data snapshots without requiring a connection, reducing power consumption and simplifying deployments. Asset tracking devices can send rich identifiers and telemetry data. Smart lighting systems can broadcast control profiles or diagnostics. Even firmware updates or broadcast-based messaging become more practical with extended advertising. These capabilities make extended advertising a game changer for IoT, industrial monitoring, logistics, and smart city deployments.

How We Used the Pixel 7 to Advertise Extended Packets

To explore extended advertising in practice, we started with a Google Pixel 7 smartphone running Android 13, using the nRF Connect app to configure and broadcast extended advertising packets. Inside the app, we created a new advertiser and carefully adjusted the settings. We enabled Extended Advertising and disabled Legacy Advertising to ensure we stayed in BLE 5.0 mode. We set the advertising properties to connectable and scannable and prepared a payload that combined a Complete Local Name along with several Manufacturer Specific Data blocks.

Our goal was to simulate realistic sensor readings, so we included data blocks such as Temp:24.5, Hum:55.6, PM2.5:15.2, and CO2:440, along with several test tags for demonstration purposes.

When we scanned this advertising payload using BleuIO Pro, we observed a total payload length of approximately 141 bytes, which is well above the 31-byte limit of legacy BLE advertising and only possible thanks to Bluetooth 5.0 extended advertising.

Before scanning with the BleuIO Pro dongle, we had to enable extended scan results. This was done using the ATES command:

ATES=1

This toggle turns on extended scanning, which is off by default. Once enabled, we scanned for the Pixel 7’s MAC address using:

AT+SCANTARGET=[1]MAC_ADDRESS=4

We were then able to see the full advertised data on the BleuIO Pro side, confirming that the Pixel 7 was successfully broadcasting extended advertising packets.

How We Used BleuIO Pro to Advertise Extended Packets

Next, we set out to test BLE extended advertising in the other direction: advertising from the BleuIO Pro dongle itself.

We began by configuring the advertising parameters with the following command:

AT+ADVEXTPARAM=0=1=0=160=320=7=0=0=0=1=0=1=0=0

Here’s what these parameters mean:

  • HANDLE: 0 — the advertising handle we are configuring.
  • mode: 1 — general discovery mode.
  • properties: 0 — non-connectable and non-scannable, which allows maximum payload.
  • primary_intv_min / max: 160 / 320 — the minimum and maximum advertising interval.
  • primary_channel_map: 7 — enabling all three primary advertising channels.
  • local_addr_type: 0 — using a public address.
  • filt_policy: 0 — no filtering policy.
  • tx_power: 0 — default transmit power.
  • primary_phy / secondary_phy: 1 — using the 1M PHY on both primary and secondary channels.
  • secondary_max_event_skip: 0 — no event skipping.
  • sid: 0 — advertising set identifier.
  • scan_req_notif_enable: 0 — scan request notifications disabled.
  • peer_address: public, 00:00:00:00:00:00 — no directed address.

Once configured, we set the advertising payload and started advertising using this command:

AT+ADVEXTSTART=0=16094469616c6f672041445620657874656e73696f6e7316ff4469616c6f672041445620657874656e73696f6e73=-

This payload contained a Complete Local Name block and repeated Manufacturer Specific Data blocks, again simulating sensor readings and test data. When we scanned this advertising from the Pixel 7 using nRF Connect, we were able to see the full payload, confirming that BleuIO Pro was successfully broadcasting extended packets.

Final Thoughts

BLE extended advertising represents a major advancement for Bluetooth Low Energy technology. By lifting the 31-byte payload limit and moving traffic onto secondary channels, it enables a wide range of applications that were previously impractical or impossible.

Through our experiments using the Pixel 7 and BleuIO Pro, we were able to demonstrate both advertising and scanning of extended packets, providing a solid foundation for developers and enthusiasts interested in exploring this powerful feature. Whether you are working on smart sensors, asset trackers, or industrial devices, understanding extended advertising will allow you to push the boundaries of what BLE can achieve.

We look forward to seeing how you apply this technology in your own projects. If you have screenshots, data examples, or need help integrating extended advertising into your applications, feel free to reach out — we’d be happy to collaborate or offer advice.

Share this post on :

Running BleuIO on M5Stack’s CoreMP135

At BleuIO, we aim to provide versatile, easy-to-use Bluetooth Low Energy (BLE) solutions that can run across a wide range of platforms.
Today, we’re excited to showcase a new environment where BleuIO works perfectly: the CoreMP135 from M5Stack Technology Co., Ltd.

We tested running our BLE sniffer script on this compact Linux industrial controller — and it worked seamlessly.

You can find the BleuIO Pro USB Dongle available for purchase here on DigiKey.

About CoreMP135

The CoreMP135 is a highly integrated Linux-based industrial control host powered by the STM32MP135DAE7 chip. It features a single-core ARM Cortex-A7 processor running at up to 1 GHz and is equipped with 4Gb (512MB) of DDR3L SDRAM.

Key highlights include:

  • Dual Gigabit Ethernet interfaces
  • USB 2.0-A and USB-C ports
  • CAN FD, RS485, and Grove I2C/UART connectivity
  • 2.0-inch IPS capacitive touchscreen
  • 1W speaker for audio output
  • Low-power design with a built-in RTC and rechargeable battery support
  • Pre-installed Debian Linux system on MicroSD — ready for development right out of the box
  • DIN rail mounting support for industrial installations

You can find the CoreMP135 available for purchase here on DigiKey.

Running BleuIO on CoreMP135

Using one of the CoreMP135’s USB ports, we connected the BleuIO dongle.
After installing Python and the required libraries, the device immediately recognized BleuIO as a USB serial device.

We ran our BLE sniffer script without any issues.

Steps to Setup:

  1. Plug the BleuIO dongle into one of the USB-A ports.
  2. Install required Python libraries:
    sudo apt update
    sudo apt install python3 python3-pip
    pip3 install pyserial
    pip3 install bluetooth-numbers
  3. Verify the dongle’s connection: ls /dev/ttyACM*
  4. Download the BLE sniffer script from GitHub: git clone https://github.com/smart-sensor-devices-ab/ble_sniffer_bleuio.git cd ble_sniffer_bleuio
  5. Run the script: python3 ble_sniffer.py

The sniffer script successfully captured BLE advertisements and displayed them on the CoreMP135’s Linux terminal.

BLE Sniffer Script

Our BLE sniffer script is available open-source on GitHub:
https://github.com/smart-sensor-devices-ab/ble_sniffer_bleuio

The script allows you to easily:

  • Scan for nearby BLE devices
  • Capture advertisement packets
  • Analyze BLE data in real-time

It’s lightweight, fast, and ideal for quick deployments or prototyping BLE-based solutions.

Output

Use Cases: Why Run BleuIO on CoreMP135?

Pairing BleuIO with the CoreMP135 opens up a range of practical applications across industries. In industrial environments, the setup can be used for continuous BLE monitoring, where devices like temperature or air quality sensors broadcast data that can be captured and logged locally. With its dual Gigabit Ethernet ports and USB connectivity, CoreMP135 serves well as a lightweight BLE-to-cloud gateway, collecting data from nearby BLE devices and forwarding it to cloud platforms for further analysis or real-time dashboards.

This setup also proves valuable for conducting Bluetooth security audits, allowing developers and testers to passively capture BLE advertisements and analyze potential vulnerabilities in connected devices such as wearables, beacons, or smart home equipment. For IoT developers, it provides a rapid prototyping platform where BLE applications can be built and tested without needing bulky workstations or cloud servers. And in the smart home space, CoreMP135 can act as a local BLE hub that listens for sensor data—such as motion, humidity, or presence—then triggers automation workflows through integrated edge logic.

The CoreMP135 from M5Stack is a powerful, compact Linux host, perfect for running BleuIO-based applications.
This platform proves that BleuIO can operate smoothly not just on desktops or laptops, but also on rugged, embedded, and industrial devices.

Whether you’re building a smart factory solution, a BLE gateway, or simply experimenting with Bluetooth technology, the combination of BleuIO and CoreMP135 provides flexibility, reliability, and ease of deployment.

Share this post on :

Control Your Windows Computer Over BLE Using BleuIO

Controlling your computer wirelessly might sound complex — but with the power of Bluetooth Low Energy (BLE) and the BleuIO dongle, it’s surprisingly simple. In this guide, we’ll walk through a creative example where you can control the brightness of your Windows PC using BLE commands sent from your mobile phone using BLE app.

What This Project Does

Using a BleuIO dongle connected to a Windows PC, we enable BLE communication using the Serial Port Service (SPS). When a BLE-enabled phone connects to the dongle and sends a value (from 1 to 10), the PC receives this data and adjusts its screen brightness accordingly — all in real-time.

It’s a simple and powerful demonstration of BLE-to-system integration, and it’s only the beginning of what’s possible with BleuIO.

Tools & Requirements

Install both with:

python -m pip install --user pyserial screen-brightness-control

How It Works

This project uses the BleuIO dongle in SPS Server mode, which allows it to receive data over Bluetooth Low Energy (BLE) from a connected device — in our case, a smartphone using the nRF Connect app.

Here’s a breakdown of how everything works together:

Initialize the Dongle on the PC ( SPS)

When you run the Python script on Windows, it sends the following commands to the BleuIO dongle via serial:

  • AT+ADVSTART → Starts advertising the dongle so it becomes discoverable over BLE.

Connect to BleuIO from Your Phone (Using nRF Connect)

On your mobile device, open the nRF Connect app:

  • Tap “Scan” and look for a device named “BleuIO”
  • Tap “Connect” to establish a BLE connection

Once connected, you’ll see a list of services and characteristics provided by the BleuIO dongle.

Identify the Correct BLE Characteristic to Send Data

In the attribute table:

  • Look for a writable characteristic under one of the unknown services.
  • You’ll often see one with the following properties:
    • Write Without Response
    • (Optionally also Notify)
  • The UUID will look like: 0783B03E-8535-B5A0-7140-A304D2495CBA

Send the SPS Command from the App

Now that you’re connected and have found the correct characteristic:

  1. Tap the write icon (↥) on that characteristic
  2. Choose “UTF-8 string” as the format (not hex!)
  3. In the message field, enter something like: AT+SPSSEND=5
  4. Tap “Send”

This sends a Bluetooth message to the BleuIO dongle, which forwards it via the SPS protocol to the Python script on your PC.

Python Script Reads and Acts on the Message

On the PC, the Python script reads the incoming SPS message and extracts the number from the AT+SPSSEND= command. It then adjusts your screen brightness using the screen-brightness-control library.

For example:

  • Sending AT+SPSSEND=1 → brightness set to 10%
  • Sending AT+SPSSEND=5 → brightness set to 50%
  • Sending AT+SPSSEND=10 → brightness set to 100%

Repeating

You can send new values anytime while connected — and your computer will respond instantly by updating the brightness accordingly.

Full Python Script

Here’s the script used in the project:

import serial
import time
import screen_brightness_control as sbc

BLEU_IO_PORT = "COM4"  # Update this to match your BleuIO COM port
BAUD_RATE = 9600

def set_brightness(level):
    brightness = int(max(10, min(100, level * 10)))
    try:
        sbc.set_brightness(brightness)
        print(f"Brightness set to {brightness}%")
    except Exception as e:
        print(f"Failed to set brightness: {e}")

def setup_bleuio(ser):
    commands = [
        b'AT+SPS=1\r\n',
        b'AT+ADVSTART\r\n'
    ]
    for cmd in commands:
        ser.write(cmd)
        time.sleep(0.5)
    print("BleuIO is in Peripheral + SPS mode, now advertising...")

def read_message(ser):
    buffer = ""
    while True:
        if ser.in_waiting:
            data = ser.read(ser.in_waiting).decode("utf-8", errors="ignore")
            buffer += data
            while "\r\n" in buffer:
                line, buffer = buffer.split("\r\n", 1)
                yield line.strip()
        else:
            time.sleep(0.1)

def process_message(msg):
    if not msg or msg.startswith("AT+") or "Invalid" in msg or "CONNECTED" in msg or "ADVERTISING" in msg:
        return

    print(f"Received message: '{msg}'")
    try:
        if "=" in msg:
            _, value = msg.split("=", 1)
        else:
            value = msg
        val = int(value.strip())
        if 1 <= val <= 10:
            set_brightness(val)
        else:
            print("Value out of range (1–10)")
    except ValueError:
        print("Invalid message format")

def main():
    try:
        with serial.Serial(BLEU_IO_PORT, BAUD_RATE, timeout=1) as ser:
            setup_bleuio(ser)
            print("Waiting for BLE messages via SPS from your phone...")
            for msg in read_message(ser):
                process_message(msg)
    except serial.SerialException as e:
        print(f"Serial error: {e}")
    except KeyboardInterrupt:
        print("Exiting...")

if __name__ == "__main__":
    main()

What is SPS on BleuIO?

SPS stands for Serial Port Service, a custom BLE profile supported by BleuIO to send and receive data like a UART over BLE.

Key SPS AT Commands:

  • AT+SPSSEND=message → Sends data via BLE from client to host or vice versa

In our case, the mobile phone is the BLE client sending data to BleuIO, which is the peripheral/server.

Use Cases & Future Ideas

This project is just the beginning! Here are more ways to expand on it:

  • Control volume using BLE
  • Send commands to launch apps or toggle Wi-Fi
  • Build a BLE-based authentication system for login or locking/unlocking the screen
  • Lock/sleep windows computer

Controlling your computer via Bluetooth from a phone is now as easy as a few lines of Python and a BLE dongle like BleuIO. This project is a great foundation for building more interactive, wireless automation solutions — from IoT control panels to personal smart systems.

Share this post on :

How to Build Your Own Bluetooth Scriptable Sniffer for Under $30

Bluetooth is commonly used in many products — from smartwatches and fitness trackers to wireless speakers, beacons, air quality sensors, and beyond. As developers, engineers, or even curious tech enthusiasts, we often would like to analyze what is being transmitted in the air interface between devices.

That’s where a Bluetooth sniffer comes into play.

What is a Bluetooth Sniffer?

A Bluetooth sniffer is a hardware or software tool that captures and monitors Bluetooth communication between devices. Think of it as a network traffic analyzer, but for Bluetooth instead of Wi-Fi or Ethernet.

It works by listening to Bluetooth advertisement packets or data exchanges, decoding them, and presenting the raw data in a human-readable format. These sniffers can help you:

  • Discover nearby Bluetooth Low Energy (BLE) devices
  • Monitor BLE advertisement packets
  • Analyze signal strength (RSSI)
  • Debug BLE applications
  • Reverse engineer custom BLE services

There are high-end Bluetooth sniffers on the market — like those from Ellisys or Teledyne LeCroy — which are powerful but often cost hundreds or thousands of dollars.

But what if you could build your own for under $30?

BleuIO – BLE USB Dongle

BleuIO is a compact USB dongle that turns your computer into a Bluetooth Low Energy sniffer and data communication tool. It’s built on Dialog Semiconductor’s DA14683 chip and supports AT command communication over a virtual COM port.

You can plug it into any USB port and control it using a terminal or a script.

Price: $24.99
Platform support: Windows, macOS, Linux
Protocols supported: Bluetooth Low Energy (BLE)
Programming Language Support: Supports almost all major programming languages including C++, C#, Python, Javascript etc

Build Your Own Scriptable BLE Sniffer with BleuIO

What You’ll Need

  • 1x BleuIO USB Dongle
  • A computer (Windows/macOS/Linux)
  • Python installed (3.x recommended)
  • The pyserial library
  • The bluetooth_numbers library

Step 1: Install Required Python Package

Open your terminal or command prompt and run:

pip install pyserial
pip install bluetooth-numbers

Step 2: Connect the BleuIO Dongle

Plug the dongle into a USB port. On Windows, it’ll appear as something like COM3. On macOS/Linux, it will show up as /dev/tty.usbmodemXXXX or /dev/ttyACM0.

Step 3: Write the BLE Sniffer Script

import serial
import time
import re
from bluetooth_numbers import company
import binascii

# Replace with your actual serial port
#SERIAL_PORT = 'COM3'      # Windows
SERIAL_PORT = '/dev/cu.usbmodem4048FDE52DAF1'  # For Linux/macOS
BAUD_RATE = 9600

def scan_devices(duration=3):
    device_list = []  

    try:
        with serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) as ser:
            ser.write(f'AT+DUAL\r\n'.encode())
            print(f"\nStarting BLE scan for {duration} seconds...\n")
            ser.write(f'AT+GAPSCAN={duration}\r\n'.encode())
            time.sleep(duration + 1)

            print("Discovered Devices:\n" + "-"*50)
            while ser.in_waiting:
                line = ser.readline().decode('utf-8', errors='ignore').strip()
                print(">>", line)

                match = re.match(r"\[\d+\] Device: \[(\d)\]([0-9A-F:]{17})\s+RSSI:\s*-?\d+(?:\s+\((.+?)\))?", line)
                if match:
                    addr_type = int(match.group(1))
                    mac = match.group(2)
                    name = match.group(3) if match.group(3) else ""
                    device_list.append((addr_type, mac, name))

        return device_list

    except serial.SerialException as e:
        print("Serial error:", e)
        return []



def scan_target_device(mac_address, address_type=1, duration=3):
    try:
        with serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) as ser:
            print(f"\nScanning target device {mac_address} (Type: {address_type}) for {duration} seconds...\n")
            cmd = f'AT+SCANTARGET=[{address_type}]{mac_address}={duration}\r\n'
            ser.write(cmd.encode())
            time.sleep(duration + 1)

            print("Advertisement Data:\n" + "-"*50)
            adv_data = None

            while ser.in_waiting:
                line = ser.readline().decode('utf-8', errors='ignore').strip()
                print(">>", line)

                if "Device Data [ADV]:" in line and adv_data is None:
                    parts = line.split("Device Data [ADV]:")
                    if len(parts) == 2:
                        adv_data = parts[1].strip()

            if adv_data:
                print("\nDecoding Advertisement Payload...\n")
                decode_ble_adv(adv_data)
            else:
                print("No ADV data found to decode.")

    except serial.SerialException as e:
        print("Serial error:", e)


AD_TYPE_NAMES = {
    0x01: "Flags",
    0x02: "Incomplete 16-bit UUIDs",
    0x03: "Complete 16-bit UUIDs",
    0x08: "Shortened Local Name",
    0x09: "Complete Local Name",
    0x0A: "TX Power Level",
    0x16: "Service Data",
    0xFF: "Manufacturer Specific Data"
}

# Flag bit definitions
FLAGS_MAP = {
    0x01: "LE Limited Discoverable Mode",
    0x02: "LE General Discoverable Mode",
    0x04: "BR/EDR Not Supported",
    0x08: "Simultaneous LE and BR/EDR (Controller)",
    0x10: "Simultaneous LE and BR/EDR (Host)"
}

def decode_ble_adv(hex_str):
    data = bytearray.fromhex(hex_str)
    index = 0
    object_count = 1

    print(f"Decoding ADV Data: {hex_str}\n{'-'*50}")

    while index < len(data):
        length = data[index]
        if length == 0 or (index + length >= len(data)):
            break

        ad_type = data[index + 1]
        ad_data = data[index + 2: index + 1 + length]
        type_name = AD_TYPE_NAMES.get(ad_type, f"UNKNOWN")

        print(f"\nData Object {object_count}:")
        print(f"Length: {length}")
        print(f"Type: 0x{ad_type:02X} ({type_name})")

        if ad_type == 0x01:  # Flags
            flags = ad_data[0]
            print("Flags:")
            for bit, label in FLAGS_MAP.items():
                if flags & bit:
                    print(f"   - {label}")
            print("Device Type Inferred:", end=" ")
            if flags & 0x04:
                print("LE Only")
            elif flags & (0x08 | 0x10):
                print("Dual Mode (LE + BR/EDR)")
            else:
                print("BR/EDR Only or Unknown")

        elif ad_type == 0xFF:  # Manufacturer Specific Data
            if len(ad_data) >= 2:
                company_id = ad_data[0] | (ad_data[1] << 8)
                company_name = company.get(company_id, "Unknown")
                print(f"Company Identifier: 0x{company_id:04X} ({company_name})")
                manufacturer_data = ad_data[2:]
                if manufacturer_data:
                    print("Manufacturer Data:", binascii.hexlify(manufacturer_data).decode())
            else:
                print("Malformed Manufacturer Specific Data")

        elif type_name == "UNKNOWN":
            print(f"This script is currently unable to decode this type.")
            print("Raw Data:", "0x" + binascii.hexlify(ad_data).decode())

        else:
            print("Raw Data:", "0x" + binascii.hexlify(ad_data).decode())

        index += length + 1
        object_count += 1



if __name__ == "__main__":
    devices = scan_devices()

    if devices:
        print("\nSelect a device to scan further:")
        for idx, (addr_type, mac, name) in enumerate(devices):
            label = f"{mac} ({name})" if name else mac
            print(f"[{idx}] {label} ")

        choice = input("Enter device number (e.g. 0): ").strip()

        try:
            selected = devices[int(choice)]
            scan_target_device(selected[1], selected[0])  
        except (IndexError, ValueError):
            print("Invalid selection. Exiting.")
    else:
        print("No devices found.")

Note: Make sure to update the SERIAL_PORT variable in the script to match your system’s COM port — for example, COM3 on Windows or /dev/tty.usbmodemXXXX on macOS/Linux.

How It Works

  • Step 1: Sends the AT+GAPSCAN command to BleuIO, which returns a list of nearby BLE devices with MAC addresses and signal strength.
  • Step 2: Parses the output and allows the user to select one device.
  • Step 3: Sends the AT+SCANTARGET=[address_type]MAC=3 command to scan the selected device and retrieve its advertisement payload.
  • Step 4: Displays the detailed advertising data broadcasted by the device — which can include device name, UUIDs, manufacturer data, and sensor readings.
  • Step 5: Attempts to decode all fields in the BLE advertisement payload, showing both known fields (like Flags, Manufacturer Data) and unknown ones with raw data formatting

Decoding Advertisement Data

Every BLE advertisement is made up of TLV (Type-Length-Value) structures. This script extracts each one and attempts to decode:

  • Flags (Type 0x01): e.g., LE Only, Dual Mode
  • Manufacturer Specific Data (Type 0xFF): Extracts company ID and raw payload
  • Unknown types: Clearly marked and printed as raw hex for future analysis

Even if the script can’t interpret a block, you’ll still see it listed with length, type, and raw content — helping with reverse engineering or debugging unknown BLE devices.

Sample Output

Starting BLE scan for 3 seconds...

Discovered Devices:
>> AT+DUAL
>> AT+GAPSCAN=3
>> SCANNING...
>> [01] Device: [1]D1:53:C9:A9:8C:D2  RSSI: -56 (HibouAIR)
>> [02] Device: [1]C4:AD:CB:84:A5:73  RSSI: -83
>> [03] Device: [1]D1:79:29:DB:CB:CC  RSSI: -52 (HibouAIR)
>> [04] Device: [1]C0:8C:23:2E:1A:E5  RSSI: -59
>> SCAN COMPLETE

Select a device to scan further:
[0] D1:53:C9:A9:8C:D2 (HibouAIR) 
[02] C4:AD:CB:84:A5:73 
[03] D1:79:29:DB:CB:CC (HibouAIR) 
[104] C0:8C:23:2E:1A:E5 
Enter device number (e.g. 0): 03      

Scanning target device D1:79:29:DB:CB:CC (Type: 1) for 3 seconds...

Advertisement Data:
--------------------------------------------------
>> AT+SCANTARGET=[1]D1:79:29:DB:CB:CC=3
>> SCANNING TARGET DEVICE...
>> [D1:79:29:DB:CB:CC] Device Data [ADV]: 0201061BFF5B0705042200696D009F26B60082023D00000000000000024C02
>> [D1:79:29:DB:CB:CC] Device Data [RESP]: 110750EADA308883B89F604F15F30100C98E09094869626F75414952
>> SCAN COMPLETE

Decoding Advertisement Payload...

Decoding ADV Data: 0201061BFF5B0705042200696D009F26B60082023D00000000000000024C02
--------------------------------------------------

Data Object 1:
Length: 2
Type: 0x01 (Flags)
Flags:
   - LE General Discoverable Mode
   - BR/EDR Not Supported
Device Type Inferred: LE Only

Data Object 2:
Length: 27
Type: 0xFF (Manufacturer Specific Data)
Company Identifier: 0x075B (Smart Sensor Devices AB)
Manufacturer Data: 05042200696d009f26b60082023d00000000000000024c02

Source Code on GitHub

You can find the full, open-source implementation of this BLE sniffer — including the Python script and all improvements — on GitHub:

https://github.com/smart-sensor-devices-ab/ble_sniffer_bleuio

Now we have a working BLE sniffer that not only scans for nearby devices but also lets you interactively select a target and read its detailed advertisement data.

Here are some cool extensions we can build from here:

  • Display air quality sensor data from BLE beacons like HibouAir
  • Export scan logs to CSV for analysis
  • Build a desktop or web UI using Electron or Flask
  • Trigger alerts based on proximity or signal strength
  • Improve decoding support for more AD types (TX Power, Local Name, Services)
  • Show scan response (RESP) data alongside advertisement (ADV)
  • Display or log RSSI values for signal analysis

Bluetooth sniffers don’t have to be complicated or expensive. With BleuIO, a bit of Python, and a USB port, you can begin exploring the hidden world of BLE devices all around you — right from your own machine.

This setup is perfect for developers working on BLE apps, IoT product engineers, or tech enthusiasts who want to learn how devices communicate wirelessly.

Share this post on :

LUA parser for Apple Homekit using BleuIO

This project demonstrates how to turn a BLE advertisement-based air quality sensor—in this case, the HibouAir—into a fully integrated Apple Home accessory. By combining the flexibility of the BleuIO USB BLE dongle and the simplicity of Lua scripting, we’ve created a bridge that reads raw BLE advertisement packets, decodes the environmental data, and makes it available to the Apple Home app through Homebridge.

Unlike most HomeKit integrations that rely on cloud APIs or native HomeKit devices, this setup is completely offline and works on any platform. The use of BleuIO allows BLE communication to be handled reliably across macOS, Linux, or Windows—something most native BLE libraries struggle to achieve consistently across platforms. Lua adds a lightweight, embeddable scripting engine perfect for decoding raw advertisement data in real time. Together, they make a fast, minimalist, and cross-platform solution for BLE-to-HomeKit integration.

What This Project Does

At a high level, the system continuously scans BLE advertisements from the HibouAir sensor using BleuIO. The data is decoded using Lua, which extracts temperature and humidity values. These values are then served via a local HTTP server, and finally read by Homebridge using the homebridge-http-temperature-humidity plugin. This enables you to view real-time air quality data directly in the Apple Home app on your iPhone, iPad, or Mac.

Project Components and Tools Used

Step-by-Step Setup

1. Connect and Configure BleuIO

Start by plugging in your BleuIO USB dongle. On macOS or Linux, find its serial port using:

ls /dev/tty.usb*

Once you’ve identified the port (e.g., /dev/tty.usbmodemXXXXXX), update the Python script accordingly.

2. Create bleuio_scan.py

This script will initiate a BLE scan using BleuIO’s AT command interface and capture the raw advertisement data from the HibouAir sensor. It filters for packets containing a specific manufacturer ID and writes the first match to a file.

import serial
import time
import re

# Update this with your actual port
port = "/dev/tty.usbmodem4048FDE52DAF1"

ser = serial.Serial(port, 9600, timeout=1)
ser.write(b"AT+FINDSCANDATA=5B07050=2\r\n")
time.sleep(4)

data = ser.read_all().decode()
ser.close()

print("RAW OUTPUT:\n", data)

# Extract first adv line
matches = re.findall(r"Device Data \[ADV\]: ([0-9A-F]+)", data)
if matches:
    with open("adv_data.txt", "w") as f:
        f.write(matches[0])
    print("✅ Wrote ADV data:", matches[0])
else:
    print("❌ No HibouAir data found.")

3. Parse the BLE Data Using Lua

Lua is ideal for embedded processing due to its speed and small footprint. We use it here to decode the hex-formatted BLE advertisement string into readable sensor values.

Create a file named parse_ble_adv.lua with the following:

local http = require("socket.http")
local ltn12 = require("ltn12")
local json = require("dkjson")

-- Reverse byte order (e.g., "1234" -> "3412")
local function reverse_bytes(hexstr)
    local bytes = {}
    for i = 1, #hexstr, 2 do
        table.insert(bytes, 1, hexstr:sub(i, i+1))
    end
    return table.concat(bytes)
end

-- Parse HibouAir BLE advertisement data
local function parse_adv_data(adv)
    local pos = string.find(adv, "5B070504")
    if not pos then return nil end
    pos = pos - 1 -- Lua is 1-indexed

    local function read_val(start, len, divide_by, signed)
        local hex = reverse_bytes(adv:sub(start, start+len-1))
        local val = tonumber(hex, 16)
        if signed and val > 0x7FFF then
            val = val - 0x10000
        end
        return divide_by and val / divide_by or val
    end

    return {
        temp = read_val(pos+23, 4, 10, true),
        hum = read_val(pos+27, 4, 10),
        pressure = read_val(pos+19, 4, 10), 
        voc = read_val(pos+31, 4),
        pm1 = read_val(pos+35, 4, 10),
        pm25 = read_val(pos+39, 4, 10),
        pm10 = read_val(pos+43, 4, 10),
        co2 = tonumber(adv:sub(pos+47, pos+50), 16),
        vocType = tonumber(adv:sub(pos+51, pos+52), 16),
        ts = os.date("%Y-%m-%d %H:%M:%S")
    }
end

-- Example BLE advertisement data (replace with real data from BleuIO scan)
-- local adv_data = "0201061BFF5B070504220069130010273A0160017E0000000000000001B703"
local file = io.open("adv_data.txt", "r")
local adv_data = file:read("*a")
file:close()

local data = parse_adv_data(adv_data)
-- Write latest data to file
print("DEBUG: Writing this to latest_data.json")
print("Temperature:", data.temp)
print("Humidity:", data.hum)

local file = io.open("latest_data.json", "w")
file:write(json.encode({
    temperature = data.temp,
    humidity = data.hum,
}))

file:close()



if not data then
    print("Failed to parse advertisement data")
    return
end

print("Parsed BLE Data:")
for k, v in pairs(data) do
    print(k, v)
end

4. Automate Scanning and Parsing

To keep your data fresh, use a simple shell script to run both the scanner and parser every 10 seconds.

Create run_everything.sh:

#!/bin/bash
while true; do
  echo "Scanning and updating Homebridge..."
  python3 bleuio_scan.py && lua parse_ble_adv.lua
  sleep 10
done

Make it executable with:

chmod +x run_everything.sh

Run it in the background or with tmux to keep it alive.

5. Create the HTTP Server in Lua

This server reads from the JSON file and exposes it via an HTTP endpoint (/temp) that Homebridge can read.

local copas = require("copas")
local socket = require("socket")
local json = require("dkjson")

-- Start TCP server on port 8081
local server = socket.bind("*", 8081)
copas.addserver(server, function(c)
    c = copas.wrap(c)
    local request = c:receive("*l")

    if request and request:match("GET /temp") then
        -- Read latest temp/hum from file
        local file = io.open("latest_data.json", "r")
        local temp_hum = { temperature = 0, humidity = 0 }

        if file then
            local contents = file:read("*a")
            file:close()
            local decoded, _, err = json.decode(contents)
            if decoded then
                temp_hum = decoded
            end
        end

        local body = json.encode(temp_hum)

        local response = {
            "HTTP/1.1 200 OK",
            "Content-Type: application/json",
            "Content-Length: " .. #body,
            "",
            body
        }
        c:send(table.concat(response, "\r\n"))
    else
        c:send("HTTP/1.1 404 Not Found\r\n\r\n")
    end
end)

print("Lua HTTP server running on http://localhost:8081")
copas.loop()

You’ll need LuaSocket and dkjson:

luarocks install luasocket
luarocks install dkjson
luarocks install copas

Run the server:

lua server.lua

It will listen on http://localhost:8081/temp and serve the current temperature and humidity.

Setting Up Homebridge and Home App Integration

Install Homebridge globally:

sudo npm install -g homebridge

Install the UI plugin for web-based setup:

sudo npm install -g homebridge-config-ui-x

Then install the required accessory plugin:

sudo npm install -g homebridge-http-temperature-humidity

Create or update your Homebridge config.json (usually located in ~/.homebridge/):

{
  "bridge": {
    "name": "Homebridge",
    "username": "0E:4E:20:2F:2E:BC",
    "port": 51826,
    "pin": "031-45-154"
  },
  "description": "Homebridge setup",
  "accessories": [
    {
      "accessory": "HttpTemphum",
      "name": "HibouAir Sensor",
      "url": "http://localhost:8081/temp",
      "http_method": "GET",
      "sendimmediately": "",
      "timeout": 3000
    }
  ],
  "platforms": [
    {
      "platform": "config",
      "name": "Config"
    }
  ]
}

Start Homebridge with:

homebridge -I

Use the Homebridge UI (usually on http://localhost:8081) to add the bridge to your Apple Home app by scanning the QR code. Once added, you’ll see temperature and humidity from your HibouAir sensor as real HomeKit accessories.

Output

This project showcases how BleuIO and Lua can be used to create a fast, simple, and platform-independent BLE integration with Apple Home. Unlike heavyweight setups or cloud-connected devices, this approach is minimal, local-first, and highly customizable. With BleuIO’s cross-platform compatibility and Lua’s tiny footprint, you can integrate BLE advertisement data into almost any platform—from macOS to Raspberry Pi to embedded Linux. This is just the beginning. You can extend this setup to support more metrics like VOC, CO₂, pressure, light.

Share this post on :