-
Notifications
You must be signed in to change notification settings - Fork 0
/
LED_CLOCK_V1.07_RGB_LCD_ESP8266.ino
390 lines (323 loc) · 13 KB
/
LED_CLOCK_V1.07_RGB_LCD_ESP8266.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
/* My version of Neopixel clock by Firepower9966 july 2020 https://github.com/firepower9966/Neopixel-Clock
based on code by Leon van den Beukel, march 2019
I have added incremental hour indication, blink hour and minute if same neopixel, brightness control using LDR for dim LED in low light,
added text output for 2002 LCD, rainbow effect test pattern while connecting to wifi.
*/
/*
WiFi connected round LED Clock. It gets NTP time from the internet and translates to a 60 RGB WS2812B LED strip.
If you have another orientation where the wire comes out then change the methods getLEDHour and getLEDMinuteOrSecond
Happy programming, Leon van den Beukel, march 2019
---
NTP and summer time code based on:
https://tttapa.github.io/ESP8266/Chap15%20-%20NTP.html
https://github.com/SensorsIot/NTPtimeESP/blob/master/NTPtimeESP.cpp (for US summer time support check this link)
*/
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WiFiUdp.h>
#include <FastLED.h>
#include <Wire.h>
#include <LiquidCrystal_PCF8574.h>
#define DEBUG_ON
const char Version[] = "LED CLOCK V1.07";
char *weekday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
const char ssid[] = "Wifi Name"; // Your network SSID name here
const char pass[] = "Wifi Password"; // Your network password here
unsigned long timeZone = 7.0; // Change this value to your local timezone (in my case +7 for Vietnam)
unsigned int LCD_Delay;
#define NUM_LEDS 60 // number of CRGB LEDS (60 for 60 sec/min)
#define DATA_PIN 12 // pin to drive Din of CRGB
#define Din_Offset 30 //offset at 00,30 for Din of CRGB at 0 or 30 minute marks
// Change the colors here if you want.
// Check for reference: https://github.com/FastLED/FastLED/wiki/Pixel-reference#predefined-colors-list
// You can also set the colors with RGB values, for example red:
// CRGB colorHour = CRGB(255, 0, 0); or CRGB::Red;
CRGB colorHour = CRGB::Red;
CRGB colorMinute = CRGB::Green;
CRGB colorSecond = CRGB::Blue;
CRGB colorMarks5 = CRGB::Indigo;
CRGB colorMarks15 = CRGB::Purple;
CRGB colorBlinkHour = CRGB::Red;
CRGB colorBlinkMinute = CRGB::Green;
CRGBArray<NUM_LEDS>LEDs;
#define Day 64
#define Night 6
ESP8266WiFiMulti wifiMulti;
WiFiUDP UDP;
IPAddress timeServerIP;
const char* NTPServerName = "pool.ntp.org"; //time.nist.gov or pool.ntp.org
const int NTP_PACKET_SIZE = 48;
byte NTPBuffer[NTP_PACKET_SIZE];
unsigned long intervalNTP = 5 * 60000; // Request NTP time every 5 minutes
unsigned long prevNTP = 0;
unsigned long lastNTPResponse = millis();
uint32_t timeUNIX = 0;
unsigned long prevActualTime = 0;
#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) )
static const uint8_t monthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
struct DateTime {
int year;
byte month;
byte day;
byte hour;
byte minute;
byte second;
byte dayofweek;
};
DateTime currentDateTime;
LiquidCrystal_PCF8574 lcd(0x27);
void setup() {
int error;
Serial.begin(115200);
Serial.println("LCD...");
while (! Serial);
Serial.println("Checking for LCD"); // See http://playground.arduino.cc/Main/I2cScanner
Wire.begin();
Wire.beginTransmission(0x27);
error = Wire.endTransmission();
Serial.print("Error: ");
Serial.print(error);
if (error == 0) {
Serial.println(": LCD found.");
lcd.begin(16, 2); // initialize the lcd
lcd.setBacklight(255);
lcd.home(); lcd.clear();
lcd.print(Version);
LCD_Delay = 1000; // 1 sec delay to read LCD
} else {
Serial.println(": LCD not found.");
LCD_Delay = 0; // no Delay needed no LCD
}
FastLED.addLeds<WS2812B, DATA_PIN, GRB>(LEDs, NUM_LEDS);
Serial.println();
Serial.println(Version); //File name of Project
Serial.print("Din Pin:\t\t");
Serial.println(DATA_PIN); //Din Data pin
Serial.print("Din Offset:\t");
Serial.println(Din_Offset);
// FastLED.delay(3000);
startWiFi();
startUDP();
if (!WiFi.hostByName(NTPServerName, timeServerIP)) {
Serial.println("DNS lookup failed. Rebooting.");
Serial.flush();
ESP.reset();
}
Serial.print("Time server:\t");
Serial.println(NTPServerName);
Serial.print("Time server IP:\t");
Serial.println(timeServerIP);
Serial.print("Sending Initial NTP request.");
Serial.println();
if (LCD_Delay != 0) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(NTPServerName);
lcd.setCursor(0, 1);
lcd.print(timeServerIP);
}
sendNTPpacket(timeServerIP);
delay(LCD_Delay);
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - prevNTP > intervalNTP) { // If a time interval has passed since last NTP request
prevNTP = currentMillis;
Serial.print("\t");
Serial.print("NTP request: ");
sendNTPpacket(timeServerIP); // Send an NTP request
}
uint32_t time = getTime(); // Check if an NTP response has arrived and get the (UNIX) time
if (time) { // If a new timestamp has been received
timeUNIX = time;
// Serial.print(" NTP response:\t");
Serial.print("\t");
Serial.println(timeUNIX);
lastNTPResponse = currentMillis;
}
else if ((currentMillis - lastNTPResponse) > 3600000) {
Serial.println("More than 1 hour since last NTP response. Rebooting.");
Serial.flush();
ESP.reset();
}
uint32_t actualTime = timeUNIX + (currentMillis - lastNTPResponse) / 1000;
if (actualTime != prevActualTime && timeUNIX != 0) { // If a second has passed since last update
prevActualTime = actualTime;
convertTime(actualTime);
if (analogRead(A0) > 20) //read Light dependant resitor(LDR) connected to ADC display dim if night
FastLED.setBrightness(Night);
else //display bright if day
FastLED.setBrightness(Day);
if ((getLEDHour(currentDateTime.hour) == getLEDMinuteOrSecond(currentDateTime.minute)) && ((currentDateTime.second) % 2 == 0)) //if hour and minute use same LED and even second
colorHour = colorBlinkMinute; //odd sec display minute color
else
colorHour = colorBlinkHour; //even sec display hour
for (int i = 0; i < NUM_LEDS; i++)
if (i % 15 == 0) // if 15
LEDs[i] = colorMarks15; //mark indices at every 15 minutes
else if ((i % 5 == 0) && (i % 15 != 0)) // if 5 && !15
LEDs[i] = colorMarks5; //mark indices at every 5 minutes
else
LEDs[i] = CRGB::Black;
LEDs[getLEDMinuteOrSecond(currentDateTime.second)] = colorSecond;
LEDs[getLEDMinuteOrSecond(currentDateTime.minute)] = colorMinute;
LEDs[getLEDHour(currentDateTime.hour)] = colorHour;
FastLED.show();
}
}
byte getLEDHour(byte hours) { //make 13 to 24 time same as 1 to 12 time
if (hours > 12)
hours -= 12;
if (hours <= 5) // used for connecting Din of LEDS at 6'oclock
hours = hours * 5 + Din_Offset; //not needed if Din at 12'oclock
else
hours = hours * 5 - Din_Offset;
if (currentDateTime.minute < 12)
return (hours);
if (currentDateTime.minute < 24) //inc hour led by 1/5
return (hours += 1);
if (currentDateTime.minute < 36) //inc hour led by 2/5
return (hours += 2);
if (currentDateTime.minute < 48) //inc hour led by 3/5
return (hours += 3);
if (currentDateTime.minute < 60) //inc hour led by 4/5
return (hours += 4);
}
byte getLEDMinuteOrSecond(byte minuteOrSecond) { // 0 offset just returns same value of minuteorsecond
if (minuteOrSecond < Din_Offset) // used for calculating Din of LEDS at 30 min
return minuteOrSecond + Din_Offset; // add 30 or 0 value of offset
else
return minuteOrSecond - Din_Offset; // sub 30 or 0 value of offset
}
void startWiFi() {
wifiMulti.addAP(ssid, pass);
Serial.println("Connecting");
while (wifiMulti.run() != WL_CONNECTED) { //show indication of wifi onnection
for (int i = 0; i < NUM_LEDS; i++) {
static uint8_t hue = 0; //define hue variable
LEDs.fill_rainbow(hue++); //fill all leds with rainbow
FastLED.delay(5); //control speed of change
Serial.print('.');
if (LCD_Delay != 0) { //if no LCD skip
if (i <= 16) {
lcd.setCursor(i, 1);
lcd.print(".");
}
}
}
}
Serial.println();
Serial.print("Connected to:\t");
Serial.println(WiFi.SSID());
Serial.print("IP address:\t");
Serial.print(WiFi.localIP());
Serial.println();
if (LCD_Delay != 0) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(WiFi.SSID());
lcd.setCursor(0, 1);
lcd.print(WiFi.localIP());
delay(LCD_Delay);
}
}
void startUDP() {
Serial.println("Starting UDP");
UDP.begin(123); // Start listening for UDP messages on port 123
Serial.print("Local port:\t");
Serial.println(UDP.localPort());
}
uint32_t getTime() {
if (UDP.parsePacket() == 0) { // If there's no response (yet)
return 0;
}
UDP.read(NTPBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
// Combine the 4 timestamp bytes into one 32-bit number
uint32_t NTPTime = (NTPBuffer[40] << 24) | (NTPBuffer[41] << 16) | (NTPBuffer[42] << 8) | NTPBuffer[43];
// Convert NTP time to a UNIX timestamp:
// Unix time starts on Jan 1 1970. That's 2208988800 seconds in NTP time:
const uint32_t seventyYears = 2208988800UL;
// subtract seventy years:
uint32_t UNIXTime = NTPTime - seventyYears;
return UNIXTime;
}
void sendNTPpacket(IPAddress& address) {
memset(NTPBuffer, 0, NTP_PACKET_SIZE); // set all bytes in the buffer to 0
// Initialize values needed to form NTP request
NTPBuffer[0] = 0b11100011; // LI, Version, Mode
// send a packet requesting a timestamp:
UDP.beginPacket(address, 123); // NTP requests are to port 123
UDP.write(NTPBuffer, NTP_PACKET_SIZE);
UDP.endPacket();
}
void convertTime(uint32_t time) {
time += (3600 * timeZone); // Correct time zone
currentDateTime.second = time % 60;
currentDateTime.minute = time / 60 % 60;
currentDateTime.hour = time / 3600 % 24;
time /= 60; // To minutes
time /= 60; // To hours
time /= 24; // To days
currentDateTime.dayofweek = ((time + 4) % 7); // 01/01/1970 = thursday (+4)
int year = 0;
int days = 0;
while ((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) {
year++;
}
days -= LEAP_YEAR(year) ? 366 : 365;
time -= days; // To days in this year, starting at 0
days = 0;
byte month = 0;
byte monthLength = 0;
for (month = 0; month < 12; month++) {
if (month == 1) { // February
if (LEAP_YEAR(year)) {
monthLength = 29;
} else {
monthLength = 28;
}
} else {
monthLength = monthDays[month];
}
if (time >= monthLength) {
time -= monthLength;
} else {
break;
}
}
currentDateTime.day = time + 1;
currentDateTime.year = year + 1970;
currentDateTime.month = month + 1;
/* Correct European Summer time //(no DST in Vietnam all references commeted out.)
if (summerTime()) {
currentDateTime.hour += 1;
}
*/
#ifdef DEBUG_ON
char buf[25]; //Buffer to show time on Serial monitor
char lcd1[16]; //Buffer to show LCD Line 1
char lcd2[16]; //Buffer to show LCD Line 2
sprintf(buf, "%03s %02d/%02d/%04d %02d:%02d:%02d ", weekday[currentDateTime.dayofweek], currentDateTime.day, currentDateTime.month, currentDateTime.year, currentDateTime.hour, currentDateTime.minute, currentDateTime.second);
sprintf(lcd1, " %02d:%02d:%02d", currentDateTime.hour, currentDateTime.minute, currentDateTime.second);
sprintf(lcd2, " %03s %02d/%02d/%04d", weekday[currentDateTime.dayofweek], currentDateTime.day, currentDateTime.month, currentDateTime.year);
//Serial.print("\r"); //use for serial Date Time on same line (CR)
Serial.print(buf);
Serial.println();
if (LCD_Delay != 0) {
lcd.setCursor(0, 0); //LCD Line 1 (row/col)
lcd.print(lcd1);
lcd.setCursor(0, 1); //LCD Line 2 (row/col)
lcd.print(lcd2);
}
#endif
}
/*
boolean summerTime() {
if (currentDateTime.month < 3 || currentDateTime.month > 10) return false; // No summer time in Jan, Feb, Nov, Dec
if (currentDateTime.month > 3 && currentDateTime.month < 10) return true; // Summer time in Apr, May, Jun, Jul, Aug, Sep
if (currentDateTime.month == 3 && (currentDateTime.hour + 24 * currentDateTime.day) >= (3 + 24 * (31 - (5 * currentDateTime.year / 4 + 4) % 7)) || currentDateTime.month == 10 && (currentDateTime.hour + 24 * currentDateTime.day) < (3 + 24 * (31 - (5 * currentDateTime.year / 4 + 1) % 7)))
return true;
else
return false;
}
*/