Fork of the espurna firmware for `mhsw` switches
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.

589 lines
16 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
6 years ago
  1. /*
  2. WIFI MODULE
  3. Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #include "JustWifi.h"
  6. #include <Ticker.h>
  7. uint32_t _wifi_scan_client_id = 0;
  8. bool _wifi_wps_running = false;
  9. uint8_t _wifi_ap_mode = WIFI_AP_FALLBACK;
  10. // -----------------------------------------------------------------------------
  11. // PRIVATE
  12. // -----------------------------------------------------------------------------
  13. void _wifiCheckAP() {
  14. static unsigned long last = 0;
  15. if (millis() - last < 60000) return;
  16. last = millis();
  17. if ((WIFI_AP_FALLBACK == _wifi_ap_mode) &&
  18. jw.connected() &&
  19. jw.connectable() &&
  20. (WiFi.softAPgetStationNum() == 0)
  21. ) {
  22. jw.destroyAP();
  23. }
  24. }
  25. void _wifiConfigure() {
  26. jw.setHostname(getSetting("hostname").c_str());
  27. #if USE_PASSWORD
  28. jw.setSoftAP(getSetting("hostname").c_str(), getSetting("adminPass", ADMIN_PASS).c_str());
  29. #else
  30. jw.setSoftAP(getSetting("hostname").c_str());
  31. #endif
  32. jw.setConnectTimeout(WIFI_CONNECT_TIMEOUT);
  33. wifiReconnectCheck();
  34. jw.enableAPFallback(true);
  35. jw.cleanNetworks();
  36. _wifi_ap_mode = getSetting("apmode", WIFI_AP_FALLBACK).toInt();
  37. // If system is flagged unstable we do not init wifi networks
  38. #if SYSTEM_CHECK_ENABLED
  39. if (!systemCheck()) return;
  40. #endif
  41. // Clean settings
  42. _wifiClean(WIFI_MAX_NETWORKS);
  43. int i;
  44. for (i = 0; i< WIFI_MAX_NETWORKS; i++) {
  45. if (getSetting("ssid" + String(i)).length() == 0) break;
  46. if (getSetting("ip" + String(i)).length() == 0) {
  47. jw.addNetwork(
  48. getSetting("ssid" + String(i)).c_str(),
  49. getSetting("pass" + String(i)).c_str()
  50. );
  51. } else {
  52. jw.addNetwork(
  53. getSetting("ssid" + String(i)).c_str(),
  54. getSetting("pass" + String(i)).c_str(),
  55. getSetting("ip" + String(i)).c_str(),
  56. getSetting("gw" + String(i)).c_str(),
  57. getSetting("mask" + String(i)).c_str(),
  58. getSetting("dns" + String(i)).c_str()
  59. );
  60. }
  61. }
  62. jw.scanNetworks(getSetting("wifiScan", WIFI_SCAN_NETWORKS).toInt() == 1);
  63. }
  64. void _wifiScan(uint32_t client_id = 0) {
  65. DEBUG_MSG_P(PSTR("[WIFI] Start scanning\n"));
  66. #if WEB_SUPPORT
  67. String output;
  68. #endif
  69. unsigned char result = WiFi.scanNetworks();
  70. if (result == WIFI_SCAN_FAILED) {
  71. DEBUG_MSG_P(PSTR("[WIFI] Scan failed\n"));
  72. #if WEB_SUPPORT
  73. output = String("Failed scan");
  74. #endif
  75. } else if (result == 0) {
  76. DEBUG_MSG_P(PSTR("[WIFI] No networks found\n"));
  77. #if WEB_SUPPORT
  78. output = String("No networks found");
  79. #endif
  80. } else {
  81. DEBUG_MSG_P(PSTR("[WIFI] %d networks found:\n"), result);
  82. // Populate defined networks with scan data
  83. for (int8_t i = 0; i < result; ++i) {
  84. String ssid_scan;
  85. int32_t rssi_scan;
  86. uint8_t sec_scan;
  87. uint8_t* BSSID_scan;
  88. int32_t chan_scan;
  89. bool hidden_scan;
  90. char buffer[128];
  91. WiFi.getNetworkInfo(i, ssid_scan, sec_scan, rssi_scan, BSSID_scan, chan_scan, hidden_scan);
  92. snprintf_P(buffer, sizeof(buffer),
  93. PSTR("BSSID: %02X:%02X:%02X:%02X:%02X:%02X SEC: %s RSSI: %3d CH: %2d SSID: %s"),
  94. BSSID_scan[1], BSSID_scan[2], BSSID_scan[3], BSSID_scan[4], BSSID_scan[5], BSSID_scan[6],
  95. (sec_scan != ENC_TYPE_NONE ? "YES" : "NO "),
  96. rssi_scan,
  97. chan_scan,
  98. (char *) ssid_scan.c_str()
  99. );
  100. DEBUG_MSG_P(PSTR("[WIFI] > %s\n"), buffer);
  101. #if WEB_SUPPORT
  102. if (client_id > 0) output = output + String(buffer) + String("<br />");
  103. #endif
  104. }
  105. }
  106. #if WEB_SUPPORT
  107. if (client_id > 0) {
  108. output = String("{\"scanResult\": \"") + output + String("\"}");
  109. wsSend(client_id, output.c_str());
  110. }
  111. #endif
  112. WiFi.scanDelete();
  113. }
  114. bool _wifiClean(unsigned char num) {
  115. bool changed = false;
  116. int i = 0;
  117. // Clean defined settings
  118. while (i < num) {
  119. // Skip on first non-defined setting
  120. if (!hasSetting("ssid", i)) {
  121. delSetting("ssid", i);
  122. break;
  123. }
  124. // Delete empty values
  125. if (!hasSetting("pass", i)) delSetting("pass", i);
  126. if (!hasSetting("ip", i)) delSetting("ip", i);
  127. if (!hasSetting("gw", i)) delSetting("gw", i);
  128. if (!hasSetting("mask", i)) delSetting("mask", i);
  129. if (!hasSetting("dns", i)) delSetting("dns", i);
  130. ++i;
  131. }
  132. // Delete all other settings
  133. while (i < WIFI_MAX_NETWORKS) {
  134. changed = hasSetting("ssid", i);
  135. delSetting("ssid", i);
  136. delSetting("pass", i);
  137. delSetting("ip", i);
  138. delSetting("gw", i);
  139. delSetting("mask", i);
  140. delSetting("dns", i);
  141. ++i;
  142. }
  143. return changed;
  144. }
  145. // Inject hardcoded networks
  146. void _wifiInject() {
  147. if (strlen(WIFI1_SSID)) {
  148. if (!hasSetting("ssid", 0)) {
  149. setSetting("ssid", 0, WIFI1_SSID);
  150. setSetting("pass", 0, WIFI1_PASS);
  151. setSetting("ip", 0, WIFI1_IP);
  152. setSetting("gw", 0, WIFI1_GW);
  153. setSetting("mask", 0, WIFI1_MASK);
  154. setSetting("dns", 0, WIFI1_DNS);
  155. }
  156. if (strlen(WIFI2_SSID)) {
  157. if (!hasSetting("ssid", 1)) {
  158. setSetting("ssid", 1, WIFI2_SSID);
  159. setSetting("pass", 1, WIFI2_PASS);
  160. setSetting("ip", 1, WIFI2_IP);
  161. setSetting("gw", 1, WIFI2_GW);
  162. setSetting("mask", 1, WIFI2_MASK);
  163. setSetting("dns", 1, WIFI2_DNS);
  164. }
  165. }
  166. }
  167. }
  168. void _wifiCallback(justwifi_messages_t code, char * parameter) {
  169. if (MESSAGE_WPS_START == code) {
  170. _wifi_wps_running = true;
  171. }
  172. if (MESSAGE_WPS_ERROR == code) {
  173. _wifi_wps_running = false;
  174. }
  175. if (MESSAGE_WPS_SUCCESS == code) {
  176. String ssid = WiFi.SSID();
  177. String pass = WiFi.psk();
  178. // Look for the same SSID
  179. uint8_t count = 0;
  180. while (count < WIFI_MAX_NETWORKS) {
  181. if (!hasSetting("ssid", count)) break;
  182. if (ssid.equals(getSetting("ssid", count, ""))) break;
  183. count++;
  184. }
  185. // If we have reached the max we overwrite the first one
  186. if (WIFI_MAX_NETWORKS == count) count = 0;
  187. setSetting("ssid", count, ssid);
  188. setSetting("pass", count, pass);
  189. _wifi_wps_running = false;
  190. }
  191. }
  192. #if WIFI_AP_CAPTIVE
  193. #include "DNSServer.h"
  194. DNSServer _wifi_dnsServer;
  195. void _wifiCaptivePortal(justwifi_messages_t code, char * parameter) {
  196. if (MESSAGE_ACCESSPOINT_CREATED == code) {
  197. _wifi_dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
  198. _wifi_dnsServer.start(53, "*", WiFi.softAPIP());
  199. DEBUG_MSG_P(PSTR("[WIFI] Captive portal enabled\n"));
  200. }
  201. if (MESSAGE_CONNECTED == code) {
  202. _wifi_dnsServer.stop();
  203. DEBUG_MSG_P(PSTR("[WIFI] Captive portal disabled\n"));
  204. }
  205. }
  206. #endif // WIFI_AP_CAPTIVE
  207. #if DEBUG_SUPPORT
  208. void _wifiDebug(justwifi_messages_t code, char * parameter) {
  209. // -------------------------------------------------------------------------
  210. if (code == MESSAGE_SCANNING) {
  211. DEBUG_MSG_P(PSTR("[WIFI] Scanning\n"));
  212. }
  213. if (code == MESSAGE_SCAN_FAILED) {
  214. DEBUG_MSG_P(PSTR("[WIFI] Scan failed\n"));
  215. }
  216. if (code == MESSAGE_NO_NETWORKS) {
  217. DEBUG_MSG_P(PSTR("[WIFI] No networks found\n"));
  218. }
  219. if (code == MESSAGE_NO_KNOWN_NETWORKS) {
  220. DEBUG_MSG_P(PSTR("[WIFI] No known networks found\n"));
  221. }
  222. if (code == MESSAGE_FOUND_NETWORK) {
  223. DEBUG_MSG_P(PSTR("[WIFI] %s\n"), parameter);
  224. }
  225. // -------------------------------------------------------------------------
  226. if (code == MESSAGE_CONNECTING) {
  227. DEBUG_MSG_P(PSTR("[WIFI] Connecting to %s\n"), parameter);
  228. }
  229. if (code == MESSAGE_CONNECT_WAITING) {
  230. // too much noise
  231. }
  232. if (code == MESSAGE_CONNECT_FAILED) {
  233. DEBUG_MSG_P(PSTR("[WIFI] Could not connect to %s\n"), parameter);
  234. }
  235. if (code == MESSAGE_CONNECTED) {
  236. wifiDebug();
  237. }
  238. if (code == MESSAGE_DISCONNECTED) {
  239. DEBUG_MSG_P(PSTR("[WIFI] Disconnected\n"));
  240. wifiDebug();
  241. }
  242. // -------------------------------------------------------------------------
  243. if (code == MESSAGE_ACCESSPOINT_CREATING) {
  244. DEBUG_MSG_P(PSTR("[WIFI] Creating access point\n"));
  245. }
  246. if (code == MESSAGE_ACCESSPOINT_CREATED) {
  247. wifiDebug();
  248. }
  249. if (code == MESSAGE_ACCESSPOINT_FAILED) {
  250. DEBUG_MSG_P(PSTR("[WIFI] Could not create access point\n"));
  251. }
  252. if (code == MESSAGE_ACCESSPOINT_DESTROYED) {
  253. DEBUG_MSG_P(PSTR("[WIFI] Access point destroyed\n"));
  254. wifiDebug();
  255. }
  256. // -------------------------------------------------------------------------
  257. if (code == MESSAGE_WPS_START) {
  258. DEBUG_MSG_P(PSTR("[WIFI] WPS started\n"));
  259. }
  260. if (code == MESSAGE_WPS_SUCCESS) {
  261. DEBUG_MSG_P(PSTR("[WIFI] WPS succeded!\n"));
  262. }
  263. if (code == MESSAGE_WPS_ERROR) {
  264. DEBUG_MSG_P(PSTR("[WIFI] WPS failed\n"));
  265. }
  266. }
  267. #endif // DEBUG_SUPPORT
  268. // -----------------------------------------------------------------------------
  269. // SETTINGS
  270. // -----------------------------------------------------------------------------
  271. #if TERMINAL_SUPPORT
  272. void _wifiInitCommands() {
  273. settingsRegisterCommand(F("WIFI.RESET"), [](Embedis* e) {
  274. _wifiConfigure();
  275. wifiDisconnect();
  276. DEBUG_MSG_P(PSTR("+OK\n"));
  277. });
  278. settingsRegisterCommand(F("WIFI.AP"), [](Embedis* e) {
  279. wifiStartAP();
  280. DEBUG_MSG_P(PSTR("+OK\n"));
  281. });
  282. settingsRegisterCommand(F("WIFI.WPS"), [](Embedis* e) {
  283. wifiStartWPS();
  284. DEBUG_MSG_P(PSTR("+OK\n"));
  285. });
  286. settingsRegisterCommand(F("WIFI.SCAN"), [](Embedis* e) {
  287. _wifiScan();
  288. DEBUG_MSG_P(PSTR("+OK\n"));
  289. });
  290. }
  291. #endif
  292. // -----------------------------------------------------------------------------
  293. // WEB
  294. // -----------------------------------------------------------------------------
  295. #if WEB_SUPPORT
  296. bool _wifiWebSocketOnReceive(const char * key, JsonVariant& value) {
  297. if (strncmp(key, "wifi", 4) == 0) return true;
  298. if (strncmp(key, "ssid", 4) == 0) return true;
  299. if (strncmp(key, "pass", 4) == 0) return true;
  300. if (strncmp(key, "ip", 2) == 0) return true;
  301. if (strncmp(key, "gw", 2) == 0) return true;
  302. if (strncmp(key, "mask", 4) == 0) return true;
  303. if (strncmp(key, "dns", 3) == 0) return true;
  304. return false;
  305. }
  306. void _wifiWebSocketOnSend(JsonObject& root) {
  307. root["maxNetworks"] = WIFI_MAX_NETWORKS;
  308. root["wifiScan"] = getSetting("wifiScan", WIFI_SCAN_NETWORKS).toInt() == 1;
  309. JsonArray& wifi = root.createNestedArray("wifi");
  310. for (byte i=0; i<WIFI_MAX_NETWORKS; i++) {
  311. if (!hasSetting("ssid", i)) break;
  312. JsonObject& network = wifi.createNestedObject();
  313. network["ssid"] = getSetting("ssid", i, "");
  314. network["pass"] = getSetting("pass", i, "");
  315. network["ip"] = getSetting("ip", i, "");
  316. network["gw"] = getSetting("gw", i, "");
  317. network["mask"] = getSetting("mask", i, "");
  318. network["dns"] = getSetting("dns", i, "");
  319. }
  320. }
  321. void _wifiWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) {
  322. if (strcmp(action, "scan") == 0) _wifi_scan_client_id = client_id;
  323. }
  324. #endif
  325. // -----------------------------------------------------------------------------
  326. // API
  327. // -----------------------------------------------------------------------------
  328. String getIP() {
  329. if (WiFi.getMode() == WIFI_AP) {
  330. return WiFi.softAPIP().toString();
  331. }
  332. return WiFi.localIP().toString();
  333. }
  334. String getNetwork() {
  335. if (WiFi.getMode() == WIFI_AP) {
  336. return jw.getAPSSID();
  337. }
  338. return WiFi.SSID();
  339. }
  340. bool wifiConnected() {
  341. return jw.connected();
  342. }
  343. void wifiDisconnect() {
  344. jw.disconnect();
  345. }
  346. bool wifiStartAP() {
  347. jw.disconnect();
  348. jw.resetReconnectTimeout();
  349. return jw.createAP();
  350. }
  351. void wifiStartWPS() {
  352. jw.startWPS();
  353. }
  354. void wifiReconnectCheck() {
  355. bool connected = false;
  356. #if WEB_SUPPORT
  357. if (wsConnected()) connected = true;
  358. #endif
  359. #if TELNET_SUPPORT
  360. if (telnetConnected()) connected = true;
  361. #endif
  362. jw.setReconnectTimeout(connected ? 0 : WIFI_RECONNECT_INTERVAL);
  363. }
  364. uint8_t wifiState() {
  365. uint8_t state = 0;
  366. if (jw.connected()) state += WIFI_STATE_STA;
  367. if (jw.connectable()) state += WIFI_STATE_AP;
  368. if (_wifi_wps_running) state += WIFI_STATE_WPS;
  369. return state;
  370. }
  371. void wifiDebug() {
  372. if (WiFi.getMode() & WIFI_STA) {
  373. uint8_t * bssid = WiFi.BSSID();
  374. DEBUG_MSG_P(PSTR("[WIFI] ------------------------------------- MODE STA\n"));
  375. DEBUG_MSG_P(PSTR("[WIFI] SSID %s\n"), WiFi.SSID().c_str());
  376. DEBUG_MSG_P(PSTR("[WIFI] IP %s\n"), WiFi.localIP().toString().c_str());
  377. DEBUG_MSG_P(PSTR("[WIFI] MAC %s\n"), WiFi.macAddress().c_str());
  378. DEBUG_MSG_P(PSTR("[WIFI] GW %s\n"), WiFi.gatewayIP().toString().c_str());
  379. DEBUG_MSG_P(PSTR("[WIFI] DNS %s\n"), WiFi.dnsIP().toString().c_str());
  380. DEBUG_MSG_P(PSTR("[WIFI] MASK %s\n"), WiFi.subnetMask().toString().c_str());
  381. DEBUG_MSG_P(PSTR("[WIFI] HOST %s\n"), WiFi.hostname().c_str());
  382. DEBUG_MSG_P(PSTR("[WIFI] BSSID %02X:%02X:%02X:%02X:%02X:%02X\n"),
  383. bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], bssid[6]
  384. );
  385. DEBUG_MSG_P(PSTR("[WIFI] CH %d\n"), WiFi.channel());
  386. DEBUG_MSG_P(PSTR("[WIFI] RSSI %d\n"), WiFi.RSSI());
  387. }
  388. if (WiFi.getMode() & WIFI_AP) {
  389. DEBUG_MSG_P(PSTR("[WIFI] -------------------------------------- MODE AP\n"));
  390. DEBUG_MSG_P(PSTR("[WIFI] SSID %s\n"), jw.getAPSSID().c_str());
  391. DEBUG_MSG_P(PSTR("[WIFI] PASS %s\n"), getSetting("adminPass", ADMIN_PASS).c_str());
  392. DEBUG_MSG_P(PSTR("[WIFI] IP %s\n"), WiFi.softAPIP().toString().c_str());
  393. DEBUG_MSG_P(PSTR("[WIFI] MAC %s\n"), WiFi.softAPmacAddress().c_str());
  394. }
  395. if (WiFi.getMode() == 0) {
  396. DEBUG_MSG_P(PSTR("[WIFI] ------------------------------------- MODE OFF\n"));
  397. DEBUG_MSG_P(PSTR("[WIFI] No connection\n"));
  398. }
  399. DEBUG_MSG_P(PSTR("[WIFI] ----------------------------------------------\n"));
  400. }
  401. void wifiRegister(wifi_callback_f callback) {
  402. jw.subscribe(callback);
  403. }
  404. // -----------------------------------------------------------------------------
  405. // INITIALIZATION
  406. // -----------------------------------------------------------------------------
  407. void wifiSetup() {
  408. WiFi.setSleepMode(WIFI_SLEEP_MODE);
  409. _wifiInject();
  410. _wifiConfigure();
  411. // Message callbacks
  412. wifiRegister(_wifiCallback);
  413. #if WIFI_AP_CAPTIVE
  414. wifiRegister(_wifiCaptivePortal);
  415. #endif
  416. #if DEBUG_SUPPORT
  417. wifiRegister(_wifiDebug);
  418. #endif
  419. #if WEB_SUPPORT
  420. wsOnSendRegister(_wifiWebSocketOnSend);
  421. wsOnReceiveRegister(_wifiWebSocketOnReceive);
  422. wsOnAfterParseRegister(_wifiConfigure);
  423. wsOnActionRegister(_wifiWebSocketOnAction);
  424. #endif
  425. #if TERMINAL_SUPPORT
  426. _wifiInitCommands();
  427. #endif
  428. // Register loop
  429. espurnaRegisterLoop(wifiLoop);
  430. }
  431. void wifiLoop() {
  432. // Main wifi loop
  433. jw.loop();
  434. // Process captrive portal DNS queries if in AP mode only
  435. #if WIFI_AP_CAPTIVE
  436. if ((WiFi.getMode() & WIFI_AP) == WIFI_AP) {
  437. _wifi_dnsServer.processNextRequest();
  438. }
  439. #endif
  440. // Do we have a pending scan?
  441. if (_wifi_scan_client_id > 0) {
  442. _wifiScan(_wifi_scan_client_id);
  443. _wifi_scan_client_id = 0;
  444. }
  445. // Check if we should disable AP
  446. _wifiCheckAP();
  447. }