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:
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?