// arduino-relay-oled-control.ino
// This code controls a relay and an OLED display with a single push button.
// It features two modes of operation:
// 1. A short press keeps the relay on continuously until the button is released.
// 2. A long press (held for > 1 second) triggers a series of four 1-second pulses,
// and then keeps the relay on until the button is released. During this time,
// a stopwatch is shown on the OLED display. When the button is released,
// the final stopwatch value remains on the display.
// --- Library Includes ---
// Required libraries for the SSD1306 OLED display.
// You must install these from the Arduino Library Manager.
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// --- Pin Definitions ---
// Change these constants to match your hardware setup.
const int RELAY_PIN = 7; // The digital pin connected to the relay signal wire.
const int BUTTON_PIN = 2; // The digital pin connected to the push button.
// OLED display settings. The SSD1306 is an I2C device.
#define OLED_RESET 4
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// --- State Variables ---
// These variables track the current state of the button, relay, and display.
int lastButtonState = HIGH; // The previous state of the button.
long lastDebounceTime = 0; // The last time the button state was changed.
long debounceDelay = 50; // Debounce time in milliseconds.
bool buttonState = HIGH; // The current state of the button.
bool isPulsing = false; // A flag to check if the pulsing mode is active.
unsigned long lastPulseTime = 0; // The last time a pulse started.
int pulseCount = 0; // The number of pulses completed.
unsigned long lastPressTime = 0; // The last time the button was pressed down.
const int longPressThreshold = 1000; // Threshold for a long press in milliseconds.
bool longPressTriggered = false; // Flag to ensure the long press action only triggers once.
unsigned long stopwatchStartTime = 0; // Time when the long press started for the stopwatch.
// --- Functions ---
void setup() {
// Initialize the pins.
pinMode(RELAY_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP); // Use internal pull-up resistor.
// Start with the relay off.
digitalWrite(RELAY_PIN, HIGH); // Many relay modules are 'active low', so HIGH turns it off.
Serial.begin(9600); // For debugging purposes.
Serial.println("Arduino Relay and OLED Control Initialized.");
// Initialize the OLED display.
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x64 display
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Don't proceed, loop forever
}
display.display(); // Show the initial Adafruit splash screen.
delay(2000);
display.clearDisplay(); // Clear the buffer.
}
void loop() {
// Read the state of the button.
int reading = digitalRead(BUTTON_PIN);
// --- Button Debouncing Logic ---
// Debouncing prevents false button presses due to mechanical jitter.
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// If the button state has been stable for longer than the debounce delay.
if (reading != buttonState) {
buttonState = reading;
// --- Button Press & Release Detection ---
if (buttonState == LOW) { // The button is pressed (LOW due to INPUT_PULLUP).
Serial.println("Button pressed.");
lastPressTime = millis();
longPressTriggered = false; // Reset the long press flag.
isPulsing = false;
pulseCount = 0;
display.clearDisplay(); // Clear the display on a new press.
} else { // The button is released (HIGH).
Serial.println("Button released.");
// The relay is turned off on release.
digitalWrite(RELAY_PIN, HIGH);
// This is the core logic for the button release.
if (!longPressTriggered) {
// This is a short press, relay on until release.
Serial.println("Short press detected. Relay is on until release.");
digitalWrite(RELAY_PIN, LOW); // Turn the relay on.
delay(100); // Brief delay for short pulse effect
digitalWrite(RELAY_PIN, HIGH); // Turn off after a very short time
display.clearDisplay();
display.display();
} else {
// This is a long press release, keep the final time on the display.
unsigned long finalSeconds = (millis() - stopwatchStartTime) / 1000;
display.clearDisplay();
display.setTextSize(2); // Set text size to 2
display.setTextColor(SSD1306_WHITE); // Set text color to white
display.setCursor(0, 0);
display.println("Brew Time:");
display.setTextSize(4);
display.setCursor(40, 30);
display.print(finalSeconds);
display.display();
}
}
}
}
// --- Long Press Detection & Action ---
if (buttonState == LOW && (millis() - lastPressTime) >= longPressThreshold) {
if (!longPressTriggered) {
Serial.println("Long press detected. Starting 4 pulses.");
isPulsing = true;
pulseCount = 0;
lastPulseTime = millis();
longPressTriggered = true; // Set the flag to true so this only triggers once.
stopwatchStartTime = millis(); // Start the stopwatch.
}
}
// --- Pulsing Mode (Long press) ---
if (isPulsing) {
// A simple non-blocking timer for a 1-second pulse.
if (millis() - lastPulseTime >= 1000) { // 1000 milliseconds = 1 second
if (pulseCount < 4) {
// Toggle the relay state to create a pulse.
digitalWrite(RELAY_PIN, !digitalRead(RELAY_PIN));
Serial.print("Pulse #");
Serial.print(pulseCount + 1);
Serial.println(" - ON/OFF");
lastPulseTime = millis();
// Increment the pulse count on the falling edge of the pulse.
if (digitalRead(RELAY_PIN) == HIGH) {
pulseCount++;
}
} else {
// All four pulses are done, but the button is still being pressed.
isPulsing = false;
}
}
}
// --- Sustained 'ON' after Pulsing and Stopwatch Display (Long press) ---
// If a long press was triggered and the button is still held down, show stopwatch.
if (longPressTriggered && buttonState == LOW) {
digitalWrite(RELAY_PIN, LOW);
// Display the stopwatch time without decimals.
unsigned long elapsedTime = millis() - stopwatchStartTime;
unsigned long seconds = elapsedTime / 1000;
display.clearDisplay();
display.setTextSize(2); // Set text size to 2
display.setTextColor(SSD1306_WHITE); // Set text color to white
display.setCursor(0, 0);
display.println("BREWING...");
display.setTextSize(4);
display.setCursor(40, 30);
display.print(seconds);
display.display();
}
// Update the last button state for the next loop.
lastButtonState = reading;
}