forked from easytarget/esp32-cam-webserver
-
Notifications
You must be signed in to change notification settings - Fork 10
/
esp32-cam-webserver.ino
191 lines (161 loc) · 5.66 KB
/
esp32-cam-webserver.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
#include "src/app_config.h" // global definitions
#include "src/storage.h" // Filesystem
#include "src/app_conn.h" // Conectivity
#include "src/app_cam.h" // Camera
#include "src/app_httpd.h" // Web server
#include "src/camera_pins.h" // Pin Mappings
/*
* This sketch is a extension/expansion/rework of the ESP32 Camera webserer example.
*
*/
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
// Warn if no PSRAM is detected (typically user error with board selection in the IDE)
if(!psramFound()){
Serial.println("\r\nFatal Error; Halting");
while (true) {
Serial.println("No PSRAM found; camera cannot be initialised: Please check the board config for your module.");
delay(5000);
}
}
#if defined(LED_PIN) // If we have a notification LED, set it to output
pinMode(LED_PIN, OUTPUT);
#endif
// Start the filesystem before we initialise the camera
filesystemStart();
delay(200); // a short delay to let spi bus settle after init
// Start (init) the camera
if (AppCam.start() != OS_SUCCESS) {
delay(100); // need a delay here or the next serial o/p gets missed
Serial.println();
Serial.print("CRITICAL FAILURE:"); Serial.println(AppCam.getErr());
Serial.println("A full (hard, power off/on) reboot will probably be needed to recover from this.");
Serial.println("Meanwhile; this unit will reboot in 1 minute since these errors sometime clear automatically");
resetI2CBus();
scheduleReboot(60);
}
else
Serial.println("Camera init succeeded");
// Now load and apply preferences
delay(200); // a short delay to let spi bus settle after camera init
AppCam.loadPrefs();
/*
* Camera setup complete; initialise the rest of the hardware.
*/
// Start Wifi and loop until we are connected or have started an AccessPoint
while (AppConn.wifiStatus() != WL_CONNECTED) {
if(AppConn.start() != WL_CONNECTED) {
Serial.println("Failed to initiate WiFi, retryng in 5 sec ... ");
delay(5000);
}
else {
// Flash the LED to show we are connected
notifyConnect();
}
}
// Set time via NTP server when enabled
if(!AppConn.isAccessPoint()) {
AppConn.configNTP();
Serial.print("Time: ");
AppConn.printLocalTime(true);
}
// Start the web server
AppHttpd.start();
}
void loop() {
/*
* Just loop forever, reconnecting Wifi As necesscary in client mode
* The stream and URI handler processes initiated by the startCameraServer() call at the
* end of setup() will handle the camera and UI processing from now on.
*/
if (AppConn.isAccessPoint()) {
// Accespoint is permanently up, so just loop, servicing the captive portal as needed
// Rather than loop forever, follow the watchdog, in case we later add auto re-scan.
unsigned long pingwifi = millis();
while (millis() - pingwifi < WIFI_WATCHDOG ) {
// delay(100);
AppConn.handleOTA();
handleSerial();
AppConn.handleDNSRequest();
}
AppHttpd.cleanupWsClients();
} else {
// client mode can fail; so reconnect as appropriate
if (AppConn.wifiStatus() == WL_CONNECTED) {
// We are connected
// loop here for §
unsigned long pingwifi = millis();
while (millis() - pingwifi < WIFI_WATCHDOG ) {
AppConn.handleOTA();
handleSerial();
}
AppHttpd.cleanupWsClients();
} else {
// disconnected; notify
notifyDisconnect();
// ensures disconnect is complete, wifi scan cleared
AppConn.stop();
//attempt to reconnect
if(AppConn.start() == WL_CONNECTED) {
notifyConnect();
}
}
}
}
/// @brief tries to initialize the filesystem until success, otherwise loops indefinitely
void filesystemStart(){
Serial.println("Starting filesystem");
while ( !Storage.init() ) {
// if we sit in this loop something is wrong;
Serial.println("Filesystem mount failed");
for (int i=0; i<10; i++) {
flashLED(100); // Show filesystem failure
delay(100);
}
delay(1000);
Serial.println("Retrying..");
}
// Storage.listDir("/", 0);
}
// Serial input
void handleSerial() {
if(Serial.available()) {
char cmd = Serial.read();
// Rceiving commands and data from serial. Any input, which doesnt start from '#' is ignored.
if (cmd == '#' ) {
String rsp = Serial.readStringUntil('\n');
rsp.trim();
snprintf(AppHttpd.getSerialBuffer(), SERIAL_BUFFER_SIZE, rsp.c_str());
}
}
}
void notifyConnect() {
for (int i = 0; i < 5; i++) {
flashLED(150);
delay(50);
}
AppHttpd.serialSendCommand("Connected");
}
void notifyDisconnect() {
AppHttpd.serialSendCommand("Disconnected");
}
// Flash LED if LED pin defined
void flashLED(int flashtime) {
#ifdef LED_PIN
digitalWrite(LED_PIN, LED_ON);
delay(flashtime);
digitalWrite(LED_PIN, LED_OFF);
#endif
}
void scheduleReboot(int delay) {
esp_task_wdt_init(delay,true);
esp_task_wdt_add(NULL);
}
// Reset the I2C bus.. may help when rebooting.
void resetI2CBus() {
periph_module_disable(PERIPH_I2C0_MODULE); // try to shut I2C down properly in case that is the problem
periph_module_disable(PERIPH_I2C1_MODULE);
periph_module_reset(PERIPH_I2C0_MODULE);
periph_module_reset(PERIPH_I2C1_MODULE);
}