_WiFi.ino 12 KB

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