ble_listen.py

Arduino Nano ESP32 · File : ble_listen.py · Language : Python · Use case : Écouter les notifications BLE depuis un PC

On the PC side, the bleak library discovers and connects to the Nano ESP32 BLE service: each notification of characteristic 2A6E prints live. The missing link to log, display or alert on BLE readings without a mobile app.

Hardware

An Arduino Nano ESP32 (dual-core ESP32-S3, 2.4 GHz Wi-Fi + Bluetooth Low Energy, Nano-compatible physical pinout, native USB, 3.3 V pins only). Linux/Windows/macOS PC with Bluetooth LE, Python 3 and bleak; board advertising the service (ble-capteur.ino).

Wiring

None; bring the board close to the PC for the first pairing.

How it works

find_device_by_name filters advertising, start_notify subscribes the callback to the characteristic over ATT. The async with context disconnects cleanly after the 30 s listen.

Running it

Install the Arduino ESP32 Boards package (or follow the official Nano ESP32 guide), select Arduino Nano ESP32, upload. Pins are 3.3 V: never feed 5 V into an input. The serial monitor uses native USB.

Variants

Push readings to MQTT/InfluxDB inside the callback, or keep the connection open with auto-reconnect for continuous logging.

ble_listen.py

#!/usr/bin/env python3
"""Ecoute les notifications du service 181A (ble-capteur.ino).

Pre-requis : pip install bleak ; Bluetooth LE sur le PC.
"""
import asyncio

from bleak import BleakClient, BleakScanner

NOM = "NanoESP32-Capteur"
CHAR_MESURE = "2a6e"  # caractéristique BLENotify du croquis


def sur_notification(_, donnees: bytearray) -> None:
    print(f"mesure = {donnees[0]}/255")


async def principal() -> None:
    print("Recherche de", NOM, "...")
    peripherique = await BleakScanner.find_device_by_name(NOM, timeout=15)
    if peripherique is None:
        print("introuvable : la carte publie-t-elle ?")
        return
    async with BleakClient(peripherique) as client:
        print("connecte :", client.address)
        await client.start_notify(CHAR_MESURE, sur_notification)
        await asyncio.sleep(30)  # 30 s d'ecoute
        await client.stop_notify(CHAR_MESURE)


if __name__ == "__main__":
    asyncio.run(principal())

← Back to the board