/* https://github.com/0x1d/esp8266-laser 0x1d, FrYakaTKoP */ #include #include #include #include #include #include #include /* some hard coded config, change if needed */ // Set how long the esp should try to connect to a network before starting it's own AP unsigned int wifiTimeout = 15000; //ms // Hardcoded Soft AP network parameters char *ssidAP = "laserAp"; IPAddress apIP(192, 168, 4, 1); IPAddress netMsk(255, 255, 255, 0); // this is sent to server if invalid request const char *metaRefreshStr = "

redirecting...

"; /* hostname for mDNS. Should work at least on windows. Try http://esplaser.local */ const char *myHostname = "esplaser"; // espsoftwareserial // SoftwareSerial(int receivePin, int transmitPin, bool inverse_logic = false, unsigned int buffSize = 64); SoftwareSerial laserSerial(14, 12, false, 256); // Presets json buffer const unsigned int maxPresets = 128; // 128 = 19496, 200 = 29864 // Preset cycleTime unsigned int cycleTime = 5000; // ms /* End of hard coded config */ const unsigned int presetsBufferSize = maxPresets * JSON_ARRAY_SIZE(4) + JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(maxPresets) + 1000; byte presets[maxPresets][4] = {1, 1, 1, 128}; unsigned int activePreset = 0; unsigned int presetMode = 0; String ssid = ""; String password = ""; int apMode = 1; // default value, will be overwriten with config from file int _apMode = 0; // runtime apMode // [0] laser, [1] m1, [2] m2, [3] m3 byte lmValues[4] = {0, 0, 0, 0}; unsigned long previousMillis = 0; // Web server ESP8266WebServer server(80); bool hFileRead(String path) { //Serial.println("handleFileRead: " + path); if (path.endsWith("/")) path += "index.html"; String contentType = getContentType(path); String pathWithGz = path + ".gz"; if (SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) { if (SPIFFS.exists(pathWithGz)) path += ".gz"; File file = SPIFFS.open(path, "r"); size_t sent = server.streamFile(file, contentType); file.close(); return true; } return false; } String getContentType(String filename) { if (server.hasArg("download")) return "application/octet-stream"; else if (filename.endsWith(".htm")) return "text/html"; else if (filename.endsWith(".html")) return "text/html"; else if (filename.endsWith(".ini")) return "text/plain"; else if (filename.endsWith(".css")) return "text/css"; else if (filename.endsWith(".js")) return "application/javascript"; else if (filename.endsWith(".png")) return "image/png"; else if (filename.endsWith(".gif")) return "image/gif"; else if (filename.endsWith(".jpg")) return "image/jpeg"; else if (filename.endsWith(".ico")) return "image/x-icon"; else if (filename.endsWith(".xml")) return "text/xml"; else if (filename.endsWith(".pdf")) return "application/x-pdf"; else if (filename.endsWith(".zip")) return "application/x-zip"; else if (filename.endsWith(".gz")) return "application/x-gzip"; return "text/plain"; } void hFileList() { String responseBuffer = String(); StaticJsonBuffer<500> jsonBuffer; JsonObject& root = jsonBuffer.createObject(); JsonArray& files = root.createNestedArray("files"); Dir dir = SPIFFS.openDir("/"); while (dir.next()) { File entry = dir.openFile("r"); files.add(String(entry.name())); entry.close(); } root.prettyPrintTo(responseBuffer); server.send(200, "text/json", responseBuffer); jsonBuffer.clear(); responseBuffer = String(); } bool hReadPresets() { // streamFile instead of rebuild json string String path = "/presets.json"; String contentType = getContentType(path); if (SPIFFS.exists(path)) { File file = SPIFFS.open(path, "r"); size_t sent = server.streamFile(file, contentType); file.close(); return true; } return false; } void hWritePreset() { presetMode = 0; int error = 0; int presetNr = 0; bool apply = false; StaticJsonBuffer<200> jsonBuffer; JsonObject& root = jsonBuffer.createObject(); JsonObject& data = root.createNestedObject("preset"); if (server.hasArg("nr") ) { presetNr = server.arg("nr").toInt(); data["nr"] = (String)presetNr; } else { error = 1; } if (server.hasArg("laser") && error == 0) { presets[presetNr-1][0] = server.arg("laser").toInt(); data["laser"] = (String)presets[presetNr-1][0]; } if (server.hasArg("motor1") && error == 0) { presets[presetNr-1][1] = server.arg("motor1").toInt(); data["motor1"] = (String)presets[presetNr-1][1]; } if (server.hasArg("motor2") && error == 0) { presets[presetNr-1][2] = server.arg("motor2").toInt(); data["motor2"] = (String) presets[presetNr-1][2]; } if (server.hasArg("motor3") && error == 0) { presets[presetNr-1][3] = server.arg("motor3").toInt(); data["motor3"] = (String) presets[presetNr-1][3]; } if (server.arg("apply") == "true" && error == 0) { apply = true; data["apply"] = "true"; presetToLaser(presetNr-1); } error = savePresetFile() ? 0 : 1; if(error != 0) { String responseBuffer = String(); root.prettyPrintTo(responseBuffer); server.send(200, "text/json", responseBuffer); responseBuffer = String(); } else { server.send(400, "text/plain", "400 Bad Request"); } jsonBuffer.clear(); } void hReadSpiro() { String responseBuffer = String(); StaticJsonBuffer<200> jsonBuffer; JsonObject& root = jsonBuffer.createObject(); JsonObject& data = root.createNestedObject("spirograph"); data["laser"] = (String)lmValues[0]; data["motor1"] = (String)lmValues[1]; data["motor2"] = (String)lmValues[2]; data["motor3"] = (String)lmValues[3]; root.prettyPrintTo(responseBuffer); server.send(200, "text/json", responseBuffer); jsonBuffer.clear(); responseBuffer = String(); } void hWriteSpiro() { presetMode = 0; String responseBuffer = String(); StaticJsonBuffer<200> jsonBuffer; JsonObject& root = jsonBuffer.createObject(); JsonObject& data = root.createNestedObject("spirograph"); if (server.hasArg("laser") ) { lmValues[0] = server.arg("laser").toInt(); data["laser"] = (String)lmValues[0]; String msg = "AT SLV "; msg += (String)lmValues[0]; laserSerial.println(msg); delay(20); } if (server.hasArg("motor1") ) { lmValues[1] = server.arg("motor1").toInt(); data["motor1"] = (String)lmValues[1]; String msg = "AT SMS 1 "; msg += (String)lmValues[1]; laserSerial.println(msg); delay(20); } if (server.hasArg("motor2") ) { lmValues[2] = server.arg("motor2").toInt(); data["motor2"] = (String)lmValues[2]; String msg = "AT SMS 2 "; msg += (String)lmValues[2]; laserSerial.println(msg); delay(20); } if (server.hasArg("motor3") ) { lmValues[3] = server.arg("motor3").toInt(); data["motor3"] = (String)lmValues[3]; String msg = "AT SMS 3 "; msg += (String)lmValues[3]; laserSerial.println(msg); delay(20); } root.prettyPrintTo(responseBuffer); server.send(200, "text/json", responseBuffer); jsonBuffer.clear(); responseBuffer = String(); } void hReadWifi() { // Serial.println("hReadWifi"); String responseBuffer = String(); StaticJsonBuffer<200> jsonBuffer; JsonObject& root = jsonBuffer.createObject(); JsonObject& data = root.createNestedObject("wificonfig"); data["apMode"] = apMode; data["SSID"] = ssid; data["Password"] = "***"; //password; //data["save"] = "false"; //data["apply"] = "false"; root.prettyPrintTo(responseBuffer); //root.prettyPrintTo(Serial); server.send(200, "text/json", responseBuffer); jsonBuffer.clear(); responseBuffer = String(); } void hWriteWifi() { // Serial.println("hWriteWifi"); String responseBuffer = String(); boolean save = false; boolean apply = false; StaticJsonBuffer<200> jsonBuffer; JsonObject& root = jsonBuffer.createObject(); JsonObject& data = root.createNestedObject("wificonfig"); if (server.hasArg("apMode") ) { apMode = server.arg("apMode").toInt(); data["apMode"] = apMode; } if (server.hasArg("SSID") ) { ssid = server.arg("SSID"); data["SSID"] = ssid; } if (server.hasArg("password") ) { password = server.arg("password"); data["Password"] = "***"; //password; } if (server.arg("save") == "true") { save = true; data["save"] = "true"; } if (server.arg("apply") == "true") { apply = true; data["apply"] = "true"; } root.prettyPrintTo(responseBuffer); //root.prettyPrintTo(Serial); server.send(200, "text/json", responseBuffer); if (save) { saveWifiConfig(); } if (apply) { setupWifi(); } jsonBuffer.clear(); responseBuffer = String(); } boolean readPresetsFile() { Serial.println("Reading presets.json"); File configFile = SPIFFS.open("/presets.json", "r"); if (!configFile) { Serial.println("Failed to open config file"); return false; } size_t size = configFile.size(); if (size > 10024) { Serial.println("Config file size is too large"); return false; } // Allocate a buffer to store contents of the file. std::unique_ptr buf(new char[size]); DynamicJsonBuffer presetsBuffer(presetsBufferSize); configFile.readBytes(buf.get(), size); JsonObject& root = presetsBuffer.parseObject(buf.get()); //root.prettyPrintTo(Serial); JsonObject& sets = root["presets"]; for (JsonObject::iterator it = sets.begin(); it != sets.end(); ++it) { const char* keyStr = it->key; unsigned int key = atoi(it->key); // it->value contains the JsonVariant which can be casted as usual const char* value = it->value; JsonArray& values = sets[keyStr]; for (int x = 0; x < 4; x++) { presets[key-1][x] = values[x]; } } if (!root.success()) { Serial.println("Failed to parse preset config file"); return false; } return true; } bool savePresetFile() { DynamicJsonBuffer presetsBuffer(presetsBufferSize); JsonObject& json = presetsBuffer.createObject(); JsonObject& sets = json.createNestedObject("presets"); for (int i = 0; i < maxPresets; i++) { JsonArray& set = sets.createNestedArray((String)i); for (int x = 0; x < 4; x++) { set.add(presets[i+1][x]); } } //json.prettyPrintTo(Serial); File configFile = SPIFFS.open("/presets.json", "w"); if (!configFile) { //Serial.println("Failed to open config file for writing"); return false; } json.printTo(configFile); return true; } boolean readWifiConfig() { Serial.println("Reading wifi.json"); File configFile = SPIFFS.open("/wifi.json", "r"); if (!configFile) { Serial.println("Failed to open config file"); return false; } size_t size = configFile.size(); if (size > 1024) { Serial.println("Config file size is too large"); return false; } // Allocate a buffer to store contents of the file. std::unique_ptr buf(new char[size]); configFile.readBytes(buf.get(), size); StaticJsonBuffer<200> jsonBuffer; JsonObject& json = jsonBuffer.parseObject(buf.get()); if (!json.success()) { Serial.println("Failed to parse config file"); return false; } apMode = json["apMode"]; apMode = apMode; const char* tSsid = json["SSID"]; const char* tPwd = json["Password"]; ssid = tSsid; password = tPwd; Serial.print("SSID: "); Serial.println(ssid); Serial.print("PW: "); Serial.println("***"); //Serial.println(password); return true; } bool saveWifiConfig() { StaticJsonBuffer<200> jsonBuffer; JsonObject& json = jsonBuffer.createObject(); json["apMode"] = apMode; json["SSID"] = ssid; json["Password"] = password; File configFile = SPIFFS.open("/wifi.json", "w"); if (!configFile) { //Serial.println("Failed to open config file for writing"); return false; } json.printTo(configFile); return true; } void presetToLaser(int nr) { String msg = "AT SLV "; msg += (String)presets[nr][0]; laserSerial.println(msg); delay(20); msg = "AT SMS 1 "; msg += (String)presets[nr][1]; laserSerial.println(msg); delay(20); msg = "AT SMS 2 "; msg += (String)presets[nr][2]; laserSerial.println(msg); delay(20); msg = "AT SMS 3 "; msg += (String)presets[nr][3]; laserSerial.println(msg); delay(20); Serial.print("writenPresetToLaser: "); Serial.println(nr); } void setupWifi() { WiFi.disconnect(); delay(100); if (!connectWifi()) { Serial.println("connect failed, start SoftAP"); _apMode = 1; // fallback to AP mode connectWifi(); } } boolean connectWifi() { Serial.print("connectWifi apMode="); Serial.println(apMode); if (_apMode == 0) { Serial.print("Connecting to "); Serial.println(ssid); WiFi.mode(WIFI_STA); WiFi.begin(ssid.c_str(), password.c_str()); previousMillis = millis(); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); if (millis() - previousMillis >= wifiTimeout) { Serial.println(""); Serial.println("connection timedout"); return false; } } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); return true; } else { Serial.printf("Starting SoftAP %s\n", ssidAP); WiFi.mode(WIFI_AP); WiFi.softAP(ssidAP); Serial.print("SoftAP started! IP address: "); Serial.println ( WiFi.softAPIP() ); return true; } } void setup(void) { laserSerial.begin(9600); laserSerial.flush(); Serial.begin(115200); Serial.print("\n"); SPIFFS.begin(); // { // Dir dir = SPIFFS.openDir("/"); // while (dir.next()) { // String fileName = dir.fileName(); // size_t fileSize = dir.fileSize(); // Serial.printf("FS File: %s\n", fileName.c_str()); // } // Serial.printf("\n"); // } if (!readWifiConfig()) { Serial.println("reading wifi config failed, start SoftAP"); _apMode = 1; } delay(100); setupWifi(); // loading presets readPresetsFile(); // Setup MDNS responder if (!MDNS.begin(myHostname)) { Serial.println("Error setting up MDNS responder!"); } else { Serial.println("mDNS responder started"); // Add service to MDNS-SD MDNS.addService("http", "tcp", 80); } //SERVER INIT //list directory server.on("/files", HTTP_GET, hFileList); server.on("/files", HTTP_POST, []() { server.send(400, "text/plain", "400 Bad Request"); }); server.on("/wificonfig", HTTP_GET, hReadWifi); server.on("/wificonfig", HTTP_POST, hWriteWifi); server.on("/spirograph", HTTP_GET, hReadSpiro); server.on("/spirograph", HTTP_POST, hWriteSpiro); server.on("/presets", HTTP_GET, hReadPresets); server.on("/presets", HTTP_POST, []() { server.send(400, "text/plain", "400 Bad Request"); }); server.on("/preset", HTTP_GET, []() { server.send(400, "text/plain", "400 Bad Request"); }); server.on("/preset", HTTP_POST, hWritePreset); server.on("/presetMode", HTTP_GET, []() { String json = "{"; json += "\"presetMode\":" + String(presetMode); json += "}"; server.send(200, "text/json", json); json = String(); }); server.on("/presetMode", HTTP_POST, []() { if (server.hasArg("presetMode") ) { presetMode = server.arg("presetMode").toInt(); } String json = "{"; json += "\"presetMode\":" + String(presetMode); json += "}"; server.send(200, "text/json", json); json = String(); }); server.on("/heap", HTTP_GET, []() { String json = "{"; json += "\"heap\":" + String(ESP.getFreeHeap()); json += "}"; server.send(200, "text/json", json); json = String(); }); server.on("/heap", HTTP_POST, []() { server.send(400, "text/plain", "400 Bad Request"); }); server.onNotFound(handleNotFound); server.begin(); Serial.println("HTTP server started"); } void handleNotFound() { String uri = server.uri(); //Serial.print("unhandled uri:"); //Serial.println(uri); if (uri.substring(0, 12) == "/wifi.json") { server.send(403, "text/plain", "Forbidden"); return; } if (!hFileRead(server.uri())) { server.send(404, "text/html", metaRefreshStr); // server.send(302, "text/plain", "blub"); } } void loop(void) { server.handleClient(); if (presetMode == 1) { if (millis() - previousMillis >= cycleTime) { presetToLaser(activePreset); if (activePreset < 128) { activePreset++; } else { activePreset = 0; } previousMillis = millis(); } } }