Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ static int re_qstringCmp(const void *ap, const void *bp) {

class RotaryEncoderUIUsermod : public Usermod {
private:
int8_t fadeAmount = 5; // Amount to change every step (brightness)
int8_t fadeAmount = 5; // Amount to change every step (brightness)
unsigned long loopTime = 0;

unsigned long buttonPressedTime = 0;
Expand Down Expand Up @@ -149,6 +149,7 @@ class RotaryEncoderUIUsermod : public Usermod {
unsigned char Enc_A;
unsigned char Enc_B;
unsigned char Enc_A_prev = 0;
unsigned char Enc_B_prev = 0;

bool currentEffectAndPaletteInitialized = false;
uint8_t effectCurrentIndex = 0;
Expand All @@ -162,6 +163,7 @@ class RotaryEncoderUIUsermod : public Usermod {
byte presetLow = 0;

bool applyToAll = true;
bool HalfStep = false; // WLEDMM: use half step for encoder

bool initDone = false;
bool enabled = true;
Expand All @@ -175,6 +177,7 @@ class RotaryEncoderUIUsermod : public Usermod {
static const char _presetHigh[];
static const char _presetLow[];
static const char _applyToAll[];
static const char _HalfStep[];

/**
* Sort the modes and palettes to the index arrays
Expand Down Expand Up @@ -330,6 +333,7 @@ const char RotaryEncoderUIUsermod::_SW_pin[] PROGMEM = "SW-pin";
const char RotaryEncoderUIUsermod::_presetHigh[] PROGMEM = "preset-high";
const char RotaryEncoderUIUsermod::_presetLow[] PROGMEM = "preset-low";
const char RotaryEncoderUIUsermod::_applyToAll[] PROGMEM = "apply-2-all-seg";
const char RotaryEncoderUIUsermod::_HalfStep[] PROGMEM = "half-step encoder"; // WLEDMM: use half step for encoder

/**
* Sort the modes and palettes to the index arrays
Expand Down Expand Up @@ -462,6 +466,7 @@ void RotaryEncoderUIUsermod::setup()
Enc_A = digitalRead(pinA); // Read encoder pins
Enc_B = digitalRead(pinB);
Enc_A_prev = Enc_A;
Enc_B_prev = Enc_B;
USER_PRINTLN(F("Rotary encoder (ALT) setup completed.")); // WLEDMM inform user
}

Expand Down Expand Up @@ -579,44 +584,103 @@ void RotaryEncoderUIUsermod::loop()

Enc_A = digitalRead(pinA); // Read encoder pins
Enc_B = digitalRead(pinB);
if ((Enc_A) && (!Enc_A_prev))
{ // A has gone from high to low
if (Enc_B == LOW) //changes to LOW so that then encoder registers a change at the very end of a pulse
{ // B is high so clockwise
switch(select_state) {
case 0: changeBrightness(true); break;
case 1: changeEffectSpeed(true); break;
case 2: changeEffectIntensity(true); break;
case 3: changePalette(true); break;
case 4: changeEffect(true); break;
case 5: changeHue(true); break;
case 6: changeSat(true); break;
case 7: changeCCT(true); break;
case 8: changePreset(true); break;
case 9: changeCustom(1,true); break;
case 10: changeCustom(2,true); break;
case 11: changeCustom(3,true); break;
if (Enc_A != Enc_A_prev || Enc_B != Enc_B_prev) {
// Serial.print(F("Encoder A: ")); Serial.print(Enc_A);
// Serial.print(F(" B: ")); Serial.println(Enc_B);
// Serial.print(F("State: ")); Serial.println(HalfStep ? "Half Step" : "Full Step" );
}

if (HalfStep) { // WLEDMM: use half step for encoder
if (Enc_A != Enc_A_prev) { // WLEDMM: use rising edge detection
if ((Enc_B == HIGH && Enc_A == LOW) || (Enc_B == LOW && Enc_A == HIGH)) {
// Serial.println("A changed +");
// Clockwise
switch(select_state) {
case 0: changeBrightness(true); break;
case 1: changeEffectSpeed(true); break;
case 2: changeEffectIntensity(true); break;
case 3: changePalette(true); break;
case 4: changeEffect(true); break;
case 5: changeHue(true); break;
case 6: changeSat(true); break;
case 7: changeCCT(true); break;
case 8: changePreset(true); break;
case 9: changeCustom(1,true); break;
case 10: changeCustom(2,true); break;
case 11: changeCustom(3,true); break;
}
}
}
else if (Enc_B == HIGH)
{ // B is low so counter-clockwise
switch(select_state) {
case 0: changeBrightness(false); break;
case 1: changeEffectSpeed(false); break;
case 2: changeEffectIntensity(false); break;
case 3: changePalette(false); break;
case 4: changeEffect(false); break;
case 5: changeHue(false); break;
case 6: changeSat(false); break;
case 7: changeCCT(false); break;
case 8: changePreset(false); break;
case 9: changeCustom(1,false); break;
case 10: changeCustom(2,false); break;
case 11: changeCustom(3,false); break;
else {
if (Enc_B != Enc_B_prev) {
if ((Enc_A == HIGH && Enc_B == LOW) || (Enc_A == LOW && Enc_B == HIGH)) {
// Counter-clockwise
// Serial.println("B changed -");
switch(select_state) {
case 0: changeBrightness(false); break;
case 1: changeEffectSpeed(false); break;
case 2: changeEffectIntensity(false); break;
case 3: changePalette(false); break;
case 4: changeEffect(false); break;
case 5: changeHue(false); break;
case 6: changeSat(false); break;
case 7: changeCCT(false); break;
case 8: changePreset(false); break;
case 9: changeCustom(1,false); break;
case 10: changeCustom(2,false); break;
case 11: changeCustom(3,false); break;
}
}
}
}
}
Comment on lines +593 to +636
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical: Incorrect half-step encoder logic implementation.

The half-step implementation has a fundamental logic error. Both the A-change and B-change branches use equivalent conditions, which would cause the same encoder state to trigger both clockwise and counter-clockwise actions.

Current logic:

  • A change: (Enc_B == HIGH && Enc_A == LOW) || (Enc_B == LOW && Enc_A == HIGH)
  • B change: (Enc_A == HIGH && Enc_B == LOW) || (Enc_A == LOW && Enc_B == HIGH)

These conditions are logically equivalent (just with A and B swapped), so they would both evaluate to true for the same encoder state.

The correct implementation should detect edge transitions and use the state of the other pin to determine direction:

    if (HalfStep) { // WLEDMM: use half step for encoder
-      if (Enc_A != Enc_A_prev) { // WLEDMM: use rising edge detection
-        if ((Enc_B == HIGH && Enc_A == LOW) || (Enc_B == LOW && Enc_A == HIGH)) {
+      if (Enc_A != Enc_A_prev) { // A pin changed
+        if ((Enc_A == HIGH && Enc_B == LOW) || (Enc_A == LOW && Enc_B == HIGH)) {
 //          Serial.println("A changed +");
           // Clockwise
           switch(select_state) {
             case  0: changeBrightness(true);      break;
             case  1: changeEffectSpeed(true);     break;
             case  2: changeEffectIntensity(true); break;
             case  3: changePalette(true);         break;
             case  4: changeEffect(true);          break;
             case  5: changeHue(true);             break;
             case  6: changeSat(true);             break;
             case  7: changeCCT(true);             break;
             case  8: changePreset(true);          break;
             case  9: changeCustom(1,true);        break;
             case 10: changeCustom(2,true);        break;
             case 11: changeCustom(3,true);        break;
           }
+        } else {
+          // Counter-clockwise
+          switch(select_state) {
+            case  0: changeBrightness(false);      break;
+            case  1: changeEffectSpeed(false);     break;
+            case  2: changeEffectIntensity(false); break;
+            case  3: changePalette(false);         break;
+            case  4: changeEffect(false);          break;
+            case  5: changeHue(false);             break;
+            case  6: changeSat(false);             break;
+            case  7: changeCCT(false);             break;
+            case  8: changePreset(false);          break;
+            case  9: changeCustom(1,false);        break;
+            case 10: changeCustom(2,false);        break;
+            case 11: changeCustom(3,false);        break;
+          }
         }
       }
-      else {
-        if (Enc_B != Enc_B_prev) {
-          if ((Enc_A == HIGH && Enc_B == LOW) || (Enc_A == LOW && Enc_B == HIGH)) {
+      if (Enc_B != Enc_B_prev) { // B pin changed
+        if ((Enc_B == HIGH && Enc_A == HIGH) || (Enc_B == LOW && Enc_A == LOW)) {
           // Counter-clockwise
 //            Serial.println("B changed -");
             switch(select_state) {
               case  0: changeBrightness(false);      break;
               case  1: changeEffectSpeed(false);     break;
               case  2: changeEffectIntensity(false); break;
               case  3: changePalette(false);         break;
               case  4: changeEffect(false);          break;
               case  5: changeHue(false);             break;
               case  6: changeSat(false);             break;
               case  7: changeCCT(false);             break;
               case  8: changePreset(false);          break;
               case  9: changeCustom(1,false);        break;
               case 10: changeCustom(2,false);        break;
               case 11: changeCustom(3,false);        break;
             }
+          } else {
+            // Clockwise
+            switch(select_state) {
+              case  0: changeBrightness(true);      break;
+              case  1: changeEffectSpeed(true);     break;
+              case  2: changeEffectIntensity(true); break;
+              case  3: changePalette(true);         break;
+              case  4: changeEffect(true);          break;
+              case  5: changeHue(true);             break;
+              case  6: changeSat(true);             break;
+              case  7: changeCCT(true);             break;
+              case  8: changePreset(true);          break;
+              case  9: changeCustom(1,true);        break;
+              case 10: changeCustom(2,true);        break;
+              case 11: changeCustom(3,true);        break;
+            }
           }
-        }
       }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h
between lines 593 and 636, the half-step encoder logic incorrectly uses
equivalent conditions for both A and B pin changes, causing both clockwise and
counter-clockwise actions to trigger simultaneously. To fix this, revise the
conditions so that on an A pin change, the direction is determined by the state
of the B pin, and on a B pin change, the direction is determined by the state of
the A pin, ensuring distinct and correct detection of rotation direction based
on edge transitions.

else { // Full Step

// if ((Enc_A) && (!Enc_A_prev))
// kkf check for half steps
if ((Enc_A_prev == HIGH) && (Enc_A == LOW))
{ // WLEDMM: use falling edge detection
if (Enc_B == HIGH)
{
// Clockwise
switch(select_state) {
case 0: changeBrightness(true); break;
case 1: changeEffectSpeed(true); break;
case 2: changeEffectIntensity(true); break;
case 3: changePalette(true); break;
case 4: changeEffect(true); break;
case 5: changeHue(true); break;
case 6: changeSat(true); break;
case 7: changeCCT(true); break;
case 8: changePreset(true); break;
case 9: changeCustom(1,true); break;
case 10: changeCustom(2,true); break;
case 11: changeCustom(3,true); break;
}
}
else
{
// Counter-clockwise
switch(select_state) {
case 0: changeBrightness(false); break;
case 1: changeEffectSpeed(false); break;
case 2: changeEffectIntensity(false); break;
case 3: changePalette(false); break;
case 4: changeEffect(false); break;
case 5: changeHue(false); break;
case 6: changeSat(false); break;
case 7: changeCCT(false); break;
case 8: changePreset(false); break;
case 9: changeCustom(1,false); break;
case 10: changeCustom(2,false); break;
case 11: changeCustom(3,false); break;
}
}
}
}

Enc_A_prev = Enc_A; // Store value of A for next time
Enc_B_prev = Enc_B; // Store value of B for next time
}
}

Expand Down Expand Up @@ -1030,6 +1094,7 @@ void RotaryEncoderUIUsermod::addToConfig(JsonObject &root) {
top[FPSTR(_presetLow)] = presetLow;
top[FPSTR(_presetHigh)] = presetHigh;
top[FPSTR(_applyToAll)] = applyToAll;
top[FPSTR(_HalfStep)] = HalfStep;
DEBUG_PRINTLN(F("Rotary Encoder config saved."));
}

Expand Down Expand Up @@ -1073,6 +1138,7 @@ bool RotaryEncoderUIUsermod::readFromConfig(JsonObject &root) {

enabled = top[FPSTR(_enabled)] | enabled;
applyToAll = top[FPSTR(_applyToAll)] | applyToAll;
HalfStep = top[FPSTR(_HalfStep)] | HalfStep;

DEBUG_PRINT(FPSTR(_name));
if (!initDone) {
Expand Down