📡 Level 3 – Advanced Communication

Project 3.6: "Bluetooth R32-PC 2.0"

 

🚀 Project 3.6 – Bluetooth Hotkeys with Joystick Buttons (A–F) → PC

🎯 What you’ll learn

  • ✅ Goal 1: Initialize built‑in Bluetooth and advertise as “Clu‑Bots”
  • ✅ Goal 2: Use joystick buttons A–F to send hotkey messages over Bluetooth to a PC
  • ✅ Goal 3: Build helper functions (def) for mapping buttons to actions and sending text

Key ideas

  • Short definition: Buttons trigger Bluetooth messages that the computer can use as hotkeys.
  • Real‑world link: Media controllers, gamepads, and presentation clickers send simple button events via Bluetooth.

🧱 Blocks glossary (used in this project)

  • Bluetooth peripheral: Announces a name and sends text messages.
  • Callback (receive): Handles messages coming back from the PC (ack or status).
  • Digital input (pull‑up): Reads button state (pressed = 0) for A–F.
  • Variable: Stores labels like “PLAY”, “STOP”, or “NEXT”.
  • def function: Encapsulates actions (map_button(), send_text()) for reuse.
  • Serial print: Logs events (press, send, receive) on your computer.
  • Loop: Continuously checks buttons and sends messages.

🧰 What you need

PartHow many?Pin connection (D1 R32)
D1 R321USB cable
Joystick Shield (buttons only)1A(26), B(25), C(17), D(16), E(27), F(14)
Built‑in Bluetooth1Internal (no pins)
  • We use only joystick buttons A–F; joystick X/Y are not used in 3.7.
  • No external Bluetooth module needed; D1 R32 includes Bluetooth.

🔌 Wiring tip: Ensure the shield is firmly seated; buttons A–F are active LOW with pull‑up.
📍 Pin map snapshot: Buttons on pins 26, 25, 17, 16, 27, 14. Bluetooth is internal.


✅ Before you start

  • Plug in the USB and open the serial monitor.
  • Test print shows:
print("Ready!")  # Confirm serial is working

🎮 Microprojects (5 mini missions)

🎮 Microproject 3.7.1 – Bluetooth init + button inputs

Goal: Initialize Bluetooth, prepare A–F inputs, and print presses to serial.

Blocks used:

  • Bluetooth peripheral: Create device “Clu‑Bots”
  • Digital input (pull‑up): Read buttons A–F
  • Serial print: Log setup and button presses

Block sequence:

  1. Create peripheral named “Clu‑Bots”
  2. Setup pins 26,25,17,16,27,14 with pull‑up
  3. In a loop, print which button is pressed
  4. Add a short delay to avoid spam

MicroPython code:

# Microproject 3.7.1 – Init Bluetooth and read joystick buttons A–F

import ble_peripheral                              # Load Bluetooth peripheral helper
import machine                                      # Load hardware pin library
import time                                         # Load time library for delays

ble_p = ble_peripheral.BLESimplePeripheral('Clu-Bots')  # Create peripheral named 'Clu-Bots'
print("[Init] Bluetooth peripheral 'Clu-Bots'")          # Serial: confirm Bluetooth init

pin26 = machine.Pin(26, machine.Pin.IN, machine.Pin.PULL_UP)  # Button A (active LOW)
pin25 = machine.Pin(25, machine.Pin.IN, machine.Pin.PULL_UP)  # Button B (active LOW)
pin17 = machine.Pin(17, machine.Pin.IN, machine.Pin.PULL_UP)  # Button C (active LOW)
pin16 = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_UP)  # Button D (active LOW)
pin27 = machine.Pin(27, machine.Pin.IN, machine.Pin.PULL_UP)  # Button E (active LOW)
pin14 = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_UP)  # Button F (active LOW)
print("[Init] Buttons A=26 B=25 C=17 D=16 E=27 F=14")          # Serial: confirm pins

while True:                                                   # Start continuous input loop
    if pin26.value() == 0:                                    # If A pressed (LOW)
        print("[Btn] A pressed")                              # Serial: log press
        time.sleep_ms(200)                                    # Debounce delay
    if pin25.value() == 0:                                    # If B pressed (LOW)
        print("[Btn] B pressed")                              # Serial: log press
        time.sleep_ms(200)                                    # Debounce delay
    if pin17.value() == 0:                                    # If C pressed (LOW)
        print("[Btn] C pressed")                              # Serial: log press
        time.sleep_ms(200)                                    # Debounce delay
    if pin16.value() == 0:                                    # If D pressed (LOW)
        print("[Btn] D pressed")                              # Serial: log press
        time.sleep_ms(200)                                    # Debounce delay
    if pin27.value() == 0:                                    # If E pressed (LOW)
        print("[Btn] E pressed")                              # Serial: log press
        time.sleep_ms(200)                                    # Debounce delay
    if pin14.value() == 0:                                    # If F pressed (LOW)
        print("[Btn] F pressed")                              # Serial: log press
        time.sleep_ms(200)                                    # Debounce delay

Reflection: You prepared the wireless device and confirmed each button responds.
Challenge:

  • Easy: Change the debounce to 150 ms for faster feedback.
  • Harder: Print a single line only once per press (ignore holding).

🎮 Microproject 3.7.2 – Define send_text() and send labels

Goal: Create a helper to send text and use A–F to send labels like PLAY, STOP.

Blocks used:

  • def function: send_text(msg)
  • Bluetooth peripheral: Send text
  • Serial print: Confirm sending

Block sequence:

  1. Define send_text(msg)
  2. Map A–F to strings (PLAY, STOP, NEXT, PREV, VOL+, VOL−)
  3. Send mapped text on press
  4. Debounce

MicroPython code:

# Microproject 3.7.2 – Send hotkey labels over Bluetooth

import ble_peripheral                              # Load Bluetooth peripheral helper
import machine                                      # Load hardware pin library
import time                                         # Load time library

ble_p = ble_peripheral.BLESimplePeripheral('Clu-Bots')  # Create peripheral named 'Clu-Bots'
print("[Init] Peripheral 'Clu-Bots' active")            # Serial: confirm Bluetooth init

pin26 = machine.Pin(26, machine.Pin.IN, machine.Pin.PULL_UP)  # A
pin25 = machine.Pin(25, machine.Pin.IN, machine.Pin.PULL_UP)  # B
pin17 = machine.Pin(17, machine.Pin.IN, machine.Pin.PULL_UP)  # C
pin16 = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_UP)  # D
pin27 = machine.Pin(27, machine.Pin.IN, machine.Pin.PULL_UP)  # E
pin14 = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_UP)  # F
print("[Init] Buttons ready (A–F)")                            # Serial: confirm pins

def send_text(msg):                                           # Define helper to send text
    # msg: string to transmit to the connected PC
    ble_p.send(msg)                                           # Send Bluetooth text
    print("[Send] TX:", msg)                                  # Serial: confirm the send

while True:                                                   # Hotkey loop
    if pin26.value() == 0:                                    # If A pressed
        send_text("PLAY")                                     # Send PLAY label
        time.sleep_ms(200)                                    # Debounce delay
    if pin25.value() == 0:                                    # If B pressed
        send_text("STOP")                                     # Send STOP label
        time.sleep_ms(200)                                    # Debounce delay
    if pin17.value() == 0:                                    # If C pressed
        send_text("NEXT")                                     # Send NEXT label
        time.sleep_ms(200)                                    # Debounce delay
    if pin16.value() == 0:                                    # If D pressed
        send_text("PREV")                                     # Send PREV label
        time.sleep_ms(200)                                    # Debounce delay
    if pin27.value() == 0:                                    # If E pressed
        send_text("VOL+")                                     # Send VOL+ label
        time.sleep_ms(200)                                    # Debounce delay
    if pin14.value() == 0:                                    # If F pressed
        send_text("VOL-")                                     # Send VOL- label
        time.sleep_ms(200)                                    # Debounce delay

Reflection: One press now sends a clear message — you’ve built a tiny Bluetooth remote.
Challenge:

  • Easy: Swap PLAY/STOP to match your habits.
  • Harder: Add “MUTE” when pressing E and F together (combo detection).

🎮 Microproject 3.7.3 – Map helper: map_button() before sending

Goal: Define map_button(code) that returns a label; keep send_text() clean.

Blocks used:

  • def function: map_button(code)
  • Variable: Use strings for actions
  • Serial print: Trace mapping

Block sequence:

  1. Create map_button(code) for A–F
  2. If a label exists, send it
  3. If unknown, send “ERROR:UNKNOWN”
  4. Debounce

MicroPython code:

# Microproject 3.7.3 – Map buttons to labels using a helper

import ble_peripheral                              # Load Bluetooth peripheral helper
import machine                                      # Load hardware pin library
import time                                         # Load time library

ble_p = ble_peripheral.BLESimplePeripheral('Clu-Bots')  # Create peripheral
print("[Init] Bluetooth 'Clu-Bots'")                    # Serial: init status

pin26 = machine.Pin(26, machine.Pin.IN, machine.Pin.PULL_UP)  # A
pin25 = machine.Pin(25, machine.Pin.IN, machine.Pin.PULL_UP)  # B
pin17 = machine.Pin(17, machine.Pin.IN, machine.Pin.PULL_UP)  # C
pin16 = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_UP)  # D
pin27 = machine.Pin(27, machine.Pin.IN, machine.Pin.PULL_UP)  # E
pin14 = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_UP)  # F
print("[Init] Buttons A–F ready")                            # Serial: pins ready

def send_text(msg):                                         # Helper: send text
    ble_p.send(msg)                                         # Send message
    print("[Send] TX:", msg)                                # Serial: log

def map_button(btn):                                       # Helper: map button to label
    # btn: string like 'A','B','C','D','E','F'
    if btn == 'A':                                         # If A
        return "PLAY"                                      # Map to PLAY
    elif btn == 'B':                                       # If B
        return "STOP"                                      # Map to STOP
    elif btn == 'C':                                       # If C
        return "NEXT"                                      # Map to NEXT
    elif btn == 'D':                                       # If D
        return "PREV"                                      # Map to PREV
    elif btn == 'E':                                       # If E
        return "VOL+"                                      # Map to VOL+
    elif btn == 'F':                                       # If F
        return "VOL-"                                      # Map to VOL-
    else:                                                  # If unknown symbol
        return "ERROR:UNKNOWN"                             # Return error label

while True:                                                # Main loop
    if pin26.value() == 0:                                 # If A pressed
        send_text(map_button('A'))                         # Map then send
        time.sleep_ms(200)                                 # Debounce
    if pin25.value() == 0:                                 # If B pressed
        send_text(map_button('B'))                         # Map then send
        time.sleep_ms(200)                                 # Debounce
    if pin17.value() == 0:                                 # If C pressed
        send_text(map_button('C'))                         # Map then send
        time.sleep_ms(200)                                 # Debounce
    if pin16.value() == 0:                                 # If D pressed
        send_text(map_button('D'))                         # Map then send
        time.sleep_ms(200)                                 # Debounce
    if pin27.value() == 0:                                 # If E pressed
        send_text(map_button('E'))                         # Map then send
        time.sleep_ms(200)                                 # Debounce
    if pin14.value() == 0:                                 # If F pressed
        send_text(map_button('F'))                         # Map then send
        time.sleep_ms(200)                                 # Debounce

Reflection: Separating mapping from sending makes your code easy to change later.
Challenge:

  • Easy: Change C to “SCROLL DOWN” and D to “SCROLL UP”.
  • Harder: Add a second mapping profile and switch with a long press on A.

🎮 Microproject 3.7.4 – Receive callback and PC feedback

Goal: Register a receive callback to show PC responses like “ACK” or “MODE:MEDIA”.

Blocks used:

  • Callback (receive): handle_method(msg)
  • def function: log_rx(msg)
  • Serial print: Clear logs

Block sequence:

  1. Create ble handle and register callback
  2. Define log_rx(msg) to format incoming messages
  3. Blink activity LED when something arrives (Pin 13)
  4. Keep sending labels on button press

MicroPython code:

# Microproject 3.7.4 – Show PC feedback via Bluetooth receive callback

import ble_peripheral                              # Load Bluetooth peripheral helper
import ble_handle                                  # Load Bluetooth callback handle
import machine                                      # Load hardware pin library
import time                                         # Load time library

ble_p = ble_peripheral.BLESimplePeripheral('Clu-Bots')  # Create peripheral
print("[Init] Bluetooth 'Clu-Bots' active")             # Serial: init status

handle = ble_handle.Handle()                             # Create callback handle
print("[Init] Handle ready")                             # Serial: handle status

pin13 = machine.Pin(13, machine.Pin.OUT)                 # LED output for activity
print("[Init] LED on Pin 13")                            # Serial: LED status

pin26 = machine.Pin(26, machine.Pin.IN, machine.Pin.PULL_UP)  # A
pin25 = machine.Pin(25, machine.Pin.IN, machine.Pin.PULL_UP)  # B
pin17 = machine.Pin(17, machine.Pin.IN, machine.Pin.PULL_UP)  # C
pin16 = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_UP)  # D
pin27 = machine.Pin(27, machine.Pin.IN, machine.Pin.PULL_UP)  # E
pin14 = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_UP)  # F
print("[Init] Buttons A–F configured")                       # Serial: pins ready

def send_text(msg):                                         # Helper: send text
    ble_p.send(msg)                                         # Send over Bluetooth
    print("[Send] TX:", msg)                                # Serial: log send

def log_rx(msg):                                            # Helper: log receives
    print("[Recv] RX:", msg)                                # Serial: show incoming
    pin13.value(1)                                          # LED ON on activity
    time.sleep_ms(80)                                       # Short blink
    pin13.value(0)                                          # LED OFF

def handle_method(msg):                                     # Callback: on receive
    log_rx(msg)                                             # Format and blink LED

handle.recv(handle_method)                                  # Register the callback
print("[BT] Callback registered")                           # Serial: confirm callback

while True:                                                 # Main loop: send on press
    if pin26.value() == 0:                                  # If A pressed
        send_text("PLAY")                                   # Send PLAY
        time.sleep_ms(200)                                  # Debounce
    if pin25.value() == 0:                                  # If B pressed
        send_text("STOP")                                   # Send STOP
        time.sleep_ms(200)                                  # Debounce
    if pin17.value() == 0:                                  # If C pressed
        send_text("NEXT")                                   # Send NEXT
        time.sleep_ms(200)                                  # Debounce
    if pin16.value() == 0:                                  # If D pressed
        send_text("PREV")                                   # Send PREV
        time.sleep_ms(200)                                  # Debounce
    if pin27.value() == 0:                                  # If E pressed
        send_text("VOL+")                                   # Send VOL+
        time.sleep_ms(200)                                  # Debounce
    if pin14.value() == 0:                                  # If F pressed
        send_text("VOL-")                                   # Send VOL-
        time.sleep_ms(200)                                  # Debounce

Reflection: Seeing “ACK” from the PC makes the remote feel responsive and alive.
Challenge:

  • Easy: Blink twice for “ACK” and once for everything else.
  • Harder: Print “MODE:MEDIA” differently (e.g., prepend “[Mode] ”).

🎮 Microproject 3.7.5 – Profile switch: media vs. slides

Goal: Use E to toggle profile (MEDIA/SLIDES) and re‑map labels automatically.

Blocks used:

  • def function: get_label(btn, profile)
  • Variable: profile state (“MEDIA” or “SLIDES”)
  • Serial print: Show profile changes

Block sequence:

  1. Start profile = MEDIA
  2. If E pressed, toggle profile
  3. Map A–F using get_label(btn, profile)
  4. Send mapped label

MicroPython code:

# Microproject 3.7.5 – Toggle hotkey profile (MEDIA ↔ SLIDES)

import ble_peripheral                              # Load Bluetooth peripheral helper
import machine                                      # Load hardware pin library
import time                                         # Load time library

ble_p = ble_peripheral.BLESimplePeripheral('Clu-Bots')  # Create peripheral
print("[Init] Bluetooth 'Clu-Bots'")                    # Serial: init

pin26 = machine.Pin(26, machine.Pin.IN, machine.Pin.PULL_UP)  # A
pin25 = machine.Pin(25, machine.Pin.IN, machine.Pin.PULL_UP)  # B
pin17 = machine.Pin(17, machine.Pin.IN, machine.Pin.PULL_UP)  # C
pin16 = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_UP)  # D
pin27 = machine.Pin(27, machine.Pin.IN, machine.Pin.PULL_UP)  # E (toggle)
pin14 = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_UP)  # F
print("[Init] Buttons set (E toggles profile)")               # Serial: pins ready

def send_text(msg):                                           # Helper: send text
    ble_p.send(msg)                                           # Send message
    print("[Send] TX:", msg)                                  # Serial: confirm

def get_label(btn, profile):                                  # Helper: map per profile
    # btn: 'A'..'F', profile: 'MEDIA' or 'SLIDES'
    if profile == 'MEDIA':                                    # If MEDIA profile
        if btn == 'A': return "PLAY"                          # Map A to PLAY
        if btn == 'B': return "STOP"                          # Map B to STOP
        if btn == 'C': return "NEXT"                          # Map C to NEXT
        if btn == 'D': return "PREV"                          # Map D to PREV
        if btn == 'E': return "VOL+"                          # Map E to VOL+
        if btn == 'F': return "VOL-"                          # Map F to VOL-
    else:                                                     # Else SLIDES profile
        if btn == 'A': return "SLIDE_NEXT"                    # Map A to next slide
        if btn == 'B': return "SLIDE_PREV"                    # Map B to previous slide
        if btn == 'C': return "POINTER_ON"                    # Map C to pointer on
        if btn == 'D': return "POINTER_OFF"                   # Map D to pointer off
        if btn == 'E': return "BLANK_SCREEN"                  # Map E to blank screen
        if btn == 'F': return "UNBLANK_SCREEN"                # Map F to unblank
    return "ERROR:UNKNOWN"                                    # Default if unmapped

profile = 'MEDIA'                                            # Start in MEDIA
print("[Profile] MEDIA")                                     # Serial: profile status

while True:                                                  # Profile loop
    if pin27.value() == 0:                                   # If E pressed (toggle)
        profile = 'SLIDES' if profile == 'MEDIA' else 'MEDIA'# Toggle profile
        send_text("MODE:" + profile)                         # Send mode change
        print("[Profile] Switched to", profile)              # Serial: show change
        time.sleep_ms(250)                                   # Debounce delay
    if pin26.value() == 0:                                   # If A pressed
        send_text(get_label('A', profile))                   # Send mapped label
        time.sleep_ms(200)                                   # Debounce delay
    if pin25.value() == 0:                                   # If B pressed
        send_text(get_label('B', profile))                   # Send mapped label
        time.sleep_ms(200)                                   # Debounce delay
    if pin17.value() == 0:                                   # If C pressed
        send_text(get_label('C', profile))                   # Send mapped label
        time.sleep_ms(200)                                   # Debounce delay
    if pin16.value() == 0:                                   # If D pressed
        send_text(get_label('D', profile))                   # Send mapped label
        time.sleep_ms(200)                                   # Debounce delay
    if pin14.value() == 0:                                   # If F pressed
        send_text(get_label('F', profile))                   # Send mapped label
        time.sleep_ms(200)                                   # Debounce delay

Reflection: A single toggle key switches your remote’s personality — powerful and simple.
Challenge:

  • Easy: Announce the profile on the LCD (Project 3.3) when it changes.
  • Harder: Add long‑press on E to reset to MEDIA after 2 seconds.

✨ Main project – Joystick buttons as Bluetooth hotkeys to PC

🔧 Blocks steps (with glossary)

  • Bluetooth peripheral: Advertise as “Clu‑Bots” and send text
  • Digital input (pull‑up): Read A–F presses
  • def function: send_text(), map_button(), get_label()
  • Callback (receive): Log PC feedback and blink LED
  • Serial print: Keep short, clear status logs

Block sequence:

  1. Setup Bluetooth peripheral and callback handle; prepare LED (Pin 13).
  2. Configure A–F inputs; define send_text() and get_label().
  3. Loop: toggle profile with E; send mapped labels on A/B/C/D/F.
  4. Log received messages and blink LED for activity.
  5. Keep debounce delays for friendly UX.

🐍 MicroPython code (mirroring blocks)

# Project 3.7 – Joystick Buttons → Bluetooth Hotkeys → PC

import ble_peripheral                              # Load Bluetooth peripheral helper
import ble_handle                                  # Load Bluetooth callback handle
import machine                                      # Load hardware pin library
import time                                         # Load time library

ble_p = ble_peripheral.BLESimplePeripheral('Clu-Bots')  # Create Bluetooth peripheral
print("[Init] Peripheral 'Clu-Bots'")                    # Serial: peripheral active

handle = ble_handle.Handle()                              # Create callback handle
print("[Init] Handle ready")                              # Serial: handle active

pin13 = machine.Pin(13, machine.Pin.OUT)                  # Activity LED on Pin 13
print("[Init] LED=13")                                    # Serial: LED init

pin26 = machine.Pin(26, machine.Pin.IN, machine.Pin.PULL_UP)  # Button A
pin25 = machine.Pin(25, machine.Pin.IN, machine.Pin.PULL_UP)  # Button B
pin17 = machine.Pin(17, machine.Pin.IN, machine.Pin.PULL_UP)  # Button C
pin16 = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_UP)  # Button D
pin27 = machine.Pin(27, machine.Pin.IN, machine.Pin.PULL_UP)  # Button E (toggle)
pin14 = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_UP)  # Button F
print("[Init] Buttons A=26 B=25 C=17 D=16 E=27 F=14")          # Serial: confirm pins

def send_text(msg):                                           # Helper: send text
    ble_p.send(msg)                                           # Bluetooth send
    print("[Send] TX:", msg)                                  # Serial: show send

def get_label(btn, profile):                                  # Helper: map per profile
    if profile == 'MEDIA':                                    # If MEDIA
        if btn == 'A': return "PLAY"                          # A → PLAY
        if btn == 'B': return "STOP"                          # B → STOP
        if btn == 'C': return "NEXT"                          # C → NEXT
        if btn == 'D': return "PREV"                          # D → PREV
        if btn == 'E': return "VOL+"                          # E → VOL+
        if btn == 'F': return "VOL-"                          # F → VOL-
    else:                                                     # If SLIDES
        if btn == 'A': return "SLIDE_NEXT"                    # A → next slide
        if btn == 'B': return "SLIDE_PREV"                    # B → prev slide
        if btn == 'C': return "POINTER_ON"                    # C → pointer on
        if btn == 'D': return "POINTER_OFF"                   # D → pointer off
        if btn == 'E': return "BLANK_SCREEN"                  # E → blank
        if btn == 'F': return "UNBLANK_SCREEN"                # F → unblank
    return "ERROR:UNKNOWN"                                    # Default mapping

def handle_method(msg):                                       # Callback: on receive
    print("[Recv] RX:", msg)                                  # Serial: show incoming
    pin13.value(1)                                            # LED ON (activity)
    time.sleep_ms(80)                                         # Short blink
    pin13.value(0)                                            # LED OFF

handle.recv(handle_method)                                    # Register callback
print("[BT] Callback registered")                             # Serial: callback active

profile = 'MEDIA'                                             # Start profile
print("[Profile] MEDIA")                                      # Serial: initial profile

while True:                                                   # Main hotkey loop
    if pin27.value() == 0:                                    # If E pressed (toggle)
        profile = 'SLIDES' if profile == 'MEDIA' else 'MEDIA' # Toggle profile state
        send_text("MODE:" + profile)                          # Inform PC of mode change
        print("[Profile] Switched to", profile)               # Serial: show change
        time.sleep_ms(250)                                    # Debounce delay
    if pin26.value() == 0:                                    # If A pressed
        send_text(get_label('A', profile))                    # Send mapped label
        time.sleep_ms(200)                                    # Debounce delay
    if pin25.value() == 0:                                    # If B pressed
        send_text(get_label('B', profile))                    # Send mapped label
        time.sleep_ms(200)                                    # Debounce delay
    if pin17.value() == 0:                                    # If C pressed
        send_text(get_label('C', profile))                    # Send mapped label
        time.sleep_ms(200)                                    # Debounce delay
    if pin16.value() == 0:                                    # If D pressed
        send_text(get_label('D', profile))                    # Send mapped label
        time.sleep_ms(200)                                    # Debounce delay
    if pin14.value() == 0:                                    # If F pressed
        send_text(get_label('F', profile))                    # Send mapped label
        time.sleep_ms(200)                                    # Debounce delay

📖 External explanation

  • What it teaches: Turning simple button presses into Bluetooth hotkeys with clean helper functions and profiles.
  • Why it works: Pull‑up buttons give reliable digital events; the Bluetooth peripheral sends short text labels; the PC app interprets them.
  • Key concept: Define helpers first (map, send, callback), then use them in a simple loop for clarity and reuse.

✨ Story time

Your joystick just became a wireless remote. One press says “PLAY,” another says “NEXT,” and with a toggle, it transforms into a slide‑show controller.


🕵️ Debugging (2)

🐞 Debugging 3.7.A – Button holds send multiple times

Problem: Holding a button repeats messages too fast.
Clues: Serial shows many “[Send] TX: …” lines for one long press.

Broken code:

if pin26.value() == 0:
    send_text("PLAY")  # No debounce or edge detection

Fixed code:

if pin26.value() == 0:               # Detect press
    send_text("PLAY")                # Send once
    time.sleep_ms(250)               # Debounce to avoid repeats

Why it works: A short delay prevents repeated sends while the button is held.
Avoid next time: Add debounce or design for “press” events instead of “hold”.


🐞 Debugging 3.7.B – No feedback from PC

Problem: Sends appear, but “[Recv] RX: …” never shows.
Clues: PC not connected or app not reading messages.

Broken code:

# Forgot to register the receive callback
# handle.recv(handle_method)

Fixed code:

handle.recv(handle_method)           # Register callback early
print("[BT] Callback registered")    # Confirm registration

Why it works: Without a callback, received messages are ignored; registering it enables feedback.


✅ Final checklist

  • Bluetooth advertises as “Clu‑Bots”
  • Buttons A–F send mapped labels to the PC
  • Profile toggles with E and re‑maps labels
  • LED blinks on received messages
  • Debounce delays keep sends readable and friendly

📚 Extras

  • 🧠 Student tip: Keep messages short and consistent (PLAY, STOP, NEXT).
  • 🧑‍🏫 Instructor tip: Demonstrate pairing in OS, then use a simple BLE terminal app to view labels.
  • 📖 Glossary:
    • Pull‑up: Input default HIGH; press pulls LOW.
    • Peripheral: Device that advertises and sends data.
    • Profile: A mapping set (MEDIA vs. SLIDES) for buttons.
  • 💡 Mini tips:
    • Use 200–250 ms debounce to reduce repeats.
    • Announce mode changes with “MODE:…”.
    • Keep the board within 1–3 meters for reliable Bluetooth.
On this page