Http error sometimes. Esp32-c3

Hi, I have some code to get data from a database. It didn't happen before, but I now get an HTTP error sometimes when I request data. Is there anything that I am not seeing that is causing it?

Here I have the database code:


String uploadData(String row, float value) {
  String query = "UPDATE `Snuffel` SET `" + row + "`=" + String(value) + " WHERE Naam = 'Joanne'";
  return executeQuery(query);
}

String downloadData(String row, bool value) {
  String naam;
  if (value){
    naam = "Joanne";
  } else {
    naam = "Ruben";
  }
  String query = "SELECT " + row + " FROM Snuffel WHERE Naam = '" + naam + "'";
  return executeQuery(query);
}

String executeQuery(String query) {

  String returnValue = "";

  String postData = "query=" + query + "&key=secret";

  Serial.println(postData);

  int httpCode = http.POST(postData);
  if (httpCode > 0) { // Controleer op een succesvolle verbinding
    if (httpCode == HTTP_CODE_OK || httpCode == 201) { // Als de verbinding OK is
      String payload = http.getString(); // Ontvang de payload (response body)

      // Zoek de eerste |/| om het sleutelgedeelte over te slaan
      int lineIndex = payload.indexOf("|/|");
      if (lineIndex != -1) {
        // Sla het sleutelgedeelte over
        lineIndex += 3; // Spring over het scheidingsteken naar het begin van de waarde
        // Vind het tweede |/| om het waardegedeelte te krijgen
        int nextIndex = payload.indexOf("|/|", lineIndex);
        if (nextIndex != -1) {
          // Ontvang de waarde
          returnValue = payload.substring(lineIndex, nextIndex);
          // Toon de waarde
        }
      }
    } else {
      Serial.print("Error on HTTP request. HTTP code: ");
      Serial.println(httpCode);
    }
  } else {
    Serial.print("Error on HTTP request. HTTP code: ");
    Serial.println(httpCode);
  }

  return returnValue;
}

void getData() {
  String newData = downloadData("NewData", Joanne);
  if (newData.toInt() == 1) {
    Serial.println("Downloading data...");
    data.putString("Lkleur", downloadData("Lkleur", Joanne));
    data.putString("Kkleur", downloadData("Kkleur", Joanne));
    data.putInt("SlaapTijd", downloadData("SlaapTijd", Joanne).toInt());
    data.putInt("OntwaakTijd", downloadData("OntwaakTijd", Joanne).toInt());
    data.putInt("SlaapDuratie", downloadData("SlaapDuratie", Joanne).toInt());
    uploadData("NewData", 0);
  }
}

Other relevant code:

bool isNear() {if (digitalRead(D8) == HIGH){return true;}else{return false;}}
bool isCharging() {if (digitalRead(D0) == LOW){return true;}else{return false;}}
bool afterSleep() {if (data.getInt("SlaapTijd") < now()){return true;}else{return false;}}
bool beforeWake() {if (now() < data.getInt("OntwaakTijd")){return true;}else{return false;}}

void looped() {
  if (count == 11) {
    if (isCharging()) {
        getData();
    }
    if (active && downloadData("Slapen", !Joanne).toInt() == 1) {
        setLed(data.getString("Lkleur"));
    } else if (active){
        setLed(data.getString("Kkleur"));
    } else {
      setLed("000000");
    }
    count = 0;
  }
  count++;
}

void setup(){

  http.begin("my url");
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");

}

void loop() {
  delay(1000);

  data.begin("Snuffel", false);

  server.handleClient();

  looped();

  if (isWiFiActive()) {
    if (isNear() && !afterSleep() && !active) {

      Serial.println("Touched!");
      offTime = data.getInt("SlaapDuratie") + now();
      active = true;
      setLed(data.getString("Kkleur"));

      if (offTime > 1440) {
        offTime -= 1440;
      }

      Serial.print("Led turning on... offTime: ");
      Serial.println(offTime);

    } else if ((minutesUntil(offTime) > data.getInt("SlaapDuratie")) && !afterSleep()) {active = false;}

  } else {connectWifi();}
  data.end();
}

And my php script on the webserver:

<?php
/*
 * Written By: ShivalWolf
 * Date: 2011/06/03
 * Contact: Shivalwolf@domwolf.net
 *
 * UPDATE 2011/04/05
 * The code now returns a real error message on a bad query with the mysql error number and its error message
 * checks for magic_quotes being enabled and strips slashes if it is. Its best to disable magic quotes still.
 * Checks to make sure the submitted form is a x-www-form-urlencode just so people dont screw with a browser access or atleast try to
 * Forces the output filename to be JSON to conform with standards
 *
 * UPDATE 2011/06/03: Code updated to use the Web Module instead of tinywebdb
 *
 * UPDATE 2013/12/26: minor modifications by Taifun
 *
 * UPDATE 2014/07/11: mysql API (deprecated) replaced by mysqli by Taifun
 *
 * UPDATE 2015/04/30: SELECT logic adjusted (result stored in temp. file removed) by Taifun
 *
 * UPDATE 2016/02/21: Bugfix Undefined variable: csv by Taifun
 *
 * UPDATE 2024-04-24: php 8 error handling update by Taifun
 */

/************************************CONFIG****************************************/
//DATABSE DETAILS//
$DB_ADDRESS="my db";
$DB_USER="my db";
$DB_PASS="my db";
$DB_NAME="my db";

//SETTINGS//
//This code is something you set in the APP so random people cant use it.
$SQLKEY="secret";

/************************************CONFIG****************************************/

//these are just in case setting headers forcing it to always expire
header('Cache-Control: no-cache, must-revalidate');

error_log(print_r($_POST,TRUE));

if( isset($_POST['query']) && isset($_POST['key']) ){                                   //checks if the tag post is there and if its been a proper form post
  //set content type to CSV (to be set here to be able to access this page also with a browser)
  header('Content-type: text/csv');

  if($_POST['key']==$SQLKEY){                                                           //validates the SQL key
    $query=urldecode($_POST['query']);

    try {
      $conn = new mysqli($DB_ADDRESS,$DB_USER,$DB_PASS,$DB_NAME);                       //connect

      try {
        $result=$conn->query($query);                                                   //runs the posted query

        if (strlen(stristr($query,"SELECT"))>0) {                                       //tests if it's a SELECT statement
          $csv = '';                                                                    // bug fix Undefined variable: csv
          while ($fieldinfo = $result->fetch_field()) {
            $csv .= $fieldinfo->name."|/|";
          }
          $csv = rtrim($csv, ",")."\n";
          echo $csv;                                                                    //prints header row
          $csv = '';

          $result->data_seek(0);
          while($row = $result->fetch_assoc()){
            foreach ($row as $key => $value) {
              $csv .= $value."|/|";
            }
            $csv = rtrim($csv, ",")."\n";
          }
          echo $csv;                                                                    //prints all data rows
        } else {
          header("HTTP/1.0 201 Rows");
          echo "AFFECTED ROWS: " . $conn->affected_rows;       //if the query is anything but a SELECT, it will return the number of affected rows
        }
      } catch (mysqli_sql_exception $e) {
        header("HTTP/1.0 400 Bad Request");                                             //sends back a bad request error
        echo "SQL statement: " . $query . "; Error: " . $e->getMessage();              // errors if the query is bad and spits the error back to the client
      }
      $conn->close();                                                                   //closes the DB

    } catch (mysqli_sql_exception $e) {
      header("HTTP/1.0 400 Bad Request");                                               //sends back a bad request error
      echo "Error connecting database: " . $e->getMessage();
    }
  } else {
     header("HTTP/1.0 400 Bad Request");
     echo "Bad Request, Error code 02";                                                 //reports if the secret key was bad
  }
} else {
  header("HTTP/1.0 400 Bad Request");
  echo "Bad Request, Error code 01";
}
?>

Have you tried printing the query that you send to upload the data to ensure that it is properly formatted ?

Yes, nothing weird. This is the postdata. query=SELECT `NewData` FROM Snuffel WHERE Naam = 'Joanne'&key=secret exactly the same with and without error. I access the db from a mobile app via the same file and that works perfectly fine. This used to be working fine as well.

Which HTTP error are your getting? Do you mean a status code beside 200 or 201?

You should also get the payload when httpCode > 0, and print it when there is an unexpected response. (Nothing to get if the HTTP call did not work at all.)

Oh I forgot to send those. I am sometimes getting error -2 and sometimes -1. Most of the time it starts with -2 and after a while it switches to -1. It also mostly gives an error once every 2 querys. Not always, its really inconsistent and I hate that.

You didn't include the declaration for http, but if that is the ESP32 HTTPClient, then the errors are

/// HTTP client errors
#define HTTPC_ERROR_CONNECTION_REFUSED  (-1)
#define HTTPC_ERROR_SEND_HEADER_FAILED  (-2)
#define HTTPC_ERROR_SEND_PAYLOAD_FAILED (-3)
#define HTTPC_ERROR_NOT_CONNECTED       (-4)
#define HTTPC_ERROR_CONNECTION_LOST     (-5)
#define HTTPC_ERROR_NO_STREAM           (-6)
#define HTTPC_ERROR_NO_HTTP_SERVER      (-7)
#define HTTPC_ERROR_TOO_LESS_RAM        (-8)
#define HTTPC_ERROR_ENCODING            (-9)
#define HTTPC_ERROR_STREAM_WRITE        (-10)
#define HTTPC_ERROR_READ_TIMEOUT        (-11)

You got basic errors with "the wire", before your actual content

  • -1: could not connect when trying to start a new request
  • -2: trying to send the bytes before the body
    • no longer connected, or
    • did not get confirmation for all the bytes that were sent

What is the timing between these requests? Are any of them close together?

One thing to try is to direct your requests to a different HTTP server, even one that you don't run but expect to be reliable. Just make sure you're not sending confidential data. Depending on exact URL you use for http.begin, you are likely to get http 404 or 401. But that means the HTTP part is working, which is not what is happening with your PHP server.

The timing between them is about 10 seconds. I didn't know those error codes. This makes so much more sense. I have probably messed something up in my wifi code or something. I will try sending something to a different server. Thanks!

I tried a url. It was giving me a 405, but also still -2 code errors.

With ESP32, you should have, under the IDE's Tools menu, "Core Debug Level" (in the 4th section, below the section with Board and Port). Set that to Debug and re-Upload. You should now see more diagnostic messages in the Serial Monitor, including error messages describing the HTTP failures.

At this point, it seems like either your specific board, or your WiFi router. If you have another of the same board, try that. Is there a firmware update to apply? And try a different WiFi, like a coffee shop or your phone as a hotspot.

Never knew that option existed. this is the monitor:

10:56:57.595 -> [ 14991][E][esp32-hal-gpio.c:180] __digitalRead(): IO 2 is not set as GPIO.
10:56:57.595 -> [ 14991][D][HTTPClient.cpp:281] beginInternal(): protocol: http, host: myhost port: 80 url: /Loveuuu.php
10:56:57.629 -> Executing
10:56:57.629 -> Database query: SELECT `NewData` FROM Snuffel WHERE Naam = 'Joanne'
10:56:57.629 -> query=SELECT `NewData` FROM Snuffel WHERE Naam = 'Joanne'&key=urmom
10:56:57.629 -> [ 14992][D][HTTPClient.cpp:552] sendRequest(): request type: 'POST' redirCount: 0
10:56:57.629 -> 
10:56:57.629 -> [ 14993][D][NetworkManager.cpp:83] hostByName(): Clearing DNS cache
10:56:57.629 -> [ 14997][D][NetworkManager.cpp:123] hostByName(): DNS found IPv4 81.169.145.153
10:56:57.669 -> [ 15046][D][HTTPClient.cpp:1090] connect():  connected to myhost :80
10:56:57.740 -> [ 15131][D][HTTPClient.cpp:1235] handleHeaderResponse(): code: 200
10:56:57.740 -> [ 15132][D][HTTPClient.cpp:1242] handleHeaderResponse(): Transfer-Encoding: chunked
10:56:57.740 -> [ 15132][D][HTTPClient.cpp:596] sendRequest(): sendRequest code=200
10:56:57.740 -> 
10:56:57.740 -> [ 15133][D][HTTPClient.cpp:359] disconnect(): still data in buffer (2), clean up.
10:56:57.740 -> 
10:56:57.740 -> [ 15133][D][HTTPClient.cpp:364] disconnect(): tcp keep open for reuse
10:56:57.740 -> 0
10:56:57.740 -> 
10:57:09.278 -> [ 26673][E][esp32-hal-gpio.c:180] __digitalRead(): IO 2 is not set as GPIO.
10:57:09.278 -> [ 26673][D][HTTPClient.cpp:281] beginInternal(): protocol: http, host: myhost  port: 80 url: /Loveuuu.php
10:57:09.317 -> Executing
10:57:09.317 -> Database query: SELECT `NewData` FROM Snuffel WHERE Naam = 'Joanne'
10:57:09.317 -> query=SELECT `NewData` FROM Snuffel WHERE Naam = 'Joanne'&key=urmom
10:57:09.317 -> [ 26674][D][HTTPClient.cpp:552] sendRequest(): request type: 'POST' redirCount: 0
10:57:09.317 -> 
10:57:09.317 -> [ 26675][D][HTTPClient.cpp:1050] connect(): already connected, reusing connection
10:57:09.317 -> [ 26676][D][NetworkClient.cpp:534] connected(): Disconnected: RES: 0, ERR: 128
10:57:09.317 -> [ 26676][W][HTTPClient.cpp:1399] returnError(): error(-2): send header failed
10:57:09.317 -> Error on HTTP request. HTTP code: -2
10:57:09.317 -> 
10:57:09.317 -> [ 26677][D][HTTPClient.cpp:379] disconnect(): tcp is closed
10:57:09.317 -> 

It is saying that it is still connected. I have added a http.end() So I am not sure why it would be connected.

With that I have tried another identical esp32. I am pretty sure it is running different firmware, so that is not the issue. Also tried an hotspot on my phone with 4G.

I also noticed this:

11:31:28.655 -> ============ After Setup End =============
11:31:41.585 -> [ 15595][E][esp32-hal-gpio.c:180] __digitalRead(): IO 2 is not set as GPIO.
11:31:41.585 -> [ 15596][D][HTTPClient.cpp:281] beginInternal(): protocol: http, host: myhost port: 80 url: /Loveuuu.php
11:31:41.585 -> Database query: SELECT `NewData` FROM Snuffel WHERE Naam = 'Joanne'
11:31:41.585 -> query=SELECT `NewData` FROM Snuffel WHERE Naam = 'Joanne'&key=urmom
11:31:41.585 -> [ 15597][D][HTTPClient.cpp:552] sendRequest(): request type: 'POST' redirCount: 0
11:31:41.585 -> 
11:31:41.585 -> [ 15597][D][NetworkManager.cpp:83] hostByName(): Clearing DNS cache
11:31:41.585 -> [ 15601][D][NetworkManager.cpp:123] hostByName(): DNS found IPv4 81.169.145.153
11:31:41.688 -> [ 15722][D][HTTPClient.cpp:1090] connect():  connected to 511982731.swh.strato-hosting.eu:80
11:31:46.702 -> [ 20735][D][HTTPClient.cpp:596] sendRequest(): sendRequest code=-11
11:31:46.702 -> 
11:31:46.702 -> [ 20735][W][HTTPClient.cpp:1399] returnError(): error(-11): read Timeout
11:31:46.702 -> [ 20736][D][HTTPClient.cpp:1401] returnError(): tcp stop
11:31:46.741 -> Error on HTTP request. HTTP code: -11

Not sure if it has anything to do with it?

Well got the answer. It was the duckling esp32 library. It updated to 3.0.0. Downgraded to 2.0.17 and it works flawlessly. I have now about 4 hours remaining to finish my whole project and I haven't solderd a wire... Anyway, thank you sooo much for helping!!

Ah -- 3.0.0 was released 4 days ago. Never upgrade to the next major version, especially at .0.0, in the middle of a project :slight_smile:

Because it does this

    if (_client->available() > 0) {
      log_d("still data in buffer (%d), clean up.\n", _client->available());
      _client->flush();
    }

    if (_reuse && _canReuse) {
      log_d("tcp keep open for reuse");

You can see those messages in the Serial Monitor output you posted.

If you want to pursue using v3.0.0, try setReuse(false)

Yeah well the update message kept popping up, so I was like, sure then. And because of my limited time I will stay with this one :upside_down_face:

Your PHP script is very dangerous because you execute the passed $query without any control or sanitization exposing your server to very easy SQL Injection.

An attacker could do almost anything he want with your database

Yeah well, I think the key is a security layer plus it is a project between me and my girlfriend so I am not worried about someone attacking it.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.