134 lines
5.2 KiB
C++
134 lines
5.2 KiB
C++
|
|
#include "WebUI.h"
|
||
|
|
#include "../util/Version.h"
|
||
|
|
#include <ArduinoJson.h>
|
||
|
|
|
||
|
|
void WebUI::begin(Settings& settings,
|
||
|
|
WiFiManager& wifi,
|
||
|
|
MoistureSensor& moisture,
|
||
|
|
FaceRenderer& face,
|
||
|
|
WebhookService& webhook,
|
||
|
|
unsigned long bootMs) {
|
||
|
|
|
||
|
|
auto sendPortalRedirect = [&]() {
|
||
|
|
String target = String("http://") + wifi.apIp().toString() + "/";
|
||
|
|
_server.sendHeader("Location", target, true);
|
||
|
|
_server.send(302, "text/plain", "");
|
||
|
|
};
|
||
|
|
|
||
|
|
_server.on("/", HTTP_GET, [&]() {
|
||
|
|
String mode = (wifi.mode() == NET_AP_SETUP) ? "Setup AP" : "Station";
|
||
|
|
String wifiSsid = settings.wifiSsid();
|
||
|
|
String currentSsid = wifi.ssid();
|
||
|
|
String page =
|
||
|
|
"<h2>FacePlant</h2>"
|
||
|
|
"<p>Firmware v" + String(PB_VERSION) + "</p>"
|
||
|
|
"<h3>Wi-Fi</h3>"
|
||
|
|
"<p>Mode: " + mode + "</p>"
|
||
|
|
"<p>Connected SSID: " + (currentSsid.length() ? currentSsid : "(not connected)") + "</p>"
|
||
|
|
"<p>Saved SSID: " + (wifiSsid.length() ? wifiSsid : "(none)") + "</p>"
|
||
|
|
"<p>Setup AP: " + String(wifi.setupSsid()) + " / " + wifi.apIp().toString() + "</p>"
|
||
|
|
"<form method='POST' action='/wifi'>"
|
||
|
|
"<label>SSID</label><br>"
|
||
|
|
"<input name='ssid' size='30' value='" + wifiSsid + "'><br>"
|
||
|
|
"<label>Password</label><br>"
|
||
|
|
"<input type='password' name='pass' size='30' value=''><br>"
|
||
|
|
"<small>Leave password blank to keep saved password for the same SSID.</small><br><br>"
|
||
|
|
"<button type='submit' name='action' value='connect'>Connect Wi-Fi</button> "
|
||
|
|
"<button type='submit' name='action' value='forget'>Forget Wi-Fi</button>"
|
||
|
|
"</form><br>"
|
||
|
|
"<form method='POST' action='/config'>"
|
||
|
|
"<label>Plant profile</label><br>"
|
||
|
|
"<select name='plant'>"
|
||
|
|
"<option value='house'>Houseplant</option>"
|
||
|
|
"<option value='succulent'>Succulent</option>"
|
||
|
|
"<option value='herbs'>Herbs</option>"
|
||
|
|
"<option value='fern'>Fern</option>"
|
||
|
|
"<option value='tropical'>Tropical</option>"
|
||
|
|
"</select><br><br>"
|
||
|
|
"<label><input type='checkbox' name='kids' " + String(settings.kidsMode() ? "checked" : "") + "> Kids Mode</label><br><br>"
|
||
|
|
"<label>Webhook URL</label><br>"
|
||
|
|
"<input name='wh' size='40' value='" + settings.webhookUrl() + "'><br>"
|
||
|
|
"<label><input type='checkbox' name='wh_en' " + String(settings.webhookEnabled() ? "checked" : "") + "> Enable webhook</label><br><br>"
|
||
|
|
"<button type='submit'>Save</button>"
|
||
|
|
"</form>"
|
||
|
|
"<p><a href='/status'>Status (JSON)</a></p>"
|
||
|
|
"<p><a href='/update'>OTA Update</a></p>";
|
||
|
|
_server.send(200, "text/html", page);
|
||
|
|
});
|
||
|
|
|
||
|
|
_server.on("/wifi", HTTP_POST, [&]() {
|
||
|
|
String action = _server.hasArg("action") ? _server.arg("action") : "connect";
|
||
|
|
|
||
|
|
if (action == "forget") {
|
||
|
|
wifi.clearAndStartSetupAP();
|
||
|
|
} else {
|
||
|
|
String ssid = _server.hasArg("ssid") ? _server.arg("ssid") : settings.wifiSsid();
|
||
|
|
String pass = "";
|
||
|
|
|
||
|
|
if (_server.hasArg("pass") && _server.arg("pass").length() > 0) {
|
||
|
|
pass = _server.arg("pass");
|
||
|
|
} else if (ssid == settings.wifiSsid()) {
|
||
|
|
pass = settings.wifiPass();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (ssid.length() > 0) wifi.saveAndConnect(ssid, pass);
|
||
|
|
}
|
||
|
|
|
||
|
|
_server.sendHeader("Location", "/");
|
||
|
|
_server.send(303);
|
||
|
|
});
|
||
|
|
|
||
|
|
_server.on("/config", HTTP_POST, [&]() {
|
||
|
|
if (_server.hasArg("plant")) settings.setPlantProfile(_server.arg("plant"));
|
||
|
|
settings.setKidsMode(_server.hasArg("kids"));
|
||
|
|
settings.setWebhookEnabled(_server.hasArg("wh_en"));
|
||
|
|
if (_server.hasArg("wh")) settings.setWebhookUrl(_server.arg("wh"));
|
||
|
|
_server.sendHeader("Location", "/");
|
||
|
|
_server.send(303);
|
||
|
|
});
|
||
|
|
|
||
|
|
_server.on("/status", HTTP_GET, [&]() {
|
||
|
|
JsonDocument doc;
|
||
|
|
doc["device"] = "FacePlant";
|
||
|
|
doc["version"] = PB_VERSION;
|
||
|
|
doc["net_mode"] = (wifi.mode() == NET_AP_SETUP) ? "setup_ap" : "sta";
|
||
|
|
doc["setup_ssid"] = wifi.setupSsid();
|
||
|
|
doc["ip"] = wifi.ip().toString();
|
||
|
|
doc["ssid"] = wifi.ssid();
|
||
|
|
doc["saved_ssid"] = settings.wifiSsid();
|
||
|
|
doc["wifi_connected"] = wifi.connected();
|
||
|
|
doc["moisture_pct"] = moisture.percent();
|
||
|
|
doc["raw"] = moisture.raw();
|
||
|
|
doc["kids_mode"] = settings.kidsMode();
|
||
|
|
doc["dead_mode"] = face.isDeadMode();
|
||
|
|
doc["uptime_ms"] = millis() - bootMs;
|
||
|
|
|
||
|
|
String out;
|
||
|
|
serializeJson(doc, out);
|
||
|
|
_server.send(200, "application/json", out);
|
||
|
|
});
|
||
|
|
|
||
|
|
// Captive portal compatibility endpoints used by common OS network checkers.
|
||
|
|
_server.on("/generate_204", HTTP_GET, [&]() { sendPortalRedirect(); }); // Android
|
||
|
|
_server.on("/gen_204", HTTP_GET, [&]() { sendPortalRedirect(); }); // Android alt
|
||
|
|
_server.on("/hotspot-detect.html", HTTP_GET, [&]() { sendPortalRedirect(); }); // iOS/macOS
|
||
|
|
_server.on("/library/test/success.html", HTTP_GET, [&]() { sendPortalRedirect(); });
|
||
|
|
_server.on("/ncsi.txt", HTTP_GET, [&]() { sendPortalRedirect(); }); // Windows
|
||
|
|
_server.on("/connecttest.txt", HTTP_GET, [&]() { sendPortalRedirect(); }); // Windows alt
|
||
|
|
_server.on("/fwlink", HTTP_GET, [&]() { sendPortalRedirect(); }); // Windows alt
|
||
|
|
|
||
|
|
_server.onNotFound([&]() {
|
||
|
|
if (wifi.mode() == NET_AP_SETUP) {
|
||
|
|
sendPortalRedirect();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
_server.send(404, "text/plain", "Not found");
|
||
|
|
});
|
||
|
|
|
||
|
|
_server.begin();
|
||
|
|
}
|
||
|
|
|
||
|
|
void WebUI::loop() {
|
||
|
|
_server.handleClient();
|
||
|
|
}
|