-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMultiZoneMatrixClock.ino
More file actions
252 lines (219 loc) · 8.19 KB
/
Copy pathMultiZoneMatrixClock.ino
File metadata and controls
252 lines (219 loc) · 8.19 KB
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
#include <ESP8266WiFi.h>
#include <WiFiManager.h>
#include <ESP8266WebServer.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <EEPROM.h>
#include <time.h>
#include "config.h"
#include "timezone.h"
#include "display.h"
#include "webserver.h"
// Global objects
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, DEFAULT_NTP_SERVER);
ESP8266WebServer server(80);
TimezoneManager tzManager;
DisplayManager displayManager;
Settings settings;
WebServerManager webManager(&server, &tzManager, &settings, &displayManager, &timeClient);
void saveSettings() {
settings.magic = EEPROM_MAGIC;
for (int i = 0; i < TZ_COUNT; i++) {
settings.enabled[i] = tzManager.tzEnabled[i] ? 1 : 0;
}
EEPROM.put(0, settings);
EEPROM.commit();
}
void loadSettings() {
EEPROM.get(0, settings);
if (settings.magic != EEPROM_MAGIC) {
// Default settings
settings.intensity = 5;
settings.use12Hour = 0;
settings.debugEnabled = 0;
settings.timeDisplayDuration = 10; // Default 10 seconds
settings.flip180 = 0;
strncpy(settings.ntpServer, DEFAULT_NTP_SERVER, sizeof(settings.ntpServer) - 1);
settings.ntpServer[sizeof(settings.ntpServer) - 1] = '\0';
strncpy(settings.password, DEFAULT_WEB_PASSWORD, sizeof(settings.password) - 1);
settings.password[sizeof(settings.password) - 1] = '\0';
for (int i = 0; i < TZ_COUNT; i++) {
settings.enabled[i] = tzManager.tzEnabled[i] ? 1 : 0;
}
saveSettings();
} else {
// Load enabled timezones from EEPROM
for (int i = 0; i < TZ_COUNT; i++) {
tzManager.tzEnabled[i] = settings.enabled[i] != 0;
}
// Initialize defaults for new fields if they're 0 (first time loading after update)
if (settings.timeDisplayDuration == 0) {
settings.timeDisplayDuration = 10;
}
// Guarantee null-termination on string fields read from EEPROM
settings.ntpServer[sizeof(settings.ntpServer) - 1] = '\0';
settings.password[sizeof(settings.password) - 1] = '\0';
if (settings.ntpServer[0] == '\0') {
strncpy(settings.ntpServer, DEFAULT_NTP_SERVER, sizeof(settings.ntpServer) - 1);
}
if (settings.password[0] == '\0') {
strncpy(settings.password, DEFAULT_WEB_PASSWORD, sizeof(settings.password) - 1);
}
}
// Update display manager with time display duration
displayManager.setTimeDisplayDuration(settings.timeDisplayDuration * 1000); // Convert to milliseconds
}
String getShortTime() {
String full = timeClient.getFormattedTime(); // HH:MM:SS
String hh = full.substring(0, 2);
String mm = full.substring(3, 5);
int hour = hh.toInt();
int minute = mm.toInt();
if (settings.use12Hour) {
bool isPM = hour >= 12;
hour = hour % 12;
if (hour == 0) hour = 12;
// Format with zero padding
String hourStr = hour < 10 ? "0" + String(hour) : String(hour);
String minuteStr = minute < 10 ? "0" + String(minute) : String(minute);
return hourStr + ":" + minuteStr + (isPM ? " PM" : " AM");
} else {
// Already padded from getFormattedTime, but ensure it's correct
return hh + ":" + mm;
}
}
void setup() {
Serial.begin(115200);
delay(1000);
// Initialize EEPROM
EEPROM.begin(EEPROM_SIZE);
// Initialize timezone manager
tzManager.init();
// Load settings from EEPROM (this will initialize debug flag)
loadSettings();
// Only log if debug is enabled
if (settings.debugEnabled) {
Serial.println("Multi-Zone Matrix Clock Starting...");
}
// Initialize display
displayManager.begin(settings.intensity);
displayManager.setShowTimezone(tzManager.getEnabledCount() > 1);
displayManager.setFlip180(settings.flip180 != 0);
// Connect to WiFi
WiFiManager wm;
wm.autoConnect("MultiZoneClock");
if (settings.debugEnabled) {
Serial.print("Connected! IP address: ");
Serial.println(WiFi.localIP());
}
// Initialize NTP client using configured pool server
timeClient.setPoolServerName(settings.ntpServer);
timeClient.begin();
// Find first enabled timezone
int firstTZ = tzManager.nextEnabledTZ(-1);
if (firstTZ >= 0) {
displayManager.setCurrentTZ(firstTZ);
long offset = tzManager.getCurrentOffset(firstTZ);
timeClient.setTimeOffset(offset);
}
// Initialize web server
webManager.begin();
// Start with first timezone display
int enabledCount = tzManager.getEnabledCount();
if (enabledCount > 0) {
if (enabledCount > 1 && displayManager.shouldShowTimezone()) {
displayManager.setState(SHOW_TZ_SCROLL);
String tzName = String(tzManager.getTimezoneName(firstTZ));
displayManager.setTimezoneName(tzName); // This will start the scroll
} else {
// Single timezone mode - go straight to time
String timeStr = getShortTime();
displayManager.setTimeString(timeStr);
displayManager.setState(SHOW_TIME_STATIC);
}
}
if (settings.debugEnabled) {
Serial.println("Setup complete!");
}
}
void loop() {
server.handleClient();
// Update NTP client periodically (it's smart enough to only sync when needed)
static unsigned long lastNTPUpdate = 0;
if (millis() - lastNTPUpdate >= NTP_UPDATE_INTERVAL) {
timeClient.update();
lastNTPUpdate = millis();
}
// Update time offset only when timezone changes (for DST and timezone switching)
static int lastTZ = -1;
int currentTZ = displayManager.getCurrentTZ();
if (currentTZ != lastTZ) {
long currentOffset = tzManager.getCurrentOffset(currentTZ);
timeClient.setTimeOffset(currentOffset);
lastTZ = currentTZ;
}
DisplayState state = displayManager.getState();
switch (state) {
case SHOW_TZ_SCROLL:
displayManager.update();
if (displayManager.getState() == SHOW_TZ_WAIT) {
// Prepare time string
String timeStr = getShortTime();
displayManager.setTimeString(timeStr);
}
break;
case SHOW_TZ_WAIT:
displayManager.update();
break;
case SHOW_TIME_LTR:
displayManager.update();
break;
case SHOW_TIME_RTL:
displayManager.update();
if (displayManager.getState() == SHOW_TZ_SCROLL) {
// Move to next timezone
int nextTZ = tzManager.nextEnabledTZ(currentTZ);
displayManager.setCurrentTZ(nextTZ);
// Update timezone display setting based on count
int enabledCount = tzManager.getEnabledCount();
displayManager.setShowTimezone(enabledCount > 1);
if (displayManager.shouldShowTimezone()) {
String tzName = String(tzManager.getTimezoneName(nextTZ));
displayManager.setTimezoneName(tzName);
} else {
// Single timezone mode - skip timezone name, go straight to time
displayManager.setTimezoneName("");
String timeStr = getShortTime();
displayManager.setTimeString(timeStr);
displayManager.setState(SHOW_TZ_WAIT);
}
}
break;
case SHOW_TIME_STATIC: {
displayManager.update();
// Update time string periodically for single timezone mode
int enabledCount = tzManager.getEnabledCount();
if (enabledCount == 1) {
// Single timezone mode - just update time every second
static unsigned long lastTimeUpdate = 0;
if (millis() - lastTimeUpdate >= 1000) {
String timeStr = getShortTime();
displayManager.setTimeString(timeStr);
displayManager.setState(SHOW_TIME_STATIC); // Reset the state to update display
lastTimeUpdate = millis();
}
} else if (millis() - displayManager.getWaitStart() >= (unsigned long)settings.timeDisplayDuration * 1000) {
// Multiple timezones - move to next timezone
int nextTZ = tzManager.nextEnabledTZ(currentTZ);
displayManager.setCurrentTZ(nextTZ);
displayManager.setState(SHOW_TZ_SCROLL);
String tzName = String(tzManager.getTimezoneName(nextTZ));
displayManager.setTimezoneName(tzName); // This will start the scroll
}
break;
}
}
// Small delay to prevent overwhelming the system
delay(10);
}