wifi.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. #include "common.h"
  2. #include "WiFi.h"
  3. #include "wifi.h"
  4. #include "config.h"
  5. #include "httpd.h"
  6. #include <lwip/dns.h>
  7. #include <lwip/inet.h>
  8. #include <lwip/apps/sntp.h>
  9. #include <esp_sntp.h>
  10. #include <esp_wifi.h>
  11. static wifi_mode_t mode;
  12. static String ssid, password, hostname, dnsserver, sntpserver;
  13. static void sntp_sync_cb(struct timeval *tv)
  14. {
  15. static uint8_t prev_sync_status = SNTP_SYNC_STATUS_RESET;
  16. uint8_t sync_status = sntp_get_sync_status();
  17. switch (sync_status) {
  18. case SNTP_SYNC_STATUS_RESET:
  19. sntp_set_sync_mode(SNTP_SYNC_MODE_IMMED); // Until first sync
  20. if (prev_sync_status != sync_status) {
  21. printf("[SNTP] time synchronization lost\n");
  22. }
  23. break;
  24. case SNTP_SYNC_STATUS_COMPLETED:
  25. sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH); // After successful sync
  26. if (prev_sync_status != sync_status) {
  27. char timebuf[64];
  28. const struct tm *tm = localtime(&tv->tv_sec);
  29. strftime(timebuf, sizeof timebuf, "%a %Y-%m-%d %H:%M:%S %z", tm);
  30. printf("[SNTP] Time synchronized: %s\n", timebuf);
  31. }
  32. break;
  33. default:
  34. break;
  35. }
  36. prev_sync_status = sync_status;
  37. }
  38. static void my_sntp_start()
  39. {
  40. sntp_set_time_sync_notification_cb(sntp_sync_cb);
  41. sntp_setoperatingmode(SNTP_OPMODE_POLL);
  42. sntp_servermode_dhcp(1);
  43. sntp_set_sync_mode(SNTP_SYNC_MODE_IMMED); // Until first sync
  44. sntp_init();
  45. }
  46. static bool services_started;
  47. static void stop_services(void)
  48. {
  49. if (services_started) {
  50. esp_unregister_shutdown_handler(stop_services);
  51. my_httpd_stop();
  52. services_started = false;
  53. }
  54. }
  55. static inline bool invalid_ip(const ip_addr_t *ip)
  56. {
  57. return !memcmp(ip, &ip_addr_any, sizeof *ip);
  58. }
  59. static void start_services(void)
  60. {
  61. /* Always run after (re)connect */
  62. const ip_addr_t *dns_ip = dns_getserver(0);
  63. if (invalid_ip(dns_ip) || mode == WIFI_AP ||
  64. getenv_bool("ip4.dhcp.nodns")) {
  65. /* Static DNS server configuration */
  66. ip_addr_t addr;
  67. if (dnsserver != "" && inet_aton(dnsserver.c_str(), &addr)) {
  68. dns_setserver(0, &addr);
  69. }
  70. }
  71. dns_ip = dns_getserver(0);
  72. printf("[DNS] DNS server: %s\n", inet_ntoa(*dns_ip));
  73. // If Arduino supported both of these at the same that would be
  74. // awesome, but it requires ESP-IDF reconfiguration...
  75. const ip_addr_t *sntp_ip = sntp_getserver(0);
  76. if (invalid_ip(sntp_ip) || mode == WIFI_AP ||
  77. getenv_bool("ip4.dhcp.nosntp")) {
  78. if (sntpserver != "")
  79. sntp_setservername(0, sntpserver.c_str());
  80. }
  81. sntp_ip = sntp_getserver(0);
  82. printf("[SNTP] Time server: %s\n", inet_ntoa(*sntp_ip));
  83. /* Only run on first start */
  84. if (!services_started) {
  85. services_started = true;
  86. my_httpd_start();
  87. esp_register_shutdown_handler(stop_services);
  88. }
  89. }
  90. static String wifi_local_ip(void)
  91. {
  92. return WiFi.localIP().toString();
  93. }
  94. static void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
  95. {
  96. bool retry = false;
  97. bool connected = false;
  98. static int ap_clients = 0;
  99. switch (event) {
  100. case ARDUINO_EVENT_WIFI_READY:
  101. printf("[WIFI] Interface ready\n");
  102. break;
  103. case ARDUINO_EVENT_WIFI_SCAN_DONE:
  104. printf("[WIFI] Completed scan for access points\n");
  105. break;
  106. case ARDUINO_EVENT_WIFI_STA_START:
  107. printf("[WIFI] Client started\n");
  108. break;
  109. case ARDUINO_EVENT_WIFI_STA_STOP:
  110. printf("[WIFI] Clients stopped\n");
  111. break;
  112. case ARDUINO_EVENT_WIFI_STA_CONNECTED:
  113. printf("[WIFI] Connected to access point\n");
  114. break;
  115. case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
  116. printf("[WIFI] Disconnected from WiFi access point\n");
  117. retry = true;
  118. break;
  119. case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE:
  120. printf("[WIFI] Authentication mode of access point has changed\n");
  121. break;
  122. case ARDUINO_EVENT_WIFI_STA_GOT_IP:
  123. printf("[WIFI] Obtained IP address: %s\n", wifi_local_ip().c_str());
  124. connected = true;
  125. break;
  126. case ARDUINO_EVENT_WIFI_STA_LOST_IP:
  127. printf("[WIFI] Lost IP address and IP address is reset to 0\n");
  128. retry = true;
  129. break;
  130. case ARDUINO_EVENT_WPS_ER_SUCCESS:
  131. printf("[WIFI] WiFi Protected Setup (WPS): succeeded in enrollee mode\n");
  132. break;
  133. case ARDUINO_EVENT_WPS_ER_FAILED:
  134. printf("[WIFI] WiFi Protected Setup (WPS): failed in enrollee mode\n");
  135. break;
  136. case ARDUINO_EVENT_WPS_ER_TIMEOUT:
  137. printf("[WIFI] WiFi Protected Setup (WPS): timeout in enrollee mode\n");
  138. break;
  139. case ARDUINO_EVENT_WPS_ER_PIN:
  140. printf("[WIFI] WiFi Protected Setup (WPS): pin code in enrollee mode\n");
  141. break;
  142. case ARDUINO_EVENT_WIFI_AP_START:
  143. printf("[WIFI] Access point started\n");
  144. ap_clients = 0;
  145. connected = true;
  146. break;
  147. case ARDUINO_EVENT_WIFI_AP_STOP:
  148. printf("[WIFI] Access point stopped\n");
  149. ap_clients = 0;
  150. connected = false;
  151. break;
  152. case ARDUINO_EVENT_WIFI_AP_STACONNECTED:
  153. printf("[WIFI] Client connected\n");
  154. ap_clients++;
  155. break;
  156. case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED:
  157. printf("[WIFI] Client disconnected\n");
  158. ap_clients--;
  159. break;
  160. case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED:
  161. printf("[WIFI] Assigned IP address %s to client\n",
  162. inet_ntoa(info.wifi_ap_staipassigned.ip));
  163. break;
  164. case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED:
  165. printf("[WIFI] Received probe request\n");
  166. break;
  167. case ARDUINO_EVENT_WIFI_AP_GOT_IP6:
  168. printf("[WIFI] AP IPv6 is preferred\n");
  169. break;
  170. case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
  171. printf("[WIFI] STA IPv6 is preferred\n");
  172. connected = true;
  173. break;
  174. case ARDUINO_EVENT_ETH_GOT_IP6:
  175. printf("[ETH] Ethernet IPv6 is preferred\n");
  176. connected = true;
  177. break;
  178. case ARDUINO_EVENT_ETH_START:
  179. printf("[ETH] Ethernet started\n");
  180. break;
  181. case ARDUINO_EVENT_ETH_STOP:
  182. printf("[ETH] Ethernet stopped\n");
  183. break;
  184. case ARDUINO_EVENT_ETH_CONNECTED:
  185. printf("[ETH] Ethernet connected\n");
  186. break;
  187. case ARDUINO_EVENT_ETH_DISCONNECTED:
  188. printf("[ETH] Ethernet disconnected\n");
  189. retry = true;
  190. break;
  191. case ARDUINO_EVENT_ETH_GOT_IP:
  192. printf("[ETH] Obtained IP address: %s\n", wifi_local_ip().c_str());
  193. connected = true;
  194. break;
  195. default:
  196. break;
  197. }
  198. /* Maybe need to do these in a different thread? */
  199. if (connected) {
  200. start_services();
  201. }
  202. if (retry) {
  203. WiFi.disconnect();
  204. WiFi.begin();
  205. }
  206. }
  207. static void wifi_config(void)
  208. {
  209. ssid = getenv("wifi.ssid");
  210. password = getenv("wifi.psk");
  211. hostname = getenv("hostname");
  212. sntpserver = getenv_bool("sntp") ? getenv("sntp.server") : "";
  213. dnsserver = getenv("ip4.dns");
  214. WiFi.persistent(false);
  215. if (hostname != "")
  216. WiFi.hostname(hostname);
  217. if (ssid == "") {
  218. uint8_t mac[6];
  219. char ssid_buf[64];
  220. mode = WIFI_AP;
  221. password = "";
  222. WiFi.macAddress(mac);
  223. /* Skip first 4 bytes of MAC */
  224. snprintf(ssid_buf, sizeof ssid_buf, "MAX80_%02X%02X", mac[4], mac[5]);
  225. ssid = String(ssid_buf);
  226. } else {
  227. mode = WIFI_STA;
  228. }
  229. printf("[WIFI] SSID [%s]: %s\n",
  230. mode == WIFI_AP ? "AP" : "STA", ssid.c_str());
  231. if (WiFi.getMode() != mode) {
  232. WiFi.mode(mode);
  233. delay(10);
  234. }
  235. if (mode == WIFI_AP) {
  236. /* No network configuration set */
  237. IPAddress AP_IP = IPAddress(192,168,0,1);
  238. IPAddress AP_Netmask = IPAddress(255,255,255,0);
  239. IPAddress AP_Gateway = IPAddress(0,0,0,0); // No gateway
  240. unsigned int channel = time(NULL) % 11;
  241. printf("[WIFI] AP IP %s netmask %s channel %u\n",
  242. AP_IP.toString(), AP_Netmask.toString(), channel+1);
  243. WiFi.softAP(ssid.c_str(), password.c_str(), channel+1, 0, 4, true);
  244. //
  245. // Conservative settings: 20 MHz, maximum power; this is for
  246. // reliability, not performance.
  247. //
  248. WiFi.setTxPower((wifi_power_t)0);
  249. esp_wifi_set_bandwidth((wifi_interface_t)ESP_IF_WIFI_AP, WIFI_BW_HT20);
  250. WiFi.softAPsetHostname(ssid.c_str());
  251. WiFi.softAPConfig(AP_IP, AP_Gateway, AP_Netmask);
  252. } else {
  253. WiFi.begin(ssid.c_str(), password.c_str());
  254. WiFi.setAutoConnect(true);
  255. WiFi.setAutoReconnect(true);
  256. }
  257. }
  258. void SetupWiFi() {
  259. services_started = false;
  260. WiFi.onEvent(WiFiEvent);
  261. my_sntp_start();
  262. printf("[INFO] Setting up WiFi\n");
  263. wifi_config();
  264. }