Část první
Použité díly:
D1 mini
Senzor LD2410 (rozměr 7x35 mm 5 pinů , VCC, GND, TX, RX, OUT napájení 5V)
Konfigurační deska ( vzal jsem ji z důvodu že senzor má rozteč pinů 1,7 mm a to se mi fakt nechtělo pájet UART:
Kód: Vybrat vše
#include "esphome.h"
#define CHECK_BIT(var, pos) (((var) >> (pos)) & 1)
class LD2410 : public PollingComponent, public UARTDevice
{
public:
LD2410(UARTComponent *parent) : UARTDevice(parent) {}
BinarySensor *hasTarget = new BinarySensor();
BinarySensor *hasMovingTarget = new BinarySensor();
BinarySensor *hasStillTarget = new BinarySensor();
BinarySensor *lastCommandSuccess = new BinarySensor();
Sensor *movingTargetDistance = new Sensor();
Sensor *movingTargetEnergy = new Sensor();
Sensor *stillTargetDistance = new Sensor();
Sensor *stillTargetEnergy = new Sensor();
Sensor *detectDistance = new Sensor();
Number *maxMovingDistanceRange;
Number *maxStillDistanceRange;
int movingSensitivities[9] = {0};
int stillSensitivities[9] = {0};
Number *noneDuration;
long lastPeriodicMillis = millis();
void setNumbers(Number *maxMovingDistanceRange_, Number *maxStillDistanceRange_, Number *noneDuration_){
maxMovingDistanceRange = maxMovingDistanceRange_;
maxStillDistanceRange = maxStillDistanceRange_;
noneDuration = noneDuration_;
}
void sendCommand(char *commandStr, char *commandValue, int commandValueLen)
{
lastCommandSuccess->publish_state(false);
// frame start bytes
write_byte(0xFD);
write_byte(0xFC);
write_byte(0xFB);
write_byte(0xFA);
// length bytes
int len = 2;
if (commandValue != nullptr)
len += commandValueLen;
write_byte(lowByte(len));
write_byte(highByte(len));
// command string bytes
write_byte(commandStr[0]);
write_byte(commandStr[1]);
// command value bytes
if (commandValue != nullptr)
{
for (int i = 0; i < commandValueLen; i++)
{
write_byte(commandValue[i]);
}
}
// frame end bytes
write_byte(0x04);
write_byte(0x03);
write_byte(0x02);
write_byte(0x01);
delay(50);
}
int twoByteToInt(char firstByte, char secondByte)
{
return (int16_t)(secondByte << 8) + firstByte;
}
void handlePeriodicData(char *buffer, int len)
{
if (len < 12)
return; // 4 frame start bytes + 2 length bytes + 1 data end byte + 1 crc byte + 4 frame end bytes
if (buffer[0] != 0xF4 || buffer[1] != 0xF3 || buffer[2] != 0xF2 || buffer[3] != 0xF1)
return; // check 4 frame start bytes
if (buffer[7] != 0xAA || buffer[len - 6] != 0x55 || buffer[len - 5] != 0x00)
return; // data head=0xAA, data end=0x55, crc=0x00
/*
Data Type: 6th byte
0x01: Engineering mode
0x02: Normal mode
*/
char dataType = buffer[5];
/*
Target states: 9th byte
0x00 = No target
0x01 = Moving targets
0x02 = Still targets
0x03 = Moving+Still targets
*/
char stateByte = buffer[8];
hasTarget->publish_state(stateByte != 0x00);
/*
Reduce data update rate to prevent home assistant database size glow fast
*/
long currentMillis = millis();
if (currentMillis - lastPeriodicMillis < 1000)
return;
lastPeriodicMillis = currentMillis;
hasMovingTarget->publish_state(CHECK_BIT(stateByte, 0));
hasStillTarget->publish_state(CHECK_BIT(stateByte, 1));
/*
Moving target distance: 10~11th bytes
Moving target energy: 12th byte
Still target distance: 13~14th bytes
Still target energy: 15th byte
Detect distance: 16~17th bytes
*/
int newMovingTargetDistance = twoByteToInt(buffer[9], buffer[10]);
if (movingTargetDistance->get_state() != newMovingTargetDistance)
movingTargetDistance->publish_state(newMovingTargetDistance);
int newMovingTargetEnergy = buffer[11];
if (movingTargetEnergy->get_state() != newMovingTargetEnergy)
movingTargetEnergy->publish_state(newMovingTargetEnergy);
int newStillTargetDistance = twoByteToInt(buffer[12], buffer[13]);
if (stillTargetDistance->get_state() != newStillTargetDistance)
stillTargetDistance->publish_state(newStillTargetDistance);
int newStillTargetEnergy = buffer[14];
if (stillTargetEnergy->get_state() != newStillTargetEnergy)
stillTargetEnergy->publish_state(buffer[14]);
int newDetectDistance = twoByteToInt(buffer[15], buffer[16]);
if (detectDistance->get_state() != newDetectDistance)
detectDistance->publish_state(newDetectDistance);
if (dataType == 0x01)
{ // engineering mode
// todo: support engineering mode data
}
}
void handleACKData(char *buffer, int len)
{
if (len < 10)
return;
if (buffer[0] != 0xFD || buffer[1] != 0xFC || buffer[2] != 0xFB || buffer[3] != 0xFA)
return; // check 4 frame start bytes
if (buffer[7] != 0x01)
return;
if (twoByteToInt(buffer[8], buffer[9]) != 0x00)
{
lastCommandSuccess->publish_state(false);
return;
}
lastCommandSuccess->publish_state(true);
switch (buffer[6])
{
case 0x61: // Query parameters response
{
if (buffer[10] != 0xAA)
return; // value head=0xAA
/*
Moving distance range: 13th byte
Still distance range: 14th byte
*/
maxMovingDistanceRange->publish_state(buffer[12]);
maxStillDistanceRange->publish_state(buffer[13]);
/*
Moving Sensitivities: 15~23th bytes
Still Sensitivities: 24~32th bytes
*/
for (int i = 0; i < 9; i++)
{
movingSensitivities[i] = buffer[14 + i];
}
for (int i = 0; i < 9; i++)
{
stillSensitivities[i] = buffer[23 + i];
}
/*
None Duration: 33~34th bytes
*/
noneDuration->publish_state(twoByteToInt(buffer[32], buffer[33]));
}
break;
default:
break;
}
}
void readline(int readch, char *buffer, int len)
{
static int pos = 0;
if (readch >= 0)
{
if (pos < len - 1)
{
buffer[pos++] = readch;
buffer[pos] = 0;
}
else
{
pos = 0;
}
if (pos >= 4)
{
if (buffer[pos - 4] == 0xF8 && buffer[pos - 3] == 0xF7 && buffer[pos - 2] == 0xF6 && buffer[pos - 1] == 0xF5)
{
handlePeriodicData(buffer, pos);
pos = 0; // Reset position index ready for next time
}
else if (buffer[pos - 4] == 0x04 && buffer[pos - 3] == 0x03 && buffer[pos - 2] == 0x02 && buffer[pos - 1] == 0x01)
{
handleACKData(buffer, pos);
pos = 0; // Reset position index ready for next time
}
}
}
return;
}
void setConfigMode(bool enable)
{
char cmd[2] = {enable ? 0xFF : 0xFE, 0x00};
char value[2] = {0x01, 0x00};
sendCommand(cmd, enable ? value : nullptr, 2);
}
void queryParameters()
{
char cmd_query[2] = {0x61, 0x00};
sendCommand(cmd_query, nullptr, 0);
}
void setup() override
{
set_update_interval(15000);
}
void loop() override
{
const int max_line_length = 80;
static char buffer[max_line_length];
while (available())
{
readline(read(), buffer, max_line_length);
}
}
void setEngineeringMode(bool enable)
{
char cmd[2] = {enable ? 0x62 : 0x63, 0x00};
sendCommand(cmd, nullptr, 0);
}
void setMaxDistancesAndNoneDuration(int maxMovingDistanceRange, int maxStillDistanceRange, int noneDuration)
{
char cmd[2] = {0x60, 0x00};
char value[18] = {0x00, 0x00, lowByte(maxMovingDistanceRange), highByte(maxMovingDistanceRange), 0x00, 0x00, 0x01, 0x00, lowByte(maxStillDistanceRange), highByte(maxStillDistanceRange), 0x00, 0x00, 0x02, 0x00, lowByte(noneDuration), highByte(noneDuration), 0x00, 0x00};
sendCommand(cmd, value, 18);
queryParameters();
}
void factoryReset()
{
char cmd[2] = {0xA2, 0x00};
sendCommand(cmd, nullptr, 0);
}
void reboot()
{
char cmd[2] = {0xA3, 0x00};
sendCommand(cmd, nullptr, 0);
// not need to exit config mode because the ld2410 will reboot automatically
}
void setBaudrate(int index)
{
char cmd[2] = {0xA1, 0x00};
char value[2] = {index, 0x00};
sendCommand(cmd, value, 2);
}
void update()
{
}
};
Kód: Vybrat vše
esphome:
name: ld2410
includes:
- components/senzor_pritomnost/ld2410_uart.h
on_boot:
priority: 600
# ...
then:
- lambda: |-
auto uart_component = static_cast<LD2410 *>(ld2410);
uart_component->setNumbers(maxMovingDistanceRange, maxStillDistanceRange, noneDuration);
esp8266:
board: d1_mini
logger:
baud_rate: 0
api:
ota:
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: "LD2410 Fallback Hotspot"
captive_portal:
uart:
id: uart1
tx_pin: TX
rx_pin: RX
baud_rate: 256000 # Změňit podle sebe v nastavení
parity: NONE
stop_bits: 1
debug:
direction: BOTH
dummy_receiver: false
after:
delimiter: [0xF8,0xF7,0xF6,0xF5]
custom_component:
- lambda: |-
return {new LD2410(id(uart1))};
components:
- id: ld2410
binary_sensor:
- platform: custom
lambda: |-
auto uart_component = static_cast<LD2410 *>(ld2410);
return {uart_component->hasTarget,uart_component->hasMovingTarget,uart_component->hasStillTarget,uart_component->lastCommandSuccess};
binary_sensors:
- name: "Cíl"
- name: "Pohyb cíl"
- name: "Stále cíl"
- name: "Úspěch příkazu"
sensor:
- platform: custom
lambda: |-
auto uart_component = static_cast<LD2410 *>(ld2410);
return {uart_component->movingTargetDistance,uart_component->movingTargetEnergy,uart_component->stillTargetDistance,uart_component->stillTargetEnergy,uart_component->detectDistance};
sensors:
- name: "Pohyb cíl vzdálenost"
unit_of_measurement: "cm"
accuracy_decimals: 0
- name: "Pohyb cíl energie"
unit_of_measurement: "%"
accuracy_decimals: 0
- name: "Stále cíl vzdálenost"
unit_of_measurement: "cm"
accuracy_decimals: 0
- name: "Stále cíl energie"
unit_of_measurement: "%"
accuracy_decimals: 0
- name: "Detekce vzdálenosti"
unit_of_measurement: "cm"
accuracy_decimals: 0
number:
- platform: template
name: "Max rozsah pohyb vzdálenost"
id: maxMovingDistanceRange
min_value: 1
max_value: 8
step: 1
update_interval: never
optimistic: true
set_action:
- lambda: |-
auto uart_component = static_cast<LD2410 *>(ld2410);
uart_component->setMaxDistancesAndNoneDuration(x,id(maxStillDistanceRange).state,id(noneDuration).state);
- platform: template
name: "Max rozsah stále vzdálenost"
id: maxStillDistanceRange
min_value: 1
max_value: 8
step: 1
update_interval: never
optimistic: true
set_action:
- lambda: |-
auto uart_component = static_cast<LD2410 *>(ld2410);
uart_component->setMaxDistancesAndNoneDuration(id(maxMovingDistanceRange).state,x,id(noneDuration).state);
- platform: template
name: "Doba trvání"
id: noneDuration
min_value: 0
max_value: 32767
step: 1
mode: box
update_interval: never
optimistic: true
set_action:
- lambda: |-
auto uart_component = static_cast<LD2410 *>(ld2410);
uart_component->setMaxDistancesAndNoneDuration(id(maxMovingDistanceRange).state,id(maxStillDistanceRange).state,x);
button:
- platform: template
name: "Reboot LD2410"
on_press:
lambda: 'static_cast<LD2410 *>(ld2410)->reboot();'
- platform: template
name: "Zapnout režim konfigurace"
on_press:
- lambda: 'static_cast<LD2410 *>(ld2410)->setConfigMode(true);'
- platform: template
name: "Vypnout režim konfigurace"
on_press:
- lambda: 'static_cast<LD2410 *>(ld2410)->setConfigMode(false);'
- platform: template
name: "Stáhnout konfiguraci"
on_press:
- lambda: 'static_cast<LD2410 *>(ld2410)->queryParameters();'
- platform: template
name: "Nastav rychlost na 256000"
on_press:
- lambda: 'static_cast<LD2410 *>(ld2410)->setBaudrate(7);'
- platform: template
name: "Nastav rychlost na 115200"
on_press:
- lambda: 'static_cast<LD2410 *>(ld2410)->setBaudrate(5);'
- platform: template
name: "Nastav rychlost na 9600"
on_press:
- lambda: 'static_cast<LD2410 *>(ld2410)->setBaudrate(1);'
Prozatím jsem ho jen rozjel a nejsou žádné testy.
Zatím funguje bez problému, ale uvidíme jak se bude chovat při různých nastavení vzdálenosti a úhlu.
Zatím jen takový bastl na stole Led červená že je pod napětím a zelená, detekuje mě jako přítomnost