When I break the sketch into parts, I get an error that "was not declared in this scope; did you mean 'MDNS_H'? "

Hello. I am using Arduino IDE 2.0.4 zip version. I decided to break the sketch into parts to make it easier to navigate the code. Everything works together. But when I create a separate tab for the mDNS setup function, it gives an error in the loop that MDNS has not been declared. Although, if I transfer the library connection
#include <ESP8266mDNS.h>
on the first tab, then the sketch compiles normally, without an error. And yet, with an error, it writes additional information that two libraries were found for ESP8266WebServer.h and the one that is in the directory where the zip version is unpacked is used, and not on a global path like this:
C:\Users\user\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.0\libraries\ESP8266WiFi
A similar situation with the portable version of Arduino IDE 1.8.19
Below are the parts into which I broke my sketch.
Main:

//#include <ESP8266mDNS.h>

void setup() {
  Serial.begin(74880);
  conectWiFi();
  init_mDNS();
}

void loop() {
//  MDNS.update();  // I'm getting an error here
  readSensor();
}

Second:

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h> 

const char* ssid = "";
const char* password = "";

ESP8266WebServer WebServerHTTP(80); 

void conectWiFi(){
  WiFi.begin(ssid, password);                         
  WebServerHTTP.begin();  
  while (WiFi.status() != WL_CONNECTED) { 
    delay(1000); Serial.println("waiting...");
    }  
  Serial.println(WiFi.localIP()); 
}

Third:

#include <ESP8266mDNS.h>

const char* host = "Sensor_1";

void init_mDNS(){
  if (MDNS.begin(host)) {
    MDNS.addService("http", "tcp", 80);
    Serial.print(F("Open http://"));
    Serial.print(host);
    Serial.println(F(".local to open the FileSystem Browser"));
  }
}

What is my mistake and is it possible to do without connecting the mDNS library in the main file?

The mistake is described in the error message you forgot to quote.

See My Post #5 in this Thread for a basic guide to breaking up a larger project into smaller modules.

Where was MDNS declared as an object?

Code snippets suck.

I conveyed the general meaning of the error, and most importantly, the error is written in the title of the topic.

When I was looking for ways to break the sketch into parts, I saw your version, but at the moment it is a bit complicated for me, so I started with an easier way and would like to figure it out first.

Maybe the code sucks, but I took it from the ESP8266mDNS library example and there is no MDNS object declaration. This code works in both the example library and my sketch, as long as the sketch is not broken into pieces. Also, I've tried declaring something like this:
MDNS MDNS;
but it did not help, the error remained.

Posting the entire error message verbatim provides far more information than your paraphrased version of it.

If your full code is too big and messy to post, please provide an an MRE. This is the smallest possible complete code that reproduces the problem at hand.

I started to respond to this, and attempt to convey the general meaning of the problem, then thought ... meh.

1 Like

The error is short. Here she is:
Compilation error: 'MDNS' was not declared in this scope; did you mean 'MDNS_H'?
As you can see in the title of the topic it's all written. In addition, I made a full output of the compilation error report in the settings. Here they are:

DISK:\portable\arduino-ide_2.0.4\myscript\Capacitive_Sensor\Capasitive_sensor_post_2\Capasitive_sensor_post_2\Capasitive_sensor_post_2.ino: In function 'void loop()':
DISK:\portable\arduino-ide_2.0.4\myscript\Capacitive_Sensor\Capasitive_sensor_post_2\Capasitive_sensor_post_2\Capasitive_sensor_post_2.ino:13:3: error: 'MDNS' was not declared in this scope; did you mean 'MDNS_H'?
   13 |   MDNS.update();
      |   ^~~~
      |   MDNS_H
DISK:\portable\arduino-ide_2.0.4\myscript\Capacitive_Sensor\Capasitive_sensor_post_2\Capasitive_sensor_post_2\init_mDNS.ino: At global scope:
DISK:\portable\arduino-ide_2.0.4\myscript\Capacitive_Sensor\Capasitive_sensor_post_2\Capasitive_sensor_post_2\init_mDNS.ino:4:1: error: 'MDNS' does not name a type
    4 | MDNS MDNS;
      | ^~~~

And here is what it says about the two libraries:

Several libraries found for "ESP8266WiFi.h"
  Used: DISK:\portable\arduino-ide_2.0.4\myscript\libraries\ESP8266WiFi
  Not Used: C:\Users\user\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.0\libraries\ESP8266WiFi

I gave all the code in the topic header. It is short and not difficult. It has all the includes that I use in the sketch. And all the functions that work together in one sketch are displayed before breaking down.
That is, at the moment there are only three files in it: the main one, which has a setup and a loop, a Wi-Fi connection file and an mDNS configuration file. There is also a fourth file for obtaining data from the sensor, but I can compile without it.

Usually, when one does not customize the full error output, the program writes exactly what I wrote in the title. Thus, I thought that usually a summary of the error from the title would be enough, because I quoted it, and did not retell it in my own words.
I hope the full version of my error will satisfy you.

You didn't state the file types of "Second" and "Third" ---- .h? .cpp? .ino? The differences between these types is important. If you don't understand that, you won't be able to create a multi-file, modularized project. That's why I pointed you to my other post where this is covered.

Of course there is.

Why did you comment that out of the main file?
If you look inside ESP8266mDNS.h you'll find:

extern MDNSResponder MDNS;

If you look inside ESP8266mDNS.cpp you'll find:

MDNSResponder MDNS;
1 Like

Thanks.

I thought that if the sketch is broken using tabs, then the .ino extension is used. And under your link it says so. Apparently, when I said that it is now difficult for me to share the file in your way, I expressed myself not quite clearly. According to your link you recommend to divide into two types of files: .h and .cpp. It was about this method that I said that for me it is still difficult. And I thought that when I say that I break the sketch using tabs, then you will understand, because you have this post: Tabs in Arduino IDE - #11 by gfvalvo

Where? Maybe you mean the declaration of the object in the library? But in the example itself, there is no such initialization. Here is a complete example from the standard library:

/*
  ESP8266 mDNS responder sample

  This is an example of an HTTP server that is accessible
  via http://esp8266.local URL thanks to mDNS responder.

  Instructions:
  - Update WiFi SSID and password as necessary.
  - Flash the sketch to the ESP8266 board
  - Install host software:
    - For Linux, install Avahi (http://avahi.org/).
    - For Windows, install Bonjour (http://www.apple.com/support/bonjour/).
    - For Mac OSX and iOS support is built in through Bonjour already.
  - Point your browser to http://esp8266.local, you should see a response.

*/


#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiClient.h>

#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK  "your-password"
#endif

const char* ssid = STASSID;
const char* password = STAPSK;

// TCP server at port 80 will respond to HTTP requests
WiFiServer server(80);

void setup(void) {
  Serial.begin(115200);

  // Connect to WiFi network
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  // Set up mDNS responder:
  // - first argument is the domain name, in this example
  //   the fully-qualified domain name is "esp8266.local"
  // - second argument is the IP address to advertise
  //   we send our IP address on the WiFi network
  if (!MDNS.begin("esp8266")) {
    Serial.println("Error setting up MDNS responder!");
    while (1) {
      delay(1000);
    }
  }
  Serial.println("mDNS responder started");

  // Start TCP (HTTP) server
  server.begin();
  Serial.println("TCP server started");

  // Add service to MDNS-SD
  MDNS.addService("http", "tcp", 80);
}

void loop(void) {

  MDNS.update();
}

I hope you can show me where the MDNS object is initialized.

In the topic header, I wrote that if you make a connection here, then everything is compiled. I also wrote in the topic header that I would like to avoid doing such an include on the first (main) tab. If this is the only way, then uncommenting this include line is easy. But, if there is another way, I would like to know it.

This declaration occurs in the library itself. What does it give me? And a little explanation. Unfortunately, besides the fact that this declaration occurs in a library, I have a poor understanding of what it says and how it happens. So tell me if there is a way to avoid the error without including the library in the main file.

To be clear. I think that using the "multiple .ino" method is absolutely the wrong way to modularize a large project. It's an ugly hack. Therefore, I'll not discuss ways to make that method "work".

The object is defined in the .cpp file. But it's also declared (as 'extern') in the .h file. To understand the difference between those two term see here.

Because the is object is declared in the .h, the compiler will know about it when it compiles your application if and only if you #include that .h file. That's all the compiler needs. The linker will sort out the exact location of the object later.

Below is a skeletal example of how I'd do your project. Look it over and compare it to the guide in the link I posted. You'll find that everything in the below example is covered in the guide.

Main .ino:

#include "Second.h"
#include "Third.h"

void setup() {
	conectWiFi();
	init_mDNS();
}

void loop() {
	MDNS.update();
}

Second.h:

#ifndef SECOND_H_
#define SECOND_H_

#include <Arduino.h>

void conectWiFi();

#endif /* SECOND_H_ */

Second.cpp:

#include "Second.h"

void conectWiFi() {

}

Third.h:

#ifndef THIRD_H_
#define THIRD_H_

#include <Arduino.h>
#include <ESP8266mDNS.h>

void init_mDNS();

#endif /* THIRD_H_ */

Third.cpp:

#include "Third.h"

static const char* const host = "Sensor_1";

void init_mDNS() {
	(MDNS.begin(host));
}
1 Like

Too bad you don't want to discuss how to make an example using the "multiple .ino" method. Of course, you have already figured out all the pros and cons for a long time. But I just started doing it. Arduino and C ++ also became involved quite recently, so I don’t know the reasons why you made such a conclusion. Of course, I trust your opinion, but I would like to understand why you should not use the "multiple .ino" method. Therefore, I would like to deal with this method.

It seems to be clear how it works in the library, but I don’t understand why it doesn’t work in my example. After all, the entire library is connected to my example.

I tried and made according to your pattern. I did it, but questions remain. And why did you write in the first place:
static const char* const host = "Sensor_1";
instead of:
const char* host = "Sensor_1";

Although I was slightly wrong. It turns out that only the sketch compiled without errors. That's why I wrote that everything works. But it turns out that nothing outputs to the serial port.
Did it like this:
Main.ino

#include "WiFi_conect.h"
#include "mDNS_init.h"
#include "readSensor.h"

void setup() {
	conectWiFi();
	init_mDNS();
}

void loop() {
	MDNS.update();
  readSensor();
}

WiFi_conect.h

#ifndef WiFi_CONECT_H_
#define WiFi_CONECT_H_

#include <Arduino.h>
#include <ESP8266WiFi.h> 
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

void conectWiFi();

#endif /* WiFi_CONECT_H_*/

WiFi_conect.cpp

#include "WiFi_conect.h"

const char* ssid = "";
const char* password = "";

ESP8266WebServer WebServerHTTP(80);

void conectWiFi(){
  WiFi.begin(ssid, password);
                         
  WebServerHTTP.begin();
  
  while (WiFi.status() != WL_CONNECTED) { 
    delay(1000); Serial.println("waiting...");
    }  
  Serial.println(WiFi.localIP());
}

mDNS_init.h

#ifndef MDNS_H_
#define MDNS_H_

#include <Arduino.h>
#include <ESP8266mDNS.h>

void init_mDNS();

#endif /* MDNS_H_ */

mDNS_init.cpp

#include "mDNS_init.h"

//static const char* const host = "Sensor_1";
const char* host = "Sensor_1";

void init_mDNS(){
  if (MDNS.begin(host)) {
    MDNS.addService("http", "tcp", 80);
    Serial.print(F("Open http://"));
    Serial.print(host);
    Serial.println(F(".local to view in Browser"));
  }
}

readSensor.h

#ifndef READSENSOR_H_
#define READSENSOR_H_

#include <Arduino.h>

void readSensor();

#endif /* READSENSOR_H_ */

readSensor.cpp

#include "readSensor.h"

int sensorPin = A0;
int sensorValue = 0;

const int AirValue = 725;
const int WaterValue = 620;

void readSensor(){
  sensorValue = analogRead(sensorPin);
  int percentValue = map(sensorValue, AirValue, WaterValue, 0, 100);
  percentValue = constrain(percentValue, 0, 100);

  Serial.print("row data = ");
  Serial.print(sensorValue);
  Serial.print("\t or ");
  Serial.print(percentValue);
  Serial.println("%");
  delay(500);
}

Serial.begin?

1 Like

Yes. My carelessness.
Can you still try to suggest how to fix my version with the "multiple .ino" method? And at the same time explain why this method is a crutch. Why is it worse than splitting into .h/.cpp files?

All your questions have the same answer … it's because of how the Arduino IDE processes multiple .ino files. All it does is mash them together into one big .cpp file before handing it to the compiler. It's essential to understand the order of mashing as that's what caused your problem. Mashing starts with the main .ino file (same name as the sketch directory) and then concatenates all the other files in alphabetical order by filename. That's why the technique doesn't provide any meaningful modularity.

Your version tried to access the MDNS object in loop() before the "#include <ESP8266mDNS.h>" statement told the compiler what that object was.

So, if you're intent on using this technique, start by putting all the #include statements at the top of the main .ino file.

1 Like

..or by naming your source files in alphabetical order.

That doesn't help if the attempt to access an object/variable/function ends up occurring in the mashed-up .cpp file before the #include that declares it.