RTC Clock App
Let’s see if we can share the code here.
This little program is at the point where I can share. It is the initial revision of the code, intended to serve as a retro digital watch running on the XIAO ESP32C6 on the XIAO Expansion Board, with an Adafruit UV Light Sensor thrown in just for fun. This is the first code I am publishing on The Streak, and I am doing so as a trial run. Future updates will be stored on my GitHub and perhaps on the blog as well. We will see.
#include <stdio.h>
#include <Wire.h>
#include <PCF8563.h> // Library: PCF8563 by Bill2462 - used for RTC
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Fonts/FreeSans12pt7b.h>
#include <Fonts/FreeMono9pt7b.h>
#include <WiFi.h> // for network connect - used in sync_network_time()
#include <NTPClient.h> // for network time sync
#include <WiFiUdp.h> // for network connect - used for timeClient and sync_network_time()
#include <TimeLib.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1 // Reset pin # (-1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C
#define BUZZER_PIN D5 // D5 on expansion board
#define BUTTON_1 D1 // user button on expansion board
#define SPEAKER D3
#define LARGE_FONT &FreeSans12pt7b
#define SMALL_FONT &FreeMono9pt7b
#define SMALL_FONT NULL
#define UV_PIN 2
char date_text[] = "01/01/1970";
String ssid = "xxxxxxxxxxxxxxxx";
String password = "xxxxxxxxxxxxxxxx";
bool twelve_hours = true;
bool tone_played = false;
int pass = 1;
int weekday_int = 0;
float uv = 0.0;
WiFiUDP ntpUDP; // create NTP Client object (ntpUDP) to get time
NTPClient timeClient(ntpUDP, "pool.ntp.org", -14400, 60000); // TimeOffset in seconds: GMT +1 = 3600, GMT -5 = -18000
PCF8563 rtc; // create RTC object
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // create SSD1306 display object for the OLED
void find_wifi_networks() {
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(100);
// Start Scan
int n = WiFi.scanNetworks();
// Scan complete
if (n == 0) {
Serial.println("no networks found.");
} else {
for (int i = 0; i < n; i++){
if (WiFi.SSID(i) == "SpectrumSetup-80") {
ssid = WiFi.SSID(i);
Serial.println(WiFi.SSID(i));
i = n;
} else if (WiFi.SSID(i) == "Saltville") {
ssid = WiFi.SSID(i);
Serial.println(WiFi.SSID(i));
i = n;
}
}
}
}
void play_tone() {
for (long i = 0; i < 100; i += 1) {
//generate square wave
digitalWrite(SPEAKER, HIGH);
delayMicroseconds(100);
digitalWrite(SPEAKER, LOW);
delayMicroseconds(100);
}
}
void sync_network_time() {
Time now = rtc.getTime();
if (now.year != 25) {
Serial.print("Current Year from RTC: ");
Serial.println(now.year);
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
// Initialize a NTPClient to get time from network
timeClient.begin();
timeClient.update();
Serial.print("Current Time from NTP: ");
Serial.println(timeClient.getFormattedTime());
// update RTC
rtc.setHour(timeClient.getHours()); //set hours
rtc.setMinut(timeClient.getMinutes()); //set minutes
rtc.setSecond(timeClient.getSeconds()); //set second
// CODE PULLS EPOCH TIME AND CONVERTS TO DAY, MONTH, YEAR, and weekday
unsigned long epoch = timeClient.getEpochTime();
int d = day(epoch);
int m = month(epoch);
int y = year(epoch);
int wd = weekday(epoch);
weekday_int = wd;
// Update date in RTC
rtc.setMonth(m);
rtc.setDay(d);
rtc.setYear(y-2000); // fix this - passing the full year doesn't work correctly
} else {
Serial.println("Network Sync bypassed");
}
}
void update_date() {
Time nowTime = rtc.getTime(); //get current time from RTC
display.setFont(SMALL_FONT);
display.setCursor(127 - (sizeof(date_text) * 5.5), 4); // assuming width of 8 pixels per character
display.setTextColor(1);
display.setTextSize(1);
snprintf(date_text, 11, "%02d/%02d/20%02d", nowTime.month, nowTime.day, nowTime.year); // stores the formatted string safely in the char array
display.print(date_text);
}
void display_current_day() {
String days[7] = {"Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"};
display.setCursor(4, 4);
display.print(days[weekday_int]);
}
float update_uv() {
int uv_sensor_reading = analogRead(UV_PIN);
float uv_index = (uv_sensor_reading * (3.3 / 1023.0)) / 0.1; // voltage = uv_sensor_reading * (3.3 / 1023.0)
return uv_index;
}
void update_time() {
Time nowTime = rtc.getTime();//get current time
display.setFont(LARGE_FONT);
display.setTextSize(1);
int hour_int = nowTime.hour;
if (twelve_hours == true) {
display.setCursor(20, 33);
if (hour_int > 12 && hour_int < 24) {
hour_int -= 12;
display.printf("%d:%02d PM", hour_int, nowTime.minute);
} else if (hour_int == 24) {
display.printf("12:%02d AM", hour_int, nowTime.minute);
} else {
display.printf("%d:%02d AM", hour_int, nowTime.minute);
}
}
if (twelve_hours == false && hour_int < 10) {
display.setCursor(18, 32);
display.printf("0%d:%02d:%02d", hour_int, nowTime.minute, nowTime.second);
} else if (twelve_hours == false && hour_int >= 10) {
display.setCursor(18, 32);
display.printf("%d:%02d:%02d", hour_int, nowTime.minute, nowTime.second);
}
if (nowTime.minute == 0 && nowTime.second==0 && tone_played==false) {
play_tone();
tone_played = true;
}
if (nowTime.minute == 30 && nowTime.second==0 && tone_played==false) {
play_tone();
tone_played = true;
}
if (nowTime.minute == 1 && nowTime.second==0) {
tone_played = false;
}
if (nowTime.minute == 31 && nowTime.second==0) {
tone_played = false;
}
}
void update_progress_bars() {
Time nowTime = rtc.getTime(); //get current time
display.fillRect(4, 47, 2 * nowTime.second, 5, SSD1306_WHITE); // Filled rectangle x, y, w, h, c
display.fillRect(4, 40, 2 * nowTime.minute, 5, SSD1306_WHITE); // Filled rectangle x, y, w, h, c
display.drawFastVLine(4, 38, 16, 1); // 0% line
display.drawFastVLine(33, 38, 16, 1); // 25% line
display.drawFastVLine(64, 38, 16, 1); // 50% line
display.drawFastVLine(94, 38, 16, 1); // 75% line
display.drawFastVLine(125, 38, 16, 1); // 100% line
}
// ============================================================================== //
void setup() {
Serial.begin(115200);
Wire.begin(); // Standard I2C pins for XIAO
pinMode(BUTTON_1, INPUT_PULLUP); // onboard button
pinMode(LED_BUILTIN, OUTPUT); // onboard LED
pinMode(SPEAKER, OUTPUT);
pinMode(UV_PIN, INPUT);
play_tone();
find_wifi_networks();
// rtc stuff
rtc.init();//initialize the clock
rtc.stopClock();//stop the clock
rtc.startClock();//start the clock
sync_network_time(); // call the sync_network_time function
// display stuff
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
for(;;); // Don't proceed, loop forever
}
display.clearDisplay();
display.display(); // Push buffer to screen
}
// ============================================================================== //
void loop() {
String uv_risk = "";
if (digitalRead(BUTTON_1) == 1){
digitalWrite(LED_BUILTIN, HIGH);
} else {
digitalWrite(LED_BUILTIN, LOW);
twelve_hours = !twelve_hours;
play_tone();
}
display.clearDisplay();
update_time();
update_progress_bars();
update_date();
display_current_day();
if (pass == 10) {
uv = update_uv();
pass = 0;
}
if (uv >= 0 && uv < 3) {
uv_risk = "Low"; // Green
} else if (uv >= 3 && uv < 6) {
uv_risk = "Moderate"; // Yellow
} else if (uv >= 6 && uv < 8) {
uv_risk = "High"; // Orange
} else if (uv >= 8 && uv < 11) {
uv_risk = "Very High"; // Red
} else if (uv >= 11) {
uv_risk = "Extreme"; // Purple
}
display.setCursor(4, 56);
display.setTextSize(1);
display.printf("UV: %s %0.2f", uv_risk, uv);
display.display(); // Push buffer to screen
delay(200);
pass = pass + 1;
}



Post Comment