support_wifi.ino 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. /*
  2. support_wifi.ino - wifi support for Sonoff-Tasmota
  3. Copyright (C) 2018 Theo Arends
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. /*********************************************************************************************\
  16. * Wifi
  17. \*********************************************************************************************/
  18. #ifndef WIFI_RSSI_THRESHOLD
  19. #define WIFI_RSSI_THRESHOLD 10 // Difference in dB between current network and scanned network
  20. #endif
  21. #ifndef WIFI_RESCAN_MINUTES
  22. #define WIFI_RESCAN_MINUTES 44 // Number of minutes between wifi network rescan
  23. #endif
  24. #define WIFI_CONFIG_SEC 180 // seconds before restart
  25. #define WIFI_CHECK_SEC 20 // seconds
  26. #define WIFI_RETRY_OFFSET_SEC 20 // seconds
  27. #include <ESP8266WiFi.h> // Wifi, MQTT, Ota, WifiManager
  28. uint8_t wifi_counter;
  29. uint8_t wifi_retry_init;
  30. uint8_t wifi_retry;
  31. uint8_t wifi_status;
  32. uint8_t wps_result;
  33. uint8_t wifi_config_type = 0;
  34. uint8_t wifi_config_counter = 0;
  35. uint8_t wifi_scan_state;
  36. uint8_t wifi_bssid[6];
  37. int WifiGetRssiAsQuality(int rssi)
  38. {
  39. int quality = 0;
  40. if (rssi <= -100) {
  41. quality = 0;
  42. } else if (rssi >= -50) {
  43. quality = 100;
  44. } else {
  45. quality = 2 * (rssi + 100);
  46. }
  47. return quality;
  48. }
  49. boolean WifiConfigCounter(void)
  50. {
  51. if (wifi_config_counter) {
  52. wifi_config_counter = WIFI_CONFIG_SEC;
  53. }
  54. return (wifi_config_counter);
  55. }
  56. extern "C" {
  57. #include "user_interface.h"
  58. }
  59. void WifiWpsStatusCallback(wps_cb_status status);
  60. void WifiWpsStatusCallback(wps_cb_status status)
  61. {
  62. /* from user_interface.h:
  63. enum wps_cb_status {
  64. WPS_CB_ST_SUCCESS = 0,
  65. WPS_CB_ST_FAILED,
  66. WPS_CB_ST_TIMEOUT,
  67. WPS_CB_ST_WEP, // WPS failed because that WEP is not supported
  68. WPS_CB_ST_SCAN_ERR, // can not find the target WPS AP
  69. };
  70. */
  71. wps_result = status;
  72. if (WPS_CB_ST_SUCCESS == wps_result) {
  73. wifi_wps_disable();
  74. } else {
  75. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_WPS_FAILED_WITH_STATUS " %d"), wps_result);
  76. AddLog(LOG_LEVEL_DEBUG);
  77. wifi_config_counter = 2;
  78. }
  79. }
  80. boolean WifiWpsConfigDone(void)
  81. {
  82. return (!wps_result);
  83. }
  84. boolean WifiWpsConfigBegin(void)
  85. {
  86. wps_result = 99;
  87. if (!wifi_wps_disable()) { return false; }
  88. if (!wifi_wps_enable(WPS_TYPE_PBC)) { return false; } // so far only WPS_TYPE_PBC is supported (SDK 2.0.0)
  89. if (!wifi_set_wps_cb((wps_st_cb_t) &WifiWpsStatusCallback)) { return false; }
  90. if (!wifi_wps_start()) { return false; }
  91. return true;
  92. }
  93. void WifiConfig(uint8_t type)
  94. {
  95. if (!wifi_config_type) {
  96. if ((WIFI_RETRY == type) || (WIFI_WAIT == type)) { return; }
  97. #if defined(USE_WEBSERVER) && defined(USE_EMULATION)
  98. UdpDisconnect();
  99. #endif // USE_EMULATION
  100. WiFi.disconnect(); // Solve possible Wifi hangs
  101. wifi_config_type = type;
  102. #ifndef USE_WPS
  103. if (WIFI_WPSCONFIG == wifi_config_type) { wifi_config_type = WIFI_MANAGER; }
  104. #endif // USE_WPS
  105. #ifndef USE_WEBSERVER
  106. if (WIFI_MANAGER == wifi_config_type) { wifi_config_type = WIFI_SMARTCONFIG; }
  107. #endif // USE_WEBSERVER
  108. #ifndef USE_SMARTCONFIG
  109. if (WIFI_SMARTCONFIG == wifi_config_type) { wifi_config_type = WIFI_SERIAL; }
  110. #endif // USE_SMARTCONFIG
  111. wifi_config_counter = WIFI_CONFIG_SEC; // Allow up to WIFI_CONFIG_SECS seconds for phone to provide ssid/pswd
  112. wifi_counter = wifi_config_counter +5;
  113. blinks = 1999;
  114. if (WIFI_RESTART == wifi_config_type) {
  115. restart_flag = 2;
  116. }
  117. else if (WIFI_SERIAL == wifi_config_type) {
  118. AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_6_SERIAL " " D_ACTIVE_FOR_3_MINUTES));
  119. }
  120. #ifdef USE_SMARTCONFIG
  121. else if (WIFI_SMARTCONFIG == wifi_config_type) {
  122. AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_1_SMARTCONFIG " " D_ACTIVE_FOR_3_MINUTES));
  123. WiFi.beginSmartConfig();
  124. }
  125. #endif // USE_SMARTCONFIG
  126. #ifdef USE_WPS
  127. else if (WIFI_WPSCONFIG == wifi_config_type) {
  128. if (WifiWpsConfigBegin()) {
  129. AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_3_WPSCONFIG " " D_ACTIVE_FOR_3_MINUTES));
  130. } else {
  131. AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_3_WPSCONFIG " " D_FAILED_TO_START));
  132. wifi_config_counter = 3;
  133. }
  134. }
  135. #endif // USE_WPS
  136. #ifdef USE_WEBSERVER
  137. else if (WIFI_MANAGER == wifi_config_type) {
  138. AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_2_WIFIMANAGER " " D_ACTIVE_FOR_3_MINUTES));
  139. WifiManagerBegin();
  140. }
  141. #endif // USE_WEBSERVER
  142. }
  143. }
  144. void WiFiSetSleepMode(void)
  145. {
  146. /* Excerpt from the esp8266 non os sdk api reference (v2.2.1):
  147. * Sets sleep type for power saving. Set WIFI_NONE_SLEEP to disable power saving.
  148. * - Default mode: WIFI_MODEM_SLEEP.
  149. * - In order to lower the power comsumption, ESP8266 changes the TCP timer
  150. * tick from 250ms to 3s in WIFI_LIGHT_SLEEP mode, which leads to increased timeout for
  151. * TCP timer. Therefore, the WIFI_MODEM_SLEEP or deep-sleep mode should be used
  152. * where there is a requirement for the accurancy of the TCP timer.
  153. *
  154. * Sleep is disabled in core 2.4.1 and 2.4.2 as there are bugs in their SDKs
  155. * See https://github.com/arendst/Sonoff-Tasmota/issues/2559
  156. */
  157. // Sleep explanation: https://github.com/esp8266/Arduino/blob/3f0c601cfe81439ce17e9bd5d28994a7ed144482/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp#L255
  158. #if defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2)
  159. #else // Enabled in 2.3.0, 2.4.0 and stage
  160. if (sleep && Settings.flag3.sleep_normal) {
  161. WiFi.setSleepMode(WIFI_LIGHT_SLEEP); // Allow light sleep during idle times
  162. } else {
  163. WiFi.setSleepMode(WIFI_MODEM_SLEEP); // Disable sleep (Esp8288/Arduino core and sdk default)
  164. }
  165. #endif
  166. }
  167. void WifiBegin(uint8_t flag, uint8_t channel)
  168. {
  169. const char kWifiPhyMode[] = " BGN";
  170. #if defined(USE_WEBSERVER) && defined(USE_EMULATION)
  171. UdpDisconnect();
  172. #endif // USE_EMULATION
  173. #ifdef ARDUINO_ESP8266_RELEASE_2_3_0 // (!strncmp_P(ESP.getSdkVersion(),PSTR("1.5.3"),5))
  174. AddLog_P(LOG_LEVEL_DEBUG, S_LOG_WIFI, PSTR(D_PATCH_ISSUE_2186));
  175. WiFi.mode(WIFI_OFF); // See https://github.com/esp8266/Arduino/issues/2186
  176. #endif
  177. WiFi.persistent(false); // Solve possible wifi init errors (re-add at 6.2.1.16 #4044, #4083)
  178. WiFi.disconnect(true); // Delete SDK wifi config
  179. delay(200);
  180. WiFi.mode(WIFI_STA); // Disable AP mode
  181. WiFiSetSleepMode();
  182. // if (WiFi.getPhyMode() != WIFI_PHY_MODE_11N) { WiFi.setPhyMode(WIFI_PHY_MODE_11N); }
  183. if (!WiFi.getAutoConnect()) { WiFi.setAutoConnect(true); }
  184. // WiFi.setAutoReconnect(true);
  185. switch (flag) {
  186. case 0: // AP1
  187. case 1: // AP2
  188. Settings.sta_active = flag;
  189. break;
  190. case 2: // Toggle
  191. Settings.sta_active ^= 1;
  192. } // 3: Current AP
  193. if ('\0' == Settings.sta_ssid[Settings.sta_active][0]) { Settings.sta_active ^= 1; } // Skip empty SSID
  194. if (Settings.ip_address[0]) {
  195. WiFi.config(Settings.ip_address[0], Settings.ip_address[1], Settings.ip_address[2], Settings.ip_address[3]); // Set static IP
  196. }
  197. WiFi.hostname(my_hostname);
  198. if (channel) {
  199. WiFi.begin(Settings.sta_ssid[Settings.sta_active], Settings.sta_pwd[Settings.sta_active], channel, wifi_bssid);
  200. } else {
  201. WiFi.begin(Settings.sta_ssid[Settings.sta_active], Settings.sta_pwd[Settings.sta_active]);
  202. }
  203. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_CONNECTING_TO_AP "%d %s " D_IN_MODE " 11%c " D_AS " %s..."),
  204. Settings.sta_active +1, Settings.sta_ssid[Settings.sta_active], kWifiPhyMode[WiFi.getPhyMode() & 0x3], my_hostname);
  205. AddLog(LOG_LEVEL_INFO);
  206. }
  207. void WifiBeginAfterScan()
  208. {
  209. static int8_t best_network_db;
  210. // Not active
  211. if (0 == wifi_scan_state) { return; }
  212. // Init scan when not connected
  213. if (1 == wifi_scan_state) {
  214. memset((void*) &wifi_bssid, 0, sizeof(wifi_bssid));
  215. best_network_db = -127;
  216. wifi_scan_state = 3;
  217. }
  218. // Init scan when connected
  219. if (2 == wifi_scan_state) {
  220. uint8_t* bssid = WiFi.BSSID(); // Get current bssid
  221. memcpy((void*) &wifi_bssid, (void*) bssid, sizeof(wifi_bssid));
  222. best_network_db = WiFi.RSSI(); // Get current rssi and add threshold
  223. if (best_network_db < -WIFI_RSSI_THRESHOLD) { best_network_db += WIFI_RSSI_THRESHOLD; }
  224. wifi_scan_state = 3;
  225. }
  226. // Init scan
  227. if (3 == wifi_scan_state) {
  228. if (WiFi.scanComplete() != WIFI_SCAN_RUNNING) {
  229. WiFi.scanNetworks(true); // Start wifi scan async
  230. wifi_scan_state++;
  231. AddLog_P(LOG_LEVEL_DEBUG, S_LOG_WIFI, PSTR("Network (re)scan started..."));
  232. return;
  233. }
  234. }
  235. int8_t wifi_scan_result = WiFi.scanComplete();
  236. // Check scan done
  237. if (4 == wifi_scan_state) {
  238. if (wifi_scan_result != WIFI_SCAN_RUNNING) {
  239. wifi_scan_state++;
  240. }
  241. }
  242. // Scan done
  243. if (5 == wifi_scan_state) {
  244. int32_t channel = 0; // No scan result
  245. int8_t ap = 3; // AP default if not found
  246. uint8_t last_bssid[6]; // Save last bssid
  247. memcpy((void*) &last_bssid, (void*) &wifi_bssid, sizeof(last_bssid));
  248. if (wifi_scan_result > 0) {
  249. // Networks found
  250. for (int8_t i = 0; i < wifi_scan_result; ++i) {
  251. String ssid_scan;
  252. int32_t rssi_scan;
  253. uint8_t sec_scan;
  254. uint8_t* bssid_scan;
  255. int32_t chan_scan;
  256. bool hidden_scan;
  257. WiFi.getNetworkInfo(i, ssid_scan, sec_scan, rssi_scan, bssid_scan, chan_scan, hidden_scan);
  258. bool known = false;
  259. uint8_t j;
  260. for (j = 0; j < 2; j++) {
  261. if (ssid_scan == Settings.sta_ssid[j]) { // SSID match
  262. known = true;
  263. if (rssi_scan > best_network_db) { // Best network
  264. if (sec_scan == ENC_TYPE_NONE || Settings.sta_pwd[j]) { // Check for passphrase if not open wlan
  265. best_network_db = (int8_t)rssi_scan;
  266. channel = chan_scan;
  267. ap = j; // AP1 or AP2
  268. memcpy((void*) &wifi_bssid, (void*) bssid_scan, sizeof(wifi_bssid));
  269. }
  270. }
  271. break;
  272. }
  273. }
  274. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI "Network %d, AP%c, SSId %s, Channel %d, BSSId %02X:%02X:%02X:%02X:%02X:%02X, RSSI %d, Encryption %d"),
  275. i, (known) ? (j) ? '2' : '1' : '-', ssid_scan.c_str(), chan_scan, bssid_scan[0], bssid_scan[1], bssid_scan[2], bssid_scan[3], bssid_scan[4], bssid_scan[5], rssi_scan, (sec_scan == ENC_TYPE_NONE) ? 0 : 1);
  276. AddLog(LOG_LEVEL_DEBUG);
  277. delay(0);
  278. }
  279. WiFi.scanDelete(); // Clean up Ram
  280. delay(0);
  281. }
  282. wifi_scan_state = 0;
  283. // If bssid changed then (re)connect wifi
  284. for (uint8_t i = 0; i < sizeof(wifi_bssid); i++) {
  285. if (last_bssid[i] != wifi_bssid[i]) {
  286. WifiBegin(ap, channel); // 0 (AP1), 1 (AP2) or 3 (default AP)
  287. break;
  288. }
  289. }
  290. }
  291. }
  292. void WifiSetState(uint8_t state)
  293. {
  294. if (state == global_state.wifi_down) {
  295. if (state) {
  296. rules_flag.wifi_connected = 1;
  297. } else {
  298. rules_flag.wifi_disconnected = 1;
  299. }
  300. }
  301. global_state.wifi_down = state ^1;
  302. }
  303. void WifiCheckIp(void)
  304. {
  305. if ((WL_CONNECTED == WiFi.status()) && (static_cast<uint32_t>(WiFi.localIP()) != 0)) {
  306. WifiSetState(1);
  307. wifi_counter = WIFI_CHECK_SEC;
  308. wifi_retry = wifi_retry_init;
  309. AddLog_P((wifi_status != WL_CONNECTED) ? LOG_LEVEL_INFO : LOG_LEVEL_DEBUG_MORE, S_LOG_WIFI, PSTR(D_CONNECTED));
  310. if (wifi_status != WL_CONNECTED) {
  311. // AddLog_P(LOG_LEVEL_INFO, PSTR("Wifi: Set IP addresses"));
  312. Settings.ip_address[1] = (uint32_t)WiFi.gatewayIP();
  313. Settings.ip_address[2] = (uint32_t)WiFi.subnetMask();
  314. Settings.ip_address[3] = (uint32_t)WiFi.dnsIP();
  315. }
  316. wifi_status = WL_CONNECTED;
  317. } else {
  318. WifiSetState(0);
  319. uint8_t wifi_config_tool = Settings.sta_config;
  320. wifi_status = WiFi.status();
  321. switch (wifi_status) {
  322. case WL_CONNECTED:
  323. AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECT_FAILED_NO_IP_ADDRESS));
  324. wifi_status = 0;
  325. wifi_retry = wifi_retry_init;
  326. break;
  327. case WL_NO_SSID_AVAIL:
  328. AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECT_FAILED_AP_NOT_REACHED));
  329. if (WIFI_WAIT == Settings.sta_config) {
  330. wifi_retry = wifi_retry_init;
  331. } else {
  332. if (wifi_retry > (wifi_retry_init / 2)) {
  333. wifi_retry = wifi_retry_init / 2;
  334. }
  335. else if (wifi_retry) {
  336. wifi_retry = 0;
  337. }
  338. }
  339. break;
  340. case WL_CONNECT_FAILED:
  341. AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECT_FAILED_WRONG_PASSWORD));
  342. if (wifi_retry > (wifi_retry_init / 2)) {
  343. wifi_retry = wifi_retry_init / 2;
  344. }
  345. else if (wifi_retry) {
  346. wifi_retry = 0;
  347. }
  348. break;
  349. default: // WL_IDLE_STATUS and WL_DISCONNECTED
  350. if (!wifi_retry || ((wifi_retry_init / 2) == wifi_retry)) {
  351. AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECT_FAILED_AP_TIMEOUT));
  352. } else {
  353. if (('\0' == Settings.sta_ssid[0][0]) && ('\0' == Settings.sta_ssid[1][0])) {
  354. wifi_config_tool = WIFI_CONFIG_NO_SSID; // Skip empty SSIDs and start Wifi config tool
  355. wifi_retry = 0;
  356. } else {
  357. AddLog_P(LOG_LEVEL_DEBUG, S_LOG_WIFI, PSTR(D_ATTEMPTING_CONNECTION));
  358. }
  359. }
  360. }
  361. if (wifi_retry) {
  362. if (Settings.flag3.use_wifi_scan) {
  363. if (wifi_retry_init == wifi_retry) {
  364. wifi_scan_state = 1; // Select scanned SSID
  365. }
  366. } else {
  367. if (wifi_retry_init == wifi_retry) {
  368. WifiBegin(3, 0); // Select default SSID
  369. }
  370. if ((Settings.sta_config != WIFI_WAIT) && ((wifi_retry_init / 2) == wifi_retry)) {
  371. WifiBegin(2, 0); // Select alternate SSID
  372. }
  373. }
  374. wifi_counter = 1;
  375. wifi_retry--;
  376. } else {
  377. WifiConfig(wifi_config_tool);
  378. wifi_counter = 1;
  379. wifi_retry = wifi_retry_init;
  380. }
  381. }
  382. }
  383. void WifiCheck(uint8_t param)
  384. {
  385. wifi_counter--;
  386. switch (param) {
  387. case WIFI_SERIAL:
  388. case WIFI_SMARTCONFIG:
  389. case WIFI_MANAGER:
  390. case WIFI_WPSCONFIG:
  391. WifiConfig(param);
  392. break;
  393. default:
  394. if (wifi_config_counter) {
  395. wifi_config_counter--;
  396. wifi_counter = wifi_config_counter +5;
  397. if (wifi_config_counter) {
  398. #ifdef USE_SMARTCONFIG
  399. if ((WIFI_SMARTCONFIG == wifi_config_type) && WiFi.smartConfigDone()) {
  400. wifi_config_counter = 0;
  401. }
  402. #endif // USE_SMARTCONFIG
  403. #ifdef USE_WPS
  404. if ((WIFI_WPSCONFIG == wifi_config_type) && WifiWpsConfigDone()) {
  405. wifi_config_counter = 0;
  406. }
  407. #endif // USE_WPS
  408. if (!wifi_config_counter) {
  409. if (strlen(WiFi.SSID().c_str())) {
  410. strlcpy(Settings.sta_ssid[0], WiFi.SSID().c_str(), sizeof(Settings.sta_ssid[0]));
  411. }
  412. if (strlen(WiFi.psk().c_str())) {
  413. strlcpy(Settings.sta_pwd[0], WiFi.psk().c_str(), sizeof(Settings.sta_pwd[0]));
  414. }
  415. Settings.sta_active = 0;
  416. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_WCFG_1_SMARTCONFIG D_CMND_SSID "1 %s"), Settings.sta_ssid[0]);
  417. AddLog(LOG_LEVEL_INFO);
  418. }
  419. }
  420. if (!wifi_config_counter) {
  421. #ifdef USE_SMARTCONFIG
  422. if (WIFI_SMARTCONFIG == wifi_config_type) { WiFi.stopSmartConfig(); }
  423. #endif // USE_SMARTCONFIG
  424. // SettingsSdkErase(); // Disabled v6.1.0b due to possible bad wifi connects
  425. restart_flag = 2;
  426. }
  427. } else {
  428. if (wifi_scan_state) { WifiBeginAfterScan(); }
  429. if (wifi_counter <= 0) {
  430. AddLog_P(LOG_LEVEL_DEBUG_MORE, S_LOG_WIFI, PSTR(D_CHECKING_CONNECTION));
  431. wifi_counter = WIFI_CHECK_SEC;
  432. WifiCheckIp();
  433. }
  434. if ((WL_CONNECTED == WiFi.status()) && (static_cast<uint32_t>(WiFi.localIP()) != 0) && !wifi_config_type) {
  435. WifiSetState(1);
  436. if (Settings.flag3.use_wifi_rescan) {
  437. if (!(uptime % (60 * WIFI_RESCAN_MINUTES))) {
  438. wifi_scan_state = 2;
  439. }
  440. }
  441. #ifdef BE_MINIMAL
  442. if (1 == RtcSettings.ota_loader) {
  443. RtcSettings.ota_loader = 0;
  444. ota_state_flag = 3;
  445. }
  446. #endif // BE_MINIMAL
  447. #ifdef USE_DISCOVERY
  448. if (!mdns_begun) {
  449. if (mdns_delayed_start) {
  450. AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_ATTEMPTING_CONNECTION));
  451. mdns_delayed_start--;
  452. } else {
  453. mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START];
  454. mdns_begun = MDNS.begin(my_hostname);
  455. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MDNS "%s"), (mdns_begun) ? D_INITIALIZED : D_FAILED);
  456. AddLog(LOG_LEVEL_INFO);
  457. }
  458. }
  459. #endif // USE_DISCOVERY
  460. #ifdef USE_WEBSERVER
  461. if (Settings.webserver) {
  462. StartWebserver(Settings.webserver, WiFi.localIP());
  463. #ifdef USE_DISCOVERY
  464. #ifdef WEBSERVER_ADVERTISE
  465. if (mdns_begun) {
  466. MDNS.addService("http", "tcp", WEB_PORT);
  467. }
  468. #endif // WEBSERVER_ADVERTISE
  469. #endif // USE_DISCOVERY
  470. } else {
  471. StopWebserver();
  472. }
  473. #ifdef USE_EMULATION
  474. if (Settings.flag2.emulation) { UdpConnect(); }
  475. #endif // USE_EMULATION
  476. #endif // USE_WEBSERVER
  477. #ifdef USE_KNX
  478. if (!knx_started && Settings.flag.knx_enabled) {
  479. KNXStart();
  480. knx_started = true;
  481. }
  482. #endif // USE_KNX
  483. } else {
  484. WifiSetState(0);
  485. #if defined(USE_WEBSERVER) && defined(USE_EMULATION)
  486. UdpDisconnect();
  487. #endif // USE_EMULATION
  488. mdns_begun = false;
  489. #ifdef USE_KNX
  490. knx_started = false;
  491. #endif // USE_KNX
  492. }
  493. }
  494. }
  495. }
  496. int WifiState(void)
  497. {
  498. int state = -1;
  499. if (!global_state.wifi_down) { state = WIFI_RESTART; }
  500. if (wifi_config_type) { state = wifi_config_type; }
  501. return state;
  502. }
  503. void WifiConnect(void)
  504. {
  505. WifiSetState(0);
  506. WiFi.persistent(false); // Solve possible wifi init errors
  507. wifi_status = 0;
  508. wifi_retry_init = WIFI_RETRY_OFFSET_SEC + ((ESP.getChipId() & 0xF) * 2);
  509. wifi_retry = wifi_retry_init;
  510. wifi_counter = 1;
  511. }
  512. // Enable from 6.0.0a until 6.1.0a - disabled due to possible cause of bad wifi connect on core 2.3.0
  513. // Re-enabled from 6.3.0.7 with ESP.restart replaced by ESP.reset
  514. void WifiDisconnect(void)
  515. {
  516. // Courtesy of EspEasy
  517. WiFi.persistent(true); // use SDK storage of SSID/WPA parameters
  518. ETS_UART_INTR_DISABLE();
  519. wifi_station_disconnect(); // this will store empty ssid/wpa into sdk storage
  520. ETS_UART_INTR_ENABLE();
  521. WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters
  522. }
  523. void EspRestart(void)
  524. {
  525. delay(100); // Allow time for message xfer - disabled v6.1.0b
  526. if (Settings.flag.mqtt_enabled) MqttDisconnect();
  527. WifiDisconnect();
  528. // ESP.restart(); // This results in exception 3 on restarts on core 2.3.0
  529. ESP.reset();
  530. }
  531. /*
  532. void EspRestart(void)
  533. {
  534. ESP.restart();
  535. }
  536. */
  537. void WifiAddDelayWhenDisconnected(void)
  538. {
  539. if (APP_BAUDRATE == baudrate) { // When baudrate too low it will fail on Sonoff Pow R2 and S31 serial interface initialization
  540. if (global_state.wifi_down) {
  541. delay(DRIVER_BOOT_DELAY);
  542. }
  543. }
  544. }