Rotary encoder help?

Hi gang,

I’m trying to use a rotary encoder to toggle between blade color presets, a clockwise turn advancing to the next preset, counter-clockwise reversing back up to the previous preset. The central push-button switch on the encoder currently activates/deactivates the blade.

Does anyone have a successful config file for this? Below is what I’m working from with the help of a neighbor, and we can’t seem to figure it out. I’m using the attached wiring schematic and rotary encoder.

#ifdef CONFIG_TOP
#include "proffieboard_config.h"
#define NUM_BLADES 1
#define NUM_BUTTONS 2
#define VOLUME 1000
const unsigned int maxLedsPerStrip = 144;
#define CLASH_THRESHOLD_G 1.0
#define ENABLE_AUDIO
#define ENABLE_MOTION
#define ENABLE_WS2811
#define ENABLE_SD
#define SAVE_STATE
#define ENABLE_ALL_EDIT_OPTIONS
#define ENABLE_ROTARY_SWITCH
#endif

#ifdef CONFIG_PRESETS
Preset presets[] = {
  { "TheBalance", "tracks/boot.wav",
    StyleNormalPtr<CYAN, WHITE, 300, 800>(), "cyan"},
  { "TheBalance", "tracks/boot.wav",
    StylePtr<InOutSparkTip<EASYBLADE(BLUE, WHITE), 300, 800> >(), "blue"},
  { "TheBalance", "tracks/boot.wav",
    StyleFirePtr<RED, YELLOW, 1>(), "fire"},
  { "TheBalance", "tracks/boot.wav",
    StyleNormalPtr<RED, WHITE, 300, 800>(), "red"},
  { "TheBalance", "tracks/boot.wav",
    StyleFirePtr<BLUE, CYAN, 1>(), "blue fire"},
  { "TheBalance", "tracks/boot.wav",
    StylePtr<InOutHelper<EASYBLADE(OnSpark<GREEN>, WHITE), 300, 800> >(), "green"},
  { "TheBalance", "tracks/boot.wav",
    StyleNormalPtr<WHITE, RED, 300, 800, RED>(), "white"},
  { "TheBalance", "tracks/boot.wav",
    StyleNormalPtr<AudioFlicker<YELLOW, WHITE>, BLUE, 300, 800>(), "yellow"},
  { "TheBalance", "tracks/boot.wav",
    StylePtr<InOutSparkTip<EASYBLADE(MAGENTA, WHITE), 300, 800> >(), "magenta"},
  { "TheBalance", "tracks/boot.wav",
    StyleNormalPtr<Gradient<RED, BLUE>, Gradient<CYAN, YELLOW>, 300, 800>(), "gradient"},
  { "TheBalance", "tracks/boot.wav",
    StyleRainbowPtr<300, 800>(), "rainbow"},
  { "TheBalance", "tracks/boot.wav",
    StyleStrobePtr<WHITE, Rainbow, 15, 300, 800>(), "strobe"}
};
BladeConfig blades[] = {
  { 0, WS2811BladePtr<144, WS2811_800kHz>(), CONFIGARRAY(presets) },
 };
#endif

#ifdef CONFIG_BUTTONS
Button PowerButton(BUTTON_POWER, powerButtonPin, "pow");
//Button AuxButton(BUTTON_AUX, auxPin, "aux");
#endif

#ifdef CONFIG_ROTARY
#define ROTARY_POSITIONS 12  // Number of positions on your rotary switch (matches preset count)
// Define rotary encoder pins
#define ROTARY_ENCODER_CLK 15  // CLK pin
#define ROTARY_ENCODER_DT 13   // DT pin
#define ROTARY_ENCODER_SW 14   // SW pin (button)

ChangePresetRotaryReceiver rotary_receiver;
Rotary<ROTARY_ENCODER_CLK, ROTARY_ENCODER_DT> rotary(&rotary_receiver);

//Button PowerButton(ROTARY_ENCODER_SW, powerButtonPin, "pow");

//RotarySwitch rotarySwitch(ROTARY_PIN1, ROTARY_PIN2, ROTARY_PIN3, ROTARY_PIN4, ROTARY_POSITIONS);
/*RotaryEncoder rotary_encoder(ROTARY_ENCODER_CLK, ROTARY_ENCODER_DT);

// This class handles rotary encoder events to change presets
class RotaryEncoderHandler : public SaberBase {
  public:
    void Loop() override {
      rotary_encoder.Loop();
      
      // If the encoder has been rotated
      int32_t change = rotary_encoder.getChange();
      if (change != 0) {
        // Calculate new preset
        int32_t current = current_preset_;
        int32_t next = current + change;
        
      // Wrap around if needed
      if (next < 0) next = NELEM(presets) - 1;
      if (next >= NELEM(presets)) next = 0;
        
        // Change preset
      if (next != current) {
          current_preset_ = next;
          SaberBase::DoEffect(EFFECT_CHANGE_PRESET, next);
      }
    }
  }
};

RotaryEncoderHandler rotary_handler; */

// This function connects the rotary switch to the preset selection
/*class RotaryEvent : public Event {
public:
  RotaryEvent() : Event(EVENT_CHANGE_PRESET) {}
  bool IsHandled() override {
    if (rotarySwitch.available()) {
      int position = rotarySwitch.position();
      if (position >= 0 && position < NELEM(presets)) {
        current_preset_ = position;
        return true;
      }
    }
    return false;
  }
};*/

//RotaryEvent rotary_event_handler;
#endif

So first: please edit your post and add 3 back ticks before and after your config. It makes it much easier to read.

Like this:

```
config here
```

Second:
#ifdef CONFIG_ROTARY is not a thing in ProffieOS so it will do nothing no matter what you put in it. I know nothing about rotary encoders but if I understand correctly, it is a button so it should go in #ifdef CONFIG_BUTTONS

Third:
class RotaryEncoderHandler + code should go in a prop not in your config. I doubt it’ll do anything in your config.

This is some notes I have for when I get a chance to play with rotary encoders.

This would go in your config file, possibly in the #ifdef CONFIG_BUTTONS section, but @profezzorn would need to confirm.

// Rotary Encoder (see rotary.h)

ChangePresetRotaryReceiver rotary_receiver;
Rotary<8, 9> rotary(&rotary_receiver);
/*
The receiver decides what the rotary events do.
There are currently receivers for changing presets, 
changing variation and one that just prints things out. 
More receivers can be added as needed. 
(I should probably create one for changing the volume.)
*/
1 Like

This is correct.
The code in the top post looks like what you get when you as chatgpt to code for you.

Asking chatgpt to code is like asking the cookie monster to eat a cookie. It might look like it’s doing it, but ultimately it just makes a mess.

Haha! Yes, that’s exactly what happened. Ran into errors, asked for Claude help, and then several iterations later ended up with the mess before you.

But, thank you for the help @NoSloppy and @profezzorn. That code and pin-out fixed it! Can confirm the rotary encoder toggles between presets now.