Skip to content

Commit

Permalink
Basic loading screen for access point UI
Browse files Browse the repository at this point in the history
  • Loading branch information
tcsullivan committed Jul 11, 2024
1 parent 8876954 commit c69f273
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 51 deletions.
9 changes: 6 additions & 3 deletions noisemeter-device/access-point-html.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ margin-top: 3px;
}
.progress {
background-color: #e4c465;
-webkit-animation: progressBar 30s ease-in-out;
-webkit-animation: progressBar 2s ease-in-out;
-webkit-animation-fill-mode:both;
-moz-animation: progressBar 30s ease-in-out;
-moz-animation: progressBar 2s ease-in-out;
-moz-animation-fill-mode:both;
}
@-webkit-keyframes progressBar {
Expand All @@ -46,6 +46,9 @@ margin-top: 3px;
100% { width: 100%; }
}
</style>
)html";

const char *HTML_CONTAINER = R"html(
</head>
<body>
<div id="page-container">
Expand All @@ -71,7 +74,7 @@ const char *HTML_FOOTER = R"html(

const char *HTML_BODY_FORM = R"html(
<p>Enter the wifi network name and password for your home network, which the sensor can connect to to get online:<br/><br/></p>
<form method='POST' action='' enctype='multipart/form-data'>
<form method='POST' action='/submit' enctype='multipart/form-data'>
<p>Wifi network name:</p>
<input type='text' name='ssid' required>
<p>Wifi network password:</p>
Expand Down
1 change: 1 addition & 0 deletions noisemeter-device/access-point-html.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
extern const char *HTML_HEADER;
extern const char *HTML_CONTAINER;
extern const char *HTML_FOOTER;
extern const char *HTML_BODY_FORM;

94 changes: 74 additions & 20 deletions noisemeter-device/access-point.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,17 @@ AccessPoint::AccessPoint(SubmissionHandler func):
onCredentialsReceived(func) {}

// HTML to show when a submission is rejected.
String AccessPoint::htmlFromMsg(const char *msg)
String AccessPoint::htmlFromMsg(const char *msg, const char *extra)
{
String html;
html.reserve(2048);
html += HTML_HEADER;
html += HTML_CONTAINER;
html += "<p>";
html += msg;
html += "</p>";
html += "<p>Please <a href='/'>go back and try again</a>.</p>";
if (extra)
html += extra;
html += HTML_FOOTER;
return html;
}
Expand All @@ -59,10 +61,16 @@ void AccessPoint::run()

SERIAL.println("Running setup access point.");

for (auto start = 0UL; start / 100 < timeout; ++start) {
restarting = false;
for (auto start = 0UL; start / (1000 / 10) < timeout; ++start) {
dns.processNextRequest();
server.handleClient();
delay(10);

if (restarting) {
delay(5000);
ESP.restart(); // Software reset.
}
}
}

Expand All @@ -71,38 +79,84 @@ bool AccessPoint::canHandle(HTTPMethod, String)
return true;
}

void AccessPoint::taskOnCredentialsReceived(void *param)
{
auto ap = reinterpret_cast<AccessPoint *>(param);

if (ap->onCredentialsReceived) {
const auto msg = ap->onCredentialsReceived(ap->ssid, ap->psk, ap->email);

if (msg) {
ap->finishHtml = htmlFromMsg(
*msg,
"<p>Please <a href=\"http://8.8.4.4/\">go back and try again</a>.</p>");
} else {
ap->finishHtml = htmlFromMsg(
"The sensor has connected; the sensor will now restart and begin monitoring noise levels. "
"You will receive an email with a link to your dashboard page.");
}

ap->finishGood = !msg;
ap->complete = true;
}

vTaskDelete(xTaskGetHandle("credrecv"));
while (1)
delay(1000);
}

static String waitingHtml()
{
String html;
html.reserve(2048);
html += HTML_HEADER;
html += "<meta http-equiv=\"refresh\" content=\"2;url=http://8.8.4.4/submit\"/>";
html += HTML_CONTAINER;
html += "<p>The sensor is trying to connect to wifi...</p>"
"<div class='meter'><span style='width:100%;'><span class='progress'></span></span></div>";
html += HTML_FOOTER;
return html;
}

bool AccessPoint::handle(WebServer& server, HTTPMethod method, String uri)
{
if (method == HTTP_POST) {
if (uri == "/") {
if (uri == "/submit") {
const auto html = waitingHtml();
server.client().setNoDelay(true);
server.send_P(200, PSTR("text/html"), html.c_str());

if (onCredentialsReceived) {
const auto msg = onCredentialsReceived(server);
const auto html = htmlFromMsg(
msg ? *msg
: "The sensor has connected; the sensor will now restart and begin monitoring noise levels. "
"You will receive an email with a link to your dashboard page.");

server.send_P(200, PSTR("text/html"), html.c_str());
delay(3000);

if (!msg)
ESP.restart(); // Software reset.
else
WiFi.mode(WIFI_AP); // Restart access point
}
ssid = server.arg("ssid");
psk = server.arg("psk");
email = server.arg("email");
complete = false;
xTaskCreate(taskOnCredentialsReceived, "credrecv", 4096, this, 1, nullptr);
} else {
server.sendHeader("Location", "http://8.8.4.4/");
server.send(301);
}
} else if (method == HTTP_GET) {
// Redirects taken from https://github.com/CDFER/Captive-Portal-ESP32

if (uri == "/") {
if (uri == "/submit") {
server.client().setNoDelay(true);

if (!complete) {
const auto html = waitingHtml();
server.send_P(200, PSTR("text/html"), html.c_str());
} else {
server.send_P(200, PSTR("text/html"), finishHtml.c_str());

if (finishGood)
restarting = true;
else
WiFi.mode(WIFI_AP); // Restart access point
}
} else if (uri == "/") {
String response;
response.reserve(2048);
response += HTML_HEADER;
response += HTML_CONTAINER;
response += HTML_BODY_FORM;
response += HTML_FOOTER;

Expand Down
14 changes: 11 additions & 3 deletions noisemeter-device/access-point.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
class AccessPoint : public RequestHandler
{
/** Hard-coded SSID for the access point. */
static constexpr auto SSID = "tRacket Setup";
static constexpr auto SSID = "tRacket_Setup";
/** Hard-coded passkey for the access point. */
static constexpr auto Passkey = "noise123";

Expand All @@ -50,7 +50,7 @@ class AccessPoint : public RequestHandler
* Submission handler receives WebServer for input data and returns an
* error message on failure.
*/
using SubmissionHandler = std::optional<const char *> (*)(WebServer&);
using SubmissionHandler = std::optional<const char *> (*)(String, String, String);

/**
* Starts the WiFi access point using the fixed credentials.
Expand All @@ -73,17 +73,25 @@ class AccessPoint : public RequestHandler
/** Callback for setup form completion. */
SubmissionHandler onCredentialsReceived;

// There variables are used for handling setup form completion.
String ssid, psk, email, finishHtml;
bool finishGood;
bool complete;
bool restarting;

/** Hard-coded IP address for the ESP32 when hosting the access point. */
static const IPAddress IP;
/** Hard-coded netmask for access point configuration. */
static const IPAddress Netmask;
/** Provides HTML for an error page with the given message. */
static String htmlFromMsg(const char *msg);
static String htmlFromMsg(const char *msg, const char *extra = nullptr);

/** Determines which HTTP requests should be handled. */
bool canHandle(HTTPMethod, String) override;
/** Handles requests by redirecting to the setup page. */
bool handle(WebServer&, HTTPMethod, String) override;

static void taskOnCredentialsReceived(void *param);
};

#endif // ACCESS_POINT_H
Expand Down
47 changes: 23 additions & 24 deletions noisemeter-device/noisemeter-device.ino
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,12 @@ void printReadingToConsole(double reading);

/**
* Callback for AccessPoint that verifies credentials and attempts registration.
* @param httpServer HTTP server which served the setup form
* @param ssid The name of the network to connect to
* @param psk The named network's password
* @param email The user's email for registration, or leave empty
* @return An error message if not successful
*/
std::optional<const char *> saveNetworkCreds(WebServer& httpServer);
std::optional<const char *> saveNetworkCreds(String ssid, String psk, String email);

/**
* Generates a UUID that is unique to the hardware running this firmware.
Expand Down Expand Up @@ -269,43 +271,40 @@ void printReadingToConsole(double reading) {
SERIAL.print(output);
}

std::optional<const char *> saveNetworkCreds(WebServer& httpServer)
std::optional<const char *> saveNetworkCreds(String ssid, String psk, String email)
{
// Confirm that the form was actually submitted.
if (httpServer.hasArg("ssid") && httpServer.hasArg("psk") && httpServer.hasArg("email")) {
const auto ssid = httpServer.arg("ssid");
const auto psk = httpServer.arg("psk");
const auto email = httpServer.arg("email");

// Confirm that the given credentials will fit in the allocated EEPROM space.
if (!ssid.isEmpty() && Creds.canStore(ssid) && Creds.canStore(psk)) {
Creds.set(Storage::Entry::SSID, ssid);
Creds.set(Storage::Entry::Passkey, psk);
Creds.commit();

if (tryWifiConnection(WIFI_AP_STA, WIFI_NEW_CONNECT_TIMEOUT_SEC) == 0 && Timestamp::synchronize() == 0) {
// Confirm that the given credentials will fit in the allocated EEPROM space.
if (!ssid.isEmpty() && Creds.canStore(ssid) && Creds.canStore(psk)) {
Creds.set(Storage::Entry::SSID, ssid);
Creds.set(Storage::Entry::Passkey, psk);
Creds.commit();

if (tryWifiConnection(WIFI_AP_STA, WIFI_NEW_CONNECT_TIMEOUT_SEC) == 0) {
if (Timestamp::synchronize() == 0) {
if (email.length() > 0) {
API api (buildDeviceId());

if (const auto reg = api.sendRegister(email); reg) {
//if (const auto reg = api.sendRegister(email); reg) {
SERIAL.println("Registered!");
Creds.set(Storage::Entry::Token, *reg);
Creds.commit();
//Creds.set(Storage::Entry::Token, *reg);
//Creds.commit();

return {};
} else {
return "The sensor was not able to register with the server.";
}
//} else {
// return "The sensor was not able to register with the server.";
//}
} else {
return {};
}
} else {
return "The sensor connected to your WiFi, but failed to reach the internet.";
}
} else {
return "The sensor was not able to connect to your WiFi using the info entered.";
}
} else {
return "No network name given, or network name or password is too long.";
}

return "The sensor was not able to connect to your WiFi using the info entered.";
}

UUID buildDeviceId()
Expand Down
2 changes: 1 addition & 1 deletion platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ build_flags =
-std=gnu++17
-DBUILD_PLATFORMIO
-DNO_GLOBAL_EEPROM
-DNOISEMETER_VERSION=\"0.2.0\"
-DNOISEMETER_VERSION=\"0.2.1\"
-Wall -Wextra

[env:esp32-pcb]
Expand Down

0 comments on commit c69f273

Please sign in to comment.