/********************************************************
* Domino Clock
* Author: John Bradnam ([email protected])
* Created: 2021-06-21
*
* Hardware: ESP32
*
* Adapted: 2024-05-24
*/
#include <WiFi.h>
#include "time.h"
#include <Adafruit_NeoPixel.h>
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// Zeitzone für automatische Sommer-/Winterzeitregelung
const char* timeZone = "CET-1CEST,M3.5.0/2,M10.5.0/3";
#define WS2812B 2
// Domino LED wiring
// 6 8
// 5 7 9
// 4 10
//
// 3 11
// 2 0 12
// 1 13
#define BLANK 13
const uint16_t digits[14] PROGMEM = {
// fedcba9876543210
0b0000000000000000, //0
0b0000000000000001, //1
0b0000100000000010, //2
0b0000100010000010, //3
0b0000100100010010, //4
0b0010000100011001, //5
0b0010100100011010, //6
0b0010100110011010, //7
0b0010110101011010, //8
0b0010110101011011, //9
0b0010110111011011, //10
0b0011110111011110, //11
0b0011111101111110, //12
0b0000000000000000 // Space
};
#define DOM_HOUR 28
#define DOM_MIN_TEN 14
#define DOM_MIN_UNIT 0
// Uncomment to show dominos in white
// #define MONOCHROME
// Uncomment to animate colors
#define ANIMATE
#ifdef MONOCHROME
#define COLOR_HOUR strip.Color(127, 127, 127)
#define COLOR_MIN_TEN strip.Color(127, 127, 127)
#define COLOR_MIN_UNIT strip.Color(127, 127, 127)
#else
#define COLOR_HOUR strip.Color(127, 0, 0)
#define COLOR_MIN_TEN strip.Color(0, 127, 0)
#define COLOR_MIN_UNIT strip.Color(0, 0, 127)
#endif
#define COLOR_BLACK strip.Color(0,0,0)
#define BRIGHTNESS 50 //Brightness level (0 to 255)
#define LED_COUNT 42
Adafruit_NeoPixel strip(LED_COUNT, WS2812B, NEO_GRB + NEO_KHZ800);
int lastHours = -1; // Used to test if hour changed
int lastMinutes = -1; // Used to test if minute changed
#ifdef ANIMATE
uint32_t colorH = COLOR_HOUR; // Used to store active hour color
uint32_t colorMT = COLOR_MIN_TEN; // Used to store active tens of minutes color
uint32_t colorMU = COLOR_MIN_UNIT; // Used to store active units of minutes color
int wheelH = 85; // Start hours with RED
int wheelMT = 255; // Start tens of minutes with GREEN
int wheelMU = 170; // Start tens of minutes with BLUE
long colorTimeout = 0; // Color timeout when animating colors
#define COLOR_CHANGE 100 // Time between color changes on animation
#endif
//---------------------------------------------------------------------------
// Hardware setup
void setup()
{
Serial.begin(9600);
strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
strip.show(); // Turn OFF all pixels ASAP
strip.setBrightness(BRIGHTNESS); // Set BRIGHTNESS to about 1/5 (max = 255)
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
// Init and get the time with automatic DST
configTzTime(timeZone, "pool.ntp.org", "time.nist.gov");
}
//---------------------------------------------------------------------------
// Main program loop
void loop()
{
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
return;
}
int hours = timeinfo.tm_hour;
int minutes = timeinfo.tm_min;
#ifdef ANIMATE
if (millis() > colorTimeout)
{
wheelH = max((wheelH + 1) & 0xFF, 1);
wheelMT = max((wheelMT + 1) & 0xFF, 1);
wheelMU = max((wheelMU + 1) & 0xFF, 1);
colorH = Wheel(wheelH);
colorMT = Wheel(wheelMT);
colorMU = Wheel(wheelMU);
colorTimeout = millis() + COLOR_CHANGE;
}
#endif
if (hours != lastHours || minutes != lastMinutes)
{
Serial.println("h="+String(hours)+", m="+String(minutes));
lastHours = hours;
lastMinutes = minutes;
displayTime(hours, minutes);
}
}
//---------------------------------------------------------------------------
// Display the given time on the dominos
// h = hours (0 to 23);
// m = minutes (0 to 59);
void displayTime(int h, int m)
{
displayDomino(DOM_HOUR, normaliseHour(h), colorH);
displayDomino(DOM_MIN_TEN, m / 10, colorMT);
displayDomino(DOM_MIN_UNIT, m % 10, colorMU);
}
//---------------------------------------------------------------------------
// Convert hour to 1 to 12
// h = hours (0 to 23);
// returns 1 to 12;
int normaliseHour(int h)
{
if (h > 11)
{
h = h - 12;
}
if (h == 0)
{
h = 12;
}
return h;
}
//---------------------------------------------------------------------------
// Display a number on the given domino
// d = domino (0 - most right, 14 - middle, 28 - left most);
// n = number to display (0 to 12)
// c = color to display
void displayDomino(int d, int n, uint32_t c)
{
uint16_t bits = pgm_read_word(&digits[n]);
uint16_t mask = 0b0000000000000001;
for (int i = 0; i < 14; i++)
{
strip.setPixelColor(i + d, (bits & mask) ? c : COLOR_BLACK);
mask = mask << 1;
}
strip.show();
}
#ifdef ANIMATE
//-------------------------------------------------------------------------
// Input a value 0 to 255 to get a color value.
// The colors are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos)
{
if (WheelPos == 0)
{
return 0;
}
else if (WheelPos < 85)
{
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
else if (WheelPos < 170)
{
WheelPos -= 85;
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
else
{
WheelPos -= 170;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
}
#endif