#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_NeoPixel.h>
#include <DFPlayerMini_Fast.h>
#include <WiFi.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
#define OLED_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
HardwareSerial dfSerial(2); // Use Serial2
DFPlayerMini_Fast myDFPlayer;
// === PINS ===
#define POT1_PIN 27
#define POT2_PIN 26
#define POT3_PIN 25
#define RELAY1_PIN 4
#define RELAY2_PIN 5
#define RELAY3_PIN 18
#define PIXEL_PIN 33
#define NUM_PIXELS 6
#define RESET_BUTTON 32
#define CONNECT_BUTTON 35
#define SHOWDUINO_RX 19
#define SHOWDUINO_TX 23
HardwareSerial ShowduinoSerial(1);
const char* ssid = "GoreFX_Network";
const char* password = "showduino123";
// === SETTINGS ===
#define TOLERANCE 2
#define TARGET1 25
#define TARGET2 50
#define TARGET3 75
Adafruit_NeoPixel pixels(NUM_PIXELS, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
// States
bool triggered1 = false, triggered2 = false, triggered3 = false;
bool pot1Moved = false, pot2Moved = false, pot3Moved = false;
int lastVal1 = -1, lastVal2 = -1, lastVal3 = -1;
bool connectedToShowduino = false;
void setup() {
Serial.begin(115200);
Wire.begin(21, 22); // SDA, SCL
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) {
Serial.println(F("❌ OLED failed to start"));
} else {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
// Helper function: returns width of a string at current text size
auto getCenteredX = [](const String& text) {
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
return (SCREEN_WIDTH - w) / 2;
};
// Line positions (manual Y spacing)
display.setCursor(getCenteredX("Showduino"), 0);
display.println("Showduino");
display.setCursor(getCenteredX("2025"), 9);
display.println("2025");
display.setCursor(getCenteredX("ver 0.2"), 18);
display.println("ver 0.2");
display.setCursor(getCenteredX("R3 Terminal"), 27);
display.println("R3 Terminal");
display.display();
}
pixels.begin();
pixels.clear();
pixels.setPixelColor(5, pixels.Color(0, 255, 0));
pixels.show();
ShowduinoSerial.begin(9600, SERIAL_8N1, SHOWDUINO_RX, SHOWDUINO_TX);
pinMode(CONNECT_BUTTON, INPUT_PULLUP);
pinMode(RESET_BUTTON, INPUT_PULLUP);
pinMode(RELAY1_PIN, OUTPUT);
pinMode(RELAY2_PIN, OUTPUT);
pinMode(RELAY3_PIN, OUTPUT);
digitalWrite(RELAY1_PIN, LOW);
digitalWrite(RELAY2_PIN, LOW);
digitalWrite(RELAY3_PIN, LOW);
WiFi.mode(WIFI_STA);
dfSerial.begin(9600, SERIAL_8N1, 16, 17);
if (!myDFPlayer.begin(dfSerial)) {
Serial.println("❌ DFPlayer not responding!");
} else {
Serial.println(" DFPlayer Ready!");
myDFPlayer.volume(25);
myDFPlayer.play(1);
display.clearDisplay();
display.setCursor(0, 0);
display.println(" DFPlayer Ready!");
display.display();
}
}
void loop() {
checkShowduinoCommands();
display.clearDisplay();
display.setCursor(0, 0);
display.println("R3 Terminal ");
display.println("standalone");
display.display();
int val1 = analogRead(POT1_PIN) / 41;
int val2 = analogRead(POT2_PIN) / 41;
int val3 = analogRead(POT3_PIN) / 41;
if (!pot1Moved && val1 != lastVal1) pot1Moved = true;
if (!pot2Moved && val2 != lastVal2) pot2Moved = true;
if (!pot3Moved && val3 != lastVal3) pot3Moved = true;
if (val1 != lastVal1 || val2 != lastVal2 || val3 != lastVal3) {
Serial.printf("Pot1: %d | Pot2: %d | Pot3: %d\n", val1, val2, val3);
lastVal1 = val1;
lastVal2 = val2;
lastVal3 = val3;
}
updatePixel(val1, TARGET1, 2, triggered1, pot1Moved);
updatePixel(val2, TARGET2, 1, triggered2, pot2Moved);
updatePixel(val3, TARGET3, 0, triggered3, pot3Moved);
if (!triggered1 && withinTolerance(val1, TARGET1)) {
digitalWrite(RELAY1_PIN, HIGH);
triggered1 = true;
Serial.println("✅ Relay 1 ON");
display.clearDisplay();
display.setCursor(0, 0);
display.println(" Relay 1 Triggered");
display.display();
}
if (!triggered2 && withinTolerance(val2, TARGET2)) {
digitalWrite(RELAY2_PIN, HIGH);
triggered2 = true;
Serial.println("✅ Relay 2 ON");
display.clearDisplay();
display.setCursor(0, 0);
display.println(" Relay 2 Triggered");
display.display();
}
if (!triggered3 && withinTolerance(val3, TARGET3)) {
digitalWrite(RELAY3_PIN, HIGH);
triggered3 = true;
Serial.println("✅ Relay 3 ON");
display.clearDisplay();
display.setCursor(0, 0);
display.println(" Relay 3 Triggered");
display.display();
}
static int fxStep = 0;
static unsigned long fxTime = 0;
if (millis() - fxTime > (triggered1 && triggered2 && triggered3 ? 100 : 200)) {
pixels.setPixelColor(3, 0);
pixels.setPixelColor(4, 0);
pixels.setPixelColor(5, 0);
uint32_t color = (triggered1 && triggered2 && triggered3) ? pixels.Color(0, 255, 0) : pixels.Color(0, 0, 255);
pixels.setPixelColor(3 + fxStep, color);
pixels.show();
fxStep = (fxStep + 1) % 3;
fxTime = millis();
}
static bool wasPressed = false;
if (digitalRead(CONNECT_BUTTON) == LOW) {
if (!wasPressed && !connectedToShowduino) {
wasPressed = true;
Serial.println("🔌 Connecting to Showduino...");
attemptShowduinoConnect();
}
} else {
wasPressed = false;
}
if (digitalRead(RESET_BUTTON) == LOW) {
triggerReset();
delay(1500);
return;
}
delay(100);
}
bool withinTolerance(int val, int target) {
return (val >= target - TOLERANCE && val <= target + TOLERANCE);
}
void updatePixel(int val, int target, int pixel, bool triggered, bool hasMoved) {
if (!hasMoved) {
pixels.setPixelColor(pixel, 0); // Keep OFF
} else if (triggered) {
pixels.setPixelColor(pixel, pixels.Color(0, 255, 0)); // Solid green
} else {
int diff = abs(val - target);
int g = map(constrain(100 - diff, 0, 100), 0, 100, 0, 255);
pixels.setPixelColor(pixel, pixels.Color(0, g, 0));
}
pixels.show();
}
void attemptShowduinoConnect() {
WiFi.begin(ssid, password);
Serial.println("🔌 Attempting connection to Showduino...");
display.clearDisplay();
display.setCursor(0, 0);
display.println(" showduino attatch");
display.display();
unsigned long animStart = millis();
int dotCount = 0;
while (millis() - animStart < 10000 && WiFi.status() != WL_CONNECTED) {
display.clearDisplay();
display.setCursor(0, 0);
display.print("Showduino attach");
for (int i = 0; i < dotCount; i++) {
display.print(".");
}
display.display();
dotCount = (dotCount + 1) % 3; // 0 to 3 dots
delay(300);
}
unsigned long startAttempt = millis();
bool connecting = true;
bool ledState = false;
unsigned long lastBlink = 0;
while (connecting && millis() - startAttempt < 10000) {
if (WiFi.status() == WL_CONNECTED) {
connectedToShowduino = true;
Serial.println("✅ Connected to Showduino!");
pixels.setPixelColor(5, pixels.Color(0, 255, 0));
pixels.show();
display.clearDisplay();
display.setCursor(0, 0);
display.println(" Connected to");
display.println("Showduino!");
display.display();
return;
}
pixels.clear();
if (millis() - lastBlink > 300) {
ledState = !ledState;
pixels.setPixelColor(5, ledState ? pixels.Color(0, 0, 255) : 0);
pixels.show();
lastBlink = millis();
}
}
WiFi.disconnect(true);
connectedToShowduino = false;
Serial.println("\n❌ Failed to connect to Showduino");
display.clearDisplay();
display.setCursor(0, 0);
display.println(" WiFi Failed");
display.println("Standalone Mode");
display.display();
for (int i = 0; i < 3; i++) {
pixels.setPixelColor(5, pixels.Color(255, 0, 0));
pixels.show();
delay(200);
pixels.setPixelColor(5, 0);
pixels.show();
delay(200);
}
}
String incomingCmd = "";
void handleCommand(String cmd) {
if (cmd == "PLAY:001") myDFPlayer.play(1);
else if (cmd == "PLAY:002") myDFPlayer.play(2);
else if (cmd == "PLAY:003") myDFPlayer.play(3);
else if (cmd == "PLAY:004") myDFPlayer.play(4);
else if (cmd == "PLAY:005") myDFPlayer.play(5);
else if (cmd == "RELAY1_ON") digitalWrite(RELAY1_PIN, HIGH);
else if (cmd == "RELAY1_OFF") digitalWrite(RELAY1_PIN, LOW);
else if (cmd == "RELAY2_ON") digitalWrite(RELAY2_PIN, HIGH);
else if (cmd == "RELAY2_OFF") digitalWrite(RELAY2_PIN, LOW);
else if (cmd == "RELAY3_ON") digitalWrite(RELAY3_PIN, HIGH);
else if (cmd == "RELAY3_OFF") digitalWrite(RELAY3_PIN, LOW);
else if (cmd == "PIXEL_ALL_RED") {
for (int i = 0; i < NUM_PIXELS; i++) pixels.setPixelColor(i, pixels.Color(255, 0, 0));
pixels.show();
}
else if (cmd == "RESET") {
triggerReset();
}
else {
Serial.println("❓ Unknown command: " + cmd);
}
}
void checkShowduinoCommands() {
if (ShowduinoSerial.available()) {
String command = ShowduinoSerial.readStringUntil('\n');
command.trim();
Serial.println("📨 From Showduino: " + command);
handleCommand(command);
}
}
void triggerReset() {
triggered1 = triggered2 = triggered3 = false;
pot1Moved = pot2Moved = pot3Moved = false;
digitalWrite(RELAY1_PIN, LOW);
digitalWrite(RELAY2_PIN, LOW);
digitalWrite(RELAY3_PIN, LOW);
pixels.clear();
pixels.setPixelColor(5, pixels.Color(0, 255, 255));
pixels.show();
display.clearDisplay();
display.setCursor(0, 0);
display.println("🔁 System Reset");
display.display();
Serial.println("🔁 System Reset");
}