PersWiFiManager.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /* PersWiFiManager
  2. version 3.0.1
  3. https://r-downing.github.io/PersWiFiManager/
  4. */
  5. #include "PersWiFiManager.h"
  6. //#ifdef WIFI_HTM_PROGMEM
  7. const char wifi_htm[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/><title>ESP WiFi</title><script>function g(i){return document.getElementById(i);};function p(t,l){if(confirm(t)) window.location=l;};function E(s){return document.createElement(s)};var S="setAttribute",A="appendChild",H="innerHTML",X,wl;function scan(){if(X) return;X=new XMLHttpRequest(),wl=document.getElementById('wl');wl[H]="Scanning...";X.onreadystatechange=function(){if (this.readyState==4&&this.status==200){X=0;wl[H]="";this.responseText.split("\n").forEach(function (e){let t=e.split(","), s=t.slice(2).join(',');var d=E('div'),i=E('a'),c=E('a');i[S]('class','s'); c[S]('class','q');i.onclick=function(){g('s').value=s;g('p').focus();};i[A](document.createTextNode(s));c[H]=t[0]+"%"+(parseInt(t[1])?"\uD83D\uDD12":"\u26A0");wl[A](i); wl[A](c);wl[A](document.createElement('br'));});}};X.open("GET","wifi/list",true);X.send();};</script><style>input{padding:5px;font-size:1em;width:95%;}body{text-align:center;font-family:verdana;background-color:black;color:white;}a{color:#1fa3ec;}button{border:0;border-radius:0.3em;background-color:#1fa3ec;color:#fff;line-height:2.4em;font-size:1.2em;width:100%;display:block;}.q{float:right;}.s{display:inline-block;width:14em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}#wl{line-height:1.5em;}</style></head><body><div style='text-align:left;display:inline-block;width:320px;padding:5px'><button onclick="scan()">&#x21bb; Scan</button><p id='wl'></p><form method='post' action='/wifi/connect'><input id='s' name='n' length=32 placeholder='SSID'><br><input id='p' name='p' length=64 type='password' placeholder='password'><br><br><button type='submit'>Connect</button></form><br><br><button onclick="p('Start WPS?','/wifi/wps')">WPS Setup</button><br><button onclick="p('Reboot device?','/wifi/rst')">Reboot</button><br><a href="/">Home</a></div></body></html>)=====";
  8. //#endif
  9. PersWiFiManager::PersWiFiManager(ESP8266WebServer& s, DNSServer& d) {
  10. _server = &s;
  11. _dnsServer = &d;
  12. _apPass = "";
  13. } //PersWiFiManager
  14. bool PersWiFiManager::attemptConnection(const String& ssid, const String& pass) {
  15. //attempt to connect to wifi
  16. WiFi.mode(WIFI_STA);
  17. if (ssid.length()) {
  18. if (pass.length()) WiFi.begin(ssid.c_str(), pass.c_str());
  19. else WiFi.begin(ssid.c_str());
  20. } else {
  21. WiFi.begin();
  22. }
  23. //if in nonblock mode, skip this loop
  24. _connectStartTime = millis();// + 1;
  25. while (!_connectNonBlock && _connectStartTime) {
  26. handleWiFi();
  27. delay(10);
  28. }
  29. return (WiFi.status() == WL_CONNECTED);
  30. } //attemptConnection
  31. void PersWiFiManager::handleWiFi() {
  32. if (!_connectStartTime) return;
  33. if (WiFi.status() == WL_CONNECTED) {
  34. _connectStartTime = 0;
  35. if (_connectHandler) _connectHandler();
  36. return;
  37. }
  38. //if failed or not connected and time is up
  39. //if ((WiFi.status() == WL_CONNECT_FAILED) || ((WiFi.status() != WL_CONNECTED) && ((millis() - _connectStartTime) > (1000 * WIFI_CONNECT_TIMEOUT)))) {
  40. if ((WiFi.status() == WL_CONNECT_FAILED) || ((WiFi.status() != WL_CONNECTED))) {
  41. if(((millis() - _connectStartTime) > (1000 * WIFI_CONNECT_TIMEOUT))) {
  42. startApMode();
  43. _connectStartTime = 0; //reset connect start time
  44. }
  45. //else {
  46. //retrying...
  47. // attemptConnection();
  48. // }
  49. }
  50. } //handleWiFi
  51. void PersWiFiManager::startApMode(){
  52. //start AP mode
  53. IPAddress apIP(192, 168, 1, 1);
  54. WiFi.mode(WIFI_AP);
  55. WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
  56. _apPass.length() ? WiFi.softAP(getApSsid().c_str(), _apPass.c_str()) : WiFi.softAP(getApSsid().c_str());
  57. if (_apHandler) _apHandler();
  58. }//startApMode
  59. void PersWiFiManager::setConnectNonBlock(bool b) {
  60. _connectNonBlock = b;
  61. } //setConnectNonBlock
  62. void PersWiFiManager::setupWiFiHandlers() {
  63. IPAddress apIP(192, 168, 1, 1);
  64. _dnsServer->setErrorReplyCode(DNSReplyCode::NoError);
  65. _dnsServer->start((byte)53, "*", apIP); //used for captive portal in AP mode
  66. _server->on("/wifi/list", [&] () {
  67. //scan for wifi networks
  68. int n = WiFi.scanNetworks();
  69. //build array of indices
  70. int ix[n];
  71. for (int i = 0; i < n; i++) ix[i] = i;
  72. //sort by signal strength
  73. for (int i = 0; i < n; i++) for (int j = 1; j < n - i; j++) if (WiFi.RSSI(ix[j]) > WiFi.RSSI(ix[j - 1])) std::swap(ix[j], ix[j - 1]);
  74. //remove duplicates
  75. for (int i = 0; i < n; i++) for (int j = i + 1; j < n; j++) if (WiFi.SSID(ix[i]).equals(WiFi.SSID(ix[j])) && WiFi.encryptionType(ix[i]) == WiFi.encryptionType(ix[j])) ix[j] = -1;
  76. //build plain text string of wifi info
  77. //format [signal%]:[encrypted 0 or 1]:SSID
  78. String s = "";
  79. s.reserve(2050);
  80. for (int i = 0; i < n && s.length() < 2000; i++) { //check s.length to limit memory usage
  81. if (ix[i] != -1) {
  82. s += String(i ? "\n" : "") + ((constrain(WiFi.RSSI(ix[i]), -100, -50) + 100) * 2) + ","
  83. + ((WiFi.encryptionType(ix[i]) == ENC_TYPE_NONE) ? 0 : 1) + "," + WiFi.SSID(ix[i]);
  84. }
  85. }
  86. //send string to client
  87. _server->send(200, "text/plain", s);
  88. }); //_server->on /wifi/list
  89. _server->on("/wifi/wps", [&]() {
  90. _server->send(200, "text/html", "attempting WPS");
  91. WiFi.mode(WIFI_STA);
  92. WiFi.beginWPSConfig();
  93. delay(100);
  94. if (WiFi.status() != WL_CONNECTED) {
  95. attemptConnection("", "");
  96. }
  97. }); //_server->on /wifi/wps
  98. _server->on("/wifi/connect", [&]() {
  99. _server->send(200, "text/html", "connecting...");
  100. attemptConnection(_server->arg("n"), _server->arg("p"));
  101. }); //_server->on /wifi/connect
  102. _server->on("/wifi/ap", [&](){
  103. _server->send(200, "text/html", "access point: "+getApSsid());
  104. startApMode();
  105. }); //_server->on /wifi/ap
  106. _server->on("/wifi/rst", [&]() {
  107. _server->send(200, "text/html", "Rebooting...");
  108. delay(100);
  109. ESP.restart();
  110. });
  111. //#ifdef WIFI_HTM_PROGMEM
  112. _server->on("/wifi.htm", [&]() {
  113. _server->send(200, "text/html", wifi_htm);
  114. });
  115. //#endif
  116. }//setupWiFiHandlers
  117. bool PersWiFiManager::begin(const String& ssid, const String& pass) {
  118. setupWiFiHandlers();
  119. return attemptConnection(ssid, pass); //switched order of these two for return
  120. } //begin
  121. String PersWiFiManager::getApSsid() {
  122. return _apSsid.length() ? _apSsid : "ESP8266";
  123. } //getApSsid
  124. void PersWiFiManager::setApCredentials(const String& apSsid, const String& apPass) {
  125. if (apSsid.length()) _apSsid = apSsid;
  126. if (apPass.length() >= 8) _apPass = apPass;
  127. } //setApCredentials
  128. void PersWiFiManager::onConnect(WiFiChangeHandlerFunction fn) {
  129. _connectHandler = fn;
  130. }
  131. void PersWiFiManager::onAp(WiFiChangeHandlerFunction fn) {
  132. _apHandler = fn;
  133. }