#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Fonts/FreeSans18pt7b.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Piny pro tlačítka a analogový vstup na ESP32
#define BUTTON_LEFT_PIN 15
#define BUTTON_RIGHT_PIN 2
#define BUTTON_SELECT_PIN 4
#define FADER_PIN 34
// Konstanty pro nastavení zpoždění a detekci dvojitého stisku
const int NORMAL_DELAY = 150;
const int FAST_DELAY = 15;
const unsigned long HOLD_THRESHOLD = 2000;
const unsigned long DOUBLE_CLICK_TIME = 2000; // 2 sekundy pro dvojklik
enum Mode { NORMAL, MULTI };
Mode currentMode = NORMAL;
int dmxChannel = 1;
byte dmxValue[512] = {0};
int lastFaderValue = -1;
int currentDelay = NORMAL_DELAY;
unsigned long leftButtonPressTime = 0;
unsigned long rightButtonPressTime = 0;
unsigned long selectButtonLastPress = 0;
bool selectButtonFirstClick = false;
int multiViewStartChannel = 1;
void setup() {
Serial.begin(115200);
pinMode(BUTTON_LEFT_PIN, INPUT_PULLUP);
pinMode(BUTTON_RIGHT_PIN, INPUT_PULLUP);
pinMode(BUTTON_SELECT_PIN, INPUT_PULLUP);
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.clearDisplay();
display.display();
updateDisplay();
}
void loop() {
handleModeSwitch();
if (currentMode == NORMAL) {
handleNormalMode();
} else if (currentMode == MULTI) {
handleMultiMode();
}
}
// Funkce pro zpracování režimu NORMAL
void handleNormalMode() {
bool updateNeeded = false;
if (handleButton(BUTTON_LEFT_PIN, leftButtonPressTime)) {
dmxChannel = (dmxChannel <= 1) ? 512 : dmxChannel - 1;
updateNeeded = true;
} else if (handleButton(BUTTON_RIGHT_PIN, rightButtonPressTime)) {
dmxChannel = (dmxChannel >= 512) ? 1 : dmxChannel + 1;
updateNeeded = true;
}
int currentFaderValue = map(analogRead(FADER_PIN), 0, 4095, 0, 255);
if (currentFaderValue != lastFaderValue) {
lastFaderValue = currentFaderValue;
dmxValue[dmxChannel - 1] = currentFaderValue;
updateNeeded = true;
}
if (updateNeeded) {
updateDisplay();
}
}
// Funkce pro zpracování režimu MULTI
void handleMultiMode() {
bool updateNeeded = false;
if (handleButton(BUTTON_LEFT_PIN, leftButtonPressTime)) {
multiViewStartChannel = (multiViewStartChannel <= 5) ? 508 : multiViewStartChannel - 5;
updateNeeded = true;
} else if (handleButton(BUTTON_RIGHT_PIN, rightButtonPressTime)) {
multiViewStartChannel = (multiViewStartChannel >= 508) ? 1 : multiViewStartChannel + 5;
updateNeeded = true;
}
if (updateNeeded) {
updateMultiDisplay();
}
}
// Funkce pro přepínání mezi režimy pomocí dvojitého stisku tlačítka SELECT
void handleModeSwitch() {
if (digitalRead(BUTTON_SELECT_PIN) == LOW) {
Serial.println("LOW");
if (!selectButtonFirstClick) {
Serial.println("FIRST CLICK");
selectButtonFirstClick = true;
selectButtonLastPress = millis();
delay(NORMAL_DELAY);
} else if (millis() - selectButtonLastPress < DOUBLE_CLICK_TIME) {
Serial.println("SECOND CLICK");
currentMode = (currentMode == NORMAL) ? MULTI : NORMAL;
selectButtonFirstClick = false;
selectButtonLastPress -= DOUBLE_CLICK_TIME;
syncChannelsToMode();
(currentMode == NORMAL) ? updateDisplay() : updateMultiDisplay();
delay(NORMAL_DELAY);
}
}
if (selectButtonFirstClick && millis() - selectButtonLastPress > DOUBLE_CLICK_TIME) {
Serial.println("RESET CLICK");
selectButtonFirstClick = false;
selectButtonLastPress -= DOUBLE_CLICK_TIME;
}
}
// Synchronizace kanálu mezi režimy NORMAL a MULTI
void syncChannelsToMode() {
if (currentMode == MULTI) {
multiViewStartChannel = ((dmxChannel - 1) / 5) * 5 + 1; // Nastavení počátečního kanálu pro MULTI režim
} else {
dmxChannel = multiViewStartChannel; // Nastavení kanálu v NORMAL na první kanál zobrazený v MULTI
}
}
// Pomocná funkce pro zpracování tlačítek s detekcí dlouhého stisku
bool handleButton(int buttonPin, unsigned long &pressTime) {
if (digitalRead(buttonPin) == LOW) {
if (pressTime == 0) {
pressTime = millis();
}
if (millis() - pressTime > HOLD_THRESHOLD) {
currentDelay = FAST_DELAY;
}
delay(currentDelay);
return true;
} else {
pressTime = 0;
currentDelay = NORMAL_DELAY;
return false;
}
}
// Funkce pro aktualizaci zobrazení v režimu NORMAL
void updateDisplay() {
display.clearDisplay();
display.setFont(&FreeSans18pt7b);
display.setTextColor(SSD1306_WHITE);
String text = String(dmxChannel);
int16_t x1, y1;
uint16_t width, height;
display.getTextBounds(text, 0, 0, &x1, &y1, &width, &height);
int16_t x = ((SCREEN_WIDTH - width) / 2) - 5;
int16_t y = ((SCREEN_HEIGHT + height) / 2) - 10;
display.setCursor(x, y);
display.println(text);
int rectHeight = 10;
int rectWidth = map(dmxValue[dmxChannel - 1], 0, 255, 0, SCREEN_WIDTH - 4);
display.drawRect(0, SCREEN_HEIGHT - rectHeight - 1, SCREEN_WIDTH, rectHeight, SSD1306_WHITE);
display.fillRect(2, SCREEN_HEIGHT - rectHeight + 1, rectWidth, rectHeight - 4, SSD1306_WHITE);
display.display();
}
// Funkce pro aktualizaci zobrazení v režimu MULTI
void updateMultiDisplay() {
display.clearDisplay();
display.setFont();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
const int rectWidth = 10;
const int displaySpace = 12;
const int displayWidth = SCREEN_WIDTH - displaySpace;
const int spacing = (displayWidth - (rectWidth * 5)) / 4;
for (int i = 0; i < 5; i++) {
int channel = multiViewStartChannel + i;
if (channel > 512) break;
int channelValue = dmxValue[channel - 1];
int rectHeight = map(channelValue, 0, 255, 0, SCREEN_HEIGHT - 12);
int x = (i * (rectWidth + spacing)) + (displaySpace / 2);
display.drawRect(x, 0, rectWidth, SCREEN_HEIGHT - 11, SSD1306_WHITE);
int innerX = x + 2;
int innerWidth = 6;
display.fillRect(innerX, SCREEN_HEIGHT - rectHeight - 10, innerWidth, rectHeight - 3, SSD1306_WHITE);
int cursorChannelShift = (channel < 10) ? 3 : (channel < 100) ? 0 : -3;
display.setCursor(x + cursorChannelShift, SCREEN_HEIGHT - 8);
display.print(channel);
}
display.display();
}