Posting to MongoDB with ESP32 based boards

`Hello experts.
Anyone work with MongoDB?
I’m struggling to make a connection from an ESP32 based board to Mongodb Atlas.
I managed to create a serverless endpoint in Mongodb and I have successfully used an HTTP POST json request to add data to a Mongodb using the online “Postman” tool. So in theory the endpoint works.
Coding that up in the Arduino IDE world is a different story for me. In searching for solutions I’ve read about different ports, WifiSecureClient vs WifiClient declarations, certificates (that Postman didn’t need) and I’ve tried different combinations but always get a return of -1 which I believe is connection refusal.
The few examples I’ve encountered are either slightly out of date or just a different enough not to be the answer I seek. I’ve never seen a Arduino example using the serverless Mongo-Atlas endpoints for example.
I suspect it’s how I’m specifying the endpoint in some manner. Probably something simple I don’t understand in the networking.
I’m trying to move from using a MYSQL database to a MongoDB. The code posted here chooses between them with a simple #define and It works fine with the MYSQL path…. I’ve only obscured a few personal details. I left the Mongodb details (that I can change later) open because those details might be key. Can anyone give some guidance?

// include the library

#include <Arduino.h>
#include <WiFiClient.h>
#include <WiFiMulti.h>
#include <WiFi.h>
#include <esp_wifi.h>
#include <HTTPClient.h>

#define xMYSQL 0  //set to 1 to enable sending readings to a MYSQL database...0 implies MongoDB

//------------Server pointers---------------------


// database values defined
#define MySQL_DBASE "http://192.168.1.86/UR_do_solar/urpost-esp-data2.php"  //pointer to php files that reads the data into MYSQL
char serverAddressMY[] = "192.168.1.86";
const char resourceMY[] = "/UR_do_solar/urpost-esp-data2.php";

#define MyMONGO_DBASE "https://us-east-3.aws.data.mongodb-api.com/app/data-grhyj/endpoint/ur_sensor/do/app/application-0-asedf/endpoint"
//#define MyMONGO_DBASE "https://us-east-3.aws.data.mongodb-api.com/app/data-grhyj/endpoint/ur_sensor/do"
char serverAddressMD[] = "us-east-3.aws.data.mongodb-api.com";
const char resourceMD[] = "/app/application-0-asedf/endpoint";
const int  port       = 80;
const int  mdport       = 27017;

String DBASE;



// Wifi network credentials---------------------
const char* ssid = "*********";
const char* password = "*************";


//----------Networking varibles if you need it-------------------------------------------------------------

IPAddress Server_ip(192, 168, 1, 208);  // IP address of this box
IPAddress gateway(192, 168, 1, 254);    // gateway of your network
IPAddress subnet(255, 255, 255, 0);     // subnet mask of your network
IPAddress dns(192, 168, 1, 254);        //dns address needed to help get to internet AND to ntp site below

//message buffering

String postData;  //String to post status data

//Client and Server starts
//WiFiClientSecure WiFiClient;
WiFiClient WiFiClient;


/******************************  Setup *************************************/
/***************************************************************************/
/***************************************************************************/


void setup() {
  Serial.begin(9600);
  //WIFI setup
  WiFi.disconnect(true);
  esp_wifi_start();
  Serial.println("UR LoRa to WiFi bridge");
  WiFi.mode(WIFI_STA);

  WiFi.config(Server_ip, dns, gateway, subnet);  // forces to use the fixed IP
  WiFi.begin(ssid, password);
  delay(1000);
  while (WiFi.status() != WL_CONNECTED) {
    delay(100);
    Serial.print(".");
  }

  Serial.print("Connecting to:   ");
  Serial.print(WiFi.SSID());
  Serial.print("\n");
  Serial.print("This device IP address: ");
  Serial.println(WiFi.localIP());


  //choose the database target
  if (xMYSQL) {
    DBASE = MySQL_DBASE;
  }
  else {
    DBASE = MyMONGO_DBASE;
  }
}
/******************************  Close Setup *************************************/
/******************************  Close Setup *************************************/
/******************************  Close Setup *************************************/
/*********************************************************************************/

void loop() {

    String Bstr;  //string received from sensor
 

    Bstr= "{\"Temp\":\"99.50\",\"DO\":\"55555.00\",\"HWBRD\":\"DO Sensor Solar2 sw:0.0.2\",\"Battery_Voltage_Monitor\":\"4.01\",\"VoltageRange\":\"zLoRa\",\"Charging\":\"15:48\",\"ChargeDone\":\"0\"}\r\n\r\n";
    SendSensorData(Bstr);
  
    delay(40000);
}  //end loop
/******************************  Close Loop *************************************/
/******************************  Close Loop *************************************/
/******************************  Close Loop *************************************/
/*********************************************************************************/


//*****************************   SENSOR  DATA TRANSMITTING   *****************************//
void SendSensorData(String sensor_message) {
  HTTPClient http;  //Declare object of class HTTPClient
  //HttpClient    http(client, serverAddressMD, mdport);  /* changed *******************************/////////
  postData = sensor_message;

  Serial.println(postData);

      http.begin(WiFiClient, DBASE);
  //  http.begin(WiFiClient, serverAddressMD, port, resourceMD);

  String contentType = "application/json" ;/* changed *******************************/////////
  http.addHeader("Content-Type", "application/json");  // SPECIFY JSON
  http.addHeader("apikey",  "6db6305781dc2db2c54b04c4");
  //int httpCode = http.post(resourceMD, contentType, postData);  /* changed *******************************/////////
  int httpCode = http.POST(postData);                  //Send the request

  String payload = http.getString();                   //Get the response payload

  Serial.println(httpCode);  //Print HTTP return code
  Serial.println(payload);   //Print request response payload


  http.end();  //Close connection
}

1 Like

I’m solving my own problem….documenting for others if their search brings them here. I found two related solutions. Atlas-Mongodb does indeed require a more secure communication link above just an API key.
First the Solution(s):
Referencing the original code I posted
a. I needed to change the WifIClient library to the WiFiClientSecure. (.h)
b. I then added the client.setInsecure() function before calling http.begin(…).

That was it!

Alternatively, I found a security certificate on the Mongdb webite...….I set the certificate to a char constant named rootCACertificate and included the function client.setCACert(rootCACertificate) INSTEAD of client.setInsecure() , again before http.begin.

Why did it take so long?:

I was using the following examples as a guide for doing a POST to Mongdb but only ONE mentioned the added security and commented they didn’t understand why it worked. (When I tried that example out originally, it didn’t work…forcing me to try other things. I’m guessing the original failure was only because of an expired certificate). For the examples that do not mention certificates or TSL or anything but an API key, I’m guessing Mongodb security has evolved over time too.
Here were the examples:
//Christmas Lights and Webcams with the MongoDB Data API | MongoDB (mentioned the need for WifIClientSecure.h)
//ESP and MongoDB, sitting in a tree. | by Jim Blackhurst | Medium (no mention of certificate need or WiFiClientSecure.h)
//https://www.donskytech.com/control-your-arduino-iot-projects-with-a-mongodb-database/ (no mention of certificate need or WiFiClientSecure.h)

My success with “Postman” helped pull me off track too. I’m now guessing that the “postman” app handles this security in a hidden manner explaining it’s success and my failure.
Further comments are welcomed….especially my conjectures on my original failures.

1 Like

My success was a somewhat short lived. Indeed I succeeded in connecting the sensor to Mongdb-Atlas through Wifi which was great, but I also wanted to build on that and use a LilyGoTSIM7000G board to extend the range of the sensor by using a LTE network rather than Wifi. So far I have not been able to do so. I'm using the TinyGSM library and ArduinoHttpClient for the LTE part and I managed to get the reading over Twillio and a local LTE network to my MYSQL database. I think that works because its uses http and TCP. However the Mongdb Atlas endpoint I received uses https (and TLS) and I've been unable to make that connection. I've substituted with HTTPClient, BearSSL using both esp32 and arduino versions and I struggle to directly connect with TinyGsm or TinyGsmSecure methods because of typedef incompatibilities. The TinyGsm library has an example of a GET request with https to their own endpoint that I can make work, but changing that to a POST request to Mongodb, which seems simple, I just can't get to work. I keep trying to understand the library sources but the needed knowledge is just outside of my grasp. IF anyone happens on this and knows of a working GSM/LTE https POST request implementation that uses both a API key and authorization certificate, please steer me in that direction.

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