HTTP requests from ESP32 to FastAPI hosted on Render

Hello,

I’m new to using Render. I am hosting a python, FastAPI server which should accept HTTP POST requests.
My goal is to be able to send POST from ESP32. This is my code:

#include <ArduinoJson.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include "DFRobot_BloodOxygen_S.h"

// Wi-Fi settings
const char *ssid = "...";
const char *password = "...";

// API server data
const char *serverAddress = "https://scir-api-server.onrender.com";
const int serverPort = 443;

// Initialize WiFi client
//WiFiClient client;
WiFiClientSecure client;

// I2C communication settings
#define I2C_ADDRESS    0x57
DFRobot_BloodOxygen_S_I2C MAX30102(&Wire ,I2C_ADDRESS);

// Define pin for LED signaling
#define LED_PIN 2

void setup() {
  Serial.begin(115200);  // Serial port for monitoring
  delay(100);

  //client.setInsecure();
  
  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  Serial.print("Connecting to Wi-Fi");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println(".");
  }
  Serial.println("Connected to Wi-Fi");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  
  // Initialize the sensor
  while (false == MAX30102.begin()) {
    Serial.println("Sensor initialization failed!");
    delay(1000);
  }
  Serial.println("Sensor initialization successful!");
  Serial.println("Start measuring...");
  MAX30102.sensorStartCollect();
}

void loop() {
  // Check Wi-Fi connection
  if (WiFi.status() == WL_CONNECTED) {
    // Take measurements
    MAX30102.getHeartbeatSPO2();
  
    // Check if SPO2 and HR values are within the appropriate ranges
    if (MAX30102._sHeartbeatSPO2.SPO2 >= 40 && MAX30102._sHeartbeatSPO2.SPO2 <= 100 && // Extended range for adults (realistically, values are always 94-100)
        MAX30102._sHeartbeatSPO2.Heartbeat >= 10 && MAX30102._sHeartbeatSPO2.Heartbeat <= 200) { // Extended range for adults (realistically, values are always 70-130)
  
      // Prepare the data to send in JSON format - create the document
      StaticJsonDocument<200> jsonDocument;
      // Add sensor ID and measurement results to the document
      // Statistically assigned sensor ID for the project
      jsonDocument["sensor_id"] = "ABC123"; 
      jsonDocument["HR"] = MAX30102._sHeartbeatSPO2.Heartbeat;
      jsonDocument["SPO2"] = MAX30102._sHeartbeatSPO2.SPO2;
      // Additionally, get the temperature measured by the sensor - not very useful in raw form
      // because it measures the body surface temperature, not the core temperature
      jsonDocument["Temperature"] = MAX30102.getTemperature_C(); 
      
      String jsonString;
      serializeJson(jsonDocument, jsonString);
      Serial.println("JSON to send:");
      Serial.println(jsonString);  // Added for debugging

      // Create HTTP client
      HTTPClient http;

      // Create the message 
      http.begin(client, serverAddress, serverPort, "/endpoint_api");
      http.addHeader("Content-Type", "application/json");

      // Send the created message - POST request with data in JSON format
      int httpCode = http.POST(jsonString);

      // Check server response
      if (httpCode > 0) {
        // Print the server response code to the terminal
        Serial.printf("[HTTP] POST... code: %d\n", httpCode);
        if (httpCode == HTTP_CODE_OK) {
          String payload = http.getString();
          Serial.println(payload);
        }
      } else {
        // Print the server response code to the terminal (error)
        Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str());
      }
      
      http.end();

    } else {
      // Print to the terminal that the data from the sensor is incorrect - not sending it
      Serial.println("Incorrect data. Measurement was not sent.");
    }
  }

  // Sensor needs four seconds for one measurement
  delay(4000);
}

However all I get when sending a POST is 400 Bad Request. In logs of the render’s server I don’t see any form of trying to get to server by ESP32.

When I do a CURL, for example:

curl -X POST "https://scir-api-server.onrender.com/endpoint_api" -H "Content-Type: application/json" -d "{ \"id_czujnika\": \"ABC123\", \"HR\": 75, \"SPO2\": 98, \"Temperatura\": 36.5 }"

I can see that it works in logs of the web service.

For ESP32 i think that payload is OK so I started wondering if it’s because of some certificates and HTTPS problems… Any suggestions?

Thanks
Natalia

You could be onto something with the last point in regards to it being certificate.

If you can try a dead simple POST and confirm yourself locally that it works via curl then it would point to being a device issue.

Certainly, for some IoT devices, https being forced makes them incompatible with us since we redirect HTTP → HTTPS

Problem solved!

I had to use WiFiClientSecure instead of WiFiClient and add .setInsecure(). setInsecure() is probably not right solution for production environment but since I’m doing an academic project it is OK.

Thanks for engagement in the topic!

1 Like

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