2015年11月21日 星期六

Step By Step系列---開始玩ESP8266-12 with Arduino IDE(第3篇-連線到自己家裡的AP)

ESP8266只是一個wifi mdoule, 了不起可以當成Arduino來用, 大家也都知道, 只要在程式裡寫入你家裡的SSID和PASSWORD再用WiFi.begin(your ssid, your password), 沒有意外, 就能連上自己家裡的AP, 但是每換一個地方(換AP), 你都得打開程式重新再programming一次, 那不是很麻煩嗎?ESP8266神奇的地方是它可以當AP, AP+STA, STA, 聰明的你一定想到, 那我只要先讓ESP8266變成AP, 再用手機或PC連上它, 再輸入你想更換的SSID和PASSWORD, 下次開機再切回STA mode不就解決了....

沒錯....就是這樣




連上192.168.4.1會有如下的連線設定畫面(網頁的內容要自己寫在ESP8266裡, 另外要用手機或NB連上ESP8266再看得到)

連上後它會先掃描周遭的無線網路並列出來, 找到你想輸入的SSID和PASSWORD, 若找不到, 可再按一次重新掃瞄無線網路, 應該就能找到, 輸入後按儲存

重新RESET ESP8266應該就能連上自己家裡的AP

原始程式碼如下(畫面和上面會稍有不同)
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <EEPROM.h>

ESP8266WebServer server(80);

const char* ssid = "test";
const char* passphrase = "test";
String st;
String content;
int statusCode;

void setup() {
  Serial.begin(115200);
  EEPROM.begin(512);
  delay(10);
  Serial.println();
  Serial.println();
  Serial.println("Startup");
  // read eeprom for ssid and pass
  Serial.println("Reading EEPROM ssid");
  String esid;
  for (int i = 0; i < 32; ++i)
    {
      esid += char(EEPROM.read(i));
    }
  Serial.print("SSID: ");
  Serial.println(esid);
  Serial.println("Reading EEPROM pass");
  String epass = "";
  for (int i = 32; i < 96; ++i)
    {
      epass += char(EEPROM.read(i));
    }
  Serial.print("PASS: ");
  Serial.println(epass);
  if ( esid.length() > 1 ) {
      WiFi.begin(esid.c_str(), epass.c_str());
      if (testWifi()) {
        launchWeb(0);
        return;
      }
  }
  setupAP();
}

bool testWifi(void) {
  int c = 0;
  Serial.println("Waiting for Wifi to connect");
  while ( c < 20 ) {
    if (WiFi.status() == WL_CONNECTED) { return true; }
    delay(500);
    Serial.print(WiFi.status());  
    c++;
  }
  Serial.println("");
  Serial.println("Connect timed out, opening AP");
  return false;
}

void launchWeb(int webtype) {
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("Local IP: ");
  Serial.println(WiFi.localIP());
  Serial.print("SoftAP IP: ");
  Serial.println(WiFi.softAPIP());
  createWebServer(webtype);
  // Start the server
  server.begin();
  Serial.println("Server started");
}

void setupAP(void) {
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);
  int n = WiFi.scanNetworks();
  Serial.println("scan done");
  if (n == 0)
    Serial.println("no networks found");
  else
  {
    Serial.print(n);
    Serial.println(" networks found");
    for (int i = 0; i < n; ++i)
     {
      // Print SSID and RSSI for each network found
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));
      Serial.print(" (");
      Serial.print(WiFi.RSSI(i));
      Serial.print(")");
      Serial.println((WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":"*");
      delay(10);
     }
  }
  Serial.println("");
  st = "<ol>";
  for (int i = 0; i < n; ++i)
    {
      // Print SSID and RSSI for each network found
      st += "<li>";
      st += WiFi.SSID(i);
      st += " (";
      st += WiFi.RSSI(i);
      st += ")";
      st += (WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":"*";
      st += "</li>";
    }
  st += "</ol>";
  delay(100);
  WiFi.softAP(ssid, passphrase, 6);
  Serial.println("softap");
  launchWeb(1);
  Serial.println("over");
}

void createWebServer(int webtype)
{
  if ( webtype == 1 ) {
    server.on("/", []() {
        IPAddress ip = WiFi.softAPIP();
        String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]);
        content = "<!DOCTYPE HTML>\r\n<html>Hello from ESP8266 at ";
        content += ipStr;
        content += "<p>";
        content += st;
        content += "</p><form method='get' action='setting'><label>SSID: </label><input name='ssid' length=32><input name='pass' length=64><input type='submit'></form>";
        content += "</html>";
        server.send(200, "text/html", content);
    });
    server.on("/setting", []() {
        String qsid = server.arg("ssid");
        String qpass = server.arg("pass");
        if (qsid.length() > 0 && qpass.length() > 0) {
          Serial.println("clearing eeprom");
          for (int i = 0; i < 96; ++i) { EEPROM.write(i, 0); }
          Serial.println(qsid);
          Serial.println("");
          Serial.println(qpass);
          Serial.println("");
         
          Serial.println("writing eeprom ssid:");
          for (int i = 0; i < qsid.length(); ++i)
            {
              EEPROM.write(i, qsid[i]);
              Serial.print("Wrote: ");
              Serial.println(qsid[i]);
            }
          Serial.println("writing eeprom pass:");
          for (int i = 0; i < qpass.length(); ++i)
            {
              EEPROM.write(32+i, qpass[i]);
              Serial.print("Wrote: ");
              Serial.println(qpass[i]);
            }  
          EEPROM.commit();
          content = "{\"Success\":\"saved to eeprom... reset to boot into new wifi\"}";
          statusCode = 200;
        } else {
          content = "{\"Error\":\"404 not found\"}";
          statusCode = 404;
          Serial.println("Sending 404");
        }
        server.send(statusCode, "application/json", content);
    });
  } else if (webtype == 0) {
    server.on("/", []() {
      IPAddress ip = WiFi.localIP();
      String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]);
      server.send(200, "application/json", "{\"IP\":\"" + ipStr + "\"}");
    });
    server.on("/cleareeprom", []() {
      content = "<!DOCTYPE HTML>\r\n<html>";
      content += "<p>Clearing the EEPROM</p></html>";
      server.send(200, "text/html", content);
      Serial.println("clearing eeprom");
      for (int i = 0; i < 96; ++i) { EEPROM.write(i, 0); }
      EEPROM.commit();
    });
  }
}

void loop() {
  server.handleClient();
  }

11 則留言:

  1. 請問能提供程式碼教學嗎? 最近也在玩這塊板子,這功能很方便,想學學看

    回覆刪除
  2. 下午post文章時還找不到當初參考的源碼, 剛才終於找到了, 原始程式碼可能和我上面的畫面不同, 我增加了重新掃瞄無線網路的code, 因為有時會找不到自己想登入的無線網路, 找不到時還要重新開機覺得麻煩, 就稍微改了一下, 我想原始程式碼貼在文章裡, 大家可能比較好找

    回覆刪除
    回覆
    1. 請問可以傳授一下重新掃瞄無線網路的code嗎?

      另外這原始碼我也搞了好久,好不容易才弄出來

      刪除
    2. 我給點方向, 你再試看看, 大致上就是按了重新掃瞄無線網路, 跳到另一個rescannetwork的網頁後, 在最後執行esp8266的WiFi.scanNetworks(); 把結果update回192.168.4.1, 其實這程式碼只是把原來的code裡的scannetwork功能抓出來再用一次而已, 就是類似迴圈的概念

      刪除
    3. 那請問掃描按鈕該如何建立?

      刪除
    4. 給你魚吃, 倒不如教你如何釣魚, 所以請google html 按鈕, 你會看到一大堆範例, 再試著改在自己的code裡, 這裡已經是前端web的領域, 一開始我也不懂, 去網路上買一本書加google大神的幫忙, 下次你就會知道該怎麼做, 我會很開心看你一步一步成長, 我自己一開始也不懂, 自己找資料, 找答案...加油

      刪除
  3. 這個程式碼能跑嗎?高度懷疑

    回覆刪除
    回覆
    1. 剛試過了...可以跑...沒有問題啊...

      刪除
  4. 能提供你自己的程式碼嗎?

    回覆刪除
    回覆
    1. 我也是照著人家寫好的去改的...沒有什麼不同

      刪除
  5. 請問老師,上面的程式都能執行,但是我只要把電腦關掉,uart也不接 eSP8266, 讓 esp8266單獨執行,就會找不到 esp8266 AP mode 自己的基地台, 這是為甚麼?, 我看很多範例,不是都可以用 ESP8266 來控制家用電器嗎?, 如果 ESP8266不能單獨執行,還要用 UART 接著電腦才能用,請問我是哪裡弄錯了??????

    蟹蟹指導

    回覆刪除

歡迎大家來討論交流一下~~~