The goal of this project is to create a presence sensor for a bed that reports its state to Home Assistant and thus can be used in automations. This is achieved by using two pressure sensors attached to an ESP32 micro controller which then relays the information about each half of the bed to the home automation server.
First of all, we want to cover some of the basics that will be necessary for this project.
ESPHome is an open source platform that allows users to configure microcontrollers and integrate them into smart home systems such as Home Assistant. As such microcontrollers are very inexpensive, they are ideal for implementing your own smart home projects.
ESPHome can be setup quite easily. There is a test version available at https://web.esphome.io/ and it can be self-hosted (for free) with Home Assistant or as an independent Docker container. I will go into further details on this in the setup
part later.
ESPHome primarily supports microcontrollers from the ESP8266 and ESP32 families, both manufactured by the Chinese company Espressif Systems. Some of the popular microcontrollers that can be used for ESPHome projects include the following:
- ESP8266-based microcontrollers
- ESP32-based microcontrollers
- ESP32 Dev Kit
- Wemos D32
- ESP32-CAM (an ESP32 based system which offers an onboard camera module for around $7)
ESP32 and ESP8266 are only the chips themselves: They are the platforms and are manufactured by Espressif Systems. These are System on a Chip (SoC) designs, meaning they integrate various components such as CPU, memory, and wireless connectivity onto a single chip.
There are several variants of these chips: Espressif Systems offers different ESP32/ESP8266 chip variants with varying features such as number of cores (single or dual), clock speed, and memory capacity.
These SoCs are then placed on different boards: Several companies produce development boards specifically designed for ESP32/ESP8266 chips. These boards typically include additional components such as voltage regulators, USB ports, and breakout pins for connecting external sensors or devices.
Although ESPHome primarily runs on ESP32 and ESP8266-based platforms it also includes limited support for RP2040-based chips and chips based on the LibreTiny platform.
In this project we are going to build a presence sensor which reports to Home Assistant whether someone is lying in bed. Moreover we are going to use two sensors which allows us to determine which of the two halfs of a bed are occupied.
I have divided this project into two main sections: First, we'll cover the hardware, and then we'll take a look at the software, where we'll set up ESPHome, among other things.
In this project we will use an ESP-32 development board which can be acquired on different platforms like Amazon.com, Amazon.de or AliExpress for less then $10.
I suggest that you look for a microcontroller that uses USB-C instead of micro-USB to be more future-proof. Unfortunately, I did not explicitly check for this when I ordered my ESP32, so I am stuck with micro-USB. Don't make the same mistake I did.
To determine if someone is in bed, we use a pressure sensor. To be precise: We will use two sensors, one for each half of the bed. This way we can determine if there are 0
, 1
or 2
people in bed. This allows for even more possible automations, which we will cover later.
The pressure sensor we use is a PM156
, manufactured by the company COMUS Group
. It can be obtained on different places like SwitchElectronics (where I bought mine from), Amazon.de or Ebay. As explained above, I bought two, but this project can be done with just one if you are fine with knowing if there is someone in bed and not knowing how many people there are.
This pressure sensor is essentially just a switch. When pressure is applied to the mat it pushes its two halfs together and thus closes the circuit.
The pressure mat looks like this:
Image source: https://www.multice.com/
It has four cables coming out of it. We only need two: from the perspective of this picture, the bottom two. These two complete an electrical circuit if pressure is applied to the mat. The other two cables are irrelevant for this project.
To power the ESP32 I am using a standard micro-USB cable which I had lying around. As described above you should use a USB-C cable instead. Any cheap power supply does the job as the microcontroller needs a maximum of ~250 mA.
The completed circuit looks like this:
To the right is the ESP32 microcontroller. On the left you can see the two pressure mats, both connected to the ground of the ESP32 and to a GPIO pin.
Note: It is important which GPIO pins of the ESP32 you connect the pressure mats to, as different pins have different functions.
Moreover you need to connect the ESP32 to power.
To connect the cables of the pressure mats to the ESP32 I recommend using a breadboard to avoid the necessity of soldering.
To summarize all the hardware costs:
- ESP32: 7,79 €
- Pressure mats: 2 x 14 € = 28 €
- Breadboard: 2 €
- USB cable: 2 €
- Power supply: 5 €
- Total: 44,79 €
I had the breadboard, usb cable and power supply lying around at home, so the total cost was only about 35 €.
After setting up the hardware it is time to take a closer look at the software needed for this project.
For this project we need a computer/server on which ESPHome can run. ESPHome does not need to run all the time, it is only needed for setup. So a computer that is not turned on all the time is fine. However, since you probably have a server where your Home Assistant instance is running, I suggest you deploy ESPHome on the same machine. I just added a section to the docker-compose.yml
of Home Assistant for ESPHome as you can see below.
There are multiple ways to use ESPHome. For testing purposes and initialization of the microcontroller it is possible to use a web hosted version of ESPHome available at https://web.esphome.io/. However this is only a lite variant of ESPHome. For bigger projects it is recommended to self-host ESPHome. There are two ways of doing this:
-
If you have a running Home Assistant instance you can install ESPHome as an add-on. The documentation on how to this can be found here.
Note:
This is not always possible. If you have setup Home Assistant with a Docker container refer to option2
. From the docs of Home Assistant:Add-ons are only available if you've used the Home Assistant Operating System or Home Assistant Supervised installation method. If you installed Home Assistant using any other method then you cannot use add-ons.
-
The other way to install ESPHome is to create a container for it. This is a simple
docker-compose.yml
example:services: homeassistant: build: image: ghcr.io/home-assistant/home-assistant container_name: homeassistant_app restart: always volumes: - ./data/homeassistant/config:/config network_mode: host esphome: image: ghcr.io/esphome/esphome container_name: homeassistant_esphome volumes: - ./data/esphome:/config - /etc/localtime:/etc/localtime:ro ports: - 6052:6052 environment: - USERNAME=admin - PASSWORD=mysecretpassword # Change me
After running
docker compose up
ESPHome can be accessed via an web browser on<Hostname/IP of the server>:6052
.Hint: If you are tired of typing in ip addresses or hostnames combined with ports and having your browser warn you about insecure websites because of missing HTTPS, take a look at NginxProxyManager. It allows you to access your self-hosted services on FQDNs like esphome.mydomain.com with valid SSL certificates.
When opening the web portal you will be greeted with a login prompt where you have to enter the credentials you've defined in the docker-compose.yml
(in this case admin
:mysecretpassword
)
When you open ESPHome for the first time, you will be greeted with a pretty empty screen:
Before adding the microcontroller, we will store the wifi password that the controller will later connect to in ESPHome. This is done in the SECRETS
in the upper right corner. Enter your credentials like this
wifi_ssid: "yourWifiSSID"
wifi_password: "yourWifiPassword"
This way we can reference the password from the configuration of the microcontroller and all the secrets (you can add other ones as well here) are stored in a single file. This has three main advantages:
- Your credentials are stored in a single place and not scattered across multiple files, making them easy to find and manage.
- If you need to change a variable, such as your WIFI password, you only need to change it once.
- The
SECRETS
are stored in a file calledsecrets.yaml
. All the other configurations of ESPHome are also stored in files (and not in a database). This way you can initialize a git repo in the root directory of ESPHome, add thesecrets.yaml
file to the gitignore and keep track of the changes you make.
Now we are finally ready to add the microcontroller to ESPHome. Start by clicking on New Device
and give your project name. I called mine Bettsensor
(german for bedsensor
).
Afterwards ESPHome will ask you to connect your device to the computer you are using. Do so and be sure to use a cable which not only provides power but also transfers data.
Click on Connect
and select your microcontroller from the list.
There can be two things that can make this stage difficult:
- The device you are trying to connect to does not appear in the list: Don't worry, this happened to me. Click on
Cancel
. A new screen will appear in ESPHome to help you with this problem: The interesting part is installing the right drivers. ESPHome presents a list of common chips, chances are that one of them is the right one for you. To find the right one, I suggest you go to the site where you ordered the microcontroller and search for the individual terms: In my case the first chip was the right one. Click on the link and download the appropriate file and install it. - There are too many devices and you don't know which one to choose: To find out which device you want to connect to, click
Cancel
, disconnect the microcontroller from your computer, and then clickConnect
again. Remember the displayed devices. ClickCancel
again, reconnect your device, clickConnect
and select the device that has been added to the list.
After selecting the device click Connect
and after a second the device should pop on the dashboard:
Click on Edit
on the tile of the device. A new screen will pop up with three main components:
- A code editor for the configuration of the device with pre-filled information
- A
Save
button on the top right which saves the changes made in the code editor to ESPHome (and NOT to the device). - An
Install
button which saves the configuration to ESPHome and to the device.
In the following we will adjust the configuration to our needs. All of the following sections are called Component
s in the ESPHome slang. You can find the documentation about all components on the ESPHome website.
ESPHome needs to know the name of the device and what type of device it is dealing with. This is already filled out and does not need to be changed.
esphome:
name: bettsensor
friendly_name: Bettsensor
esp32:
board: esp32dev
framework:
type: arduino
You can find more information about the two configuration parameters here and here.
We enable some basic logging. These logs can be viewed later in ESPHome and can help to debug problems.
logger:
Yes, that's it. No further configuration required. You can also set the log level if you wish, as follows:
logger:
level: DEBUG
You can find more information about this configuration parameter here.
To transfer the configuration wirelessly to the device you have to add an one-liner:
ota:
If you're only planning to transfer changes via cable, you can leave this out, but it doesn't hurt to leave it in, especially if you're installing the ESP32 under your bed where it may be hard to reach.
You can find more information about this configuration parameter here.
The api
configuration enables Home Assistant to access the ESP32.
api:
In addition it is possible to encrypt the connection between the two parties with a 32 byte base64 encoded pre shared key. Such a key can be generated on a command line by running head -c 32 /dev/urandom | base64
. The configuration with encryption set up looks as follows:
api:
encryption:
key: "Q0RumGgCXxzAhLyhRuhs/RcS/iNOAqWwp0n6RINbPOE="
You can find more information about this configuration parameter here.
The wifi
configuration consists of several parts:
- Access to your WiFi: For this we use the secrets we defined above
- The hostname where the device can be reached: If you've configured a DNS A record for your device, you can add it here so you don't have to remember its IP address.
- A fallback access point: If the device cannot connect to your WiFi (for example, after you change your WiFi password or if the access point is out of range), the device will create its own access point that you can connect to and configure.
After the wifi
section there is simple one-liner captive_portal:
. This enables a captive portal that allows you to change the wifi credentials when connecting to the fallback access point:
Image source: https://esphome.io/components/captive_portal.html
The whole configuration looks like this:
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
use_address: bettsensor.fs
ap:
ssid: "Bettsensor Fallback Hotspot"
password: "my secret fallback password"
captive_portal:
You can find more information about this configuration parameter here.
In the last section we will tackle the actual sensing part: We will define the inputs that the device shall manage and how they are configured.
The configuration looks like this:
binary_sensor: # 1
- platform: gpio # 2
pin:
number: 13 # 3
inverted: true # 4
mode:
input: true # 5
pullup: true # 6
name: Bettsensor left # 7
device_class: occupancy # 8
filters: # 9
- delayed_on: 2s
- delayed_off: 2s
- platform: gpio
pin:
number: 12
inverted: true
mode:
input: true
pullup: true
name: Bettsensor right
device_class: occupancy
filters:
- delayed_on: 2s
- delayed_off: 2s
- We tell ESPHome that we are using a
binary sensor
, i.e. a sensor that can beON
orOFF
. Other components could be afan
, alight
or abutton
. - We define that we want to work with
GPIO
(General Purpose Input/Output) pins. Other options might include a temperature sensor built right into the ESP32 itself. - We define the port by specifying its
number
. The ports are labeled on the device. - By default, the sensor reports
ON
when the PIN is untouched. This is not what we want. We want the sensor to reportON
when it is connected to ground, because this is what happens when you apply pressure to the pressure sensor. So we setinverted
totrue
. - Since GPIO pins are General Purpose Input/Output pins we have to set the pin to be an
input
. - We set
pullup
totrue
. This activates the pull-up resistors inside the ESP32 and helps to mitigate fast erroneous switching betweenON
andOFF
. You can find more information here. - The
name
configuration parameter defines what the sensor will be called in Home Assistant. - The
device_class
setting is also for the Home Assistant. It defines what kind of device we are providing. This could be alight
or afan
for example. - Finally, we set two filters: If you turn in bed in the middle of the night or move around a little, you might not apply enough pressure for a short period of time. In this case we don't want the sensor to report no occupancy. For this we enable the
delay_on
anddelay_off
filters. For the sensor to report anON
state, the GPIO pin must be grounded for two seconds at a time. The same is true for theOFF
state.
The entire configuration can be copied for a pressure sensor, only the pin number needs to be adjusted to allow the use of one sensor per side of the bed.
You can find more information about these configuration parameters here.
The complete configuration is as follows:
esphome:
name: bettsensor
friendly_name: Bettsensor
esp32:
board: esp32dev
framework:
type: arduino
logger:
ota:
api:
encryption:
key: "Q0RumGgCXxzAhLyhRuhs/RcS/iNOAqWwp0n6RINbPOE="
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
use_address: bettsensor.fs
ap:
ssid: "Bettsensor Fallback Hotspot"
password: "my secret fallback password"
captive_portal:
binary_sensor:
- platform: gpio
pin:
number: 13
inverted: true
mode:
input: true
pullup: true
name: Bettsensor left
device_class: occupancy
filters:
- delayed_on: 2s
- delayed_off: 2s
- platform: gpio
pin:
number: 12
inverted: true
mode:
input: true
pullup: true
name: Bettsensor right
device_class: occupancy
filters:
- delayed_on: 2s
- delayed_off: 2s
Now we can flash the configuration to the device. The first time flashing the device has to be plugged in into your computer. On changes later wirelessly flashing works.
- Click on
Install
on the top right. This automatically also saves your config. - Select
Plug into this computer
. - Select the port where the device is connected to (as before).
- Afterwards it will install the configtration to your device. Just wait a few seconds.
- Click on
Close
and exit the editor with theX
on the top right.
When clicking on LOGS
of your device in the ESPHome dashboard you can connect to the device and see the logs in realtime:
INFO ESPHome 2023.12.9
INFO Reading configuration /config/bettsensor.yaml...
WARNING GPIO12 is a strapping PIN and should only be used for I/O with care.
Attaching external pullup/down resistors to strapping pins can cause unexpected failures.
See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins
INFO Starting log output from bettsensor.fs using esphome API
INFO Successfully connected to bettsensor @ 192.168.4.221 in 0.155s
INFO Successful handshake with bettsensor @ 192.168.4.221 in 0.048s
[15:26:40][I][app:102]: ESPHome version 2023.12.9 compiled on Jun 13 2024, 15:16:23
[15:26:40][C][wifi:573]: WiFi:
[15:26:40][C][wifi:405]: Local MAC: [redacted]
[15:26:40][C][wifi:410]: SSID: [redacted]
[15:26:40][C][wifi:411]: IP Address: 192.168.4.221
[15:26:40][C][wifi:413]: BSSID: [redacted]
[15:26:40][C][wifi:414]: Hostname: 'bettsensor'
[15:26:40][C][wifi:416]: Signal strength: -59 dB ▂▄▆█
[15:26:40][C][wifi:420]: Channel: 11
[15:26:40][C][wifi:421]: Subnet: 255.255.255.0
[15:26:40][C][wifi:422]: Gateway: 192.168.4.1
[15:26:40][C][wifi:423]: DNS1: 192.168.4.1
[15:26:40][C][wifi:424]: DNS2: 0.0.0.0
[15:26:40][C][logger:439]: Logger:
[15:26:40][C][logger:440]: Level: DEBUG
[15:26:40][C][logger:441]: Log Baud Rate: 115200
[15:26:40][C][logger:443]: Hardware UART: UART0
[15:26:40][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Bettsensor left'
[15:26:40][C][gpio.binary_sensor:015]: Device Class: 'occupancy'
[15:26:40][C][gpio.binary_sensor:016]: Pin: GPIO13
[15:26:40][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Bettsensor right'
[15:26:40][C][gpio.binary_sensor:015]: Device Class: 'occupancy'
[15:26:40][C][gpio.binary_sensor:016]: Pin: GPIO12
[15:26:40][C][captive_portal:088]: Captive Portal:
[15:26:40][C][mdns:115]: mDNS:
[15:26:40][C][mdns:116]: Hostname: bettsensor
[15:26:40][C][ota:097]: Over-The-Air Updates:
[15:26:40][C][ota:098]: Address: bettsensor.fs:3232
[15:26:40][C][api:139]: API Server:
[15:26:40][C][api:140]: Address: bettsensor.fs:6053
[15:26:40][C][api:144]: Using noise encryption: NO
When applying force to the pressure sensors you can see some log outputs:
[15:29:19][D][binary_sensor:036]: 'Bettsensor left': Sending state ON
[15:29:22][D][binary_sensor:036]: 'Bettsensor left': Sending state OFF
[15:29:37][D][binary_sensor:036]: 'Bettsensor right': Sending state ON
[15:29:44][D][binary_sensor:036]: 'Bettsensor right': Sending state OFF
When doing this you can also notice the delay_on
and delay_off
filters we applied.
Normally ESPHome will automatically detect the ESP32 and prompt you to accept the addition. If this does not happen, simply add the integration in the settings application, search for ESPHome
and enter the hostname or IP address of the device:
You will then see the device and its two sensors:
When you apply pressure to the sensor, you will see the change immediately (after the delay_on
period) in Home Assistant:
As you can see, the sensor is not added as any binary input, but as an occupancy detector.
You can skip this step if you are using only one pressure sensor.
Currently we have two independent sensors, one for the left side of the bed, one for the right side. However, for some automations we may need a sensor that reports if one of the two sides (left
or right
or left and right
) is occupied:
- Switch to the
helpers
section in the settings. - Click on
create helper
. - Select
group
. - Choose
binary sensor group
. - Give the group a name and add the two entities for the left and right side.
This sensor is now on
if any of the two sensors report pressure.
The following example shows an automation that turns on a light in the bedroom when motion is detected - but only when no one is in bed:
The whole code might look something like this:
alias: Light - Bedroom - Turn the light on when detecting motion
description: ""
trigger:
- platform: state
entity_id:
- binary_sensor.motion_sensor_bedroom
to: "on"
alias: Motion detected
condition:
- alias: Only after sunset
condition: sun
after: sunset
after_offset: "-01:00:00"
- alias: Noone is in bed
condition: state
entity_id: binary_sensor.bedsensor_any_side
state: "off"
enabled: true
action:
- service: light.turn_on
target:
entity_id:
- light.bedlamp
data:
color_temp: 500
brightness_pct: 1
alias: Turn light on
- wait_for_trigger:
- platform: state
entity_id:
- binary_sensor.motion_sensor_bedroom
from: "on"
to: "off"
alias: Wait for no motion
- delay:
hours: 0
minutes: 0
seconds: 20
milliseconds: 0
alias: Wait after no motion
- service: light.turn_off
target:
entity_id: light.bedlamp
data: {}
alias: Turn light off
mode: restart
max_exceeded: silent
Since we have not only the group but also the individual sensors in Home Assistant, we can create some automations that use this additional information. Examples:
- Turn off all the lights when both people go to bed.
- Turn on a small light when one person gets up in the middle of the night to get a glass of water.
- Play a special Spotify playlist to help people fall asleep when the right side of the bed is occupied.
- Close the shades when someone goes to bed.
- Turn on the fan if the left side of the bed is occupied.
I think this is a great project to dip your toes into ESPHome and get to know the system and its functionality. Also, a bed sensor is an unusual but (in my opinion) great addition to a smart home that will definitely earn some wife approval factor!
This is just a brief introduction to ESPHome. There are so many more possibilities. I suggest you check out the documentation and especially the sensor components
section.
Have fun tinkering :-)