diff --git a/vtech.org b/vtech.org index 0d079bf..f720f22 100644 --- a/vtech.org +++ b/vtech.org @@ -18624,3 +18624,262 @@ void loop() { try hardcoded station connect if fail, start softap + web portal from portal, optionally save new ssid/pwd and switch to station mode + +* webserver +#+begin_src c++ + #include +#include +#include +#include + +Preferences prefs; +WebServer server(80); + +// touch pad used as boot override / setup trigger +const touch_pad_t touch_pin = TOUCH_PAD_NUM4; // gpio13 +const int touch_threshold = 500; + +// softap fallback +const char* ap_ssid = "baby-monitor-setup"; +const char* ap_password = "setup1234"; + +// saved / editable config +String wifi_ssid = ""; +String wifi_password = ""; +String dest_ip_str = "192.168.1.190"; +uint16_t udp_port = 5004; + +bool config_mode = false; +const unsigned long wifi_connect_timeout_ms = 15000; + +String html_escape(const String& s) { + String out = s; + out.replace("&", "&"); + out.replace("<", "<"); + out.replace(">", ">"); + out.replace("\"", """); + return out; +} + +void load_config() { + prefs.begin("bmcfg", true); + wifi_ssid = prefs.getString("ssid", ""); + wifi_password = prefs.getString("pwd", ""); + dest_ip_str = prefs.getString("destip", "192.168.1.190"); + udp_port = prefs.getUShort("port", 5004); + prefs.end(); +} + +void save_config(const String& ssid, const String& pwd, const String& dest_ip, uint16_t port) { + prefs.begin("bmcfg", false); + prefs.putString("ssid", ssid); + prefs.putString("pwd", pwd); + prefs.putString("destip", dest_ip); + prefs.putUShort("port", port); + prefs.end(); +} + +void clear_config() { + prefs.begin("bmcfg", false); + prefs.clear(); + prefs.end(); +} + +bool force_setup_requested() { + // give touch pad a moment to settle + delay(100); + + uint16_t touch_val = 0; + touch_pad_read(touch_pin, &touch_val); + + Serial.printf("touch boot check: %u\n", touch_val); + return touch_val < touch_threshold; +} + +void handle_root() { + String page = + "" + "" + "" + "baby monitor setup" + "" + "" + "

baby monitor setup

" + "

connect to ap " + String(ap_ssid) + " then browse to 192.168.4.1.

" + "
" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
" + "
" + "" + "
" + "

status json

" + ""; + + server.send(200, "text/html", page); +} + +void handle_status() { + String json = "{"; + json += "\"config_mode\":" + String(config_mode ? "true" : "false") + ","; + json += "\"ap_ssid\":\"" + String(ap_ssid) + "\","; + json += "\"saved_ssid\":\"" + html_escape(wifi_ssid) + "\","; + json += "\"dest_ip\":\"" + html_escape(dest_ip_str) + "\","; + json += "\"udp_port\":" + String(udp_port); + json += "}"; + + server.send(200, "application/json", json); +} + +bool valid_ipv4(const String& s) { + IPAddress ip; + return ip.fromString(s); +} + +void handle_save() { + String new_ssid = server.arg("ssid"); + String new_pwd = server.arg("pwd"); + String new_dest = server.arg("destip"); + uint16_t new_port = (uint16_t)server.arg("port").toInt(); + + if (new_ssid.length() == 0) { + server.send(400, "text/plain", "ssid required"); + return; + } + + if (!valid_ipv4(new_dest)) { + server.send(400, "text/plain", "invalid destination ip"); + return; + } + + if (new_port == 0) { + server.send(400, "text/plain", "invalid udp port"); + return; + } + + save_config(new_ssid, new_pwd, new_dest, new_port); + + server.send(200, "text/html", + "

saved. rebooting...

"); + delay(1000); + esp_restart(); +} + +void handle_clear() { + clear_config(); + server.send(200, "text/html", + "

config cleared. rebooting...

"); + delay(1000); + esp_restart(); +} + +void start_config_ap() { + config_mode = true; + + WiFi.disconnect(true, true); + delay(250); + + WiFi.mode(WIFI_AP); + WiFi.softAP(ap_ssid, ap_password); + + IPAddress ip = WiFi.softAPIP(); + Serial.printf("config ap active\n"); + Serial.printf(" ssid: %s\n", ap_ssid); + Serial.printf(" pass: %s\n", ap_password); + Serial.printf(" ip: %s\n", ip.toString().c_str()); + + server.on("/", HTTP_GET, handle_root); + server.on("/save", HTTP_POST, handle_save); + server.on("/clear", HTTP_POST, handle_clear); + server.on("/status", HTTP_GET, handle_status); + server.begin(); +} + +bool try_connect_wifi() { + if (wifi_ssid.length() == 0) { + Serial.println("no saved wifi ssid"); + return false; + } + + WiFi.disconnect(true, true); + delay(250); + + WiFi.mode(WIFI_STA); + WiFi.begin(wifi_ssid.c_str(), wifi_password.c_str()); + + Serial.printf("connecting to wifi: %s\n", wifi_ssid.c_str()); + + unsigned long start = millis(); + while (WiFi.status() != WL_CONNECTED && + millis() - start < wifi_connect_timeout_ms) { + delay(500); + Serial.print("."); + } + Serial.println(); + + if (WiFi.status() == WL_CONNECTED) { + Serial.printf("connected\n"); + Serial.printf(" ip: %s\n", WiFi.localIP().toString().c_str()); + Serial.printf(" dest ip: %s\n", dest_ip_str.c_str()); + Serial.printf(" udp port: %u\n", udp_port); + return true; + } + + Serial.println("wifi connect failed"); + return false; +} + +void setup() { + Serial.begin(115200); + delay(200); + + touch_pad_init(); + touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_1V); + touch_pad_config(touch_pin, 0); + + load_config(); + + if (force_setup_requested()) { + Serial.println("force setup mode requested"); + start_config_ap(); + return; + } + + if (!try_connect_wifi()) { + start_config_ap(); + } +} + +void loop() { + if (config_mode) { + server.handleClient(); + delay(2); + return; + } + + // placeholder for later normal-mode behavior + static unsigned long last_print = 0; + if (millis() - last_print > 5000) { + Serial.printf("normal mode alive. wifi=%s ip=%s dest=%s:%u\n", + wifi_ssid.c_str(), + WiFi.localIP().toString().c_str(), + dest_ip_str.c_str(), + udp_port); + last_print = millis(); + } + + delay(10); +} +#+end_src diff --git a/web/web.ino b/web/web.ino index a4a88b3..b194bfc 100644 --- a/web/web.ino +++ b/web/web.ino @@ -1,27 +1,29 @@ #include #include #include -#include -preferences prefs; -webserver server(80); +Preferences prefs; +WebServer server(80); -// touch pad used as boot override / setup trigger -const touch_pad_t touch_pin = TOUCH_PAD_NUM4; // gpio13 -const int touch_threshold = 500; +// dedicated reset/setup button: wire gpio27 -> momentary button -> gnd +const int RESET_PIN = 27; +const unsigned long RESET_HOLD_MS = 1000; // softap fallback -const char* ap_ssid = "baby-monitor-setup"; -const char* ap_password = "setup1234"; +const char* AP_SSID = "baby-monitor-setup"; +const char* AP_PASSWORD = "setup1234"; // saved / editable config String wifi_ssid = ""; String wifi_password = ""; String dest_ip_str = "192.168.1.190"; uint16_t udp_port = 5004; - +c:\Users\moses\proj\vtech\mic\mic.ino bool config_mode = false; -const unsigned long wifi_connect_timeout_ms = 15000; +const unsigned long WIFI_CONNECT_TIMEOUT_MS = 15000; + +unsigned long reset_press_start = 0; +bool reset_armed = false; String html_escape(const String& s) { String out = s; @@ -56,15 +58,9 @@ void clear_config() { prefs.end(); } -bool force_setup_requested() { - // give touch pad a moment to settle - delay(100); - - uint16_t touch_val = 0; - touch_pad_read(touch_pin, &touch_val); - - Serial.printf("touch boot check: %u\n", touch_val); - return touch_val < touch_threshold; +bool valid_ipv4(const String& s) { + IPAddress ip; + return ip.fromString(s); } void handle_root() { @@ -81,7 +77,7 @@ void handle_root() { "" "" "

baby monitor setup

" - "

connect to ap " + String(ap_ssid) + " then browse to 192.168.4.1.

" + "

connect to ap " + String(AP_SSID) + " then browse to 192.168.4.1.

" "
" "" "" @@ -96,7 +92,7 @@ void handle_root() { "" "" "
" - "

status json

" + "

view status json

" ""; server.send(200, "text/html", page); @@ -105,7 +101,7 @@ void handle_root() { void handle_status() { String json = "{"; json += "\"config_mode\":" + String(config_mode ? "true" : "false") + ","; - json += "\"ap_ssid\":\"" + String(ap_ssid) + "\","; + json += "\"ap_ssid\":\"" + String(AP_SSID) + "\","; json += "\"saved_ssid\":\"" + html_escape(wifi_ssid) + "\","; json += "\"dest_ip\":\"" + html_escape(dest_ip_str) + "\","; json += "\"udp_port\":" + String(udp_port); @@ -114,9 +110,11 @@ void handle_status() { server.send(200, "application/json", json); } -bool valid_ipv4(const String& s) { - ipaddress ip; - return ip.fromString(s); +void reboot_to_setup_mode() { + Serial.println("clearing config and rebooting to setup mode..."); + clear_config(); + delay(250); + ESP.restart(); } void handle_save() { @@ -145,7 +143,7 @@ void handle_save() { server.send(200, "text/html", "

saved. rebooting...

"); delay(1000); - esp_restart(); + ESP.restart(); } void handle_clear() { @@ -153,7 +151,7 @@ void handle_clear() { server.send(200, "text/html", "

config cleared. rebooting...

"); delay(1000); - esp_restart(); + ESP.restart(); } void start_config_ap() { @@ -163,12 +161,12 @@ void start_config_ap() { delay(250); WiFi.mode(WIFI_AP); - WiFi.softAP(ap_ssid, ap_password); + WiFi.softAP(AP_SSID, AP_PASSWORD); IPAddress ip = WiFi.softAPIP(); - Serial.printf("config ap active\n"); - Serial.printf(" ssid: %s\n", ap_ssid); - Serial.printf(" pass: %s\n", ap_password); + Serial.println("config ap active"); + Serial.printf(" ssid: %s\n", AP_SSID); + Serial.printf(" pass: %s\n", AP_PASSWORD); Serial.printf(" ip: %s\n", ip.toString().c_str()); server.on("/", HTTP_GET, handle_root); @@ -194,14 +192,14 @@ bool try_connect_wifi() { unsigned long start = millis(); while (WiFi.status() != WL_CONNECTED && - millis() - start < wifi_connect_timeout_ms) { + millis() - start < WIFI_CONNECT_TIMEOUT_MS) { delay(500); Serial.print("."); } Serial.println(); if (WiFi.status() == WL_CONNECTED) { - Serial.printf("connected\n"); + Serial.println("connected"); Serial.printf(" ip: %s\n", WiFi.localIP().toString().c_str()); Serial.printf(" dest ip: %s\n", dest_ip_str.c_str()); Serial.printf(" udp port: %u\n", udp_port); @@ -212,28 +210,43 @@ bool try_connect_wifi() { return false; } +void check_reset_button() { + bool pressed = (digitalRead(RESET_PIN) == LOW); + + if (pressed) { + if (!reset_armed) { + reset_armed = true; + reset_press_start = millis(); + Serial.println("reset button pressed..."); + } else if (millis() - reset_press_start >= RESET_HOLD_MS) { + Serial.println("reset hold met"); + reboot_to_setup_mode(); + } + } else { + if (reset_armed) { + Serial.println("reset button released"); + } + reset_armed = false; + reset_press_start = 0; + } +} + void setup() { Serial.begin(115200); delay(200); - touch_pad_init(); - touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_1V); - touch_pad_config(touch_pin, 0); + pinMode(RESET_PIN, INPUT_PULLUP); load_config(); - if (force_setup_requested()) { - Serial.println("force setup mode requested"); - start_config_ap(); - return; - } - if (!try_connect_wifi()) { start_config_ap(); } } void loop() { + check_reset_button(); + if (config_mode) { server.handleClient(); delay(2);