You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

448 line
17KB

  1. #include <ArduinoJson.h>
  2. #include <WiFi.h>
  3. #include "FS.h"
  4. #include "SPIFFS.h"
  5. #include <EEPROM.h>
  6. #include <WebServer.h>
  7. #define MESSAGE_MAX_LEN 256
  8. //**************DEEP SLEEP CONFIG******************//
  9. #define uS_TO_S_FACTOR 1000000
  10. #define TIME_TO_SLEEP 5
  11. //************** Auxillary functions******************//
  12. WebServer server(80);
  13. StaticJsonDocument<234> jsonBuffer;
  14. //**********softAPconfig Timer*************//
  15. unsigned long APTimer = 0;
  16. unsigned long APInterval = 120000;
  17. //*********SSID and Pass for AP**************//
  18. const char* ssidAPConfig = "Andreas-Grabner.NET";
  19. const char* passAPConfig = "born2win";
  20. //**********check for connection*************//
  21. bool isConnected = true;
  22. bool isAPConnected = true;
  23. //*********Contains SPIFFS Info*************//
  24. String debugLogData;
  25. //HTML char array
  26. const char HTTP_HEAD_HTML[] PROGMEM = "<!DOCTYPE HTML><html><head><meta name = \"viewport\" http-equiv=\"content-type\" content = \"width = device-width, initial-scale = 1.0, maximum-scale = 1.0, user-scalable=0\"><title>ESP32 Demo</title>";
  27. const char HTTP_STYLE[] PROGMEM= "<style>body { background-color: #0067B3 ; font-family: Arial, Helvetica, Sans-Serif; Color: #FFFFFF; }</style></head>";
  28. const char HTTP_HEAD_STYLE[] PROGMEM= "<body><center><h1 style=\"color:#FFFFFF; font-family:verdana;font-family: verdana;padding-top: 10px;padding-bottom: 10px;font-size: 36px\">ESP32 Captive Portal</h1><h2 style=\"color:#FFFFFF;font-family: Verdana;font: caption;font-size: 27px;padding-top: 10px;padding-bottom: 10px;\">Give Your WiFi Credentials</h2>";
  29. const char HTTP_FORM_START[] PROGMEM= "<FORM action=\"/\" method= \"post\">";
  30. const char HTTP_CONTENT1_START[] PROGMEM= "<div style=\"padding-left:100px;text-align:left;display:inline-block;min-width:150px;\"><a href=\"#pass\" onclick=\"c(this)\" style=\"text-align:left\">{v}</a></div>&nbsp&nbsp&nbsp <div style=\"display:inline-block;min-width:260px;\"><span class=\"q\" style=\"text-align:right\">{r}%</span></div><br>";
  31. const char HTTP_CONTENT2_START[] PROGMEM= "<P ><label style=\"font-family:Times New Roman\">SSID</label><br><input maxlength=\"30px\" id=\"ssid\" type=\"text\" name=\"ssid\" placeholder='Enter WiFi SSID' style=\"width: 400px; padding: 5px 10px ; margin: 8px 0; border : 2px solid #3498db; border-radius: 4px; box-sizing:border-box\" ><br></P>";
  32. const char HTTP_CONTENT3_START[] PROGMEM= "<P><label style=\"font-family:Times New Roman\">PASSKEY</label><br><input maxlength=\"30px\" type = \"text\" id=\"pass\" name=\"passkey\" placeholder = \"Enter WiFi PASSKEY\" style=\"width: 400px; padding: 5px 10px ; margin: 8px 0; border : 2px solid #3498db; border-radius: 4px; box-sizing:border-box\" ><br><P>";
  33. const char HTTP_CONTENT4_START[] PROGMEM= "<input type=\"checkbox\" name=\"configure\" value=\"change\"> Change IP Settings </P>";
  34. const char HTTP_CONTENT5_START[] PROGMEM= "<INPUT type=\"submit\">&nbsp&nbsp&nbsp&nbsp<INPUT type=\"reset\"><style>input[type=\"reset\"]{background-color: #3498DB; border: none; color: white; padding: 15px 48px; text-align: center; text-decoration: none;display: inline-block; font-size: 16px;}input[type=\"submit\"]{background-color: #3498DB; border: none; color: white; padding: 15px 48px;text-align: center; text-decoration: none;display: inline-block;font-size: 16px;}</style>";
  35. const char HTTP_FORM_END[] PROGMEM= "</FORM>";
  36. const char HTTP_SCRIPT[] PROGMEM= "<script>function c(l){document.getElementById('ssid').value=l.innerText||l.textContent;document.getElementById('pass').focus();}</script>";
  37. const char HTTP_END[] PROGMEM= "</body></html>";
  38. //const char* const WEBPAGE_TABLE[] PROGMEM = {HTTP_HEAD_HTML, HTTP_STYLE, HTTP_HEAD_STYLE, HTTP_FORM_START, HTTP_CONTENT1_START, HTTP_CONTENT2_START,HTTP_CONTENT3_START,HTTP_CONTENT4_START,HTTP_CONTENT5_START,HTTP_FORM_END,HTTP_SCRIPT, };
  39. const char* messageStatic PROGMEM= "{\"staticSet\":\"staticValue\", \"staticIP\":\"%s\", \"staticGate\":\"%s\", \"staticSub\":\"%s\",\"ssidStatic\":\"%s\",\"staticPass\":\"%s\"}";
  40. const char* messageDhcp PROGMEM= "{\"dhcpSet\":\"dhcpValue\",\"ssidDHCP\":\"%s\", \"passDHCP\":\"%s\"}";
  41. const char HTTP_PAGE_STATIC[] PROGMEM = "<p>{s}<br>{g}<br>{n}<br></p>";
  42. const char HTTP_PAGE_DHCP[] PROGMEM = "<p>{s}</p>";
  43. const char HTTP_PAGE_WiFi[] PROGMEM = "<p>{s}<br>{p}</p>";
  44. const char HTTP_PAGE_GOHOME[] PROGMEM = "<H2><a href=\"/\">go home</a></H2><br>";
  45. char messageBuf[MESSAGE_MAX_LEN];
  46. void setup() {
  47. Serial.begin(115200);
  48. while(!Serial);
  49. WiFi.persistent(false);
  50. WiFi.disconnect(true);
  51. SPIFFS.begin();
  52. delay(100);
  53. EEPROM.begin(512);
  54. delay(100);
  55. File file = SPIFFS.open("/ip_set.txt", "r");
  56. Serial.println("- read from file:");
  57. if(!file){
  58. Serial.println("- failed to open file for reading");
  59. return;
  60. }
  61. while(file.available()){
  62. debugLogData += char(file.read());
  63. }
  64. file.close();
  65. if(debugLogData.length()>10){
  66. //JsonObject& readRoot =jsonBuffer.parseObject(debugLogData);
  67. StaticJsonDocument<256> readRoot;
  68. deserializeJson(readRoot, debugLogData);
  69. Serial.println("=====================================");
  70. Serial.println(debugLogData);
  71. Serial.println("=====================================");
  72. if(readRoot.containsKey("staticSet")){
  73. Serial.println("Static IP Started ");
  74. staticAPConfig(readRoot["staticIP"],readRoot["staticGate"],readRoot["staticSub"],readRoot["ssidStatic"],readRoot["staticPass"]);
  75. }
  76. else if(readRoot.containsKey("dhcpSet")){
  77. Serial.println("DHCP IP Started" );
  78. dhcpAPConfig(readRoot["ssidDHCP"],readRoot["passDHCP"]);
  79. }
  80. else{
  81. handleClientAP();
  82. }
  83. }else{
  84. handleClientAP();
  85. }
  86. reconnectWiFi();
  87. }
  88. void loop() {
  89. Serial.println(WiFi.localIP());
  90. delay(500);
  91. }
  92. //****************************HANDLE ROOT***************************//
  93. void handleRoot() {
  94. //Redisplay the form
  95. if(server.args()>0){
  96. for(int i=0; i<=server.args();i++){
  97. Serial.println(String(server.argName(i))+'\t' + String(server.arg(i)));
  98. }
  99. if(server.hasArg("ipv4static") && server.hasArg("gateway") && server.hasArg("subnet")){
  100. staticSet();
  101. }else if(server.hasArg("passkeyDhcp")&&server.hasArg("ssidDhcp")){
  102. dhcpSetDefault();
  103. }
  104. }else{
  105. File file = SPIFFS.open("/Select_Settings.html", "r");
  106. server.streamFile(file,"text/html");
  107. file.close();
  108. }
  109. }
  110. //****************************HANDLE DHCP***************************//
  111. void handleDHCP(){
  112. File file = SPIFFS.open("/page_dhcp.html", "r");
  113. server.streamFile(file,"text/html");
  114. file.close();
  115. }
  116. //****************************HANDLE STATIC***************************//
  117. void handleStatic(){
  118. File file = SPIFFS.open("/page_static.html", "r");
  119. server.streamFile(file,"text/html");
  120. file.close();
  121. }
  122. //*************Helper Meathod for Writing IP CONFIG**************//
  123. //*************Helper 1 STATIC**************//
  124. void staticSet(){
  125. String response=FPSTR(HTTP_PAGE_STATIC);
  126. response.replace("{s}",server.arg("ipv4static"));
  127. response.replace("{g}",server.arg("gateway"));
  128. response.replace("{n}",server.arg("subnet"));
  129. response+=FPSTR(HTTP_PAGE_GOHOME);
  130. server.send(200, "text/html", response);
  131. snprintf(messageBuf,MESSAGE_MAX_LEN,messageStatic,String(server.arg("ipv4static")),String(server.arg("gateway")),String(server.arg("subnet")),String(server.arg("ssidStatic")),String(server.arg("passkeyStatic")));
  132. String str(messageBuf);
  133. File fileToWrite = SPIFFS.open("/ip_set.txt", FILE_WRITE);
  134. if(!fileToWrite){
  135. Serial.println("Error opening SPIFFS");
  136. return;
  137. }
  138. if(fileToWrite.write((uint8_t*)str.c_str(),str.length())){
  139. Serial.println("--File Written");
  140. }else{
  141. Serial.println("--Error Writing File");
  142. }
  143. fileToWrite.close();
  144. isConnected = false;
  145. }
  146. //*************Helper 3 DHCP DEFAULT**************//
  147. void dhcpSetDefault(){
  148. String response=FPSTR(HTTP_PAGE_DHCP);
  149. response.replace("{s}","192.168.4.1");
  150. response+=FPSTR(HTTP_PAGE_GOHOME);
  151. server.send(200, "text/html", response);
  152. snprintf(messageBuf,MESSAGE_MAX_LEN,messageDhcp,String(server.arg("ssidDhcp")).c_str(),String(server.arg("passkeyDhcp")).c_str());
  153. String str(messageBuf);
  154. File fileToWrite = SPIFFS.open("/ip_set.txt", FILE_WRITE);
  155. if(!fileToWrite){
  156. Serial.println("Error opening SPIFFS");
  157. }
  158. if(fileToWrite.write((uint8_t*)str.c_str(),str.length())){
  159. Serial.println(F("--File Written"));
  160. }else{
  161. Serial.println(F("--Error Writing File"));
  162. }
  163. fileToWrite.close();
  164. isConnected = false;
  165. }
  166. //****************HANDLE NOT FOUND*********************//
  167. void handleNotFound()
  168. {
  169. String message = "File Not Found\n\n";
  170. message += "URI: ";
  171. message += server.uri();
  172. server.send(404, "text/plain", message);
  173. }
  174. //***************Parse bytes from string******************//
  175. void parseBytes(const char* str, char sep, byte* bytes, int maxBytes, int base) {
  176. for (int i = 0; i < maxBytes; i++) {
  177. bytes[i] = strtoul(str, NULL, base); // Convert byte
  178. str = strchr(str, sep); // Find next separator
  179. if (str == NULL || *str == '\0') {
  180. break; // No more separators, exit
  181. }
  182. str++; // Point to next character after separator
  183. }
  184. }
  185. //****************HANDLE CLIENT 192.168.1.77*********************//
  186. void handleClientAP(){
  187. //*********Static IP Config**************//
  188. WiFi.mode(WIFI_AP);
  189. Serial.println(WiFi.softAP(ssidAPConfig,passAPConfig) ? "soft-AP setup": "Failed to connect");
  190. delay(100);
  191. Serial.println(WiFi.softAPConfig( IPAddress(192,168,1,77),IPAddress(192,168,1,254), IPAddress(255,255,255,0))? "Configuring Soft AP" : "Error in Configuration");
  192. Serial.println(WiFi.softAPIP());
  193. server.begin();
  194. server.on("/", handleRoot);
  195. server.on("/dhcp", handleDHCP);
  196. server.on("/static", handleStatic);
  197. server.onNotFound(handleNotFound);
  198. APTimer = millis();
  199. while(isConnected && millis()-APTimer<= APInterval) {
  200. server.handleClient();}
  201. esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  202. esp_deep_sleep_start();
  203. }
  204. //***************************STATIC Helper method**************************//
  205. void staticAPConfig(String IPStatic, String gateway, String subnet, String ssid, String pass){
  206. //*********hold IP octet**************//
  207. uint8_t ip0,ip1,ip2,ip3;
  208. //*********IP Char Array**************//
  209. Serial.print(ssid);
  210. Serial.print(pass);
  211. byte ip[4];
  212. parseBytes(IPStatic.c_str(),'.', ip, 4, 10);
  213. ip0 = (uint8_t)ip[0];
  214. ip1 = (uint8_t)ip[1];
  215. ip2 = (uint8_t)ip[2];
  216. ip3 = (uint8_t)ip[3];
  217. IPAddress ap_local(ip0,ip1,ip2,ip3);
  218. parseBytes(gateway.c_str(),'.', ip, 4, 10);
  219. ip0 = (uint8_t)ip[0];
  220. ip1 = (uint8_t)ip[1];
  221. ip2 = (uint8_t)ip[2];
  222. ip3 = (uint8_t)ip[3];
  223. IPAddress ap_gate(ip0,ip1,ip2,ip3);
  224. parseBytes(subnet.c_str(),'.', ip, 4, 10);
  225. ip0 = (uint8_t)ip[0];
  226. ip1 = (uint8_t)ip[1];
  227. ip2 = (uint8_t)ip[2];
  228. ip3 = (uint8_t)ip[3];
  229. IPAddress ap_net(ip0,ip1,ip2,ip3);
  230. WiFi.disconnect(true);
  231. WiFi.mode(WIFI_AP);
  232. Serial.println(WiFi.softAP(ssid.c_str(),pass.c_str()) ? "Setting up SoftAP" : "error setting up");
  233. delay(100);
  234. Serial.println(WiFi.softAPConfig(ap_local, ap_gate, ap_net) ? "Configuring softAP" : "kya yaar not connected");
  235. Serial.println(WiFi.softAPIP());
  236. server.begin();
  237. server.on("/", handleStaticForm);
  238. server.onNotFound(handleNotFound);
  239. APTimer = millis();
  240. while(isAPConnected && millis()-APTimer<= APInterval) {
  241. server.handleClient(); }
  242. }
  243. //***************************WiFi Credintial Form**************************//
  244. void dhcpAPConfig(String ssid, String pass){
  245. WiFi.mode(WIFI_OFF);
  246. WiFi.softAPdisconnect(true);
  247. delay(1000);
  248. WiFi.mode(WIFI_AP);
  249. Serial.println(WiFi.softAP(ssid.c_str(),pass.c_str()) ? "Setting up SoftAP" : "error setting up");
  250. delay(200);
  251. Serial.println(WiFi.softAPIP());
  252. server.begin();
  253. server.on("/", handleStaticForm);
  254. server.onNotFound(handleNotFound);
  255. APTimer = millis();
  256. while(isAPConnected && millis()-APTimer<= APInterval) {
  257. server.handleClient(); }
  258. }
  259. //****************************HANDLE STATIC FORM***************************//
  260. void handleStaticForm() {
  261. //JsonObject& root =jsonBuffer.createObject();
  262. DynamicJsonDocument root(1024);
  263. root["no"]= "";
  264. //root.printTo(Serial);
  265. serializeJson(root, Serial);
  266. if(server.hasArg("ssid") && server.hasArg("passkey")){
  267. if(server.arg("configure") != ""){
  268. File fileToWrite = SPIFFS.open("/ip_set.txt", FILE_WRITE);
  269. if(!fileToWrite){
  270. Serial.println("Error opening SPIFFS");
  271. return;
  272. }
  273. if(!serializeJson(root, fileToWrite)){
  274. Serial.println("--File Written");
  275. esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  276. esp_deep_sleep_start();
  277. }else{
  278. Serial.println("--Error Writing File");
  279. }
  280. }
  281. handleSubmitForm();
  282. }else{
  283. int n = WiFi.scanNetworks();
  284. int indices[n];
  285. if(n == 0){
  286. Serial.println("No networks found");
  287. }else{
  288. for (int i = 0; i < n; i++) {
  289. indices[i] = i;
  290. }
  291. for (int i = 0; i < n; i++) {
  292. Serial.println(WiFi.SSID(indices[i]));
  293. Serial.print('\t');
  294. Serial.println(getRSSIasQuality(WiFi.RSSI(indices[i])));
  295. }
  296. }
  297. String webpage = FPSTR(HTTP_HEAD_HTML);
  298. webpage += FPSTR(HTTP_STYLE);
  299. webpage += FPSTR(HTTP_HEAD_STYLE);
  300. webpage += FPSTR(HTTP_FORM_START);
  301. for(int i=0;i<n;i++){
  302. int quality = getRSSIasQuality(WiFi.RSSI(indices[i]));
  303. String item = FPSTR(HTTP_CONTENT1_START);
  304. String RssiQuality = String(quality);
  305. item.replace("{v}",WiFi.SSID(indices[i]));
  306. item.replace("{r}",RssiQuality);
  307. webpage+=item;
  308. }
  309. webpage += FPSTR(HTTP_CONTENT2_START);
  310. webpage += FPSTR(HTTP_CONTENT3_START);
  311. webpage += FPSTR(HTTP_CONTENT4_START);
  312. webpage += FPSTR(HTTP_CONTENT5_START);
  313. webpage += FPSTR(HTTP_FORM_END);
  314. webpage += FPSTR(HTTP_SCRIPT);
  315. webpage += FPSTR(HTTP_END);
  316. server.send(200,"text/html",webpage);
  317. }
  318. }
  319. //****************************WiFi Credintial Submit****************************//
  320. void handleSubmitForm() {
  321. String response=FPSTR(HTTP_PAGE_WiFi);
  322. response.replace("{s}",server.arg("ssid"));
  323. response.replace("{p}",String(server.arg("passkey")));
  324. response+=FPSTR(HTTP_PAGE_GOHOME);
  325. server.send(200, "text/html", response);
  326. ROMwrite(String(server.arg("ssid")),String(server.arg("passkey")));
  327. isAPConnected = false;
  328. }
  329. //----------Write to ROM-----------//
  330. void ROMwrite(String s, String p){
  331. s+=";";
  332. write_EEPROM(s,0);
  333. p+=";";
  334. write_EEPROM(p,50);
  335. EEPROM.commit();
  336. }
  337. //***********Write to ROM**********//
  338. void write_EEPROM(String x,int pos){
  339. for(int n=pos;n<x.length()+pos;n++){
  340. //write the ssid and password fetched from webpage to EEPROM
  341. EEPROM.write(n,x[n-pos]);
  342. }
  343. }
  344. //****************************EEPROM Read****************************//
  345. String read_string(int l, int p){
  346. String temp;
  347. for (int n = p; n < l+p; ++n)
  348. {
  349. // read the saved password from EEPROM
  350. if(char(EEPROM.read(n))!=';'){
  351. temp += String(char(EEPROM.read(n)));
  352. }else n=l+p;
  353. }
  354. return temp;
  355. }
  356. //****************************Connect to WiFi****************************//
  357. void reconnectWiFi(){
  358. WiFi.mode(WIFI_STA);
  359. WiFi.disconnect();
  360. String string_Ssid="";
  361. String string_Password="";
  362. string_Ssid= read_string(30,0);
  363. string_Password= read_string(30,50);
  364. Serial.println("ssid: "+ string_Ssid);
  365. Serial.println("Password: "+string_Password);
  366. delay(400);
  367. WiFi.begin(string_Ssid.c_str(),string_Password.c_str());
  368. int counter = 0;
  369. while (WiFi.status() != WL_CONNECTED)
  370. {
  371. delay(500);
  372. Serial.print(".");
  373. if(counter == 20){
  374. String response = "<script>alert(\"Password not connected\")</script";
  375. server.send(200,"text/html",response);
  376. ESP.restart();
  377. }
  378. counter++;
  379. }
  380. Serial.print("Connected to:\t");
  381. Serial.println(WiFi.localIP());
  382. }
  383. int getRSSIasQuality(int RSSI) {
  384. int quality = 0;
  385. if (RSSI <= -100) {
  386. quality = 0;
  387. } else if (RSSI >= -50) {
  388. quality = 100;
  389. } else {
  390. quality = 2 * (RSSI + 100);
  391. }
  392. return quality;
  393. }