BTW, in my project layout, I keep all my include files in a sensible folder structure:
And then the master device configs in the parent folder:
Along with the separate secrets files. This makes it easy to commit all your configs to GitHub should you want to without sharing things like WiFi passwords.
Here is an example of one of the more complex device files - for the M5 Basic:
# M5 Basic Configuration for m5basic01
# MAC Address: 84:0D:8E:3D:3B:D4
# NB: This configuration does not use Home Assistant (HA). It uses TotallyInformation's standard MQTT Schema for ESP devices.
# Pins/GPIO | ADC | Touch | DAC | Comments
# 00 | | | | Left button. Must be HIGH on normal boot
# 02 | 12 | 2 | | On-board LED.
# 12 | 15 | 5 | |
# 13 | 14 | 4 | |
# 15 | 13 | 3 | |
# 17 | | | |
# 21 | | | | Wire SDA
# 22 | | | | Wire SCL
# 25 | 18 | | 1 | Speaker (Buzzer)
# 26 | 19 | | 2 |
# 27 | 17 | 7 | |
# 32 | 4 | 9 | | Display Backlight
# 33 | 5 | 8 | |
# (34) | | | | ? Can't be an output
# 35 | | | | Right button. Can't be an output
# 36 | 0 | | | Can't be an output
# 37 | | | | Can't be an output
# 38 | | | | Can't be an output
# 39 | 3 | | | Can't be an output
# ---- Display - ---------------
# 14 | | | |
# 18 | | | | SCLK
# 19 | | | | MOSI
# 23 | | | | RT
# 05 | | | | CS
# 16 | | | | DC
#
# === General ESP32 Pin data ===
# GPIO00 | Must be LOW on normal boot (HIGH to boot into FLASH mode). Can be used as an output.
# GPIO34-GPIO39 | Cannot be used as outputs.
# GPIO32-GPIO39 | ADC capable (voltage measurements)
# GPIO02 | This pin is connected to the blue LED on the board. It also supports the touch pad binary sensor like some other pins.
#
# === M5Stack Specific ===
# @see https://github.com/m5stack/M5Stack/blob/master/src/utility/Config.h
# ---- Display (IPS ILI9342C 2", SPI) ----
# TFT_LED_PIN | 32 | Backlight
# TFT_DC_PIN | 27 |
# TFT_CS_PIN | 14 |
# TFT_MOSI_PIN | 23 | SPI MOSI
# TFT_MISO_PIN | 19 | SPI MISO
# TFT_CLK_PIN | 18 | SPI Clock
# TFT_RST_PIN | 33 |
# ------ SD card (SPI) ------
# TFCARD_MOSI_PIN | 23 | SPI MOSI
# TFCARD_MISO_PIN | 19 | SPI MISO
# TFCARD_CS_PIN | 04 |
# ------ Buttons ------
# BUTTON_A_PIN | 39 | Left Button
# BUTTON_B_PIN | 38 | Middle Button
# BUTTON_C_PIN | 37 | Right Button
# ------ BEEP PIN ------
# SPEAKER_PIN | 25 | (TONE_PIN_CHANNEL 0)
# -------- LORA --------
# LORA_CS_PIN | 5 |
# LORA_RST_PIN | 26 |
# LORA_IRQ_PIN | 36 |
# -------- I2C ---------
# SDA | 21 |
# SCL | 22 |
#
# Grove Port A - I2C
# IPS5306 (Power management SoC) - I2C
# === BTC 2.1 Base ===
# SHT30 Temperature/Humidity
# I2C address: 0x44
#
substitutions: # All have to be strings, the substitution process will convert them to the correct types
devicename: m5basic01
upper_devicename: M5BASIC01
device_location: Office
device_description: Knightnet Home custom sensor platform using ESPhome firmware
mqtt_root: ESP
mqtt_prefix: ESP/m5basic01 #$mqtt_root/$devicename
mqtt_broker: !secret mqtt_broker
mqtt_username: !secret mqtt_username
mqtt_password: !secret mqtt_password
publish_interval: 50s
ipaddress: 192.168.1.193
wifi_power_save_mode: light # none, light, high
wifi_fast_connect: "true"
wifi_ssid: !secret WiFi_SSID
wifi_password: !secret WiFi_password
wifi_domain: !secret WiFi_domain
wifi_gateway: !secret WiFi_gateway
wifi_subnet: !secret WiFi_subnet
wifi_dns1: !secret WiFi_DNS1
wifi_ap_password: !secret WiFi_AP_Password
log_level: info # none, error, warn, info, debug, verbose
esp_platform: ESP32
esp_board: m5stack-core-esp32
sun_latitude: !secret sun_latitude
sun_longitude: !secret sun_longitude
#light_sensitivity: "100" # 31->69->254 - bh1750 sensor measurement duration # DEPRECATED
globals:
- id: backlight_level
type: float
restore_value: yes
initial_value: '0.5'
<<: !include includes/mqtt.yaml # For some reason, the config checker doesn't like this as a package
packages: # These allow merging whereas global includes do not
common: !include includes/common.yaml
logger: !include includes/logger.yaml
wifi: !include includes/wifi.yaml
m5basic: !include includes/m5stack-basic.yaml # All of the config, standard buttons, backlight, etc
color: !include color/COLOR_CSS # Standard CSS colour names
common_sensors: !include includes/common-sensors.yaml # Includes number, text and binary
common_switches: !include includes/common-switches.yaml
common_intervals: !include includes/common-intervals.yaml
esphome:
includes:
- lib/common.h
on_boot:
- light.control:
id: backlight
brightness: !lambda |-
return id(backlight_level);
# Basic configuration for ESP32 based boards. https://esphome.io/components/esp32.html
# Board names: https://registry.platformio.org/platforms/platformio/espressif32/boards
esp32:
board: $esp_board
sensor: # NB: See also common_sensors
# Temperature & Humidity
- <<: !include includes/sensors/th_sht3xd.yaml
# Ambient light intensity
- <<: !include includes/sensors/light_bh1750.yaml
# --- End of sensor --- #
text_sensor: # NB: See also common_sensors
- platform: template # Template text sensor wifi channel
id: wifi_channel
lambda: |-
// --- ESP8266 version ---
//std::string out;
//char buffer[64];
//sprintf(buffer, "%u", wifi_get_channel());
//out.append(buffer);
//return out;
// --- ESP32 version ---
wifi_ap_record_t wifidata;
esp_wifi_sta_get_ap_info(&wifidata);
std::string out;
if (wifidata.primary != 0) {
char buffer[64];
sprintf(buffer, "%u", wifidata.primary);
out.append(buffer);
}
return out;
- platform: mqtt_subscribe
name: "Landing Temperature (D1M04)"
id: landing_temperature
topic: environment/temperature/Landing/temperature
- platform: mqtt_subscribe
name: "Landing Humidity (D1M04)"
id: landing_humidity
topic: environment/humidity/Landing/humidity
- platform: mqtt_subscribe
name: "Bathroom Temperature"
id: bathroom_temperature
topic: environment/temperature/Bathroom/temperature_measured
- platform: mqtt_subscribe
name: "Bathroom Humidity"
id: bathroom_humidity
topic: environment/humidity/Bathroom/humidity
- platform: mqtt_subscribe
name: "Front Hall Temperature"
id: front_hall_temperature
topic: environment/temperature/Front Hall/temperature_measured
- platform: mqtt_subscribe
name: "Rear Hall Temperature (D1M02)"
id: rear_hall_temperature
topic: environment/temperature/Rear Hall/temperature
- platform: mqtt_subscribe
name: "Rear Hall Humidity (D1M02)"
id: rear_hall_humidity
topic: environment/humidity/Rear Hall/humidity
- platform: mqtt_subscribe
name: "Kitchen Temperature"
id: kitchen_temperature
topic: environment/temperature/Kitchen/temperature_measured
# --- End of text_sensor --- #
font:
# https://community.home-assistant.io/t/display-materialdesign-icons-on-esphome-attached-to-screen/199790/2
# https://materialdesignicons.com/
# https://fonts.google.com/specimen/Roboto
# MD Icons: https://fonts.google.com/icons?selected=Material+Icons&icon.query=wifi
# FA Icons: https://fontawesome.com/icons?d=gallery&p=2&q=wifi&m=free
# 1 Point = 1.333333 Pixel. 12pt=16px, 16pt=22px, 18pt=24px, 22pt=26px, 24pt=32px, 26pt=35px, 30pt=40px :: https://reeddesign.co.uk/test/points-pixels.html
- file: "fonts/Roboto-Medium.ttf"
id: print_font_large
size: 22
glyphs: '!"%()+,-_.:°0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz/³µ'
- file: "fonts/Font Awesome 5 Free-Solid-900.ttf"
id: icon_font_large
size: 22
glyphs: [
'', # thermometer-three-quarters
'', # water-drop (tint)
'' # WiFi
]
- file: "fonts/Roboto-Medium.ttf"
id: print_font_medium
size: 20
glyphs: '!"%()+,-_.:°0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz/³µ'
- file: "fonts/Font Awesome 5 Free-Solid-900.ttf"
id: icon_font_medium
size: 20
glyphs: [
'', # thermometer-three-quarters
'', # water-drop (tint)
'' # WiFi
]
- file: "fonts/Roboto-Medium.ttf"
id: print_font
size: 18
glyphs: '!"%()+,-_.:°0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz/³µ'
- file: "fonts/Font Awesome 5 Free-Solid-900.ttf"
id: icon_font
size: 18
glyphs: [
'', # thermometer-three-quarters
'', # water-drop (tint)
'' # WiFi
]
# glyphs: [
# "", # mdi-thermometer
# "", # mdi-water-percent
# "ﴟ" # mdi-air-filter
# ]
display:
- platform: ili9341
id: m5stack_display
model: M5STACK_OLD
cs_pin: 14
dc_pin: 27
led_pin: 32
reset_pin: 33
rotation: 0
#brightness: 25% # not available in driver
# Colours: https://css-tricks.com/snippets/css/named-colors-and-hex-equivalents/
pages:
- <<: !include pages/m5basic01/page1.yaml
- <<: !include pages/m5basic01/page2.yaml
- <<: !include pages/m5basic01/page3.yaml
- <<: !include pages/m5basic01/page4.yaml
# Turn on backlight for 1min out of 5.
interval:
# TODO: To be more flexible, change to a 1sec interval but check an external value to see if a set time
# has expired. This would let you have a variable time limit. (Ideas: https://www.instructables.com/ESPHOME-SONOF-S26-Timed-Light/)
# Also: Maybe use time:on_time and exclude night-time?
- interval: 5min
then:
- wait_until:
mqtt.connected:
- light.turn_on: # Always turn on the backlight to the set level
id: backlight
# brightness: !lambda |-
# return id(backlight_level);
#- display.page.show: page2 # And show page 2
# EOF
I also created some notes for myself since I very rarely ever need to touch the devices these days - so when I do, it can take a while to remember everything:
ESPhome Configuration
This contains my configuration for all ESPHome devices.
Folders
Root
Each device has a YAML file in the root folder.
Sensitive data is kept in the secrets.yaml
file in the this folder. Assign these to substitutions in the top-level YAML file so that
they can be also used in included files. This file is not pushed to git. There is an example-secrets.yaml
file that can be included to git.
includes
Common settings are in the ./includes folder and its sub-folders.
Things common to all (at least most) devices are in the root. Specifics are in the sub-folders.
color
Contains lots of color definitions that match standard CSS colours. Include as required.
fonts
Contains any required font files. Include as required.
custom_components
Contains any custom ESPHome components such as my amended ILI9341 display component that has the correct colours for older M5Stack devices.
lib
Contains C++ files that can be included such that the contents are available to all lambda's.
pages
Split into sub-folders per device. Standard display page definitions.
builds
Contains the built/compiled software.
esphome
This is created when you create your Python virtual environment. See the installing section below.
\Users<userName>\AppData\Local\Packages\PythonSoftwareFoundation.\LocalCache\local-packages\Python38\site-packages\esphome
The master packages, updated when ESPhome is updated.
Installing and configuring
# Start with a root folder name
cd <root-folder>
# Create a python virtual environment - creates a new sub-folder called `esphome`
python -m venv env_esphome
# Run the activate script (see ./esphome/Scripts/) for your OS
./env_esphome/Scripts/Activate.ps1 # PowerShell example
# Now install ESPHome
pip install esphome
# And install pillow for font conversion
pip install pillow
# You can now run the command called `esphome`
See Using Python Environments in Visual Studio Code if working with VSCode as you can fix the envionment into your VSCode workspace.
See Getting Started with the ESPHome Command Line — ESPHome to get started with ESPhome. Here we are assuming that you already have a project
See Command Line Interface — ESPHome for all of the esphome commands.
See Release 2024.12.2 · esphome/esphome · GitHub for the latest changes
Build process
Initial build and upload to a device has to be over USB since the ESPHome OTA firmware won't yet be available. Subsequent build and upload can happen OTA.
# Start with the root folder name
cd <root-folder>
# Run the activate script (see ./esphome/Scripts/) for your OS
./env_esphome/Scripts/Activate.ps1 # PowerShell example
# Run esphome and compile then upload the firmware to the device
esphome run <devicename>.yaml # e.g. esphome run m5basic01.yaml
Validate any configuration changes
Checks for and reports any errors.
# Start with the root folder name
cd <root-folder>
# Run the activate script (see ./esphome/Scripts/) for your OS
./env_esphome/Scripts/Activate.ps1 # PowerShell example
esphome config <devicename>.yaml # e.g. esphome config m5basic01.yaml
Only compile
Just compiles all the code and produces but does not upload the firmware.
This is useful because it finds any compile-time errors but doesn't waste another set of changes to the device FLASH
which typically has a limited number of updates before failing.
# Start with the root folder name
cd <root-folder>
# Run the activate script (see ./esphome/Scripts/) for your OS
./env_esphome/Scripts/Activate.ps1 # PowerShell example
esphome compile <devicename>.yaml # e.g. esphome compile m5basic01.yaml
Upload to device
Uploads the latest compiled firmware to the device (don't forget to compile first)
# Start with the root folder name
cd <root-folder>
# Run the activate script (see ./esphome/Scripts/) for your OS
./env_esphome/Scripts/Activate.ps1 # PowerShell example
# Let esphome find all possible upload ports (you chose one)
esphome upload <devicename>.yaml # e.g. esphome upload m5basic01.yaml
# OR Pre-select the port - OTA is typically quicker than serial.
esphome upload <devicename>.yaml --device COM6 # e.g. esphome upload m5basic01.yaml --upload-port COM6
esphome upload <devicename>.yaml --device OTA # e.g. esphome upload m5basic01.yaml --upload-port OTA
Updating ESPhome
If NOT using a Python virtual environment as described here, you will probably need to do this from an elevated prompt since we are using the Windows Store (UWP) version of Python 3.9. Your milage may vary depending on how you have Python installed and whether you are using Python environments.
# Start with a root folder name
cd <root-folder> # e.g. c:/src/esphome
# Run the Python virtual env activate script (see ./esphome/Scripts/) for your OS
# ??? python -m venv env_esphome
./env_esphome/Scripts/Activate.ps1 # PowerShell example
# Now update ESPHome
pip install --upgrade esphome
pip install --upgrade pillow
Moving to new PC (maybe if moving to Python >3.9 from Windows Store)
I have had some issues when copying my root-folder to a new PC as the Virtual Environment doesn't recognise the Python install.
I simply created a new virtual environment and installed everything again.
Useful PowerShell Commands
- Show the Windows PATH:
$env:path -split ";"