From d4654e6147d3dd48cd42d585106df0290c125e3b Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Sat, 11 May 2024 13:04:45 -0400 Subject: [PATCH] setup form: email field, rejection path; store api token --- noisemeter-device/access-point.cpp | 26 ++++++++++++++++++++----- noisemeter-device/access-point.h | 12 ++++++++++-- noisemeter-device/noisemeter-device.ino | 11 ++++++----- noisemeter-device/storage.h | 3 ++- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/noisemeter-device/access-point.cpp b/noisemeter-device/access-point.cpp index eb94c9c..b333573 100644 --- a/noisemeter-device/access-point.cpp +++ b/noisemeter-device/access-point.cpp @@ -43,9 +43,11 @@ const char *AccessPoint::htmlSetup = "

Noise Meter Setup

" "
" "

SSID:

" - "" + "" "

Password:

" - "" + "" + "

Email:

" + "" "" "
" HTML_FOOTER; @@ -57,6 +59,13 @@ const char *AccessPoint::htmlSubmit = "

Connecting...

" HTML_FOOTER; +// HTML to show when a submission is rejected. +const char *AccessPoint::htmlSubmitFailed = + HTML_HEADER + "

Noise Meter Setup

" + "

Invalid setup form input! Please go back and try again.

" + HTML_FOOTER; + [[noreturn]] void AccessPoint::run() { @@ -88,9 +97,16 @@ bool AccessPoint::handle(WebServer& server, HTTPMethod method, String uri) if (method == HTTP_POST) { if (uri == "/") { server.client().setNoDelay(true); - server.send_P(200, PSTR("text/html"), htmlSubmit); - if (onCredentialsReceived) - onCredentialsReceived(server); + + if (onCredentialsReceived) { + if (onCredentialsReceived(server)) { + server.send_P(200, PSTR("text/html"), htmlSubmit); + delay(2000); + ESP.restart(); // Software reset. + } else { + server.send_P(200, PSTR("text/html"), htmlSubmitFailed); + } + } } else { server.sendHeader("Location", "http://8.8.4.4/"); server.send(301); diff --git a/noisemeter-device/access-point.h b/noisemeter-device/access-point.h index 54d3239..adfbe92 100644 --- a/noisemeter-device/access-point.h +++ b/noisemeter-device/access-point.h @@ -44,11 +44,17 @@ class AccessPoint : public RequestHandler static constexpr auto Passkey = "noisemeter"; public: + /** + * Submission handler receives WebServer for input data and returns true + * on success, false to reject bad submission. + */ + using SubmissionHandler = bool (*)(WebServer&); + /** * Starts the WiFi access point using the fixed credentials. * @param func Callback to handle user setup form submission. */ - AccessPoint(void (*func)(WebServer&)): + AccessPoint(SubmissionHandler func): server(80), onCredentialsReceived(func) {} @@ -63,7 +69,7 @@ class AccessPoint : public RequestHandler /** Web server object for running the setup form. */ WebServer server; /** Callback for setup form completion. */ - void (*onCredentialsReceived)(WebServer&); + SubmissionHandler onCredentialsReceived; /** Hard-coded IP address for the ESP32 when hosting the access point. */ static const IPAddress IP; @@ -73,6 +79,8 @@ class AccessPoint : public RequestHandler static const char *htmlSetup; /** Hard-coded HTML for the page shown after completing the form. */ static const char *htmlSubmit; + /** Hard-coded HTML for the page shown when rejecting a form submission. */ + static const char *htmlSubmitFailed; /** Determines which HTTP requests should be handled. */ bool canHandle(HTTPMethod, String) override; diff --git a/noisemeter-device/noisemeter-device.ino b/noisemeter-device/noisemeter-device.ino index a4ef60d..eaad012 100644 --- a/noisemeter-device/noisemeter-device.ino +++ b/noisemeter-device/noisemeter-device.ino @@ -86,8 +86,9 @@ void printReadingToConsole(double reading); /** * Callback for AccessPoint that verifies and stores the submitted credentials. * @param httpServer HTTP server which served the setup form + * @return True if successful */ -void saveNetworkCreds(WebServer& httpServer); +bool saveNetworkCreds(WebServer& httpServer); /** * Generates a UUID that is unique to the hardware running this firmware. @@ -298,7 +299,7 @@ void printReadingToConsole(double reading) { SERIAL.println(output); } -void saveNetworkCreds(WebServer& httpServer) { +bool saveNetworkCreds(WebServer& httpServer) { // Confirm that the form was actually submitted. if (httpServer.hasArg("ssid") && httpServer.hasArg("psk")) { const auto ssid = httpServer.arg("ssid"); @@ -308,14 +309,14 @@ void saveNetworkCreds(WebServer& httpServer) { if (!ssid.isEmpty() && Creds.canStore(ssid) && Creds.canStore(psk)) { Creds.set(Storage::Entry::SSID, ssid); Creds.set(Storage::Entry::Passkey, psk); + Creds.set(Storage::Entry::Token, API_TOKEN); Creds.commit(); - - ESP.restart(); // Software reset. + return true; } } - // TODO inform user that something went wrong... SERIAL.println("Error: Invalid network credentials!"); + return false; } UUID buildDeviceId() diff --git a/noisemeter-device/storage.h b/noisemeter-device/storage.h index dc3f9d4..668e555 100644 --- a/noisemeter-device/storage.h +++ b/noisemeter-device/storage.h @@ -40,7 +40,8 @@ class Storage : protected EEPROMClass Checksum = 0, /** Storage CRC32 Checksum */ SSID = Checksum + sizeof(uint32_t), /** User's WiFi SSID */ Passkey = SSID + StringSize, /** User's WiFi passkey */ - TotalSize = Passkey + StringSize /** Marks storage end address */ + Token = Passkey + StringSize, /** Device API token */ + TotalSize = Token + StringSize /** Marks storage end address */ }; /**