Rotary Encoder with The Ai-Thinker ESP32 Audiokit for Volume

I need to make an audio system for my go-kart with an esp32
I got the Bluetooth part sorted out, but the EQ, Menu, and Rotary Encoder are not done yet.
I'm working on the rotary encoder first since it's not as hard as the other two I have to work on.

I tried making code for controlling the volume of the kit but it isn't super responsive.
I need help making it more responsive since it is too slow

Here's the code:

#include <Pushbutton.h>
#include <RotaryEncoder.h>
#define USE_A2DP
#include "AudioTools.h"
#include "AudioLibs/AudioKit.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

BluetoothA2DPSink a2dp_sink;
AudioKitStream kit;

String songName;
String songArtist;
//Millis
unsigned long currentMillis;
unsigned long previousMillis = 0;
unsigned long previousMillis1 = 0;
//rotary encoder
RotaryEncoder encoder(18, 23, RotaryEncoder::LatchMode::FOUR3);
#define ROTARYSTEPS 5
#define ROTARYMIN 0
#define ROTARYMAX 100
int lastPos = -1;
bool usingApsoluteVolume = false;
Pushbutton rnButton(5);

//lcd
LiquidCrystal_I2C lcd(0x27, 16, 2);
byte zero[] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000
};
byte one[] = {
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
  B10000
};
byte two[] = {
  B11000,
  B11000,
  B11000,
  B11000,
  B11000,
  B11000,
  B11000,
  B11000
};
byte three[] = {
  B11100,
  B11100,
  B11100,
  B11100,
  B11100,
  B11100,
  B11100,
  B11100
};
byte four[] = {
  B11110,
  B11110,
  B11110,
  B11110,
  B11110,
  B11110,
  B11110,
  B11110
};
byte five[] = {
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
bool volumeOnScreen = false;
bool backlight = true;
// Connected States
bool connectedState;
bool lastConnectedState;
//volume
int volume;
//Menus
/*Main Menu*/
bool mainMenuShown = false;
int mainMenuSelected = 0;
// Write data to AudioKit in callback
void read_data_stream(const uint8_t *data, uint32_t length) {
  kit.write(data, length);
}
void avrc_metadata_callback(uint8_t id, const uint8_t *text) {
  //Serial.printf(">id 0x%x, %s\n", id, text);

  switch (id) {
    case 0x1:
      songName = (char *)text;
      break;
    case 0x2:
      songArtist = (char *)text;
      break;
  }
  if (!mainMenuShown) {
    lcd.clear();
    lcd.home();
    lcd.print(songName);
    lcd.setCursor(0, 1);
    lcd.print(songArtist);
  }
}

void startDisplay() {
  lcd.init(21, 22);
  lcd.backlight();
  lcd.createChar(0, zero);
  lcd.createChar(1, one);
  lcd.createChar(2, two);
  lcd.createChar(3, three);
  lcd.createChar(4, four);
  lcd.createChar(5, five);
}


void updateProgressBar(unsigned long count, unsigned long totalCount, int lineToPrintOn)
{
  double factor = totalCount / 80.0;
  int percent = (count + 1) / factor;
  int number = percent / 5;
  int remainder = percent % 5;
  if (number > 0)
  {
    for (int j = 0; j < number; j++)
    {
      lcd.setCursor(j, lineToPrintOn);
      lcd.write(5);
    }
  }
  lcd.setCursor(number, lineToPrintOn);
  lcd.write(remainder);
  if (number < 16)
  {
    for (int j = number + 1; j <= 16; j++)
    {
      lcd.setCursor(j, lineToPrintOn);
      lcd.write(0);
    }
  }
}

void setup() {
  Serial.begin(115200);
  AudioLogger::instance().begin(Serial, AudioLogger::Warning);
  // setup output
  auto cfg = kit.defaultConfig(TX_MODE);
  cfg.bits_per_sample = AUDIO_HAL_BIT_LENGTH_32BITS;
  cfg.sample_rate = AUDIO_HAL_44K_SAMPLES;
  kit.begin(cfg);
  kit.setVolume(0);
  startDisplay();
  // register callback
  a2dp_sink.set_stream_reader(read_data_stream, false);
  a2dp_sink.set_avrc_metadata_attribute_mask(ESP_AVRC_MD_ATTR_TITLE | ESP_AVRC_MD_ATTR_ARTIST);
  a2dp_sink.set_avrc_metadata_callback(avrc_metadata_callback);
  a2dp_sink.set_bits_per_sample(32);
  a2dp_sink.start("TrixoleKart Go-Kart");
  a2dp_sink.set_auto_reconnect(true, false, 1000);
}
void volumeChange(int c_volume) {
  previousMillis = currentMillis;
  if (usingApsoluteVolume) {
    volume = map(c_volume, 0, 127, 0, 100);
  } else {
    volume = c_volume;
  }
  char buffer[40];
  sprintf(buffer, ">volume: %d", volume);
  //Serial.println(buffer);
  lcd.setCursor(0, 0);
  lcd.print("     Volume     ");
  updateProgressBar(volume, 100, 1);
  volumeOnScreen = true;
}
void loop() {
  currentMillis = millis();
  kit.processActions();
  clearAndReturn(2);
  SendToMega();
  ReceiveFromMega();
  rotaryEncoderVolume();
  mainMenu();
  //connect states
  vTaskDelay(5);
  connectedState = a2dp_sink.is_connected();
  if (connectedState == true && lastConnectedState != true) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Connected to:");
    lcd.setCursor(0, 1);
    lcd.print(a2dp_sink.get_connected_source_name());
    Serial.println(">Bluetooth: Connected to ");
    Serial.print(a2dp_sink.get_connected_source_name());
    delay(1000);
    a2dp_sink.set_volume(127);
    lastConnectedState = connectedState;
  }
  if (connectedState == false && lastConnectedState != false) {
    lcd.clear();
    lcd.setCursor(2, 0);
    lcd.print("Disconnected");
    Serial.println(">Bluetooth: Disconnected");
    songName = "";
    songArtist = "";
    delay(1000);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("No Device");
    lcd.setCursor(0, 1);
    lcd.print("Connected!");
    lastConnectedState = connectedState;
  }

}

void clearAndReturn(int interval) {
  if (volumeOnScreen == true) {
    if (currentMillis - previousMillis >= interval * 1000) {
      previousMillis = currentMillis;
      lcd.clear();
      lcd.home();
      lcd.print(songName);
      lcd.setCursor(0, 1);
      lcd.print(songArtist);
      volumeOnScreen = false;
    }
  }
}
void SendToMega() {
  if (currentMillis - previousMillis1 >= 500) {
    previousMillis1 = currentMillis;
    String data = songName + "," + songArtist + "," + String(a2dp_sink.get_connected_source_name()) + ", ";
    Serial.print(data);
  }
}

void ReceiveFromMega() {
  char iC = Serial.read();
  switch (iC) {
    case 'D':
      backlight = !backlight;
      if (backlight) {
        lcd.backlight();
      } else {
        lcd.noBacklight();
      }
      break;
    case 'N':
      a2dp_sink.next();
      break;
    case 'P':
      a2dp_sink.previous();
      break;
  }
}
void rotaryEncoderVolume() {
  if (usingApsoluteVolume)
  {
    switch (encoder.getDirection()) {
      case RotaryEncoder::Direction::CLOCKWISE:
        if (a2dp_sink.get_volume() < 127) {
          a2dp_sink.set_volume(a2dp_sink.get_volume() + 1);
          volumeChange(kit.volume());
        }
        break;
      case RotaryEncoder::Direction::COUNTERCLOCKWISE:
        if (a2dp_sink.get_volume() > 0) {
          a2dp_sink.set_volume(a2dp_sink.get_volume() - 1);
          volumeChange(kit.volume());
        }
        break;
    }
  } else {
    encoder.tick();
    switch (encoder.getDirection()) {
      case RotaryEncoder::Direction::CLOCKWISE:
        if (kit.volume() < 100) {
          int Volume = kit.volume() + ROTARYSTEPS + 2;
          kit.setVolume(Volume);
          volumeChange(kit.volume());
        }
        break;
      case RotaryEncoder::Direction::COUNTERCLOCKWISE:
        if (kit.volume() > 0) {
          int Volume = kit.volume() - ROTARYSTEPS;
          kit.setVolume(Volume);
          volumeChange(kit.volume());
        }
        break;
    }
    if (kit.volume() > 100) {
      kit.setVolume(100);
    }
    if (kit.volume() < 0) {
      kit.setVolume(0);
    }
    if (a2dp_sink.get_volume() > 127) {
      a2dp_sink.set_volume(127);
    }
    if (a2dp_sink.get_volume() < 0) {
      a2dp_sink.set_volume(0);
    }
  }
}

void mainMenu() {
  if (rnButton.getSingleDebouncedPress() && !mainMenuShown) {
    mainMenuShown = true;
    mainMenuSelected = 0;
  }
  if (mainMenuShown) {
    encoder.tick();
    int newPos = encoder.getPosition();
    if (newPos < 0) {
      encoder.setPosition(0);
      newPos = 0;

    } else if (newPos > 5) {
      encoder.setPosition(5);
      newPos = 5;
    }
    if (lastPos != newPos) {
      mainMenuSelected = newPos;
      lcd.clear();
      switch (mainMenuSelected) {
        case 0:
          lcd.setCursor(0, 0);
          lcd.print("~");
          lcd.setCursor(1, 0);
          lcd.print("Play");
          lcd.setCursor(1, 1);
          lcd.print("Pause");
          break;
        case 1:
          lcd.setCursor(0, 0);
          lcd.print("~");
          lcd.setCursor(1, 0);
          lcd.print("Pause");
          lcd.setCursor(1, 1);
          lcd.print("Next");
          break;
        case 2:
          lcd.setCursor(0, 0);
          lcd.print("~");
          lcd.setCursor(1, 0);
          lcd.print("Next");
          lcd.setCursor(1, 1);
          lcd.print("Previous");
          break;
        case 3:
          lcd.setCursor(0, 0);
          lcd.print("~");
          lcd.setCursor(1, 0);
          lcd.print("Previous");
          lcd.setCursor(1, 1);
          lcd.print("Settings");
          break;
        case 4:
          lcd.setCursor(0, 0);
          lcd.print("~");
          lcd.setCursor(1, 0);
          lcd.print("Settings (N/A)");
          lcd.setCursor(1, 1);
          lcd.print("Back");
          break;
        case 5:
          lcd.setCursor(0, 0);
          lcd.print("~");
          lcd.setCursor(1, 0);
          lcd.print("Back");
          break;
        default:
          mainMenuSelected = 0;
          break;
      }
      lastPos = newPos;
    }
    if (rnButton.getSingleDebouncedPress()) {
      switch (mainMenuSelected) {
        case 0:
          a2dp_sink.play();
          mainMenuShown = false;
          break;
        case 1:
          a2dp_sink.pause();
          mainMenuShown = false;
          break;
        case 2:
          a2dp_sink.next();
          mainMenuShown = false;
          break;
        case 3:
          a2dp_sink.previous();
          mainMenuShown = false;
          break;
        case 4:
          break;
        case 5:
          mainMenuShown = false;
          lcd.clear();
          lcd.home();
          lcd.print(songName);
          lcd.setCursor(0, 1);
          lcd.print(songArtist);
          break;
      }
    }
  }
}

Here are some pictures if you need them:



Do You try to tell You want to use the rotary encoder to control the volume? If so, why not use a simple pot?

Tour code is not responsive You tell. There's not any useful information in that.

Know that no helper has Your rigging available and can't test Your code.

Please be more precise in Your information and request.

I have to do the volume first and then use the rotary encoder for other things like menus.

Okey.

As You don't post a datasheet link to just the encoder You use You get no useful answer.

I suggest You startup a little test sketch only reading the encoder. Use example code, maybe code suggested in the datasheet application notes. Else, Google on ESP32 + "Your encoder".

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