7.7 Alarm Clock

In this project, you will build a Wi-Fi-connected alarm clock using the NULA MINI, a Qwiic 16×2 LCD display, two buttons, and a passive buzzer.
The NULA MINI connects to your Wi-Fi network, retrieves the current time from an NTP server, and displays it on the LCD.
You can use the two buttons to set the alarm hour and minute. When the set time matches the current time, the buzzer plays a tone until a button is pressed.
This project demonstrates how to combine Wi-Fi networking, time synchronization, LCD output, and button input in one practical example.
In this documentation you will learn:
- How to get accurate real-time data using NTP (Network Time Protocol).
- How to display dynamic text on a Qwiic LCD using the Soldered LCD library.
- How to use buttons with external resistors and proper debouncing.
- How to control a passive buzzer using
tone()andnoTone().
Hardware required
- 1× Soldered NULA MINI board
- 1× Soldered Qwiic 16×2 LCD display
- 2× Push buttons
- 2× 10 kΩ resistors
- 1× Passive buzzer
- Breadboard
- Jumper wires
- Qwiic cable
- USB-C cable

How it works
When powered on, the NULA MINI connects to your Wi-Fi network and retrieves the current time from the NTP (Network Time Protocol) server pool.ntp.org.
The LCD shows both the current time and the alarm time that you can set with two buttons:
- Button 1: Increments the hour.
- Button 2: Increments the minute.
Each button uses external pull-down resistors and a debounce timer to ensure accurate readings.
When the clock time matches your set alarm time, the passive buzzer generates a repeating tone until you press any button to stop it.

Wiring and connections
| Component | NULA MINI Pin | Description |
|---|---|---|
| Qwiic LCD | Qwiic port | Displays time and alarm settings |
| Button 1 (Hour) | IO2 | Increments alarm hour (active HIGH) |
| Button 2 (Minute) | IO3 | Increments alarm minute (active HIGH) |
| Buzzer (passive) | IO4 | Outputs tone using tone() function |
| 10 kΩ resistor (x2) | IO2→GND, IO3→GND | External pull-down resistors for stable button readings |
| 3.3V / GND | — | Power and ground connections |

Full code
Below is the full example code for this project:
#include "LCD-SOLDERED.h"
#include <WiFi.h>
#include <time.h>
const char* WIFI_SSID = "your ssid";
const char* WIFI_PASS = "your password";
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 0; // Adjust to your timezone
const int daylightOffset_sec = 0; // Set to 3600 if you have DST
LCD lcd(16, 2); // Qwiic 16x2 LCD
const int BUTTON_HOUR = 2; // Hour set button
const int BUTTON_MIN = 3; // Minute set button
const int BUZZER_PIN = 4; // Passive buzzer pin
int alarmHour = 7;
int alarmMinute = 0;
bool alarmTriggered = false;
// Debounce logic
bool lastHourState = LOW;
bool lastMinState = LOW;
unsigned long lastHourChangeMs = 0;
unsigned long lastMinChangeMs = 0;
const unsigned long debounceMs = 25;
unsigned long lastSync = 0;
const unsigned long syncInterval = 60000; // Sync every 60 seconds
void getLocalTimeData(struct tm *timeinfo) {
if (!getLocalTime(timeinfo)) {
Serial.println("Failed to obtain time from NTP");
}
}
// Play tone on passive buzzer
void beepAlarm() {
for (int i = 0; i < 5; i++) {
tone(BUZZER_PIN, 1000); // 1 kHz tone
delay(300);
noTone(BUZZER_PIN);
delay(100);
}
}
void setup() {
Serial.begin(115200);
lcd.begin();
lcd.backlight();
pinMode(BUZZER_PIN, OUTPUT);
pinMode(BUTTON_HOUR, INPUT); // external pull-down
pinMode(BUTTON_MIN, INPUT); // external pull-down
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Connecting WiFi");
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected!");
lcd.clear();
lcd.print("WiFi connected");
delay(1000);
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
lcd.clear();
lcd.print("Time synced!");
delay(1000);
lcd.clear();
}
void loop() {
struct tm timeinfo;
getLocalTimeData(&timeinfo);
// Display current time
char timeStr[6];
sprintf(timeStr, "%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
lcd.setCursor(0, 0);
lcd.print("Time: ");
lcd.print(timeStr);
// Display alarm
lcd.setCursor(0, 1);
lcd.print("Alarm ");
if (alarmHour < 10) lcd.print("0");
lcd.print(alarmHour);
lcd.print(":");
if (alarmMinute < 10) lcd.print("0");
lcd.print(alarmMinute);
// Handle hour button
bool hourReading = digitalRead(BUTTON_HOUR);
unsigned long now = millis();
if (hourReading != lastHourState && (now - lastHourChangeMs) > debounceMs) {
lastHourChangeMs = now;
if (lastHourState == LOW && hourReading == HIGH) {
alarmHour++;
if (alarmHour > 23) alarmHour = 0;
}
lastHourState = hourReading;
}
// Handle minute button
bool minReading = digitalRead(BUTTON_MIN);
if (minReading != lastMinState && (now - lastMinChangeMs) > debounceMs) {
lastMinChangeMs = now;
if (lastMinState == LOW && minReading == HIGH) {
alarmMinute++;
if (alarmMinute > 59) alarmMinute = 0;
}
lastMinState = minReading;
}
// Check if it's time for alarm
if (timeinfo.tm_hour == alarmHour && timeinfo.tm_min == alarmMinute && !alarmTriggered) {
alarmTriggered = true;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("ALARM!");
Serial.println("Alarm Triggered!");
beepAlarm();
}
// Stop alarm if button pressed
if (alarmTriggered && (hourReading == HIGH || minReading == HIGH)) {
alarmTriggered = false;
lcd.clear();
}
// Re-sync time occasionally
if (millis() - lastSync > syncInterval) {
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
lastSync = millis();
}
delay(100);
}
Full example

Check out the full example code on the link below:
7.7_Alarm_Clock.ino
Wi-Fi-connected alarm clock using NULA MINI, Qwiic LCD, buttons with debouncing, and a passive buzzer. Retrieves time via NTP and triggers alarm at set time.