#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); }