|
#include <ESP8266WiFi.h> |
|
#include <WiFiClient.h> |
|
#include <ESP8266WebServer.h> |
|
#include <ESP8266mDNS.h> |
|
#include <Adafruit_VC0706.h> |
|
#include <SPI.h> |
|
#include <SD.h> |
|
|
|
#include <SoftwareSerial.h> |
|
|
|
#define DBG_PORT Serial |
|
|
|
const char* ssid = "SSID"; |
|
const char* password = "PASSWORD"; |
|
const char* host = "ESP8266"; |
|
|
|
ESP8266WebServer server = ESP8266WebServer(80); |
|
SoftwareSerial cameraconnection = SoftwareSerial(4, 5); |
|
Adafruit_VC0706 cam = Adafruit_VC0706(&cameraconnection); |
|
|
|
static bool hasSD = false; |
|
File imgFile; |
|
|
|
void returnOK() { |
|
server.send(200, "text/plain", ""); |
|
} |
|
|
|
void returnFail(String msg) { |
|
server.send(500, "text/plain", msg + "\r\n"); |
|
} |
|
|
|
bool loadFromSdCard(String path) { |
|
String dataType = "text/plain"; |
|
if (path.endsWith("/")) path += "index.htm"; |
|
|
|
if (path.endsWith(".src")) path = path.substring(0, path.lastIndexOf(".")); |
|
else if (path.endsWith(".htm")) dataType = "text/html"; |
|
else if (path.endsWith(".css")) dataType = "text/css"; |
|
else if (path.endsWith(".js")) dataType = "application/javascript"; |
|
else if (path.endsWith(".png")) dataType = "image/png"; |
|
else if (path.endsWith(".gif")) dataType = "image/gif"; |
|
else if (path.endsWith(".jpg")) dataType = "image/jpeg"; |
|
else if (path.endsWith(".ico")) dataType = "image/x-icon"; |
|
else if (path.endsWith(".xml")) dataType = "text/xml"; |
|
else if (path.endsWith(".pdf")) dataType = "application/pdf"; |
|
else if (path.endsWith(".zip")) dataType = "application/zip"; |
|
|
|
File dataFile = SD.open(path.c_str()); |
|
if (dataFile.isDirectory()) { |
|
path += "/index.htm"; |
|
dataType = "text/html"; |
|
dataFile = SD.open(path.c_str()); |
|
} |
|
|
|
if (!dataFile) |
|
return false; |
|
|
|
if (server.hasArg("download")) dataType = "application/octet-stream"; |
|
|
|
if (server.streamFile(dataFile, dataType) != dataFile.size()) { |
|
DBG_PORT.println("Sent less data than expected!"); |
|
} |
|
|
|
dataFile.close(); |
|
return true; |
|
} |
|
|
|
void handleFileUpload() { |
|
if (server.uri() != "/edit") return; |
|
HTTPUpload& upload = server.upload(); |
|
if (upload.status == UPLOAD_FILE_START) { |
|
if (SD.exists((char *)upload.filename.c_str())) SD.remove((char *)upload.filename.c_str()); |
|
imgFile = SD.open(upload.filename.c_str(), FILE_WRITE); |
|
DBG_PORT.print("Upload: START, filename: "); DBG_PORT.println(upload.filename); |
|
} |
|
else if (upload.status == UPLOAD_FILE_WRITE) { |
|
if (imgFile) imgFile.write(upload.buf, upload.currentSize); |
|
DBG_PORT.print("Upload: WRITE, Bytes: "); DBG_PORT.println(upload.currentSize); |
|
} |
|
else if (upload.status == UPLOAD_FILE_END) { |
|
if (imgFile) imgFile.close(); |
|
DBG_PORT.print("Upload: END, Size: "); DBG_PORT.println(upload.totalSize); |
|
} |
|
} |
|
|
|
void deleteRecursive(String path) { |
|
File file = SD.open((char *)path.c_str()); |
|
if (!file.isDirectory()) { |
|
file.close(); |
|
SD.remove((char *)path.c_str()); |
|
return; |
|
} |
|
|
|
file.rewindDirectory(); |
|
while (true) { |
|
File entry = file.openNextFile(); |
|
if (!entry) break; |
|
String entryPath = path + "/" + entry.name(); |
|
if (entry.isDirectory()) { |
|
entry.close(); |
|
deleteRecursive(entryPath); |
|
} |
|
else { |
|
entry.close(); |
|
SD.remove((char *)entryPath.c_str()); |
|
} |
|
yield(); |
|
} |
|
|
|
SD.rmdir((char *)path.c_str()); |
|
file.close(); |
|
} |
|
|
|
void handleDelete() { |
|
if (server.args() == 0) return returnFail("BAD ARGS"); |
|
String path = server.arg(0); |
|
if (path == "/" || !SD.exists((char *)path.c_str())) { |
|
returnFail("BAD PATH"); |
|
return; |
|
} |
|
deleteRecursive(path); |
|
returnOK(); |
|
} |
|
|
|
void handleCreate() { |
|
if (server.args() == 0) return returnFail("BAD ARGS"); |
|
String path = server.arg(0); |
|
if (path == "/" || SD.exists((char *)path.c_str())) { |
|
returnFail("BAD PATH"); |
|
return; |
|
} |
|
|
|
if (path.indexOf('.') > 0) { |
|
File file = SD.open((char *)path.c_str(), FILE_WRITE); |
|
if (file) { |
|
file.write((const char *)0); |
|
file.close(); |
|
} |
|
} |
|
else { |
|
SD.mkdir((char *)path.c_str()); |
|
} |
|
returnOK(); |
|
} |
|
|
|
void printDirectory() { |
|
if (!server.hasArg("dir")) return returnFail("BAD ARGS"); |
|
String path = server.arg("dir"); |
|
if (path != "/" && !SD.exists((char *)path.c_str())) return returnFail("BAD PATH"); |
|
File dir = SD.open((char *)path.c_str()); |
|
path = String(); |
|
if (!dir.isDirectory()) { |
|
dir.close(); |
|
return returnFail("NOT DIR"); |
|
} |
|
dir.rewindDirectory(); |
|
server.setContentLength(CONTENT_LENGTH_UNKNOWN); |
|
server.send(200, "text/json", ""); |
|
WiFiClient client = server.client(); |
|
|
|
server.sendContent("["); |
|
for (int cnt = 0; true; ++cnt) { |
|
File entry = dir.openNextFile(); |
|
if (!entry) |
|
break; |
|
|
|
String output; |
|
if (cnt > 0) |
|
output = ","; |
|
|
|
output += "{\"type\":\""; |
|
output += (entry.isDirectory()) ? "dir" : "file"; |
|
output += "\",\"name\":\""; |
|
output += entry.name(); |
|
output += "\""; |
|
output += "}"; |
|
server.sendContent(output); |
|
entry.close(); |
|
} |
|
server.sendContent("]"); |
|
dir.close(); |
|
} |
|
|
|
void handleNotFound() { |
|
if (hasSD && loadFromSdCard(server.uri())) return; |
|
String message = "SDCARD Not Detected\n\n"; |
|
message += "URI: "; |
|
message += server.uri(); |
|
message += "\nMethod: "; |
|
message += (server.method() == HTTP_GET) ? "GET" : "POST"; |
|
message += "\nArguments: "; |
|
message += server.args(); |
|
message += "\n"; |
|
for (uint8_t i = 0; i<server.args(); i++) { |
|
message += " NAME:" + server.argName(i) + "\n VALUE:" + server.arg(i) + "\n"; |
|
} |
|
server.send(404, "text/plain", message); |
|
DBG_PORT.print(message); |
|
} |
|
|
|
|
|
void setup() { |
|
DBG_PORT.begin(115200); |
|
DBG_PORT.println("VC0706 Camera test"); |
|
|
|
pinMode(SS, OUTPUT); |
|
if (!SD.begin(SS)) { |
|
DBG_PORT.println("Card failed, or not present"); |
|
return; |
|
} |
|
else { |
|
hasSD = true; |
|
} |
|
|
|
WiFi.begin(ssid, password); |
|
DBG_PORT.print("Connecting to "); |
|
DBG_PORT.println(ssid); |
|
uint8_t i = 0; |
|
while (WiFi.status() != WL_CONNECTED && i++ < 20) { |
|
delay(500); |
|
} |
|
if (i == 21) { |
|
DBG_PORT.print("Could not connect to"); |
|
DBG_PORT.println(ssid); |
|
while (1) delay(500); |
|
} |
|
DBG_PORT.print("Connected! IP address: "); |
|
DBG_PORT.println(WiFi.localIP()); |
|
|
|
if (MDNS.begin(host)) { |
|
MDNS.addService("http", "tcp", 80); |
|
DBG_PORT.println("MDNS responder started"); |
|
DBG_PORT.print("You can now connect to http://"); |
|
DBG_PORT.print(host); |
|
DBG_PORT.println(".local"); |
|
} |
|
|
|
server.on("/list", HTTP_GET, printDirectory); |
|
server.on("/edit", HTTP_DELETE, handleDelete); |
|
server.on("/edit", HTTP_PUT, handleCreate); |
|
server.on("/edit", HTTP_POST, []() { returnOK(); }, handleFileUpload); |
|
server.onNotFound(handleNotFound); |
|
|
|
server.begin(); |
|
DBG_PORT.println("HTTP server started"); |
|
|
|
if (cam.begin()) { |
|
DBG_PORT.println("Camera Found:"); |
|
} |
|
else { |
|
DBG_PORT.println("No camera found?"); |
|
return; |
|
} |
|
|
|
char *reply = cam.getVersion(); |
|
if (reply == 0) { |
|
Serial.print("Failed to get version"); |
|
} |
|
else { |
|
Serial.println("-----------------"); |
|
Serial.print(reply); |
|
Serial.println("-----------------"); |
|
} |
|
|
|
//cam.setImageSize(VC0706_640x480); // biggest |
|
cam.setImageSize(VC0706_320x240); // medium |
|
//cam.setImageSize(VC0706_160x120); // small |
|
|
|
uint8_t imgsize = cam.getImageSize(); |
|
Serial.print("Image size: "); |
|
if (imgsize == VC0706_640x480) Serial.println("640x480"); |
|
if (imgsize == VC0706_320x240) Serial.println("320x240"); |
|
if (imgsize == VC0706_160x120) Serial.println("160x120"); |
|
|
|
cam.setMotionDetect(true); |
|
|
|
Serial.print("Motion detection is "); |
|
if (cam.getMotionDetect()) |
|
Serial.println("ON"); |
|
else |
|
Serial.println("OFF"); |
|
} |
|
|
|
void loop() { |
|
server.handleClient(); |
|
|
|
if (cam.motionDetected()) { |
|
Serial.println("Motion!"); |
|
cam.setMotionDetect(false); |
|
|
|
if (!cam.takePicture()) |
|
Serial.println("Failed to snap!"); |
|
else |
|
Serial.println("Picture taken!"); |
|
|
|
char filename[13]; |
|
strcpy(filename, "IMAGE00.JPG"); |
|
|
|
SD.remove(filename); |
|
File imgFile = SD.open(filename, FILE_WRITE); |
|
|
|
uint16_t jpglen = cam.frameLength(); |
|
Serial.print(jpglen, DEC); |
|
Serial.println(" byte image"); |
|
|
|
Serial.print("Writing image to "); Serial.print(filename); |
|
|
|
while (jpglen > 0) { |
|
uint8_t *buffer; |
|
uint8_t bytesToRead; |
|
if (jpglen < 32) |
|
bytesToRead = jpglen; |
|
else |
|
bytesToRead = 32; |
|
buffer = cam.readPicture(bytesToRead); |
|
imgFile.write(buffer, bytesToRead); |
|
|
|
jpglen -= bytesToRead; |
|
} |
|
imgFile.close(); |
|
Serial.println("...Done!"); |
|
cam.resumeVideo(); |
|
cam.setMotionDetect(true); |
|
} |
|
} |