dance_party module
Dance Party Routine - Multi-UFO Synchronized Light Show via BLE.
This module implements a synchronized dance party routine where multiple Circuit Playground Bluefruit devices can synchronize their NeoPixel displays over Bluetooth Low Energy (BLE) using advertisement names as the communication protocol.
- The routine supports two roles:
Leader: Audio-reactive display with beat detection (Mode 1)
Follower: Mirrors leader’s display in real-time (Modes 2-4)
- Protocol Format:
ILLO_<seq>_<pos1>_<int1>_<col1>_<pos2>_<int2>_<col2>_<pos3>_<int3>_<col3>
Example
>>> from dance_party import DanceParty
>>> dance = DanceParty("ILLO_01", debug_bluetooth=True)
>>> dance.run(mode=1, volume=1) # Leader mode with audio (volume: 0=off, 1=on)
- Author:
Charles Doebler — Feral Cat AI
- Dependencies:
adafruit_circuitplayground
adafruit_ble
audio_processor (optional)
Note
The “volume” parameter throughout this module is a sound enable flag (0=off, 1=on) rather than an actual volume control, since the Circuit Playground Bluefruit piezo speaker has no volume adjustment capability. The naming is maintained for consistency with the hardware switch and other routines.
- class dance_party.DanceParty(device_name, debug_bluetooth=False, debug_audio=False)
Bases:
BaseRoutineLeader/follower visual synchronization over BLE advertisement names.
This class implements a synchronized light show routine where one device acts as a leader (audio-reactive) and others follow by mirroring the leader’s display.
- The visual display consists of three pixels that form an animated baton:
Head pixel: Full intensity at current position
Trail1: 55% intensity, follows head by 1 step
Trail2/Spark: Temporary beat effect at 75% intensity
- Audio processing features (leader mode):
Two-stage smoothing prevents visual jitter
Hysteretic color switching prevents rapid flickering
Beat detection triggers direction changes and visual effects
- device_name
BLE device identifier
- Type:
str
- debug_bluetooth
Enable verbose BLE debugging output
- Type:
bool
- debug_audio
Enable verbose audio processing output
- Type:
bool
- sync_enabled
Whether BLE sync is enabled via config
- Type:
bool
- sync_active
Whether BLE is currently initialized and active
- Type:
bool
- ble
BLE radio instance (None if not initialized)
- Type:
BLERadio
- Class Attributes:
_NUM_PIXELS (int): Number of NeoPixels on the device (10) _BRIGHTNESS (float): Global brightness setting (0.0-1.0) _STEP_MS (int): Time between position updates in milliseconds _ADV_PERIOD_MS (int): BLE advertisement refresh rate in milliseconds _SCAN_BURST_S (float): Follower scan duration in seconds _LOSS_TIMEOUT_S (float): Follower timeout before declaring leader lost _MIN_RENDER_MS (int): Minimum time between render updates (rate limiting) _SMOOTH_ALPHA (float): Exponential smoothing factor for follower (0.0-1.0)
Example
>>> # Leader mode with debugging >>> leader = DanceParty("LEADER_01", debug_bluetooth=True, debug_audio=True) >>> leader.run(mode=1, volume=1) # volume: 0=off, 1=on
>>> # Follower mode >>> follower = DanceParty("FOLLOWER_02") >>> follower.run(mode=2, volume=0) # silent follower
Note
Mode 1 is always Leader
Modes 2-4 are always Follower (safe default for undefined modes)
Follower mode ignores audio input and mirrors leader visuals
Volume parameter is a sound on/off flag, not actual volume control
- cleanup()
Clean shutdown of Dance Party resources.
Called by code.py when switching routines. Stops all BLE operations, clears NeoPixel display, and reports cleanup status if debugging.
Note
Safe to call multiple times
Catches and logs all exceptions during cleanup
Always attempts to clear pixels even if BLE cleanup fails
- enable_bluetooth()
Enable Bluetooth if not already active.
- Returns:
True if BLE is active after call, False otherwise
- Return type:
bool
Note
This method is called by code.py to enable BLE dynamically. Safe to call multiple times - idempotent operation.
- get_debug_status()
Return current status for debugging and monitoring.
- Returns:
- Status dictionary with the following keys:
sync_active (bool): Whether BLE is initialized
seq (int): Current sequence number
free_memory (int): Available memory in bytes
sync_success (int): Successful sync count (follower)
sync_fail (int): Failed sync count (follower)
last_seen_age (float): Seconds since last leader packet (follower)
- Return type:
dict
Example
>>> dance = DanceParty("ILLO_01") >>> status = dance.get_debug_status() >>> print(status['free_memory']) 45632
- run(mode, volume)
Main execution loop for Dance Party routine.
- Parameters:
mode (int) – Determines role. 1=Leader, 2-4=Follower (safe default)
volume (int) – Sound enable flag (0=off, 1=on). Note: Called “volume” for consistency with hardware switch, but acts as boolean since piezo speaker has no actual volume control. Passed to audio processor for compatibility with other routines.
Note
Called repeatedly by main event loop in code.py
Leader mode: Draws audio-reactive visuals and broadcasts via BLE
Follower mode: Scans for leader and mirrors received visuals
Falls back to local audio visualization if BLE unavailable
Example
>>> dance = DanceParty("ILLO_01") >>> while True: ... dance.run(mode=1, volume=1) # Leader with audio (sound enabled)
- set_custom_responsiveness(adv_period_ms, smooth_alpha)
Set custom responsiveness parameters.
- Parameters:
adv_period_ms (int) – Advertisement period in milliseconds (50-200)
smooth_alpha (float) – Smoothing factor 0.0-1.0 (higher = snappier)
- Returns:
True if parameters were valid and applied
- Return type:
bool
Example
>>> dance = DanceParty("ILLO_01") >>> dance.set_custom_responsiveness(60, 0.92) # Custom tuning
- set_responsiveness(mode='balanced')
Adjust synchronization responsiveness with preset modes.
- Parameters:
mode (str) – One of “fast”, “balanced”, or “smooth” - “fast”: Maximum responsiveness (50ms ads, 0.95 alpha) - “balanced”: Good balance (80ms ads, 0.90 alpha) [DEFAULT] - “smooth”: Smoother motion (120ms ads, 0.70 alpha)
- Returns:
True if mode was applied successfully
- Return type:
bool
Example
>>> dance = DanceParty("ILLO_01") >>> dance.set_responsiveness("fast") # Maximum responsiveness >>> dance.set_responsiveness("smooth") # Battery-saving smooth mode