This has been a great thread, which I’ve taken and implemented using the Seeed 24GHz sensor in ESPHome.
My yaml file
substitutions:
# Change the disp_name to something you want
display_name: Office presence
# Interval of how often the power is updated
update_time: 1s
esphome:
name: office-presence-sensor
comment: ${display_name}
includes:
- uart_read_radar_sensor.h
libraries:
- "Seeed Arduino 24GHz Radar Sensor"
esp32:
board: esp32dev
framework:
type: arduino
wifi:
ssid: something
password: something
fast_connect: true
# power_save_mode: none
manual_ip:
static_ip: 192.168.1.33
gateway: 192.168.1.1
subnet: 255.255.255.0
dns1: 192.168.1.1
# Enable logging
logger:
level: INFO #makes uart stream available in esphome logstream
# Enable Home Assistant API
api:
services:
# Service to send a command directly to the display. Useful for testing
- service: send_command
variables:
cmd: string
then:
- uart.write: !lambda
char buf[128];
sprintf(buf, "%s\n", cmd.c_str());
std::string s = buf;
return std::vector<unsigned char>( s.begin(), s.end() );
ota:
password: "s"
uart:
id: uart_bus
tx_pin: GPIO17
rx_pin: GPIO16
baud_rate: 9600
# debug:
# Example configuration entry
binary_sensor:
- platform: gpio
pin: GPIO21
name: ${display_name} Presence
device_class: motion
filters:
- delayed_on: 100ms
- delayed_off: 500ms
- platform: gpio
pin: GPIO22
name: ${display_name} Moving
device_class: moving
filters:
- delayed_on: 100ms
- delayed_off: 500ms
sensor:
- platform: custom
lambda: |-
auto my_custom_sensor = new UartReadRadarSensor(id(uart_bus));
App.register_component(my_custom_sensor);
return {my_custom_sensor->action_status, my_custom_sensor->movement_status };
sensors:
- name: ${display_name} Action
id: office_presence_action
- name: ${display_name} Movement
id: office_presence_movement
# Example configuration entry
text_sensor:
- platform: template
name: "${display_name} Action Description"
id: office_presence_action_description
lambda: |-
if( id(office_presence_action).state == 2 ) {
return{ "Movement" };
}
else if( id(office_presence_action).state == 3 ) {
return{ "Stationary" };
}
else if( id(office_presence_action).state == 4 ) {
return{ "No-movement" };
}
else if( id(office_presence_action).state == 5 ) {
return{ "Closer" };
}
else if( id(office_presence_action).state == 6 ) {
return{ "Further" };
}
return {"Vacant"};
update_interval: ${update_time}
- platform: template
name: "${display_name} Movement Description"
id: office_presence_movement_description
lambda: |-
if( id(office_presence_movement).state == 1 ) {
return{ "Still" };
}
else if( id(office_presence_movement).state == 2 ) {
return{ "Micro" };
}
else if( id(office_presence_movement).state == 3 ) {
return{ "Slow" };
}
else if( id(office_presence_movement).state == 4 ) {
return{ "Fast" };
}
return {"None"};
update_interval: ${update_time}
My uart_read_radar_sensor.h file
#include "esphome.h"
#include "radar.h"
#define MESSAGE_HEAD 0x55
#define NEWLINE 0x0a
class UartReadRadarSensor : public Component, public UARTDevice {
public:
radar RADAR;
Sensor *action_status = new Sensor();
Sensor *movement_status = new Sensor();
UartReadRadarSensor(UARTComponent *parent) : UARTDevice(parent) {}
void setup() override {
// nothing to do here
}
int Bodysign_judgment(int ad1, int ad2, int ad3, int ad4, int ad5){
float s;
s = RADAR.Bodysign_val(ad1, ad2, ad3, ad4, ad5);
ESP_LOGV("custom", "Bodysign_val = %f", s );
if(s < 1.0){
return 0; // NOBODY;
}
else if(s < 2.0){
return 1; // STATIONARY;
}
else if(s >= 2.0 && s < 30.0){
return 2; // MICRO MOVEMENTS;
}
else if(s >= 30.0 && s < 60.0){
return 3; // SLOW MOVEMENT;
}
else if(s >= 60.0){
return 4; // FAST MOVEMENT;
}
return -1;
}
int readline(int readch, int *thisMessage, int len)
{
static int pos = 0;
int rpos;
ESP_LOGV("custom", "this char = %2x; pos = %i", readch, pos );
// if the read char is not the marker and the pos is zero, skip
// i.e. skip until the start marker is found
if( readch != MESSAGE_HEAD && pos == 0 ){
return -1;
}
// if the read char is a newline and the pos is 1, store the data
// I find i'm getting 0x55, then 0x0a, then the good data
if( readch == NEWLINE && pos == 1 ){
if (pos < len-1) {
thisMessage[pos++] = readch;
thisMessage[pos] = 0;
}
return -1;
}
// if the read char is the marker and the pos is not zero, return result
if( readch == MESSAGE_HEAD && pos != 0 ){
rpos = pos;
pos = 0; // Reset position index ready for next time
return rpos;
}
if (readch != -1) {
switch (readch) {
// case '\r': // Return on CR
// break;
case NEWLINE: // Return on new-line
rpos = pos;
pos = 0; // Reset position index ready for next time
return rpos;
default:
if (pos < len-1) {
thisMessage[pos++] = readch;
thisMessage[pos] = 0;
}
}
}
// No end of line has been found, so return -1.
return -1;
}
void loop() override {
const int max_line_length = 14;
static int thisMessage[max_line_length];
int activity_result = 0;
int movement_result = 0;
while (available()) {
if(readline(read(), thisMessage, max_line_length) > 0) {
activity_result = RADAR.Situation_judgment(thisMessage[4], thisMessage[5], thisMessage[6], thisMessage[7], thisMessage[8]);
ESP_LOGD("custom", "The value of sensor is: %i = RADAR.Situation_judgment( %2x, %2x, %2x, %2x, %2x, )", activity_result, thisMessage[4], thisMessage[5], thisMessage[6], thisMessage[7], thisMessage[8] );
if( activity_result > 0 ) {
action_status->publish_state( activity_result );
}
movement_result = Bodysign_judgment(thisMessage[5], thisMessage[6], thisMessage[7], thisMessage[8], thisMessage[9]);
ESP_LOGD("custom", "The value of sensor is: %i = Bodysign_judgment( %2x, %2x, %2x, %2x, %2x, )", movement_result, thisMessage[5], thisMessage[6], thisMessage[7], thisMessage[8], thisMessage[9] );
if( thisMessage[5] == 6 ){
movement_status->publish_state( movement_result );
}
}
}
}
};