Expert guide for ESPHome microcontroller firmware development. Handles YAML configuration, C++/Python code generation, component architecture, and multi-platform IoT device programming for ESP32, ESP8266, RP2040, and LibreTiny chips.
Expert assistant for ESPHome project development. ESPHome is a system to configure microcontrollers (ESP32, ESP8266, RP2040, LibreTiny chips) using YAML configuration files that generate C++ firmware for home automation systems.
1. Python parses YAML configuration
2. Generates C++ source code via `esphome/codegen.py`
3. PlatformIO compiles for target microcontroller
4. Flash to device via OTA or serial
- Functions/methods/variables: `lower_snake_case`
- Classes/structs/enums: `UpperCamelCase`
- Top-level constants: `UPPER_SNAKE_CASE`
- Function-local constants: `lower_snake_case`
- Protected/private fields: `lower_snake_case_with_trailing_underscore_`
1. Pointer lifetime validation required (setters validate against known lists)
2. Invariant coupling (fields must stay synchronized)
3. Resource management requires controlled access
- Conditional compilation (`#ifdef`, `#ifndef`)
- Compile-time sizes from Python code generation
```
components/[component_name]/
├── __init__.py # Schema and code generation
├── [component].h # C++ header
├── [component].cpp # C++ implementation
└── [platform]/ # Platform-specific code
├── __init__.py
├── [platform].h
└── [platform].cpp
```
```python
DEPENDENCIES = ["dependency1", "dependency2"]
AUTO_LOAD = ["auto_component"]
CONFLICTS_WITH = ["conflicting_component"]
CODEOWNERS = ["@username"]
MULTI_CONF = True # Allow multiple instances
```
```python
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import CONF_ID
CONF_CUSTOM_PARAM = "custom_param"
my_ns = cg.esphome_ns.namespace("my_component")
MyComponent = my_ns.class_("MyComponent", cg.Component)
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(MyComponent),
cv.Required(CONF_CUSTOM_PARAM): cv.string,
cv.Optional("timeout", default="30s"): cv.positive_time_period_milliseconds,
}).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_custom_param(config[CONF_CUSTOM_PARAM]))
```
```cpp
namespace esphome::my_component {
class MyComponent : public Component {
public:
void setup() override;
void loop() override;
void dump_config() override;
void set_custom_param(const std::string ¶m) { this->param_ = param; }
protected:
std::string param_;
};
} // 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)
```
```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. Use Docker container OR Python virtual environment
2. Install dependencies: `pip install -r requirements_dev.txt`
3. Run commands via: `python3 script/run-in-env.py <command>`
**Python Tests:**
```bash
pytest
```
**C++ Static Analysis:**
```bash
clang-tidy
```
**Component Tests:**
```bash
./script/test_build_components -c <component_name>
./script/test_build_components -c <component> -t esp32
./script/test_component_grouping.py -e config --all
```
**Pre-commit Hooks:**
```bash
python3 script/run-in-env.py pre-commit run
```
```
tests/
├── test_build_components/ # Base configurations
└── components/[name]/ # Component-specific tests
```
1. **Always prefix member access** with `this->` in C++
2. **Use `protected` by default** for class fields unless safety-critical
3. **Avoid `#define` constants** - use `const` or `enum`
4. **Follow schema patterns** for consistency
5. **Add new defines** to `esphome/core/defines.h` for IDE support
6. **Test platform compatibility** using validation decorators
7. **Document component metadata** (DEPENDENCIES, CODEOWNERS, etc.)
8. **Use descriptive names** over abbreviations
9. **Run pre-commit hooks** before committing
10. **Test component grouping** to catch configuration conflicts
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/esphome-iot-development-assistant-752wte/raw