2018年5月17日 星期四

WiFiManager with ESP8266 – Autoconnect, Custom Parameter and Manage your SSID and Password

WiFiManager with ESP8266 – Autoconnect, Custom Parameter and Manage your SSID and Password

    26 Shares
    In this guide you’ll learn how to use WiFiManager with the ESP8266 board. WiFiManager allows you to connect your ESP8266 to different Access Points (AP) without having to hard-code and upload new code to your board. Additionally, you can also add custom parameters (variables) and manage multiple SSID connections with the WiFiManager library.

    How WiFiManager Works with ESP8266

    The WiFiManager is a great library do add to your ESP8266 projects, because using this library you no longer have to hard-code your network credentials (SSID and password). Your ESP will automatically join a known network or set up an Access Point that you can use to configure the network credentials. Here’s how this process works:
    • When your ESP8266 boots, it is set up in Station mode, and tries to connect to a previously saved Access Point (a known SSID and password combination);
    • If this process fails, it sets the ESP into Access Point mode;
    • Using any Wi-Fi enabled device with a browser, connect to the newly created Access Point (default name AutoConnectAP);
    • After establishing a connection with the AutoConnectAP, you can go to the default IP address 192.168.4.1 to open a web page that allows you to configure your SSID and password;
    • Once a new SSID and password is set, the ESP reboots and tries to connect;
    • If it establishes a connection, the process is completed successfully. Otherwise, it will be set up as an Access Point.
    This blog post illustrates two different use cases for the WiFiManager library:
    • Example #1 – Autoconnect: Web Server Example
    • Example #2 – Adding Custom Parameters

    Prerequisites

    Before proceeding with this tutorial we recommend reading the following resources:

    Installing WiFiManager and ArduinoJSON

    You also need to install the WiFiManager Library and ArduinoJSON Library. Follow these next instructions.
    Installing the WiFiManager Library
    1. Click here to download the WiFiManager library. You should have a .zip folder in your Downloads
    2. Unzip the .zip folder and you should get WiFiManager-master folder
    3. Rename your folder from WiFiManager-master to WiFiManager
    4. Move the WiFiManager folder to your Arduino IDE installation libraries folder
    5. Finally, re-open your Arduino IDE
    Installing the ArduinoJSON Library
    1. Click here to download the ArduinoJSON library. You should have a .zip folder in your Downloads
    2. Unzip the .zip folder and you should get ArduinoJSON-master folder
    3. Rename your folder from ArduinoJSON-master to ArduinoJSON
    4. Move the ArduinoJSON folder to your Arduino IDE installation libraries folder
    5. Finally, re-open your Arduino IDE

    Example #1 – WiFiManager with ESP8266: Autoconnect Example

    This first example is based on the ESP8266 Web Server post, where you build a web server with an ESP8266 to control two outputs (watch the video tutorial below).

    For Example #1 we’ll use the previous project, but instead of hard-coding the SSID and password, you’ll be able to configure it with the WiFiManager library.

    Code

    Having the ESP8266 add-on for the Arduino IDE installed (How to Install the ESP8266 Board in Arduino IDE), go to Tools and select “ESP-12E” (or choose the development board that you’re using). Here’s the code that you need to upload to your ESP8266:
    /*********
      Rui Santos
      Complete project details at http://randomnerdtutorials.com  
    *********/
    #include <ESP8266WiFi.h>
    #include <DNSServer.h>
    #include <ESP8266WebServer.h>
    #include <WiFiManager.h>         // https://github.com/tzapu/WiFiManager
    // Set web server port number to 80
    WiFiServer server(80);
    // Variable to store the HTTP request
    String header;
    // Auxiliar variables to store the current output state
    String output5State = "off";
    String output4State = "off";
    // Assign output variables to GPIO pins
    const int output5 = 5;
    const int output4 = 4;
    void setup() {
      Serial.begin(115200);
      
      // Initialize the output variables as outputs
      pinMode(output5, OUTPUT);
      pinMode(output4, OUTPUT);
      // Set outputs to LOW
      digitalWrite(output5, LOW);
      digitalWrite(output4, LOW);
    
      // WiFiManager
      // Local intialization. Once its business is done, there is no need to keep it around
      WiFiManager wifiManager;
      
      // Uncomment and run it once, if you want to erase all the stored information
      //wifiManager.resetSettings();
      
      // set custom ip for portal
      //wifiManager.setAPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
    
      // fetches ssid and pass from eeprom and tries to connect
      // if it does not connect it starts an access point with the specified name
      // here  "AutoConnectAP"
      // and goes into a blocking loop awaiting configuration
      wifiManager.autoConnect("AutoConnectAP");
      // or use this for auto generated name ESP + ChipID
      //wifiManager.autoConnect();
      
      // if you get here you have connected to the WiFi
      Serial.println("Connected.");
      
      server.begin();
    }
    void loop(){
      WiFiClient client = server.available();   // Listen for incoming clients
    
      if (client) {                             // If a new client connects,
        Serial.println("New Client.");          // print a message out in the serial port
        String currentLine = "";                // make a String to hold incoming data from the client
        while (client.connected()) {            // loop while the client's connected
          if (client.available()) {             // if there's bytes to read from the client,
            char c = client.read();             // read a byte, then
            Serial.write(c);                    // print it out the serial monitor
            header += c;
            if (c == '\n') {                    // if the byte is a newline character
              // if the current line is blank, you got two newline characters in a row.
              // that's the end of the client HTTP request, so send a response:
              if (currentLine.length() == 0) {
                // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
                // and a content-type so the client knows what's coming, then a blank line:
                client.println("HTTP/1.1 200 OK");
                client.println("Content-type:text/html");
                client.println("Connection: close");
                client.println();
                
                // turns the GPIOs on and off
                if (header.indexOf("GET /5/on") >= 0) {
                  Serial.println("GPIO 5 on");
                  output5State = "on";
                  digitalWrite(output5, HIGH);
                } else if (header.indexOf("GET /5/off") >= 0) {
                  Serial.println("GPIO 5 off");
                  output5State = "off";
                  digitalWrite(output5, LOW);
                } else if (header.indexOf("GET /4/on") >= 0) {
                  Serial.println("GPIO 4 on");
                  output4State = "on";
                  digitalWrite(output4, HIGH);
                } else if (header.indexOf("GET /4/off") >= 0) {
                  Serial.println("GPIO 4 off");
                  output4State = "off";
                  digitalWrite(output4, LOW);
                }
                
                // Display the HTML web page
                client.println("<!DOCTYPE html><html>");
                client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
                client.println("<link rel=\"icon\" href=\"data:,\">");
                // CSS to style the on/off buttons 
                // Feel free to change the background-color and font-size attributes to fit your preferences
                client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
                client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;");
                client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
                client.println(".button2 {background-color: #77878A;}</style></head>");
                
                // Web Page Heading
                client.println("<body><h1>ESP8266 Web Server</h1>");
                
                // Display current state, and ON/OFF buttons for GPIO 5  
                client.println("<p>GPIO 5 - State " + output5State + "</p>");
                // If the output5State is off, it displays the ON button       
                if (output5State=="off") {
                  client.println("<p><a href=\"/5/on\"><button class=\"button\">ON</button></a></p>");
                } else {
                  client.println("<p><a href=\"/5/off\"><button class=\"button button2\">OFF</button></a></p>");
                } 
                   
                // Display current state, and ON/OFF buttons for GPIO 4  
                client.println("<p>GPIO 4 - State " + output4State + "</p>");
                // If the output4State is off, it displays the ON button       
                if (output4State=="off") {
                  client.println("<p><a href=\"/4/on\"><button class=\"button\">ON</button></a></p>");
                } else {
                  client.println("<p><a href=\"/4/off\"><button class=\"button button2\">OFF</button></a></p>");
                }
                client.println("</body></html>");
                
                // The HTTP response ends with another blank line
                client.println();
                // Break out of the while loop
                break;
              } else { // if you got a newline, then clear currentLine
                currentLine = "";
              }
            } else if (c != '\r') {  // if you got anything else but a carriage return character,
              currentLine += c;      // add it to the end of the currentLine
            }
          }
        }
        // Clear the header variable
        header = "";
        // Close the connection
        client.stop();
        Serial.println("Client disconnected.");
        Serial.println("");
      }
    }
    This code needs to include the following libraries for the WiFiManager:
    #include <DNSServer.h>
    #include <ESP8266WebServer.h>
    #include <WiFiManager.h>
    You also need to create a WiFiManager object:
    WiFiManager wifiManager;
    And run the autoConnect() method:
    wifiManager.autoConnect("AutoConnectAP");
    That’s it! By adding these new lines of code to your ESP8266 projects, you’re able to configure Wi-Fi credentials using the WiFiManager.

    Accessing the WiFiManager AP

    If it’s your first time running the WiFiManager code with your ESP8266 board, you’ll see the next messages being printed in your Arduino IDE Serial Monitor.
    You can either use your computer/laptop to connect to the AutoConnectAP Access point:
    Then, open your browser and type the following IP address: 192.168.4.1. This loads the next web page, where you can set your Wi-Fi credentials:
    Alternatively, you can use your smartphone, activate Wi-Fi and connect to AutoConnectAP as follows:
    You should see a a window similar to the one shown in the figure below. Then, press the “SIGN IN” button:

    Configuring the WiFi page

    You’ll be redirected to a web page at 192.168.4.1 that allows you to configure your ESP’s WiFi credentials. Press the “Configure WiFi” button:
    Choose your desired network by tapping its name and the SSID should be filled instantly (in my case “MEO-620B4B”):
    After that, type your password and press “save“:
    You’ll see a similar message saying “Credentials Saved“:
    In the meanwhile, the Serial Monitor displays the scan results of the available Access Points and message stating that Wi-Fi credentials were saved.

    Accessing your web server

    Now, if you RESET your ESP board, it will print the IP address in the Serial Monitor (in my case it’s 192.168.1.132):
    Open your browser and type the IP address. You should see the web server shown below, that allows you to control two GPIOs on and off:

    Parts required and schematic

    If you want to make this project work, here’s the parts that you need:
    You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!
    Follow this schematic:

    How to Erase Credentials From Your ESP8266

    This next line is commented by default, otherwise you would need to configure your ESP8266 every time it boots up.
    // Uncomment and run it once, if you want to erase all the stored information
    //wifiManager.resetSettings();
    If for some reason you want to erase all the saved credentials:
    1. Uncomment the preceding line;
    2. Upload the code to the ESP8266;
    3. Let it run once (reset your board);
    4. Comment that line again;
    5. Upload the code to the ESP8266 with the line commented.

    Example #2 – WiFiManager with ESP8266 and Custom Parameters

    The WiFiManager has a useful feature that allows you to add custom parameters to the “Configure WiFi” web page. This is extremely useful, because in some applications you might want to add a different API Key, an MQTT broker IP Address, assign a different GPIO, activate a sensor, etc..
    In Example #2, you’ll make a web server to control an ESP8266 GPIO pin that is defined with a custom parameter set through the WiFiManager.

    Code

    Having the ESP8266 add-on for the Arduino IDE installed (How to Install the ESP8266 Board in Arduino IDE), go to Tools and select “ESP-12E” (or choose the development board that you’re using). Here’s the code that you need to upload to your ESP8266:
    /*********
      Rui Santos
      Complete project details at http://randomnerdtutorials.com  
    *********/
    #include <FS.h> //this needs to be first, or it all crashes and burns...
    #include <ESP8266WiFi.h>
    #include <DNSServer.h>
    #include <ESP8266WebServer.h>
    #include <WiFiManager.h>          // https://github.com/tzapu/WiFiManager
    #include <ArduinoJson.h>          // https://github.com/bblanchon/ArduinoJson
    // Set web server port number to 80
    WiFiServer server(80);
    // Variable to store the HTTP request
    String header;
    // Auxiliar variables to store the current output state
    String outputState = "off";
    // Assign output variables to GPIO pins
    char output[2] = "5";
    //flag for saving data
    bool shouldSaveConfig = false;
    //callback notifying us of the need to save config
    void saveConfigCallback () {
      Serial.println("Should save config");
      shouldSaveConfig = true;
    }
    void setup() {
      Serial.begin(115200);
      
      //clean FS, for testing
      //SPIFFS.format();
    
      //read configuration from FS json
      Serial.println("mounting FS...");
    
      if (SPIFFS.begin()) {
        Serial.println("mounted file system");
        if (SPIFFS.exists("/config.json")) {
          //file exists, reading and loading
          Serial.println("reading config file");
          File configFile = SPIFFS.open("/config.json", "r");
          if (configFile) {
            Serial.println("opened config file");
            size_t size = configFile.size();
            // Allocate a buffer to store contents of the file.
            std::unique_ptr<char[]> buf(new char[size]);
    
            configFile.readBytes(buf.get(), size);
            DynamicJsonBuffer jsonBuffer;
            JsonObject& json = jsonBuffer.parseObject(buf.get());
            json.printTo(Serial);
            if (json.success()) {
              Serial.println("\nparsed json");
              strcpy(output, json["output"]);
            } else {
              Serial.println("failed to load json config");
            }
          }
        }
      } else {
        Serial.println("failed to mount FS");
      }
      //end read
      
      WiFiManagerParameter custom_output("output", "output", output, 2);
    
      // WiFiManager
      // Local intialization. Once its business is done, there is no need to keep it around
      WiFiManager wifiManager;
    
      //set config save notify callback
      wifiManager.setSaveConfigCallback(saveConfigCallback);
      
      // set custom ip for portal
      //wifiManager.setAPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
    
      //add all your parameters here
      wifiManager.addParameter(&custom_output);
      
      // Uncomment and run it once, if you want to erase all the stored information
      //wifiManager.resetSettings();
    
      //set minimu quality of signal so it ignores AP's under that quality
      //defaults to 8%
      //wifiManager.setMinimumSignalQuality();
      
      //sets timeout until configuration portal gets turned off
      //useful to make it all retry or go to sleep
      //in seconds
      //wifiManager.setTimeout(120);
    
      // fetches ssid and pass from eeprom and tries to connect
      // if it does not connect it starts an access point with the specified name
      // here  "AutoConnectAP"
      // and goes into a blocking loop awaiting configuration
      wifiManager.autoConnect("AutoConnectAP");
      // or use this for auto generated name ESP + ChipID
      //wifiManager.autoConnect();
      
      // if you get here you have connected to the WiFi
      Serial.println("Connected.");
      
      strcpy(output, custom_output.getValue());
    
      //save the custom parameters to FS
      if (shouldSaveConfig) {
        Serial.println("saving config");
        DynamicJsonBuffer jsonBuffer;
        JsonObject& json = jsonBuffer.createObject();
        json["output"] = output;
    
        File configFile = SPIFFS.open("/config.json", "w");
        if (!configFile) {
          Serial.println("failed to open config file for writing");
        }
    
        json.printTo(Serial);
        json.printTo(configFile);
        configFile.close();
        //end save
      }
    
      // Initialize the output variables as outputs
      pinMode(atoi(output), OUTPUT);
      // Set outputs to LOW
      digitalWrite(atoi(output), LOW);;
      
      server.begin();
    }
    void loop(){
      WiFiClient client = server.available();   // Listen for incoming clients
    
      if (client) {                             // If a new client connects,
        Serial.println("New Client.");          // print a message out in the serial port
        String currentLine = "";                // make a String to hold incoming data from the client
        while (client.connected()) {            // loop while the client's connected
          if (client.available()) {             // if there's bytes to read from the client,
            char c = client.read();             // read a byte, then
            Serial.write(c);                    // print it out the serial monitor
            header += c;
            if (c == '\n') {                    // if the byte is a newline character
              // if the current line is blank, you got two newline characters in a row.
              // that's the end of the client HTTP request, so send a response:
              if (currentLine.length() == 0) {
                // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
                // and a content-type so the client knows what's coming, then a blank line:
                client.println("HTTP/1.1 200 OK");
                client.println("Content-type:text/html");
                client.println("Connection: close");
                client.println();
                
                // turns the GPIOs on and off
                if (header.indexOf("GET /output/on") >= 0) {
                  Serial.println("Output on");
                  outputState = "on";
                  digitalWrite(atoi(output), HIGH);
                } else if (header.indexOf("GET /output/off") >= 0) {
                  Serial.println("Output off");
                  outputState = "off";
                  digitalWrite(atoi(output), LOW);
                }
                
                // Display the HTML web page
                client.println("<!DOCTYPE html><html>");
                client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
                client.println("<link rel=\"icon\" href=\"data:,\">");
                // CSS to style the on/off buttons 
                // Feel free to change the background-color and font-size attributes to fit your preferences
                client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
                client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;");
                client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
                client.println(".button2 {background-color: #77878A;}</style></head>");
                
                // Web Page Heading
                client.println("<body><h1>ESP8266 Web Server</h1>");
                
                // Display current state, and ON/OFF buttons for the defined GPIO  
                client.println("<p>Output - State " + outputState + "</p>");
                // If the outputState is off, it displays the ON button       
                if (outputState=="off") {
                  client.println("<p><a href=\"/output/on\"><button class=\"button\">ON</button></a></p>");
                } else {
                  client.println("<p><a href=\"/output/off\"><button class=\"button button2\">OFF</button></a></p>");
                }                  
                client.println("</body></html>");
                
                // The HTTP response ends with another blank line
                client.println();
                // Break out of the while loop
                break;
              } else { // if you got a newline, then clear currentLine
                currentLine = "";
              }
            } else if (c != '\r') {  // if you got anything else but a carriage return character,
              currentLine += c;      // add it to the end of the currentLine
            }
          }
        }
        // Clear the header variable
        header = "";
        // Close the connection
        client.stop();
        Serial.println("Client disconnected.");
        Serial.println("");
      }
    }

    Adding custom parameters

    To add a custom parameter, you need to add a bunch of code (see the preceding sketch) that allows you to manipulate the /config.json file stored in the ESP. For this tutorial we won’t explain how the custom parameters feature works, but basically if you wanted to create another custom parameter follow these next steps.
    In this example, we’ll create a variable to store an MQTT broker server IP address. First, create a char variable:
    char output[2];
    char mqtt_server[40];
    Then, if it’s already saved in the /config.json, you can copy it:
    strcpy(output, json["output"]);
    strcpy(mqtt_server, json["mqtt_server"]);
    Create a WiFiManagerParameter (so, the parameter is displayed in the “Configure WiFi” web page:
    WiFiManagerParameter custom_output("output", "output", output, 2);
    WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40);
    Add the variable as a parameter:
    wifiManager.addParameter(&custom_output);
    wifiManager.addParameter(&custom_mqtt_server);
    Check and update the char variables with the latest value:
    strcpy(output, custom_output.getValue());
    strcpy(mqtt_server, custom_mqtt_server.getValue());
    Finally, if the user submits a new value to one of the parameters, this line updates the/config.json file:
    json["output"] = output;
    json["mqtt_server"] = mqtt_server;
    You could repeat this process to add more custom parameters.

    Accessing the WiFiManager AP

    Use your smartphone, computer or tablet and connect to the AutoConnectAP Access Point:
    You should see a a window similar to the one shown in the figure below. Then, press the “SIGN IN” button:

    Configuring the WiFi page

    You’ll be redirected to a web page at 192.168.4.1 that allows you to configure your ESP’s WiFi credentials. Press the “Configure WiFi” button:
    Choose your desired network by tapping its name and the SSID should be filled instantly (in my case “MEO-620B4B”):
    After that, type your password, your desired GPIO number (in my case it’s GPIO 5, so I’ve entered 5) and press “save“:
    In the meanwhile, the Serial Monitor displays:
    • Scan results of the available Access Points;
    • Message stating that Wi-Fi credentials were saved;
    • Confirmation that the output parameter (that refers to the GPIO) was set to 5: {“output”:”5″}.

    Accessing your web server

    Now, if you RESET your ESP board, it will print the IP address in the Serial Monitor (in my case it’s 192.168.1.132):
    Open your browser and type the IP address. You should see the web server shown below, that allows you to control the GPIO you’ve defined on and off:

    Parts required and schematic

    If you want to make this project work, here’s the parts that you need:
    You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!
    Note: if you’ve defined a GPIO number different than GPIO 5 (which is D1 with the NodeMCU board), you need to make a different circuit.

    Wrapping Up

    That’s it for now, I hope you found this project useful and you can use the WiFiManager library in your projects!
    If you like the ESP8266, you may also like:

    沒有留言:

    張貼留言