FluxBench.AIShared project · read-only

RTC Alarm Clock

ESP32 DevKit (WROOM-32)·Arduino C++·Updated Jul 27, 2026·by FluxBench TeamIncludes Lab + Schematic

A real alarm clock built on the DS3231 real-time clock: an SSD1306 OLED shows the date, big zero-padded HH:MM:SS time and the alarm status, and a piezo buzzer on GPIO 4 beeps at 1600 Hz when the alarm fires. The simulator RTC starts at 12:00:00, so the alarm (12:00:15) rings 15 seconds after you press Run — then click the bench push button (GPIO 14) to snooze it for 20 seconds, or click it while quiet to toggle the alarm on/off. Comments in the sketch show the two lines to change for real hardware: set the RTC from the compile time, and use a 5-minute snooze.

sketch.ino
// RTC Alarm Clock - DS3231 real-time clock, OLED face, buzzer + snooze button
// ESP32 DevKit v1. DS3231 @0x68 and SSD1306 @0x3C share the I2C bus
// (SDA=21, SCL=22). Buzzer on GPIO 4, snooze/enable button on GPIO 14.
//
// In the Lab simulator the DS3231 starts at 12:00:00, so the demo alarm is
// set for 12:00:15 - it rings 15 seconds after you press Run. While it rings,
// click the bench button to snooze (+20 s). When it is quiet, the button
// toggles the alarm on/off. On real hardware you would set alarmHour/alarmMin
// to a real wake-up time and let rtc.adjust() sync the clock once.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <RTClib.h>

#define BUZZER_PIN 4
#define SNOOZE_PIN 14

RTC_DS3231 rtc;
Adafruit_SSD1306 display(128, 64, &Wire, -1);

// Demo alarm time (simulator clock starts at 12:00:00)
int alarmHour = 12;
int alarmMinute = 0;
int alarmSecond = 15;

bool alarmEnabled = true;
bool ringing = false;
bool beepOn = false;
unsigned long lastBeepToggle = 0;
unsigned long lastDraw = 0;
int lastButton = HIGH;
long snoozeUntil = -1;  // unixtime when a snooze ends (-1 = none)

void startRinging() {
  ringing = true;
  Serial.println("ALARM! Press the button to snooze (+20 s).");
}

void stopRinging() {
  ringing = false;
  beepOn = false;
  noTone(BUZZER_PIN);
}

void setup() {
  Serial.begin(115200);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(SNOOZE_PIN, INPUT_PULLUP);
  Wire.begin();
  rtc.begin();
  // On real hardware, uncomment once to set the clock from build time:
  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.display();
  Serial.println("RTC Alarm Clock ready - alarm set for 12:00:15");
}

void loop() {
  DateTime now = rtc.now();
  long t = now.unixtime();

  // ---- alarm trigger ----
  bool atAlarm = (now.hour() == alarmHour && now.minute() == alarmMinute && now.second() == alarmSecond);
  bool atSnooze = (snoozeUntil >= 0 && t >= snoozeUntil);
  if (alarmEnabled && !ringing && (atAlarm || atSnooze)) {
    snoozeUntil = -1;
    startRinging();
  }

  // ---- button: snooze while ringing, enable/disable while quiet ----
  int btn = digitalRead(SNOOZE_PIN);
  if (btn == LOW && lastButton == HIGH) {  // falling edge = press
    if (ringing) {
      stopRinging();
      snoozeUntil = t + 20;  // snooze 20 s (use +300 for 5 min on hardware)
      Serial.println("Snoozed for 20 seconds...");
    } else {
      alarmEnabled = !alarmEnabled;
      if (!alarmEnabled) snoozeUntil = -1;
      Serial.print("Alarm ");
      Serial.println(alarmEnabled ? "ENABLED" : "DISABLED");
    }
  }
  lastButton = btn;

  // ---- beeper: 1600 Hz, 250 ms on / 250 ms off while ringing ----
  if (ringing && millis() - lastBeepToggle >= 250) {
    lastBeepToggle = millis();
    beepOn = !beepOn;
    if (beepOn) tone(BUZZER_PIN, 1600);
    else noTone(BUZZER_PIN);
  }

  // ---- OLED clock face, redrawn 4x per second ----
  if (millis() - lastDraw >= 250) {
    lastDraw = millis();
    char buf[16];
    display.clearDisplay();

    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    sprintf(buf, "%04d-%02d-%02d", now.year(), now.month(), now.day());
    display.print(buf);

    display.setTextSize(2);
    display.setCursor(16, 20);
    sprintf(buf, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
    display.print(buf);

    display.setTextSize(1);
    display.setCursor(0, 48);
    if (ringing) {
      display.print("WAKE UP! btn=snooze");
    } else if (snoozeUntil >= 0) {
      sprintf(buf, "Snooze %lds", snoozeUntil - t);
      display.print("Zzz... ");
      display.print(buf);
    } else if (alarmEnabled) {
      sprintf(buf, "Alarm %02d:%02d:%02d", alarmHour, alarmMinute, alarmSecond);
      display.print(buf);
    } else {
      display.print("Alarm off");
    }
    display.display();
  }

  delay(20);
}

Built with FluxBench.AI — the AI workbench for embedded projects.