0483d84c2afb6bd701dd9f9a33bafdaa89bb6120
[vfd-clock.git] / code / rhandorf-vfd-clock / rhandorf-vfd-clock.ino
1 //NodeMCU  Wemos D1
2 //Arduino as ISP
3 #include <SPI.h>
4 #include <NTPClient.h>
5 #include <ESP8266WiFi.h>
6 #include <WiFiUdp.h>
7 #include <Adafruit_NeoPixel.h>
8
9 #include "config.h"
10
11 /*
12  * TO CONFIGURE YOUR SSID AND TIME ZONE, EDIT CONFIG.H
13  */
14
15 #define LED_PIN D6
16 #define LED_COUNT 6
17
18 static uint16_t hue = 0; // 0-359
19 uint8_t saturation = 100; // 0-100
20 uint8_t lightness = 50; // 0-100
21
22 unsigned int HColor = 0;
23 unsigned int MColor = 0;
24 unsigned int SColor = 0;
25
26 unsigned int Hour1 = 0;
27 unsigned int Hour2 = 0;
28 unsigned int Minute1 = 0;
29 unsigned int Minute2 = 0;
30 unsigned int Second1 = 0;
31 unsigned int Second2 = 0;
32
33 WiFiUDP ntpUDP;
34 NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);
35 Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
36
37 //arduino
38 //const int dataPin = 13;   //Outputs the byte to transfer
39 //const int loadPin = 11;   //3 //Controls the internal transference of data in SN74HC595 internal registers
40 //const int clockPin = 12;  // 4//Generates the clock signal to control the transference of data
41
42 //nodeMCU
43 //const int dataPin = 14;   //Outputs the byte to transfer
44 //const int loadPin = 0;   //3 //Controls the internal transference of data in SN74HC595 internal registers
45 //const int clockPin = 4;  // 4//Generates the clock signal to control the transference of data
46
47 //wemos
48 const int dataPin = 14;  //D5 //Outputs the byte to transfer
49 const int loadPin = 0;   //D3 //3 //Controls the internal transference of data in SN74HC595 internal registers
50 const int clockPin = 4;  //D2 // 4//Generates the clock signal to control the transference of data
51
52 byte digits[10] {
53   0b11111100, //0
54   0b01100000, //1
55   0b11011010, //2
56   0b11110010, //3
57   0b01100110, //4
58   0b10110110, //5
59   0b10111110, //6
60   0b11100000, //7
61   0b11111110, //8
62   0b11100110  //9
63 };
64
65 void setup() {
66   Serial.begin(115200);
67
68   HColor = 0;
69   MColor = HColor + COLOR_OFFSET;
70   SColor = MColor + COLOR_OFFSET;
71   
72   pinMode(dataPin, OUTPUT);
73   pinMode(loadPin, OUTPUT);
74   pinMode(clockPin, OUTPUT);  
75   digitalWrite(loadPin, 0);
76   shiftOut(dataPin, clockPin, LSBFIRST, 0b00000000);
77   shiftOut(dataPin, clockPin, LSBFIRST, 0b00000000);
78   shiftOut(dataPin, clockPin, LSBFIRST, 0b00000000);
79   shiftOut(dataPin, clockPin, LSBFIRST, 0b00000000);
80   shiftOut(dataPin, clockPin, LSBFIRST, 0b00000000);
81   shiftOut(dataPin, clockPin, LSBFIRST, 0b00000000);
82   digitalWrite(loadPin, 1);
83
84   WiFi.begin(ssid, password);
85   int i=0;
86   int b=0;
87   while ( WiFi.status() != WL_CONNECTED ) {
88     delay ( 500 );
89     digitalWrite(loadPin, 0);
90     shiftOut(dataPin, clockPin, LSBFIRST, digits[i]); //right
91     shiftOut(dataPin, clockPin, LSBFIRST, digits[b]); //left
92     shiftOut(dataPin, clockPin, LSBFIRST, 0b00000000);
93     shiftOut(dataPin, clockPin, LSBFIRST, 0b00000000);
94     shiftOut(dataPin, clockPin, LSBFIRST, 0b00000000);
95     shiftOut(dataPin, clockPin, LSBFIRST, 0b00000000);
96     digitalWrite(loadPin, 1);
97     i++;
98     if (i==10) {
99       i=0;
100       b++;
101     }
102     if (b==9 && i==9) {
103       digitalWrite(loadPin, 0);
104       shiftOut(dataPin, clockPin, LSBFIRST, 0b00000001); //right
105       shiftOut(dataPin, clockPin, LSBFIRST, 0b00001011); //right
106       shiftOut(dataPin, clockPin, LSBFIRST, 0b00111010); //00111111
107       shiftOut(dataPin, clockPin, LSBFIRST, 0b00001010); //right
108       shiftOut(dataPin, clockPin, LSBFIRST, 0b00001010); //right
109       shiftOut(dataPin, clockPin, LSBFIRST, 0b10011110); //left
110       digitalWrite(loadPin, 1);
111       delay(10000);
112       i=0;
113       b=0;
114     }
115   }
116   timeClient.begin();
117   strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
118   strip.show();            // Turn OFF all pixels ASAP
119   strip.setBrightness(25); // Set BRIGHTNESS to about 1/5 (max = 255)
120 }
121
122 void chase() {
123   byte disp = 0;
124   for (unsigned int j=0; j<5; j++) {
125     for (unsigned int i=0; i<8; i++) {
126       digitalWrite(loadPin, 0);
127       bitSet(disp, i);
128       shiftOut(dataPin, clockPin, LSBFIRST, disp); //right
129       shiftOut(dataPin, clockPin, LSBFIRST, disp); //left
130       digitalWrite(loadPin, 1);
131       delay(25);
132       bitClear(disp, i);
133     }  
134   }
135 }
136
137 void casino() {
138   for (unsigned int i=0; i<20; i++) {
139     digitalWrite(loadPin, 0);
140     shiftOut(dataPin, clockPin, LSBFIRST, digits[random(0,9)]); //right
141     shiftOut(dataPin, clockPin, LSBFIRST, digits[random(0,9)]); //left
142     shiftOut(dataPin, clockPin, LSBFIRST, digits[random(0,9)]); //left
143     shiftOut(dataPin, clockPin, LSBFIRST, digits[random(0,9)]); //left
144     shiftOut(dataPin, clockPin, LSBFIRST, digits[random(0,9)]); //left
145     shiftOut(dataPin, clockPin, LSBFIRST, digits[random(0,9)]); //left
146     digitalWrite(loadPin, 1);
147     delay(25);
148   }  
149 }
150
151 /**
152  * Map HSL color space to RGB
153  * 
154  * Totally borrowed from:
155  * http://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/ 
156  * 
157  * Probably not the most efficient solution, but 
158  * it get's the job done.
159  */
160 uint32_t hsl(uint16_t ih, uint8_t is, uint8_t il) {
161
162   float h, s, l, t1, t2, tr, tg, tb;
163   uint8_t r, g, b;
164
165   h = (ih % 360) / 360.0;
166   s = constrain(is, 0, 100) / 100.0;
167   l = constrain(il, 0, 100) / 100.0;
168
169   if ( s == 0 ) { 
170     r = g = b = 255 * l;
171     return ((uint32_t)r << 16) | ((uint32_t)g <<  8) | b;
172   } 
173   
174   if ( l < 0.5 ) t1 = l * (1.0 + s);
175   else t1 = l + s - l * s;
176   
177   t2 = 2 * l - t1;
178   tr = h + 1/3.0;
179   tg = h;
180   tb = h - 1/3.0;
181
182   r = hsl_convert(tr, t1, t2);
183   g = hsl_convert(tg, t1, t2);
184   b = hsl_convert(tb, t1, t2);
185
186   // NeoPixel packed RGB color
187   return ((uint32_t)r << 16) | ((uint32_t)g <<  8) | b;
188 }
189 /**
190  * HSL Convert
191  * Helper function
192  */
193 uint8_t hsl_convert(float c, float t1, float t2) {
194
195   if ( c < 0 ) c+=1; 
196   else if ( c > 1 ) c-=1;
197
198   if ( 6 * c < 1 ) c = t2 + ( t1 - t2 ) * 6 * c;
199   else if ( 2 * c < 1 ) c = t1;
200   else if ( 3 * c < 2 ) c = t2 + ( t1 - t2 ) * ( 2/3.0 - c ) * 6;
201   else c = t2;
202   
203   return (uint8_t)(c*255); 
204 }
205
206 void loop() {
207   timeClient.update();
208
209   unsigned int b=0;
210   unsigned int Hour = timeClient.getHours();
211   unsigned int Minute = timeClient.getMinutes();
212   unsigned int Seconds = timeClient.getSeconds();
213   
214   digitalWrite(loadPin, 0);
215   shiftOut(dataPin, clockPin, LSBFIRST, 0b000000000000000000000000000000000000000000000000);
216   digitalWrite(loadPin, 1);
217   
218   chase();
219   
220   while (Seconds<60) {
221     Hour1 = (Hour/10U) % 10;
222     Hour2 = (Hour/1U) % 10;
223     Minute1 = (Minute/10U) % 10;
224     Minute2 = (Minute/1U) % 10;
225     Second1 = (Seconds/10U) % 10;
226     Second2 = (Seconds/1U) % 10;
227     unsigned int pause = 1000;
228
229     strip.setPixelColor(0, hsl(HColor, saturation, lightness));
230     strip.setPixelColor(1, hsl(HColor, saturation, lightness));
231     strip.setPixelColor(2, hsl(MColor, saturation, lightness));
232     strip.setPixelColor(3, hsl(MColor, saturation, lightness));
233     strip.setPixelColor(4, hsl(SColor, saturation, lightness));
234     strip.setPixelColor(5, hsl(SColor, saturation, lightness));
235
236     HColor = (HColor + 1) % 360;
237     MColor = (MColor + 1) % 360;
238     SColor = (SColor + 1) % 360;
239
240     #ifdef SPIN_CASINO
241     if (Second2==0) {
242       casino();
243       pause=500;
244     } else {
245       pause = 1000;
246     }
247     #else
248     pause = 1000;
249     #endif
250     
251     digitalWrite(loadPin, 0);
252     
253     shiftOut(dataPin, clockPin, LSBFIRST, digits[Second2]); //right
254     shiftOut(dataPin, clockPin, LSBFIRST, digits[Second1]); //left
255     shiftOut(dataPin, clockPin, LSBFIRST, digits[Minute2]); //right
256     shiftOut(dataPin, clockPin, LSBFIRST, digits[Minute1]); //left
257     shiftOut(dataPin, clockPin, LSBFIRST, digits[Hour2]); //right
258     shiftOut(dataPin, clockPin, LSBFIRST, digits[Hour1]); //left
259     digitalWrite(loadPin, 1);
260     delay(pause);
261     Seconds = Seconds+1;
262   }
263 }