aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
blob: a0bbc6fb406e9bcdfe1195992046ff601090c039 (plain)
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
// #define DEBUG 1

#include <user_settings.h>
#include <header.h>

#include <FastLED.h>
#include <ESP8266WiFi.h>
#include <ezTime.h>

// Define the array of leds
CRGB leds[LED_COUNT];

Timezone CopenhagenTime;

int hue = 0;
int max_brightness = 255;
bool on_state[SEGMENT_COUNT * DIGIT_COUNT] = {false};

typedef enum : uint8_t {
	seg_a = 1<<0, // 00000001
	seg_b = 1<<1, // 00000010
	seg_c = 1<<2, // 00000100
	seg_d = 1<<3, // ...
	seg_e = 1<<4,
	seg_f = 1<<5,
	seg_g = 1<<6
} segments;

uint8_t symbols[] = {
	/* 0 */ seg_a | seg_b | seg_c | seg_d | seg_e | seg_f,
	/* 1 */ seg_b | seg_c,
	/* 2 */ seg_a | seg_b | seg_g | seg_e | seg_d,
	/* 3 */ seg_a | seg_b | seg_g | seg_c | seg_d,
	/* 4 */ seg_f | seg_g | seg_c | seg_b,
	/* 5 */ seg_a | seg_f | seg_g | seg_c | seg_d,
	/* 6 */ seg_a | seg_f | seg_g | seg_c | seg_d | seg_e,
	/* 7 */ seg_a | seg_b | seg_c,
	/* 8 */ seg_a | seg_b | seg_c | seg_d | seg_e | seg_f | seg_g,
	/* 9 */ seg_g | seg_f | seg_a | seg_b | seg_c | seg_d,
	/* ° */ seg_a | seg_b | seg_g | seg_f,
	/* C */ seg_a | seg_f | seg_e | seg_d
};

uint8_t spin_animation[] = {
	seg_a,
	seg_b,
	seg_c,
	seg_d,
	seg_e,
	seg_f,
};


uint8_t dual_spin_animation[] = {
	seg_a | seg_d,
	seg_b | seg_e,
	seg_c | seg_f,
	seg_d | seg_a,
	seg_e | seg_b,
	seg_f | seg_c,
};

void display_symbols(uint8_t *symbols_mask) {
	// Fades all at once
	for (int brightness = 0; brightness <= max_brightness; brightness ++) {
		for (uint8_t digit_index = 0; digit_index < DIGIT_COUNT; digit_index++) {
			// Counts up by bitshifting
			uint8_t seg_counter = 1;

			for (int segment_index = 0; segment_index < SEGMENT_COUNT; segment_index++) {
				int digit_offset = digit_index * SEGMENT_COUNT;
				int led_raw_index = digit_offset + segment_index;
				int led_index = START_OFFSET + led_raw_index;
				bool previously_on = on_state[led_raw_index];

				// Compare the current segment bit with the mask for the symbol
				bool turn_on = symbols_mask[digit_index] & seg_counter;

				if (turn_on) {
					// Turn on LED
					if(previously_on){
						// Previously on, allow hue change
						leds[led_index] = CHSV(hue, SATURATION, max_brightness);
					} else {
						leds[led_index] = CHSV(hue, SATURATION, brightness);
					}
				} else {
					// Turn off LED
					if(previously_on) {
						leds[led_index] = CHSV(hue, SATURATION, max_brightness - brightness);
					}
				}

				if (brightness == max_brightness) {
					on_state[led_raw_index] = turn_on;
				}

				seg_counter = seg_counter<<1;
			}
		}
		FastLED.show();
		delay(2);
	}
}

void display_number(int number) {
	uint8_t symbols_mask[DIGIT_COUNT];
	// Start from the last digit
	for (int digit_index = DIGIT_COUNT - 1; digit_index >= 0; digit_index--) {
		symbols_mask[digit_index] = symbols[number % 10];
		number /= 10;
	}
	display_symbols(symbols_mask);
}

void display_symbol(int digit_index, uint8_t symbol) {
	// Counts up by bitshifting
	uint8_t seg_counter = 1;
	for (int segment_index = 0; segment_index < SEGMENT_COUNT; segment_index++) {
		int offset = digit_index * SEGMENT_COUNT;
		int led_index = START_OFFSET + offset + segment_index;

		// Compare the current segment bit with the mask for the symbol
		if (symbol & seg_counter) {
			// Turn on LED
			leds[led_index] = CHSV(hue, SATURATION, max_brightness);
			FastLED.show();
		}

		seg_counter = seg_counter<<1;
	}
}

void play_animation(uint8_t *animation, int animation_size, int segment_delay) {
	for (int i = 0; i < animation_size; i++){
		for (int digit_index = 0; digit_index < 4; digit_index++) {
			display_symbol(digit_index, animation[i]);
		}

		hue += 16;
		FastLED.show();
		delay(segment_delay);
	}
}

void update_clock() {
	// Format the time as a 4-digit integer
	int timeInt = CopenhagenTime.dateTime("Hi").toInt(); // Sadly string format
	display_number(timeInt);
	hue++;
}

void setup() {
	FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, LED_COUNT).setCorrection( TypicalLEDStrip );
	FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, LED_COUNT);  // GRB ordering is assumed

	// Turn off all LEDs
  FastLED.clear();

	#ifdef DEBUG
	Serial.begin(9600);
	#endif	
	
	setServer(NTP_SERVER);

	WiFi.setHostname("7-segment-esp-ws2811"); //define hostname
	WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
	Serial.print("Connecting");
	while (WiFi.status() != WL_CONNECTED)
	{
		if (millis() < WIFI_CONN_ANI_TIMEOUT) {
			play_animation(spin_animation, sizeof(spin_animation), 100);
		} else {
			// Turn off all LEDs
			FastLED.clear();		
		}
	}
	
	delay(100);

 	hue = 0;
	// Turn off all LEDs
  FastLED.clear();

	Serial.println();
	Serial.print("Connected, IP address: ");
	Serial.println(WiFi.localIP());

	waitForSync();
	Serial.println("UTC: " + UTC.dateTime());
	CopenhagenTime.setLocation("Europe/Copenhagen");
	Serial.println("Copenhagen time: " + CopenhagenTime.dateTime());
	
	update_clock();
}

/*
// Test each segment
int i = 0;

void loop() {
	leds[i] = CRGB::Red;
	FastLED.show();
	delay(500);

	leds[i] = CRGB::Black;
	FastLED.show();
	delay(500);
	i++;
	if (i > LED_COUNT - 1) {
		i = 0;
	}
}
*/

void loop() {
	// Only update on each hole minute to avoid flickering
	int seconds = CopenhagenTime.dateTime("s").toInt();
	int minutes = CopenhagenTime.dateTime("i").toInt();

	if(minutes == 59 && seconds >= 55) { //if(minutes == 59 && seconds >= 55) {
		play_animation(dual_spin_animation, sizeof(spin_animation), 50);
  	FastLED.clear();
	}

	if(seconds != 0) {
		delay(10);
		return;
	}

	update_clock();

	delay(1000);
}