Example project · ESP32
Bluetooth LE: pair & encrypt
Two ESP32-C6 boards secure a real LE link end-to-end: one advertises connectably, the other connects as central and calls gap_pair. The SMP Just-Works handshake runs over the link (watch the SMP frames in the Sniffer), the controllers derive the key and run the LL encryption-start procedure, and BOTH boards report _IRQ_ENCRYPTION_UPDATE with a 16-byte key — the peripheral’s report rides the emulator’s post-encryption receive path through the controller’s own buffer allocator. One script on both boards; roles derive from each board’s MAC.

What's on the bench
- 2× Battery
- 2× ESP32-C6
The code
This MicroPython script runs on the emulated board every boot; edit it in the Code tab.
import bluetooth, time b = bluetooth.BLE() b.active(1) b.config(bond=False, mitm=False, le_secure=False) S = {} server = b.config('mac')[1][-1] % 2 == 0 tag = 'SRV' if server else 'CLI' tgt = [] cn = [] def cb(e, d): if e == 29: t, i, k = d return None if k is None else S.get((t, bytes(k)), None) if e == 30: t, k, v = d k = (t, bytes(k)) if v is None: S.pop(k, None) else: S[k] = bytes(v) return True if e == 28: print(tag + ' encrypted, key size ' + str(d[4])) elif e == 5 and not tgt: tgt.append((d[0], bytes(d[1]))) print('CLI found advertiser') elif e == 7: cn.append(d[0]) print('CLI connected, pairing soon') elif e == 1: print('SRV central connected') b.irq(cb) if server: b.gap_advertise(50000, b'\x02\x01\x06\x05\xffCAFE', connectable=True) print('SRV advertising, ready to pair') else: b.gap_scan(0, 30000, 30000) while not tgt: time.sleep_ms(50) b.gap_scan(None) time.sleep_ms(50) b.gap_connect(tgt[0][0], tgt[0][1]) while not cn: time.sleep_ms(50) time.sleep_ms(2000) b.gap_pair(cn[0]) print('CLI pairing...')