Guides AI models in developing ESPHome components for IoT devices. Covers YAML config validation, C++ code generation, platform-specific implementations, and testing workflows for ESP32/ESP8266/RP2040 microcontrollers.
This skill provides comprehensive guidance for developing ESPHome components, focusing on the project's unique code-generation architecture, component system, and multi-platform support.
ESPHome is a system to configure microcontrollers (ESP32, ESP8266, RP2040, LibreTiny chips) using YAML configuration files. It generates C++ firmware that can be compiled and flashed to devices for remote control through home automation systems.
**Architecture:** Code-generation model where Python parses YAML configs and generates C++ source code, compiled via PlatformIO.
```
/esphome # Core Python source
/esphome/components # Individual components (self-contained units)
/tests # Unit and integration tests
/docker # Container files
/script # Development helper scripts
```
**Naming:**
**Field Visibility:**
1. Pointer lifetime issues (setters validate pointers from known lists)
2. Invariant coupling (multiple fields must stay synchronized)
3. Resource management (setters perform cleanup/registration)
**Conventions:**
**Preprocessor Directives:**
- Conditional compilation (`#ifdef`, `#ifndef`)
- Compile-time sizes calculated during code generation (e.g., `std::array` dimensions via `cg.add_define()`)
```
components/[component_name]/
├── __init__.py # Configuration schema and code generation
├── [component].h # C++ header (if needed)
├── [component].cpp # C++ implementation (if needed)
└── [platform]/ # Platform-specific implementations
├── __init__.py # Platform-specific configuration
├── [platform].h # Platform C++ header
└── [platform].cpp # Platform C++ implementation
```
```python
DEPENDENCIES = ["component_name"] # Required components
AUTO_LOAD = ["auto_loaded_component"] # Auto-load components
CONFLICTS_WITH = ["incompatible_component"] # Incompatible components
CODEOWNERS = ["@github_username"] # Maintainer GitHub handles
MULTI_CONF = True # Allow multiple instances
```
```python
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import CONF_KEY, CONF_ID
CONF_PARAM = "param" # New constant not in esphome/const.py
my_component_ns = cg.esphome_ns.namespace("my_component")
MyComponent = my_component_ns.class_("MyComponent", cg.Component)
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(MyComponent),
cv.Required(CONF_KEY): cv.string,
cv.Optional(CONF_PARAM, default=42): cv.int_,
}).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
cg.add(var.set_key(config[CONF_KEY]))
cg.add(var.set_param(config[CONF_PARAM]))
```
```cpp
namespace esphome::my_component {
class MyComponent : public Component {
public:
void setup() override;
void loop() override;
void dump_config() override;
void set_key(const std::string &key) { this->key_ = key; }
void set_param(int param) { this->param_ = param; }
protected:
std::string key_;
int param_{0};
};
} // namespace esphome::my_component
```
```python
from esphome.components import sensor
CONFIG_SCHEMA = sensor.sensor_schema(MySensor).extend(
cv.polling_component_schema("60s")
)
async def to_code(config):
var = await sensor.new_sensor(config)
await cg.register_component(var, config)
```
```python
from esphome.components import binary_sensor
CONFIG_SCHEMA = binary_sensor.binary_sensor_schema().extend({ ... })
async def to_code(config):
var = await binary_sensor.new_binary_sensor(config)
```
```python
from esphome.components import switch
CONFIG_SCHEMA = switch.switch_schema().extend({ ... })
async def to_code(config):
var = await switch.new_switch(config)
```
**Common Validators:**
**Platform-Specific:**
**Framework-Specific:**
**Schema Extensions:**
```python
CONFIG_SCHEMA = cv.Schema({ ... }) \
.extend(cv.COMPONENT_SCHEMA) \
.extend(uart.UART_DEVICE_SCHEMA) \
.extend(i2c.i2c_device_schema(0x48)) \
.extend(spi.spi_device_schema(cs_pin_required=True))
```
1. **ESP32** (`components/esp32/`): Espressif ESP32 family. Supports variants: Original, C2, C3, C5, C6, H2, P4, S2, S3. ESP-IDF framework (all variants), Arduino framework (subset only).
2. **ESP8266** (`components/esp8266/`): Arduino framework only, memory-constrained.
3. **RP2040** (`components/rp2040/`): Raspberry Pi Pico. Arduino framework with PIO support.
4. **LibreTiny** (`components/libretiny/`): Realtek and Beken chips.
Use Docker container or Python virtual environment:
```bash
pip install -r requirements_dev.txt
```
```bash
python3 script/run-in-env.py <command>
python3 script/run-in-env.py pre-commit run
```
**Python Tests:**
```bash
pytest
```
**C++ Static Analysis:**
```bash
clang-tidy
```
**Component Tests (YAML-based):**
```bash
./script/test_build_components -c <component>
./script/test_build_components -t <target>
./script/test_component_grouping.py -e config --all
```
1. **Always use `this->` for member access** to maintain consistency
2. **Favor `protected` fields** unless safety-critical (pointers, invariants, resources)
3. **Avoid `#define` constants** — use `const` or `enum` instead
4. **Add new defines to `esphome/core/defines.h`** for static analyzer support
5. **Use descriptive names** over abbreviations
6. **Test platform-specific code** on all supported variants
7. **Validate YAML schemas thoroughly** with appropriate validators
8. **Run pre-commit hooks** before committing changes
See the component structure pattern above combined with configuration validation and C++ implementation patterns to create complete, production-ready ESPHome components.
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/esphome-component-development-8m43hh/raw