Tooling
Tooling
This tooling is still a work in progress, and ideally I would like to build a sensible CI/CD build system that
would compile the configs into programs and upload them to the ESP devices. The esph.py
tool will
eventually (and hopefully) move into its own project under homie
along with (most of) the configuration,
with the lofty goal of making that possible.
esph.py
Since I prefer to mange configuration in code whenever possible, I am not using the dashboard to manage
ESPHome, instead preferring managing the configs with ansible and
and my esph.py
tool.
$ esph.py clean device_kind.yaml
$ esph.py compile device_kind.yml --name livingroom
$ esph.py upload device_kind.yml --name livingroom
esph.py --help
esph.py --help
$ esph.py --help
usage: esph.py [-h] [-q] [-v] [-R] [-l] [-u] [-s key value] [-d DOMAIN] [-n NAME] [-D DEVICE] [-N]
ACTION ... config
positional arguments:
ACTION Command to pass to ESPHome.
clean Delete all temporary build files and program binary.
config Validate and print full YAML config.
compile Read the config, validate it, compile a program and store a binary in target path.
upload Validate the current config and upload the latest binary in target path.
logs Connect to ESPHome device and print logs to stdout.
run Validate, compile and upload the config.
version Print ESPHome version to stdout.
esphome-help Print ESPHome --help output.
substitutions Show substitutions.
config ESPHome config file.
options:
-h, --help show this help message and exit
-q, --quiet Quiet output. (default: False)
-v, --verbose Verbose output. (default: False)
-R, --dry-run Only log what would be run, without running it. (default: False)
-l, --show-log Print logs from ESPHome device to stdout. (default: False)
-u, --user Run as 'ben', otherwise sudo's to 'hass'. (default: False)
-s key value, --substitution key value
ESPHome substitutions (default: None)
-d DOMAIN, --domain DOMAIN
Domain for hostname. (default: s21.sudo.is)
-n NAME, --name NAME Device name. Hostname becomes 'esphome-${name}' (default: None)
-D DEVICE, --device DEVICE
Device name to upload program to. Can be device file (example: /dev/ttyUSB0) or hostname
(can be used when renaming device). (default: None)
-N, --no-device Ignore found device files and computed hostnames, and do not attempt to write to them.
(default: False)
In order to minimize the number of config files and use my naming scheme, I've
written a wrapper esph.py
that wraps the esphome
script (suportig the useful esphome
commands).
Substitutions are used to set the hostname and to provide variables to set name
attributes (which
get used for the entity_id
in Home Assistant).
$ esph.py substitutions radar.yaml -s "docs" "foobar"
{
"lower_node_name": "radar",
"friendly_node_name": "Radar",
"device_type_name": "radar",
"hostname": "esphome-radar",
"domain": ".home.sudo.is",
"config_name": "radar.yaml",
"config_date": "2023-12-30",
"build_path": "/srv/hass/esphome/target/radar",
"docs": "foobar"
}
Each individual device does not need its own config file, instead each "kind" of ESPHome device has a config file
and then each device of that kind is targeted by passing esph.py
the --name
argument.
$ esph.py run radar.yml --name livingroom
...
Uploading to: esphome-radar-livingroom.home.sudo.is
There are multiple radar
"kind" devices, and each device is named esphome-${kind}-${area}
(or if there
is more than in in each ${area}
it gets expanded to esphome-${kind}-${area}-${placement}
instead).
Packages
I use "packages" to i
re-use and organize my ESPHome configuration files. For example, the config for the "device kind" radar
looks
something like this:
packages:
board: !include ../packages/boards/esp32s2mini.yaml
esphome: !include ../packages/common/esphome.yaml
network: !include ../packages/common/network.yaml
http_server: !include ../packages/common/http_server.yaml
sensors_esp32: !include ../packages/sensors/esp32.yaml
sensors_esphome: !include ../packages/sensors/esphome.yaml
sensors_wifi: !include ../packages/sensors/wifi.yaml
This example is radar.yaml
on an ESP32 S2 Mini board with an LD2410 mmWave
presence detection sensor1.
Working with entity_id
in Home Assistant
By default, ESPHome wants you to set esphome.friendly_name
, which then gets prefixed to all names
and entity_id
s in Home Assistant. This is a problem for me, since I want some entity_id
s to not
start with a "friendly name".
For example, using the default suggested naming standard and config and a minimal example with the Version Text Sensor2:
esphome:
name: livingroom
# This will get lowercased, and prefixed to any name attributes to
# form the entity_id in Home Assistant
friendly_name: "Livingroom"
wifi:
# This is the default value
domain: ".local"
mdns:
# This is the default value
disabled: false
text_sensor:
- platform: version
# This will get suffixed to the friendly_name
name: "ESPHome Version"
This results in the following naming:
- Hostname:
livingroom.local
- Version Text Sensor
entity_id
:sensor.livingroom_esphome_version
This is unsuitable for me for numerous reasons.
- I do not want to use
.local
or rely on mDNS. My ESPHome devices are segregated on a separate VLAN, and I dislike relying on auto-discovery in general (preferring to manage configuration in code) - I want my hostnames to be prefixed with
esphome-
, and to have the fully qualified name that my DHCP server hands out (this can be fixed by simply settingesphome.name
correctly). - I don't want everything to be prefixed with the "friendly name". For the Version Text
Sensor, I want it to use
sensor.esphome_version_livingroom
asentity_id
in Home Assistant.
This is a small example, but this quickly gets out of hand. So instead, the config equivalent config that I use looks something like this:
esphome:
name: ${hostname}
wifi:
domain: ".home.sudo.is"
mdns:
disabled: true
text_sensor:
- platform: version
name: "ESPHome version ${lower_node_name}"
This results in the following naming:
- Hostname:
esphome-livingroom.home.s21.sudo.is
- Version Text Sensor
entity_id
:sensor.esphome_version_livingroom
The variables/substitutions ${hostname}
and ${lower_node_name}
are stitched together
by esph.py
using the config filename and --name
parameter.
References
Configuration types - ESPHome. Details on id
, pin schema, YAML operators/substitutions, packages ad etc.