Files
Amirine_Cosplay_Lights/arduino/cosplay_lights/cosplay_lights.ino
T
bgrolleman a96f378c9c Add triple-tap lights-off and fix LED pin to D5
- Triple tap turns off LEDs; any subsequent tap or hold resumes the current show
- Change LED_DATA_PIN default from 6 to 5 across config, docs, and wiring diagram
- Fix Makefile upload to pass --input-dir so it uses the pre-built binary

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 13:20:36 +02:00

105 lines
3.3 KiB
Arduino
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Amirine Cosplay Lights
*
* Plays lightshows defined in shows.h on a WS2812B LED strip.
* A single button navigates between shows:
* 1 tap — next show
* 2 taps — previous show
* 3 taps — lights off (any tap or hold resumes)
* hold — reset to show 0 (blue breath)
*
* To add or update shows:
* 1. Add or edit a .txt file in converter/shows/
* 2. Run: make shows
* 3. Run: make upload
*
* Required libraries: FastLED, OneButton (Sketch > Include Library > Manage Libraries)
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <OneButton.h>
#include "config.h"
#include "led_controller.h"
#include "shows.h"
// ---- Playback state ----------------------------------------------------
static uint8_t s_show_index = 0;
static ShowDef s_show; // PROGMEM cache for the active show
static uint16_t s_step_index = 0;
static uint32_t s_step_start = 0;
static CRGB s_from_color = CRGB::Black;
static bool s_lights_off = false;
static void load_show(uint8_t index) {
s_lights_off = false;
s_show_index = index;
s_show = read_show_def(&SHOWS[index]);
s_step_index = 0;
s_step_start = millis();
s_from_color = CRGB::Black;
}
// How far through the current step we are (0255).
// Returns 255 immediately for instant steps (duration_ms == 0).
static uint8_t step_progress(const Step& step, uint32_t now) {
if (step.duration_ms == 0) return 255;
uint32_t elapsed = now - s_step_start;
if (elapsed >= step.duration_ms) return 255;
return (uint8_t)((elapsed * 255UL) / step.duration_ms);
}
// Complete the current step and advance to the next.
// SHOW_LOOP wraps back to step 0; SHOW_SINGLE loads the next show when the last step ends.
static void advance_step(CRGB reached_color, uint32_t now) {
s_from_color = reached_color;
uint16_t next = s_step_index + 1;
if (next >= s_show.length) {
if (s_show.mode == SHOW_SINGLE) {
load_show((s_show_index + 1) % SHOW_COUNT);
return;
}
next = 0;
}
s_step_index = next;
s_step_start = now;
}
// ---- Button ------------------------------------------------------------
static OneButton s_button(BUTTON_PIN, true, true); // active-low, enable pullup
// ---- Arduino entry points ----------------------------------------------
void setup() {
leds_begin();
load_show(0);
s_button.setClickMs(400);
s_button.setPressMs(800);
s_button.attachClick([]() { load_show((s_show_index + 1) % SHOW_COUNT); });
s_button.attachDoubleClick([]() { load_show((s_show_index + SHOW_COUNT - 1) % SHOW_COUNT); });
s_button.attachMultiClick([]() { if (s_button.getNumberClicks() == 3) { s_lights_off = true; leds_apply_color(CRGB::Black); leds_show(); } });
s_button.attachLongPressStart([]() { load_show(0); });
}
void loop() {
s_button.tick();
static uint32_t s_last_frame = 0;
uint32_t now = millis();
if (now - s_last_frame < 16) return;
s_last_frame = now;
if (s_lights_off) return;
Step step = read_step(&s_show.steps[s_step_index]);
CRGB to = CRGB(step.r, step.g, step.b);
uint8_t t8 = step_progress(step, now);
leds_apply_color(blend(s_from_color, to, t8));
leds_show();
if (t8 == 255) advance_step(to, now);
}