/* Generic GPIO Control by HTTP REST interface */ /* Modify GPIO by accessing DEVICE_IP/gpio?gpio=[GPIO]&value=[0|1] */ /* At first boot it creates a WiFi access point */ /* and provide a web server on it, so you can configure Wifi ssid */ /* Wifi passwd, and a mDNS hostname */ /* In this mode, device will be available at 192.168.4.1 */ /* Device can also be put in OTA Mode: In this case, if you have */ /* a little flash (512K), it better to disable SPIFFS in */ /* "Flash Size" Menu. Use espota.py to upload OTA */ /* After passing in OTA mode, next boot will be in setup mode */ /* To Use GPIO 3 And 1, uncomment #define ENABLE_EXTRA_GPIO */ /* but Serial will be available on GPIO 15 and 13 */ #include #include #include #include #include #include #include //#define ENABLE_EXTRA_GPIO #define EEPROM_SIZE 512 char eeprom[EEPROM_SIZE]; #define BOOTMODE_SETUP 0 #define BOOTMODE_NORMAL 1 #define BOOTMODE_OTA 2 int mode; /* EEPROM LAYOUT "BOOTMODE;SSID;PASSWORD;HOSTNAME;" BOOTMODE could be 0 for Setup, 1 for normal use, 2 for OTA Setup mode is trigger by setting GPIO3 to ground or at first boot */ /* Set these to your desired credentials. */ const char *ssid = "ESPConfigurator"; ESP8266WebServer server(80); /* Just a little test message. Go to http://192.168.4.1 in a web browser connected to this access point to see it. */ void handleRoot() { server.send(200, "text/html", "

You are connected


" "Setup
" "OTA mode
" "ON
" "OFF
" ); } void handleSetup() { server.send(200, "text/html", "
" "
" "
" "
" "
" "
"); } void handleGpio() { if (!server.hasArg("gpio") || !server.hasArg("value")) { server.send(500, "text/plain", "Bad arguments\r\n"); return; } pinMode(server.arg("gpio").toInt(), OUTPUT); digitalWrite(server.arg("gpio").toInt(), server.arg("value").toInt()); server.send(200, "text/html", "

GPIO" + server.arg("gpio") + " changed to " + server.arg("value") + "

"); } int saveConfig(int bootMode, String ssid, String password, String host ) { String eeprom; eeprom = String(bootMode) + ";" + ssid + ";" + password + ";" + host + ";"; if (eeprom.length() > EEPROM_SIZE ) return -EMSGSIZE; Serial.println("Saving " + eeprom); for (int i = 0; i < eeprom.length() && i < EEPROM_SIZE; i++) { EEPROM.write(i, eeprom.charAt(i)); } EEPROM.commit(); delay(100); return 0; } int saveBootMode(int bootMode){ EEPROM.write(0,String(bootMode).charAt(0)); EEPROM.commit(); delay(100); return 0; } void handleSave() { String password; String ssid; String hostName; if (!server.hasArg("ssid") || !server.hasArg("password") || !server.hasArg("host")) { server.send(500, "text/plain", "Bad arguments\r\n"); return; } if (saveConfig(BOOTMODE_NORMAL, server.arg("ssid"), server.arg("password"), server.arg("host")) < 0) { server.send(500, "text/plain", "Cannot Save Credentials (Too long ?Contains \";\"?)\r\n"); return; } server.send(200, "text/html", "

Configuration Saved


" "You can reboot now"); } void handleOTA() { Serial.println("Boot mode Set to OTA"); saveBootMode(BOOTMODE_OTA); server.send(200, "text/html", "

OTA Mode set


" "You can reboot now"); } void handleNotFound() { String message = "File Not Found\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 += " " + server.argName(i) + ": " + server.arg(i) + "\n"; } server.send(404, "text/plain", message); } void readEEPROM(int &bootMode, char **ssid, char **password, char **host) { int i = 2; int boot = EEPROM.read(0); if (boot == '1') { bootMode = BOOTMODE_NORMAL; } else if (boot == '2') { bootMode = BOOTMODE_OTA; } else { //Do not need to parse EEPROM when not configured bootMode = BOOTMODE_SETUP; return; } //Read SSID *ssid = &eeprom[2]; do { eeprom[i] = EEPROM.read(i); i++; } while (i < EEPROM_SIZE && eeprom[i - 1] != ';'); eeprom[i - 1] = '\0'; //Read password *password = &eeprom[i]; do { eeprom[i] = EEPROM.read(i); i++; } while (i < EEPROM_SIZE && eeprom[i - 1] != ';'); eeprom[i - 1] = '\0'; //Read HostName *host = &eeprom[i]; do { eeprom[i] = EEPROM.read(i); i++; } while (i < EEPROM_SIZE && eeprom[i - 1] != ';'); eeprom[i - 1] = '\0'; } void setupWifi(int bootmode, int forceSetup, char *confSsid, char *confPassword, char *confHost) { IPAddress myIP; if (bootmode == BOOTMODE_SETUP || forceSetup) { Serial.println("Configuring access point..."); /* You can set a password to the AP here */ WiFi.softAP(ssid); myIP = WiFi.softAPIP(); } else { Serial.println("Connecting to Wifi..."); WiFi.begin(confSsid, confPassword); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); if (!MDNS.begin(confHost)) { Serial.println("Error setting up MDNS responder!"); while (1) { delay(1000); } } Serial.println("mDNS responder started"); myIP = WiFi.localIP(); } Serial.print("My IP address: "); Serial.println(myIP); } void setupOTA() { // Port defaults to 8266 // ArduinoOTA.setPort(8266); // Hostname defaults to esp8266-[ChipID] // ArduinoOTA.setHostname("myesp8266"); // No authentication by default // ArduinoOTA.setPassword((const char *)"123"); //Disable OTA mode to avoid forever loop //Force BOOTMODE_SETUP in case eeprom layout have changed saveConfig(BOOTMODE_SETUP, "", "", "" ); ArduinoOTA.onStart([]() { Serial.println("Start"); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); else if (error == OTA_END_ERROR) Serial.println("End Failed"); }); ArduinoOTA.begin(); Serial.println("Ready"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); Serial.print("Free Space: "); Serial.println(ESP.getFreeSketchSpace()); } void setupWebServer() { server.on("/", handleRoot); server.on("/setup", handleSetup); server.on("/save", handleSave); if (mode == BOOTMODE_NORMAL){ server.on("/gpio", handleGpio); server.on("/otamode", handleOTA); } server.onNotFound(handleNotFound); server.begin(); Serial.println("HTTP server started"); } void setup() { pinMode(3, OUTPUT); char *confSsid; char *confPassword; char *confHost; delay(1000); Serial.begin(115200); Serial.println(); // Get GPIO 3 Status Serial.swap(); //Switch Serial on GPIO 13 & 15 pinMode(3, INPUT_PULLUP); int txStatus = digitalRead(3); #ifndef ENABLE_EXTRA_GPIO Serial.swap(); // Switch back on GPIO 1 & 3 #endif EEPROM.begin(EEPROM_SIZE); readEEPROM(mode, &confSsid, &confPassword, &confHost); if (mode == BOOTMODE_NORMAL || mode == BOOTMODE_OTA) { Serial.println("Configuration Found !:"); Serial.println(mode); Serial.println(confSsid); Serial.println(confPassword); Serial.println(confHost); Serial.println(); } else { Serial.println("No configuration saved"); } Serial.print("Force Setup Mode ? :"); Serial.print(txStatus?"No":"Yes"); Serial.println(); setupWifi(mode, txStatus == 0, confSsid, confPassword, confHost); if (mode == BOOTMODE_OTA) { setupOTA(); } else { setupWebServer(); } } void loop() { if (mode == BOOTMODE_OTA) { ArduinoOTA.handle(); } else { server.handleClient(); } }