OLED menu with double click select

Hi folks,
I'm working on an Infinity Cube and I am having trouble with my menu system.

As it is now, the menu has a list of 10 animations, a timed playlist of all animations and a lamp that I can scroll through with a rotary encoder and click the button to activate selection.
This works as it should but I would like to have a brightness control that is selected with a double click, then just up and down changes the brightness as it happens, then after 3 seconds or so with no movement it returns to the list screen.

My code does detect the double click in serial monitor but I can not get it to display the brightness screen.

#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <Fonts/FreeSans9pt7b.h>
#include <Arduino.h>
#include <RotaryEncoder.h>
#include <OneButton.h>
#include <FastLED.h>

#define NUM_LEDS   336
#define LED_PIN     27
#define BRIGHTNESS  70
#define BRIGHTNESS2      50     // brightness level 
#define BRIGHTNESS3      20     // brightness level for lamp
#define LED_TYPE    WS2812B
#define COLOR_ORDER GRB
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))

int encoderValue = 0;
int brightnessValue = map(encoderValue, 0, 1023, 0, 255);
uint8_t hue = 0;
uint8_t colorIndex[144];
CRGB leds[NUM_LEDS];            // color data for each led - sets up an array that we can manipulate to set/clear led data.
CRGB leds_buffor[168];               // half of the total number of pixels
CRGB leds_in_segments[14];

/// Encoder used is KY-040 / HW-040
#define PIN_IN1 2                           // CLK pin
#define PIN_IN2 5                           // DT  pin   
#define PIN_INPUT 32                   // SW / button pin
#define ROTARYSTEPS 1            // encoder step
#define ROTARYMIN 1                  // encoder min
#define ROTARYMAX 12              // encoder max
#define ROTARYMAX2 25              // encoder max
int lastPos = -1;
int newPos = 1;
int newPos2 = 1;
int newPos3 = 1;
#define OLED_ADDR   0x3C
#define SCREEN_WIDTH 128        // OLED display width, in pixels
#define SCREEN_HEIGHT 64        // OLED display height, in pixels
#define OLED_RESET     -1       // Reset pin # (or -1 if sharing Arduino reset pin)

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

//---------------

volatile int interrupts;
int totalInterrupts;

hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

void IRAM_ATTR onTime() {
  portENTER_CRITICAL_ISR(&timerMux);
  interrupts++;

  portEXIT_CRITICAL_ISR(&timerMux);
}

// A pointer to the dynamic created rotary encoder instance.
// This will be done in setup()

RotaryEncoder *encoder = nullptr;

// @brief The interrupt service routine will be called on any change of one of the input signals.

IRAM_ATTR void checkPosition()
{
  encoder->tick();                               // just call tick() to check the state.
}

OneButton button(PIN_INPUT, true,true);
//unsigned long pressStartTime;

ICACHE_RAM_ATTR void checkTicks() { 
// include all buttons here to be checked
  button.tick();                                 // just call tick() to check the state.
}

// this function will be called when the button was pressed 1 time only.
void singleClick() {
  Serial.println("singleClick() detected.");
  newPos2 = newPos;
} // singleClick

// this function will be called when the button was pressed 2 times in a short timeframe.
void doubleClick() {
  Serial.println("doubleClick() detected.");
  newPos3 = newPos;
} // doubleClick

// this function will be called when the button was held down for 1 second or more.

DEFINE_GRADIENT_PALETTE( matrix_gp ) {            //gradient for pattern usage
    0, 173,229, 51,
   73, 139,199, 45,
  140,  46,176, 37,
  204,   7, 88,  5,
  255,   0, 24,  0};

CRGBPalette16 greenblue2 = matrix_gp;                


DEFINE_GRADIENT_PALETTE( spellbound_gp ) {          //gradient2 for pattern usage
    0, 232,235, 40,
   12, 157,248, 46,
   25, 100,246, 51,
   45,  53,250, 33,
   63,  18,237, 53,
   81,  11,211,162,
   94,  18,147,214,
  101,  43,124,237,
  112,  49, 75,247,
  127,  49, 75,247,
  140,  92,107,247,
  150, 120,127,250,
  163, 130,138,252,
  173, 144,131,252,
  186, 148,112,252,
  196, 144, 37,176,
  211, 113, 18, 87,
  221, 163, 33, 53,
  234, 255,101, 78,
  247, 229,235, 46,
  255, 229,235, 46};

CRGBPalette16 greenblue = spellbound_gp;

void setup() {
  //--------------------------------
  // Configure Prescaler to 80, as our timer runs @ 80Mhz
  // Giving an output of 80,000,000 / 80 = 1,000,000 ticks / second
  timer = timerBegin(0, 80, true);                
  timerAttachInterrupt(timer, &onTime, true);    
  // Fire Interrupt every 1m ticks, so 1s
  timerAlarmWrite(timer, 5000000, true);      
  timerAlarmEnable(timer);
  //--------------------------------
   FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);        // setup leds
   FastLED.setBrightness(brightnessValue);
  
  Serial.begin(9600);
  while (!Serial)
    ;
  // setup the rotary encoder functionality
  encoder = new RotaryEncoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);
  // register interrupt routine
  attachInterrupt(digitalPinToInterrupt(PIN_IN1), checkPosition, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_IN2), checkPosition, CHANGE);

  encoder->setPosition(1 / ROTARYSTEPS);                                     // start with the value of 10.    

    // setup interrupt routine
  attachInterrupt(digitalPinToInterrupt(PIN_INPUT), checkTicks, CHANGE);
  button.attachClick(singleClick);
  button.attachDoubleClick(doubleClick);
  button.setPressMs(1000);                                                  // that is the time when LongPressStart is called - not in use

  display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
  display.display();
  display.clearDisplay();                                                  // Clear the buffer
  
for (int i = 0; i < 168; i++) {
    colorIndex[i] = random8();
  }
  
} // setup() close

typedef void (*SimplePatternList[])();
SimplePatternList gPatterns = {rainbow, matrix, spellPattern, dots, colourSnake, confetti, randomStar, colourful, beat, snake};
int secondsPerPattern[] = {20, 5, 5, 20, 20, 20, 20,20,20,20};
uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current
uint8_t gHue = 0; // rotating "base color"

void screen() {                                                              //funtion for screen operation

   display.setTextSize(1);
   display.setTextColor(WHITE);
   display.setCursor(28, 0);
   display.println("LIGHTING MODES");
   display.drawLine(4, 12, 128, 12, WHITE);
 switch (newPos) {
  case 0:
     break;

 case 1:
   highlight(); 
   display.setCursor(6, 32);
   display.println(" Rainbow ");
   display.setTextColor(WHITE);
   display.setCursor(6, 44);
   display.println(" Matrix ");
    break;
      
  case 2:
   display.setCursor(6, 20);
   display.println(" Rainbow ");
   highlight(); 
   display.setCursor(6, 32);
   display.println(" Matrix ");
   display.setTextColor(WHITE);
   display.setCursor(6, 44);
   display.println(" Spell Pattern ");      
    break;
      
  case 3:
   display.setCursor(6, 20);
   display.println(" Matrix ");
   highlight(); 
   display.setCursor(6, 32);
   display.println(" Spell Pattern ");
   display.setTextColor(WHITE);
   display.setCursor(6, 44);
   display.println(" Move Dots ");
    break;
      
  case 4:
    display.setCursor(6, 20);
   display.println(" Spell Pattern ");
   highlight(); 
   display.setCursor(6, 32);
   display.println(" Move Dots ");
   display.setTextColor(WHITE);
   display.setCursor(6, 44);
   display.println(" Colour Snake ");
    break;
      
  case 5:
   display.setCursor(6, 20);
   display.println(" Move Dots ");
   highlight(); 
   display.setCursor(6, 32);
   display.println(" Colour Snake ");
   display.setTextColor(WHITE);
   display.setCursor(6, 44);
   display.println(" Confetti ");
    break;
      
  case 6:
   display.setCursor(6, 20);
   display.println(" Colour Snake ");
   highlight(); 
   display.setCursor(6, 32);
   display.println(" Confetti ");
   display.setTextColor(WHITE);
   display.setCursor(6, 44);
   display.println(" Random Star");
    break;
      
  case 7:
   display.setCursor(6, 20);
   display.println(" Confetti ");
   highlight(); 
   display.setCursor(6, 32);
   display.println(" Random Star ");
   display.setTextColor(WHITE);
   display.setCursor(6, 44);
   display.println(" Colorful ");
    break;
      
  case 8:
   display.setCursor(6, 20);
   display.println(" Random Star ");
   highlight(); 
   display.setCursor(6, 32);
   display.println(" Colorful ");
   display.setTextColor(WHITE);
   display.setCursor(6, 44);
   display.println(" Beat ");
    break;
      
  case 9:
   display.setCursor(6, 20);
   display.println(" Colorful ");
   highlight(); 
   display.setCursor(6, 32);
   display.println(" Beat ");
   display.setTextColor(WHITE);
   display.setCursor(6, 44);
   display.println(" Snake ");
    break;
      
  case 10:
   display.setCursor(6, 20);
   display.println(" Beat ");
   highlight(); 
   display.setCursor(6, 32);
   display.println(" Snake ");
   display.setTextColor(WHITE);
   display.setCursor(6, 44);
   display.println(" Playlist ");
    break;
      
  case 11:
   display.setCursor(6, 20);
   display.println(" Snake ");
   highlight(); 
   display.setCursor(6, 32);
   display.println(" Playlist ");
   display.setTextColor(WHITE);
   display.setCursor(6, 44);
   display.println(" Lamp ");
    break;
      
  case 12:
   display.setCursor(6, 20);
   display.println(" Playlist ");
   highlight(); 
   display.setCursor(6, 32);
   display.println(" Lamp ");
   display.setTextColor(WHITE);
    break;
      
  }
  
   display.display();
   delay(100);
   display.clearDisplay();
}

void screen2() {

   display.setTextSize(1);
   display.setTextColor(WHITE);
   display.setCursor(32, 0);
   display.println("BRIGHTNESS");
   display.drawLine(27, 12, 95, 12, WHITE);
  switch (newPos) {
   case 0:
     break;

  case 1:
   highlight(); 
   display.setTextSize(2);
   display.setCursor(6, 28);
   display.println("  UP   + ");
   display.setTextColor(WHITE);
   display.setCursor(6, 48);
   display.println(" DOWN  - ");
    break;

  case 2:
   display.setCursor(6, 28);
   display.println("  UP   + ");
   highlight(); 
   display.setCursor(6, 32);
   display.println(" DOWN  - ");
   display.setTextColor(WHITE);
    break;
  }

  display.display();
  delay(100);
  display.clearDisplay();
}

void highlight() {
  display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
  }

void rainbow() {
  
   FastLED.setBrightness(BRIGHTNESS);  // set brightness level
 for (uint8_t j = 0; j < 168; j++) {
   leds_buffor[j]= CHSV(hue+(j*10), 255, 255);
   }
    mirror();
    FastLED.show();
   
    EVERY_N_MILLISECONDS(10){
    hue++;
 }
}

void matrix() {    
                     
   FastLED.setBrightness(BRIGHTNESS3);  // set brightness level
for (int i = 0; i < 168; i++) {
    leds_buffor[i] = ColorFromPalette(greenblue2, colorIndex[i]);
  }
 EVERY_N_MILLISECONDS(5){
    for (int i = 0; i < 168; i++) {
      colorIndex[i]++;
    }
  } 
  mirror();
  FastLED.show();
}

void dots() {
                                                  
   FastLED.setBrightness(BRIGHTNESS);  // set brightness level

  uint16_t posBeat  = beatsin16(30, 0, 14, 0, 0);
  uint16_t posBeat2 = beatsin16(60, 0, 14, 0, 0);
  uint16_t posBeat3 = beatsin16(30, 0, 14, 0, 32767);
  uint16_t posBeat4 = beatsin16(60, 0, 14, 0, 32767);

  // Wave for LED color
  uint8_t colBeat  = beatsin8(45, 0, 255, 0, 0);

  leds_in_segments[(posBeat + posBeat2) / 2]  = CHSV(colBeat, 255, 255);
  //leds_segments[(posBeat3 + posBeat4) / 2]  = CHSV(colBeat, 255, 255);

  fadeToBlackBy(leds_in_segments, 14, 15);
  segments();
  FastLED.show();
}

void colourful() {

   FastLED.setBrightness(BRIGHTNESS);  // set brightness level

  static uint16_t sPseudotime = 0;
  static uint16_t sLastMillis = 0;
  static uint16_t sHue16 = 0;
 
  uint8_t sat8 = beatsin88( 87, 220, 250);
  uint8_t brightdepth = beatsin88( 341, 96, 224);
  uint16_t brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256));
  uint8_t msmultiplier = beatsin88(147, 23, 60);

  uint16_t hue16 = sHue16;//gHue * 256;
  uint16_t hueinc16 = beatsin88(113, 1, 3000);
  
  uint16_t ms = millis();
  uint16_t deltams = ms - sLastMillis ;
  sLastMillis  = ms;
  sPseudotime += deltams * msmultiplier;
  sHue16 += deltams * beatsin88( 400, 5,9);
  uint16_t brightnesstheta16 = sPseudotime;
  
  for( uint16_t i = 0 ; i < 168; i++) {
    hue16 += hueinc16;
    uint8_t hue8 = hue16 / 256;

    brightnesstheta16  += brightnessthetainc16;
    uint16_t b16 = sin16( brightnesstheta16  ) + 32768;

    uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
    uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
    bri8 += (255 - brightdepth);
    
    CRGB newcolor = CHSV( hue8, sat8, bri8);
    
    uint16_t pixelnumber = i;
    pixelnumber = (167) - pixelnumber;
    
    nblend( leds_buffor[pixelnumber], newcolor, 64);
  }
  mirror();
   FastLED.show();
  }
  
void snake() {

   FastLED.setBrightness(BRIGHTNESS);  // set brightness level

  fadeToBlackBy( leds_in_segments, 14, 20);
  int pos = beatsin16( 30, 0, 13 );
  leds_in_segments[pos] += CHSV( hue, 255, 192);
  segments();
   FastLED.show();
    EVERY_N_MILLISECONDS(100){
   hue++;
  }
}

void spellPattern() {
  
   FastLED.setBrightness(BRIGHTNESS3);  // set brightness level

for (int i = 0; i < 168; i++) {
    leds_buffor[i] = ColorFromPalette(greenblue, colorIndex[i]);
  }
 EVERY_N_MILLISECONDS(5){
    for (int i = 0; i < 168; i++) {
      colorIndex[i]++;
    }
  }
   mirror();
 
   FastLED.show();
  }
  
void beat() {
  
   FastLED.setBrightness(BRIGHTNESS);  // set brightness level

  // colored stripes pulsing at a defined Beats-Per-Minute (BPM)
  uint8_t BeatsPerMinute = 30;
  CRGBPalette16 palette = PartyColors_p;
  uint8_t beat = beatsin8( BeatsPerMinute, 64, 255);
  for( int i = 0; i < 14; i++) { //9948
    leds_in_segments[i] = ColorFromPalette(palette, hue+(i*2), beat-hue+(i*10));
  }
   segments();
   FastLED.show();
    EVERY_N_MILLISECONDS(20){
   hue++;
  }
}

void confetti() {
  
   FastLED.setBrightness(BRIGHTNESS);  // set brightness level
  // random colored speckles that blink in and fade smoothly
  fadeToBlackBy( leds_buffor, 168, 10);
  int pos = random16(168);
  leds_buffor[pos] += CHSV( hue + random8(64), 200, 255);
  mirror();
   FastLED.show();
    EVERY_N_MILLISECONDS(20){
    hue++;
    }
}

void colourSnake() {
  
   FastLED.setBrightness(BRIGHTNESS);  // set brightness level
  // eight colored dots, weaving in and out of sync with each other
  fadeToBlackBy( leds_buffor, 168, 30);
  uint8_t dothue = 0;
  for( int i = 0; i < 8; i++) {
    leds_buffor[beatsin16( i+1, 0, 168 )] |= CHSV(dothue, 200, 255);  // i+1 change to i+7 fot faster effect 
    dothue += 32;
  }
  mirror();
   FastLED.show();
    EVERY_N_MILLISECONDS(20){
    hue++;
  }
}

void randomStar() {
  
   FastLED.setBrightness(BRIGHTNESS);  // set brightness level
   EVERY_N_MILLISECONDS(100) {
    leds_buffor[random16(0, 168)] = CHSV((random16(130, 160)), (random16(0, 255)), 255); 
   }
   fadeToBlackBy(leds_buffor, 168, 5);
mirror();
FastLED.show();
}

void lamp() {

   FastLED.setBrightness(BRIGHTNESS2);  // set brightness level
   fill_solid(leds, NUM_LEDS, CRGB::White);
  FastLED.show();
}

void playlist() {

    gPatterns[gCurrentPatternNumber]();

  FastLED.show();
  EVERY_N_MILLISECONDS( 20 ) {
    gHue++;  // slowly cycle base color through rainbow
  }
  //EVERY_N_SECONDS(secondsPerPattern[gCurrentPatternNumber]) {
  static long lastChangeMs = 0;
  if(millis() - lastChangeMs >= secondsPerPattern[gCurrentPatternNumber]*1000L){
    lastChangeMs = millis();
  // add one to the current pattern number, and wrap around at the end
  gCurrentPatternNumber = (gCurrentPatternNumber + 1) % ARRAY_SIZE( gPatterns);

 }
}

//--------------------------------------------------end patterns---------

// this function puts the seperate sections in to pairs

 void mirror() {
for (uint8_t i = 0; i < 14; i++) {
  
 leds[i] = leds_buffor[i];                                  // section 1
 leds[335-i]=leds[i];                                        // section 24
 leds[14+i] = leds_buffor[14+i];                    // section 2
 leds[293-i]=leds[14+i];                                 // section 21
 leds[28+i] = leds_buffor[28+i];                    // section 3
 leds[83-i]=leds[28+i];                                   // section 6
 leds[42+i] = leds_buffor[42+i];                    // section 4
 leds[69-i]=leds[42+i];                                   // section 5
 leds[84+i] = leds_buffor[56+i];                    // section 7
 leds[279-i]=leds[84+i];                                 // section 20
 leds[98+i] = leds_buffor[70+i];                    // section 8
 leds[153-i]=leds[98+i];                                 // section 11
 leds[125-i] = leds_buffor[84+i];                   // section 9
 leds[139-i]=leds[112+i];                               // section 10
 leds[154+i] = leds_buffor[98+i];                  // section 12
 leds[265-i]=leds[154+i];                               // section 19
 leds[168+i] = leds_buffor[112+i];                // section 13
 leds[251-i]=leds[168+i];                              // section 18
 leds[182+i]=leds_buffor[126+i];                  // section 14
 leds[209-i]=leds[182+i];                               // section 15
 leds[210+i] = leds_buffor[140+i];                // section 16
 leds[237-i]=leds[210+i];                               // section 17
 leds[307-i] = leds_buffor[154+i];                 // section 22
 leds[308+i]=leds[307-i];                               // section 23
 }
}

// this function puts the strip in to 24 equal sections of 14 pixels

void segments() {                
for (uint8_t i = 0; i < 14; i++) {
  
  leds[i] = leds_in_segments[i];                      // section 
  leds[252+i]=leds_in_segments[i];                // section 
  leds[27-i] = leds_in_segments[i];                // section 
  leds[168+i]=leds_in_segments[i];                // section 
  leds[28+i] = leds_in_segments[i];               // section 
  leds[112+i]=leds_in_segments[i];               // section 
  leds[55-i] = leds_in_segments[i];               // section 
  leds[56+i]=leds_in_segments[i];                  // section 
  leds[83-i] = leds_in_segments[i];               // section 
  leds[279-i]=leds_in_segments[i];               // section 
  leds[84+i] = leds_in_segments[i];                // section 
  leds[307-i]=leds_in_segments[i];               // section 
  leds[111-i] = leds_in_segments[i];               // section 
  leds[139-i]=leds_in_segments[i];                // section 
  leds[140+i] = leds_in_segments[i];             // section 
  leds[280+i]=leds_in_segments[i];                // section 
  leds[167-i] = leds_in_segments[i];              // section 
  leds[195-i]=leds_in_segments[i];               // section 
  leds[196+i] = leds_in_segments[i];              // section 
  leds[308+i]=leds_in_segments[i];                // section 
  leds[224+i] = leds_in_segments[i];             // section 
  leds[251-i]=leds_in_segments[i];               // section 
  leds[223-i] = leds_in_segments[i];             // section 
  leds[335-i] = leds_in_segments[i];             // section 
}
}

//------------------------Main loop--------------

void loop() {
  


  static int pos = 0;
  button.tick();
  encoder->tick();                                     // just call tick() to check the state.
  
  newPos = encoder->getPosition() * ROTARYSTEPS;

  
  if (newPos < ROTARYMIN) {
    encoder->setPosition(ROTARYMIN / ROTARYSTEPS);
    newPos = ROTARYMIN;
  } 
  else if (newPos > ROTARYMAX) {
    encoder->setPosition(ROTARYMAX / ROTARYSTEPS);
    newPos = ROTARYMAX;
  }
  else if (newPos > ROTARYMAX2) {
    encoder->setPosition(ROTARYMAX2 / ROTARYSTEPS);
    newPos = ROTARYMAX2;
  }
  if (lastPos != newPos) {
    Serial.print(newPos);
    lastPos = newPos;
    screen();
  } 
  else if(lastPos != newPos2) {
    Serial.print(newPos);
    lastPos = newPos;
    screen2();
  }
  switch (newPos2) {
// play order of animations    
    case 0:  //  Serial.print(newPos);
     break;
    case 1:  rainbow(); break;
    case 2:  matrix(); break;
    case 3:  SpellPattern(); break;
    case 4:  dots(); break;
    case 5:  ColourSnake(); break;
    case 6:  confetti(); break;
    case 7:  RandomStar(); break;
    case 8:  colourful(); break;
    case 9:  beat(); break;
    case 10:  snake(); break;
    case 11:  playlist(); break;
    case 12:  lamp(); break;
  } 
  switch (newPos3) {
    case 0:
     break;
    case 1: FastLED.setBrightness(brightnessValue); break;
    case 2: FastLED.setBrightness(brightnessValue); break; 
  }
  //--------
  if (interrupts > 0) {
    portENTER_CRITICAL(&timerMux);
    interrupts--;
    portEXIT_CRITICAL(&timerMux);
    totalInterrupts++;
    Serial.print("totalInterrupts");
    Serial.println(totalInterrupts);
  }
}

This is my first project with a screen and rotary encoder. I think everything is there, just maybe not written correct or in the wrong place.

Could anyone point me in the right direction with this please, my last hurdle in this project.
Thanks

1 Like

What is the value of newPos3?

  switch (newPos3) {
    case 0:
      break;
    case 1: FastLED.setBrightness(brightnessValue); break;
    case 2: FastLED.setBrightness(brightnessValue); break;

@xfpd As I said, this is my first project with a screen and encoder.

Maybe should be more like this

 switch (newPos3) {
    case 0:
     break;
    case 1: brightUp(); break;
    case 2: brightDown(); break; 

witch relates to

void brightUp() {
int brightnessValue = map(encoderValue, 0, 1023, 0, 255);
   FastLED.setBrightness(brightnessValue);
 FastLED.show();
}

void brightDown() {
  int brightnessValue = map(encoderValue, 1023, 0, 255, 0);
   FastLED.setBrightness(brightnessValue);
 FastLED.show();
}

possibly ?

My first problem with this is to assign the brightness screen to a double click. That should teach me more about encoders, buttons and screens.
I have seen examples of menus but none of them use a double click. Most of them use sub-menus witch is not really what I want and looks a bit too complicated for me.

Without a monitor, you can use your NeoPixels as your "standard output" (monitor/screen). That is to say, if you get a "0" case, light one NeoPixel red, if you get a "1" case, light the neopixel green (or light a second neopixel)... et c. Make your debug pixels work for you.

I am going to start again and learn how to a assign specific function to a double click for a second menu. My single menu works great but I still need a second menu for the brightness.
Serial monitor does detect double click, it just doesn't respond to it.
Closest I have got so far is the second menu appears when rotary encoder is at minimum and screens alternate when encoder is above minimum.
I did think of using WLED but I have no idea how to map my pixel numbers into it so it displays like a genuine infinity cube.
Back to the drawing board, as they say.

Describe the input required, the "detected" values in the Serial Monitor, the response you observe versus the response you intend.

This sounds like your encoder needs a debounce function.

If you are meaning the "one pixel = screen 1, 2 pixels = screen 2, et c." then WLED should have ready-to-go functions to light any pixel in any color.

I think you should solve your most important issue first... which is... ??

Thanks for answering.

With just the 1 menu, serial monitor reports the encoder position 1 move at a time and when (and what type of) a button click is detected. Also the interrupts increase by 1every 5 seconds.
When I try to add a second menu, serial monitor continues to repeat encoder position and screen flashes between the 2 displays.
When I click the button, serial monitor displays type of click detected, screen stops flashing and serial monitor stops repeating. As soon as encoder is moved, repeating starts again.

The first and most important thing is to get the 'Brightness' screen to appear when I double click the button.

Basic explanation:-
Screen 1, a list of animations, a timed playlist and a lamp setting. Select with encoder, activate with single click. This works great.
Screen 2, selected with a double click. It just display UP and DOWN. Increase or decrease brightness as it happens (in 25 steps, encoder is set to 12 for list) when encoder is turned. When no signal is detected for 3 seconds, main menu screen is displayed.
Probably a bit too ambitious for me I think.

Any help is greatly received and welcomed.

Try another encoder... (edit)... if the "back and forth" continues, look at your code.

I don't see how it can be the encoder when it works with 1 menu and double click is detected.
Problem is with the code and me, I'm not good enough to be doing this.
I might just shelve this project. It's making me mad that I can't solve what should be a simple thing.

Edit: adding a second encoder for brightness might be another option.

When you say the most important part to solve is to assign brightness to a double-click... is the double-click option available at startup? It looks like that is buried deep in the code that needs other problems fixed first.

Your sketch is overly complicated for no good reason. Your sketch seems to wait for a rotary encoder action (CW, CCW, SELECT) and do something after the action happens.

However; your sketch is mapping an encoder to an analog value. Rotary encoders (and their library) yield a HIGH or LOW depending on the rotation direction (CW or CCW). In your IDE, look under FILE >> EXAMPLES >> (your encoder) >> (examples) to compare an example sketch to your sketch. Practice with the examples, or search "arduino rotary encoder" for other examples online.

I would encourage encapsulating each action from your hardware into its own software function. When you have each function complete, add a call from the main function to that sub-function.

Keep the animations, but the rest seems over-done. Simplify your code.

Thanks for the advice.

I have the code running without any other screen stuff in it and it runs fine.
I will strip the code into separate sketches for button, screen and encoder and 1 to just run the animations in the playlist.

Then a 5 step plan,
Step 1, have a play with some encoder examples and compare to mine and see if I can get anywhere. Examples look easier than mine.
Step 2, play with button examples for single and double click, make double click do something different to single click.
Step 3, try some OLED menu examples.
Step 4, combine the 3 together.
Step 5, rebuild the code and organise it better.

Might take some time but I should learn a bit, don't hold out much hope though.

Solve each step. Ask any questions.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.