/*
* This ESP32 code is created by esp32io.com
*
* This ESP32 code is released in the public domain
*
* For more detail (instruction and wiring diagram), visit https://esp32io.com/tutorials/esp32-rotary-encoder
*/
#include <ezButton.h> // the library to use for SW pin
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED width, in pixels
#define SCREEN_HEIGHT 64 // OLED height, in pixels
// create an OLED display object connected to I2C
Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Color definitions
// #define BLACK 0x0000
// #define BLUE 0x001F
// #define RED 0xF800
// #define GREEN 0x07E0
// #define CYAN 0x07FF
// #define MAGENTA 0xF81F
// #define YELLOW 0xFFE0
// #define WHITE 0xFFFF
#define CLK_PIN 25 // ESP32 pin GPIO25 connected to the rotary encoder's CLK pin
#define DT_PIN 26 // ESP32 pin GPIO26 connected to the rotary encoder's DT pin
#define SW_PIN 27 // ESP32 pin GPIO27 connected to the rotary encoder's SW pin
// Relay Channel Pins
#define ch1pin 4
#define ch2pin 13
#define ch3pin 33
#define ch4pin 32
#define fanpin 16
#define DIRECTION_CW 0 // clockwise direction
#define DIRECTION_CCW 1 // counter-clockwise direction
// Var Declaration
int btncounter = 0;
int btncounterlimit = 5;
const char* modeList[] = {"Fan", "Light1", "Light2", "Light3", "Light4"};
// levels of the Mode...
int level_Fan = 0;
int level_Light1 = 0;
int level_Light2 = 0;
int level_Light3 = 0;
int level_Light4 = 0;
// Min
int minlevel_Fan = 0;
int minlevel_Light1 = 0;
int minlevel_Light2 = 0;
int minlevel_Light3 = 0;
int minlevel_Light4 = 0;
// Max
int maxlevel_Fan = 5;
int maxlevel_Light1 = 1;
int maxlevel_Light2 = 1;
int maxlevel_Light3 = 1;
int maxlevel_Light4 = 1;
int counter = 0;
int direction = DIRECTION_CW;
int CLK_state;
int prev_CLK_state;
ezButton button(SW_PIN); // create ezButton object that attach to pin 7;
// Custome Function
void adjustLevel(int& level, int minLevel, int maxLevel, int direction, int btncounter) {
if (direction == DIRECTION_CW && level < maxLevel) {
level++;
} else if (direction == DIRECTION_CCW && level > minLevel) {
level--;
}
// Access the mode from the list
const char* selectedMode = modeList[btncounter];
Serial.print(selectedMode);Serial.print(" Level: ");Serial.println(level);
}
void displayModeInfo(int btncounter, int level) {
oled.clearDisplay();
oled.setTextSize(1); // Normal 1:1 pixel scale
// Customize text color or other display features based on mode and level
// For illustration purposes, using fixed colors based on level
// if (level <= 1) {
// oled.setTextColor(WHITE);
// } else if (level <= 2) {
// oled.setTextColor(WHITE);
// } else if (level <= 3) {
// oled.setTextColor(WHITE);
// } else {
// oled.setTextColor(WHITE);
// }
// Access the mode from the list
const char* selectedMode = modeList[btncounter];
Serial.print(selectedMode);Serial.print(" Level: ");Serial.println(level);
oled.setCursor(30, 0); // Start at top-left corner
oled.println(F("Haptic Knob"));
oled.println("");
oled.print("Mode: ");
oled.println(selectedMode);
oled.println("");
oled.println("");
oled.print("Level: ");
oled.println(level);
oled.display();
}
void setup() {
Serial.begin(9600);
// configure encoder pins as inputs
pinMode(CLK_PIN, INPUT);
pinMode(DT_PIN, INPUT);
button.setDebounceTime(50); // set debounce time to 50 milliseconds
// read the initial state of the rotary encoder's CLK pin
prev_CLK_state = digitalRead(CLK_PIN);
// initialize OLED display with I2C address 0x3C
if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3c)) {
Serial.println(F("failed to start SSD1306 OLED"));
while (1);
}
delay(2000); // wait two seconds for initializing
oled.clearDisplay(); // clear display
oled.setTextSize(1); // set text size
oled.setTextColor(WHITE); // set text color
oled.setCursor(0, 2); // set position to display (x,y)
oled.println("Haptic Knob"); // set text
oled.display(); // display on OLED
// Relay Chennel Pin Mode declaration
pinMode(ch1pin, OUTPUT); // Set the pin as an output
pinMode(ch2pin, OUTPUT); // Set the pin as an output
pinMode(ch3pin, OUTPUT); // Set the pin as an output
pinMode(ch4pin, OUTPUT); // Set the pin as an output
pinMode(fanpin, OUTPUT); // Set the pin as an output
Serial.println("Setup Done !!!");
displayModeInfo(btncounter, level_Fan);
delay(100);
}
void loop() {
button.loop(); // MUST call the loop() function first
// read the current state of the rotary encoder's CLK pin
CLK_state = digitalRead(CLK_PIN);
// If the state of CLK is changed, then pulse occurred
// React to only the rising edge (from LOW to HIGH) to avoid double count
if (CLK_state != prev_CLK_state && CLK_state == HIGH) {
// if the DT state is HIGH
// the encoder is rotating in counter-clockwise direction => decrease the counter
if (digitalRead(DT_PIN) == HIGH) {
counter--;
direction = DIRECTION_CCW;
} else {
// the encoder is rotating in clockwise direction => increase the counter
counter++;
direction = DIRECTION_CW;
}
// const char* modeList[] = {"Fan", "Light1", "Light2"};
// Serial.print("Rotary Encoder:: direction: ");
// if (direction == DIRECTION_CW){Serial.print("Clockwise");}
// else{Serial.print("Counter-clockwise");}
if (btncounter == 0){
// Adjust the level for the current mode
adjustLevel(level_Fan, minlevel_Fan, maxlevel_Fan, direction, btncounter);
// Serial.print("Fan Level: ");Serial.println(level_Fan);
displayModeInfo(btncounter, level_Fan);
// digitalWrite(ch1pin, HIGH);
}
if (btncounter == 1){
// Adjust the level for the current mode
adjustLevel(level_Light1, minlevel_Light1, maxlevel_Light1, direction, btncounter);
// Serial.print("level_Light1 Level: ");Serial.println(level_Light1);
displayModeInfo(btncounter, level_Light1);
}
if (btncounter == 2){
// Adjust the level for the current mode
adjustLevel(level_Light2, minlevel_Light2, maxlevel_Light2, direction, btncounter);
// Serial.print("level_Light2 Level: ");Serial.println(level_Light2);
displayModeInfo(btncounter, level_Light2);
}
if (btncounter == 3){
// Adjust the level for the current mode
adjustLevel(level_Light3, minlevel_Light3, maxlevel_Light3, direction, btncounter);
// Serial.print("level_Light2 Level: ");Serial.println(level_Light2);
displayModeInfo(btncounter, level_Light3);
}
if (btncounter == 4){
// Adjust the level for the current mode
adjustLevel(level_Light4, minlevel_Light4, maxlevel_Light4, direction, btncounter);
// Serial.print("level_Light2 Level: ");Serial.println(level_Light2);
displayModeInfo(btncounter, level_Light4);
}
// FAN
analogWrite(fanpin, level_Fan * 64); // Adjust LED brightness based on dim level
// Relay channels
digitalWrite(ch1pin, level_Light1);
digitalWrite(ch2pin, level_Light2);
digitalWrite(ch3pin, level_Light3);
digitalWrite(ch4pin, level_Light4);
// Adjust the counter for the next mode
// btncounter = (btncounter + 1) % btncounterlimit;
// Serial.print(" - count: ");Serial.println(counter);
}
// save last CLK state
prev_CLK_state = CLK_state;
// Simulate button press
if (button.isPressed()) {
Serial.println("btn pressed");
btncounter++;
if (btncounter >= btncounterlimit) {btncounter = 0;}
// Serial.print("Mode : "); Serial.println(btncounter);
const char* selectedMode = modeList[btncounter];
Serial.print("Selected Mode: "); Serial.println(selectedMode);
if (btncounter == 0){displayModeInfo(btncounter, level_Fan);}
if (btncounter == 1){displayModeInfo(btncounter, level_Light1);}
if (btncounter == 2){displayModeInfo(btncounter, level_Light2);}
if (btncounter == 3){displayModeInfo(btncounter, level_Light3);}
if (btncounter == 4){displayModeInfo(btncounter, level_Light4);}
}
}