@Guinnberg Thought you might be interested in my ESPHome sensor using the DFRobot mmWave. I use it to play a message to remind me to get up if I accidentally sleep in for more than 20 minutes. It works very well.
I have it sitting below my bed and it produces data like this:
Red at 3:25 AM is because I got out of bed.
Things to note:
If you .readPresenceDetection()
within loop()
it can lock the thread for too long and can cause the ESP32 to drop off the network. By doing it in update()
say once or twice a second, it never drops connection.
The rotation of the sensor matters a small amount.
The sensor data is not ideal. It will give random blips once in a while and will turn on and off right after you leave. I process the readings over 25s to get no false positives and almost no false negatives. I think when I roll over onto the edge of the bed every couple weeks I
I used a ESP32-DEVKITC-32D and connected pin TX → 27, RX → 26, G → GND, V → 5V
No other components needed
I added an HTU31D to have temp & humidity as well. SDA → 21 and SCL → 22. Easy to remove from the code. Dangling far away because the ESP was throwing off temperature readings.
Need to add the libaries to your esphome directory:
https://github.com/DFRobotdl/DFRobot_mmWave_Radar
https://github.com/DFRobotdl/DFRobot_mmWave_Radar/archive/refs/heads/master.zip
presence_sensor.h
#include "esphome.h"
#include <HardwareSerial.h>
#include <Wire.h>
#include "DFRobot_mmWave_Radar.h"
#include "Adafruit_HTU31D.h"
using namespace esphome;
static const char *TAG = "PresenceAndMulti";
static const int levels = 25;
HardwareSerial mySerial(1);
DFRobot_mmWave_Radar presenceSensor(&mySerial);
Adafruit_HTU31D htu = Adafruit_HTU31D();
class PresenceAndMultiSensor : public PollingComponent {
public:
Sensor *temperature_sensor = new Sensor();
Sensor *humidity_sensor = new Sensor();
Sensor *presence_sensor = new Sensor();
PresenceAndMultiSensor () : PollingComponent(1000) {}
bool lastLevels[levels] = {0}; //initializes the first to 0 and also all the rest to 0
bool currentlyInBed = false;
bool needToPublish = true;
int ledPin = 2;
int extLedPin = 32;
void setup()
{
Serial.begin(115200);
while (!Serial) {
delay(10); // wait till serial port opens
}
Serial.println("Adafruit HTU31D test");
if (!htu.begin(0x40)) {
Serial.println("Couldn't find sensor!");
while (1);
}
htu.enableHeater(false);
mySerial.begin(115200, SERIAL_8N1, 27, 26);
//pinMode(ledPin, OUTPUT);
//pinMode(extLedPin, OUTPUT);
presenceSensor.factoryReset(); //Restore to the factory settings
presenceSensor.DetRangeCfg(0, 5); //The detection range is as far as 9m
presenceSensor.OutputLatency(0, 0);
}
long long loopIterations = 0;
long long lastTempReading = 0;
void loop() override {
loopIterations++;
if (millis() - 15000 < lastTempReading) //if it hasn't been 5s, return
return;
lastTempReading = millis();
sensors_event_t humidity, temp;
htu.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data
ESP_LOGI(TAG, "temperature %d, humidity: %d", temp.temperature, humidity.relative_humidity);
temperature_sensor->publish_state(temp.temperature);
humidity_sensor->publish_state(humidity.relative_humidity);
}
long long updateIterations = 0;
void update() override {
updateIterations++;
bool presenceVal = presenceSensor.readPresenceDetection();
ESP_LOGI(TAG, "presence %d", presenceVal);
//digitalWrite(extLedPin, presenceVal);
//digitalWrite(ledPin, presenceVal);
//loop through and move the values over
for(int i = 0; i < levels - 1; i++)
{
lastLevels[i] = lastLevels[i+1];
}
//set the latest level
lastLevels[levels - 1] = presenceVal;
//wait for levels to fill with readings
if (updateIterations < 5)
{
return;
}
int numBelow = 0; //turns it on
int numAbove = 0; //turns it off
for(int i = 0; i < levels; i++)
{
if(lastLevels[i] == true)
{
numAbove++;
}
if(lastLevels[i] == false)
{
numBelow++;
}
}
//ESP_LOGI(TAG, "num above: %d. num below: %d", numAbove, numBelow);
if (numAbove >= levels - 5 && !currentlyInBed) { // 4/5 have to be above
currentlyInBed = true;
needToPublish = true; //state has changed
ESP_LOGI(TAG, "New State: on");
} else if (numBelow >= levels && currentlyInBed) { // all have to be below.
currentlyInBed = false;
needToPublish = true; //state has changed
ESP_LOGI(TAG, "New State: off");
}
//ESP_LOGI(TAG, "New State: %s", currentlyInBed ? "on" : "off");
if (needToPublish) {
presence_sensor->publish_state(currentlyInBed);
needToPublish = false;
}
}
};
presence_sensor.yaml
esphome:
name: presence-sensor
platform: ESP32
board: esp32dev
libraries:
- adafruit/Adafruit BusIO
- adafruit/Adafruit Unified Sensor
includes:
- presence_sensor.h
- libraries/DFRobot_mmWave_Radar.h
- libraries/DFRobot_mmWave_Radar.cpp
- libraries/Adafruit_HTU31D.h
- libraries/Adafruit_HTU31D.cpp
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
password: "your password"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
power_save_mode: none
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Presence Sensor"
password: "your password"
captive_portal:
# Example configuration entry
sensor:
- platform: custom
lambda: |-
auto my_sensor = new PresenceAndMultiSensor();
App.register_component(my_sensor);
return {my_sensor->temperature_sensor,my_sensor->humidity_sensor,my_sensor->presence_sensor};
sensors:
- name: "Room Temperature"
unit_of_measurement: °C
accuracy_decimals: 2
state_class: measurement
- name: "Room Humidity"
accuracy_decimals: 1
state_class: measurement
- name: "Bed Occupied"
accuracy_decimals: 0
Excuse the mess. I had to redo this 3 times. The first time I put the sensor upside down.