Execute Python Scripts via BLE Using BleuIO and Your Mobile Phone

August 8, 2025
Execute Python Scripts via BLE Using BleuIO and Your Mobile Phone

This project demonstrates how to execute a Python script wirelessly from your mobile phone using a BleuIO dongle. By sending simple text commands over Bluetooth Low Energy (BLE) through the Serial Port Service (SPS), the Python script can trigger actions. In our case, the script will retrieve and display CO2, temperature, and humidity values from a nearby BLE air quality monitoring sensor called HibouAir.

This approach opens up many possibilities for interactive projects, sensor monitoring, and remote control applications — all without the need for internet connectivity.

Prerequisites

Hardware

Software

  • Python 3 installed on your computer
  • pyserial library (pip install pyserial)
  • nRF Connect (iOS / Android)

Setting up the BleuIO Dongle

Begin by plugging your BleuIO dongle into the computer. Open a BLE terminal such as the BleuIO Web Terminal or any serial monitor and enable the Serial Port Service. You can do this by entering:


ATASPS1
AT+ADVSTART

This enables the SPS service, ensures incoming data is displayed as ASCII text, and starts advertising so your phone can connect.

The Python Script

The Python script connects to the BleuIO dongle over a serial port and listens for incoming BLE messages. When it receives one of four possible commands — CO2, TEMP, HUM, or ALL — it triggers a scan using the AT+FINDSCANDATA=220069=3 command. Here 220069 is the boardID of HibouAir sensor which we will use to retrieve air quality data in real time. This scans for nearby BLE devices broadcasting the matching advertising data. From the latest packet received, the script decodes and extracts the relevant sensor values.

Below is the complete script. Update the port variable to match your BleuIO’s serial port location.

import serial
import time
import re

def send_and_wait(ser, at_cmd):
    ser.write((at_cmd + '\r\n').encode())
    time.sleep(2)
    output = []
    while ser.in_waiting:
        line = ser.readline().decode('utf-8', errors='ignore').strip()
        output.append(line)
    return output

def extract_last_adv_hex(lines):
    adv_lines = [l for l in lines if "Device Data [ADV]:" in l]
    if not adv_lines:
        return None
    last_line = adv_lines[-1]
    match = re.search(r'([0-9A-Fa-f]{40,})$', last_line)
    if match:
        return match.group(1)
    return None

def parse_co2_temp_hum(adv):
    pos = adv.find("5B0705")
    if pos == -1:
        return None

    def parse_val(offset, reverse=True, scale=1.0, signed=False):
        raw = adv[pos + offset : pos + offset + 4]
        if reverse:
            raw = ''.join(reversed([raw[i:i+2] for i in range(0, 4, 2)]))
        val = int(raw, 16)
        if signed and val > 32767:
            val -= 65536
        return val / scale

    temp_raw = parse_val(22, scale=1, signed=True)
    temp = temp_raw / 10
    hum = parse_val(26, scale=10)
    co2 = int(adv[pos + 46 : pos + 50], 16)

    return {
        "temp": round(temp, 1),
        "hum": round(hum, 1),
        "co2": co2
    }

# --- Main Loop ---
port = "/dev/cu.usbmodem4048FDEBA6D01"
baudrate = 115200

try:
    with serial.Serial(port, baudrate, timeout=1) as ser:
        print("Listening for BLE SPS command...")
        while True:
            line = ser.readline().decode('utf-8', errors='ignore').strip()
            if line:
                #print(f" Received: {line}")
                cmd = line.replace("[Received]:", "").strip().upper()
                if cmd in ["CO2", "TEMP", "HUM", "ALL"]:
                    print(" Scanning for environmental data...")
                    results = send_and_wait(ser, "AT+FINDSCANDATA=0504220069=3")
                    adv = extract_last_adv_hex(results)
                    if adv:
                        data = parse_co2_temp_hum(adv)
                        if data:
                            if cmd == "CO2":
                                print(f" CO2: {data['co2']} ppm")
                            elif cmd == "TEMP":
                                print(f" Temp: {data['temp']} °C")
                            elif cmd == "HUM":
                                print(f" Hum: {data['hum']} %")
                            elif cmd == "ALL":
                                print(f" Temp: {data['temp']} °C")
                                print(f" Hum: {data['hum']} %")
                                print(f" CO2: {data['co2']} ppm")
                        else:
                            print(" Could not decode sensor values.")
                    else:
                        print(" No advertising data found.")
except serial.SerialException as e:
    print("Serial error:", e)

How It Works

Once the script is running, it keeps the serial connection to the BleuIO open and listens for BLE SPS messages sent from the phone. When a command is received, it is cleaned to remove any extra text added by the dongle, then matched against one of the four recognized keywords. If a match is found, the script asks the dongle to scan for nearby advertising packets from a device matching our filter. The script extracts the CO2, temperature, and humidity values, then displays the requested data based on the command.

For example, sending CO2 from the phone will only display the CO2 value, while sending ALL will show all three measurements.

Testing the Project

Run the script on your computer, then use the nRF Connect app on your phone to connect to the BleuIO dongle. Locate the SPS write characteristic (UUID ending in ...5CBA) and send a command in Text mode. Try sending CO2, TEMP, HUM, and ALL to see the different outputs. You should see the values appear in your terminal almost instantly after each command is sent.

Output

Use Cases and Expanding the Idea

This setup goes beyond simply reading CO2, temperature, and humidity. At its core, it is a BLE command-to-script bridge — meaning you can trigger any Python action from your phone without needing Wi-Fi or internet access.

In real-world use, this could be applied to:

  • Remote environmental monitoring: Trigger on-demand scans for sensor readings in greenhouses, offices, or laboratories.
  • IoT control panels: Send commands to control connected devices, such as turning fans or air purifiers on when CO2 levels rise.
  • Data logging systems: Store sensor readings in a file or database only when requested, helping conserve storage and processing power.
  • Event-based automation: Pair with external hardware like Raspberry Pi GPIO pins to trigger physical actions when commands are received.

Because the commands are just plain text, the possibilities for customization are endless. You could add more commands to control different hardware, run different scripts, or even communicate with multiple BLE devices. This same approach can also integrate with web dashboards, cloud services, or data visualization tools to make the results more accessible and actionable.

This project shows how simple it is to control Python scripts and interact with BLE sensor data using BleuIO and your phone. By combining the SPS profile with AT commands, you can create flexible, interactive tools that can be extended for various IoT applications — from remote environmental monitoring to interactive control systems.

Share this post on :

Leave a Reply

Your email address will not be published. Required fields are marked *

Follow us on LinkedIn :

Order Now