Esp8266 使用可配置式 WiFi

最近在使用 WeMos D1 mini 制作一个局域网开机模块,需要将 WiFi 信息设置为可配置,网上搜索良久都未发现满意的解决方案,最终在一个台湾上人的博客上,发现了一个相对比较友好的程序,博客原链接如下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,可以写入在这里预先输入自己最常用的 WiFi 信息,也可以设置为空字符串
String WiFi_SSID = "";
String WiFi_Password = "";

//Ap 设置热点信息
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 连接需要时间,因此这里相当于持续检测 10 秒
  int times = 0;
  while ( times < 10 ) {
    if (WiFi.status() == WL_CONNECTED) {
      return true;
    }
    delay(1000);
    times++;
  }
  return false;
}

/********* 设置为 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");
  }
}

/********* 创建 AP 模式网页 ***************/
void createApModeWeb()
{
  //加载网页
  WebServer.on("/", []() {
    IPAddress ip = WiFi.softAPIP();
    webContent = "<!DOCTYPE HTML>";
    webContent += "<html>";
    webContent += "<title>WiFi 信息设置</title>";
    webContent += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">";
    webContent +=  "<p>请输入 WiFi 信息</p>";
    webContent += wifiScanContent;
    //&nbsp;代表插入一个空格, 重复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=\"重新扫描网络\" onclick=\"self.location.href='/rescannetwork'\">";
    webContent += "&nbsp;&nbsp;&nbsp;<input type='reset' value=\"重设\">&nbsp;&nbsp;&nbsp;<input type='submit' value=\"存储\"></form></html>";
    WebServer.send(200, "text/html", webContent);  //200代表服务器状态码为 OK, text/html代表用html网页类型, 不加这个会找不到网页
  });

  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, 而是要执行 EEPROM.commit()才会实际的写入EEPROM
        delay(50);

        webContent = "存储成功, 请按 RESET 键重新开机!";
        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);
  });
}

/********* 扫描无线网络 ***************/
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 信息构造成 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>当前 WiFi 信息</p>";
    //    webContent += wifiScanContent;
    //&nbsp;代表插入一个空格, 重复5个就是插入5个空格
    webContent += "<br>";

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


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342