// https://forum.arduino.cc/t/help-me-with-some-ideas-to-create-such-a-clock/1402098
// https://wokwi.com/projects/422079783532441601
// ALARM SETTING
byte alarmHour = 7, alarmMinute = 3; // 7:03 AM
#include <SSD1306Ascii.h> // https://github.com/greiman/SSD1306Ascii/blob/master/src/SSD1306Ascii.h
#include <SSD1306AsciiAvrI2c.h>
#define I2C_ADDRESS 0x3C
#define RST_PIN -1
SSD1306AsciiAvrI2c oled;
#include <DHT.h>
#define DHTTYPE DHT22
#define DHTPIN 8
DHT dht = DHT(DHTPIN, DHTTYPE);
#include <RTClib.h>
RTC_DS1307 rtc;
#include <FastLED.h>
#define NUM_LEDS 73
#define MATRIX_PIN 7
#define MAXBRIGHT 255
CRGB leds[NUM_LEDS];
int section[] = { 7, 2, 2, 6, 21, 2, 21, 21}; // day, ampm, temp/humi, HHtens, Hones, MMtens, Mones
int timseg[] = {11, 17, 38, 59}; // clock digits
/*****************************
WS2812
****************************
SEG leds[+x] HH H MM M
A 0 - 2 9 15 36 51
B 3 - 5
C 6 - 8
D 9 - 11
E 12 - 14
F 15 - 17
G 18 - 20
DIG SEGMENTS
0 A, B, C, D, E, F
1 B, C
2 A, B, D, E, G
3 A, B, C, D, G
4 B, C, f, G
5 A, C, D, F, G
6 A, C, D, E, F, G
7 A, B, C
8 A, B, C, D, E, F, G
9 A, B, C, D, F, G
******************************/
#define OFF 0
#define ON 1
#define AM 0
#define PM 1
unsigned long timer, timeout = 500, dataTimer, dataTimeout = 1000;
byte month, date, temp, humi;
bool oledBlink, toggle; // alarm, rtc/dht
void setup() {
Serial.begin(115200);
rtc.begin();
dht.begin();
oled.begin(&Adafruit128x64, I2C_ADDRESS, RST_PIN);
oled.setFont(Adafruit5x7);
oled.clear();
oledOverlay(); // draw OLED static data
FastLED.addLeds<WS2812B, MATRIX_PIN, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(MAXBRIGHT); // Adjust the brightness value as needed
FastLED.clear();
FastLED.show();
oledAlarmTime(alarmHour, alarmMinute);
oledAlarmSet(ON);
oledAlarmAmPm(AM);
// testfunctions(); while (1); // run test functions once
}
void loop() {
// testfunctions(); // run many times
heartBeat();
getData();
}
void getData() {
if (millis() - dataTimer > dataTimeout) {
dataTimer = millis();
if (toggle) // alternating rtc/dht, not both together
rtcMonDat();
else
dhtTempHumi();
toggle = !toggle; // change flag
}
}
void rtcMonDat() {
DateTime now = rtc.now();
// days of the week
leds[0 + now.dayOfTheWeek()] = CRGB(128, 128, 255); // color the day light blue
// AM/PM
if (now.hour() < 12) {
leds[7] = CRGB(128, 128, 0);
leds[8] = CRGB(0, 0, 0);
} else {
leds[8] = CRGB(0, 128, 128);
leds[7] = CRGB(0, 0, 0);
}
FastLED.show();
oledPlaceData(1, 1, now.month());
oledPlaceData(1, 0, now.day());
}
void dhtTempHumi() {
float humi = dht.readHumidity();
float temp = dht.readTemperature();
oledPlaceData(0, 1, temp); // temperature
oledPlaceData(0, 0, humi); // humidity
}
void oledAlarmSet(bool on) {
oled.set1X();
if (on) {
oled.setCursor(6, 1);
oled.setInvertMode(1);
oled.print(F(" "));
oled.setCursor(10, 1);
oled.print(F("ON"));
oled.setInvertMode(0);
} else {
oled.setCursor(6, 1);
oled.print(F("off"));
}
}
void oledAlarmAmPm(bool ampm) {
if (ampm) { // PM
oled.setCursor(113, 1);
oled.print(F("PM"));
} else { // AM
oled.setCursor(113, 0);
oled.print(F("AM"));
}
}
void oledAlarmTime(int hour, int minute) {
oled.set2X();
if (hour < 10) {
oled.setCursor(49, 0);
oled.print(hour);
} else {
oled.setCursor(37, 0);
oled.print(hour);
}
oled.setCursor(73, 0);
if (minute < 10) {
oled.print(F("0"));
oled.setCursor(85, 0);
oled.print(minute);
} else {
oled.print(minute);
}
}
void oledPlaceData (byte rtcdht, byte temphumi, byte val) {
byte y, tens, ones;
oled.set2X();
if (rtcdht) // 1 = RTC - month/date
y = 3; // oled 1X font row 3
else // 0 = DHT - temp/humi
y = 6; // oled 1X font row 6
if (temphumi) // 1 = month/temp
tens = 37, ones = 49; // month/temp columns
else // 0 = date/humi
tens = 99, ones = 111; // date/humi columns
oled.clearField(tens, y, 2); // clear col, row, characters
if (val < 10) {
oled.setCursor(ones, y);
oled.print(val);
} else {
// oled.setCursor(tens, y);
// oled.print(val / 10);
// oled.setCursor(ones, y);
// oled.print(val % 10);
oled.setCursor(tens, y);
oled.print(val);
}
}
void heartBeat() { // oledBlink colon
if (millis() - timer > timeout) {
timer = millis();
// oled
oled.set2X();
if (oledBlink) {
oled.setCursor(61, 0);
oled.print(F(":"));
} else {
oled.clearField(61, 0, 1); // col, row, characters
}
oledBlink = !oledBlink; // toggle oledBlink flag
// ws2812
if (oledBlink) {
leds[38] = CRGB(128, 0, 0);
leds[39] = CRGB(128, 0, 0);
FastLED.show();
} else {
leds[38] = CRGB(0, 0, 0);
leds[39] = CRGB(0, 0, 0);
FastLED.show();
}
}
}
// =====================
// OLED STATIC FUNCTIONS
// =====================
void oledOverlay() {
oled.set1X();
horizontalLine (2);
horizontalLine (5);
verticalLine(63);
oled.setCursor(0, 0);
oled.print(F("ALARM"));
oled.setCursor(0, 3);
oled.print(F("MONTH"));
oled.setCursor(69, 3);
oled.print(F("DATE"));
oled.setCursor(0, 6);
oled.print(F("TEMP"));
oled.setCursor(69, 6);
oled.print(F("HUMI"));
}
void horizontalLine(int row) { // draw horizontal line at row (range 0 to 7)
oled.set1X(); // font size
oled.setCursor(0, row);
for (int i = 0; i < 21; i++) {
oled.print(F("-"));
}
}
void verticalLine(byte col) { // draw vertical line at col (range 0 to 127)
oled.set1X(); // font size
oled.setCursor(col, 3); oled.print(F("|"));
oled.setCursor(col, 4); oled.print(F("|"));
oled.setCursor(col, 6); oled.print(F("|"));
oled.setCursor(col, 7); oled.print(F("|"));
}
// ==============
// TEST FUNCTIONS
// ==============
#include<Wire.h>
int address, deviceFound, error; // i2c bus test
void testfunctions() {
// i2ctest();
// dhttest();
// rtctest();
// oledtest();
// ledtest();
}
void oledtest() {
oled1206AsciiTest(); // print 1x and 2x ASCII
oledAlarmSet(OFF); // ON/OFF placement
oledAlarmAmPm(AM); // AM/PM placement
oledAlarmTime(alarmHour, alarmMinute); // time
oledPlaceData(1, 1, 19); // rtc, mon
oledPlaceData(1, 0, 28); // rtc, date
oledPlaceData(0, 1, 37); // dht, temp
oledPlaceData(0, 0, 46); // dht, humi
}
void oled1206AsciiTest() {
oled.set1X();
for (byte i = 0; i < 21; i++)
oled.print(i % 10);
oled.setCursor(0, 0);
for (byte i = 0; i < 8; i++) {
oled.print(i);
if (i > 0)
for (byte i = 1; i < 21; i++)
oled.print(F("."));
oled.println();
}
delay(2000);
oled.clear();
oled.set2X();
for (byte i = 0; i < 11; i++)
oled.print(i % 10);
oled.setCursor(0, 0);
for (byte i = 0; i < 4; i++) {
oled.print(i);
if (i > 0)
for (byte i = 1; i < 111; i++)
oled.print(F("."));
oled.println();
}
delay(2000);
oled.clear();
}
void dhttest() {
delay(2000);
float h = dht.readHumidity();
float t = dht.readTemperature();
Serial.print(F("H: "));
Serial.print(h);
Serial.print(F(" "));
Serial.print(F("T: "));
Serial.print(t);
Serial.println();
}
void rtctest() {
char dotw[7][5] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"}; // not used
DateTime now = rtc.now();
Serial.print(dotw[now.dayOfTheWeek()]);
Serial.print(F(" "));
Serial.print(now.year(), DEC);
Serial.print(F("."));
Serial.print(now.month(), DEC);
Serial.print(F("."));
Serial.print(now.day(), DEC);
Serial.print(F(" "));
Serial.print(now.hour(), DEC);
Serial.print(F(":"));
Serial.print(now.minute(), DEC);
Serial.print(F(":"));
Serial.print(now.second(), DEC);
Serial.println();
}
void ledtest() {
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = CRGB::White;
FastLED.show();
delay(10);
}
delay(2000);
FastLED.clear();
FastLED.show();
}
void i2ctest() { // read I2C bus addresses
Wire.begin();
int address, deviceFound, error;
Serial.print(F("I2C bus device addresses:"));
for (address = 0; address < 128; address++) {
Wire.beginTransmission(address);
if (!Wire.endTransmission()) {
deviceFound++;
Serial.print(F(" 0x"));
Serial.print(address, HEX);
} else if (error == 4) {
Serial.print(F(" Error at"));
Serial.print(F(" 0x"));
Serial.print(address, HEX);
}
}
if (!deviceFound)
Serial.println(F(" No I2C devices found."));
}
SUN
MON
TUE
WED
THU
FRI
SAT
AM
PM
TEM
HUM