#include <Adafruit_NeoPixel.h> // library for NeoPixels
//#include <Encoder.h> // library for rotary encoder
#include <AiEsp32RotaryEncoder.h>
#include <Arduino.h>
#define ROTARY_ENCODER_A_PIN 22
#define ROTARY_ENCODER_B_PIN 23
#define ENCODER_BTN 18
#define ROTARY_ENCODER_VCC_PIN -1
#define ROTARY_ENCODER_STEPS 4

#define PIN_NEO_PIXEL 16  // Arduino pin that connects to NeoPixel
#define NUM_PIXELS 16 // The number of LEDs (pixels) on NeoPixel
//#define ENCODER_BTN 18 // rotary encoder button pin

AiEsp32RotaryEncoder rotaryEncoder = AiEsp32RotaryEncoder(ROTARY_ENCODER_A_PIN, ROTARY_ENCODER_B_PIN, ENCODER_BTN, ROTARY_ENCODER_VCC_PIN, ROTARY_ENCODER_STEPS);

Adafruit_NeoPixel NeoPixel(NUM_PIXELS, PIN_NEO_PIXEL, NEO_GRB + NEO_KHZ800); // set the NeoPixel ring initialization
//Encoder myEnc(22, 23); // initialize the rotary encoder

///////////////////////////////---------------------------////////////////////////////////
void rotary_onButtonClick()
{
    static unsigned long lastTimePressed = 0; // Soft debouncing
    if (millis() - lastTimePressed < 500)
    {
            return;
    }
    lastTimePressed = millis();
    Serial.print("button pressed ");
    Serial.print(millis());
    Serial.println(" milliseconds after restart");
}

void rotary_loop()
{
    //dont print anything unless value changed
    if (rotaryEncoder.encoderChanged())
    {
            Serial.print("Value: ");
            Serial.println(rotaryEncoder.readEncoder());
    }
    if (rotaryEncoder.isEncoderButtonClicked())
    {
            rotary_onButtonClick();
    }
}


void IRAM_ATTR readEncoderISR()
{
    rotaryEncoder.readEncoder_ISR();
}
///////////////////////////////---------------------------////////////////////////////////


byte color_blue_RGB[3] = {0, 0, 255}; // blue color in RGB color space
byte color_red_RGB[3] = {255, 0, 0}; // red color in RGB color space
byte color_blend_RGB[3]; // variable to store blended RGB color

byte color_blue_HSV[3] = {170, 255, 255}; // blue color in HSV color space
byte color_red_HSV[3] = {0, 255, 255}; // red color in HSV color space
byte color_blend_HSV[3]; // variable to store blended HSV color


int encoder_value_old = 0; // previous value of rotary encoder
int encoder_value_new = 0; // current value of rotary encoder
int percentage_value = 50; // percentage value to fill the ring: 0 - 100%


int mode = 0; // 0 = white, 1 = blue to red RGB, 2 = blue to red HSV


// function to blend between two colors
void blend_colors (byte color_start[3], byte color_end[3], byte color_blended[3], float percentage /*0-100*/) {
  for (int i = 0; i < 3; i ++) {
    // linear interpolation between two values
    color_blended[i] = round((float)color_start[i] + (((float)color_end[i] - (float)color_start[i]) * (percentage / 100.0)));
  }
}

void setup() {
  Serial.begin(115200);
  NeoPixel.begin();  // initialize the NeoPixel strip object
  pinMode(ENCODER_BTN, INPUT_PULLUP); // set pin for rotary encoder button
      

    //we must initialize rotary encoder
    rotaryEncoder.begin();
    rotaryEncoder.setup(readEncoderISR);
    //set boundaries and if values should cycle or not
    //in this example we will set possible values between 0 and 1000;
    bool circleValues = false;
    rotaryEncoder.setBoundaries(-100, 100, circleValues); //minValue, maxValue, circleValues true|false (when max go to min and vice versa)

    /*Rotary acceleration introduced 25.2.2021.
   * in case range to select is huge, for example - select a value between 0 and 1000 and we want 785
   * without accelerateion you need long time to get to that number
   * Using acceleration, faster you turn, faster will the value raise.
   * For fine tuning slow down.
   */
    //rotaryEncoder.disableAcceleration(); //acceleration is now enabled by default - disable if you dont need it
    rotaryEncoder.setAcceleration(250); //or set the value - larger number = more accelearation; 0 or 1 means disabled acceleration
}

void loop() {


Serial.print(percentage_value);
  // read the new value of rotary encoder
  //encoder_value_new = myEnc.read(); // read the encoder value
  //in loop call your custom function which will process rotary encoder values
    encoder_value_new = rotaryEncoder.readEncoder();
    delay(50); //or do whatever you need to do...
  if (encoder_value_new != encoder_value_old) { // if the old value does not equal the new value
    percentage_value = constrain(percentage_value - (encoder_value_new - encoder_value_old), 0, 100); // set the percentage value between 0-100%
    encoder_value_old = encoder_value_new; // update the old encoder value
  }


  if (digitalRead(ENCODER_BTN) == LOW) {
    // switch the mode
    mode++;
    if (mode > 2) {
      mode = 0;
    }
    delay(500); // add a small delay
  }

  NeoPixel.clear();  // set all pixel colors to 'off'. It only takes effect if pixels.show() is called

  // go over every single pixel on the neopixel ring
  for (int pixel = 0; pixel < NUM_PIXELS; pixel++) {  // for each pixel
    if ((pixel * (100 / (NUM_PIXELS - 1))) < percentage_value) { // fill pixels based on the rotary encoder value
      if (mode == 0) { // draw white pixels
        // set pixels to WHITE color
        NeoPixel.setPixelColor(pixel, NeoPixel.Color(255, 255, 255));  // set all pixels to white color

      } else if (mode == 1) { // blend between blue and red in RGB
        // blend two colors in RGB color space
        blend_colors(color_blue_RGB, color_red_RGB, color_blend_RGB, pixel * (100.0 / (NUM_PIXELS - 1)));
        // set the pixel to the blended color
        NeoPixel.setPixelColor(pixel, NeoPixel.Color(color_blend_RGB[0], color_blend_RGB[1], color_blend_RGB[2]));

      } else if (mode == 2) { // blend between blue and red in HSV
        // blend two colors in HSV color space
        blend_colors(color_blue_HSV, color_red_HSV, color_blend_HSV, pixel * (100.0 / (NUM_PIXELS - 1)));
        // set the pixel to the blended color
        NeoPixel.setPixelColor(pixel, NeoPixel.ColorHSV((unsigned int)color_blend_HSV[0] * 256, color_blend_HSV[1], color_blend_HSV[2]));

      }
    }
  }

  //NeoPixel.setBrightness(50);  // don´t forget to uncomment this line for real Arduino to make it less bright
  NeoPixel.show(); // show all the set pixels on neopixel ring
}
esp:0
esp:2
esp:4
esp:5
esp:12
esp:13
esp:14
esp:15
esp:16
esp:17
esp:18
esp:19
esp:21
esp:22
esp:23
esp:25
esp:26
esp:27
esp:32
esp:33
esp:34
esp:35
esp:3V3
esp:EN
esp:VP
esp:VN
esp:GND.1
esp:D2
esp:D3
esp:CMD
esp:5V
esp:GND.2
esp:TX
esp:RX
esp:GND.3
esp:D1
esp:D0
esp:CLK
ring1:GND
ring1:VCC
ring1:DIN
ring1:DOUT
encoder1:CLK
encoder1:DT
encoder1:SW
encoder1:VCC
encoder1:GND