networking.cpp
1 #include "api.h" 2 #include <config.h> 3 #include <networking/wifi.h> 4 #include <identity.h> 5 6 #include <Arduino.h> 7 #include <WiFi.h> 8 #include <AsyncJson.h> 9 #include <ArduinoJson.h> 10 11 namespace { 12 13 void fill_wireless_status(JsonObject &data) { 14 NetworkStatusSnapshot snapshot = {}; 15 ::networking::wifi::accessSnapshot(&snapshot); 16 data["connected"] = snapshot.connected; 17 data["mode"] = snapshot.ap.active ? "ap_sta" : "sta"; 18 data["tenant"] = config::cloudevents::TENANT; 19 data["sta_ssid"] = snapshot.ssid; 20 data["sta_bssid"] = snapshot.bssid; 21 data["sta_ipv4"] = snapshot.ip; 22 data["wifi_rssi"] = snapshot.rssi; 23 data["ap_active"] = snapshot.ap.active; 24 data["ap_ssid"] = snapshot.ap.ssid; 25 data["ap_ipv4"] = snapshot.ap.ip; 26 data["ap_clients"] = snapshot.ap.clients; 27 data["ap_hostname"] = snapshot.ap.hostname; 28 data["ap_mac"] = snapshot.ap.mac; 29 } 30 31 void handle_wifi(AsyncWebServerRequest *request) { 32 AsyncJsonResponse *response = new AsyncJsonResponse(); 33 JsonObject root = response->getRoot().to<JsonObject>(); 34 35 NetworkStatusSnapshot snapshot = {}; 36 ::networking::wifi::accessSnapshot(&snapshot); 37 root["connected"] = snapshot.connected; 38 root["ssid"] = snapshot.ssid; 39 root["ip"] = snapshot.ip; 40 root["rssi"] = snapshot.rssi; 41 root["mac"] = snapshot.mac; 42 43 response->setLength(); 44 request->send(response); 45 } 46 47 void handle_wireless_status(AsyncWebServerRequest *request) { 48 AsyncJsonResponse *response = new AsyncJsonResponse(); 49 JsonObject root = response->getRoot().to<JsonObject>(); 50 root["ok"] = true; 51 JsonObject data = root["data"].to<JsonObject>(); 52 fill_wireless_status(data); 53 response->setLength(); 54 request->send(response); 55 } 56 57 void handle_wireless_scan(AsyncWebServerRequest *request) { 58 WifiScanResult results[16] = {}; 59 WifiScanCommand command = { 60 .results = results, 61 .max_results = 16, 62 .result_count = -1, 63 }; 64 ::networking::wifi::scan(&command); 65 int16_t count = command.result_count; 66 67 AsyncJsonResponse *response = new AsyncJsonResponse(); 68 JsonObject root = response->getRoot().to<JsonObject>(); 69 root["ok"] = (count >= 0); 70 JsonObject data = root["data"].to<JsonObject>(); 71 data["scan_count"] = (count >= 0) ? count : 0; 72 73 JsonArray networks = data["networks"].to<JsonArray>(); 74 int16_t limit = (count < 16) ? count : 16; 75 for (int16_t index = 0; index < limit; index++) { 76 JsonObject network = networks.add<JsonObject>(); 77 network["ssid"] = results[index].ssid; 78 network["bssid"] = results[index].bssid; 79 network["rssi"] = results[index].rssi; 80 network["channel"] = results[index].channel; 81 network["encryption"] = results[index].encryption; 82 network["open"] = results[index].open; 83 } 84 response->setLength(); 85 request->send(response); 86 } 87 88 void handle_ap_config_get(AsyncWebServerRequest *request) { 89 APSnapshot snapshot = {}; 90 ::networking::wifi::ap::accessSnapshot(&snapshot); 91 92 AsyncJsonResponse *response = new AsyncJsonResponse(); 93 JsonObject root = response->getRoot().to<JsonObject>(); 94 root["ok"] = true; 95 JsonObject data = root["data"].to<JsonObject>(); 96 data["ssid"] = snapshot.ssid; 97 data["enabled"] = snapshot.active; 98 data["active"] = snapshot.active; 99 data["ip"] = snapshot.ip; 100 data["clients"] = snapshot.clients; 101 data["hostname"] = snapshot.hostname; 102 data["mac"] = snapshot.mac; 103 response->setLength(); 104 request->send(response); 105 } 106 107 } 108 109 void services::http::api::networking::registerRoutes(AsyncWebServer &server, 110 AsyncRateLimitMiddleware &scan_limit) { 111 server.on("/api/wifi", HTTP_GET, handle_wifi); 112 server.on("/api/wireless/status", HTTP_GET, handle_wireless_status); 113 server.on("/api/wireless/actions/scan", HTTP_POST, handle_wireless_scan) 114 .addMiddleware(&scan_limit); 115 server.on("/api/ap/config", HTTP_GET, handle_ap_config_get); 116 117 AsyncCallbackJsonWebHandler &ap_config_handler = 118 server.on("/api/ap/config", HTTP_POST, 119 [](AsyncWebServerRequest *request, JsonVariant &json) { 120 JsonObject body = json.as<JsonObject>(); 121 122 if (!body["ssid"].isNull() && !body["password"].isNull()) { 123 APConfigureCommand command = { 124 .config = {}, 125 .snapshot = {}, 126 }; 127 strlcpy(command.config.ssid, body["ssid"] | "", sizeof(command.config.ssid)); 128 strlcpy(command.config.password, body["password"] | "", sizeof(command.config.password)); 129 ::networking::wifi::ap::applyConfig(&command); 130 } 131 132 if (!body["enabled"].isNull()) { 133 APEnabledCommand command = { 134 .enabled = body["enabled"] | true, 135 .snapshot = {}, 136 }; 137 ::networking::wifi::ap::setEnabled(&command); 138 } 139 140 APSnapshot snapshot = {}; 141 ::networking::wifi::ap::accessSnapshot(&snapshot); 142 143 AsyncJsonResponse *response = new AsyncJsonResponse(); 144 JsonObject root = response->getRoot().to<JsonObject>(); 145 root["ok"] = true; 146 JsonObject data = root["data"].to<JsonObject>(); 147 data["ssid"] = snapshot.ssid; 148 data["enabled"] = snapshot.active; 149 data["active"] = snapshot.active; 150 data["ip"] = snapshot.ip; 151 data["clients"] = snapshot.clients; 152 response->setLength(); 153 request->send(response); 154 }); 155 ap_config_handler.setMaxContentLength(512); 156 157 AsyncCallbackJsonWebHandler &connect_handler = 158 server.on("/api/wireless/actions/connect", HTTP_POST, 159 [](AsyncWebServerRequest *request, JsonVariant &json) { 160 JsonObject body = json.as<JsonObject>(); 161 String ssid = body["ssid"] | ""; 162 String password = body["password"] | ""; 163 ssid.trim(); 164 165 if (ssid.isEmpty()) { 166 request->send(400, asyncsrv::T_application_json, 167 "{\"ok\":false,\"error\":{\"code\":\"SSID_REQUIRED\"," 168 "\"message\":\"Missing ssid parameter\"}}"); 169 return; 170 } 171 172 WifiConnectCommand command = { 173 .request = { 174 .ssid = ssid.c_str(), 175 .password = password.c_str(), 176 .enable_ap_fallback = true, 177 }, 178 .result = {}, 179 }; 180 ::networking::wifi::connect(&command); 181 182 AsyncJsonResponse *response = new AsyncJsonResponse(); 183 JsonObject root = response->getRoot().to<JsonObject>(); 184 root["ok"] = command.result.connected; 185 JsonObject data = root["data"].to<JsonObject>(); 186 data["attempted_ssid"] = ssid; 187 data["status_code"] = command.result.status_code; 188 fill_wireless_status(data); 189 190 response->setLength(); 191 request->send(response); 192 }); 193 connect_handler.setMaxContentLength(512); 194 }