ESP_IOT v2.5
IOT ESP Coding
WIFI_APModule.cpp
Go to the documentation of this file.
1//! \link WIFI_APModule
2/*
3 *******************************************************************************
4 Copyright (c) 2021 by M5Stack
5 Equipped with M5StickC-Plus sample source code
6 配套 M5StickC-Plus 示例源代码
7 Visit the website for more information:https://docs.m5stack.com/en/core/m5stickc_plus
8 获取更多资料请访问:https://docs.m5stack.com/zh_CN/core/m5stickc_plus
9
10 describe:WiFi connect. wifi连接
11 date:2021/9/18
12
13 Scott Version: 1.1.2022
14 *******************************************************************************
15 */
16//#include "../../Defines.h"
17#include "WIFI_APModule.h"
18//! 8.16.25 WIFI AP
19
20#define TRY_FEED_FROM_AP
21
22//NOTE: one solution is to create a JSON object, and stringify then pass to the MQTT code to set the credentials..
23//! Will spif up the web page with some small images..
24//! https://randomnerdtutorials.com/display-images-esp32-esp8266-web-server/
25#include <ArduinoJson.h>
26
27//!NOTE: 12.15.23 The WiFiClientSecure does NOT work with the access point shown below.
28//!So we will go back to the WiFi.h
29#ifdef X_USE_REST_MESSAGING
30#include <WiFiClientSecure.h>
31#else
32#include <WiFi.h>
33#endif
34#include <ESPmDNS.h>
35#include <WiFiClient.h>
36
37#ifdef USE_LIB_WEBSERVER
38//! 7.16.26 try included one.. see if fixed M5Atom AP webpage not working.. only the header
39#include <WebServer.h>
40#else
41#include "WebServer.h"
42#endif
43
44#include <Preferences.h>
45
46//!returns string for the header image
47String headerImageString();
48
50void WIFI_setupMode();
51String WIFI_makePage(String title, String contents);
52String WIFI_urlDecode(String input);
53
54//used when we server as a WAP (Wireless Access Point == PetTutorSetup_192_168_4_1)
55const char *_WIFIWirelessAP = "192.168.4.1";
56
57//web page afterwards, using the wifi chosen.. NOT USED..
58//const char* _WIFIWirelessPage = "192.168.0.57";
59
60//Define the address of the wireless AP. 定义无线AP的地址
61const IPAddress _WIFIapIP(192, 168, 4, 1);
62
63//Define the name of the created hotspot. 定义创建热点的名称
64const char* _apSSID = "PetTutorSetup_192_168_4_1";
65
68//Store the name of the wireless network. 存储无线网络的名称
70//Store the password of the wireless network. 存储无线网络的密码
72//last ssid saved
74
75//!EPROM INFO .. might be a length issue of the attribute name
76#define AP_EPROM_NAME "ap_wifi"
77#define WIFI_SSID "1ws"
78#define WIFI_PASSWORD "2wp"
79
80//the last time it was saved - only used for the PULL DOWN web list
81#define WIFI_SSID_LAST "3sl"
82
83#define MQTT
84#ifdef MQTT
85#define MQTT_PORT "4pt"
86#define MQTT_SERVER "5sv"
87#define MQTT_USER "6mu"
88#define MQTT_PASSWORD "7mp"
89#define MQTT_GUEST_PASSWORD "8mg"
90
91#define MQTT_TOPIC "9mt"
92#define MQTT_DEVICE_NAME "10md"
93#define MQTT_LOCATION_NAME "11ml"
94
100
102//char _WIFI_mqttTopic[100]; // or it's created from the 'user', etc user/bark
105
106
107#endif
108
109//!rediscover (and prints) the WIFIlist .. scanning each time.. so a page refresh will look again...
110void rediscoverWIFIList();
111
112//!create the javascript header to convert to lowercase, etc
113String getJavascriptString();
114
115//!remove spaces in a string
116//https://stackoverflow.com/questions/16329358/remove-spaces-from-a-string-in-c
117String removeSpaces(String input)
118{
119 String result = "";
120 for (int i=0; i< input.length(); i++)
121 {
122 if (input[i] != ' ')
123 {
124 result += input[i];
125 }
126 }
127 return result;
128}
129
130//! DNSServer dnsServer;. webServer的类, port 80
131WebServer WIFI_webServer(80);
132//!client of the web server??
133WiFiClient _WIFIClient;
134
135//! wifi config store. wifi配置存储的类
137
139//!called to set the done flag
140void setDoneWIFI_APModuleFlag(boolean flag)
141{
143}
144
145//!called to see if the WIFIModule has finished bootstrapping..
147{
149}
150
151//!resets the credentials
153{
154 _WIFI_SettingMode = true;
155}
156
157//! the json output string that contain the credentials
159
160//! retrieves the JSON string
162{
163 return _jsonOutputString;
164}
165
166
167//!returns true if the SSID is set, false otherwise. If set, then just exit..
169{
171
174
175 //added for last, only used in the web
177 _WIFIPreferences.end();
178
179 boolean ssidSet = _WIFI_ssid && (_WIFI_ssid.length() > 0);
180 SerialDebug.print("WIFI ssid = ");
181 SerialDebug.println(_WIFI_ssid?_WIFI_ssid:"NULL");
182 return ssidSet;
183}
184
185//!returns true if the SSID is set, false otherwise. If set, then just exit..
187{
188 SerialDebug.println("clean_SSID_WIFICredentials");
189
191
192 //this is emptied .. as the only way we know to get into this mode is an empty SSID ..
193 // THUS .. it doesn't matter if we had a value before.. UNLESS we save it somewhere else!
194 _WIFI_ssid = "";
196 _WIFIPreferences.end();
197 //! 8.16.25 MQTT
198 SerialDebug.println("call cleanMQTTpasswordsUpdateInEPROM");
199 //! 9.18.23 LA (after Eagle Rock bike ride, Van Morrison tomorrow)
201
202 SerialDebug.println("cleaned EPROM WIFI ssid and MQTT passwords ** REBOOTING");
203 //Restart MPU. 重启MPU
204 ESP.restart();
205
206}
207
208//!cleans the eprom info
210{
211 SerialDebug.println("cleanEPROM_WIFI_APModule");
212 _WIFIPreferences.begin(AP_EPROM_NAME, false); //readwrite..
213 _WIFIPreferences.clear();
214 _WIFIPreferences.end();
215}
216
217//! sets the MQTT user/password. It's up to the code to decide who needs to know
218void WIFI_APModule_updateMQTTInfo(char *ssid, char *ssid_password, char *username, char *password, char *guestPassword, char *deviceName, char *host, char *port, char *locationString)
219{
220 SerialDebug.printf("wifi_apModule.updateMQTTInfo(%s, %s, %s,%s, %s, %s, %s)\n", ssid?ssid:"NULL", ssid_password?ssid_password:"NULL", username?username:"NULL", password?password:"NULL", guestPassword?guestPassword:"NULL", locationString?locationString:"NULL", deviceName?deviceName:"NULL");
221
222 //!@see https://github.com/HomeSpan/HomeSpan/discussions/1148#discussioncomment-16508830
223 //! 8.11.26 try disconnect before
224 //!Disconnect wifi connection. 断开wifi连接
225 SerialTemp.println("WIFI.disconnect");
226 WiFi.disconnect();
227
228 _WIFIPreferences.begin(AP_EPROM_NAME, false); //readwrite..
229 _WIFIPreferences.putString(WIFI_SSID, ssid);
230 _WIFIPreferences.putString(WIFI_PASSWORD, ssid_password?ssid_password:"");
231
232 _WIFIPreferences.putString(MQTT_PORT, port);
233 _WIFIPreferences.putString(MQTT_SERVER, host);
234
235 _WIFIPreferences.putString(MQTT_USER, username);
236 _WIFIPreferences.putString(MQTT_PASSWORD, password?password:"");
237 _WIFIPreferences.putString(MQTT_GUEST_PASSWORD, guestPassword?guestPassword:"");
238
239 _WIFIPreferences.putString(MQTT_DEVICE_NAME, deviceName);
240 _WIFIPreferences.putString(MQTT_LOCATION_NAME, locationString);
241
242 _WIFIPreferences.end();
243
244 SerialDebug.println("done wifi_apModule.updateMQTTInfo");
245}
246
247//! 4.8.22. Called to do any state variables.
248//! a presetup() approach ..
250{
251//#define ADDED_TO_INIT_WILL_TAIKE_OUT_FOR_NOW
252
253#ifdef ADDED_TO_INIT_WILL_TAIKE_OUT_FOR_NOW
256#endif
257 SerialTemp.printf("preSetup_WIFI_APModule: isSet(%s)\n", isSet_SSID_WIFICredentials()?"set":"notSet");
258
260 {
261 //!Exit setup(). 退出setup()
263 }
264
265}
266
267//!sets the config in the EPPROM called wifi-config. NOTE: the _done isn't valid until after this code...
269
270 SerialTemp.printf("setup_WIFI_APModule: isSet(%s)\n", isSet_SSID_WIFICredentials()?"set":"notSet");
271
273 {
274 //!Exit setup(). 退出setup()
276 return;
277 }
278
279 //NOTE: here is where we would look for SSID set (if empty .. then continue). Not worrying about MQTT
281 delay(200);
282
283 //If there is no stored wifi configuration information, turn on the setting mode. 若没有已存储的wifi配置信息,则开启设置模式
284 _WIFI_SettingMode = true;
286}
287
288//!main loop
291 {
292 }
293 //Check that there is no facility to send requests to the M5StickC Web server over the network.
294 WIFI_webServer.handleClient();
295}
296
297//!starts the web server
298//!Open the web service. 打开Web服务
300{
301 SerialDebug.println("wifi_apModule.WIFI_startWebServer");
302
303 //! 8.10.26 Turning OFF BLE client
304 SerialDebug.println(" *** Turning OFF BLE_Client ****");
306
307
308 //If the setting mode is on. 如果设置模式处于开启状态
310 {
316
319
320 //CREATE TOPIC HERE
321#ifdef SPRINTF_WORKS //NOTE: it should work as it's used all over the place..
322 sprintf(_WIFI_mqttTopic, "usersP/bark/%s", _WIFI_mqttUser);
323#else
324 _WIFI_mqttTopic = "usersP/bark/" + _WIFI_mqttUser;
325
326 // strcpy(_WIFI_mqttTopic,"usersP/bark/");
327 // strcat(_WIFI_mqttTopic, &_WIFI_mqttUser[0]);
328#endif
329 SerialDebug.print("Visit Web Server: \n");
330
331 //Output AP address (you can change the address you want through _WIFIapIP at the beginning). 输出AP地址(可通过开头的_WIFIapIP更改自己想要的地址)
332 SerialDebug.print(WiFi.softAPIP());
333
334#pragma mark ANDROID WEB TEST
335 //! 8.18.16 some mroe to test WIFI not working on Android
336 //! @see https://github.com/konacurrents/ESP_IOT/issues/455#issuecomment-5320075972
337#define ANDROID_WEB_TEST
338#ifdef ANDROID_WEB_TEST
339 WIFI_webServer.on("/generate_204",[]() {
340 WIFI_webServer.send(204, "text/plain", "");
341 });
342 WIFI_webServer.on("/gen_204", [](){
343 WIFI_webServer.send(204, "text/plain", "");
344 });
345 WIFI_webServer.on("/hotspot-detect.html",[]() {
346 WIFI_webServer.send(200, "text/html",
347 "<TITLE>Success</TITLE>Success");
348 });
349 WIFI_webServer.on("/connecttest.txt",[]() {
350 WIFI_webServer.send(200, "text/plain", "Microsoft Connect Test");
351 });
352 WIFI_webServer.on("/ncsi.txt", [](){
353 WIFI_webServer.send(200, "text/plain", "Microsoft NCSI");
354 });
355#endif
356
357 /********* ROOT == notFound *****************/
358 WIFI_webServer.onNotFound([]() {
359 SerialDebug.println("WIFI_webServer.onNotFound");
360
361#ifdef DONT_USE_BASE_ADDRESS
362 // String s = "<meta HTTP-EQUIV=\"REFRESH\" content=\"0; url=http://192.168.4.1/settings\">";
363
364 String s = "<h1>ESP is now in Access Point mode</h1><p><a href=\"/settings\">Click to update WiFi Credentials</a></p>";
365 // s += "<img src=\"https://idogwatch.com/pettutor/iDogWatch.png\" width=\"200\">";
366 // s += "<img src=\"https://idogwatch.com/pettutor/PetTutor.jpeg\" width=\"500\">";
367
368
369
370 WIFI_webServer.send(200, "text/html", WIFI_makePage("AP mode", s));
371 });
372
373 /******* /settings *******************/
374 //AP web interface settings. AP网页界面设置
375 //NOTE: the <input name=X> has to have X known later to get the value back..
376 WIFI_webServer.on("/settings", []() {
377#endif
378
379 //addToTextMessages_displayModule("AP Credentials");
380 SerialDebug.println("Creating AP Credentials web page");
381 //! get the header string
382 String s = headerImageString();
383 SerialLots.println(s);
384 //!add the javascript
385 s += getJavascriptString();
386
387#ifdef NOT_AGAIN
388 //! 8.16.26 only do this one time..
389 //!this re-calculates the WIFI list
391#endif
392
393 SerialDebug.print("settings touched, ssid_last = ");
394 SerialDebug.println(_WIFI_ssid_last);
395
396
397
398#ifdef ESP_M5_ATOM_S3
399 s += "<h1>Wi-Fi Settings for ESP-M5 ATOM S3 Device 8.18.2026</h1>";
400#elif defined(ESP_M5)
401 s += "<h1>Wi-Fi Settings for ESP-M5(M5AtomLite) Device 2026</h1>";
402#else // ESP_32
403 s += "<h1>Wi-Fi Settings for ESP-32 Device</h1>";
404#endif
405
406 s += "<p>Enter your password after selecting the visible SSID names";
407//! ##47 https://github.com/konacurrents/ESP_IOT/issues/47
408//!so referting back to this..
409#define TRY_DATA_LIST
410#ifdef TRY_DATA_LIST
411s += " (or type missing WIFI). <i>*older web browsers may not show list, and only 2.4gHz WIFI supported</i></p>";
412 s += "<button onClick=\"window.location.reload();\">Refresh to re-discover WIFI list</button> </p>";
413
414#else
415s += "<button onClick=\"window.location.reload();\">Refresh to re-discover WIFI list</button></p>";
416#endif
417
418 s += "<form method=\"get\" action=\"setap\" onsubmit=\"return validateForm()\">\n";
419 s += "<label>SSID: </label>\n";
420
421#ifdef TRY_DATA_LIST
422 s += "<input list=\"ssid\" class=\"form-control\" name=\"ssid\" id=\"ssid_val\" style=\"width:300px;\">";
423
424 s += "<datalist id=\"ssid\" >";
425 s += _WIFISSIDList; //a list that is discovered..
426 s += "</datalist>";
427#else
428 s += "<select name=\"ssid\" id=\"ssid_val\" length=\"64\" \">";
429 s += _WIFISSIDList; //a list that is discovered..
430 s += "</select>";
431#endif
432 s += "<br>SSID Last: " + _WIFI_ssid_last;
433 s += "<br>Password: <input name=\"pass\" id=\"pass\" length=64 type=\"text\" value=\"" + _WIFI_password + "\">";
434
435 //hard wire for now... TODO remove this..
436 _WIFI_mqttServer = "idogwatch.com";
437 _WIFI_mqttPort = "1883";
438
439#ifdef MQTT
440 s += "<h2>MQTT User Settings</h2>";
441 s += "MQTT user : <input name=\"mqtt_user\" id=\"mqtt_user\" length=\"64\" size=\"64\" type=\"text\" style=\"text-transform: lowercase\" value=\"" + _WIFI_mqttUser + "\">";
442 s += "<br>MQTT pass : <input name=\"mqtt_password\" id=\"mqtt_password\" length=\"64\" size=\"64\" type=\"text\" style=\"text-transform: lowercase\" value=\"" + _WIFI_mqttPassword + "\">";
443 s += "<br>MQTT guestpass: <input name=\"mqtt_guestPassword\" id=\"mqtt_guestPassword\" length=\"64\" size=\"64\" type=\"text\" style=\"text-transform: lowercase\" value=\"" + _WIFI_mqttGuestPassword + "\">";
444#ifdef SPRINTF_WORKS
445 sprintf(_WIFI_mqttTopic, "usersP/bark/%s", _WIFI_mqttUser);
446 String topic(_WIFI_mqttTopic);
447#else
448 _WIFI_mqttTopic = "usersP/bark/" + _WIFI_mqttUser;
449
450 // strcpy(_WIFI_mqttTopic,"usersP/bark/");
451 // strcat(_WIFI_mqttTopic, &_WIFI_mqttUser[0]);
452#endif
453
454 s += "<br>DeviceName : <input name=\"deviceName\" id=\"deviceName\" length=\"64\" size=\"64\" type=\"text\" value=\"" + _WIFI_deviceName + "\">";
455 s += "<br>Location in World (city,state): <input name=\"locationString\" id=\"locationString\" length=\"64\" size=\"64\" type=\"text\" value=\"" + _WIFI_locationString + "\">";
456 s += "<h2>MQTT Server Settings</h2>";
457 s += "<br>MQTT Topic : " + _WIFI_mqttTopic;
458 s += "<br>MQTT Server: <input name=\"mqtt_server\" id=\"mqtt_server\" length=\"64\" size=\"64\" type=\"text\" value=\"" + _WIFI_mqttServer + "\">";
459 s += "<br>MQTT Port : <input name=\"mqtt_port\" id=\"mqtt_port\" length=\"10\" size=\"10\" type=\"text\" value=\"" + _WIFI_mqttPort + "\">";
460#ifdef ESP_M5_too_much_for_users // 7.16.26
461 {
462 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
464 String isBLEServerStr = isBLEServer?"1":"0";
465 s += "<br><br>is BLE Server (type 1 or 0): <input name=\"isBLEServer\" id=\"isBLEServer\" length=\"1\" size=\"1\" type=\"text\" value=\"" + isBLEServerStr + "\">";
466 }
467#endif
468#endif
469 // s += "<br><input type=\"reset\">";
470 s += "<br><br><input type=\"submit\"></form>";
471 //submit will call /setap
472 // s += "<br><a href=\"http://192.168.4.1\">Restart</a>";
473
474#ifdef M5_CAPTURE_SCREEN
475 //!try to grab the screen as a BMP and post it ...
476 s += "<a href=\"capture\">capture</a>";
477#endif
478
479#ifdef TRY_FEED_FROM_AP
480 //! invokes the web server with "feed" which will be the "/feed" below
481 s += "<br><h2><a href=\"feed\">Feed your dog right now</a></h2>";
482#endif
483
484 //! 8.2.26 turn this on .. for debugging .. OR keep it on.
485#define AP_DEBUG_MODE (defined in Perferences..)
486#ifdef AP_DEBUG_MODE
487 /******** APDebug ******************/
488
489 SerialDebug.println("apDebug touched");
490
491 s += "<br><br><h1>Diagnostic Information<br>";
492 s += "<textarea rows='30' cols='100'>";
493
494 //! show some information...
495 s += "\nVERSON = " + String(VERSION);
496 // s += "WIFI_CREDENTIAL_1:" + getPreference_mainModule(PREFERENCE_WIFI_CREDENTIAL_1_SETTING) + "\n";
497
498 //! 8.16.25 MQTT
499 //! 9.16.23 some debug information
500 //! retrieve the Configuration JSON string in JSON format..
501 s += "\nConfig (minus password) = \n" + getJSONConfigString();
502 //! retrieve the WIFIInfoString
503 s += "\nLast AP reason = " + String(getPreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING));
504
505 s += "\n</textarea>";
506
507 //! empty it now.
509
510#endif
511
512
513 WIFI_webServer.send(200, "text/html", WIFI_makePage((char*)"Wi-Fi & MQTT Settings 2026", s));
514 });
515
516 /******** /setap ******************/
517 //call this when the 'submit' touched..s
518 WIFI_webServer.on("/setap", []() {
519 SerialDebug.println("WIFI_webServer.on(/setap touched");
520
521 //String ssid = removeSpaces(WIFI_urlDecode(WIFI_webServer.arg("ssid")));
522 //! as per #248 support SSID syntax (first will remove the spaces at start and end)
523 String ssid = WIFI_urlDecode(WIFI_webServer.arg("ssid"));
524
526
527 SerialDebug.print("SSID: ");
528 SerialDebug.println(ssid);
529
530 //! Issue #305 don't remove spaces...
531 //String pass = removeSpaces(WIFI_urlDecode(WIFI_webServer.arg("pass")));
532 String pass = WIFI_urlDecode(WIFI_webServer.arg("pass"));
533
534#ifdef MQTT
540
542 //strip spaces
544 _WIFI_locationString = WIFI_urlDecode(WIFI_webServer.arg("locationString"));
545 //CREATE TOPIC HERE
546#ifdef SPRINTF_WORKS
547 sprintf(_WIFI_mqttTopic, "usersP/bark/%s", _WIFI_mqttUser);
548#else
549 _WIFI_mqttTopic = "usersP/bark/" + _WIFI_mqttUser;
550
551#endif
552#ifdef ESP_M5
553 //! 9.18.26
554 //! For now, will force this ON
555#define FORCE_ON
556#ifdef FORCE_ON
557 SerialDebug.printf("Setting isBLEServerFlag = ON\n");
559#else
560 {
561 String isBLEServerString = removeSpaces(WIFI_urlDecode(WIFI_webServer.arg("isBLEServer")));
562 boolean isBLEServerFlag = isBLEServerString.compareTo("1")==0;
563 SerialDebug.printf("Setting isBLEServerFlag = %d\n", isBLEServerFlag);
565
566 }
567#endif
568
569#endif
570
571 SerialDebug.print("mqtt_server = "); SerialDebug.print(_WIFI_mqttServer?_WIFI_mqttServer:"NULL");
572 SerialDebug.print(":");SerialDebug.println(_WIFI_mqttPort);
573 SerialDebug.print("mqtt_user = "); SerialDebug.println(_WIFI_mqttUser?_WIFI_mqttUser:"NULL");
574 SerialDebug.print("mqtt_password = "); SerialDebug.println(_WIFI_mqttPassword?_WIFI_mqttPassword:"NULL");
575 SerialDebug.print("mqtt_guestPassword = "); SerialDebug.println(_WIFI_mqttGuestPassword?_WIFI_mqttGuestPassword:"NULL");
576
577 SerialDebug.print("deviceName = "); SerialDebug.println(_WIFI_deviceName?_WIFI_deviceName:"NULL");
578 SerialDebug.print("mqtt_topic = "); SerialDebug.println(_WIFI_mqttTopic?_WIFI_mqttTopic:"NULL");
579 SerialDebug.print("location = "); SerialDebug.println(_WIFI_locationString?_WIFI_locationString:"NULL");
580
581#endif
582
583 SerialDebug.println(" **** Writing out SSID .. ");
584 _WIFIPreferences.putString(WIFI_SSID, ssid?ssid:"");
585 _WIFIPreferences.putString(WIFI_PASSWORD, pass?pass:"");
586
587 //last ssid as well
588 _WIFIPreferences.putString(WIFI_SSID_LAST, ssid?ssid:"");
589
590#ifdef MQTT
596
600
601#endif
602 DynamicJsonDocument myObject(1024);
603 myObject["ssid"] = ssid;
604 myObject["ssidPassword"] = pass;
605 myObject["mqtt_server"] = _WIFI_mqttServer;
606 myObject["mqtt_port"] = _WIFI_mqttPort;;
607 myObject["mqtt_user"] = _WIFI_mqttUser;
608 myObject["mqtt_password"] = _WIFI_mqttPassword;
609 myObject["mqtt_guestPassword"] = _WIFI_mqttGuestPassword;
610
611 myObject["mqtt_topic"] = _WIFI_mqttTopic;
612 myObject["deviceName"] = _WIFI_deviceName;
613 myObject["location"] = _WIFI_locationString;
614
615 serializeJson(myObject, _jsonOutputString);
616
617 SerialDebug.print("JSON = ");
618 SerialDebug.println(_jsonOutputString);
619 // Store wifi config. 存储wifi配置信息
620 SerialDebug.println("Write to WIFI_AP_Module.eprom done!");
621
622 //now let the other code work..
624
625 String s = headerImageString();
626 s += "<h1>Credential Setup Complete.</h1><ol><li>Reconnect to your favorite WIFI\n<li>Then to access device commands, click: ";
627 s += "<a href=\"https://idogwatch.com/bot/userpage2/"+ _WIFI_mqttUser + "/" + _WIFI_mqttPassword + "\">Feeding User Page</a></ol>";
628 s += "<br><a href=\"http://192.168.4.1\">Restart Credentials (after connecting to PetTutorSetup_192_168_4_1)</a>";
629 WIFI_webServer.send(200, "text/html", WIFI_makePage("iDogWatch Page", s));
630 //delay(2000);
631 //delay(200); //??
632 delay(10);
633
634 });
635#ifdef M5_CAPTURE_SCREEN
636 /******** /capture ******************/
637 WIFI_webServer.on("/capture", []() {
638
639 SerialDebug.println("capture touched");
640 WiFiClient _WIFIClient = WIFI_webServer.client();
641
642 //!The WIFI client
643
644 _WIFIClient.println("HTTP/1.1 200 OK");
645 _WIFIClient.println("Content-type:image/bmp");
646 _WIFIClient.println();
647 M5Screen2bmp(_WIFIClient);
648 _WIFIClient.println();
649 // _WIFIClient.stop();
650
651 });
652#endif
653
654
655#ifdef TRY_FEED_FROM_AP
656 /******** /feed ******************/
657 WIFI_webServer.on("/feed", []() {
658
659 SerialDebug.println("WIFI_webServer.on(/feed - feed touched");
660 //!send a feed command 's'
662
663 //shows that we clicked the button... (vs waiting for another to show it..)
664 showText_mainModule("FEED..");
665
666 String s = headerImageString();
667 s += "<h1>Your dog was just feed via local WIFI without bluetooth";
668 s += "<br><br><a href=\"/feed\">Feed Again</a>";
669 s += "<br><br><a href=\"/setup\">Return to Setup Credentials</a>";
670
671 WIFI_webServer.send(200, "text/html", WIFI_makePage("iDogWatch Page", s));
672 //delay(2000);
673 delay(200); //??
674
675 });
676#endif
677 }
678
679 //Start web service. 开启web服务
680 WIFI_webServer.begin();
681}
682
683//!print the WIFIlist .. scanning each time..
685{
686 int n = WiFi.scanNetworks();
687 delay(100);
688 SerialTemp.println(" *** WIFI LIST: ");
689#ifdef AP_DEBUG_MODE
690 //!try debug
692
693#endif
694 _WIFISSIDList = "";
695 //Save each wifi name scanned to ssidList. 将扫描到的每个wifi名称保存到ssidList中
696 for (int i = 0; i < n; i++) {
697 SerialTemp.print("SSID: ");
698 SerialTemp.print(WiFi.SSID(i));
699#ifdef AP_DEBUG_MODE
700 //!try debug
702#endif
703
704 SerialTemp.print(" Signal: ");
705 SerialTemp.print(WiFi.RSSI(i));
706 SerialTemp.print(" dBm, channel: ");
707 SerialTemp.println(WiFi.channel(i));
708
709 _WIFISSIDList += "<option value=\"";
710 _WIFISSIDList += WiFi.SSID(i);
711 _WIFISSIDList += "\"";
712#ifndef TRY_DATA_LIST
713 if(_WIFI_ssid_last.compareTo(WiFi.SSID(i)) == 0)
714 {
715 _WIFISSIDList += " selected";
716 }
717#endif
718 _WIFISSIDList += ">";
719 _WIFISSIDList += WiFi.SSID(i);
720 _WIFISSIDList += "</option>";
721 }
722#ifdef AP_DEBUG_MODE
723 //!try debug\
725#endif
726}
727
728//!Setup the WIFI access point
730 SerialDebug.println("wifi_apModule.WIFI_setupMode");
731
732 //Set Wi-Fi mode to WIFI_MODE_STA. 设置Wi-Fi模式为WIFI_MODE_STA
733 //WiFi.mode(WIFI_MODE_STA);
734 WiFi.mode(WIFI_MODE_APSTA); // AP + STA so a later scan cannot kill the AP
735
736
737 //Disconnect wifi connection. 断开wifi连接
738 WiFi.disconnect();
739 //delay(100);
740
741 //!@see https://stackoverflow.com/questions/59500095/esp32-as-wifi-access-point-crashes-on-connection
742 //!others with issue
743
744 //delay(2000);
745 delay(200);
746
747 SerialTemp.print("_WIFIapIP ");
748 SerialTemp.println(_WIFIapIP);
749
750 //Set WiFi to soft-AP mode. 设置WiFi为soft-AP模式
751
752 //create an access point
753 WiFi.softAPConfig(_WIFIapIP, _WIFIapIP, IPAddress(255, 255, 255, 0));
754
755 //Turn on Ap mode. 开启Ap模式
756 //WiFi.softAP(_apSSID);
757 //! 8.8.26 not working with Android, try a passord
758 //! 9.7.26 try withoiut password as those on() methods hopefully were the AP fix for android
759 boolean usePassword = false;
760 SerialDebug.printf(" ****** AP MODE %s 'password' ****\n", usePassword?"with":"with OUT");
761 /*
762 bool softAP(
763 const char *ssid, const char *passphrase = NULL, int channel = 1, int ssid_hidden = 0, int max_connection = 4, bool ftm_responder = false,
764 wifi_auth_mode_t auth_mode = WIFI_AP_DEFAULT_AUTH_MODE, wifi_cipher_type_t cipher = WIFI_AP_DEFAULT_CIPHER
765 );
766
767 */
768
769 if (usePassword)
770 {
771 //! add the password
772 WiFi.softAP(_apSSID, "password");
773 }
774 else
775 {
776 WiFi.softAP(_apSSID);
777 }
778 //Set WiFi to soft-AP mode. 设置WiFi为soft-AP模式
779 //WiFi.mode(WIFI_MODE_AP);
780 // Do NOT call WiFi.mode() again after softAP().
781
782 rediscoverWIFIList(); // scan once now, cache the SSID list
783
784 //Open the web service. 打开Web服务
786
788
789 SerialDebug.printf("\nStarting Access Point at \n\"%s\"\n", _apSSID);
790
791}
792
793//!makes a webpage with the title, and contents, already in HTML
794String WIFI_makePage(String title, String contents) {
795
796 SerialDebug.print("WIFI_makePage:");
797 SerialDebug.println(title);
798 SerialTemp.printf("1.Length = %d\n", contents.length());
799
800 String s = "<!DOCTYPE html><html><head>";
801 s += "<meta name=\"viewport\" content=\"width=device-width,user-scalable=0\">";
802
803 s += "<title>";
804 s += title;
805 s += "</title></head><body>";
806 s += contents;
807 s += "</body></html>";
808 SerialLots.println(s);
809 SerialTemp.printf("2.Length = %d\n", s.length());
810 //! see what's up..
811 if (s.length() < contents.length())
812 {
813 SerialError.println(" ***** Length shrunk .. bad C++ string concat **");
814 s = "ERROR RENDERING WEB PAGE .. please try again and also let developers know";
815 }
816
817 return s;
818}
819
820//!Decode the URL
821String WIFI_urlDecode(String input) {
822 String s = input;
823 s.replace("%20", " ");
824 s.replace("+", " ");
825 s.replace("%21", "!");
826 s.replace("%22", "\"");
827 s.replace("%23", "#");
828 s.replace("%24", "$");
829 s.replace("%25", "%");
830 s.replace("%26", "&");
831 s.replace("%27", "\'");
832 s.replace("%28", "(");
833 s.replace("%29", ")");
834 s.replace("%30", "*");
835 s.replace("%31", "+");
836 s.replace("%2C", ",");
837 s.replace("%2E", ".");
838 s.replace("%2F", "/");
839 s.replace("%2C", ",");
840 s.replace("%3A", ":");
841 s.replace("%3A", ";");
842 s.replace("%3C", "<");
843 s.replace("%3D", "=");
844 s.replace("%3E", ">");
845 s.replace("%3F", "?");
846 s.replace("%40", "@");
847 s.replace("%5B", "[");
848 s.replace("%5C", "\\");
849 s.replace("%5D", "]");
850 s.replace("%5E", "^");
851 s.replace("%5F", "-");
852 s.replace("%60", "`");
853 return s;
854}
855
856//!returns string for the header image. This was about the smallest image without incuring much bits in the size of the BIN file
858{
859 //#include "idogwatch.base64"
860#define DOIT_IMAGE_not_working // 7.26.26 put back .. lots of room
861#ifdef DOIT_IMAGE
862//#ifdef ESP_M5_ATOM_S3
863 //! 7.16.26 Stormy day, seems the memory (89%) and heap are full so this dynamic string is garbage ..
864 //! 8..2.26 seems to be break the s += (length big, then small .. breaks the CString concat)
865
866 String imageString = "<img width=\"200\" src=\"data:image/png;base64,";
867 imageString +=
868 "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";
869 imageString += "\">";
870
871
872 imageString += "<br>";
873#else
874 String imageString = "<br>";
875#endif
876
877 return imageString;
878
879//data:image/png;base64,iVBORWOKGgOAAAANSUhEUgAAAMgAAADICAYAAACtWK6EAA
880}
881
882//!create the javascript header to convert to lowercase, etc
884{
885 String s = "";
886
887 s += "<script type=\"text/javascript\">\n";
888
889 s += "var _validatedForm = true;\n";
890
891 s += "//!convert to lower case and strip spaces, using the valId, and setting valId if valid. if toLower==-1 then fix SSID\n";
892 s += "function checkAndConvertText(valId, msg, toLower)\n";
893 s += "{\n";
894 s += "var val = document.getElementById(valId).value;\n";
895 s += "if (!val)\n";
896 s += "{\n";
897 s += "alert(msg + \" required\");\n";
898 s += " _validatedForm = false;\n";
899 s += " return;\n";
900 s += "}\n\n";
901#define TRY_SSID_AMPER
902#ifdef TRY_SSID_AMPER
903 s += "if (toLower == -1) {\n";
904 s += " var ssidStr = val.replace(/&/g,'%26');\n";
905 s += " document.getElementById(valId).value = ssidStr;\n";
906 s += " return true; \n";
907 s += "}\n";
908#endif
909 s += "//!strip all spaces\n";
910 //NOTE: the \ in front of \s
911 s += "var str = val.replace(/\\s+/g, '');\n";
912
913 s += "if (toLower)\n";
914 s += "{\n";
915 s += "//!convert to lower case\n";
916 s += "str = str.toLowerCase();\n";
917 s += "}\n\n";
918
919 s += "document.getElementById(valId).value = str;\n";
920 s += "return true;\n";
921 s += "}\n\n";
922
923 s += "//!checks a string to make sure a number..\n";
924 s += "function checkNumber(valId, msg)\n";
925 s += "{\n";
926 s += "var num = document.getElementById(valId).value;\n";
927 s += "if (isNaN(num) || num < 1)\n";
928 s += "{\n";
929 s += "alert(msg + \": \" + num + \" must be valid number\");\n";
930 s += "_validatedForm = false;\n";
931 s += "}\n\n";
932 s += "}\n\n";
933
934
935
936
937
938
939 s += "//!v8 confirms the values the user entered\n";
940 s += "//! set _validatedForm = false if not confirmed\n";
941 s += "function confirmValues()\n";
942 s += "{\n";
943 s += " var val;\n";
944 s += " var msg = \"Please confirm values - especially Device Name\\n\";\n";
945 s += " val = document.getElementById(\"ssid_val\").value;\n";
946 s += " msg += \"WIFI SSID = '\" + val + \"'\\n\";\n";
947 s += " val = document.getElementById(\"pass\").value;\n";
948 s += " msg += \"WIFI PASS = '\" + val + \"'\\n\";\n";
949 s += " val = document.getElementById(\"mqtt_user\").value;\n";
950 s += " msg += \"MQTT USER = '\" + val + \"'\\n\";\n";
951 s += " val = document.getElementById(\"mqtt_password\").value;\n";
952 s += " msg += \"MQTT PASS = '\" + val + \"'\\n\";\n";
953 s += " val = document.getElementById(\"mqtt_guestPassword\").value;\n";
954 s += " msg += \"MQTT Guest PASS = '\" + val + \"'\\n\";\n";
955 s += " val = document.getElementById(\"deviceName\").value;\n";
956 s += " msg += \"Device Name = '\" + val + \"'\\n\";\n";
957 s += " val = document.getElementById(\"locationString\").value;\n";
958 s += " msg += \"Location in world = '\" + val + \"'\\n\";\n";
959 s += " _validatedForm = confirm(msg);\n";
960 s += "}\n\n";
961
962
963
964
965 s += "//! checks a few fields, and makes sure they are not null, and convert to lowerCase and strip spaces\n";
966 s += "function validateForm()\n";
967 s += "{\n";
968 s += "//! set default that alls good\n";
969 s += "_validatedForm = true;\n";
970 s += "var toLower = true;\n";
971 s += "var keepCase = false;\n";
972
973 s += "// These will set _validatedFrom to false if not valid\n";
974 //!issue #248 support full SSID name syntax (or at least let the user type anything.)
975 // s += "checkAndConvertText(\"ssid_val\",\"WIFI SSID\", keepCase);\n";
976#ifdef TRY_SSID_AMPER
977 s += "checkAndConvertText(\"ssid_val\",\"WIFI SSID\", -1);\n";
978
979#endif
980 s += "checkAndConvertText(\"mqtt_user\",\"MQTT User Name\", toLower);\n";
981 s += "checkAndConvertText(\"mqtt_password\",\"MQTT Password\", toLower);\n";
982 s += "checkAndConvertText(\"mqtt_guestPassword\",\"MQTT Guest Password\", toLower);\n";
983 s += "checkAndConvertText(\"deviceName\",\"Device Name\", keepCase);\n";
984
985 s += "checkAndConvertText(\"mqtt_server\",\"MQTT Server Name\", toLower);\n";
986 s += "checkNumber(\"mqtt_port\",\"MQTT Port\");\n";
987 s += "\n";
988 s += "if (_validatedForm) confirmValues();\n";
989 s += "return _validatedForm;\n";
990
991 s += "}\n\n";
992
993 s += "</script>\n";
994
995 return s;
996}
997
void addToTextMessages_displayModule(String text)
String getJSONConfigString()
retrieve the Configuration JSON string in JSON format..
void cleanMQTTpasswordsUpdateInEPROM()
9.18.23 LA (after Eagle Rock bike ride, Van Morrison tomorrow)
void processClientCommandChar_mainModule(char cmd)
single character version of processClientCommand (since many used that already)
void showText_mainModule(String text)
void savePreferenceBoolean_mainModule(int preferenceID, boolean flag)
save a boolean preference
void appendPreference_mainModule(int preferenceID, String preferenceValue)
called to append to a a preference (which will be an identifier and a string, which can be converted ...
boolean getPreferenceBoolean_mainModule(int preferenceID)
called to set a preference (which will be an identifier and a string, which can be converted to a num...
void resetPreference_mainModule(int preferenceID)
called to reset to blank a preference (which will be an identifier and a string, which can be convert...
void storePreference_mainModule(int preferenceID, String preferenceValue)
called to append to a a preference (which will be an identifier and a string, which can be converted ...
char * getPreference_mainModule(int preferenceID)
#define PREFERENCE_MAIN_BLE_SERVER_VALUE
#define PREFERENCE_DEBUG_INFO_SETTING
a place to put some kind of Last Will of what went wrong .. for now (> max tries)
#define PREFERENCE_MAIN_BLE_CLIENT_VALUE
#define MQTT_GUEST_PASSWORD
String WIFI_APModule_JsonOutputString()
retrieves the JSON string
WiFiClient _WIFIClient
client of the web server??
const char * _apSSID
String _WIFI_ssid
boolean _doneWIFI_APModuleFlag
String WIFI_urlDecode(String input)
Decode the URL.
String getJavascriptString()
create the javascript header to convert to lowercase, etc
void loop_WIFI_APModule()
main loop
void setup_WIFI_APModule()
sets the config in the EPPROM called wifi-config. NOTE: the _done isn't valid until after this code....
String _WIFI_mqttUser
#define MQTT_TOPIC
const char * _WIFIWirelessAP
#define MQTT_PASSWORD
#define WIFI_SSID
String _WIFI_mqttGuestPassword
#define MQTT_USER
const IPAddress _WIFIapIP(192, 168, 4, 1)
#define MQTT_DEVICE_NAME
void clean_SSID_WIFICredentials()
returns true if the SSID is set, false otherwise. If set, then just exit..
String _WIFISSIDList
String _WIFI_mqttPort
String _WIFI_mqttServer
void WIFI_APModule_ResetCredentials()
resets the credentials
Preferences _WIFIPreferences
wifi config store. wifi配置存储的类
void WIFI_APModule_updateMQTTInfo(char *ssid, char *ssid_password, char *username, char *password, char *guestPassword, char *deviceName, char *host, char *port, char *locationString)
sets the MQTT user/password. It's up to the code to decide who needs to know
#define WIFI_PASSWORD
boolean doneWIFI_APModule_Credentials()
called to see if the WIFIModule has finished bootstrapping..
void cleanEPROM_WIFI_APModule()
cleans the eprom info
String _WIFI_locationString
#define AP_EPROM_NAME
EPROM INFO .. might be a length issue of the attribute name.
#define MQTT_SERVER
#define MQTT_PORT
String _WIFI_password
void WIFI_startWebServer()
String _WIFI_mqttPassword
void preSetup_WIFI_APModule()
#define WIFI_SSID_LAST
boolean _WIFI_SettingMode
String removeSpaces(String input)
remove spaces in a string
void setDoneWIFI_APModuleFlag(boolean flag)
called to set the done flag
boolean isSet_SSID_WIFICredentials()
returns true if the SSID is set, false otherwise. If set, then just exit..
String _jsonOutputString
the json output string that contain the credentials
String _WIFI_ssid_last
String WIFI_makePage(String title, String contents)
makes a webpage with the title, and contents, already in HTML
void rediscoverWIFIList()
rediscover (and prints) the WIFIlist .. scanning each time.. so a page refresh will look again....
String _WIFI_deviceName
#define MQTT_LOCATION_NAME
WebServer WIFI_webServer(80)
DNSServer dnsServer;. webServer的类, port 80.
void WIFI_setupMode()
Setup the WIFI access point.
String _WIFI_mqttTopic
String headerImageString()
7.16.26 try included one.. see if fixed M5Atom AP webpage not working.. only the header