Fix LED change, fix chasing animation change
[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   chase();
122 }
123
124 void chase() {
125   byte disp = 0;
126   for (unsigned int j=0; j<5; j++) {
127     for (unsigned int i=0; i<8; i++) {
128       digitalWrite(loadPin, 0);
129       bitSet(disp, i);
130       shiftOut(dataPin, clockPin, LSBFIRST, disp); //right
131       shiftOut(dataPin, clockPin, LSBFIRST, disp); //left
132       digitalWrite(loadPin, 1);
133       delay(25);
134       bitClear(disp, i);
135     }  
136   }
137 }
138
139 void casino() {
140   for (unsigned int i=0; i<20; i++) {
141     digitalWrite(loadPin, 0);
142     shiftOut(dataPin, clockPin, LSBFIRST, digits[random(0,9)]); //right
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     shiftOut(dataPin, clockPin, LSBFIRST, digits[random(0,9)]); //left
147     shiftOut(dataPin, clockPin, LSBFIRST, digits[random(0,9)]); //left
148     digitalWrite(loadPin, 1);
149     delay(25);
150   }  
151 }
152
153 /**
154  * Map HSL color space to RGB
155  * 
156  * Totally borrowed from:
157  * http://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/ 
158  * 
159  * Probably not the most efficient solution, but 
160  * it get's the job done.
161  */
162 uint32_t hsl(uint16_t ih, uint8_t is, uint8_t il) {
163
164   float h, s, l, t1, t2, tr, tg, tb;
165   uint8_t r, g, b;
166
167   h = (ih % 360) / 360.0;
168   s = constrain(is, 0, 100) / 100.0;
169   l = constrain(il, 0, 100) / 100.0;
170
171   if ( s == 0 ) { 
172     r = g = b = 255 * l;
173     return ((uint32_t)r << 16) | ((uint32_t)g <<  8) | b;
174   } 
175   
176   if ( l < 0.5 ) t1 = l * (1.0 + s);
177   else t1 = l + s - l * s;
178   
179   t2 = 2 * l - t1;
180   tr = h + 1/3.0;
181   tg = h;
182   tb = h - 1/3.0;
183
184   r = hsl_convert(tr, t1, t2);
185   g = hsl_convert(tg, t1, t2);
186   b = hsl_convert(tb, t1, t2);
187
188   // NeoPixel packed RGB color
189   return ((uint32_t)r << 16) | ((uint32_t)g <<  8) | b;
190 }
191 /**
192  * HSL Convert
193  * Helper function
194  */
195 uint8_t hsl_convert(float c, float t1, float t2) {
196
197   if ( c < 0 ) c+=1; 
198   else if ( c > 1 ) c-=1;
199
200   if ( 6 * c < 1 ) c = t2 + ( t1 - t2 ) * 6 * c;
201   else if ( 2 * c < 1 ) c = t1;
202   else if ( 3 * c < 2 ) c = t2 + ( t1 - t2 ) * ( 2/3.0 - c ) * 6;
203   else c = t2;
204   
205   return (uint8_t)(c*255); 
206 }
207
208 void loop() {
209   timeClient.update();
210
211   unsigned int b=0;
212   unsigned int Hour = timeClient.getHours();
213   unsigned int Minute = timeClient.getMinutes();
214   unsigned int Seconds = timeClient.getSeconds();
215   
216   digitalWrite(loadPin, 0);
217   shiftOut(dataPin, clockPin, LSBFIRST, 0b000000000000000000000000000000000000000000000000);
218   digitalWrite(loadPin, 1);
219
220   chase();
221   
222   while (Seconds<60) {
223     Hour1 = (Hour/10U) % 10;
224     Hour2 = (Hour/1U) % 10;
225     Minute1 = (Minute/10U) % 10;
226     Minute2 = (Minute/1U) % 10;
227     Second1 = (Seconds/10U) % 10;
228     Second2 = (Seconds/1U) % 10;
229     unsigned int pause = 1000;
230
231     strip.setPixelColor(0, hsl(HColor, saturation, lightness));
232     strip.show();
233     strip.setPixelColor(1, hsl(HColor, saturation, lightness));
234     strip.show();
235     strip.setPixelColor(2, hsl(MColor, saturation, lightness));
236     strip.show();
237     strip.setPixelColor(3, hsl(MColor, saturation, lightness));
238     strip.show();
239     strip.setPixelColor(4, hsl(SColor, saturation, lightness));
240     strip.show();
241     strip.setPixelColor(5, hsl(SColor, saturation, lightness));
242     strip.show();
243
244     HColor = (HColor + 1) % 360;
245     MColor = (MColor + 1) % 360;
246     SColor = (SColor + 1) % 360;
247
248     #ifdef SPIN_CASINO
249     if (Second2==0) {
250       casino();
251       pause=500;
252     } else {
253       pause = 1000;
254     }
255     #else
256     pause = 1000;
257     #endif
258     
259     digitalWrite(loadPin, 0);
260     
261     shiftOut(dataPin, clockPin, LSBFIRST, digits[Second2]); //right
262     shiftOut(dataPin, clockPin, LSBFIRST, digits[Second1]); //left
263     shiftOut(dataPin, clockPin, LSBFIRST, digits[Minute2]); //right
264     shiftOut(dataPin, clockPin, LSBFIRST, digits[Minute1]); //left
265     shiftOut(dataPin, clockPin, LSBFIRST, digits[Hour2]); //right
266     shiftOut(dataPin, clockPin, LSBFIRST, digits[Hour1]); //left
267     digitalWrite(loadPin, 1);
268     delay(pause);
269     Seconds = Seconds+1;
270   }
271 }