Tasmota/tasmota/tasmota_xsns_sensor/xsns_102_ld2410s.ino

744 lines
24 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
xsns_102_ld2410s.ino - HLK-LD2410S 24GHz smart wave motion sensor support for Tasmota
SPDX-FileCopyrightText: 2022 Theo Arends, 2024 md5sum-as (https://github.com/md5sum-as)
SPDX-License-Identifier: GPL-3.0-only
*/
#ifdef USE_LD2410S
/*********************************************************************************************\
* HLK-LD2410S 24GHz smart wave motion sensor
*
* Attention!
* This module works with HLK-LD2410S devices.
* The module does not support another HLK-LD2410 devices.
*
* Available commands:
* LD2410S_Parameters - showing previously received parameters
* LD2410S_ReRead - reread common, trigger and hold parameters from device
* LD2410S_SetCommon 0-16,1-16,10-120,5-80,5-80,5/10 - set common: near door, far door, hold_time, status_freq, distance_freq, response_speed
* LD2410S_SetTrigger n,n1..n16 - set trigger values (16)
* LD2410S_SetHold n,n1..n16 - set hold values (16)
* LD2410S_Out_Mode 0/1 - set device output mode 0-short (only distance and 0/1 - no people, 2/3 detect people), 1-normal mode (add energy values per door)
* LD2410S_AutoUpdate 2,1,60 - start autoupdate trigger and hold thresholds/ Params: trigger_scale,retension_factor,scan_time
* LD2410S_Follow 0/1 - if 1 then start reports every seconds
*
\*********************************************************************************************/
#define XSNS_102 102
#undef TM_SERIAL_BUFFER_SIZE
#define TM_SERIAL_BUFFER_SIZE 128
#define LD2410S_BUFFER_SIZE TM_SERIAL_BUFFER_SIZE // 128
#define LD2410S_NUM_GATES 16
#define LD2410S_CMND_START_CONFIGURATION 0xFF
#define LD2410S_CMND_END_CONFIGURATION 0xFE
#define LD2410S_CMND_SET_COMMON 0x70
#define LD2410S_CMND_READ_COMMON 0x71
#define LD2410S_CMND_AUTO_THRESHOLD 0x09
#define LD2410S_CMND_WRITE_TRIGGER 0x72
#define LD2410S_CMND_READ_TRIGGER 0x73
#define LD2410S_CMND_WRITE_HOLD 0x76
#define LD2410S_CMND_READ_HOLD 0x77
#define LD2410S_CMND_OUTPUT_MODE 0x7A
#define CMD_LD2410S_Read_Parametrs 40
#define CMD_LD2410S_Write_Common 50
#define CMD_LD2410S_Out_Mode 60
#define CMD_LD2410S_Auto_Update 100
#define CMD_LD2410S_Write_Trigger 70
#define CMD_LD2410S_Write_Hold 65
const uint8_t LD2410_config_header[4] = {0xFD, 0xFC, 0xFB, 0xFA};
const uint8_t LD2410_config_footer[4] = {0x04, 0x03, 0x02, 0x01};
const uint8_t LD2410_target_header[4] = {0xF4, 0xF3, 0xF2, 0xF1};
const uint8_t LD2410_target_footer[4] = {0xF8, 0xF7, 0xF6, 0xF5};
#include <TasmotaSerial.h>
TasmotaSerial *LD2410Serial = nullptr;
struct {
uint8_t *buffer;
// Common params
uint8_t far_end;
uint8_t near_end;
uint8_t hold_duration;
uint8_t status_report_f;
uint8_t distance_report_f;
uint8_t response_speed;
// gates param
uint8_t trigger_energy[LD2410S_NUM_GATES]; // not 16
uint8_t hold_energy[LD2410S_NUM_GATES]; // not 16
// Report values
uint16_t detect_distance;
uint8_t energy[LD2410S_NUM_GATES]; // not 16
uint8_t human;
uint8_t human_last;
// uint8_t state;
uint8_t step;
uint8_t retry;
uint8_t next_step;
uint8_t byte_counter;
uint8_t ack;
uint8_t out_mode;
uint8_t report_type;
uint8_t follow;
// autoupdate
uint8_t auto_upd__scale;
uint8_t auto_upd_retension;
uint8_t auto_upd_time;
} LD2410S;
/********************************************************************************************/
void Ld1410HandleTargetData(void) {
if (LD2410S.step > 150) {LD2410S.step = 20;} //Stop boot delay on receive valid data
/*
F4F3F2F1 - 0..3
4600 - 4,5 length 70
01 - 6 type
02 - 7 people
9100 - 8,9 distance
4600 - 10,11 - old dist???
00000000 - 12..15 0..3
543D0000 - 16..19 4..7
1D160000 - 20..23 8..11
2E070000 D8020000 B0040000 DF000000 FD010000 74040000 B4070000 72090000 F0040000 C8000000 F0040000 A4060000 CE050000 F8F7F6F5
*/
if ((LD2410S.buffer[6] == 1) && (LD2410S.buffer[4] == 70)) {
if (LD2410S.report_type == 3) {
Ld2410ExecCommand(CMD_LD2410S_Read_Parametrs);
}
LD2410S.report_type = 1;
LD2410S.detect_distance = LD2410S.buffer[9] << 8 | LD2410S.buffer[8];
LD2410S.human = LD2410S.buffer[7];
for (uint32_t i = 0; i < LD2410S_NUM_GATES; i++) {
LD2410S.energy[i] = /*LD2410S.buffer[i * 4 + 13] << 8 |*/ LD2410S.buffer[i * 4 + 12];
}
}
if ((LD2410S.buffer[6]) == 3) {
/* F4F3F2F1 0300 03 6400 F8F7F6F5
len type percent
*/
LD2410S.report_type = 3;
LD2410S.detect_distance = LD2410S.buffer[7];
}
}
void Ld1410HandleConfigData(void) {
LD2410S.ack = 0;
if ((LD2410S.buffer[8]==0) && (LD2410S.buffer[7]==1)) {
LD2410S.ack = LD2410S.buffer[6];
}
if (LD2410S_CMND_READ_COMMON == LD2410S.buffer[6]) {
// FDFCFBFA - header 0,1,2,3
// 1C00 - datalen 4,5
// 7101 - command 6,7
// 0000 - ACK 8,9
// 00000000 - Near 10,11,12,13
// 0C000000 - Far 14,15,16,17
// 0A000000 - Hold 18,19,20,21
// 28000000 - StatusF 22,23,24,25
// 05000000 - DistanceF 26,27,28,29
// 05000000 - RespSpeed 30,31,32,33
// 04030201
LD2410S.near_end = LD2410S.buffer[10];
LD2410S.far_end = LD2410S.buffer[14];
LD2410S.hold_duration = LD2410S.buffer[18];
LD2410S.status_report_f = LD2410S.buffer[22];
LD2410S.distance_report_f = LD2410S.buffer[26];
LD2410S.response_speed = LD2410S.buffer[30];
} else if (LD2410S_CMND_READ_TRIGGER == LD2410S.buffer[6]) {
/*FDFCFBFA - 0..3
4400 - 4,5
7301 - 6,7
0000 - 8,9
30000000 2A000000 24000000 22000000 20000000 1F000000 1F000000 1F000000 1F000000 1F000000 1F000000 1F000000 1F000000 1F000000 1F000000 1F000000 04030201
10 14 20
*/
for (uint32_t i = 0; i < LD2410S_NUM_GATES; i++) {
LD2410S.trigger_energy[i] = /*LD2410S.buffer[i * 4 + 11] << 8 |*/ LD2410S.buffer[i * 4 + 10];
}
} else if (LD2410S_CMND_READ_HOLD == LD2410S.buffer[6]) {
for (uint32_t i = 0; i < LD2410S_NUM_GATES; i++) {
LD2410S.hold_energy[i] = /*LD2410S.buffer[i * 4 + 11] << 8 |*/ LD2410S.buffer[i * 4 + 10];
}
}
}
bool Ld2410Match(const uint8_t *header, uint32_t offset) {
for (uint32_t i = 0; i < 4; i++) {
if (LD2410S.buffer[offset +i] != header[i]) { return false; }
}
return true;
}
bool Ld2410MatchShort(uint32_t offset) {
if (LD2410S.buffer[offset] != 0x6e) { return false; }
if (LD2410S.buffer[offset+1] > 0x03) { return false; }
if (LD2410S.buffer[offset+4] != 0x62) { return false; }
LD2410S.detect_distance=LD2410S.buffer[offset+3] << 8 | LD2410S.buffer[offset+2];
LD2410S.human = LD2410S.buffer[offset+1];
if (LD2410S.report_type == 3) {
Ld2410ExecCommand(CMD_LD2410S_Read_Parametrs);
}
LD2410S.report_type = 0;
if (LD2410S.step > 150) {LD2410S.step = 20;} //Stop boot delay on receive valid data
return true;
}
void Ld2410Input(void) {
while (LD2410Serial->available()) {
yield(); // Fix watchdogs
LD2410S.buffer[LD2410S.byte_counter++] = LD2410Serial->read();
// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("LD2: Rcvd %*_H"), LD2410.byte_counter, LD2410.buffer);
if (LD2410S.byte_counter < 5) { continue; } // Need first four header bytes
uint32_t header_start = LD2410S.byte_counter -5; // Fix interrupted header transmits
bool short_report = (Ld2410MatchShort(header_start));
if (short_report) {
LD2410S.byte_counter = 0; // Finished
break; // Exit loop to satisfy yields
}
bool target_header = (Ld2410Match(LD2410_target_header, header_start)); // F4F3F2F1
bool config_header = (Ld2410Match(LD2410_config_header, header_start)); // FDFCFBFA
if ((target_header || config_header) && (header_start != 0)) {
memmove(LD2410S.buffer, LD2410S.buffer + header_start, 5); // Sync buffer with header
LD2410S.byte_counter = 5;
}
if (LD2410S.byte_counter < 6) { continue; } // Need packet size bytes
target_header = (Ld2410Match(LD2410_target_header, 0)); // F4F3F2F1
config_header = (Ld2410Match(LD2410_config_header, 0)); // FDFCFBFA
if (target_header || config_header) {
uint32_t len = LD2410S.buffer[4] +10; // Total packet size
if (len > LD2410S_BUFFER_SIZE) {
LD2410S.byte_counter = 0; // Invalid data
break; // Exit loop to satisfy yields
}
if (LD2410S.byte_counter < len) { continue; } // Need complete packet
if (target_header) { // F4F3F2F1
if (Ld2410Match(LD2410_target_footer, len -4)) { // F8F7F6F5
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("LD2: Rcvd %*_H"), len, LD2410S.buffer);
Ld1410HandleTargetData();
}
}
else if (config_header) { // FDFCFBFA
if (Ld2410Match(LD2410_config_footer, len -4)) { // 04030201
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("LD2: Rcvd %*_H"), len, LD2410S.buffer);
Ld1410HandleConfigData();
LD2410Serial->setReadChunkMode(0); // Disable chunk mode fixing Hardware Watchdogs
}
}
}
LD2410S.byte_counter = 0; // Finished or bad received footer
break; // Exit loop to satisfy yields
}
// If here then LD2410.byte_counter could still be partial correct for next loop
}
void Ld2410SendCommand(uint32_t command, uint8_t *val = nullptr, uint32_t val_len = 0);
void Ld2410SendCommand(uint32_t command, uint8_t *val, uint32_t val_len) {
uint32_t len = val_len +12;
uint8_t buffer[len];
buffer[0] = 0xFD;
buffer[1] = 0xFC;
buffer[2] = 0xFB;
buffer[3] = 0xFA;
buffer[4] = val_len +2;
buffer[5] = 0x00;
buffer[6] = command;
buffer[7] = 0x00;
if (val) {
for (uint32_t i = 0; i < val_len; i++) {
buffer[8 +i] = val[i];
}
}
buffer[8 +val_len] = 0x04;
buffer[9 +val_len] = 0x03;
buffer[10 +val_len] = 0x02;
buffer[11 +val_len] = 0x01;
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("LD2: Send %*_H"), len, buffer);
LD2410Serial->setReadChunkMode(1); // Enable chunk mode introducing possible Hardware Watchdogs
LD2410Serial->flush();
LD2410Serial->write(buffer, len);
}
void Ld2410SetConfigMode(void) { // 0xFF
uint8_t value[2] = { 0x01, 0x00 };
Ld2410SendCommand(LD2410S_CMND_START_CONFIGURATION, value, sizeof(value));
}
void Ld2410SetOutputMode(void) {
uint8_t value[6] = { 0,0,0,0,0,0 };
value[2] = LD2410S.out_mode?1:0;
Ld2410SendCommand(LD2410S_CMND_OUTPUT_MODE, value, sizeof(value));
}
void Ld2410ReadCommonParameters(void) {
/*
Detection of the closest distance door 0x0A 0~16
Detection of the farthest distance door 0x05 1~16
No delay time 0x06 10 ~ 120s
Status reporting frequency 0x02 0.5 ~ 80.5SteppingHz)
Distance reporting frequency 0x0C 0.5 ~ 80.5SteppingHz)
Response speed 0x0B 5(normal)/10(fast)-
*/
uint8_t value[12] = { 0x0A, 0x00, 0x05, 0x00, 0x06, 0x00, 0x02, 0x00, 0x0C, 0x00, 0x0B, 0x00};
Ld2410SendCommand(LD2410S_CMND_READ_COMMON, value, sizeof(value));
}
void Ld2410SetCommonParametrs(void) {
uint8_t value[36] = { 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00 };
value[2] = LD2410S.near_end;
value[8] = LD2410S.far_end;
value[14] = LD2410S.hold_duration;
value[20] = LD2410S.status_report_f;
value[26] = LD2410S.distance_report_f;
value[32] = LD2410S.response_speed;
Ld2410SendCommand(LD2410S_CMND_SET_COMMON, value, sizeof(value));
}
#define Ld2410ReadTrigger() Ld2410ReadTriggerHold(LD2410S_CMND_READ_TRIGGER)
#define Ld2410ReadHold() Ld2410ReadTriggerHold(LD2410S_CMND_READ_HOLD)
void Ld2410ReadTriggerHold(uint8_t cmdn) {
uint8_t value[32] = {0,0, 1,0, 2,0, 3,0, 4,0, 5,0, 6,0, 7,0, 8,0, 9,0, 10,0, 11,0, 12,0, 13,0, 14,0, 15,0};
Ld2410SendCommand(cmdn, value, sizeof(value));
}
void Ld2410AutoUpdate(void) {
uint8_t value[6] = { 0 };
value[0] = LD2410S.auto_upd__scale;
value[2] = LD2410S.auto_upd_retension;
value[4] = LD2410S.auto_upd_time;
Ld2410SendCommand(LD2410S_CMND_AUTO_THRESHOLD, value, sizeof(value));
}
#define Ld2410WriteTrigger() Ld2410WriteTriggerHold(LD2410S_CMND_WRITE_TRIGGER)
#define Ld2410WriteHold() Ld2410WriteTriggerHold(LD2410S_CMND_WRITE_HOLD)
void Ld2410WriteTriggerHold(uint8_t cmnd) {
uint8_t value[96] = { 0 };
for (uint32_t i = 0; i < LD2410S_NUM_GATES; i++) {
value[i*6]=i;
if (cmnd == LD2410S_CMND_WRITE_TRIGGER) {
value[i*6+2]=LD2410S.trigger_energy[i];
}else{
value[i*6+2]=LD2410S.hold_energy[i];
}
}
Ld2410SendCommand(cmnd, value, sizeof(value));
}
void Ld2410ExecCommand(uint8_t cmnd) {
LD2410S.step = 15;
LD2410S.next_step = cmnd;
}
/********************************************************************************************/
void Ld2410Every100MSecond(void) {
if (LD2410S.step) {
LD2410S.step--;
switch (LD2410S.step) {
// boot module delay
case 200:
LD2410S.step = 15;
break;
// 100 auto update
case 99:
Ld2410AutoUpdate();
LD2410S.step = 5;
break;
// 70 - write trigger
case 69:
Ld2410WriteTrigger();
LD2410S.retry = 2;
break;
case 67:
if (LD2410S.ack != LD2410S_CMND_WRITE_TRIGGER) {
if (LD2410S.retry--) {
LD2410S.step=70;
break;
}
}
LD2410S.step = 40; // reread params
break;
// 65 - write hold
case 64:
Ld2410WriteHold();
LD2410S.retry = 2;
break;
case 62:
if (LD2410S.ack != LD2410S_CMND_WRITE_HOLD) {
if (LD2410S.retry--) {
LD2410S.step=65;
break;
}
}
LD2410S.step = 40; // reread params
break;
// 60 - Out mode
case 59:
Ld2410SetOutputMode();
LD2410S.retry = 2;
break;
case 57:
if (LD2410S.ack != LD2410S_CMND_OUTPUT_MODE) {
if (LD2410S.retry--) {
LD2410S.step=60;
break;
}
}
LD2410S.step = 5; // End command
break;
// 50 - write common
case 49:
Ld2410SetCommonParametrs();
LD2410S.retry = 2;
break;
case 47:
if (LD2410S.ack != LD2410S_CMND_SET_COMMON) {
if (LD2410S.retry--) {
LD2410S.step=50;
break;
}
}
LD2410S.step = 40; // read params
break;
// 40 - read params
case 39:
Ld2410ReadCommonParameters();
LD2410S.retry = 4;
break;
case 37:
if (LD2410S.ack != LD2410S_CMND_READ_COMMON) {
if (LD2410S.retry--) {
LD2410S.step=40;
break;
}
}
break;
// 35 - read trigger
case 34:
Ld2410ReadTrigger();
LD2410S.retry = 2;
break;
case 32:
if (LD2410S.ack != LD2410S_CMND_READ_TRIGGER) {
if (LD2410S.retry--) {
LD2410S.step=35;
break;
}
}
break;
// 30 - read hold
case 29:
Ld2410ReadHold();
LD2410S.retry = 2;
break;
case 27:
if (LD2410S.ack != LD2410S_CMND_READ_HOLD) {
if (LD2410S.retry--) {
LD2410S.step=30;
break;
}
}
LD2410S.step=5; // End command
break;
// 20 - loop
// 15 - Config mode
case 14:
Ld2410SetConfigMode(); // Stop running mode
break;
case 10:
if (LD2410S.ack != LD2410S_CMND_START_CONFIGURATION) {
if (LD2410S.retry--) {
LD2410S.step = 20; // Retry
} else {
LD2410S.step = 0;
AddLog(LOG_LEVEL_DEBUG, PSTR("LD2: Not detected"));
}
} else {
LD2410S.step = LD2410S.next_step;
}
break;
case 1:
Ld2410SendCommand(LD2410S_CMND_END_CONFIGURATION);
break;
default:
break;
}
}
}
void Ld2410EverySecond(void) {
if (LD2410S.human != LD2410S.human_last) {
LD2410S.human_last = LD2410S.human;
MqttPublishSensor();
}else if ((LD2410S.report_type ==3 ) || (LD2410S.follow)) {
MqttPublishSensor();
}
}
void Ld2410Detect(void) {
if (PinUsed(GPIO_LD2410S_RX) && PinUsed(GPIO_LD2410S_TX)) {
LD2410S.buffer = (uint8_t*)malloc(LD2410S_BUFFER_SIZE); // Default 64
AddLog(LOG_LEVEL_DEBUG, PSTR("LD2: Buff size %d"), LD2410S_BUFFER_SIZE);
if (!LD2410S.buffer) { AddLog(LOG_LEVEL_DEBUG, PSTR("LD2: No buff")); return; }
LD2410Serial = new TasmotaSerial(Pin(GPIO_LD2410S_RX), Pin(GPIO_LD2410S_TX), 2);
if (LD2410Serial->begin(115200)) {
if (LD2410Serial->hardwareSerial()) { ClaimSerial(); }
#ifdef ESP32
AddLog(LOG_LEVEL_DEBUG, PSTR("LD2: Serial UART%d"), LD2410Serial->getUart());
#endif
LD2410S.retry = 4;
LD2410S.step = 250;
LD2410S.next_step = CMD_LD2410S_Read_Parametrs;
}
}
}
/*********************************************************************************************\
* Commands
\*********************************************************************************************/
const char kLd2410Commands[] PROGMEM = "LD2410S_|" // Prefix
"SetCommon|Out_Mode|AutoUpdate|Parameters|SetTrigger|SetHold|Help|ReRead|Follow";
void (* const Ld2410Command[])(void) PROGMEM = {
&CmndLd2410Common, &CmndLd2410OutMode, &CmndLd2410AutoUpdate, &CmndLd2410Response, &CmndLd2410Trigger, &CmndLd2410Hold, &CmndLd2410Help, &CmndLd2410ReRead, &CmndLd2410Follow};
void CmndLd2410Help(void) {
Response_P(PSTR("Available commands: LD2410S_Parameters (display parameters), LD2410S_ReRead (read param from module), LD2410S_SetCommon, LD2410S_SetTrigger, LD2410S_SetHold, LD2410S_Out_Mode (0-short, 1-normal), LD2410S_AutoUpdate, LD2410S_Follow (0/1 every 1 sec.)"));
}
void CmndLd2410Response(void) {
Response_P(PSTR("{\"LD2410S_Common\":{\"Near Door\": %d,\"Far Door\":%d,\"Hold Time\":%d,\"Status freq\":%d,\"Distance freq\":%d,\"Response speed\":%d}"),
LD2410S.near_end, LD2410S.far_end, LD2410S.hold_duration, LD2410S.status_report_f, LD2410S.distance_report_f,LD2410S.response_speed);
ResponseAppend_P(PSTR(",\"Trigger values\":["));
for (uint32_t i = 0; i < LD2410S_NUM_GATES; i++) {
ResponseAppend_P(PSTR("%d"), LD2410S.trigger_energy[i]);
if (i < (LD2410S_NUM_GATES-1)) {
ResponseAppend_P(PSTR(","));
} else {
ResponseAppend_P(PSTR("]"));
}
}
ResponseAppend_P(PSTR(",\"Hold values\":["));
for (uint32_t i = 0; i < LD2410S_NUM_GATES; i++) {
ResponseAppend_P(PSTR("%d"), LD2410S.hold_energy[i]);
if (i < (LD2410S_NUM_GATES-1)) {
ResponseAppend_P(PSTR(","));
} else {
ResponseAppend_P(PSTR("]"));
}
}
ResponseJsonEnd();
}
void CmndLd2410ReRead(void) {
Ld2410ExecCommand(CMD_LD2410S_Read_Parametrs);
Response_P(PSTR("Accepted... Use LD2410S_Parameters after 1 second."));
}
void CmndLd2410Common(void) {
if (ArgC() == 6) {
uint32_t param[6] = { 0 };
ParseParameters(6, param);
param[3]=(param[3]/5)*5;
param[3]=(param[4]/5)*5;
if (param[0]>16) {param[0] = 16;}
if (param[1]>16) {param[1] = 16;}
if (param[1]<1) {param[1] = 1;}
if (param[2]>120) {param[2] = 120;}
if (param[2]<10) {param[2] = 10;}
if (param[3]>80) {param[3] = 80;}
if (param[3]<5) {param[3] = 5;}
if (param[4]>80) {param[4] = 80;}
if (param[4]<5) {param[4] = 5;}
LD2410S.near_end = (uint8_t)param[0];
LD2410S.far_end = (uint8_t)param[1];
LD2410S.hold_duration = (uint8_t)param[2];
LD2410S.status_report_f = (uint8_t)param[3];
LD2410S.distance_report_f = (uint8_t)param[4];
LD2410S.response_speed = (param[5]>5?10:5);
Ld2410ExecCommand(CMD_LD2410S_Write_Common);
// Response_P(PSTR("Accepted."));
CmndLd2410Response();
} else {
Response_P(PSTR("Use LD2410S_SetCommon near_door,far_door,hold_time,status_freq,distance_freq,response_speed"));
}
}
void CmndLd2410OutMode(void) {
char Argument[XdrvMailbox.data_len];
ArgV(Argument,1);
LD2410S.out_mode = atoi(Argument);
Response_P(PSTR("{\"LD2410S_out_mode\":%d}"),LD2410S.out_mode);
Ld2410ExecCommand(CMD_LD2410S_Out_Mode);
}
void CmndLd2410Follow(void) {
char Argument[XdrvMailbox.data_len];
ArgV(Argument,1);
LD2410S.follow = atoi(Argument);
Response_P(PSTR("{\"LD2410S_Follow\":%d}"),LD2410S.follow);
}
void CmndLd2410AutoUpdate(void) {
if (ArgC() != 3) {
Response_P(PSTR("Use LS2410S_AutoUpdate trigger_scale,retension_factor,scan_time"));
return;
}
uint32_t param[3] = {0};
ParseParameters(3, param);
LD2410S.auto_upd__scale = param[0];
LD2410S.auto_upd_retension = param[1];
LD2410S.auto_upd_time = param[2];
Ld2410ExecCommand(CMD_LD2410S_Auto_Update);
Response_P(PSTR("LD2410S Auto Update started..."));
}
void CmndLd2410Trigger(void) {
if (ArgC() != 16) {
Response_P(PSTR("Use LS2410S_SetTrigger 1,2,..16"));
return;
}
uint32_t param[16] = { 0 };
ParseParameters(16, param);
for (uint32_t i = 0; i < LD2410S_NUM_GATES; i++) {
LD2410S.trigger_energy[i]=param[i];
}
Ld2410ExecCommand(CMD_LD2410S_Write_Trigger);
// Response_P(PSTR("Accepted."));
CmndLd2410Response();
}
void CmndLd2410Hold(void) {
if (ArgC() != 16) {
Response_P(PSTR("Use LS2410S_SetHold 1,2,..16"));
return;
}
uint32_t param[16] = { 0 };
ParseParameters(16, param);
for (uint32_t i = 0; i < LD2410S_NUM_GATES; i++) {
LD2410S.hold_energy[i]=param[i];
}
Ld2410ExecCommand(CMD_LD2410S_Write_Hold);
// Response_P(PSTR("Accepted."));
CmndLd2410Response();
}
/*********************************************************************************************\
* Presentation
\*********************************************************************************************/
#ifdef USE_WEBSERVER
const char HTTP_SNS_LD2410_CM[] PROGMEM =
"{s}LD2410S " D_DETECT_DISTANCE "{m}%1_f " D_UNIT_CENTIMETER "{e}";
const char HTTP_SNS_LD2410_UPD[] PROGMEM =
"{s}LD2410S Auto Update{m}%d " D_UNIT_PERCENT "{e}";
#endif
#ifndef D_JSON_PEOPLE
#define D_JSON_PEOPLE "People"
#endif
void Ld2410Show(bool json) {
float detect_distance = LD2410S.detect_distance;
if (json) {
if (LD2410S.report_type != 3) {
ResponseAppend_P(PSTR(",\"LD2410S\":{\"" D_JSON_DISTANCE "\":%1_f, \"" D_JSON_PEOPLE "\":%d"), &detect_distance, LD2410S.human);
if (LD2410S.report_type == 1) {
ResponseAppend_P(PSTR(", \"Energy\":["));
for (uint32_t i = 0; i < LD2410S_NUM_GATES; i++) {
ResponseAppend_P(PSTR("%d"), LD2410S.energy[i]);
if (i < (LD2410S_NUM_GATES-1)) {
ResponseAppend_P(PSTR(","));
} else {
ResponseAppend_P(PSTR("]"));
}
}
}
ResponseJsonEnd();
}else{
ResponseAppend_P(PSTR(",\"LD2410S\":{\"Update threshold\":\"%1d%%\"}"), LD2410S.detect_distance);
}
#ifdef USE_WEBSERVER
} else {
if (LD2410S.report_type != 3) {
WSContentSend_PD(HTTP_SNS_LD2410_CM, &detect_distance);
}else{
WSContentSend_PD(HTTP_SNS_LD2410_UPD, LD2410S.detect_distance);
}
#endif
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xsns102(uint32_t function) {
bool result = false;
if (FUNC_INIT == function) {
Ld2410Detect();
}
else if (LD2410Serial) {
switch (function) {
case FUNC_LOOP:
case FUNC_SLEEP_LOOP:
Ld2410Input();
break;
case FUNC_EVERY_100_MSECOND:
Ld2410Every100MSecond();
break;
case FUNC_EVERY_SECOND:
Ld2410EverySecond();
break;
case FUNC_JSON_APPEND:
Ld2410Show(1);
break;
#ifdef USE_WEBSERVER
case FUNC_WEB_SENSOR:
Ld2410Show(0);
break;
#endif // USE_WEBSERVER
case FUNC_COMMAND:
result = DecodeCommand(kLd2410Commands, Ld2410Command);
break;
}
}
return result;
}
#endif // USE_LD2410S