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
| Part | How many? | Pin connection (D1 R32) |
|---|---|---|
| D1 R32 | 1 | USB cable |
| Joystick Shield (buttons only) | 1 | A(26), B(25), C(17), D(16), E(27), F(14) |
| Built‑in Bluetooth | 1 | Internal (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:
- Create peripheral named “Clu‑Bots”
- Setup pins 26,25,17,16,27,14 with pull‑up
- In a loop, print which button is pressed
- 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:
- Define send_text(msg)
- Map A–F to strings (PLAY, STOP, NEXT, PREV, VOL+, VOL−)
- Send mapped text on press
- 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:
- Create map_button(code) for A–F
- If a label exists, send it
- If unknown, send “ERROR:UNKNOWN”
- 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:
- Create ble handle and register callback
- Define log_rx(msg) to format incoming messages
- Blink activity LED when something arrives (Pin 13)
- 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:
- Start profile = MEDIA
- If E pressed, toggle profile
- Map A–F using get_label(btn, profile)
- 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:
- Setup Bluetooth peripheral and callback handle; prepare LED (Pin 13).
- Configure A–F inputs; define send_text() and get_label().
- Loop: toggle profile with E; send mapped labels on A/B/C/D/F.
- Log received messages and blink LED for activity.
- 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.