Temperature Sensor
Basic ESP32 project.
This guide covers advanced ESPHome techniques - from packages and substitutions to multi-sensor projects and external components. Perfect for taking your DIY projects to the next level!
Packages let you reuse configuration across many devices. Instead of copying the same WiFi, API, and OTA configuration to 10 devices, put it in one file and import it.
# device.yamlsubstitutions: device_name: living-room-sensor friendly_name: "Living Room Sensor" update_interval: 60s
esphome: name: ${device_name} friendly_name: ${friendly_name}
sensor: - platform: dht pin: GPIO4 temperature: name: "${friendly_name} Temperature" humidity: name: "${friendly_name} Humidity" update_interval: ${update_interval}esphome/├── common/│ ├── base.yaml # WiFi, API, OTA│ ├── sensors.yaml # Common sensors│ └── wifi.yaml # WiFi config├── living-room-sensor.yaml├── bedroom-sensor.yaml└── secrets.yaml# common/base.yamlesphome: name: ${device_name} friendly_name: ${friendly_name} platform: ${platform} board: ${board}
wifi: ssid: !secret wifi_ssid password: !secret wifi_password ap: ssid: "${device_name} Fallback" password: !secret fallback_password
api: encryption: key: !secret api_key
ota: platform: esphome password: !secret ota_password
logger: level: DEBUG
# Common sensorssensor: - platform: wifi_signal name: "${friendly_name} WiFi Signal" update_interval: 60s
- platform: uptime name: "${friendly_name} Uptime"
button: - platform: restart name: "${friendly_name} Restart"# living-room-sensor.yamlsubstitutions: device_name: living-room-sensor friendly_name: "Living Room Sensor" platform: esp32 board: esp32dev
packages: base: !include common/base.yaml
# Device-specific configurationsensor: - platform: bme280_i2c address: 0x76 temperature: name: "${friendly_name} Temperature" oversampling: 16x pressure: name: "${friendly_name} Pressure" humidity: name: "${friendly_name} Humidity" update_interval: 60s
i2c: sda: GPIO21 scl: GPIO22# Import packages directly from GitHubsubstitutions: device_name: my-sensor friendly_name: "My Sensor"
packages: # Official ESPHome packages voice_assistant: url: https://github.com/esphome/firmware files: - voice-assistant/m5stack-atom-echo.yaml refresh: 1d
# Community packages common: url: https://github.com/olegtarasov/esphome-common ref: main files: - common/base.yaml refresh: 1dsensor: - platform: template name: "Calculated Value" lambda: |- // C++ code here float temp = id(temperature_sensor).state; float hum = id(humidity_sensor).state;
// Calculate dew point float a = 17.27; float b = 237.7; float alpha = ((a * temp) / (b + temp)) + log(hum / 100.0); float dewpoint = (b * alpha) / (a - alpha);
return dewpoint; update_interval: 60s unit_of_measurement: "°C" accuracy_decimals: 1binary_sensor: - platform: template name: "Comfort Zone" lambda: |- float temp = id(temperature_sensor).state; float hum = id(humidity_sensor).state;
// Comfortable: 20-24°C and 40-60% humidity bool comfortable = (temp >= 20 && temp <= 24) && (hum >= 40 && hum <= 60); return comfortable;# New in ESPHome 2025.7: Jinja2 in substitutions!substitutions: # Dynamic values compile_time: "{{ now().strftime('%Y-%m-%d %H:%M') }}" random_suffix: "{{ range(1000, 9999) | random }}"
text_sensor: - platform: template name: "Firmware Info" lambda: |- return {"Compiled: ${compile_time}"};# Complete room sensor with all relevant measurementssubstitutions: device_name: room-sensor friendly_name: "Living Room Multi-Sensor"
esphome: name: ${device_name} friendly_name: ${friendly_name}
esp32: board: esp32dev framework: type: arduino
# I2C bus for sensorsi2c: sda: GPIO21 scl: GPIO22 scan: true
# UART for CO2 sensoruart: - id: uart_co2 rx_pin: GPIO16 tx_pin: GPIO17 baud_rate: 9600
sensor: # ===== TEMPERATURE & HUMIDITY ===== - platform: bme280_i2c address: 0x76 temperature: name: "${friendly_name} Temperature" id: temperature filters: - sliding_window_moving_average: window_size: 5 send_every: 1 humidity: name: "${friendly_name} Humidity" id: humidity pressure: name: "${friendly_name} Pressure" update_interval: 30s
# ===== CO2 ===== - platform: senseair uart_id: uart_co2 co2: name: "${friendly_name} CO2" id: co2 update_interval: 60s
# ===== LIGHT ===== - platform: bh1750 name: "${friendly_name} Illuminance" address: 0x23 update_interval: 30s
# ===== PRESENCE (mmWave) ===== # Add LD2410 for presence detection
# ===== CALCULATED: DEW POINT ===== - platform: template name: "${friendly_name} Dew Point" lambda: |- float t = id(temperature).state; float h = id(humidity).state; float a = 17.27, b = 237.7; float alpha = ((a * t) / (b + t)) + log(h / 100.0); return (b * alpha) / (a - alpha); unit_of_measurement: "°C" accuracy_decimals: 1 update_interval: 60s
# ===== CALCULATED: AIR QUALITY INDEX ===== - platform: template name: "${friendly_name} Air Quality" lambda: |- int co2_val = id(co2).state; if (co2_val < 600) return 100; // Excellent if (co2_val < 800) return 80; // Good if (co2_val < 1000) return 60; // Moderate if (co2_val < 1500) return 40; // Poor return 20; // Bad unit_of_measurement: "%" update_interval: 60s
binary_sensor: # PIR motion - platform: gpio pin: GPIO27 name: "${friendly_name} Motion" device_class: motion
# Status LEDlight: - platform: esp32_rmt_led_strip rgb_order: GRB pin: GPIO25 num_leds: 1 chipset: WS2812 name: "${friendly_name} Status LED" id: status_led
# Interval for status LED based on CO2interval: - interval: 5s then: - if: condition: lambda: 'return id(co2).state < 800;' then: - light.turn_on: id: status_led brightness: 30% red: 0% green: 100% blue: 0% else: - if: condition: lambda: 'return id(co2).state < 1200;' then: - light.turn_on: id: status_led brightness: 30% red: 100% green: 100% blue: 0% else: - light.turn_on: id: status_led brightness: 30% red: 100% green: 0% blue: 0%| Sensor | Measurement | I2C Address | Price |
|---|---|---|---|
| BME280 | Temp, Hum, Pressure | 0x76/0x77 | ~$5 |
| SenseAir S8 | CO2 | UART | ~$40 |
| BH1750 | Light | 0x23 | ~$3 |
| LD2410 | mmWave | UART | ~$8 |
| AM312 | PIR | GPIO | ~$2 |
Total: ~$60 for complete multi-sensor
External components are custom ESPHome components hosted on GitHub. They extend ESPHome with functionality not in the core library.
external_components: # LD2410 mmWave radar - source: github://screek-workshop/ld2410@main components: [ld2410] refresh: 1d
# Custom sensor from community - source: type: git url: https://github.com/ssieb/esphome_components components: [serial_csv]| Component | Function | GitHub |
|---|---|---|
| ld2410 | mmWave radar | screek-workshop/ld2410 |
| ratgdo | Garage door | ratgdo/esphome-ratgdo |
| bluetooth_proxy | BLE proxy | esphome/bluetooth-proxies |
| improv | Easy WiFi setup | esphome/improv |
# external_components/my_sensor/__init__.pyimport esphome.codegen as cgimport esphome.config_validation as cvfrom esphome.components import sensorfrom esphome.const import CONF_ID, UNIT_CELSIUS
my_sensor_ns = cg.esphome_ns.namespace('my_sensor')MySensor = my_sensor_ns.class_('MySensor', sensor.Sensor, cg.PollingComponent)
CONFIG_SCHEMA = sensor.sensor_schema( MySensor, unit_of_measurement=UNIT_CELSIUS, accuracy_decimals=1).extend(cv.polling_component_schema('60s'))
async def to_code(config): var = await sensor.new_sensor(config) await cg.register_component(var, config)# For sharing your projectssubstitutions: name: "my-project" friendly_name: "My Project"
esphome: name: "${name}" friendly_name: "${friendly_name}" name_add_mac_suffix: true # Unique per device
project: name: "username.my-project" version: "1.0.0"
# Dashboard import for easy adoptiondashboard_import: package_import_url: github://username/esphome-project/project.yaml@v1 import_full_config: false
# Captive portal for first-time setupwifi: ap: ssid: "${name} Setup" password: "12345678"
captive_portal:# New command for memory analysisesphome analyze-memory device.yamllogger: level: DEBUG logs: # Reduce noise from specific components component: ERROR wifi: WARN # Increase logging for debugging sensor: DEBUG api: VERBOSE# Optimize for battery operationdeep_sleep: run_duration: 30s sleep_duration: 5min
# Reduce WiFi power consumptionwifi: power_save_mode: LIGHT # or HIGH
# Batch sensor updatessensor: - platform: adc filters: - sliding_window_moving_average: window_size: 10 send_every: 5Temperature Sensor
Basic ESP32 project.
mmWave Sensor
Advanced presence detection.
Last updated: December 2025