wifi: add WPA2 AP setup API and pairing roadmap
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#include <WebServer.h>
|
||||
#include <Preferences.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_system.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include "config.h"
|
||||
@@ -781,6 +782,13 @@ HardwareSerial DashboardSerial(2);
|
||||
String uartLineBuffer;
|
||||
|
||||
Preferences wifiPrefs;
|
||||
Preferences apPrefs;
|
||||
|
||||
String apSsid = "OverlandController";
|
||||
String apPassword = "";
|
||||
const int AP_PASSWORD_MIN_LEN = 8;
|
||||
const int AP_PASSWORD_MAX_LEN = 63;
|
||||
|
||||
|
||||
const int MAX_WIFI_NETWORKS = 3;
|
||||
String staSsids[MAX_WIFI_NETWORKS];
|
||||
@@ -854,6 +862,147 @@ void clearWifiConfig() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String generateDefaultApPassword() {
|
||||
uint64_t mac = ESP.getEfuseMac();
|
||||
uint32_t a = esp_random();
|
||||
uint32_t b = ((uint32_t)(mac >> 16)) ^ esp_random();
|
||||
|
||||
char buffer[17];
|
||||
snprintf(buffer, sizeof(buffer), "%08lX%08lX", (unsigned long)a, (unsigned long)b);
|
||||
return String(buffer);
|
||||
}
|
||||
|
||||
bool validApSsid(const String& ssid) {
|
||||
return ssid.length() > 0 && ssid.length() <= 32;
|
||||
}
|
||||
|
||||
bool validApPassword(const String& password) {
|
||||
return password.length() >= AP_PASSWORD_MIN_LEN && password.length() <= AP_PASSWORD_MAX_LEN;
|
||||
}
|
||||
|
||||
void loadApConfig() {
|
||||
apPrefs.begin("ap", false);
|
||||
|
||||
apSsid = apPrefs.getString("ssid", "OverlandController");
|
||||
apPassword = apPrefs.getString("password", "");
|
||||
|
||||
if (!validApSsid(apSsid)) {
|
||||
apSsid = "OverlandController";
|
||||
apPrefs.putString("ssid", apSsid);
|
||||
}
|
||||
|
||||
if (!validApPassword(apPassword)) {
|
||||
apPassword = generateDefaultApPassword();
|
||||
apPrefs.putString("password", apPassword);
|
||||
}
|
||||
|
||||
apPrefs.end();
|
||||
}
|
||||
|
||||
void saveApConfig(const String& ssid, const String& password) {
|
||||
apSsid = ssid;
|
||||
apPassword = password;
|
||||
|
||||
apPrefs.begin("ap", false);
|
||||
apPrefs.putString("ssid", apSsid);
|
||||
apPrefs.putString("password", apPassword);
|
||||
apPrefs.end();
|
||||
}
|
||||
|
||||
bool startAccessPoint() {
|
||||
bool ok = WiFi.softAP(apSsid.c_str(), apPassword.c_str());
|
||||
|
||||
if (ok) {
|
||||
Serial.println("AP Started");
|
||||
Serial.print("AP SSID: ");
|
||||
Serial.println(apSsid);
|
||||
Serial.print("AP Password: ");
|
||||
Serial.println(apPassword);
|
||||
Serial.print("AP IP: ");
|
||||
Serial.println(WiFi.softAPIP());
|
||||
} else {
|
||||
Serial.println("AP failed to start");
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void restartAccessPoint() {
|
||||
WiFi.softAPdisconnect(true);
|
||||
delay(250);
|
||||
startAccessPoint();
|
||||
}
|
||||
|
||||
void sendSimpleJsonError(int status, const char* error, const char* detail) {
|
||||
DynamicJsonDocument doc(512);
|
||||
doc["ok"] = false;
|
||||
doc["error"] = error;
|
||||
if (detail && detail[0]) {
|
||||
JsonArray details = doc.createNestedArray("details");
|
||||
details.add(detail);
|
||||
}
|
||||
|
||||
String output;
|
||||
serializeJson(doc, output);
|
||||
server.send(status, "application/json", output);
|
||||
}
|
||||
|
||||
void handleGetApConfig() {
|
||||
DynamicJsonDocument response(512);
|
||||
|
||||
response["ok"] = true;
|
||||
response["ssid"] = apSsid;
|
||||
response["password_set"] = validApPassword(apPassword);
|
||||
response["password_min_length"] = AP_PASSWORD_MIN_LEN;
|
||||
response["password_max_length"] = AP_PASSWORD_MAX_LEN;
|
||||
response["auth"] = "wpa2";
|
||||
|
||||
String output;
|
||||
serializeJson(response, output);
|
||||
server.send(200, "application/json", output);
|
||||
}
|
||||
|
||||
void handleUpdateApConfig() {
|
||||
DynamicJsonDocument doc(512);
|
||||
DeserializationError err = deserializeJson(doc, server.arg("plain"));
|
||||
|
||||
if (err) {
|
||||
sendSimpleJsonError(400, "invalid_json", err.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
String ssid = doc["ssid"] | apSsid;
|
||||
String password = doc["password"] | "";
|
||||
|
||||
ssid.trim();
|
||||
password.trim();
|
||||
|
||||
if (!validApSsid(ssid)) {
|
||||
sendSimpleJsonError(400, "invalid_ap_ssid", "AP SSID must be 1-32 characters.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validApPassword(password)) {
|
||||
sendSimpleJsonError(400, "invalid_ap_password", "AP password must be 8-63 characters.");
|
||||
return;
|
||||
}
|
||||
|
||||
saveApConfig(ssid, password);
|
||||
restartAccessPoint();
|
||||
|
||||
DynamicJsonDocument response(512);
|
||||
response["ok"] = true;
|
||||
response["ssid"] = apSsid;
|
||||
response["password_set"] = true;
|
||||
response["auth"] = "wpa2";
|
||||
response["ap_ip"] = WiFi.softAPIP().toString();
|
||||
|
||||
String output;
|
||||
serializeJson(response, output);
|
||||
server.send(200, "application/json", output);
|
||||
}
|
||||
|
||||
int findNextWifiIndexByPriority(bool tried[]) {
|
||||
int bestIndex = -1;
|
||||
int bestPriority = 1000000;
|
||||
@@ -1327,6 +1476,8 @@ void buildStatusDocument(JsonDocument& doc) {
|
||||
network["wifi_enabled"] = true;
|
||||
network["uart_connected"] = true;
|
||||
network["ap_enabled"] = true;
|
||||
network["ap_ssid"] = apSsid;
|
||||
network["ap_auth"] = "wpa2";
|
||||
network["ap_ip"] = WiFi.softAPIP().toString();
|
||||
network["sta_enabled"] = wifiNetworkCount > 0;
|
||||
network["sta_connected"] = WiFi.status() == WL_CONNECTED;
|
||||
@@ -2229,6 +2380,8 @@ void handleHealth() {
|
||||
|
||||
JsonObject network = doc.createNestedObject("network");
|
||||
network["ap_enabled"] = true;
|
||||
network["ap_ssid"] = apSsid;
|
||||
network["ap_auth"] = "wpa2";
|
||||
network["ap_ip"] = WiFi.softAPIP().toString();
|
||||
network["sta_enabled"] = wifiNetworkCount > 0;
|
||||
network["sta_connected"] = WiFi.status() == WL_CONNECTED;
|
||||
@@ -2836,15 +2989,10 @@ void setup() {
|
||||
initBms();
|
||||
|
||||
loadWifiConfig();
|
||||
loadApConfig();
|
||||
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
bool apResult = WiFi.softAP("OverlandController");
|
||||
|
||||
if (apResult) {
|
||||
Serial.println("AP Started");
|
||||
Serial.print("AP IP: ");
|
||||
Serial.println(WiFi.softAPIP());
|
||||
}
|
||||
startAccessPoint();
|
||||
|
||||
connectStaWifi();
|
||||
|
||||
@@ -2861,6 +3009,8 @@ void setup() {
|
||||
server.on(API_V1("/config/export"), HTTP_GET, handleExportConfig);
|
||||
server.on(API_V1("/config/import"), HTTP_POST, handleImportConfig);
|
||||
server.on(API_V1("/config/wifi"), HTTP_GET, handleGetWifiConfig);
|
||||
server.on(API_V1("/config/ap"), HTTP_GET, handleGetApConfig);
|
||||
server.on(API_V1("/config/ap"), HTTP_POST, handleUpdateApConfig);
|
||||
server.on(API_V1("/config/wifi"), HTTP_POST, handleUpdateWifiConfig);
|
||||
server.on(API_V1("/wifi/connect"), HTTP_POST, handleWifiConnect);
|
||||
server.on(API_V1("/wifi/clear"), HTTP_POST, handleWifiClear);
|
||||
|
||||
Reference in New Issue
Block a user