Case wont change when given input. Neopixels night light

Hi I’m fairly new to Arduino, I’m trying to make a night light with different modes but when cycling through the modes by pressing in the rotary controller mode 3 won’t change to mode 4 which is off, im at a loss for why…?

any help would be very much appreciated.

#include <Encoder.h>
#include <Adafruit_NeoPixel.h>

const int NUM_LEDS = 60; // number of leds in strip
const int LED_PIN = 5; // pin for led strip
const int BRIGHTNESS = 255; // brightness of all leds
const int WHEEL_SIZE = 256; // how many entries in the color wheel
const boolean MOVE_LIGHT = false; // move one light around or keep all lights on
const int ENCODER_PIN_1 = 2;
const int ENCODER_PIN_2 = 3;
const int ENCODER_BUTTON = 4;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, LED_PIN, NEO_RGB + NEO_KHZ800);
Encoder encoder(ENCODER_PIN_1, ENCODER_PIN_2);
int mode = 0;
long lastPush = 0;
int autoPosition = 0;

void initializeToBlack() {
for (int i =0; i < NUM_LEDS; i++) {
strip.setPixelColor(i, 0);
uint32_t white = strip.Color(255, 255, 255);

}
}

void setup() {
Serial.begin(9600);
pinMode(ENCODER_BUTTON, INPUT);
digitalWrite(ENCODER_BUTTON, HIGH); //turn pullup resistor on

strip.begin();
initializeToBlack();
strip.show();
}
uint32_t white = strip.Color(255, 255, 255);
long normalize(long value, long radix) {
long rval = value % radix;
if (rval < 0) return radix + rval;
else return rval;
}

void loop() {
int button= digitalRead(ENCODER_BUTTON);
if (button == 0) {
if ((millis() - lastPush) > 250) {
lastPush = millis();
mode++;
if (mode > 4) mode = 0;
}
}
long knobValue = encoder.read() / 1;

long ledPosition = normalize(knobValue, NUM_LEDS);
long colorValue = normalize(knobValue * 5, WHEEL_SIZE);
long sleepValue = abs(knobValue) % 500;

switch(mode) {
// off
case 0: initializeToBlack();
break;

// all on, White
case 1: for (int i =0; i < NUM_LEDS; i++) {
strip.fill(white, 0, 60);
}
break;

// all on, knob makes rainbow
case 2: for (int i =0; i < NUM_LEDS; i++) {
strip.setPixelColor(i, colorWheel(BRIGHTNESS, colorValue));
}
break;

// Rainbow
case 3: rainbow(20);
break;

// slug of rainbow auto moving lights, knob adjusts speed
case 4: initializeToBlack();
break;

}
strip.show();
}

// given a wheel position in 0-255 range
// return a rainbow color adjusted by intensity 0 to 1.0
uint32_t colorWheel(float intensity, byte wheelPos)
{
const int WHEEL_THIRD = (WHEEL_SIZE - 1) / 3;

if (intensity < 0.0 ) intensity = 0.0;
if (intensity > 1.0) intensity = 1.0;

// as wheelPos progresses from 0 to 255 once, colorIndex should progress from 0 to 255 3 times
// find out position in current third of wheel then multiple by 3 to get full color value
byte colorIndex = (wheelPos % WHEEL_THIRD) * 3;

int fadeColor = (255 - colorIndex) * intensity; // color going down
int increaseColor = colorIndex * intensity; // color going up

switch (wheelPos / WHEEL_THIRD) {
case 0: // first third of the wheel, red fading, no green, blue increasing
return Adafruit_NeoPixel::Color(fadeColor, 0, increaseColor);
break;
case 1: // second third of the wheel no red, green increasing, blue fading
return Adafruit_NeoPixel::Color(0, increaseColor, fadeColor);
break;

case 2: // last third of the wheel, red increasing, green fading, no blue
return Adafruit_NeoPixel::Color(increaseColor, fadeColor, 0);
break;
}
}

void rainbow(uint8_t wait) {
uint16_t i, j;

for(j=0; j<256; j++) {
for(i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel((i+j) & 255));
}
strip.show();
delay(wait);
}
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
if(WheelPos < 85) {
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
} else if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
} else {
WheelPos -= 170;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
}

Your rainbow function is blocking. This means that while the function is running, input on ENCODER_BUTTON is ignored. The solution is to use non-blocking code, as demonstrated in this tutorial:

Hi Pert Thank you for your reply this has been very useful. When trying to replace the delay with Millis I keep getting 'Wheel' was not declared in this scope this seems to only change when I remove the

strip.show();
delay(wait);

Portion of code

Please post your full sketch.

If possible, you should always post code directly in the forum thread as text using code tags:

  • Do an Auto Format (Tools > Auto Format in the Arduino IDE or Ctrl + B in the Arduino Web Editor) on your code. This will make it easier for you to spot bugs and make it easier for us to read.
  • In the Arduino IDE or Arduino Web Editor, click on the window that contains your sketch code.
  • Press “Ctrl + A”. This will select all the text.
  • Press “Ctrl + C”. This will copy the selected text to the clipboard.
  • In a forum reply here, click the “Reply” button.
  • click on the reply field.
  • Click the </> button on the forum toolbar. This will add the forum’s code tags markup to your reply.
  • Press “Ctrl + V”. This will paste the sketch between the code tags.
  • Move the cursor outside of the code tags before you add any additional text to your reply.
  • Repeat the above process if your sketch has multiple tabs.

This will make it easy for anyone to look at it, which will increase the likelihood of you getting help.

If the sketch is longer than the 9000 characters maximum allowed by the forum, then it’s OK to add it as an attachment. After clicking the “Reply” button, you will see an “Attachments and other settings” link.

When your code requires a library that’s not included with the Arduino IDE please post a link (using the chain links icon on the forum toolbar to make it clickable) to where you downloaded that library from or if you installed it using Library Manger (Sketch > Include Library > Manage Libraries in the Arduino IDE or Libraries > Library Manager in the Arduino Web Editor) then say so and state the full name of the library.

Thank you again, Pert.
As you can tell I’m very new to this, Is this the correct way to post this?

I’m now trying to replace “Delay” in my code with a non-blocking millis() function, I had a go but I was definitely doing it completely wrong so I reverted back.

librarys:

Encoder.h

Adafruit_NeoPixel.h
Installed it using Library Manger

#include <Encoder.h>
#include <Adafruit_NeoPixel.h>

const int NUM_LEDS = 60;            // number of leds in strip
const int LED_PIN = 5;             // pin for led strip
const int BRIGHTNESS = 255;        // brightness of all leds
const int WHEEL_SIZE = 256;        // how many entries in the color wheel
const boolean MOVE_LIGHT = false;  // move one light around or keep all lights on
const int ENCODER_PIN_1 = 2;
const int ENCODER_PIN_2 = 3;
const int ENCODER_BUTTON = 4;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, LED_PIN, NEO_RGB + NEO_KHZ800);
Encoder encoder(ENCODER_PIN_1, ENCODER_PIN_2);
int mode = 0;
long lastPush = 0;
int autoPosition = 0;

void initializeToBlack() {
  for (int i =0; i < NUM_LEDS; i++) {
   strip.setPixelColor(i, 0);
   uint32_t white = strip.Color(255, 255, 255);

  } 
}

void setup() {
  Serial.begin(9600);
  pinMode(ENCODER_BUTTON, INPUT);
  digitalWrite(ENCODER_BUTTON, HIGH); //turn pullup resistor on

  strip.begin();
  initializeToBlack();
  strip.show();   
}
 uint32_t white = strip.Color(255, 255, 255);
long normalize(long value, long radix) {
  long rval = value % radix;
  if (rval < 0) return radix + rval;
  else return rval;
}

void loop() {
  int button= digitalRead(ENCODER_BUTTON);
  if (button == 0) {
    if ((millis() - lastPush) > 250) {
      lastPush = millis();
      mode++;
      if (mode > 4) mode = 0;
    }
  }
  long knobValue = encoder.read() / 1;

  long ledPosition = normalize(knobValue, NUM_LEDS);
  long colorValue = normalize(knobValue * 5, WHEEL_SIZE);
  long sleepValue = abs(knobValue) % 500;
 
  switch(mode) {
  // off
  case 0: initializeToBlack();
          break;

 // all on, White
  case 1: for (int i =0; i < NUM_LEDS; i++) {
strip.fill(white, 0, 60);
          }
          break;

   // all on, knob makes rainbow
  case 2: for (int i =0; i < NUM_LEDS; i++) {
            strip.setPixelColor(i, colorWheel(BRIGHTNESS, colorValue));
          }
          break;
 
 // Rainbow
  case 3:   rainbow(20);
          break;
         
  // slug of rainbow auto moving lights, knob adjusts speed
  case 4: initializeToBlack();
          break;

  }
  strip.show();
}

// given a wheel position in 0-255 range
// return a rainbow color adjusted by intensity 0 to 1.0
uint32_t colorWheel(float intensity, byte wheelPos)
{
  const int WHEEL_THIRD = (WHEEL_SIZE - 1) / 3;
 
  if (intensity < 0.0 ) intensity = 0.0;
  if (intensity > 1.0) intensity = 1.0;

  // as wheelPos progresses from 0 to 255 once, colorIndex should progress from 0 to 255 3 times
  // find out position in current third of wheel then multiple by 3 to get full color value
  byte colorIndex = (wheelPos % WHEEL_THIRD) * 3;
 
  int fadeColor = (255 - colorIndex) * intensity;  // color going down
  int increaseColor = colorIndex * intensity;    // color going up
 
  switch (wheelPos / WHEEL_THIRD) {
    case 0:    // first third of the wheel, red fading, no green, blue increasing
      return Adafruit_NeoPixel::Color(fadeColor, 0, increaseColor);
      break;
    case 1:    // second third of the wheel no red, green increasing, blue fading
      return Adafruit_NeoPixel::Color(0, increaseColor, fadeColor);
      break;
 
    case 2:    // last third of the wheel, red increasing, green fading, no blue
      return Adafruit_NeoPixel::Color(increaseColor, fadeColor, 0);
      break;
  }
}


void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if(WheelPos < 85) {
   return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if(WheelPos < 170) {
   WheelPos -= 85;
   return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
   WheelPos -= 170;
   return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

The only way you're going to make this work is by switching to non-blocking code. You can't just give up because your first try ended up in an error. We're here to help you fix that error, but to do that we need to see the code that caused the error.

Noob who is confused. I’m trying to replace “Delay” in my code with a non-blocking millis() function.

librarys:

Encoder.h

Adafruit_NeoPixel.h
Installed it using Library Manger

#include <Encoder.h>
#include <Adafruit_NeoPixel.h>

const int NUM_LEDS = 60;            // number of leds in strip
const int LED_PIN = 5;             // pin for led strip
const int BRIGHTNESS = 255;        // brightness of all leds
const int WHEEL_SIZE = 256;        // how many entries in the color wheel
const boolean MOVE_LIGHT = false;  // move one light around or keep all lights on
const int ENCODER_PIN_1 = 2;
const int ENCODER_PIN_2 = 3;
const int ENCODER_BUTTON = 4;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, LED_PIN, NEO_RGB + NEO_KHZ800);
Encoder encoder(ENCODER_PIN_1, ENCODER_PIN_2);
int mode = 0;
long lastPush = 0;
int autoPosition = 0;

void initializeToBlack() {
  for (int i =0; i < NUM_LEDS; i++) {
   strip.setPixelColor(i, 0);
   uint32_t white = strip.Color(255, 255, 255);

  } 
}

void setup() {
  Serial.begin(9600);
  pinMode(ENCODER_BUTTON, INPUT);
  digitalWrite(ENCODER_BUTTON, HIGH); //turn pullup resistor on

  strip.begin();
  initializeToBlack();
  strip.show();   
}
 uint32_t white = strip.Color(255, 255, 255);
long normalize(long value, long radix) {
  long rval = value % radix;
  if (rval < 0) return radix + rval;
  else return rval;
}

void loop() {
  int button= digitalRead(ENCODER_BUTTON);
  if (button == 0) {
    if ((millis() - lastPush) > 250) {
      lastPush = millis();
      mode++;
      if (mode > 4) mode = 0;
    }
  }
  long knobValue = encoder.read() / 1;

  long ledPosition = normalize(knobValue, NUM_LEDS);
  long colorValue = normalize(knobValue * 5, WHEEL_SIZE);
  long sleepValue = abs(knobValue) % 500;
 
  switch(mode) {
  // off
  case 0: initializeToBlack();
          break;

 // all on, White
  case 1: for (int i =0; i < NUM_LEDS; i++) {
strip.fill(white, 0, 60);
          }
          break;

   // all on, knob makes rainbow
  case 2: for (int i =0; i < NUM_LEDS; i++) {
            strip.setPixelColor(i, colorWheel(BRIGHTNESS, colorValue));
          }
          break;
 
 // Rainbow
  case 3:   rainbow(20);
          break;
         
  // slug of rainbow auto moving lights, knob adjusts speed
  case 4: initializeToBlack();
          break;

  }
  strip.show();
}

// given a wheel position in 0-255 range
// return a rainbow color adjusted by intensity 0 to 1.0
uint32_t colorWheel(float intensity, byte wheelPos)
{
  const int WHEEL_THIRD = (WHEEL_SIZE - 1) / 3;
 
  if (intensity < 0.0 ) intensity = 0.0;
  if (intensity > 1.0) intensity = 1.0;

  // as wheelPos progresses from 0 to 255 once, colorIndex should progress from 0 to 255 3 times
  // find out position in current third of wheel then multiple by 3 to get full color value
  byte colorIndex = (wheelPos % WHEEL_THIRD) * 3;
 
  int fadeColor = (255 - colorIndex) * intensity;  // color going down
  int increaseColor = colorIndex * intensity;    // color going up
 
  switch (wheelPos / WHEEL_THIRD) {
    case 0:    // first third of the wheel, red fading, no green, blue increasing
      return Adafruit_NeoPixel::Color(fadeColor, 0, increaseColor);
      break;
    case 1:    // second third of the wheel no red, green increasing, blue fading
      return Adafruit_NeoPixel::Color(0, increaseColor, fadeColor);
      break;
 
    case 2:    // last third of the wheel, red increasing, green fading, no blue
      return Adafruit_NeoPixel::Color(increaseColor, fadeColor, 0);
      break;
  }
}


void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if(WheelPos < 85) {
   return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if(WheelPos < 170) {
   WheelPos -= 85;
   return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
   WheelPos -= 170;
   return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

normally you check if time has passed before doing something. you're check if time has passed before incrementing mode, but process it regardless.

i'll guess you're see multiple (and many) processing events of mode without it being incremented

you might try return if the time has not passed to avoid any further processing

Your case is a little bit more difficult than the usual BlinkWithoutDelay example. But you will figure this out.

The issue is that currently the rainbow function runs for a long time and updates the pattern. To make this non-blocking the rainbow function itself needs to become non-blocking. That means you need to change it in a way that you need to call it many times to create the total effect you get now.

There are different ways. A simple one is to declare the variables i and j as static. That way they will keep their values between calls.

static uint16_t i = 0;
static uint16_t j = 0;

Now instead of a loop, you increment the value and set it to zero when the value is larger than the maximum it should be.

j = j++;
if( j >= 256 ){ j = 0; }

or shorter

j = (j + 1) % 256;

Then call setPixelColor and strip.show and leave the rainbow function.

Now use millis() in your loop and call rainbow every 10ms or so.

I've merged your other cross-post @Deakindesigns.

Cross-posting is against the rules of the forum. The reason is that duplicate posts can waste the time of the people trying to help. Someone might spend 15 minutes (or more) writing a detailed answer on this topic, without knowing that someone else already did the same in the other topic.

Repeated cross-posting will result in a suspension from the forum.

In the future, please take some time to pick the forum board that best suits the topic of your question and then only post once to that forum board. This is basic forum etiquette, as explained in the sticky "How to use this forum - please read." post you will find at the top of every forum board. It contains a lot of other useful information. Please read it.

Thanks in advance for your cooperation.