here is the code, I didn't write the code for LED yet but that part is fairly simple.
#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif
#include <WiFi.h>
#include <AsyncTCP.h>
#include <DNSServer.h>
#include <ESPAsyncWebServer.h>
#include <DHT.h>
#include "EEPROM.h"
#include <Arduino.h> // for type definitions
#define _DHT_PIN 26
#define _DHTTYPE DHT22
// define two tasks for Blink & AnalogRead
void ReadTemp( void *pvParameters );
void HandleGeneral( void *pvParameters );
DHT dht(_DHT_PIN, _DHTTYPE);
DNSServer dnsServer;
AsyncWebServer server(80);
float current_temp = 0;
bool APMode = false;
String portalTitle = "My ESP32 Hub";
String ssid = "";
String pwd = "";
struct hub_settings_t
{
const char* ssid;
const char* pwd;
} hubSettings;
bool hasWifi = false;
bool isConnected = false;
bool isConnecting = false;
void handleRequest(AsyncWebServerRequest *request) {
if (request->host() != toStringIp(WiFi.softAPIP())) {
if (APMode) {
AsyncResponseStream *response = request->beginResponseStream("text/plain");
response->setCode(302);
response->addHeader("Location", String("http://") + toStringIp(WiFi.softAPIP()));
request->send(response);
}
} else {
AsyncResponseStream *response = request->beginResponseStream("text/html");
response->printf("<!DOCTYPE html><html> <head> <meta charset=\"UTF-8\" name=\"viewport\" content=\"width=device-width,initial-scale=1\"/> <title>%s</title> <style>body, html{margin: 0px; padding: 0px; font-family: Arial, Helvetica, sans-serif; box-sizing: border-box;}nav{background-color: #dc143c; color: #fff; height: 50px; line-height: 50px; font-size: 1.4em; text-align: center;}.content{max-width: 300px; margin: 0 auto; padding-top: 30px;}input{font-size: 1em;}input[type=\"text\"], input[type=\"password\"]{padding: 6px; border: 1px solid #a5a5a5; border-radius: 3px; margin: 6px 0; width: 100%; box-sizing: border-box;}button{font-size: 1em; background-color: #dc143c; color: #fff; padding: 10px 14px; border: none; border-radius: 3px; cursor: pointer; width: 100%;}.field-label{margin-top: 10px; margin-bottom: 10px;}.form-field{margin-top: 10px; margin-bottom: 10px;}</style> </head> <body> <nav>%s</nav> <div class=\"content\">", portalTitle, portalTitle);
if (request->url() == "/") {
response->print("<div> <form action=\"save\" method=\"post\" > <div class=\"field-label\"> SSID: </div><div class=\"form-field\"> <input type=\"text\" name=\"ssid\"/> </div><div class=\"field-label\"> Password: </div><div class=\"form-field\"> <input type=\"password\" name=\"pwd\"/> </div><div><button type=\"submit\">Connect</button></div></form> </div>");
} else if (request->url() == "/save") {
if (request->hasParam("ssid", true)) {
ssid = request->getParam("ssid", true, false)->value();
hubSettings.ssid = ssid.c_str();
}
if (request->hasParam("pwd", true)) {
pwd = request->getParam("pwd", true, false)->value();
hubSettings.pwd = pwd.c_str();
}
Serial.print("wifi credentials received ");
Serial.println(hubSettings.ssid);
Serial.println(hubSettings.pwd);
response->print("<div>Connecting to WiFi</div>");
if (hubSettings.ssid != NULL && hubSettings.pwd != NULL) {
hasWifi = true;
}
}
response->print("</div></body></html>");
request->send(response);
}
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_AP_STA);
WiFi.setAutoConnect(false);
Serial.println("Initializing");
EEPROM.begin(512);
if (!isFirstRun()) {
ReadSettings(1, hubSettings);
}
if (hubSettings.ssid != NULL && hubSettings.pwd != NULL) {
hasWifi = true;
}
dht.begin();
if (!hasWifi) {
SetupWifi();
}
xTaskCreatePinnedToCore(
HandleGeneral
, "HandleGeneral" // A name just for humans
, 1024 // This stack size can be checked & adjusted by reading the Stack Highwater
, NULL
, 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
, NULL
, ARDUINO_RUNNING_CORE);
xTaskCreatePinnedToCore(
ReadTemp
, "ReadTemp" // A name just for humans
, 1024 // This stack size can be checked & adjusted by reading the Stack Highwater
, NULL
, 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
, NULL
, ARDUINO_RUNNING_CORE);
}
void loop()
{
// Empty. Things are done in Tasks.
}
void SetupWifi(void) {
Serial.println("Setting up AP + Captive Portal");
WiFi.softAP("ESP32-Hub", "12345678");
APMode = true;
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
dnsServer.start(53, "*", WiFi.softAPIP());
server.on("/generate_204", HTTP_GET, handleRequest); //Android captive portal. Maybe not needed. Might be handled by notFound handler.
server.on("/fwlink", HTTP_GET, handleRequest); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
server.onNotFound(handleRequest);
server.on("/", HTTP_GET, handleRequest);
server.on("/save", HTTP_POST, handleRequest);
server.begin();
Serial.print("Portal Initialized at ");
Serial.println(WiFi.softAPIP());
}
String toStringIp(IPAddress ip) {
String res = "";
for (int i = 0; i < 3; i++) {
res += String((ip >> (8 * i)) & 0xFF) + ".";
}
res += String(((ip >> 8 * 3)) & 0xFF);
return res;
}
void ReadTemp(void *pvParameters) // This is a task.
{
(void) pvParameters;
for (;;) // A Task shall never return or exit.
{
float t = dht.readTemperature();
if (isnan(t)) {
Serial.println("Failed to read from DHT sensor!");
} else {
current_temp = t;
Serial.print("Current Temperature ");
Serial.println(String(t));
}
vTaskDelay(2000);
}
}
void HandleGeneral(void *pvParameters) // This is a task.
{
(void) pvParameters;
for (;;)
{
if (APMode) {
dnsServer.processNextRequest();
}
if (!isConnected) {
connectWifi();
}
checkWifi();
vTaskDelay(500);
}
}
void connectWifi() {
if (hasWifi && isConnected == false && isConnecting == false) {
Serial.print("connecting to ");
Serial.println(hubSettings.ssid);
Serial.println(hubSettings.pwd);
isConnecting = true;
WiFi.begin(hubSettings.ssid, hubSettings.pwd);
//WiFi.begin(hubSettings.ssid.c_str(), hubSettings.pwd.c_str());
}
}
void checkWifi() {
if (WiFi.status() == WL_CONNECTED) {
if (isConnected == false) {
isConnected = true;
isConnecting = false;
onConnect();
}
} else if ( WiFi.status() == WL_DISCONNECTED) {
if (isConnected == true) {
isConnected = false;
onDisconnect();
}
}
}
void onConnect() {
Serial.println("wifi connected");
Serial.println(WiFi.localIP());
WiFi.enableAP(false);
dnsServer.stop();
APMode = false;
vTaskDelay(100);
SaveSettings(0,false);
SaveSettings(1,hubSettings);
}
void onDisconnect() {
Serial.println("wifi disconnected");
}
bool isFirstRun() {
bool fr = true;
ReadSettings(0, fr);
return fr;
}
template <class T> int SaveSettings(int ee, const T& value)
{
const byte* p = (const byte*)(const void*)&value;
unsigned int i;
EEPROM.begin(sizeof(value));
for (i = 0; i < sizeof(value); i++)
EEPROM.write(ee++, *p++);
EEPROM.commit();
return i;
}
template <class T> int ReadSettings(int ee, T& value)
{
byte* p = (byte*)(void*)&value;
unsigned int i;
EEPROM.begin(sizeof(value));
for (i = 0; i < sizeof(value); i++)
*p++ = EEPROM.read(ee++);
EEPROM.commit();
return i;
}