Unable to connect in Ap_mode in esp32 - arduino

I am making and auto connect code for esp32 in which i am trying to get wifi credential from the webpage when it is operated in ap-mode after getting credential it will connected to wifi whose credential are provided in webpage. But problem i am facing is that i am unable to connect my esp module when it is in ap mode here is my code.
#include "SPIFFS.h"
#include <FS.h>
#include <ArduinoJson.h>
#include "WiFi.h"
#include "ESPAsyncWebServer.h"
uint8_t pin_led = 2;
char* ssid = "YOUR_SSID"; //not used
char* password = "YOUR_AP_PASSWORD";
char* mySsid = "YOUR_AP_SSID";
AsyncWebServer server(80);
IPAddress local_ip(192,168,11,4);
IPAddress gateway(192,168,11,1);
IPAddress netmask(255,255,255,0);
char webpage[] PROGMEM = R"=====(
<html>
<head>
</head>
<body>
<form>
<fieldset>
<div>
<label for="ssid">SSID</label>
<input value="" id="ssid" placeholder="SSID">
</div>
<div>
<label for="password">PASSWORD</label>
<input type="password" value="" id="password" placeholder="PASSWORD">
</div>
<div>
<button class="primary" id="savebtn" type="button" onclick="myFunction()">SAVE</button>
</div>
</fieldset>
</form>
</body>
<script>
function myFunction()
{
console.log("button was clicked!");
var ssid = document.getElementById("ssid").value;
var password = document.getElementById("password").value;
var data = {ssid:ssid, password:password};
var xhr = new XMLHttpRequest();
var url = "/settings";
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// Typical action to be performed when the document is ready:
if(xhr.responseText != null){
console.log(xhr.responseText);
}
}
};
xhr.open("POST", url, true);
xhr.send(JSON.stringify(data));
};
</script>
</html>
)=====";
void setup()
{
pinMode(pin_led, OUTPUT);
Serial.begin(115200);
SPIFFS.begin();
wifiConnect();
server.on("/", HTTP_POST, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", webpage);
});
server.on("/toggle", HTTP_POST, [](AsyncWebServerRequest *request){
digitalWrite(pin_led,!digitalRead(pin_led));
request->send(204,"");
});
server.on("/settings", HTTP_POST, [](AsyncWebServerRequest *request){
if(request->hasArg("plain")){
String data = request->arg("plain");//("plain");
DynamicJsonDocument doc(1024);
serializeJson(doc, data);
// DynamicJsonBuffer jBuffer;
//JsonObject jObject = doc.as<JsonObject>();
File configFile = SPIFFS.open("/config.json", "w");
serializeJsonPretty(doc, configFile);
//jObject.printTo(configFile);
configFile.close();
request->send(200, "application/json", "{\"status\" : \"ok\"}");
delay(500);
wifiConnect();
}});
server.begin();
}
void loop()
{
}
void wifiConnect()
{
//reset networking
WiFi.softAPdisconnect(true);
WiFi.disconnect();
delay(1000);
//check for stored credentials
if(SPIFFS.exists("/config.json")){
const char * _ssid = "", *_pass = "";
File configFile = SPIFFS.open("/config.json", "r");
if(configFile){
size_t size = configFile.size();
std::unique_ptr<char[]> buf(new char[size]);
configFile.readBytes(buf.get(), size);
configFile.close();
DynamicJsonDocument doc(1024);
// DynamicJsonBuffer jsonBuffer;
DeserializationError error=deserializeJson(doc, buf.get());
//JsonObject& jObject = doc.as<JsonObject>();
if (error)
{
Serial.print("deserializeJson() failed: ");
Serial.println(error.c_str());
}
else{
_ssid = doc["ssid"];
_pass = doc["password"];
WiFi.mode(WIFI_STA);
WiFi.begin(_ssid, _pass);
unsigned long startTime = millis();
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
digitalWrite(pin_led,!digitalRead(pin_led));
if ((unsigned long)(millis() - startTime) >= 5000) break;
}
}
}
}
if (WiFi.status() == WL_CONNECTED)
{
digitalWrite(pin_led,HIGH);
} else
{
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(local_ip, gateway, netmask);
WiFi.softAP(mySsid, password);
digitalWrite(pin_led,LOW);
}
Serial.println("");
WiFi.printDiag(Serial);
}
Please help me to figure it out

Putting the wifiConnect() as the last command in setup worked for my environment. This program works only under two important preconditions.1. No json on SPIFFS - so make sure during testing you always have a fresh formatted SPIFFS2. No open AP in range, because it will connect to it without pw and no AP_mode would be initiated. There are a lot of more or less working examples for captive portals especially for ESP32 around, but they all have their specific detection problems (e.g. always read the issues on github)

Related

What does an HTTP response code of -5 or -2 mean?

i am writing a code that connects an ESP32 to an Arduino Nano 33 IoT. The ESP32 is acting as some sort of bridge between the client and an Arduino Nano 33 IoT as a server. Both devices are connected to a local network. The ESP32 is acting as both client and server. That means it spits out its static IP address and you can connect to it and then through an HTML web page on that IP address, you can control 4 LEDs connected to the Arduino Nano 33 IoT. The requests will be sent with the HTTP method to the Arduino Nano 33 and the Arduino will turn the LEDs on and off. The ESP32 will then wait for the response code and when it comes, it shows it in the serial monitor. Now I have two problems:
When I make a request, especially at the beginning when the code gets uploaded, it will be executed without any problem, but after that when I want to turn an LED off, often I get a -5 response code and sometimes even -2 (which represents an error in the code) and the LEDs won't turn off.
Even when an LED turns on successfully, I don't get 200 as the response code.
I would appreciate it if someone can help me understand, what these negative response codes are and how can i fix them. You can find the codes I have written in VSCode for both ESP32 and Arduino below.
Thanks,
Ali
P.S.: I'm relatively new to the topic and might need some basic explanations as well :)
ESP32:
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <SPI.h>
#include <SPIFFS.h>
#include <ESPAsyncWebServer.h>
IPAddress ip(192, 168, 0, 32);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 0, 0);
IPAddress nano(192, 168, 0, 33);
AsyncWebServer server(80);
WiFiClient client;
HTTPClient http;
String redState = "";
String greenState = "";
String blueState = "";
String whiteState = "";
String fadeState = "";
uint8_t ledStatus[5];
String processor(const String &var)
{
if(var == "rState"){
if(ledStatus[1] == 1){
redState = "ON";
}
else
{
redState = "OFF";
}
return redState;
}
if(var == "gState"){
if(ledStatus[2] == 1){
greenState = "ON";
}
else
{
greenState = "OFF";
}
return greenState;
}
if(var == "bState"){
if(ledStatus[3] == 1){
blueState = "ON";
}
else
{
blueState = "OFF";
}
return blueState;
}
if(var == "wState"){
if(ledStatus[4] == 1){
whiteState = "ON";
}
else
{
whiteState = "OFF";
}
return whiteState;
}
if(var == "fadeState"){
if(ledStatus[5] == 1){
fadeState = "ON";
}
else
{
fadeState = "OFF";
}
return fadeState;
}
return String();
}
void httpGETRequest(const char* serverName) {
// Your Domain name with URL path or IP address with path
http.begin(client, serverName);
}
String httpGETResponse(int a, bool status) {
// Send HTTP POST request
int httpResponseCode = http.GET();
String payload = "--";
if (httpResponseCode>0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
payload = http.getString();
if (httpResponseCode == 200)
{
ledStatus[a] = status;
}
}
else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
// Free resources
http.end();
return payload;
}
const char* ssid = "opdeckenlicht";
const char* password = "opdeckenlicht";
const char* nano33 = "http://192.168.0.32/";
const char* reconnect = "http://192.168.0.32/reconnect";
const char* redLEDon = "http://192.168.0.32/r/On";
const char* redLEDoff = "http://192.168.0.32/r/Off";
const char* greenLEDon = "http://192.168.0.32/g/On";
const char* greenLEDoff = "http://192.168.0.32/g/Off";
const char* blueLEDon = "http://192.168.0.32/b/On";
const char* blueLEDoff = "http://192.168.0.32/b/Off";
const char* whiteLEDon = "http://192.168.0.32/w/On";
const char* whiteLEDoff = "http://192.168.0.32/w/Off";
const char* fadeLEDon = "http://192.168.0.32/fade/on";
const char* fadeLEDoff = "http://192.168.0.32/fade/off";
void setup() {
Serial.begin(9600);
WiFi.config(ip, gateway, subnet);
Serial.println("");
Serial.print("Connecting to ");
Serial.print(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(" .");
}
// Print local IP address and start web server
Serial.println("");
Serial.println("WiFi connected.");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Initialize SPIFFS
if(!SPIFFS.begin(true)){
Serial.println("An Error has occurred while mounting SPIFFS");
return;
}
}
void loop() {
server.begin();
client.connect(nano, 80);
http.begin(nano33);
// Route to load style.css file
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/style.css", "text/css");
});
server.on("/r/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/style.css", "text/css");
});
server.on("/g/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/style.css", "text/css");
});
server.on("/b/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/style.css", "text/css");
});
server.on("/w/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/style.css", "text/css");
});
server.on("/fade/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/style.css", "text/css");
});
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
Serial.println("Client connected.");
Serial.println("");
request->send(SPIFFS, "/index.html", String(), false, processor);
});
server.on("/reconnect", HTTP_GET, [](AsyncWebServerRequest *request){
httpGETRequest(reconnect);
delay(1000);
client.connect(nano, 80);
http.begin(nano33);
request->send(SPIFFS, "/index.html", String(), false, processor);
});
// Red LED
server.on("/r/on", HTTP_GET, [](AsyncWebServerRequest *request){
httpGETRequest(redLEDon);
delay(5);
httpGETResponse(1, 1);
// ledStatus[1] = 1;
request->send(SPIFFS, "/index.html", String(), false, processor);
});
server.on("/r/off", HTTP_GET, [](AsyncWebServerRequest *request){
httpGETRequest(redLEDoff);
delay(5);
httpGETResponse(1, 0);
// ledStatus[1] = 0;
request->send(SPIFFS, "/index.html", String(), false, processor);
});
// Green LED
server.on("/g/on", HTTP_GET, [](AsyncWebServerRequest *request){
httpGETRequest(greenLEDon);
delay(5);
httpGETResponse(2, 1);
// ledStatus[2] = 1;
request->send(SPIFFS, "/index.html", String(), false, processor);
});
server.on("/g/off", HTTP_GET, [](AsyncWebServerRequest *request){
httpGETRequest(greenLEDoff);
delay(5);
httpGETResponse(2, 0);
// ledStatus[2] = 0;
request->send(SPIFFS, "/index.html", String(), false, processor);
});
// Blue LED
server.on("/b/on", HTTP_GET, [](AsyncWebServerRequest *request){
httpGETRequest(blueLEDon);
delay(5);
httpGETResponse(3, 1);
// ledStatus[3] = 1;
request->send(SPIFFS, "/index.html", String(), false, processor);
});
server.on("/b/off", HTTP_GET, [](AsyncWebServerRequest *request){
httpGETRequest(blueLEDoff);
delay(5);
httpGETResponse(3, 0);
// ledStatus[3] = 0;
request->send(SPIFFS, "/index.html", String(), false, processor);
});
// White LED
server.on("/w/on", HTTP_GET, [](AsyncWebServerRequest *request){
httpGETRequest(whiteLEDon);
delay(5);
httpGETResponse(4, 1);
// ledStatus[4] = 1;
request->send(SPIFFS, "/index.html", String(), false, processor);
});
server.on("/w/off", HTTP_GET, [](AsyncWebServerRequest *request){
httpGETRequest(whiteLEDoff);
delay(5);
httpGETResponse(4, 0);
// ledStatus[4] = 0;
request->send(SPIFFS, "/index.html", String(), false, processor);
});
// Fade Mode
server.on("/fade/on", HTTP_GET, [](AsyncWebServerRequest *request){
httpGETRequest(fadeLEDon);
delay(3000);
httpGETResponse(5, 1);
// ledStatus[5] = 1;
request->send(SPIFFS, "/index.html", String(), false, processor);
});
server.on("/fade/off", HTTP_GET, [](AsyncWebServerRequest *request){
httpGETRequest(fadeLEDoff);
delay(3000);
httpGETResponse(5, 0);
// ledStatus[5] = 0;
request->send(SPIFFS, "/index.html", String(), false, processor);
});
}
Arduino Nano 33:
#include <Arduino.h>
#include <WiFi.h>
#include <SPI.h>
#include "WebServer.h"
IPAddress ip(192, 168, 0, 33);
IPAddress esp(192, 168, 0, 32);
WiFiServer server(80);
WiFiClient client;
Lightcontroller leds;
Luefter x;
Tempsensor core, driver;
VController vcont;
WebServer::WebServer()
{
ssid = "opdeckenlicht";
password = "opdeckenlicht";
status = WL_IDLE_STATUS;
}
void WebServer::setup()
{
WiFi.config(ip);
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true);
}
String fv = WiFi.firmwareVersion();
if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
Serial.println("Please upgrade the firmware");
}
// attempt to connect to WiFi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to Network named: ");
Serial.println(ssid); // print the network name (SSID);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, password);
// wait 5 seconds for connection:
delay(5000);
}
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print where to go in a browser:
Serial.print("To see this page in action, open a browser to http://");
Serial.println(ip);
server.begin(); // start the web server on port 80
}
void WebServer::begin()
{
leds.setup();
x.setup();
WebServer::setup();
}
void WebServer::run()
{
// put your main code here, to run repeatedly:
client = server.available(); // listen for incoming clients
if (client) { // if you get a client,
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected()) { // loop while the client's connected
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
// Check to see what the client request was:
if (currentLine.endsWith("GET /reconnect")) {
status = WiFi.begin(ssid, password);
server.begin();
Serial.println("Reconnected to: ");
Serial.print(ssid);
}
if (currentLine.endsWith("GET /r/On")) {
leds.control(2,255);
Serial.println("Red LED on.");
}
if (currentLine.endsWith("GET /r/Off")) {
leds.control(2,0);
Serial.println("Red LED off.");
}
if (currentLine.endsWith("GET /g/On")) {
leds.control(3,255);
Serial.println("Green LED on.");
}
if (currentLine.endsWith("GET /g/Off")) {
leds.control(3,0);
Serial.println("Green LED off.");
}
if (currentLine.endsWith("GET /b/On")) {
leds.control(5,255);
Serial.println("Blue LED on.");
}
if (currentLine.endsWith("GET /b/Off")) {
leds.control(5,0);
Serial.println("Blue LED off.");
}
if (currentLine.endsWith("GET /w/On")) {
leds.control(6,255);
Serial.println("White LED on.");
}
if (currentLine.endsWith("GET /w/Off")) {
leds.control(6,0);
Serial.println("White LED off.");
}
if (currentLine.endsWith("GET /fade/on")) {
leds.fade(1);
Serial.println("Fade mode on.");
}
if (currentLine.endsWith("GET /fade/off")) {
leds.fade(0);
Serial.println("Fade LED off.");
}
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
Serial.println("Executing task...");
// break out of the while loop:
break;
}
else { // if you got a newline, then clear currentLine:
currentLine = "";
}
}
else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
}
}
// close the connection:
// client.stop();
// Serial.println("client disconnected");
}
}
Negative returns from the ESP32 HTTPClient library indicate an error while attempting to communicate with the server, rather than an HTTP response code.
The library is open source, so you can find its source code online and see what the return values indicate. -2 means HTTPC_ERROR_SEND_HEADER_FAILED, -5 means HTTPC_ERROR_CONNECTION_LOST. The gist of it is that the network connection to the web server is unstable and unexpectedly goes away.
In this case, you're using the ESPAsyncWebServer. Its README is long but contains critical information, particularly in the "Important Things To Remember" section:
You can not use yield or delay or any function that uses them inside
the callbacks
You directly call delay() in callback handlers, which is disallowed.
This section should spell it out more clearly, but this means it is not safe to re-enter the network stack - it is not safe to call TCP-related functions (including HTTPClient) from a callback. Unfortunately you call HTTPClient functions extensively from web server callbacks, which is why they're failing.
In general for web server callbacks (not just the async library ones), requests should be handled in a short, determinate amount of time. If you need to run a function that can take a long time, you should start that outside the callback. If you need to report its results to the browser accessing the web server you should do that asynchronously.
It might be sufficient to eliminate the delay() calls, but it's still unsafe to call HTTPClient from the async web server callbacks, and it's still a problem to call potentially long running functions while responding to a web server request.
The best approach is to rewrite your code to perform the HTTPClient calls from outside the web server callbacks and to not call delay() in them. One way to do this is to provide state variables which the callbacks set and which the loop() code inspects to decide whether to do the HTTPClient work.
For instance, something like this would move the code out of the callback:
boolean turn_red_len_on = false;
// Red LED
server.on("/r/on", HTTP_GET, [](AsyncWebServerRequest *request) {
turn_red_led_on = true;
request->send(SPIFFS, "/index.html", String(), false, processor);
});
void loop() {
if(turn_red_len_on) {
httpGETRequest(redLEDon);
delay(5);
httpGETResponse(1, 1);
turn_red_led_on = false;
}
}
You'd need to restructure your code similarly to the example I provided, and do this for each callback that needs to use an HTTPClient.
As an alternative, you could switch to the WebServer library that's part of the Arduino framework for the ESP32. This loses many of the advanced features of the async web server but will be more resilient with code that misbehaves by running long running functions in the callbacks.
Perhaps it would be simpler just to put the LEDs on the ESP32?

ESP32 ASyncWifiManager and HHTPSOTAUpdates Libraries are clashing and I can't upload code

I'm running an Async web server on an esp32 and need to run an OTA update where Im grabbing the bin file from a link on a local server. My OTA update code works on another code and my async web server works without the OTA code but when I try to use both the codes together it wont upload. Just wondered if there is an alternative library I can use or an edit I can make to make it all work in one. because the libraries seem to clash.
#include <Arduino.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>
#include "SPIFFS.h"
#include "HttpsOTAUpdate.h"
These are my libraries and this is the error message I get. In the IDE. I would post the full console error message but its super long.
IDE Error
#include <Arduino.h>
#include <WiFi.h>
#include <ESPAsyncWe5bServer.h>
#include <AsyncTCP.h>
#include "SPIFFS.h"
#include "HttpsOTAUpdate.h"
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
TaskHandle_t Task1;
// Search for parameter in HTTP POST request
const char* PARAM_INPUT_1 = "ssid";
const char* PARAM_INPUT_2 = "pass";
const char* PARAM_INPUT_3 = "ip";
const char* PARAM_INPUT_4 = "gateway";
String payload = "";
//Variables to save values from HTML form
String ssid;
String pass;
String ip;
String gateway;
// File paths to save input values permanently
const char* ssidPath = "/ssid.txt";
const char* passPath = "/pass.txt";
const char* ipPath = "/ip.txt";
const char* gatewayPath = "/gateway.txt";
bool apmode = false;
IPAddress localIP;
//IPAddress localIP(192, 168, 1, 200); // hardcoded
// Set your Gateway IP address
IPAddress localGateway;
//IPAddress localGateway(192, 168, 1, 1); //hardcoded
IPAddress subnet(255, 255, 0, 0);
// Timer variables
unsigned long previousMillis = 0;
const long interval = 10000; // interval to wait for Wi-Fi connection (milliseconds)
static const char *url = "http://192.168.1.142/arduinotest/https_OTA_updatesv2.ino.doitESP32devkitV1.bin"; //state url of your firmware image
static const char *server_certificate = "-----BEGIN CERTIFICATE-----\n" \
"MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\n" \
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" \
"DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\n" \
"SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\n" \
"GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\n" \
"AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\n" \
"q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\n" \
"SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\n" \
"Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA\n" \
"a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj\n" \
"/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T\n" \
"AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG\n" \
"CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv\n" \
"bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k\n" \
"c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw\n" \
"VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC\n" \
"ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz\n" \
"MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu\n" \
"Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF\n" \
"AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo\n" \
"uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/\n" \
"wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu\n" \
"X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG\n" \
"PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6\n" \
"KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n" \
"-----END CERTIFICATE-----";
static HttpsOTAStatus_t otastatus;
// Initialize SPIFFS
void initSPIFFS() {
if (!SPIFFS.begin(true)) {
Serial.println("An error has occurred while mounting SPIFFS");
}
Serial.println("SPIFFS mounted successfully");
}
// Read File from SPIFFS
String readFile(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\r\n", path);
File file = fs.open(path);
if(!file || file.isDirectory()){
Serial.println("- failed to open file for reading");
return String();
}
String fileContent;
while(file.available()){
fileContent = file.readStringUntil('\n');
break;
}
return fileContent;
}
void HttpEvent(HttpEvent_t *event)
{
switch(event->event_id) {
case HTTP_EVENT_ERROR:
Serial.println("Http Event Error");
break;
case HTTP_EVENT_ON_CONNECTED:
Serial.println("Http Event On Connected");
break;
case HTTP_EVENT_HEADER_SENT:
Serial.println("Http Event Header Sent");
break;
case HTTP_EVENT_ON_HEADER:
Serial.printf("Http Event On Header, key=%s, value=%s\n", event->header_key, event->header_value);
break;
case HTTP_EVENT_ON_DATA:
break;
case HTTP_EVENT_ON_FINISH:
Serial.println("Http Event On Finish");
break;
case HTTP_EVENT_DISCONNECTED:
Serial.println("Http Event Disconnected");
break;
}
}
void OTAUpdate(){
HttpsOTA.onHttpEvent(HttpEvent);
Serial.println("Starting OTA");
HttpsOTA.begin(url, server_certificate);
Serial.println("Please Wait it takes some time ...");
while(true){
otastatus = HttpsOTA.status();
if(otastatus == HTTPS_OTA_SUCCESS) {
Serial.println("Firmware written successfully. To reboot device, call API ESP.restart() or PUSH restart button on device");
} else if(otastatus == HTTPS_OTA_FAIL) {
Serial.println("Firmware Upgrade Fail");
}
delay(1000);
}
}
// Write file to SPIFFS
void writeFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Writing file: %s\r\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("- failed to open file for writing");
return;
}
if(file.print(message)){
Serial.println("- file written");
} else {
Serial.println("- frite failed");
}
}
// Initialize WiFi
bool initWiFi() {
if(ssid=="" || ip==""){
Serial.println("Undefined SSID or IP address.");
return false;
}
WiFi.mode(WIFI_STA);
localIP.fromString(ip.c_str());
localGateway.fromString(gateway.c_str());
if (!WiFi.config(localIP, localGateway, subnet)){
Serial.println("STA Failed to configure");
return false;
}
WiFi.begin(ssid.c_str(), pass.c_str());
Serial.println("Connecting to WiFi...");
unsigned long currentMillis = millis();
previousMillis = currentMillis;
while(WiFi.status() != WL_CONNECTED) {
currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
Serial.println("Failed to connect.");
return false;
}
}
Serial.println(WiFi.localIP());
apmode = false;
return true;
}
void networkScan(void * pvParameters){
while (true){
String payloadtmp = "";
Serial.println("Scanning");
int n = WiFi.scanNetworks();
if (n == 0) {
Serial.println("no networks found");
} else {
Serial.print(n);
Serial.println(" networks found");
payloadtmp += "[";
for (int i = 0; i < n; ++i) {
payloadtmp += " \"";
payloadtmp += (WiFi.SSID(i));
payloadtmp += "\",";
}
payloadtmp += "]";
payload = payloadtmp;
}
Serial.println(payload);
delay(1000);
}
}
// Replaces placeholder with LED state value
String processor(const String& var) {
if (var == "SSIDLST"){
Serial.println(payload);
return payload;
}
return String();
}
void setup() {
// Serial port for debugging purposes
Serial.begin(115200);
initSPIFFS();
// Set GPIO 2 as an OUTPUT
// Load values saved in SPIFFS
ssid = readFile(SPIFFS, ssidPath);
pass = readFile(SPIFFS, passPath);
ip = readFile(SPIFFS, ipPath);
gateway = readFile (SPIFFS, gatewayPath);
Serial.println(ssid);
Serial.println(pass);
Serial.println(ip);
Serial.println(gateway);
if(initWiFi()) {
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { //default page (settings tab)
request->send(SPIFFS, "/index.html", "text/html", false, processor);
});
server.on("/otaupdates", HTTP_GET, [](AsyncWebServerRequest *request) { //ota updates
request->send(SPIFFS, "/otaupdates.html", "text/html", false, processor);
});
server.on("/updateOTA", HTTP_GET, [](AsyncWebServerRequest *request) { //ota updates
OTAUpdate();
request->send(SPIFFS, "/otaupdates.html", "text/html", false, processor);
});
server.serveStatic("/", SPIFFS, "/");
server.begin();
}
else {
apmode = true;
// Connect to Wi-Fi network with SSID and password
Serial.println("Setting AP (Access Point)");
// NULL sets an open Access Point
WiFi.softAP("ESP-WIFI-MANAGER", NULL);
IPAddress IP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(IP);
// Web Server Root URL
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ //The defult web page on client connect
request->send(SPIFFS, "/wifimanager.html", "text/html", false, processor);
});
server.serveStatic("/", SPIFFS, "/");
server.on("/scan", HTTP_POST, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/wifimanager.html", "text/html", false, processor);
});
server.on("/submit", HTTP_POST, [](AsyncWebServerRequest *request) { // Handles input taking and ssid and password saving once submit is saved.
int params = request->params();
for(int i=0;i<params;i++){
AsyncWebParameter* p = request->getParam(i);
if(p->isPost()){
// HTTP POST ssid value
if (p->name() == PARAM_INPUT_1) {
ssid = p->value().c_str();
Serial.print("SSID set to: ");
Serial.println(ssid);
// Write file to save value
writeFile(SPIFFS, ssidPath, ssid.c_str());
}
// HTTP POST pass value
if (p->name() == PARAM_INPUT_2) {
pass = p->value().c_str();
Serial.print("Password set to: ");
Serial.println(pass);
// Write file to save value
writeFile(SPIFFS, passPath, pass.c_str());
}
// HTTP POST ip value
if (p->name() == PARAM_INPUT_3) {
ip = p->value().c_str();
Serial.print("IP Address set to: ");
Serial.println(ip);
// Write file to save value
writeFile(SPIFFS, ipPath, ip.c_str());
}
// HTTP POST gateway value
if (p->name() == PARAM_INPUT_4) {
gateway = p->value().c_str();
Serial.print("Gateway set to: ");
Serial.println(gateway);
// Write file to save value
writeFile(SPIFFS, gatewayPath, gateway.c_str());
}
//Serial.printf("POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
}
}
request->send(200, "text/plain", "Done. ESP will restart, connect to your router and go to IP address: " + ip);
delay(3000);
ESP.restart();
});
server.begin();
xTaskCreatePinnedToCore(
networkScan, /* Task function. */
"Task1", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
delay(500);
}
}
void loop() {
if (!apmode){
vTaskDelete(Task1);
}
}

ESP32 writeStringEEPROM adds unwanted nembers when I use the letter '&'

I am trying to use this code:
https://github.com/jatocode/WifiConnect/blob/master/WifiConnect/WifiConnect.ino with my ESP32.
The problem is that my wifi network name is "y&t" and when I am trying to use it the progrem saves to the EEPROM "y&26t" insted, with other networks names in my area it dosn't have a problem.
I will be greatful if somebady knows how to solve this problem.
Thanks to #Juraj I solved the problem.
I used in this code a decoder from here: https://circuits4you.com/2019/03/21/esp8266-url-encode-decode-example/
/*
Configuration AP example
The example shows a very simple Configuration Access Point.
created in August 2019
by Juraj Andrassy https://github.com/jandrassy
*/
#include <WiFi.h>
#include <WiFiClient.h>
#include <WiFiAP.h>
#include <Arduino.h>
// #include <String.h>
String urldecode(String str);
unsigned char h2int(char c);
void setup() {
Serial.begin(115200);
delay(500);
// WiFi.disconnect(); // forget the persistent connection to test the Configuration AP
WiFi.persistent(true);
// waiting for connection to remembered Wifi network
Serial.println("Waiting for connection to WiFi");
WiFi.begin(); // use SSID and password stored by SDK
WiFi.waitForConnectResult();
if (WiFi.status() != WL_CONNECTED) {
Serial.println();
Serial.println("Could not connect to WiFi. Starting configuration AP...");
configAP();
} else {
Serial.println("WiFi connected");
}
}
void loop() {
}
void configAP() {
WiFiServer configWebServer(80);
WiFi.mode(WIFI_AP_STA); // starts the default AP (factory default or setup as persistent)
Serial.print("Connect your computer to the WiFi network ");
// Serial.print(WiFi.softAP());
Serial.println();
IPAddress ip = WiFi.softAPIP();
Serial.print("and enter http://");
Serial.print(ip);
Serial.println(" in a Web browser");
configWebServer.begin();
while (true) {
WiFiClient client = configWebServer.available();
if (client) {
char line[64];
int l = client.readBytesUntil('\n', line, sizeof(line));
line[l] = 0;
client.find((char*) "\r\n\r\n");
if (strncmp_P(line, PSTR("POST"), strlen("POST")) == 0) {
l = client.readBytes(line, sizeof(line));
line[l] = 0;
// parse the parameters sent by the html form
const char* delims = "=&";
strtok(line, delims);
const char* ssid = strtok(NULL, delims);
strtok(NULL, delims);
const char* pass = strtok(NULL, delims);
// decoding the ssid and the password for ASCII characters
String ssidS = String(ssid);
String ssidSdecode= urldecode(ssidS);
ssid=const_cast<char*>(ssidSdecode.c_str());
String passS = String(pass);
String passSdecode= urldecode(passS);
pass=const_cast<char*>(passSdecode.c_str());
// send a response before attemting to connect to the WiFi network
// because it will reset the SoftAP and disconnect the client station
client.println(F("HTTP/1.1 200 OK"));
client.println(F("Connection: close"));
client.println(F("Refresh: 10")); // send a request after 10 seconds
client.println();
client.println(F("<html><body><h3>Configuration AP</h3><br>connecting...</body></html>"));
client.stop();
Serial.println();
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
WiFi.begin(ssid, pass);
WiFi.waitForConnectResult();
// configuration continues with the next request
} else {
client.println(F("HTTP/1.1 200 OK"));
client.println(F("Connection: close"));
client.println();
client.println(F("<html><body><h3>Configuration AP</h3><br>"));
int status = WiFi.status();
if (status == WL_CONNECTED) {
client.println(F("Connection successful. Ending AP."));
} else {
client.println(F("<form action='/' method='POST'>WiFi connection failed. Enter valid parameters, please.<br><br>"));
client.println(F("SSID:<br><input type='text' name='i'><br>"));
client.println(F("Password:<br><input type='password' name='p'><br><br>"));
client.println(F("<input type='submit' value='Submit'></form>"));
}
client.println(F("</body></html>"));
client.stop();
if (status == WL_CONNECTED) {
delay(1000); // to let the SDK finish the communication
Serial.println("Connection successful. Ending AP.");
configWebServer.stop();
WiFi.mode(WIFI_STA);
}
}
}
}
}
String urldecode(String str) {
String encodedString="";
char c;
char code0;
char code1;
for (int i =0; i < str.length(); i++) {
c=str.charAt(i);
if (c == '+') {
encodedString+=' ';
} else if (c == '%') {
i++;
code0=str.charAt(i);
i++;
code1=str.charAt(i);
c = (h2int(code0) << 4) | h2int(code1);
encodedString+=c;
} else {
encodedString+=c;
}
yield();
}
return encodedString;
}
unsigned char h2int(char c) {
if (c >= '0' && c <='9') {
return((unsigned char)c - '0');
}
if (c >= 'a' && c <='f') {
return((unsigned char)c - 'a' + 10);
}
if (c >= 'A' && c <='F') {
return((unsigned char)c - 'A' + 10);
}
return(0);
}

ESP8266 EEPROM or FLASH Error: Succesfully connecting to Wifi with false credentials

I am building a small sensor based on the ESP8266. For setting up wifi I host a small webserver, where the user can enter the credentials.
In the setup routine I load the credentials and try to connect to wifi. If the connection fails, the esp creates an AP and the user can enter new credentials.
I got some strange behaviour. Because when I remove the credentials, the esp nevertheless connects successfully to the wifi. But the 'serial.print()' don't show any credentials.
Maybe its a problem with the EEPROM or FLASH I have no idea. I could reproduce this behaviour on several ESPs.
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <EEPROM.h>
ESP8266WebServer server(80);
const char *soft_ap_ssid = "Connect Sensor to MCU";
const char *soft_ap_password = "MySensor";
char ssid[32] = "";
char password[32] = "";
bool wifi_status;
void setup()
{
Serial.begin(115200);
Serial.println();
delay(10);
load_credentials();
wifi_status = setup_wifi(5);
if (!wifi_status)
{
setup_soft_ap();
setup_server();
}
}
void loop()
{
if (!wifi_status)
{
server.handleClient();
}
else
{
Serial.println("Doing Sensor stuff");
delay(2000);
// Remove exsting credentials
for( int i = 0; i < sizeof(ssid); i++ ){
ssid[i] = (char)0;
password[i] = (char)0;
}
save_credentials();
}
}
/*
############## Gernerische Code ########### TODO LIB
*/
bool setup_wifi(int timeout)
{
int timeout_ctr = 0;
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password); //Connect to the WiFi network
while ((WiFi.status() != WL_CONNECTED) && (timeout_ctr < timeout))
{
delay(500);
Serial.println("...");
timeout_ctr++;
}
if (WiFi.status())
{
Serial.print("IP address: ");
Serial.println(WiFi.localIP()); //Print the local IP
}
else
{
Serial.println("Connection to MCU failed, setting up AP.");
}
return (WiFi.status() == WL_CONNECTED);
}
void setup_soft_ap()
{
Serial.println();
Serial.println("Creating WiFi AP...");
WiFi.softAP(soft_ap_ssid, soft_ap_password);
Serial.print("AP \"");
Serial.print(soft_ap_ssid);
Serial.println("\" is online.");
Serial.print("IP address: ");
Serial.println(WiFi.softAPIP());
Serial.println();
}
void setup_server()
{
server.on("/", handle_root); //Associate the landingpage function to the path
server.on("/submit", handle_submit); //Associate the handler function to the path
server.begin(); //Start the server
Serial.println("Server listening");
}
void handle_root()
{
const char *landingpage = "<html><head> <title>ESP8266 Demo</title> <style></style></head><body> <h1>Sensor einrichten</h1> <p> Eingabe der Wifi Daten </p><form action='/submit' method='post'> <input type='text' name='ssid' placeholder='Wifi SSID'> <input type='text' name='pw' placeholder='Wifi Password'> <input type='submit' value='Submit'> </form></body></html>";
server.send(200, "text/html", landingpage);
}
void handle_submit()
{
if (server.args() > 0)
{
Serial.println("POST:");
Serial.println(server.arg("ssid"));
Serial.println(server.arg("pw"));
server.arg("ssid").toCharArray(ssid, sizeof(ssid) - 1);
server.arg("pw").toCharArray(password, sizeof(password) - 1);
Serial.println("credentials:");
Serial.println(ssid);
Serial.println(password);
save_credentials();
}
server.sendHeader("Location", String("/"), true);
server.send(302, "text/plain", "");
}
void load_credentials()
{
EEPROM.begin(512);
EEPROM.get(0, ssid);
EEPROM.get(0 + sizeof(ssid), password);
char ok[2 + 1];
EEPROM.get(0 + sizeof(ssid) + sizeof(password), ok);
EEPROM.end();
if (String(ok) != String("OK"))
{
ssid[0] = 0;
password[0] = 0;
}
Serial.println("Recovered credentials:");
Serial.println(ssid);
Serial.println(password);
}
/** Store WLAN credentials to EEPROM */
void save_credentials()
{
EEPROM.begin(512);
EEPROM.put(0, ssid);
EEPROM.put(0 + sizeof(ssid), password);
char ok[2 + 1] = "OK";
EEPROM.put(0 + sizeof(ssid) + sizeof(password), ok);
EEPROM.commit();
EEPROM.end();
}
By default, the ESP8266 Arduino SDK saves its wifi configuration in flash memory.
This is documented but not called out clearly.
You'll need to call Wifi.persistent() to get the ESP to not save the credentials. This doesn't seem to be called out clearly in a lot of ESP Arduino Core writeups that I've seen.
Try this:
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.persistent(false);
WiFi.begin(ssid, password); //Connect to the WiFi network
while ((WiFi.status() != WL_CONNECTED) && (timeout_ctr < timeout))
You'll probably want to write a bad set of credentials to flash before you update your code to tell the SDK to stop saving them, otherwise I think it will keep using the last saved set. The alternative is to wipe the sector of flash on your ESP where the credentials are stored, which is a lot more work.
There's some documentation on WiFi.persistent() here - which appears to be incorrect - I believe this call operates the way I described (passing false just doesn't store the credentials at all).
If your project is going to be restarting frequently (like going in and out of deep sleep often) I'd definitely use WiFi.persistent(false) to avoid wear on the flash.

Validating the return of an HTTP GET request with arduino IDE and nodemcu-esp-12e

Using the Arduino IDE with the Nodemcu-esp12e module, I created a program which makes an HTTP GET request.
However, I do not know how it would be the right way to deal with the return of this consultation.
I am validating the return with the 'indexOf' function to find out if the return is false/off or true/on.
This is the correct way to validate the return?
Any suggestions for how to improve this code?
#include <ESP8266WiFi.h>
const char* ssid = "mywifiid";
const char* password = "mypassword";
IPAddress host(192,168,0,11);
void setup() {
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
//
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
//
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
//
Serial.print("connecting to ");
Serial.println(host);
//
WiFiClient client;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
return;
}
else{
Serial.println("connection success");
}
//
String get = "http://localhost/Test/GetStatusSensor?idsensor=2";
Serial.println(get);
//
client.print("GET " + get + "\r\nHTTP/1.1\r\nHost: localhost\Test\r\nConnection: keep-alive\r\n\r\n");
//
while(client.available()){
String line = client.readStringUntil('\r');
//
int iret= line.indexOf('on');
//
Serial.print(line);
Serial.println(String(iret));
//
if (iret> 0) {
//
Serial.println("On");
}
else {
Serial.println("Off");
}
}
//
Serial.println();
Serial.println("closing connection");
delay(20000); // 20 sec
}
My suggestion is to use JSON to switch to more structured way of comm. You can define custom data names and types and easily cover them. Take a look it at :
https://github.com/bblanchon/ArduinoJson
Here some JSON example from the HTTPClient example :
DynamicJsonBuffer jsonBuffer(BUFFER_SIZE);
JsonObject& root = jsonBuffer.parseObject(client);
if (!root.success()) {
Serial.println("JSON parsing failed!");
return false;
}
// Here were copy the strings we're interested in
strcpy(userData->name, root["name"]);
strcpy(userData->company, root["company"]["name"]);

Resources