kitesurfer1404 / WS2812FX

WS2812 FX Library for Arduino and ESP8266
MIT License
1.58k stars 344 forks source link

Switching patterns by button presses #262

Closed neopolygnath closed 3 years ago

neopolygnath commented 3 years ago

Hello, found the WS2812FX library recently as I'm working on a lighting project that would require me to switch between complex segment patterns by pushing two buttons. I'm not a programmer and unsure if WS2812FX is even adaptable for my scenario. My issue: I have two to patterns with two modes that I want to modify by button presses. I'm not a programmer myself (sadly) but I try to describe what I want to achieve and maybe someone here can help me with an example or give some hints:

Pressing the first button is intended to switch between the main patterns 1 and 2. Patterns 3 and 4 are color inverted versions of the two main patterns. So pressing the second button is intended to switch between patterns 1 and 3 and 2 and 4 (depending upon the previously selected pattern). To my understanding I would have to stop, swap and then re-initialize the activated pattern by "ws2812fx.start();". Is it even technically possible with the library (or could another library be more helpful here)? My patterns look like the following:

Pattern 1:

  ws2812fx.init();
  //ws2812fx.setBrightness(200);

  // parameters: index, start, stop, mode, color, speed, reverse
  ws2812fx.setSegment(0,  0,  9, FX_MODE_FIRE_FLICKER, 0xFF0000, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.setSegment(1,  10,  19, FX_MODE_BLINK, 0xFFFFFF, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.setSegment(2,  20,  29, FX_MODE_FIRE_FLICKER, 0x00FF00, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.setSegment(3,  30,  39, FX_MODE_BLINK, 0xFFFFFF, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.setSegment(4,  40,  49, FX_MODE_FIRE_FLICKER, 0x0000FF, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.start();
}

Pattern 2:

  ws2812fx.init();
  //ws2812fx.setBrightness(200);

  // parameters: index, start, stop, mode, color, speed, reverse
  ws2812fx.setSegment(0,  0,  9, FX_MODE_BLINK, 0xFF0000, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.setSegment(1,  10,  19, FX_MODE_FIRE_FLICKER, 0xFFFFFF, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.setSegment(2,  20,  29, FX_MODE_BLINK, 0x00FF00, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.setSegment(3,  30,  39, FX_MODE_FIRE_FLICKER, 0xFFFFFF, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.setSegment(4,  40,  49, FX_MODE_BLINK, 0x0000FF, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.start();
}

Pattern 3:

 ws2812fx.init();
  //ws2812fx.setBrightness(200);

  // parameters: index, start, stop, mode, color, speed, reverse
  ws2812fx.setSegment(0,  0,  9, FX_MODE_FIRE_FLICKER, 0xFFFFFF, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.setSegment(1,  10,  19, FX_MODE_BLINK, 0xFF0000, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.setSegment(2,  20,  29, FX_MODE_FIRE_FLICKER, 0xFFFFFF, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.setSegment(3,  30,  39, FX_MODE_BLINK, 0x00FF00, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.setSegment(4,  40,  49, FX_MODE_FIRE_FLICKER, 0xFFFFFF, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.start();
}

Pattern 4:

  ws2812fx.init();
  //ws2812fx.setBrightness(200);

  // parameters: index, start, stop, mode, color, speed, reverse
  ws2812fx.setSegment(0,  0,  9, FX_MODE_BLINK, 0xFFFFFF, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.setSegment(1,  10,  19, FX_MODE_FIRE_FLICKER, 0xFF0000, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.setSegment(2,  20,  29, FX_MODE_BLINK, 0xFFFFFF, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.setSegment(3,  30,  39, FX_MODE_FIRE_FLICKER, 0x00FF00, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.setSegment(4,  40,  49, FX_MODE_BLINK, 0xFFFFFF, 1000, false); // segment 0 is leds 0 - 9
  ws2812fx.start();
}
moose4lord commented 3 years ago

Seems like you're using button1 to change the effect of each segment, and button2 to change the color of each segment. You don't need to reconfigure each segment whenever a button is pressed. You can just use setSegment() to initialize the segments, then use setMode() and setColor() to update the segments in response to a button press. This is what I came up with:

#include <WS2812FX.h>

#define LED_PIN   D2  // digital pin used to drive the LED strip
#define LED_COUNT 50  // number of LEDs on the strip

#define BUTTON1_PIN   D0 // digital pin for button 1
#define BUTTON2_PIN   D1 // digital pin for button 2

boolean button1 = HIGH; // initial state of the buttons
boolean button2 = HIGH;

boolean modeState = false;  // initial state of the effect mode
boolean colorState = false; // initial state of the color palette

WS2812FX ws2812fx = WS2812FX(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  Serial.begin(115200);
  delay(500);

  pinMode(BUTTON1_PIN, INPUT_PULLUP); // config buttons as inputs with pullup resistors
  pinMode(BUTTON2_PIN, INPUT_PULLUP);

  ws2812fx.init();
  ws2812fx.setBrightness(128);

  // parameters: index, start, stop, mode, color, speed, reverse
  ws2812fx.setSegment(0,   0,   9, FX_MODE_FIRE_FLICKER, RED,   1000, false);
  ws2812fx.setSegment(1,  10,  19, FX_MODE_BLINK,        WHITE, 1000, false);
  ws2812fx.setSegment(2,  20,  29, FX_MODE_FIRE_FLICKER, GREEN, 1000, false);
  ws2812fx.setSegment(3,  30,  39, FX_MODE_BLINK,        WHITE, 1000, false);
  ws2812fx.setSegment(4,  40,  49, FX_MODE_FIRE_FLICKER, BLUE,  1000, false);
  ws2812fx.start();
}

void loop() {
  ws2812fx.service();

  // Check button 1 (controls the effect mode)
  boolean newState = digitalRead(BUTTON1_PIN);
  if((newState == LOW) && (button1 == HIGH)) { // button 1 toggled high to low
    if(modeState) {
      ws2812fx.setMode(0, FX_MODE_FIRE_FLICKER);
      ws2812fx.setMode(1, FX_MODE_BLINK);
      ws2812fx.setMode(2, FX_MODE_FIRE_FLICKER);
      ws2812fx.setMode(3, FX_MODE_BLINK);
      ws2812fx.setMode(4, FX_MODE_FIRE_FLICKER);
    } else {
      ws2812fx.setMode(0, FX_MODE_BLINK);
      ws2812fx.setMode(1, FX_MODE_FIRE_FLICKER);
      ws2812fx.setMode(2, FX_MODE_BLINK);
      ws2812fx.setMode(3, FX_MODE_FIRE_FLICKER);
      ws2812fx.setMode(4, FX_MODE_BLINK);
    }
    modeState = !modeState;
  }
  button1 = newState;

  // Check button 2 (controls the color scheme)
  newState = digitalRead(BUTTON2_PIN);
  if((newState == LOW) && (button2 == HIGH)) { // button 2 toggled high to low
    if(colorState) {
      ws2812fx.setColor(0, RED);
      ws2812fx.setColor(1, WHITE);
      ws2812fx.setColor(2, GREEN);
      ws2812fx.setColor(3, WHITE);
      ws2812fx.setColor(4, BLUE);
    } else {
      ws2812fx.setColor(0, WHITE);
      ws2812fx.setColor(1, RED);
      ws2812fx.setColor(2, WHITE);
      ws2812fx.setColor(3, GREEN);
      ws2812fx.setColor(4, WHITE);
    }
    colorState = !colorState;
  }
  button2 = newState;
}
neopolygnath commented 3 years ago

Wow, that was fast (and it's working like a charm). Many thanks for your input and your example :-) It depicts capabilities of this library I had not even thought possible. Especially the solution to decouple the segment description from the rest and your way to set the modes and colors - that's just elegant - I raise my virtual hat to your programming skills. Thank you and best wishes