# ==========================================================
# ESP32 BLE UART (NUS) - Version pédagogique
# - RX : Téléphone -> ESP32 (écriture)
# - TX : ESP32 -> Téléphone (notifications)
# ==========================================================
import bluetooth
import time
from micropython import const
from ble_advertising import advertising_payload
# ----------------------------------------------------------
# ÉTAPE 1) Constantes des événements BLE (IRQ)
# ----------------------------------------------------------
_IRQ_CENTRAL_CONNECT = const(1) # un téléphone se connecte
_IRQ_CENTRAL_DISCONNECT = const(2) # un téléphone se déconnecte
_IRQ_GATTS_WRITE = const(3) # le téléphone écrit sur une caractéristique
# ----------------------------------------------------------
# ÉTAPE 2) Flags des caractéristiques (droits d'accès)
# ----------------------------------------------------------
_FLAG_BROADCAST = const(0x0001)
_FLAG_READ = const(0x0002)
_FLAG_WRITE_NO_RESPONSE = const(0x0004)
_FLAG_WRITE = const(0x0008)
_FLAG_NOTIFY = const(0x0010)
_FLAG_INDICATE = const(0x0020)
# ----------------------------------------------------------
# ÉTAPE 3) UUIDs du service UART (NUS) + caractéristiques TX/RX
# ----------------------------------------------------------
_UART_UUID = bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
# TX : ESP32 -> téléphone (lecture + notification)
_UART_TX = (bluetooth.UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"),
_FLAG_READ | _FLAG_NOTIFY)
# RX : téléphone -> ESP32 (écriture)
_UART_RX = (bluetooth.UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E"),
_FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE)
_UART_SERVICE = (_UART_UUID, (_UART_TX, _UART_RX))
# ----------------------------------------------------------
# ÉTAPE 4) Variables globales simples (pour éviter les classes)
# ----------------------------------------------------------
ble = bluetooth.BLE()
connections = set() # stocke les conn_handle des clients connectés
handle_tx = None
handle_rx = None
payload = None
# ----------------------------------------------------------
# ÉTAPE 5) Fonction : démarrer l'advertising
# ----------------------------------------------------------
def start_advertising(interval_us=500000):
print(">> Advertising BLE en cours...")
ble.gap_advertise(interval_us, adv_data=payload)
# ----------------------------------------------------------
# ÉTAPE 6) Fonction : envoyer (TX) -> notifications vers téléphone
# ----------------------------------------------------------
def send_tx(text):
data = text.encode("utf-8")
# 1) Mettre à jour la valeur stockée dans la caractéristique TX
ble.gatts_write(handle_tx, data)
# 2) Notifier tous les clients (sans repasser data si tu veux)
for conn_handle in connections:
ble.gatts_notify(conn_handle, handle_tx) # envoie la valeur stockée
# ----------------------------------------------------------
# ÉTAPE 7) Gestionnaire d'interruptions BLE (IRQ)
# ----------------------------------------------------------
def irq_handler(event, data):
global connections
# 7.1) Connexion
if event == _IRQ_CENTRAL_CONNECT:
conn_handle, _, _ = data
print("✅ Connecté ! conn_handle =", conn_handle)
connections.add(conn_handle)
# 7.2) Déconnexion
elif event == _IRQ_CENTRAL_DISCONNECT:
conn_handle, _, _ = data
print("❌ Déconnecté ! conn_handle =", conn_handle)
if conn_handle in connections:
connections.remove(conn_handle)
# Redémarrer l'advertising pour permettre une nouvelle connexion
start_advertising()
# 7.3) Écriture sur une caractéristique (téléphone -> ESP32)
elif event == _IRQ_GATTS_WRITE:
conn_handle, value_handle = data
# Lire la donnée reçue dans la caractéristique
received = ble.gatts_read(value_handle)
# On ne traite que RX
if value_handle == handle_rx:
try:
msg = received.decode("utf-8")
except:
msg = str(received)
print("📩 Reçu sur RX :", msg)
# ----------------------------------------------------------
# ÉTAPE 8) Programme principal
# ----------------------------------------------------------
def main():
global ble, handle_tx, handle_rx, payload
print("=== ESP32 BLE UART (NUS) - Mode pédagogique ===")
# 8.1) Activer BLE et installer l'IRQ
ble.active(True)
ble.irq(irq_handler)
# 8.2) Enregistrer le service -> récupère les handles
# gatts_register_services retourne une structure de handles
((handle_tx, handle_rx),) = ble.gatts_register_services((_UART_SERVICE,))
print("Handles:")
print(" handle_tx =", handle_tx)
print(" handle_rx =", handle_rx)
# 8.3) Créer le payload advertising : nom + UUID du service
payload = advertising_payload(name="ESP-UART", services=[_UART_UUID])
# 8.4) Démarrer l'advertising
start_advertising()
# 8.5) Boucle principale : si connecté, on peut envoyer
while True:
if connections:
# Exemple : envoyer un message au téléphone
msg = input("\nTape un message à envoyer (TX) : ")
send_tx(msg)
else:
print("⏳ En attente d'une connexion BLE...")
time.sleep(2)
# ----------------------------------------------------------
# Lancer
# ----------------------------------------------------------
if __name__ == "__main__":
main()