Build a Bed Occupancy Sensor with ESPHome (Under $15)
Knowing whether someone is in bed unlocks powerful automations: lights that stay off when you get up at night, climate adjustments, morning routines that wait until you actually get up. Here’s how to build one for under $15.
What You Need
| Part | Approx. Cost |
|---|---|
| ESP32 dev board (any) | $5 |
| 2x FSR 406 (force-sensitive resistors) | $4 |
| 2x 10K resistors | $0.50 |
| Dupont jumper wires | $1 |
| Total | ~$10-15 |
Where to buy:
How It Works
A force-sensitive resistor (FSR) changes its resistance based on pressure. Put one under each side of the mattress (between the mattress and the bed frame/slats), wire it into a voltage divider with a 10K resistor, and read the analog value with the ESP32’s ADC.
- No pressure: High resistance (~1M ohm), ADC reads near 0
- Person in bed: Low resistance (~1-50K ohm), ADC reads significantly higher
Wiring
Each FSR gets a simple voltage divider circuit:
3.3V ---[FSR]---+---[10K]--- GND
|
GPIO pin (ADC)
- Left side FSR → GPIO 34 (ADC1_CH6)
- Right side FSR → GPIO 35 (ADC1_CH7)
Use GPIO 32-39 on the ESP32 — these are the ADC-capable pins. Avoid GPIO 36 and 39 if you’re using Wi-Fi (they can have noise issues on some boards).
ESPHome Configuration
esphome:
name: bed-sensor
friendly_name: Bed Sensor
esp32:
board: esp32dev
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
api:
encryption:
key: !secret api_key
sensor:
- platform: adc
pin: GPIO34
name: "Bed Left Raw"
id: bed_left_raw
update_interval: 1s
attenuation: 11db
filters:
- sliding_window_moving_average:
window_size: 10
send_every: 5
- platform: adc
pin: GPIO35
name: "Bed Right Raw"
id: bed_right_raw
update_interval: 1s
attenuation: 11db
filters:
- sliding_window_moving_average:
window_size: 10
send_every: 5
binary_sensor:
- platform: template
name: "Bed Left Occupied"
device_class: occupancy
lambda: |-
return id(bed_left_raw).state > 0.5;
filters:
- delayed_on: 3s
- delayed_off: 10s
- platform: template
name: "Bed Right Occupied"
device_class: occupancy
lambda: |-
return id(bed_right_raw).state > 0.5;
filters:
- delayed_on: 3s
- delayed_off: 10s
Calibration
The threshold value (0.5 in the config above) needs calibration for your specific mattress and body weight:
- Flash the config and open the ESPHome logs
- Note the raw ADC value with nobody in bed (usually 0.01-0.1)
- Note the value with someone in bed (usually 0.4-2.0+)
- Set your threshold roughly in the middle
The delayed_on and delayed_off filters prevent false triggers from rolling over or briefly shifting weight.
Physical Installation
- Place each FSR flat on the bed frame slats, roughly where each person’s torso sits
- Run the wires down along a bed leg — DuPont connectors make this easy to disconnect
- The ESP32 can sit on the floor under the bed or mounted to the frame
- Use a USB cable long enough to reach a power outlet
No soldering required if you use DuPont jumper wires.
Home Assistant Automations
Once the binary sensors show up in HA, you can build:
- Both in bed → trigger goodnight routine
- One person gets up → dim hallway nightlight on (not bedroom lights)
- Both out of bed after alarm time → start morning routine
- Bed occupied + TV on past midnight → gentle “go to sleep” notification
Troubleshooting
Sensor always reads occupied: Your threshold is too low. Increase it. Some mattresses transfer enough weight through the slats to register even when “empty.”
Sensor never triggers: Check your wiring. The FSR needs firm, even contact with the surface. If it’s dangling or folded, it won’t register properly.
Readings are noisy: Increase the moving average window size to 20 or add a multiply filter to dampen small fluctuations.
What This Costs vs. Commercial Options
Commercial bed sensors like the Withings Sleep run $100+, require cloud accounts, and don’t integrate natively with Home Assistant. This DIY version costs $15, runs 100% locally, and gives you two independent zones.
The trade-off is setup time — about 30 minutes if you’ve used ESPHome before.
If you’re new to ESPHome, check out my ESPHome vs Tasmota comparison to understand why ESPHome is the better choice for Home Assistant. And for more sensor ideas, see my 15 devices that work without internet.
Want this config ready to go without the DIY? I sell the complete config pack with wiring diagram for $4.99.