Esp8266 使用可配置式 WiFi

最近在使用 WeMos D1 mini 制作一個局域網(wǎng)開機(jī)模塊椭豫,需要將 WiFi 信息設(shè)置為可配置,網(wǎng)上搜索良久都未發(fā)現(xiàn)滿意的解決方案,最終在一個臺灣上人的博客上蛉幸,發(fā)現(xiàn)了一個相對比較友好的程序,博客原鏈接如下http://nhs-tw.blogspot.com/2015/11/step-by-step-esp8266-12-with-arduino_27.html丛晦,我將它整理了一下奕纫,并修改添加了部分注釋。


代碼

//聲明
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <EEPROM.h>
#include <ESP8266mDNS.h>

int EPPROM_Address = 512;

// WiFi烫沙,可以寫入在這里預(yù)先輸入自己最常用的 WiFi 信息匹层,也可以設(shè)置為空字符串
String WiFi_SSID = "";
String WiFi_Password = "";

//Ap 設(shè)置熱點(diǎn)信息
const char* AP_Host = "esp8266";
const char* AP_SSID = "Esp8266AP";
const char* AP_Password = "12345678";

// web
String webContent;
int webStatusCode;
String wifiScanContent;

ESP8266WebServer WebServer(80);

void DebugMessage(String str)
{
  Serial.println(str);
}

void setup() {
  Serial.begin(115200);
  DebugMessage("The program startup...");

  EEPROM.begin(EPPROM_Address);
  readWiFiInfoFromEEPROM();

  bool connectStatus = tryToConnectToWiFi();
  if (connectStatus)
  {
    DebugMessage("WiFi connected, IP address: " + WiFi.localIP());
    createConnectedWeb();
  }
  else
  {
    DebugMessage("Connect timed out, ESP8266 change to AP mode");
    ScanNetwork();
    SetupToAPMode();
    connectStatus = tryToConnectToWiFi();
  }

  WebServer.begin();
  delay(100);
}


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


/********* 從存儲器中讀取 WiFi 信息 ***************/
void readWiFiInfoFromEEPROM()
{
  //--- 從 EEPROM 中讀取 WiFi 的 SSID 和密碼
  DebugMessage("--- Reading EEPROM SSID & PASSWORD");

  //--- 讀取 wifi ssid
  WiFi_SSID = "";
  for (int i = 0; i < 32; ++i)
  {
    WiFi_SSID += char(EEPROM.read(i));
  }
  delay(100);

  //--- 讀取 wifi 密碼
  WiFi_Password = "";
  for (int i = 32; i < 96; ++i)
  {
    WiFi_Password += char(EEPROM.read(i));
  }
  delay(100);

  //--- 打印 EEPROM 中存儲的 WiFi 信息
  DebugMessage("SSID NAME : " + WiFi_SSID);
  DebugMessage("PASSWORD NAME : " + WiFi_Password);
  DebugMessage("essid.length = " + WiFi_SSID.length());
}

/********* 嘗試連接 WiFi ***************/
bool tryToConnectToWiFi()
{
  DebugMessage("--- try to connect to ssid: " + WiFi_SSID + " with password: " + WiFi_Password);

  WiFi.mode(WIFI_STA);
  WiFi.begin(WiFi_SSID.c_str(), WiFi_Password.c_str());
  delay(100);

  // WiFi 連接需要時間,因此這里相當(dāng)于持續(xù)檢測 10 秒
  int times = 0;
  while ( times < 10 ) {
    if (WiFi.status() == WL_CONNECTED) {
      return true;
    }
    delay(1000);
    times++;
  }
  return false;
}

/********* 設(shè)置為 AP 模式 ***************/
void SetupToAPMode() {
  DebugMessage("--- Setup Ap Model");

  WiFi.mode(WIFI_AP);
  WiFi.softAP(AP_SSID, AP_Password, 6, 0);
  createApModeWeb();

  //貌似 dns 不生效
  if (MDNS.begin(AP_Host))
  {
    MDNS.addService("http", "tcp", 80);
    DebugMessage("MDNS responder started");
    DebugMessage("You can now connect to http://" + String(AP_Host) + ".local");
  }
}

/********* 創(chuàng)建 AP 模式網(wǎng)頁 ***************/
void createApModeWeb()
{
  //加載網(wǎng)頁
  WebServer.on("/", []() {
    IPAddress ip = WiFi.softAPIP();
    webContent = "<!DOCTYPE HTML>";
    webContent += "<html>";
    webContent += "<title>WiFi 信息設(shè)置</title>";
    webContent += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">";
    webContent +=  "<p>請輸入 WiFi 信息</p>";
    webContent += wifiScanContent;
    //&nbsp;代表插入一個空格, 重復(fù)5個就是插入5個空格
    webContent += "<br>";
    webContent += "<form method='get' action='setting'>";
    webContent += "<table border=\"0\"><tr><td><label>SSID</label></td><td><input type=\"text\" placeholder=\"請輸入你要連接的 SSID\" name='ssid' maxlength=32 size=64></td></tr>";
    webContent += "<tr><td><label>PASSWORD</label></td><td><input type=\"text\" placeholder=\"請輸入該 WiFi 密碼\" name='pass' maxlength=64 size=64></td></tr></table>";
    //    webContent += "<input type=\"button\" value=\"重新掃描網(wǎng)絡(luò)\" onclick=\"self.location.href='/rescannetwork'\">";
    webContent += "&nbsp;&nbsp;&nbsp;<input type='reset' value=\"重設(shè)\">&nbsp;&nbsp;&nbsp;<input type='submit' value=\"存儲\"></form></html>";
    WebServer.send(200, "text/html", webContent);  //200代表服務(wù)器狀態(tài)碼為 OK, text/html代表用html網(wǎng)頁類型, 不加這個會找不到網(wǎng)頁
  });

  WebServer.on("/setting", []() {
    WiFi_SSID = WebServer.arg("ssid");
    WiFi_Password = WebServer.arg("pass");
    if (WiFi_SSID.length() > 0 && WiFi_Password.length() > 0)
    {
      if (WiFi_SSID.length() <= 32 && WiFi_Password.length() <= 64)
      {
        DebugMessage("clearing eeprom");
        for (int i = 0; i < 96; ++i) {
          EEPROM.write(i, 0);
        }
        DebugMessage("SSID To Write: " + WiFi_SSID + " Password To Write: " + WiFi_Password);

        for (int i = 0; i < WiFi_SSID.length(); ++i)
        {
          EEPROM.write(i, WiFi_SSID[i]);
        }

        for (int i = 0; i < WiFi_Password.length(); ++i)
        {
          EEPROM.write(32 + i, WiFi_Password[i]);
        }
        EEPROM.commit(); //EEPROM.write 并不會馬上寫入 EEPROM, 而是要執(zhí)行 EEPROM.commit()才會實(shí)際的寫入EEPROM
        delay(50);

        webContent = "存儲成功, 請按 RESET 鍵重新開機(jī)!";
        webStatusCode = 200;
      }
      else {
        webContent = "<p>輸入錯誤!!! SSID 允許的最大長度為 32,PASSWORD 允許的最大長度為 64, 按上一頁重新輸入</p>";
        webContent += "<input type=\"button\" value=\"上一頁\" onclick=\"self.location.href='/'\"></html>";
        webStatusCode = 404;
        DebugMessage("SSID length OR Password length too long");
      }
    }
    else {
      webContent = "<p>輸入錯誤!!! SSID 和 PASSWORD 都不允許為空, 按上一頁重新輸入</p>";
      webContent += "<input type=\"button\" value=\"上一頁\" onclick=\"self.location.href='/'\"></html>";
      webStatusCode = 404;
      DebugMessage("SSID length Password length is empty");
    }
    WebServer.send(webStatusCode, "text/html", webContent);
  });
}

/********* 掃描無線網(wǎng)絡(luò) ***************/
void ScanNetwork() {
  DebugMessage("---  Scan WiFi");

  WiFi.disconnect();
  WiFi.mode(WIFI_STA);
  delay(100);
  int wifiCount = WiFi.scanNetworks();

  if (wifiCount == 0)
    DebugMessage("Scan Network Done...and No Any Networks Found!");
  else
  {
    DebugMessage("Scan Network Done...and " + String(wifiCount) + " Networks Found!");
    for (int i = 0; i < wifiCount; ++i)
    {
      // Print SSID and RSSI for each network found
      DebugMessage(String(i + 1) + ": " + WiFi.SSID(i) + " (" + WiFi.RSSI(i) + ") Encryption Type:" + getEncryptionTypeString(WiFi.encryptionType(i))) ;
      delay(100);
    }
  }

  // 將 WiFi 信息構(gòu)造成 html 格式
  wifiScanContent = "<ol type=\"1\" start=\"1\">";
  for (int i = 0; i < wifiCount; ++i)
  {
    // Print SSID and RSSI for each network found
    wifiScanContent += "<table border=\"0\"><tr><td width=\"300px\">";
    wifiScanContent += String(i + 1) + ". ";
    wifiScanContent += WiFi.SSID(i);
    wifiScanContent += " (";
    wifiScanContent += WiFi.RSSI(i);
    wifiScanContent += ")";
    wifiScanContent += "</td><td width=\"200px\">";

    byte encryption = WiFi.encryptionType(i);
    wifiScanContent += getEncryptionTypeString(encryption);
    wifiScanContent += "</td></tr>";
  }
  wifiScanContent += "</ol></table><br>";
}

String getEncryptionTypeString(byte type)
{
  String str = "";
  switch (type) {
    case 2: str = "TKIP(WPA)"; break;
    case 5: str = "WEP"; break;
    case 4: str = "CCMP(WPA)"; break;
    case 7: str = "NONE"; break;
    case 8: str = "AUTO(WPA or WPA2)"; break;
    default:
      str = "";
  }
  return str;
}

void createConnectedWeb()
{
  WebServer.on("/", []() {
    webContent = "<!DOCTYPE HTML>";
    webContent += "<html>";
    webContent += "<title>WiFi 信息</title>";
    webContent += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">";
    webContent +=  "<p>當(dāng)前 WiFi 信息</p>";
    //    webContent += wifiScanContent;
    //&nbsp;代表插入一個空格, 重復(fù)5個就是插入5個空格
    webContent += "<br>";

    webContent += "<table border=\"0\"><tr><td><label>當(dāng)前 SSID: </label></td>";
    webContent += "<td><label>" + WiFi_SSID + "</label></td></tr>";
    webContent += "<tr><td><label>當(dāng)前 IP 地址: </label></td>";
    webContent += "<td><label>" +  WiFi.localIP().toString() + "</label></td></tr></table>";
    webContent += "</html>";
    WebServer.send(200, "text/html", webContent);
  });
}


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末升筏,一起剝皮案震驚了整個濱河市撑柔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌您访,老刑警劉巖铅忿,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異灵汪,居然都是意外死亡檀训,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門享言,熙熙樓的掌柜王于貴愁眉苦臉地迎上來峻凫,“玉大人,你說我怎么就攤上這事览露∮恚” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵肛循,是天一觀的道長铭腕。 經(jīng)常有香客問我,道長多糠,這世上最難降的妖魔是什么累舷? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮夹孔,結(jié)果婚禮上被盈,老公的妹妹穿的比我還像新娘。我一直安慰自己搭伤,他們只是感情好只怎,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著怜俐,像睡著了一般身堡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拍鲤,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天贴谎,我揣著相機(jī)與錄音,去河邊找鬼季稳。 笑死擅这,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的景鼠。 我是一名探鬼主播仲翎,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了溯香?” 一聲冷哼從身側(cè)響起鲫构,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎玫坛,沒想到半個月后芬迄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡昂秃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了杜窄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肠骆。...
    茶點(diǎn)故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖塞耕,靈堂內(nèi)的尸體忽然破棺而出蚀腿,到底是詐尸還是另有隱情,我是刑警寧澤扫外,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布莉钙,位于F島的核電站,受9級特大地震影響筛谚,放射性物質(zhì)發(fā)生泄漏磁玉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一驾讲、第九天 我趴在偏房一處隱蔽的房頂上張望蚊伞。 院中可真熱鬧,春花似錦吮铭、人聲如沸时迫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽掠拳。三九已至,卻和暖如春纸肉,著一層夾襖步出監(jiān)牢的瞬間溺欧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工毁靶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胧奔,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓预吆,卻偏偏與公主長得像龙填,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評論 2 345