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.

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