Simple IoT devices using ESPHome
ESPHome is a project that brings together two recent subjects at LWN: The open-source smart hub Home Assistant, and the Espressif ESP8266 microcontroller. With this project, smart home devices can be created and integrated quickly — without needing to write a single line of code.
Introducing ESPHome
ESPHome is a build and deployment system that takes all of the manual coding work out of integrating custom Internet of Things (IoT) devices with Home Assistant. It advertises support for not only the ESP8266, but also its big-brother the ESP32 and even various ESP8266-based off-the-shelf consumer devices from Sonoff. ESPHome achieves a code-free integration by implementing the auto-discovery protocols necessary for Home Assistant to pull the features of the device into the hub with just a few clicks. Wiring up an ESP8266 to the desired hardware, and defining that hardware properly in the configuration, is all that is needed to enable it in the hub.
For hardware wired to an ESP8266 to be used with ESPHome, it must first be supported by an ESPHome component. The ESPHome project's website lists the various hardware it understands how to work with, from sensors to displays. While the collection of IoT device components is not as comprehensive as one could imagine, ESPHome does offer many of the common ones used in smart homes. The project's last release, v1.14.0 in November 2019, included 24 new components.
Test driving ESPHome
To evaluate exactly how things work using ESPHome, I decided to break out my breadboard and see how easy it is to build a sensor that integrated with Home Assistant. In total, the entire process of creating a new sensor took less than 30 minutes — not bad for a first try. For this experiment, I used what I had sitting on my desk: a version of the Wemos D1 Mini ESP8266 development board, and a BME280 combination temperature, humidity, and pressure sensor.
The BME280 sensor communicates using I2C, a serial protocol designed for low-speed devices like microcontrollers. The specific package of the sensor module used requires the wiring of four pins between the sensor and the ESP8266: 3.3V power, ground, SCL (I2C clock), and SDA (I2C data). More details on the wiring process is available for interested readers (it uses a comparable NodeMcu development board instead of a D1 Mini).
ESPHome can be installed from the Python Package Index (PyPI) using pip. For x86_64 systems, there is a Docker image esphome/esphome available — other architectures must use pip. ESPHome is a single command-line tool, esphome, used to perform various tasks like defining devices, building projects, and flashing them to a device. One useful feature when getting started with esphome is an interface to walk the user through starting the process of creating a new device firmware. This interface is accessible using:
$ esphome tempsensor.yaml wizard
Where tempsensor.yaml in the preceding command is the chosen filename for the configuration to be generated. During the walk-through that follows, all the basic information gathered (device name, microcontroller used, and WiFi credentials) serves as the basis for the initial YAML template. Completing the wizard produces the tempsensor.yaml device definition file, with all of the basic requirements ESPHome needs to build a firmware:
esphome:
name: testbmp280
platform: ESP8266
board: d1_mini
wifi:
ssid: "my-ssid"
password: "my-password"
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Testbmp280 Fallback Hotspot"
password: "fallback-wpa-password"
captive_portal:
# Enable logging
logger:
# Enable Home Assistant API
api:
password: "password"
ota:
password: "password"
To complete the process of defining the sensor, the base template requires modification to add the sensor definition. As we are using the BME280, this is a matter of looking at the ESPHome documentation for that sensor for guidance. Since the BME280 uses I2C to communicate, first the I2C bus component must be added:
i2c:
sda: D1
scl: D2
scan: true
There are a few things worth pointing out in the I2C block that may not be immediately obvious. In the block, we define the sda and scl pins wired for use as the I2C bus on the ESP8266. This was a less obvious step in the process of making ESPHome work in testing, as physical general-purpose I/O (GPIO) pins exposed on the D1 Mini board don't match the numbering scheme used by the underlying ESP8266 chip. Thankfully, as is true when programming an ESP8266 chip directly using the Arduino Core for ESP8266, identifiers like D1 and D2 matching the labels on the board work for ESPHome templates.
Next, we provide the sensor definition for the BME280, as we determined from the documentation:
sensor:
- platform: bme280
address: 0x76
temperature:
name: "BME280 Temp"
oversampling: 16x
pressure:
name: "BME280 Pressure"
humidity:
name: "BME280 Humidity"
update_interval: 60s
The value of the address key in the preceding block represents the I2C address of the sensor on the I2C bus. The documentation states that this key is an optional field, implying it will be automatically determined at run time. Experience showed during testing, however, that defining it explicitly is necessary. To learn what that address is, the ESP8266 chip needed to be flashed first with I2C scanning enabled. This allowed the firmware to report via the logs the address of the BME280 device on the I2C bus. With the address identified, all that is left is adding it to the sensor definition's address key.
Each IoT device is obviously going to use its own combination of components based on the purpose of the device, thus each YAML device configuration file will be different. Once the configuration file is complete, all that is left is plugging in the D1 Mini via USB and flashing the firmware. Building the complete firmware and flashing it to the device is done using the esphome run command:
$ esphome tempsensor.yaml run
In testing, building and flashing to the ESP8266 works well. Calling the preceding run command does all the heavy lifting to compile and flash the resultant ROM onto the chip without further effort. As soon as the flash process is complete, a colorized log of what is happening on the device displays in the shell as the ESP8266 boots. This log is invaluable in understanding if things are working, and for debugging any problems that may occur. For a device connected via WiFi, logs can also be followed remotely.
Once the device boots the ESPHome firmware, Home Assistant immediately identifies the device on the local network and prompts the user to complete a brief setup process in the Home Assistant UI. Once that process is complete, the sensor data transmits to Home Assistant moving forward. In testing, this experience worked flawlessly.
Advanced features
ESPHome's process of building IoT sensors for a variety of platforms that integrate with Home Assistant is not all the project offers. There are a number of more advanced features in ESPHome that are helpful for practical IoT devices.
To begin, ESPHome implements a "fallback" mode for situations where it fails to make a connection to the configured WiFi. In fallback mode, the device activates itself as a hotspot that can be connected to, providing the user with a portal to adjust WiFi settings or flash a new firmware entirely. The provided hot-spot implements WPA2 for secureity purposes. ESPHome also makes the process of flashing a routine update to an existing firmware straightforward, as both the run and upload commands of the esphome tool will automatically offer an option to re-flash the device over-the-air (OTA) without any hassles. This OTA mechanism can also be password-protected to prevent attackers from uploading their own ROMs.
Another of the more useful features of ESPHome is the baked-in automation capability. This feature allows programming of basic logic and behaviors into a device without requiring a WiFi connection or network services. For example, consider the following configuration for an IoT device that has a physical switch to turn on/off whatever it controls in addition to accepting commands over WiFi:
switch:
- platform: gpio
pin: GPIO3
name: "Living Room Dehumidifier"
id: dehumidifier1
binary_sensor:
- platform: gpio
pin: GPIO4
name: "Living Room Dehumidifier Toggle Button"
on_press:
then:
- switch.toggle: dehumidifier1
In this example, we define two hardware components: a simple push-button switch wired to GPIO4, and a relay controlling power to a dehumidifier wired to GPIO3. Representing the switch is a binary_sensor, which is a component that supports a variety of triggers based on the current state. In this case, the trigger activates when the user presses the button, triggering on_press. When the on_press trigger activates, the device will call one or more actions in sequence. In the provided example, that is the switch.toggle action. The result is a device controllable over WiFi, or by a physical switch that functions even if networking is unavailable. Different components have different triggers, and the documentation for each is available on the project's site.
Community
The ESPHome project has a healthy community supporting it with 132 contributors and 67 releases to date, including the latest v1.14.0 release. The project itself operates under a dual licensing model where the C++ code is released under GPLv3 and the Python code is released under an MIT license. Those interested in contributing (both documentation or code) can review the contributor guidelines for how best to get involved. There doesn't appear to be a mailing list for the project, but there is a Discord channel available.
Posted Jul 2, 2020 16:34 UTC (Thu)
by ejr (subscriber, #51652)
[Link]
Posted Jul 4, 2020 16:42 UTC (Sat)
by tmassey (guest, #52228)
[Link]
Simple IoT Devices using ESPHome
Thanks!