Search code examples
c++esp32platformioarduino-esp32

Getting [e][wifigeneric.cpp:739] hostbyname(): dns failed when performing POST request


I am getting started with electronics and microcontrollers programming.

I have made a simple circuit where I use DHT22 sensor to measure temperature and humidity. I have also made my own API in Node and Express (MongoDB as a database). It is very simple API, just two endpoints: one for getting. and one for posting data. I ma able to create succesfull requests using Postman (and with the browser).

Just to be clear, I want to send temperature and humidity to my API, and then do some work with this data on Vue website (I think that this is not relevant at all, but again, just to be clear what I am trying to achieve).

Now I will say what I am using:

Windows 10 OS NodeMCU ESP32 microcontroller DHT22 sensor HTTPClient library (I think this one is causing a problem) PlatformIO with Arduino.h header file Everything is ok, but when I try to send data to my database things fail. I am ALWAYS getting following error

[e][wifigeneric.cpp:739] hostbyname(): dns failed

I have tried to make the POST request using both http://localhost:3000/endpoint and http://127.0.0.1/endpoint (that part is really strange, why I am getting DNS error when using IP address without domain name?).

I have already looked up for the solution on the web. I have come across many similar questions on github, but any of them worked for me). Also, none of them were solving error caused by line 739.

Here I will leave my code. Is is simple and short, so I will post all of it. Please, do not blame me for my c++ skills, I am getting better :D

Thank you in advance, have a nice day or evening.

Kind regards, Bartek.

#include <Arduino.h>
#include <DHT.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <ArduinoJson.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

#define DHTPIN 22
#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);

const char ssid[] = "MY_SSIID";
const char password[] = "MY_WIFI_PASSWORD";
const char apiAddress[] = "http://localhost:3000/reading";

unsigned long lastTime = 0;
unsigned long timerDelay = 60000;

struct sensorReading {
  float temperature;
  float humidity;
  float heatIndex;
};

sensorReading readDataFromSensor();
void sendData(sensorReading * reading);

void setup() {
  Serial.begin(9600);
  dht.begin();

  WiFi.begin(ssid, password);

 WiFi.config(IPAddress(192, 168, 1, 223), IPAddress(192, 168, 1, 1), IPAddress(255, 255, 255, 0));

  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print('.');
  }

}

void loop() {
  if (millis() > lastTime + timerDelay) {
    sensorReading data;
    sensorReading * p_data = NULL;
    data = readDataFromSensor();
    p_data = &data;
    sendData(p_data);
  }
}

sensorReading readDataFromSensor() {
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();
  float heatIndex = dht.computeHeatIndex(temperature, humidity, false);

  if (isnan(temperature) || isnan(humidity)) {
    return sensorReading {};
  }

  const sensorReading dataToReturn {temperature, humidity, heatIndex};
  return dataToReturn;
}

void sendData(sensorReading * reading) {
  using namespace std;

  if(WiFi.status() == WL_CONNECTED) {
    HTTPClient http;

    http.begin(apiAddress, 3000);

    http.addHeader("Content-Type", "application/json");

    DynamicJsonDocument doc(1024);

    doc["temperature"] = reading->temperature;
    doc["humidity"] = reading->humidity;
    doc["heatIndex"] = reading->heatIndex;

    String dataToSend; 

    serializeJson(doc, dataToSend);

    int responseCode = http.POST(dataToSend);

    Serial.println(responseCode);
    http.end();
  } else {
    Serial.print("Ups...");
  }

  lastTime = millis();
}

Solution

  • You're calling the begin() method on http with two arguments, which are meant to be a hostname and a port number (and optionally a URI/path). Instead of passing a hostname, you're passing a full URL, which the HTTP client is attempting to resolve as a hostname.

    The single argument form of http.begin() does take a URL. The form you're calling does not.

    You can confirm this by reading the source code, which allows for these declarations of the begin() method:

        bool begin(WiFiClient &client, String url);
        bool begin(WiFiClient &client, String host, uint16_t port, String uri = "/", bool https = false);
    
    #ifdef HTTPCLIENT_1_1_COMPATIBLE
        bool begin(String url);
        bool begin(String url, const char* CAcert);
        bool begin(String host, uint16_t port, String uri = "/");
        bool begin(String host, uint16_t port, String uri, const char* CAcert);
        bool begin(String host, uint16_t port, String uri, const char* CAcert, const char* cli_cert, const char* cli_key);
    #endif
    

    A big hint to this problem is that you repeated the port number in both the URL and the second argument to http.begin().

    Instead your code should look like either:

        http.begin(apiAddress);
    

    or

    const char apiName[] = "localhost";
    const unsigned apiPort = 3000;
    const char apiPath[] = "reading";
    
    ...
    
        http.begin(apiName, apiPort, apiPath);
    
    

    However - this also will not work because localhost and 127.0.0.1 mean "self" or "the same computer". You'll need to provide the real IP address of the server you're trying to reach; localhost and 127.0.0.1 only refer to it when you're running software on it.