Hi,
I am trying to create server and client interaction on Microcontroller ESP32. It'll consist of simple HTTP server and a client. So the client will send a POST request to the server, and the server will do some logic with the data it received.
And for more context, here is the server-side code:
#include <WiFi.h>
#include <iostream>
#include <string>
// Replace with your network credentials
const char* ssid = "Steins";
const char* password = "elpsycongroo";
// Set web server port number to 80
WiFiServer server(80);
// Variable to store the HTTP request
String header;
// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0;
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println("Configuring access point...");
// You can remove the password parameter if you want the AP to be open.
// a valid password must have more than 7 characters
WiFi.begin(ssid, password);
Serial.println("Connecting");
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to WiFi network with IP Address: ");
Serial.println(WiFi.localIP());
server.begin();
Serial.println("Server started");
}
void loop(){
WiFiClient client = server.available(); // Listen for incoming clients
if (client) { // If a new client connects,
currentTime = millis();
previousTime = currentTime;
Serial.println("New Client."); // print a message out in the serial port
String currentLine = "";
String requestBody = ""; // make a String to hold incoming data from the client
while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected
currentTime = millis();
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
header += c;
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) {
Serial.print("STATUS REPORT <header> : ");
Serial.println(header);
// Find the Content-Length header
int contentLength = header.indexOf("Content-Length: ");
if (contentLength != -1) {
Serial.print("STATUS REPORT <contentLength> : ");
Serial.println(contentLength);
// Find the end of the Content-Length line
int endOfContentLength = header.indexOf("\r\n", contentLength);
Serial.print("STATUS REPORT <endOfContentLength> : ");
Serial.println(endOfContentLength);
if (endOfContentLength != -1) {
// Extract the Content-Length value as an integer
contentLength = header.substring(contentLength + 16, endOfContentLength).toInt();
int bodyRead = 0;
while (bodyRead < contentLength && client.available()) {
char c = client.read();
requestBody += c;
bodyRead++;
}
}
}
// Separate direction and vehicle id
int sd = requestBody.indexOf('=');
int vd = requestBody.indexOf('&');
String direction = requestBody.substring(sd + 1, vd);
int pos = requestBody.indexOf('=', vd);
String vehicle = requestBody.substring(pos + 1);
// 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:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println("Got it, " + direction + " for : " + vehicle);
client.println();
Serial.println("Request Body : " + requestBody);
Serial.println("Direction : " + direction);
Serial.println("Vehicle : " + vehicle);
// 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
}
}
}
// Clear the header variable
header = "";
// Close the connection
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
}
and here is the client-side code
#include <WiFi.h>
#include <HTTPClient.h>
const char* ssid = "Steins";
const char* password = "elpsycongroo";
//Your Domain name with URL path or IP address with path
const char* serverName = "http://192.168.160.248:80/";
// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastTime = 0;
// Timer set to 10 minutes (600000)
//unsigned long timerDelay = 600000;
// Set timer to 5 seconds (5000)
unsigned long timerDelay = 5000;
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.println("Connecting");
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to WiFi network with IP Address: ");
Serial.println(WiFi.localIP());
Serial.println("Timer set to 5 seconds (timerDelay variable), it will take 5 seconds before publishing the first reading.");
}
void loop() {
//Send an HTTP POST request every 10 minutes
if ((millis() - lastTime) > timerDelay) {
//Check WiFi connection status
if(WiFi.status()== WL_CONNECTED){
WiFiClient client;
HTTPClient http;
// Your Domain name with URL path or IP address with path
http.begin(client, serverName);
// Specify content-type header
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
http.addHeader("Connection", "keep-alive");
// Data to send with HTTP POST
String httpRequestData = "from=sout&id=mill";
// Send HTTP POST request
int httpResponseCode = http.POST(httpRequestData);
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
// Free resources
http.end();
}
else {
Serial.println("WiFi Disconnected");
}
lastTime = millis();
}
}
Now, the server-code is actually working. I tested it using API Tester (mobile apps) to send POST request and the server is able to read and print out the data on serial monitor.
But, when sending the data from client, the server for some reason cannot read/catch the data.
For context, here is what the server printed out when receiving request from :
- API Tester
New Client.
POST / HTTP/1.1
user-agent: apitester.org Android/7.5(641)
accept: */*
Content-Type: application/x-www-form-urlencoded
Content-Length: 17
Host: 192.168.160.248
Connection: Keep-Alive
Accept-Encoding: gzip
STATUS REPORT <header> : POST / HTTP/1.1
user-agent: apitester.org Android/7.5(641)
accept: */*
Content-Type: application/x-www-form-urlencoded
Content-Length: 17
Host: 192.168.160.248
Connection: Keep-Alive
Accept-Encoding: gzip
STATUS REPORT <contentLength> : 123
STATUS REPORT <endOfContentLength> : 141
Request Body : from=nort&id=ambu
Direction : nort
Vehicle : ambu
Client disconnected.
- from Client
New Client.
POST / HTTP/1.1
Host: 192.168.160.248
User-Agent: ESP32HTTPClient
Connection: keep-alive
Accept-Encoding: identity;q=1,chunked;q=0.1,*;q=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 17
STATUS REPORT <header> : POST / HTTP/1.1
Host: 192.168.160.248
User-Agent: ESP32HTTPClient
Connection: keep-alive
Accept-Encoding: identity;q=1,chunked;q=0.1,*;q=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 17
STATUS REPORT <contentLength> : 193
STATUS REPORT <endOfContentLength> : 211
Request Body :
Direction :
Vehicle :
Client disconnected.
I've try asking on other forum and even to chatGPT, but I still cannot really understand where the problem is or why the problem is there.
Both (forum and chatGPT) says the problem lays in how the server index / locate the request body, that's why I try adding the status report to compare them.
request from ESP32 have more character than the one sent by API Tester, but they still have the same difference. So, I don't where to look / from where I could solve this problem.
Any feedback is appreciated. Thank you