generated from ben/template
268 lines
6.9 KiB
C++
268 lines
6.9 KiB
C++
#include <WiFi.h>
|
|
#include <WebServer.h>
|
|
#include <Preferences.h>
|
|
|
|
Preferences prefs;
|
|
WebServer server(80);
|
|
|
|
// 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";
|
|
|
|
// 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;
|
|
|
|
unsigned long reset_press_start = 0;
|
|
bool reset_armed = false;
|
|
|
|
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 valid_ipv4(const String& s) {
|
|
IPAddress ip;
|
|
return ip.fromString(s);
|
|
}
|
|
|
|
void handle_root() {
|
|
String page =
|
|
"<!doctype html>"
|
|
"<html><head>"
|
|
"<meta name='viewport' content='width=device-width,initial-scale=1'>"
|
|
"<title>baby monitor setup</title>"
|
|
"<style>"
|
|
"body{font-family:sans-serif;max-width:520px;margin:2rem auto;padding:0 1rem;}"
|
|
"input{width:100%;padding:.6rem;margin:.2rem 0 1rem 0;box-sizing:border-box;}"
|
|
"button{padding:.7rem 1rem;margin-right:.5rem;}"
|
|
"code{background:#eee;padding:.1rem .3rem;}"
|
|
"</style>"
|
|
"</head><body>"
|
|
"<h2>baby monitor setup</h2>"
|
|
"<p>connect to ap <code>" + String(AP_SSID) + "</code> then browse to <code>192.168.4.1</code>.</p>"
|
|
"<form method='post' action='/save'>"
|
|
"<label>wifi ssid</label>"
|
|
"<input name='ssid' value='" + html_escape(wifi_ssid) + "'>"
|
|
"<label>wifi password</label>"
|
|
"<input name='pwd' type='password' value='" + html_escape(wifi_password) + "'>"
|
|
"<label>destination ip</label>"
|
|
"<input name='destip' value='" + html_escape(dest_ip_str) + "'>"
|
|
"<label>udp port</label>"
|
|
"<input name='port' value='" + String(udp_port) + "'>"
|
|
"<button type='submit'>save and reboot</button>"
|
|
"</form>"
|
|
"<form method='post' action='/clear' onsubmit='return confirm(\"clear saved config?\");'>"
|
|
"<button type='submit'>clear saved config</button>"
|
|
"</form>"
|
|
"<p><a href='/status'>view status json</a></p>"
|
|
"</body></html>";
|
|
|
|
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);
|
|
}
|
|
|
|
void reboot_to_setup_mode() {
|
|
Serial.println("clearing config and rebooting to setup mode...");
|
|
clear_config();
|
|
delay(250);
|
|
ESP.restart();
|
|
}
|
|
|
|
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",
|
|
"<html><body><h3>saved. rebooting...</h3></body></html>");
|
|
delay(1000);
|
|
ESP.restart();
|
|
}
|
|
|
|
void handle_clear() {
|
|
clear_config();
|
|
server.send(200, "text/html",
|
|
"<html><body><h3>config cleared. rebooting...</h3></body></html>");
|
|
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.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);
|
|
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.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);
|
|
return true;
|
|
}
|
|
|
|
Serial.println("wifi connect failed");
|
|
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);
|
|
|
|
pinMode(RESET_PIN, INPUT_PULLUP);
|
|
|
|
load_config();
|
|
|
|
if (!try_connect_wifi()) {
|
|
start_config_ap();
|
|
}
|
|
}
|
|
|
|
void loop() {
|
|
check_reset_button();
|
|
|
|
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);
|
|
} |