kitesurfer1404 / WS2812FX

WS2812 FX Library for Arduino and ESP8266
MIT License
1.59k stars 346 forks source link

Using segment runtime in custom mode #349

Closed kaysond closed 7 months ago

kaysond commented 7 months ago

I'm trying to create a custom mode that is the same as breath, except it does it once as one color, then switches to another color, repeat. So my first attempt is to essentially copy mode_breathbut grab segment info from the public segment/runtime getters. Unfortunately, I get a static dim color, and no animation. It seems like counter_mode_step is getting reset by something, but I couldn't figure out what.

What am I doing wrong here? Or maybe there's an entirely better way entirely to do this? TIA.

bool alternate = false;

uint16_t alternating_breath(void)
{
  WS2812FX::Segment *seg = ws2812fx.getSegment();
  WS2812FX::Segment_runtime *seg_rt = ws2812fx.getSegmentRuntime();
  int lum = seg_rt->counter_mode_step;
  if (lum > 255)
    lum = 511 - lum; // lum = 15 -> 255 -> 15

  uint16_t delay;
  if (lum == 15)
    delay = 970; // 970 pause before each breath
  else if (lum <= 25)
    delay = 38; // 19
  else if (lum <= 50)
    delay = 36; // 18
  else if (lum <= 75)
    delay = 28; // 14
  else if (lum <= 100)
    delay = 20; // 10
  else if (lum <= 125)
    delay = 14; // 7
  else if (lum <= 150)
    delay = 11; // 5
  else
    delay = 10; // 4

  ws2812fx.setBrightness(lum);
  for (uint16_t i = seg->start; i < seg->stop; i++)
  {
    if (alternate)
      ws2812fx.setPixelColor(i, seg->colors[1]);
    else
      ws2812fx.setPixelColor(i, seg->colors[0]);
  }

  seg_rt->counter_mode_step += 2;
  if (seg_rt->counter_mode_step > (512 - 15))
  {
    seg_rt->counter_mode_step = 15;
    seg_rt->aux_param2 |= CYCLE;
  }
  return delay;
}
moose4lord commented 7 months ago

Hmmmm...I don't see where you're blending colors to create the fading effect in your code. Like this line in the WS2812FX::mode_breath(void) function:

uint32_t color =  color_blend(_seg->colors[1], _seg->colors[0], lum);

I would take a different tack. Instead of creating a custom effect, I think I'd use the isCycle() function to detect the end of the breath animation cycle and change color at that point in time. Like this:

void loop() {
  ws2812fx.service();

  if(ws2812fx.getMode() == FX_MODE_BREATH) {
    if(ws2812fx.isCycle()) {  // if end of breath cycle, change color
      uint32_t newColor = ws2812fx.color_wheel(ws2812fx.random8());  // some random color
      ws2812fx.setColor(newColor);
    }
  }
}
kaysond commented 7 months ago

I don't see where you're blending colors

I was wondering why that was there... I thought its a one-color effect so I just set the one color and dimmed using setBrightness, assuming that color_blend effectively does the same thing if the second color is 0.

I think I'd use the isCycle()

I don't think that will quite work the way I want because it'll instantly swap between the two colors at the end of the cycle, right? Because there's the pause in breath. I want to make it fade to nothing before switching colors so there's no instant color switch.

moose4lord commented 7 months ago

One thing you can do if you want to fade to black is to turn on Gamma Correction. when you setup the segment. Gamma correction will skew dim colors dimmer and bright colors brighter. Very dIm colors will be black. It's a bit of a hack, but might give you want you want.

ws2812fx.setSegment(0,  0,  LED_COUNT - 1, FX_MODE_BREATH, RED, 1000, GAMMA);

Otherwise, I think you're right, you'll have to develop a custom effect.

kaysond commented 7 months ago

So the gamma didn't work, but turns out my issue was that I didn't know you have to do both setCustomMode() and setMode(FX_MODE_CUSTOM). Now I've got it working!