Why Component class is not found in c++ file?

Hello,
I’m coding a sample ESPHome custom device and I’ve found something that I would understand…
My c++ code is in a ‘src’ folder, because it is the easiest way to have many files compiled with the yaml file.
My custom component extends PollingComponent. If I put my custom component class declaration and implementation in the same file (*.h), I have no problem to have it compiled.
Nevertheless, when I try to separate and put the class declaration in a *.h file, and the class implementation in a *.cpp file, when compiling (esphome compile xxx.yaml), I get a “error: expected class-name before ‘{’ token” during cpp compilation because it seems that it is unable to find the PollingComponent class definition (even if I add #include “esphome\core\component.h”).

Any hints about how to isolate component implementation in a cpp file avoiding this error?

THIS COMPILES WITHOUT PROBLEM:

issue_h.yaml

esphome:
  name: issue_h
  includes:
    - issue_h_src
esp8266:
  board: d1_mini
# Example configuration entry
custom_component:
- lambda: |-
    auto my_custom = new MyCustomComponent();
    return {my_custom};
  components:
  - id: my_custom_id

issue_h_src\my_custom_component.h

class MyCustomComponent : public PollingComponent {
 public:
	MyCustomComponent();
	void setup() override;
	void update() override;
};
MyCustomComponent::MyCustomComponent() : PollingComponent(50) {}
void MyCustomComponent::setup() {}
void MyCustomComponent::update() {}

THIS DOES NOT COMPILE

issue_h_cpp.yaml

esphome:
  name: issue_h_cpp
  includes:
    - issue_h_cpp_src
esp8266:
  board: d1_mini
custom_component:
- lambda: |-
    auto my_custom = new MyCustomComponent();
    return {my_custom};
  components:
  - id: my_custom_id

issue_h_cpp_src\my_custom_component.h

#pragma once
class MyCustomComponent : public PollingComponent {
 public:
	MyCustomComponent();
	void setup() override;
	void update() override;
};

issue_h_cpp_src\my_custom_component.cpp

#include "my_custom_component.h"
MyCustomComponent::MyCustomComponent() : PollingComponent(50) {}
void MyCustomComponent::setup() {}
void MyCustomComponent::update() {}

Error that I get

My guess is that somehow the scopes are different between the .h and .cpp and PollingComponent isn’t found as a class in the .cpp. Try adding #include "esphome.h" to the .cpp file or maybe using namespace esphome; before your class definition.

Thanks for the suggestion, though I tried it and it didn’t do the trick…
Don’t worry, it works anyway keeping all in the same header file, so there is no problem.

Thanks for the hint about namespaces. Finally I got it working… I needed adding #include “esphome.h” to the .hpp file, and precede ‘PollingComponent’ with “esphome::” prefix.

The working code for issue_h_cpp.yaml should be:

issue_h_cpp_src\my_custom_component.h

#pragma once
#include "esphome.h"
class MyCustomComponent : public esphome::PollingComponent {
 public:
	MyCustomComponent();
	void setup() override;
	void update() override;
};

issue_h_cpp_src\my_custom_component.cpp

#include "my_custom_component.h"
MyCustomComponent::MyCustomComponent() : esphome::PollingComponent(50) {}
void MyCustomComponent::setup() {}
void MyCustomComponent::update() {}
1 Like

I had a similar problem:

I made a minimal ‘custom sensor’ and got the same error

The solution was this - If you reference the “Sensor” class in your custom code - then you must have “sensor:” entry in your YAML file

So if you have this in your custom C++

class CustomFT6236 : public PollingComponent, public Sensor {

Then you need at least this in your yaml file

sensor:

So that the appropriate modules are made available by the esphome build system.

Hope that helps someone :slight_smile:

1 Like

I’m having trouble with this same issue. I’m writing a small C++ class that coordinates several esphome built-in components (switches, text sensors, and a text field). I write all the correct c++ includes, according to the API docs for those components, and yet compilation fails as those .h files cannot be found.

If I put dummy configuration in my yaml file, that matches the components and platforms I’m trying to include, then it does compile. But as soon as I remove the dummy config from the yaml file, compilation fails again.

Looking at the esphome source tree, I can see the .h files I need, and they appear or disappear, depending on the yaml config. So how do I ensure that these c++ header files that I need will be in the location specified in the API documentation?

And why are files being dynamically added/removed from the esphome source tree? Is there any documentation that explains what is going on here and how to control it?