_WiFi.ino 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. // 1-channel LoRa Gateway for ESP8266
  2. // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
  3. // Version 6.1.5
  4. // Date: 2019-12-20
  5. //
  6. // based on work done by Thomas Telkamp for Raspberry PI 1ch gateway
  7. // and many others.
  8. //
  9. // All rights reserved. This program and the accompanying materials
  10. // are made available under the terms of the MIT License
  11. // which accompanies this distribution, and is available at
  12. // https://opensource.org/licenses/mit-license.php
  13. //
  14. // NO WARRANTY OF ANY KIND IS PROVIDED
  15. //
  16. // Author: Maarten Westenberg (mw12554@hotmail.com)
  17. //
  18. // This file contains the LoRa filesystem specific code
  19. // ----------------------------------------------------------------------------
  20. // WLANSTATUS prints the status of the Wlan.
  21. // The status of the Wlan "connection" can change if we have no relation
  22. // with the well known router anymore. Normally this relation is preserved
  23. // but sometimes we have to reconfirm to the router again and we get the same
  24. // address too.
  25. // So, if the router is still in range we can "survive" with the same address
  26. // and we may have to renew the "connection" from time to time.
  27. // But when we loose the SSID connection, we may have to look for another router.
  28. //
  29. // Parameters: <none>
  30. // Return value: Returns 1 when still WL_CONNETED, otherwise returns 0
  31. // ----------------------------------------------------------------------------
  32. int WlanStatus() {
  33. switch (WiFi.status()) {
  34. case WL_CONNECTED:
  35. # if _MONITOR>=1
  36. if ( debug>=1 ) {
  37. mPrint("A WlanStatus:: CONNECTED to " + String(WiFi.SSID())); // 3
  38. }
  39. # endif //_MONITOR
  40. WiFi.setAutoReconnect(true); // Reconect to this AP if DISCONNECTED
  41. return(1);
  42. break;
  43. // In case we get disconnected from the AP we loose the IP address.
  44. // The ESP is configured to reconnect to the last router in memory.
  45. case WL_DISCONNECTED:
  46. # if _MONITOR>=1
  47. if ( debug>=0 ) {
  48. mPrint("A WlanStatus:: DISCONNECTED, IP=" + String(WiFi.localIP().toString())); // 6
  49. }
  50. # endif
  51. //while (! WiFi.isConnected() ) {
  52. // Wait
  53. delay(1);
  54. //}
  55. return(0);
  56. break;
  57. // When still pocessing
  58. case WL_IDLE_STATUS:
  59. # if _MONITOR>=1
  60. if ( debug>=0 ) {
  61. mPrint("A WlanStatus:: IDLE"); // 0
  62. }
  63. # endif //_MONITOR
  64. break;
  65. // This code is generated as soonas the AP is out of range
  66. // Whene detected, the program will search for a better AP in range
  67. case WL_NO_SSID_AVAIL:
  68. # if _MONITOR>=1
  69. if ( debug>=0 )
  70. mPrint("WlanStatus:: NO SSID"); // 1
  71. # endif //_MONITOR
  72. break;
  73. case WL_CONNECT_FAILED:
  74. # if _MONITOR>=1
  75. if ( debug>=0 )
  76. mPrint("A WlanStatus:: FAILED"); // 4
  77. # endif //_MONITOR
  78. break;
  79. // Never seen this code
  80. case WL_SCAN_COMPLETED:
  81. # if _MONITOR>=1
  82. if ( debug>=0 )
  83. mPrint("A WlanStatus:: SCAN COMPLETE"); // 2
  84. # endif //_MONITOR
  85. break;
  86. // Never seen this code
  87. case WL_CONNECTION_LOST:
  88. # if _MONITOR>=1
  89. if ( debug>=0 )
  90. mPrint("A WlanStatus:: Connection LOST"); // 5
  91. # endif //_MONITOR
  92. break;
  93. // This code is generated for example when WiFi.begin() has not been called
  94. // before accessing WiFi functions
  95. case WL_NO_SHIELD:
  96. # if _MONITOR>=1
  97. if ( debug>=0 )
  98. Serial.println(F("A WlanStatus:: WL_NO_SHIELD")); //
  99. # endif //_MONITOR
  100. break;
  101. default:
  102. # if _MONITOR>=1
  103. if ( debug>=0 ) {
  104. mPrint("A WlanStatus Error:: code=" + String(WiFi.status())); // 255 means ERROR
  105. }
  106. # endif //_MONITOR
  107. break;
  108. }
  109. return(-1);
  110. } // WlanStatus
  111. // ----------------------------------------------------------------------------
  112. // config.txt is a text file that contains lines(!) with WPA configuration items
  113. // Each line contains an KEY vaue pair describing the gateway configuration
  114. //
  115. // ----------------------------------------------------------------------------
  116. int WlanReadWpa() {
  117. readConfig(CONFIGFILE, &gwayConfig);
  118. if (gwayConfig.sf != (uint8_t) 0) sf = (sf_t) gwayConfig.sf;
  119. ifreq = gwayConfig.ch;
  120. debug = gwayConfig.debug;
  121. pdebug = gwayConfig.pdebug;
  122. _cad = gwayConfig.cad;
  123. _hop = gwayConfig.hop;
  124. gwayConfig.boots++; // Every boot of the system we increase the reset
  125. #if GATEWAYNODE==1
  126. if (gwayConfig.fcnt != (uint8_t) 0) frameCount = gwayConfig.fcnt+10;
  127. #endif
  128. #if _WIFIMANAGER==1
  129. String ssid=gwayConfig.ssid;
  130. String pass=gwayConfig.pass;
  131. char ssidBuf[ssid.length()+1];
  132. ssid.toCharArray(ssidBuf,ssid.length()+1);
  133. char passBuf[pass.length()+1];
  134. pass.toCharArray(passBuf,pass.length()+1);
  135. Serial.print(F("WlanReadWpa: ")); Serial.print(ssidBuf); Serial.print(F(", ")); Serial.println(passBuf);
  136. strcpy(wpa[0].login, ssidBuf); // XXX changed from wpa[0][0] = ssidBuf
  137. strcpy(wpa[0].passw, passBuf);
  138. Serial.print(F("WlanReadWpa: <"));
  139. Serial.print(wpa[0].login); // XXX
  140. Serial.print(F(">, <"));
  141. Serial.print(wpa[0].passw);
  142. Serial.println(F(">"));
  143. #endif
  144. }
  145. // ----------------------------------------------------------------------------
  146. // Print the WPA data of last WiFiManager to the config file
  147. // ----------------------------------------------------------------------------
  148. #if _WIFIMANAGER==1
  149. int WlanWriteWpa( char* ssid, char *pass) {
  150. # if _MONITOR>=1
  151. if (( debug >=0 ) && ( pdebug & P_MAIN )) {
  152. mPrint("WlanWriteWpa:: ssid="+mPrint(ssid)+", pass="+mPrint(pass));
  153. }
  154. # endif //_MONITOR
  155. // Version 3.3 use of config file
  156. String s((char *) ssid);
  157. gwayConfig.ssid = s;
  158. String p((char *) pass);
  159. gwayConfig.pass = p;
  160. # if GATEWAYNODE==1
  161. gwayConfig.fcnt = frameCount;
  162. # endif
  163. gwayConfig.ch = ifreq;
  164. gwayConfig.sf = sf;
  165. gwayConfig.cad = _cad;
  166. gwayConfig.hop = _hop;
  167. writeConfig( CONFIGFILE, &gwayConfig);
  168. return 1;
  169. }
  170. #endif
  171. // ----------------------------------------------------------------------------
  172. // Function to join the Wifi Network
  173. // It is a matter of returning to the main loop() asap and make sure in next loop
  174. // the reconnect is done first thing. By default the system will reconnect to the
  175. // samen SSID as it was connected to before.
  176. // Parameters:
  177. // int maxTry: Number of retries we do:
  178. // 0: Used during Setup first CONNECT
  179. // 1: Try once and if unsuccessful return(1);
  180. // x: Try x times
  181. //
  182. // Returns:
  183. // On failure: Return -1
  184. // On connect: return 1
  185. // On Disconnect state: return 0
  186. //
  187. // XXX After a few retries, the ESP8266 should be reset. Note: Switching between
  188. // two SSID's does the trick. Rettrying the same SSID does not.
  189. // Workaround is found below: Let the ESP8266 forget the SSID
  190. //
  191. // NOTE: The Serial works only on debug setting and not on pdebug. This is
  192. // because WiFi problems would make webserver (which works on WiFi) useless.
  193. // ----------------------------------------------------------------------------
  194. int WlanConnect(int maxTry) {
  195. #if _WIFIMANAGER==1
  196. WiFiManager wifiManager;
  197. #endif
  198. unsigned char agains = 0;
  199. unsigned char wpa_index = (_WIFIMANAGER >0 ? 0 : 1); // Skip over first record for WiFiManager
  200. // The initial setup() call is done with parameter 0
  201. // We clear the WiFi memory and start with previous AP.
  202. //
  203. if (maxTry==0) {
  204. # if _MONITOR>=1
  205. mPrint("WlanConnect:: Init para 0");
  206. # endif //_MONITOR
  207. WiFi.persistent(false);
  208. WiFi.mode(WIFI_OFF); // this is a temporary line, to be removed after SDK update to 1.5.4
  209. if (gwayConfig.ssid.length() >0) {
  210. WiFi.begin(gwayConfig.ssid.c_str(), gwayConfig.pass.c_str());
  211. delay(100);
  212. }
  213. }
  214. // So try to connect to WLAN as long as we are not connected.
  215. // The try parameters tells us how many times we try before giving up
  216. // Value 0 is reserved for setup() first time connect
  217. int i=0;
  218. while ( (WiFi.status() != WL_CONNECTED) && ( i<= maxTry ) )
  219. {
  220. // We try every SSID in wpa array until success
  221. for (int j=wpa_index; (j< (sizeof(wpa)/sizeof(wpa[0]))) && (WiFi.status() != WL_CONNECTED ); j++)
  222. {
  223. // Start with well-known access points in the list
  224. char *ssid = wpa[j].login;
  225. char *password = wpa[j].passw;
  226. #if _DUSB>=1
  227. if (debug>=0) {
  228. Serial.print(i);
  229. Serial.print(':');
  230. Serial.print(j);
  231. Serial.print(':');
  232. Serial.print(sizeof(wpa)/sizeof(wpa[0]));
  233. Serial.print(F(". WiFi connect SSID="));
  234. Serial.print(ssid);
  235. if ( debug>=1 ) {
  236. Serial.print(F(", pass="));
  237. Serial.print(password);
  238. }
  239. Serial.println();
  240. }
  241. #endif
  242. // Count the number of times we call WiFi.begin
  243. gwayConfig.wifis++;
  244. WiFi.mode(WIFI_STA);
  245. delay(1000);
  246. WiFi.begin(ssid, password);
  247. delay(8000);
  248. // Check the connection status again, return values
  249. // 1 = CONNECTED
  250. // 0 = DISCONNECTED (will reconnect)
  251. // -1 = No SSID or other cause
  252. int stat = WlanStatus();
  253. if ( stat == 1) {
  254. writeGwayCfg(CONFIGFILE); // Write configuration to SPIFFS
  255. return(1);
  256. }
  257. // We increase the time for connect but try the same SSID
  258. // We try for 10 times
  259. agains=1;
  260. while (((WiFi.status()) != WL_CONNECTED) && (agains < 10)) {
  261. agains++;
  262. delay(agains*500);
  263. # if _DUSB>=1
  264. if ( debug>=0 ) {
  265. Serial.print(".");
  266. }
  267. # endif //_DUSB
  268. }
  269. # if _DUSB>=1
  270. Serial.println();
  271. # endif //_DUSB
  272. //if ( WiFi.status() == WL_DISCONNECTED) return(0); // 180811 removed
  273. // Make sure that we can connect to different AP's than 1
  274. // this is a patch. Normally we connect to previous one.
  275. WiFi.persistent(false);
  276. WiFi.mode(WIFI_OFF); // this is a temporary line, to be removed after SDK update to 1.5.4
  277. } //for next WPA defined AP
  278. i++; // Number of times we try to connect
  279. } //while
  280. // If we are not connected to a well known AP
  281. // we can invoike _WIFIMANAGER or else return unsuccessful.
  282. if (WiFi.status() != WL_CONNECTED) {
  283. #if _WIFIMANAGER==1
  284. # if _MONITOR>=1
  285. if (debug>=1) {
  286. mPrint("Starting Access Point Mode"));
  287. mPrint("Connect Wifi to accesspoint: "+mPrint(AP_NAME)+" and connect to IP: 192.168.4.1");
  288. }
  289. # endif //_MONITOR
  290. wifiManager.autoConnect(AP_NAME, AP_PASSWD );
  291. //wifiManager.startConfigPortal(AP_NAME, AP_PASSWD );
  292. // At this point, there IS a Wifi Access Point found and connected
  293. // We must connect to the local SPIFFS storage to store the access point
  294. //String s = WiFi.SSID();
  295. //char ssidBuf[s.length()+1];
  296. //s.toCharArray(ssidBuf,s.length()+1);
  297. // Now look for the password
  298. struct station_config sta_conf;
  299. wifi_station_get_config(&sta_conf);
  300. //WlanWriteWpa(ssidBuf, (char *)sta_conf.password);
  301. WlanWriteWpa((char *)sta_conf.ssid, (char *)sta_conf.password);
  302. #else
  303. # if _MONITOR>=1
  304. if (debug>=0) {
  305. mPrint("WlanConnect:: Not connected, WLAN retry="+String(i)+", stat="+String(WiFi.status()) );
  306. }
  307. # endif // _MONITOR
  308. return(-1);
  309. #endif
  310. }
  311. yield();
  312. return(1);
  313. }
  314. // ----------------------------------------------------------------------------
  315. // resolveHost
  316. // This function will use MDNS or DNS to resolve a hostname.
  317. // So it may be .local or a normal hostname.
  318. // Return:
  319. // svrIP: 4 byte IP address of machine resolved
  320. // ----------------------------------------------------------------------------
  321. IPAddress resolveHost(String svrName)
  322. {
  323. IPAddress svrIP;
  324. # if _MONITOR>=1
  325. mPrint("Server " + String(svrName));
  326. # endif
  327. if (svrName.endsWith(".local")) {
  328. # if ESP32_ARCH==1
  329. svrName=svrName.substring(0,svrName.length()-6);
  330. svrIP = MDNS.queryHost(svrName);
  331. for (byte i=0; i<5; i++) { // Try 5 times MDNS
  332. svrIP = MDNS.queryHost(svrName);
  333. if (svrIP.toString() != "0.0.0.0") break;
  334. # if (_MONITOR>=1)
  335. mPrint("ReTrying to resolve with mDNS");
  336. # endif
  337. delay(1000);
  338. }
  339. # else
  340. char cc[svrName.length() +1 ];
  341. strcpy(cc, svrName.c_str());
  342. if (!WiFi.hostByName(cc, svrIP)) // Use DNS to get server IP once
  343. {
  344. die("resolveHost:: ERROR hostByName="+ String(cc));
  345. };
  346. # endif
  347. }
  348. else
  349. {
  350. char cc[svrName.length() +1 ];
  351. strcpy(cc, svrName.c_str());
  352. if (!WiFi.hostByName(cc, svrIP)) // Use DNS to get server IP once
  353. {
  354. die("resolveHost:: ERROR hostByName="+ String(cc));
  355. };
  356. }
  357. return svrIP;
  358. }