Hi, i creating an LED clock using WS2812b LED's and wanting it to get the time from NTP using an ESP8266.
It all works fine for now, although i will need to do some polishing of the visual output.
The issue i ran into is that while the NTP time is updated, the program does not progress. Possibly due to the clock not being to close to the router, it seems as if the response takes almost 5 seconds to come in, during which the program does not update the time on the LEDs. The seconds marker stops.
Now i don't intend to update very often, once a day should be enough, but i would like to run some kind of animation while it is updating, either something fancy, or just that the seconds keep running.
The full code at the moment
#include <NTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <TimeLib.h>
#include <time.h>
#include <Timezone.h>
#include <NeoPixelBus.h>
#define PIN 3 // ws2811 data pin
#define BLOCK_PIN 0
#define HR_WIDTH 2
#define MN_WIDTH 3
#define BR_DEC 6
#define BACK_LED 28
#define LED_COUNT (60 + BACK_LED)
const RgbColor HR_COLOR (0, 255, 0);
const RgbColor MN_COLOR (255, 0, 0);
const RgbColor SC_COLOR (0, 0, 255);
const RgbColor BACK_COL (160, 30, 0);
static tm getDateTimeByParams(long time) {
struct tm *newtime;
const time_t tim = time;
newtime = localtime(&tim);
return *newtime;
}
static String getDateTimeStringByParams(tm *newtime, char* pattern = (char *)"%d/%m/%Y %H:%M:%S") {
char buffer[30];
strftime(buffer, 30, pattern, newtime);
return buffer;
}
static String getEpochStringByParams(long time, char* pattern = (char *)"%d/%m/%Y %H:%M:%S") {
tm newtime;
newtime = getDateTimeByParams(time);
return getDateTimeStringByParams(&newtime, pattern);
}
NeoPixelBus<NeoGrbFeature, NeoEsp8266Dma800KbpsMethod> strip(LED_COUNT, PIN); // the object name is strip.
const char *ssid = "XXX";
const char *password = "xxxxxxxx";
WiFiUDP ntpUDP;
int GTMOffset = 0;
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", GTMOffset * 60 * 60, 60 * 1000);
// Central European Time (Frankfurt, Paris)
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; // Central European Summer Time
TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60}; // Central European Standard Time
Timezone CE(CEST, CET);
void setup() {
delay(100);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay (500);
}
timeClient.begin();
delay (1000);
while (!timeClient.update()) {
delay(3000);
}
unsigned long epoch = timeClient.getEpochTime();
setTime(epoch);
delay(200);
pinMode(1, OUTPUT);
digitalWrite(1, LOW);
strip.Begin();
ClearLeds();
strip.Show();
delay(200);
pinMode(BLOCK_PIN, OUTPUT);
digitalWrite(BLOCK_PIN, LOW);
strip.Show();
}
void loop() {
static uint32_t moment = millis();
if (millis() - moment > 60000) { // * 60 * 24) { // every minute or once a day
moment = millis();
timeClient.update();
}
DisplayTime(CE.toLocal(now()));
}
void DisplayTime(uint32_t theTime) {
static uint32_t oldTime = 0;
static int8_t oldSec = 0;
static uint32_t lastNewSec = 0;
tm nowtime;
uint8_t centerPix, brightness;
nowtime = getDateTimeByParams(theTime);
ClearLeds();
SetBackLeds();
centerPix = nowtime.tm_min;
brightness = 255;
for (uint8_t i = 0; i < MN_WIDTH; i++) { // fill the Hour
//uint8_t brightness = ((uint16_t) 255 * (MN_WIDTH - i)) / MN_WIDTH + (i * 2);
brightness = brightness / (BR_DEC - MN_WIDTH) ;
uint8_t pix = (59 + centerPix - i) % 60;
strip.SetPixelColor(pix + BACK_LED, ColorBrightness(MN_COLOR, brightness));
pix = (59 + centerPix + i) % 60;
strip.SetPixelColor(pix + BACK_LED, ColorBrightness(MN_COLOR, brightness));
}
centerPix = ((nowtime.tm_hour % 12) * 5) + (nowtime.tm_min / 12);
brightness = 255;
for (uint8_t i = 0; i < HR_WIDTH; i++) { // fill the Hour
brightness = brightness / (BR_DEC - HR_WIDTH);
//uint8_t brightness = ((uint16_t) 255 * (HR_WIDTH - i)) / HR_WIDTH + (i * 2);
uint8_t pix = (59 + centerPix - i) % 60;
strip.SetPixelColor(pix + BACK_LED, ColorBrightness(HR_COLOR, brightness));
pix = (59 + centerPix + i) % 60;
strip.SetPixelColor(pix + BACK_LED, ColorBrightness(HR_COLOR, brightness));
}
if (oldSec != nowtime.tm_sec) {
oldSec = nowtime.tm_sec;
lastNewSec = millis();
}
uint16_t elapsed = millis() - lastNewSec;
if (elapsed < 512) {
if (elapsed > 255) elapsed = 511 - elapsed;
uint8_t pix = (59 + oldSec) % 60;
strip.SetPixelColor(pix + BACK_LED, ColorBrightness(SC_COLOR, elapsed));
//digitalWrite(1, LOW);
}
else {
//digitalWrite(1, HIGH);
}
strip.Show();
}
RgbColor ColorBrightness(RgbColor color, uint16_t brightness) {
RgbColor newColor = 0;
newColor.R = (color.R * brightness) / 255;
newColor.G = (color.G * brightness) / 255;
newColor.B = (color.B * brightness) / 255;
return newColor;
}
void ClearLeds() {
for (uint16_t u = 0; u < LED_COUNT; u++) {
strip.SetPixelColor(u, 0);
}
}
void SetBackLeds() {
for (uint8_t i = 0; i < BACK_LED; i++) {
strip.SetPixelColor(i, BACK_COL);
}
}
I started out with a basic sketch i found somewhere, which works, but once i moved the clock to my soldering desk, updating started to take a bit longer. I know the libraries i use are not the only ones, and i am looking for recommendations before i start looking into the libraries to see how it could also be fixed. In this project i would really just like to focus on the cosmetics.