//Jan 2025
//Interactive wall clock by Newson's Electronics
#include <Adafruit_NeoPixel.h>
#include <RtcDS1302.h> //Rtc by Makuna
ThreeWire myWire(3, 2, 4); // IO, SCLK, CE
RtcDS1302<ThreeWire> Rtc(myWire);
int hue = 150; // Variable to track the hue
int hue2 = 42; // Variable to track the hue
int changeTime = 0;
int bx, by = 0;
int h1, h2 = 0; // h1= hour ones, h2= hour tens (digits)
int m1, m2 = 0; // m1= minutes ones, m2=minutes tens
int s = 0; // seconds
int dots = 0;
int year, month, day, hours, minutes, seconds = 0;
int shift = 0;
int mode = 0;
int brightness = 5;
// Define shift values for each digit type
int shifts[] = { 0, 22, 55, 77 };
int col = 0;
int row = 0;
const int numButtons = 19;
const int numRows = 9; // Total number of row pins
const int numBacklights = 19; // Total number of row pins
int expectedADCValues[numButtons] = { 1020, 925, 765, 612, 475, 361, 265, 190, 133, 92 };
int threshold = 10; // Adjusted threshold for better accuracy (test and adjust further)
int rowPins[numRows] = { 5, 6, 7, 8, 9, 10, 11, 12, 13 };
int backLights[numBacklights] = { 5, 10, 16, 21, 27, 32, 38, 43, 49, 54, 60, 65, 71, 76, 82, 87, 93, 98, 104 };
int displayLeds[9][10] = {
{ 0, 11, 22, 33, 44, 55, 66, 77, 88, 99 },
{ 9, 20, 31, 42, 53, 64, 75, 86, 97, 0 },
{ 1, 12, 23, 34, 45, 56, 67, 78, 89, 100 },
{ 8, 19, 30, 41, 52, 63, 74, 85, 96, 0 },
{ 2, 13, 24, 35, 46, 57, 68, 79, 90, 101 },
{ 7, 18, 29, 40, 51, 62, 73, 84, 95, 0 },
{ 3, 14, 25, 36, 47, 58, 69, 80, 91, 102 },
{ 6, 17, 28, 39, 50, 61, 72, 83, 94, 0 },
{ 4, 15, 26, 37, 48, 59, 70, 81, 92, 103 }
};
int litLeds[54] = {};
int litNumbers[4];
int digit0[] = { 9, 8, 7, 6, 11, 15, 20, 19, 18, 17 };
int digit1[] = { 20, 19, 18, 17 };
int digit2[] = { 9, 7, 6, 11, 13, 14, 20, 19, 17 };
int digit3[] = { 9, 18, 6, 11, 13, 15, 20, 19, 17 };
int digit4[] = { 9, 8, 13, 20, 19, 18, 17 };
int digit5[] = { 9, 8, 7, 11, 13, 15, 18, 17 };
int digit6[] = { 9, 8, 7, 6, 11, 13, 15, 20, 18, 17 };
int digit7[] = { 9, 11, 20, 19, 18, 17 };
int digit8[] = { 9, 8, 7, 6, 11, 13, 15, 20, 19, 18, 17 }; //13*4=52
int digit9[] = { 9, 8, 11, 13, 20, 19, 18, 17 };
//determine sizes of the arrays
int sizeZero = sizeof(digit0) / sizeof(digit0[0]);
int sizeOne = sizeof(digit1) / sizeof(digit1[0]);
int sizeTwo = sizeof(digit2) / sizeof(digit2[0]);
int sizeThree = sizeof(digit3) / sizeof(digit3[0]);
int sizeFour = sizeof(digit4) / sizeof(digit4[0]);
int sizeFive = sizeof(digit5) / sizeof(digit5[0]);
int sizeSix = sizeof(digit6) / sizeof(digit6[0]);
int sizeSeven = sizeof(digit7) / sizeof(digit7[0]);
int sizeEight = sizeof(digit8) / sizeof(digit8[0]);
int sizeNine = sizeof(digit9) / sizeof(digit9[0]);
//stores all the digit sizes into a single array 0 for sizeZero etc.
int sizes[] = { sizeZero, sizeOne, sizeTwo, sizeThree, sizeFour, sizeFive, sizeSix, sizeSeven, sizeEight, sizeNine };
#define LED_PIN A1
#define LED_COUNT 105
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
// Array to store the color state for each button
int colorState[numButtons] = { 0 }; // 0: Red, 1: Green, 2: Blue, 3: White, 4: Off
void updateTime() {
// Create a new RtcDateTime object with updated minutes
RtcDateTime updatedTime(
year, month, day,
hours, minutes, seconds);
// Set the updated time back to the RTC
Rtc.SetIsWriteProtected(false);
Rtc.SetDateTime(updatedTime);
delay(200);
Rtc.SetIsWriteProtected(true);
}
void clearDisplay() {
for (int i = 0; i < LED_COUNT; i++) {
strip.setPixelColor(i, strip.Color(0, 0, 0)); // Off
}
//strip.show();
}
void fillColor(uint8_t hue) {
//uint32_t color = strip.ColorHSV(hue * 256); // Using the built-in ColorHSV function
for (int i = 0; i < LED_COUNT; i++) {
strip.setPixelColor(i, strip.ColorHSV(hue * 256)); // Set each LED color
}
// strip.show(); // Update the LED strip
}
void redBee() {
strip.setPixelColor(bx, strip.Color(255, 0, 0)); // Set the pixel color
bx++;
if (bx > 105) {
bx = 0;
}
}
//void fillColor(uint8_t red, uint8_t green, uint8_t blue) {
// for (int i = 0; i < LED_COUNT; i++) {
// strip.setPixelColor(i, strip.Color(red, green, blue)); // Set the pixel color
//}
//strip.show(); // Update the LED strip
//}
void zero() {
for (int i = 0; i < sizeZero; i++) {
strip.setPixelColor(digit0[i] + shift, strip.ColorHSV(hue2 * 256));
// int shifts[] = {0, 22, 55, 77};
if (shift == 0) litLeds[i] = digit0[i] + shift;
if (shift == 22) litLeds[i + 12] = digit0[i] + shift;
if (shift == 55) litLeds[i + 24] = digit0[i] + shift;
if (shift == 77) litLeds[i + 36] = digit0[i] + shift;
}
}
void one() {
for (int i = 0; i < sizeOne; i++) {
strip.setPixelColor(digit1[i] + shift, strip.ColorHSV(hue2 * 256));
if (shift == 0) litLeds[i] = digit1[i] + shift;
if (shift == 22) litLeds[i + 12] = digit1[i] + shift;
if (shift == 55) litLeds[i + 24] = digit1[i] + shift;
if (shift == 77) litLeds[i + 36] = digit1[i] + shift;
}
}
void two() {
for (int i = 0; i < sizeTwo; i++) {
strip.setPixelColor(digit2[i] + shift, strip.ColorHSV(hue2 * 256));
if (shift == 0) litLeds[i] = digit2[i] + shift;
if (shift == 22) litLeds[i + 12] = digit2[i] + shift;
if (shift == 55) litLeds[i + 24] = digit2[i] + shift;
if (shift == 77) litLeds[i + 36] = digit2[i] + shift;
}
}
void three() {
for (int i = 0; i < sizeThree; i++) {
strip.setPixelColor(digit3[i] + shift, strip.ColorHSV(hue2 * 256));
if (shift == 0) litLeds[i] = digit3[i] + shift;
if (shift == 22) litLeds[i + 12] = digit3[i] + shift;
if (shift == 55) litLeds[i + 24] = digit3[i] + shift;
if (shift == 77) litLeds[i + 36] = digit3[i] + shift;
}
}
void four() {
for (int i = 0; i < sizeFour; i++) {
strip.setPixelColor(digit4[i] + shift, strip.ColorHSV(hue2 * 256));
if (shift == 0) litLeds[i] = digit4[i] + shift;
if (shift == 22) litLeds[i + 12] = digit4[i] + shift;
if (shift == 55) litLeds[i + 24] = digit4[i] + shift;
if (shift == 77) litLeds[i + 36] = digit4[i] + shift;
}
}
void five() {
for (int i = 0; i < sizeFive; i++) {
strip.setPixelColor(digit5[i] + shift, strip.ColorHSV(hue2 * 256));
if (shift == 0) litLeds[i] = digit5[i] + shift;
if (shift == 22) litLeds[i + 12] = digit5[i] + shift;
if (shift == 55) litLeds[i + 24] = digit5[i] + shift;
if (shift == 77) litLeds[i + 36] = digit5[i] + shift;
}
}
void six() {
for (int i = 0; i < sizeSix; i++) {
strip.setPixelColor(digit6[i] + shift, strip.ColorHSV(hue2 * 256));
if (shift == 0) litLeds[i] = digit6[i] + shift;
if (shift == 22) litLeds[i + 12] = digit6[i] + shift;
if (shift == 55) litLeds[i + 24] = digit6[i] + shift;
if (shift == 77) litLeds[i + 36] = digit6[i] + shift;
}
}
void seven() {
for (int i = 0; i < sizeSeven; i++) {
strip.setPixelColor(digit7[i] + shift, strip.ColorHSV(hue2 * 256));
if (shift == 0) litLeds[i] = digit7[i] + shift;
if (shift == 22) litLeds[i + 12] = digit7[i] + shift;
if (shift == 55) litLeds[i + 24] = digit7[i] + shift;
if (shift == 77) litLeds[i + 36] = digit7[i] + shift;
}
}
void eight() {
for (int i = 0; i < sizeEight; i++) {
strip.setPixelColor(digit8[i] + shift, strip.ColorHSV(hue2 * 256));
if (shift == 0) litLeds[i] = digit8[i] + shift;
if (shift == 22) litLeds[i + 12] = digit8[i] + shift;
if (shift == 55) litLeds[i + 24] = digit8[i] + shift;
if (shift == 77) litLeds[i + 36] = digit8[i] + shift;
}
}
void nine() {
for (int i = 0; i < sizeNine; i++) {
strip.setPixelColor(digit9[i] + shift, strip.ColorHSV(hue2 * 256));
if (shift == 0) litLeds[i] = digit9[i] + shift;
if (shift == 22) litLeds[i + 12] = digit9[i] + shift;
if (shift == 55) litLeds[i + 24] = digit9[i] + shift;
if (shift == 77) litLeds[i + 36] = digit9[i] + shift;
}
}
// Declare an array of function pointers to hold the functions
void (*functionArray[10])(); // Array to hold 10 function pointers
void displayTime() {
if (hue!=157) fillColor(hue); // Update the LED color based on the current hue
if (hue==157) clearDisplay();
///fillColor(0,100,0);
//randomHex();
if (seconds % 2 == 0 && changeTime != 1) {
strip.setPixelColor(52, strip.ColorHSV(hue2 * 256)); // Red
strip.setPixelColor(50, strip.ColorHSV(hue2 * 256)); // Red
//redBee();
}
if (changeTime == 1) {
strip.setPixelColor(displayLeds[3][4], strip.Color(255, 0, 0)); // Red
strip.setPixelColor(displayLeds[7][4], strip.Color(255, 0, 0)); // Red
}
//strip.show();
shift = 0; // Set shift to 0 once since it's always 0
if (h2 >= 0 && h2 <= 9) functionArray[h2]();
shift = 22; // Set shift to 0 once since it's always 0
if (h1 >= 0 && h1 <= 9) functionArray[h1]();
shift = 55; // Set shift to 0 once since it's always 0
if (m2 >= 0 && m2 <= 9) functionArray[m2]();
shift = 77; // Set shift to 0 once since it's always 0
if (m1 >= 0 && m1 <= 9) functionArray[m1]();
strip.show();
}
void setup() {
Serial.begin(9600);
functionArray[0] = zero;
functionArray[1] = one;
functionArray[2] = two;
functionArray[3] = three;
functionArray[4] = four;
functionArray[5] = five;
functionArray[6] = six;
functionArray[7] = seven;
functionArray[8] = eight;
functionArray[9] = nine;
for (int i = 0; i < 52; i++) { // 13 * 4 = 52
litLeds[i] = -1;
}
randomSeed(analogRead(2));
Serial.print("compiled: ");
Serial.print(__DATE__);
Serial.println(__TIME__);
Rtc.Begin();
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
printDateTime(compiled);
Serial.println();
if (!Rtc.IsDateTimeValid()) {
// Common Causes:
// 1) first time you ran and the device wasn't running yet
// 2) the battery on the device is low or even missing
Serial.println("RTC lost confidence in the DateTime!");
Rtc.SetDateTime(compiled);
}
if (Rtc.GetIsWriteProtected()) {
Serial.println("RTC was write protected, enabling writing now");
Rtc.SetIsWriteProtected(false);
}
if (!Rtc.GetIsRunning()) {
Serial.println("RTC was not actively running, starting now");
Rtc.SetIsRunning(true);
}
RtcDateTime now = Rtc.GetDateTime();
if (now < compiled) {
Serial.println("RTC is older than compile time! (Updating DateTime)");
Rtc.SetDateTime(compiled);
} else if (now > compiled) {
Serial.println("RTC is newer than compile time. (this is expected)");
} else if (now == compiled) {
Serial.println("RTC is the same as compile time! (not expected but all is fine)");
}
for (int i = 0; i < numRows; i++) {
pinMode(rowPins[i], OUTPUT);
digitalWrite(rowPins[i], LOW); // Ensure rows are initially LOW
}
strip.begin(); // Initialize NeoPixel strip object
clearDisplay();
delay(1000);
strip.setBrightness(brightness); // Set maximum brightness
}
void loop() {
RtcDateTime now = Rtc.GetDateTime();
m1 = minutes % 10;
m2 = minutes / 10;
h1 = hours % 10;
h2 = hours / 10;
s = seconds % 10;
printDateTime(now);
Serial.println();
//strip.setBrightness(brightness);
//fillColor(0,10,100);
//clearDisplay();
if (mode == 0) {
displayTime();
}
//Check the buttons pressed
for (int i = 0; i < numRows; i++) {
// Activate the current row
row = i;
digitalWrite(rowPins[row], HIGH);
// Read the ADC value
int sensorValue = analogRead(A0);
// Check which button is pressed
int buttonPressed = getButtonPressed(sensorValue);
if (buttonPressed != -1) {
col = buttonPressed;
// Cycle through colors for the button pressed
cycleColor(buttonPressed);
// if (mode == 1&&col!=0&&row!=i,&&row!=i) delay(200); // if drawing mode
if (row == 0 && col == 0 && brightness < 255) {
brightness += 5;
strip.setBrightness(brightness);
}
if (row == 2 && col == 0 && brightness > 5) {
brightness -= 5;
strip.setBrightness(brightness);
}
// Simple to just check a button and do something
// change the background hue
if (row == 0 && col == 9) {
hue=hue+3; // Increment the hue to cycle through colors
if (hue >= 256) hue = 0; // Reset hue when it reaches 255
}
if (row==2&&col==9)
{
hue=157;
}
// if (row==2&&col==9)
//{
// hue2++; // Increment the hue to cycle through colors
///if (hue2 >= 256) hue2 = 0; // Reset hue when it reaches 255
//}
//change time if either the two center dots are pressed and not drawing mode
if (((row == 3 && col == 4) || (row == 7 && col == 4))
&& mode != 1) {
changeTime = !changeTime;
displayTime();
//if (changeTime==1) {
mode = 2; //change time mode
//}
if (changeTime == 0) {
mode = 0;
}
delay(200);
}
//
//change the time.
if (changeTime == 1) {
// change h2 digit if any of the three top button are pressed over that digit.
if (col == 8) {
m1 += 1;
if (m1 == 10) {
m1 = 0;
}
minutes = m2 * 10 + m1;
updateTime();
}
if (col == 6) {
m2 += 1;
if (m2 == 6) {
m2 = 0;
}
minutes = m2 * 10 + m1;
updateTime();
}
if (col == 3) {
h1 += 1;
if (h1 == 10 || h1 > 3 && h2 == 2) {
if (h2 != 0) h1 = 0;
if (h2 == 0) h1 = 1;
}
hours = h2 * 10 + h1;
updateTime();
}
if (col == 1) {
h2 += 1;
if (h2 == 3) {
if (h1 != 0) h2 = 0;
if (h1 == 0) h2 = 1;
}
hours = h2 * 10 + h1;
updateTime();
}
//update the display to show the red dots
displayTime();
}
if (changeTime == 0) {
// test to see if button coresponds to a lit led from the digits.
if(mode!=1)
{
for (int c = 0; c < 13 * 4; c++) {
if (litLeds[c] == displayLeds[row][col]) /// test to see if the button pressesed led matched the litLEDS array
{
hue2 = hue2 + 3; // Increment the hue to cycle through colors
if (hue2 >= 256) hue2 = 0; // Reset hue when it reaches 255
break;
}
}
}
//drawing mode
if (row == 8 && col == 0) {
mode++;
fillColor(hue); // Increment the hue to cycle through colors
if (mode == 1) strip.setPixelColor(displayLeds[row][col], strip.Color(255, 0, 0)); // Red
strip.show();
delay(200);
if (mode >= 2) mode = 0; // Reset hue when it reaches 255
}
if (mode == 1) // coloring mode
{
if (row == 4 && col == 0) {
clearDisplay();
}
if (row == 6 && col == 0)
fillColor(hue);
strip.show();
//delay(200);
}
}
// Print which button is pressed
Serial.print("Button [");
Serial.print(row);
Serial.print(",");
Serial.print(col);
Serial.print("]: ");
Serial.print(sensorValue);
Serial.print(",");
Serial.print(h2);
Serial.print(h1);
Serial.print(m2);
Serial.print(m1);
// for (int i = 0; i < 13 * 4; i++) {
// Serial.print(litLeds[i]); // Print the value
// Serial.print(",");
// }
Serial.println("");
//Serial.println(displayLeds[row][col]);
}
// Deactivate the row
digitalWrite(rowPins[row], LOW);
}
}
int getButtonPressed(int adcValue) {
for (int i = 0; i < numButtons; i++) {
if ((adcValue >= (expectedADCValues[i] - threshold) && adcValue <= (expectedADCValues[i] + threshold)) && adcValue > threshold) {
return i;
}
}
return -1;
}
void randomHex() {
//strip.setPixelColor(displayLeds[random(9)][random(10)], strip.Color(random(200, 240), random(200, 240), random(0, 10))); // yellow
strip.setPixelColor(displayLeds[random(9)][random(10)], strip.Color(random(0, 255), random(0, 255), random(0, 255))); // yellow
//strip.show();
//delay(200);
}
void cycleColor(int buttonIndex) {
colorState[buttonIndex] = (colorState[buttonIndex] + 1) % 5; // Cycle through 0 to 4
// Set the color based on the current state
switch (colorState[buttonIndex]) {
case 0:
strip.setPixelColor(displayLeds[row][col], strip.Color(255, 0, 0)); // Red
break;
case 1:
strip.setPixelColor(displayLeds[row][col], strip.Color(0, 255, 0)); // Green
break;
case 2:
strip.setPixelColor(displayLeds[row][col], strip.Color(238, 210, 2)); // yellow
break;
case 3:
strip.setPixelColor(displayLeds[row][col], strip.Color(255, 255, 255)); // White
break;
case 4:
strip.setPixelColor(displayLeds[row][col], strip.Color(0, 0, 0)); // Off
break;
}
strip.show();
}
#define countof(a) (sizeof(a) / sizeof(a[0]))
void printDateTime(const RtcDateTime& dt) {
char datestring[26];
// uint8_t hours = dt.Hour();
month = dt.Month();
year = dt.Year();
day = dt.Day();
hours = dt.Hour();
minutes = dt.Minute();
seconds = dt.Second();
snprintf_P(datestring,
countof(datestring),
PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
dt.Month(),
dt.Day(),
dt.Year(),
dt.Hour(),
dt.Minute(),
dt.Second());
Serial.print(datestring);
}