From f3ae3bec4bc579d8790d7549378a67b3ba58e1dd Mon Sep 17 00:00:00 2001 From: protectivedad Date: Tue, 11 Mar 2025 13:03:54 -0300 Subject: [PATCH] Added support for hlk-ld2402 tasmota_xsns_sensor (#23133) This is based on the xsns_102_ld2410s.ino. * Available commands: * LD2402_Status 0|1|2 - showing parameters|sensor readings|firmware info * LD2402_ReRead - reread common, motion and micro threshold parameters from device * LD2402_SetCommon 7-100,0-65535 - set common: maximum distance, disappearance delay * LD2402_SetMotion n,n1..n16 - set motion threshold values (16) * LD2402_SetMicro n,n1..n16 - set micro threshold values (16) * LD2402_Mode 0/1 - set device output mode 0-normal, 1-engineering * LD2402_AutoUpdate 3.0,2.0,3.0 - start autoupdate trigger,keep,micro magnification factor * LD2402_Follow 0/n - reports every n seconds Signed-off-by: Anthony Sepa Co-authored-by: Anthony Sepa --- tasmota/include/tasmota_template.h | 6 + tasmota/language/af_AF.h | 4 + tasmota/language/bg_BG.h | 4 + tasmota/language/ca_AD.h | 4 + tasmota/language/cs_CZ.h | 4 + tasmota/language/de_DE.h | 4 + tasmota/language/el_GR.h | 4 + tasmota/language/en_GB.h | 4 + tasmota/language/es_ES.h | 4 + tasmota/language/fr_FR.h | 4 + tasmota/language/fy_NL.h | 4 + tasmota/language/he_HE.h | 4 + tasmota/language/hu_HU.h | 4 + tasmota/language/it_IT.h | 4 + tasmota/language/ko_KO.h | 4 + tasmota/language/lt_LT.h | 4 + tasmota/language/nl_NL.h | 4 + tasmota/language/pl_PL.h | 4 + tasmota/language/pt_BR.h | 4 + tasmota/language/pt_PT.h | 4 + tasmota/language/ro_RO.h | 4 + tasmota/language/ru_RU.h | 4 + tasmota/language/sk_SK.h | 4 + tasmota/language/sv_SE.h | 4 + tasmota/language/tr_TR.h | 4 + tasmota/language/uk_UA.h | 4 + tasmota/language/vi_VN.h | 4 + tasmota/language/zh_CN.h | 4 + tasmota/language/zh_TW.h | 4 + .../tasmota_xsns_sensor/xsns_102_ld2402.ino | 939 ++++++++++++++++++ 30 files changed, 1057 insertions(+) create mode 100644 tasmota/tasmota_xsns_sensor/xsns_102_ld2402.ino diff --git a/tasmota/include/tasmota_template.h b/tasmota/include/tasmota_template.h index 946dffea0..f64bd3737 100644 --- a/tasmota/include/tasmota_template.h +++ b/tasmota/include/tasmota_template.h @@ -231,6 +231,7 @@ enum UserSelectablePins { GPIO_TWAI_TX, GPIO_TWAI_RX, GPIO_TWAI_BO, GPIO_TWAI_CLK, // ESP32 TWAI serial interface GPIO_C8_CO2_5K_TX, GPIO_C8_CO2_5K_RX, // C8-CO2-5K CO2 Sensor GPIO_V9240_TX, GPIO_V9240_RX, // V9240 serial interface + GPIO_LD2402_TX, GPIO_LD2402_RX, // HLK-LD2402 GPIO_SENSOR_END }; // Error as warning to rethink GPIO usage with max 2045 @@ -509,6 +510,7 @@ const char kSensorNames[] PROGMEM = D_SENSOR_TWAI_TX "|" D_SENSOR_TWAI_RX "|" D_SENSOR_TWAI_BO "|" D_SENSOR_TWAI_CLK "|" D_SENSOR_C8_CO2_5K_TX "|" D_SENSOR_C8_CO2_5K_RX "|" D_SENSOR_V9240_TX "|" D_SENSOR_V9240_RX + D_SENSOR_LD2402_TX "|" D_SENSOR_LD2402_RX ; const char kSensorNamesFixed[] PROGMEM = @@ -1126,6 +1128,10 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_CM11_TXD), // CM110x Serial interface AGPIO(GPIO_CM11_RXD), // CM110x Serial interface #endif +#ifdef USE_LD2402 + AGPIO(GPIO_LD2402_TX), // HLK-LD2402 Serial interface + AGPIO(GPIO_LD2402_RX), // HLK-LD2402 Serial interface +#endif #ifdef USE_LD2410 AGPIO(GPIO_LD2410_TX), // HLK-LD2410 Serial interface AGPIO(GPIO_LD2410_RX), // HLK-LD2410 Serial interface diff --git a/tasmota/language/af_AF.h b/tasmota/language/af_AF.h index aeb690224..b9ce56bb7 100644 --- a/tasmota/language/af_AF.h +++ b/tasmota/language/af_AF.h @@ -58,6 +58,7 @@ #define D_AS "as" #define D_AT "at" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Lading" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Ontfout" #define D_DEWPOINT "Dou punt" #define D_DISABLED "Gedeaktiveer" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Afstand" #define D_DNS_SERVER "DNS" #define D_DO "Opgeloste suurstof" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index 54e4fda15..8bcf0ed11 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -58,6 +58,7 @@ #define D_AS "като" #define D_AT "at" #define D_AUTO "АВТОМАТИЧНО" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Бат." // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Премахване на дефекти" #define D_DEWPOINT "Температура на оросяване" #define D_DISABLED "Забранено" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Разстояние" #define D_DNS_SERVER "Сървър на DNS" #define D_DO "Разтворен кислород" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/ca_AD.h b/tasmota/language/ca_AD.h index 373ee312f..61501b131 100644 --- a/tasmota/language/ca_AD.h +++ b/tasmota/language/ca_AD.h @@ -58,6 +58,7 @@ #define D_AS "com" #define D_AT "at" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Bat" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Depuració" #define D_DEWPOINT "Punt de rossada" #define D_DISABLED "Deshabilitat" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Distancia" #define D_DNS_SERVER "Servidor DNS" #define D_DO "Oxígen dissolt" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index 7e4a1d6a2..ef7f3ef19 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -58,6 +58,7 @@ #define D_AS "jako" #define D_AT "at" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Debug" #define D_DEWPOINT "Dew point" #define D_DISABLED "Zablokováno" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Distance" #define D_DNS_SERVER "Server DNS" #define D_DO "Disolved Oxygen" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index d48df566b..f00f11fcf 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -58,6 +58,7 @@ #define D_AS "als" #define D_AT "an" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Batterie" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Ladung" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "debug" #define D_DEWPOINT "Taupunkt" #define D_DISABLED "deaktiviert" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Abstand" #define D_DNS_SERVER "DNS-Server" #define D_DO "gelöster Sauerstoff" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index 72f00e61c..0521ed281 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -58,6 +58,7 @@ #define D_AS "ως" #define D_AT "at" #define D_AUTO "ΑΥΤΟΜΑΤΟ" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Debug" #define D_DEWPOINT "Dew point" #define D_DISABLED "Ανενεργό" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Απόσταση" #define D_DNS_SERVER "Διακομιστής DNS" #define D_DO "Disolved Oxygen" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index f9de343bc..ede817f25 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -58,6 +58,7 @@ #define D_AS "as" #define D_AT "at" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Debug" #define D_DEWPOINT "Dew point" #define D_DISABLED "Disabled" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Distance" #define D_DNS_SERVER "DNS Server" #define D_DO "Disolved Oxygen" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index a17b1f628..d59695f99 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -58,6 +58,7 @@ #define D_AS "como" #define D_AT "at" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Bat" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Debug" #define D_DEWPOINT "Punto de Rocío" #define D_DISABLED "Deshabilitado" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Distancia" #define D_DNS_SERVER "Servidor DNS" #define D_DO "Oxígeno Disuelto" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index 403304737..51529ee98 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -58,6 +58,7 @@ #define D_AS "comme" #define D_AT "at" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Debug" #define D_DEWPOINT "Point de rosée" #define D_DISABLED "Désactivé" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Distance" #define D_DNS_SERVER "Serveur DNS" #define D_DO "Oxygène dissout" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/fy_NL.h b/tasmota/language/fy_NL.h index 0c362f0ba..e381ce01f 100644 --- a/tasmota/language/fy_NL.h +++ b/tasmota/language/fy_NL.h @@ -58,6 +58,7 @@ #define D_AS "als" #define D_AT "at" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Lading" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Debugearje" #define D_DEWPOINT "Dauwpunt" #define D_DISABLED "Útsetten" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Ôfstân" #define D_DNS_SERVER "DNS Server" #define D_DO "Oploste soerstof" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index ab67db617..7fee7c024 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -58,6 +58,7 @@ #define D_AS "-כ" #define D_AT "at" #define D_AUTO "אוטומטי" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "באגים" #define D_DEWPOINT "Dew point" #define D_DISABLED "מבוטל" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "מרחק" #define D_DNS_SERVER "DNS שרת" #define D_DO "Disolved Oxygen" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index 87cb26693..6a27e71f6 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -58,6 +58,7 @@ #define D_AS "mint" #define D_AT "at" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Debug" #define D_DEWPOINT "Harmatpont" #define D_DISABLED "Letiltva" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Távolság" #define D_DNS_SERVER "DNS szerver" #define D_DO "Oldott oxygén" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index 3a9db30cc..0d2fc54c9 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -58,6 +58,7 @@ #define D_AS "come" #define D_AT "in" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Batteria" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Carica" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Debug" #define D_DEWPOINT "Punto rugiada" // #define D_DISABLED "Disabilitato/a" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Distanza" #define D_DNS_SERVER "Server DNS" #define D_DO "Ossigeno dissolto" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 - RX" #define D_SENSOR_WE517_TX "WE517 - TX" #define D_SENSOR_WE517_RX "WE517 - RX" +#define D_SENSOR_LD2402_TX "LD2402 - Tx" +#define D_SENSOR_LD2402_RX "LD2402 - Rx" #define D_SENSOR_LD2410_TX "LD2410 - TX" #define D_SENSOR_LD2410_RX "LD2410 - RX" #define D_SENSOR_LD2410S_TX "LD2410S - TX" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index fda914fd7..27204a1d5 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -58,6 +58,7 @@ #define D_AS "as" #define D_AT "at" #define D_AUTO "자동" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "디버그" #define D_DEWPOINT "Dew point" #define D_DISABLED "사용안함" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "거리" #define D_DNS_SERVER "DNS 서버" #define D_DO "Disolved Oxygen" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/lt_LT.h b/tasmota/language/lt_LT.h index d03792699..ffb2488ff 100644 --- a/tasmota/language/lt_LT.h +++ b/tasmota/language/lt_LT.h @@ -58,6 +58,7 @@ #define D_AS "kaip" #define D_AT "prie" #define D_AUTO "AUTOMATINĖ" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Baterija" #define D_BATT "Baterija" // Short for Battery #define D_BATTERY_CHARGE "Įkrova" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Derinimas" #define D_DEWPOINT "Rasos taškas" #define D_DISABLED "Išjungta" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Atstumas" #define D_DNS_SERVER "DNS Serveris" #define D_DO "Ištirpęs deguonis" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index cffeb5fc9..6e3fcb7f9 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -58,6 +58,7 @@ #define D_AS "als" #define D_AT "at" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Lading" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Debug" #define D_DEWPOINT "Dauwpunt" #define D_DISABLED "Uitgeschakeld" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Afstand" #define D_DNS_SERVER "DNS Server" #define D_DO "Opgelost zuurstof" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index 801924e5b..0bba643ab 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -58,6 +58,7 @@ #define D_AS "jak" #define D_AT "at" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Bateria" #define D_BATT "Bat" // Short for Battery #define D_BATTERY_CHARGE "Ładowanie" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Debug" #define D_DEWPOINT "Punkt rosy" #define D_DISABLED "Wyłączony" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Odległość" #define D_DNS_SERVER "Serwer DNS" #define D_DO "Rozpuszczalność tlenu" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index cf26085df..68002b940 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -58,6 +58,7 @@ #define D_AS "como" #define D_AT "at" #define D_AUTO "Auto" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Bat" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Depurar" #define D_DEWPOINT "Ponto de orvalho" #define D_DISABLED "Desabilitado" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Distância" #define D_DNS_SERVER "Servidor DNS" #define D_DO "Oxigênio dissolvido" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index 7b7d90d5a..9b0800b13 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -58,6 +58,7 @@ #define D_AS "como" #define D_AT "at" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Depurar" #define D_DEWPOINT "Ponto de Condensação" #define D_DISABLED "Disabilitado" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Distância" #define D_DNS_SERVER "Servidor DNS" #define D_DO "Oxigénio Dissolvido" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index 9898d3128..fcd19e50e 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -58,6 +58,7 @@ #define D_AS "as" #define D_AT "at" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Depanare" #define D_DEWPOINT "Punct de rouă" #define D_DISABLED "Dezactivat" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Distanță" #define D_DNS_SERVER "Server DNS" #define D_DO "Disolved Oxygen" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index fc935ace2..df1fa52c8 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -59,6 +59,7 @@ #define D_AS "как" #define D_AT "at" #define D_AUTO "АВТО" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -89,6 +90,7 @@ #define D_DEBUG "Отладка" #define D_DEWPOINT "Dew point" #define D_DISABLED "Блокирован" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Расстояние" #define D_DNS_SERVER "DNS Сервер" #define D_DO "Disolved Oxygen" @@ -777,6 +779,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index c6e37b675..3a62082de 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -58,6 +58,7 @@ #define D_AS "ako" #define D_AT "at" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -90,6 +91,7 @@ #define D_DEBUG "Debug" #define D_DEWPOINT "Dew point" #define D_DISABLED "Zablokované" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Vzdialenosť" #define D_DNS_SERVER "Server DNS" #define D_DO "Disolved Oxygen" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index 1314ca049..f21ed90d1 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -58,6 +58,7 @@ #define D_AS "som" #define D_AT "at" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Debug" #define D_DEWPOINT "Dew point" #define D_DISABLED "Inaktiverad" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Distans" #define D_DNS_SERVER "DNS-server" #define D_DO "Disolved Oxygen" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index 228e6da08..6795e5e84 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -58,6 +58,7 @@ #define D_AS "as" #define D_AT "at" #define D_AUTO "OTOMATIK" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Hata Ayıklama" #define D_DEWPOINT "Dew point" #define D_DISABLED "Etkin Değil" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Mesage" #define D_DNS_SERVER "DNS Sunucu" #define D_DO "Disolved Oxygen" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index c9e9a267f..f1c49089d 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -58,6 +58,7 @@ #define D_AS "як" #define D_AT "at" #define D_AUTO "АВТО" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Налагодження" #define D_DEWPOINT "Tочка роси" #define D_DISABLED "Вимкнено" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Відстань" #define D_DNS_SERVER "Сервер DNS" #define D_DO "Disolved Oxygen" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/vi_VN.h b/tasmota/language/vi_VN.h index 9079f40e3..968cb05b4 100644 --- a/tasmota/language/vi_VN.h +++ b/tasmota/language/vi_VN.h @@ -58,6 +58,7 @@ #define D_AS "với tên gọi" #define D_AT "at" #define D_AUTO "AUTO" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "Tìm lỗi" #define D_DEWPOINT "Điểm sương" #define D_DISABLED "Vô hiệu hóa" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "Khoảng cách" #define D_DNS_SERVER "Máy chủ DNS" #define D_DO "Disolved Oxygen" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index 520e90d0d..20523c5d5 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -58,6 +58,7 @@ #define D_AS "名称:" #define D_AT "at" #define D_AUTO "自动" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "Batt" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "调试" #define D_DEWPOINT "Dew point" #define D_DISABLED "禁用" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "距离" #define D_DNS_SERVER "DNS服务器" #define D_DO "Disolved Oxygen" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index a3f615d2f..0d96ca41f 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -58,6 +58,7 @@ #define D_AS "名稱:" #define D_AT "at" #define D_AUTO "自動" +#define D_AUTO_UPDATE "Auto Update" #define D_BATTERY "Battery" #define D_BATT "電池" // Short for Battery #define D_BATTERY_CHARGE "Charge" // Battery charge in % @@ -88,6 +89,7 @@ #define D_DEBUG "偵錯" #define D_DEWPOINT "Dew point" #define D_DISABLED "已停用" +#define D_DISCONNECTED "Disconnected" #define D_DISTANCE "距離" #define D_DNS_SERVER "DNS伺服器" #define D_DO "Disolved Oxygen" @@ -776,6 +778,8 @@ #define D_SENSOR_SDM630_RX "SDM630 Rx" #define D_SENSOR_WE517_TX "WE517 Tx" #define D_SENSOR_WE517_RX "WE517 Rx" +#define D_SENSOR_LD2402_TX "LD2402 Tx" +#define D_SENSOR_LD2402_RX "LD2402 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_SENSOR_LD2410S_TX "LD2410S Tx" diff --git a/tasmota/tasmota_xsns_sensor/xsns_102_ld2402.ino b/tasmota/tasmota_xsns_sensor/xsns_102_ld2402.ino new file mode 100644 index 000000000..0a91aa428 --- /dev/null +++ b/tasmota/tasmota_xsns_sensor/xsns_102_ld2402.ino @@ -0,0 +1,939 @@ +/* + xsns_102_ld2402.ino - HLK-LD2402 24GHz smart wave motion sensor support for Tasmota + + Copyright (C) 2025 Anthony Sepa + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Based in part on xsns_102_ld2410s.ino by: + SPDX-FileCopyrightText: 2022 Theo Arends, 2024 md5sum-as (https://github.com/md5sum-as) + + SPDX-License-Identifier: GPL-3.0-only +*/ + +#ifdef USE_LD2402 + +/*********************************************************************************************\ + * HLK-LD2402 24GHz smart wave motion sensor + * + * Attention! + * This module works with HLK-LD2402 devices. + * + * Available commands: + * LD2402_Status 0|1|2 - showing parameters|sensor readings|firmware info + * LD2402_ReRead - reread common, motion and micro threshold parameters from device + * LD2402_SetCommon 7-100,0-65535 - set common: maximum distance, disappearance delay + * LD2402_SetMotion n,n1..n16 - set motion threshold values (16) + * LD2402_SetMicro n,n1..n16 - set micro threshold values (16) + * LD2402_Mode 0/1 - set device output mode 0-normal, 1-engineering + * LD2402_AutoUpdate 3.0,2.0,3.0 - start autoupdate trigger,keep,micro magnification factor + * LD2402_Follow 0/n - reports every n seconds + * +\*********************************************************************************************/ + +#define XSNS_102 102 + +// Max line length is in engineering mode at 141 characters +#define LD2402_BUFFER_SIZE 141 + +#define LD2402_NUM_GATES 0x10 + +// control commands +#define LD2402_CMND_NOCMND 0x02 + +// use command values << 4 (to allow delay space) as steps +#define LD2402_CMND_READ_VERSION 0x00F +#define LD2402_CMND_READ_SERIAL 0x11F +#define LD2402_CMND_WRITE_PARAM 0x07F +#define LD2402_CMND_READ_PARAM 0x08F +#define LD2402_CMND_AUTO_THRESHOLD 0x09F +#define LD2402_CMND_AUTO_PROGRESS 0x0AF +#define LD2402_CMND_MODE 0x12F +#define LD2402_CMND_AUTO_INTERFERENCE 0x14F +#define LD2402_CMND_SAVE_PARAM 0xFDF +#define LD2402_CMND_END_CONFIGURATION 0xFEF +#define LD2402_CMND_START_CONFIGURATION 0xFFF + +#define CMD_LD2402_TIMEOUT_DELAY 8 +#define CMD_LD2402_BOOT_DELAY 3 +#define CMD_LD2402_Done 0x01 +#define CMD_LD2402_Wait_Timeout (CMD_LD2402_Done+CMD_LD2402_TIMEOUT_DELAY+1) + +#define CMD_LD2402_END_DELAY 2 +#define CMD_LD2402_PROGRESS_DELAY 7 + +#define LD2402_CMND_PARAM_MAX_DISTANCE 0x01 +#define LD2402_CMND_PARAM_DISP_DELAY 0x04 +#define LD2402_CMND_PARAM_PWR_INTERFER 0x05 +#define LD2402_CMND_PARAM_MOTION_START 0x10 +#define LD2402_CMND_PARAM_MOTION_END LD2402_CMND_PARAM_MOTION_START + LD2402_NUM_GATES - 1 +#define LD2402_CMND_PARAM_MICRO_START 0x30 +#define LD2402_CMND_PARAM_MICRO_END LD2402_CMND_PARAM_MICRO_START + LD2402_NUM_GATES - 1 + +#define LD2402_target_Error 0x4572726f +#define LD2402_target_OFF 0x4F46460D +#define LD2402_target_distance 0x64697374 +#define LD2402_config_header 0xFDFCFBFA +#define LD2402_config_header_a {0xFD, 0xFC, 0xFB, 0xFA} +#define LD2402_engineering_header 0xF4F3F2F1 +#define LD2402_config_footer 0x04030201 +const uint8_t LD2402_config_footer_a[4] {0x04, 0x03, 0x02, 0x01}; +#define LD2402_engineering_footer 0xF8F7F6F5 + +#include +TasmotaSerial *LD2402Serial = nullptr; + +union uint32_union { + uint8_t buffer[4]; + uint32_t buffer_32; +}; + +struct { + uint8_t *buffer; + uint8_t cmnd_param[8] = {}; + uint32_t initializing; + uint32_t busy; + uint32_t step; + uint32_t next_step; + uint32_t sent_ack = LD2402_CMND_NOCMND; +// Static params + char *version = NULL; + char *serial_number = NULL; +// Detection Parameters + uint32_t max_distance; + uint32_t disp_delay; + uint8_t motion_threshold[LD2402_NUM_GATES * 4]; + uint8_t micro_threshold[LD2402_NUM_GATES * 4]; +// Results + uint32_t pwr_interf; + char gates[20] = "FFFF FFFF FFFF FFFF"; +// Report values + uint32_t person; + uint32_t detect_distance; + uint8_t motion_energy[LD2402_NUM_GATES * 4]; + uint8_t micro_energy[LD2402_NUM_GATES * 4]; +// program flow + uint32_t follow; + uint32_t timer; + uint32_t report_type; +// autoupdate + uint32_t auto_upd_progress; +// endianess + uint32_t is_big; +} LD2402; + +#define D_LD2402 "LD2402" +#define D_LD2402_LOG_PREFIX "LD2: " +#define D_BUSY_MSG "{\"" D_LD2402 "\":\"Busy, wait till finished current command.\"}" +#define D_COMMAND_PREFIX_JSON "{\"" D_LD2402 "_%s\":" +#define D_COMMAND_HELP_MSG D_COMMAND_PREFIX_JSON "\"%s\"}" +/********************************************************************************************/ + +void Ld2402HandleEngineeringData(void) { + /* + 01 - 0 type + 9100 - 1,2 distance + F6110000 6C0A0000 3D020000 A3020000 20030000 50060000 57030000 48010000 F3010000 3B010000 07010000 00010000 D2000000 23010000 F3000000 F4000000 - 3+ motion gates + B1270300 F30B0100 703E0000 8E120000 C5080000 3F100000 25030000 7A060000 7F080000 7E070000 FB050000 64040000 F3040000 2D040000 F9030000 43040000 - 67micro gates + */ + LD2402.report_type = 1; + LD2402.detect_distance = LD2402.buffer[2] << 8 | LD2402.buffer[1]; + LD2402.person = LD2402.buffer[0]; + memcpy(LD2402.motion_energy, LD2402.buffer + 3, LD2402_NUM_GATES * 4); + memcpy(LD2402.micro_energy, LD2402.buffer + 67, LD2402_NUM_GATES * 4); +} + +void Ld2402ToBinary(char *buffer, uint32_t byte_h, uint32_t byte_l) { + uint32_t mask_01 = 0x01, mask_10 = 0x10; + for (uint32_t i = 4; i; i--) { + buffer[i-1] = (byte_h & mask_10) ? '1' : '0'; + buffer[i+4] = (byte_h & mask_01) ? '1' : '0'; + buffer[i+9] = (byte_l & mask_10) ? '1' : '0'; + buffer[i+14] = (byte_h & mask_01) ? '1' : '0'; + mask_10<<=1; + mask_01<<=1; + } +} + +void Ld2402HandleConfigData(void) { + uint32_t rcvd_ack = LD2402.buffer[0]; + if (rcvd_ack != LD2402.sent_ack) { + return; + } + if (1 != LD2402.buffer[1]) { + // maybe do a retry? + return; + } + + if (LD2402_CMND_READ_VERSION>>4 == rcvd_ack) { + // 00010000060076332E332E32 + // 0 2 4 6 + uint32_t len = LD2402.buffer[4]; + free(LD2402.version); + LD2402.version = (char*)malloc(len+1); + memcpy(LD2402.version, LD2402.buffer + 6, len); + LD2402.version[len] = 0; + DEBUG_SENSOR_LOG(PSTR(D_LD2402_LOG_PREFIX "Rcvd %s"), LD2402.version); + } else if (LD2402_CMND_READ_SERIAL>>4 == rcvd_ack) { + // 1101000008004646464646464646 + // 0 2 4 6 + uint32_t len = LD2402.buffer[4]; + free(LD2402.serial_number); + LD2402.serial_number = (char*)malloc(len+1); + memcpy(LD2402.serial_number, LD2402.buffer + 6, len); + LD2402.serial_number[len] = 0; + DEBUG_SENSOR_LOG(PSTR(D_LD2402_LOG_PREFIX "Rcvd %s"), LD2402.serial_number); + } else if (LD2402_CMND_READ_PARAM>>4 == rcvd_ack) { + // + switch (LD2402.cmnd_param[0]) { + // common params + case LD2402_CMND_PARAM_MAX_DISTANCE: + LD2402.max_distance = LD2402.buffer[4]; + break; + case LD2402_CMND_PARAM_DISP_DELAY: + LD2402.disp_delay = LD2402.buffer[5] << 8 | LD2402.buffer[4]; + break; + case LD2402_CMND_PARAM_PWR_INTERFER: + LD2402.pwr_interf = LD2402.buffer[4]; + break; + default: + switch (LD2402.cmnd_param[0] & 0xF0) { + // gate specific params + case LD2402_CMND_PARAM_MOTION_START: + memcpy(LD2402.motion_threshold + (LD2402.cmnd_param[0] & 0x0F) * 4, LD2402.buffer + 4, 4); + break; + case LD2402_CMND_PARAM_MICRO_START: + memcpy(LD2402.micro_threshold + (LD2402.cmnd_param[0] & 0x0F) * 4, LD2402.buffer + 4, 4); + break; + default: + break; + } + break; + } + } else if ((LD2402_CMND_AUTO_PROGRESS>>4) == rcvd_ack) { + // 0A0100003C00 + // 0 2 4 + LD2402.auto_upd_progress = LD2402.buffer[4]; + LD2402.report_type = 3; + } else if (LD2402_CMND_AUTO_INTERFERENCE>>4 == rcvd_ack) { + // 140100000000 + // 0 2 4 + Ld2402ToBinary(LD2402.gates, LD2402.buffer[5], LD2402.buffer[4]); + } + Ld2402OnDemand(rcvd_ack); +} + +void Ld2402Input(void) { + uint32_t avail; + while (LD2402Serial->available()) { + static uint32_union header; + static uint32_union footer; + static uint32_t data_type = 0, byte_counter = 0; + if (!data_type) { + if (!byte_counter) { + avail = LD2402Serial->available(); + if (avail < 4) { + DEBUG_SENSOR_LOG(PSTR(D_LD2402_LOG_PREFIX "Don't have enough for header.")); + break; + } + for (uint32_t i = 3; i; i--) { + header.buffer_32<<=8; + header.buffer[LD2402.is_big*3] = LD2402Serial->read(); + } + byte_counter = 4; + } + + avail = LD2402Serial->available(); + header.buffer_32<<=8; + header.buffer[LD2402.is_big*3] = LD2402Serial->read(); + + // I will get out of this mess with either: + // - Config/Engineering header match, set data_type (most likely/quickest further processing) + // - Known text match, process line, clear byte count for next line (less likely but no further processing) + // - No header matches, continue, shift in the next character if/when available + data_type = (LD2402_engineering_header == header.buffer_32) ? 2 : 0; + if (!data_type) { + data_type = (LD2402_config_header == header.buffer_32) ? 3 : 0; + if (!data_type) { + if (LD2402_target_Error != header.buffer_32) { + if (LD2402_target_OFF != header.buffer_32) { + if (LD2402_target_distance != header.buffer_32) { + continue; + } else { + // process distance line + byte_counter = LD2402Serial->readBytesUntil(0x0A, LD2402.buffer, LD2402_BUFFER_SIZE); + LD2402.buffer[byte_counter] = 0; + DEBUG_SENSOR_LOG(PSTR(D_LD2402_LOG_PREFIX "Dist%s"), LD2402.buffer); + // ance:105\r\n + LD2402.detect_distance = atoi((char*) LD2402.buffer + 5); + LD2402.person = 2; + } + } else { + // process OFF line + LD2402.detect_distance = 0; + LD2402.person = 0; + LD2402Serial->read(); + } + LD2402.report_type = 2; + } else { + // preocess Error line + byte_counter = LD2402Serial->readBytesUntil(0x0A, LD2402.buffer, LD2402_BUFFER_SIZE); + LD2402.buffer[byte_counter] = 0; + AddLog(LOG_LEVEL_INFO, PSTR(D_LD2402_LOG_PREFIX "Erro%s"), LD2402.buffer); + LD2402.report_type = 0; + } + byte_counter = 0; + break; + } + } + } + + static uint32_t length, got; + if (byte_counter < 6) { + avail = LD2402Serial->available(); + if (avail < 2) { + DEBUG_SENSOR_LOG(PSTR(D_LD2402_LOG_PREFIX "Don't have enough for length.")); + break; + } + length = LD2402Serial->read(); + LD2402Serial->read(); + got = 0; + if (length > LD2402_BUFFER_SIZE) { + data_type = 0; + byte_counter = 0; + break; + } + byte_counter = 6; + } + + avail = LD2402Serial->available(); + if (avail < (length - got)) { + got += LD2402Serial->readBytes(LD2402.buffer + got, avail); + break; + } + if (got < length) { + got += LD2402Serial->readBytes(LD2402.buffer + got, length - got); + } + + avail = LD2402Serial->available(); + if (avail < 4) { + DEBUG_SENSOR_LOG(PSTR(D_LD2402_LOG_PREFIX "Don't have enough for footer.")); + break; + } + for (uint32_t i = 4; i; i--) { + footer.buffer_32<<=8; + footer.buffer[LD2402.is_big*3] = LD2402Serial->read(); + } + + if (2 == data_type) { + if (LD2402_engineering_footer == footer.buffer_32) { + Ld2402HandleEngineeringData(); + } else { + DEBUG_SENSOR_LOG(PSTR(D_LD2402_LOG_PREFIX "Head %*_H"), 4, header.buffer); + DEBUG_SENSOR_LOG(PSTR(D_LD2402_LOG_PREFIX "Eng %*_H"), length, LD2402.buffer); + DEBUG_SENSOR_LOG(PSTR(D_LD2402_LOG_PREFIX "byte_counter: %d, avail: %d, got %d, length %d"), byte_counter, avail, got, length); + DEBUG_SENSOR_LOG(PSTR(D_LD2402_LOG_PREFIX "Foot %*_H"), 4, footer.buffer); + } + } else { + if (LD2402_config_footer == footer.buffer_32) { + Ld2402HandleConfigData(); + LD2402Serial->setReadChunkMode(0); + } else { + DEBUG_SENSOR_LOG(PSTR(D_LD2402_LOG_PREFIX "Head %*_H"), 4, header.buffer); + DEBUG_SENSOR_LOG(PSTR(D_LD2402_LOG_PREFIX "Cmd %*_H"), length, LD2402.buffer); + DEBUG_SENSOR_LOG(PSTR(D_LD2402_LOG_PREFIX "byte_counter: %d, avail: %d, got %d, length %d"), byte_counter, avail, got, length); + DEBUG_SENSOR_LOG(PSTR(D_LD2402_LOG_PREFIX "Foot %*_H"), 4, footer.buffer); + } + } + data_type = 0; + byte_counter = 0; + break; + } + // If here then LD2402.byte_counter could still be partial correct for next loop +} + +void Ld2402SendCommand(uint8_t command, uint32_t val_len = 0); +void Ld2402SendCommand(uint8_t command, uint32_t val_len) { + uint8_t buffer[20] = LD2402_config_header_a; + + buffer[4] = val_len + 2; + buffer[6] = command; + if (val_len) { + memcpy(buffer+8,LD2402.cmnd_param,val_len); + } + memcpy(buffer+8+val_len, LD2402_config_footer_a, sizeof(LD2402_config_footer_a)); + + LD2402.sent_ack = command; + LD2402Serial->setReadChunkMode(1); // Enable chunk mode introducing possible Hardware Watchdogs + LD2402Serial->flush(); + LD2402Serial->write(buffer, val_len + 12); +} + +void Ld2402LoadLastParam(uint32_t curr_param) { + memset(LD2402.cmnd_param, 0x00, 6); + LD2402.cmnd_param[0] = curr_param; + switch (curr_param) { + case LD2402_CMND_PARAM_MAX_DISTANCE: + LD2402.cmnd_param[2] = LD2402.max_distance; + break; + + case LD2402_CMND_PARAM_DISP_DELAY: + LD2402.cmnd_param[2] = LD2402.disp_delay & 0x00FF; + LD2402.cmnd_param[3] = LD2402.disp_delay >> 8; + break; + + default: + switch (curr_param & 0xF0) { + case LD2402_CMND_PARAM_MOTION_START: + memcpy(LD2402.cmnd_param + 2, LD2402.motion_threshold + (curr_param & 0x0F) * 4, 4); + break; + + case LD2402_CMND_PARAM_MICRO_START: + memcpy(LD2402.cmnd_param + 2, LD2402.micro_threshold + (curr_param & 0x0F) * 4, 4); + break; + + default: + break; + } + break; + } +} + +void Ld2402WriteThresholds(uint8_t *thresholds, uint32_t cmnd_param) { + if (LD2402.busy) { + Response_P(PSTR(D_BUSY_MSG)); + return; + } + if (ArgC() != 16) { + Response_P(PSTR("Use LS2410S_Set{Motion/Micro} 1,2,..16 (values are dB <= 95.00")); + return; + } + char strbuf[24]; + float param; + uint32_t i = 0; + for (uint32_t j = 0; j < LD2402_NUM_GATES; j++) { + ArgV(strbuf, j+1); + param = CharToFloat(strbuf); + uint32_t val = exp10(param > 95.00f ? 95.00f : param); + thresholds[i++] = val & 0x000000FF; + thresholds[i++] = val >> 8 & 0x000000FF; + thresholds[i++] = val >> 16 & 0x000000FF; + thresholds[i++] = val >> 24; + } + Ld2402LoadLastParam(cmnd_param); + Ld2402ExecConfigCmnd(LD2402_CMND_WRITE_PARAM); + Response_P(PSTR("Accepted... Allow 2 seconds to write to device.")); +} + +void Ld2402ResponseAppendGates(uint8_t *energies) { + const float multiplier = 10.0f / 2.302585f; + uint32_t i = 0; + float val; + while (i < LD2402_NUM_GATES * 4) { + val = energies[i++] | energies[i++] << 8 | energies[i++] << 16 | energies[i++] << 24; + val = (val ? multiplier * logf(val) : 0); + if (4 != i) { ResponseAppend_P(PSTR(",")); } + ResponseAppend_P(PSTR("%2_f"), &val); + } +} + +void Ld2402ResponseAppendReport() { + if (3 == LD2402.report_type) { + ResponseAppend_P(PSTR("\"AutoUpdate\":\"%1d%%\"}"), LD2402.auto_upd_progress); + } else if (0 == LD2402.report_type) { + ResponseAppend_P(PSTR("\"Error\":\"Disconnected\"}")); + } else { + ResponseAppend_P(PSTR("\"" D_JSON_DISTANCE "\":%d"), LD2402.detect_distance); + if (1 == LD2402.report_type) { + ResponseAppend_P(PSTR(",\"Motion\":%s"), (1 == LD2402.person ? "true" : "false")); + ResponseAppend_P(PSTR(",\"Occupancy\":%s"), (LD2402.person ? "true" : "false")); + ResponseAppend_P(PSTR(",\"PowerInterference\":%d"), LD2402.pwr_interf); + if (2 == LD2402.pwr_interf) { ResponseAppend_P(PSTR(",\"InterferenceGates\":\"%s\""), LD2402.gates); } + ResponseAppend_P(PSTR(",\"MotionEnergies\":[")); + Ld2402ResponseAppendGates(LD2402.motion_energy); + ResponseAppend_P(PSTR("],\"MicroEnergies\":[")); + Ld2402ResponseAppendGates(LD2402.micro_energy); + ResponseAppend_P(PSTR("]}")); + } + } +} +void Ld2402ExecQuickCmnd(uint32_t cmnd) { + LD2402.busy = true; + LD2402.step = cmnd; +} + +void Ld2402ExecConfigCmnd(uint32_t cmnd) { + LD2402.next_step = cmnd; + Ld2402ExecQuickCmnd(LD2402_CMND_START_CONFIGURATION); +} + +void Ld2402DeviceDisconnected(void) { + AddLog(LOG_LEVEL_INFO, PSTR(D_LD2402_LOG_PREFIX "Device disconnected")); + LD2402.step = CMD_LD2402_Done; + LD2402.report_type = 0; +} + +/********************************************************************************************/ + +void Ld2402OnDemand(uint32_t ack_rcvd) { + switch (ack_rcvd) { + case LD2402_CMND_START_CONFIGURATION>>4: + LD2402.step = LD2402.next_step; + break; + + case LD2402_CMND_END_CONFIGURATION>>4: + LD2402.step = CMD_LD2402_Done; + return; + + case LD2402_CMND_SAVE_PARAM>>4: + return; + + case LD2402_CMND_AUTO_THRESHOLD>>4: + LD2402.step = LD2402_CMND_AUTO_PROGRESS; + return; + + case LD2402_CMND_AUTO_PROGRESS>>4: + if (100 > LD2402.auto_upd_progress) { + LD2402.step = LD2402_CMND_AUTO_PROGRESS; + return; + } + LD2402.step = LD2402_CMND_READ_PARAM; + break; + + case LD2402_CMND_AUTO_INTERFERENCE>>4: + LD2402.step = LD2402_CMND_READ_PARAM; + break; + + case LD2402_CMND_MODE>>4: + LD2402.step = LD2402_CMND_END_CONFIGURATION; + return; + + case LD2402_CMND_READ_VERSION>>4: + LD2402.step = LD2402_CMND_READ_SERIAL; + break; + + case LD2402_CMND_READ_SERIAL>>4: + if (!LD2402.initializing) { + LD2402.step = LD2402_CMND_END_CONFIGURATION; + return; + } + LD2402.cmnd_param[0] = LD2402_CMND_PARAM_MAX_DISTANCE; + LD2402.next_step = LD2402_CMND_READ_PARAM; + LD2402.step = LD2402_CMND_START_CONFIGURATION; + break; + + case LD2402_CMND_WRITE_PARAM>>4: + switch (LD2402.cmnd_param[0]) { + case LD2402_CMND_PARAM_MAX_DISTANCE: + Ld2402LoadLastParam(LD2402_CMND_PARAM_DISP_DELAY); + LD2402.step = LD2402_CMND_WRITE_PARAM; + break; + + case LD2402_CMND_PARAM_DISP_DELAY: + case LD2402_CMND_PARAM_MOTION_END: + case LD2402_CMND_PARAM_MICRO_END: + LD2402.step = LD2402_CMND_END_CONFIGURATION; + return; + + default: + switch (LD2402.cmnd_param[0] & 0xF0) { + // gate specific params + case LD2402_CMND_PARAM_MICRO_START: + case LD2402_CMND_PARAM_MOTION_START: + Ld2402LoadLastParam(++LD2402.cmnd_param[0]); + LD2402.step = LD2402_CMND_WRITE_PARAM; + break; + default: + LD2402.step = LD2402_CMND_END_CONFIGURATION; + return; + } + } + break; + + case LD2402_CMND_READ_PARAM>>4: + switch (LD2402.cmnd_param[0]) { + case LD2402_CMND_PARAM_MAX_DISTANCE: + LD2402.cmnd_param[0] = LD2402_CMND_PARAM_DISP_DELAY; + break; + + case LD2402_CMND_PARAM_DISP_DELAY: + LD2402.cmnd_param[0] = LD2402_CMND_PARAM_PWR_INTERFER; + break; + + case LD2402_CMND_PARAM_PWR_INTERFER: + LD2402.cmnd_param[0] = LD2402_CMND_PARAM_MOTION_START; + if (2 == LD2402.pwr_interf) { + LD2402.step = LD2402_CMND_AUTO_INTERFERENCE; + } + break; + + case LD2402_CMND_PARAM_MOTION_END: + LD2402.cmnd_param[0] = LD2402_CMND_PARAM_MICRO_START; + break; + + case LD2402_CMND_PARAM_MICRO_END: + if (LD2402.initializing) { + // clear LD2402_CMND_READ_PARAM param + LD2402.cmnd_param[0] = 0x00; + LD2402.cmnd_param[2] = 0x04; + LD2402.step = LD2402_CMND_MODE; + Ld2402EveryXMSecond(); + } else { + LD2402.step = LD2402_CMND_END_CONFIGURATION; + } + return; + + default: + switch (LD2402.cmnd_param[0] & 0xF0) { + // gate specific params + case LD2402_CMND_PARAM_MOTION_START: + case LD2402_CMND_PARAM_MICRO_START: + LD2402.cmnd_param[0]++; + break; + default: + LD2402.step = LD2402_CMND_END_CONFIGURATION; + return; + } + break; + } + LD2402.step = LD2402_CMND_READ_PARAM; + break; + + default: + return; + } + Ld2402EveryXMSecond(); +} + +void Ld2402EveryXMSecond(void) { + if (LD2402.step) { + uint32_t command = LD2402.step>>4; + switch (LD2402.step--) { + // special: get control of LD2402 + case LD2402_CMND_READ_PARAM: + Ld2402SendCommand(command, 2); + break; + + case LD2402_CMND_START_CONFIGURATION: + LD2402.cmnd_param[0] = 0x01; + Ld2402SendCommand(command, 2); + if (LD2402.initializing) { + LD2402.step = LD2402_CMND_START_CONFIGURATION+CMD_LD2402_BOOT_DELAY; + return; + } + break; + + case LD2402_CMND_AUTO_PROGRESS-CMD_LD2402_PROGRESS_DELAY: + case LD2402_CMND_AUTO_INTERFERENCE: + case LD2402_CMND_READ_VERSION: + case LD2402_CMND_READ_SERIAL: + case LD2402_CMND_SAVE_PARAM: + case LD2402_CMND_END_CONFIGURATION-CMD_LD2402_END_DELAY: + Ld2402SendCommand(command); + break; + + case LD2402_CMND_AUTO_THRESHOLD: + case LD2402_CMND_WRITE_PARAM: + case LD2402_CMND_MODE: + Ld2402SendCommand(command, 6); + break; + + case CMD_LD2402_Wait_Timeout-CMD_LD2402_TIMEOUT_DELAY: + Ld2402DeviceDisconnected(); + return; + + case CMD_LD2402_Done: + LD2402.busy = 0; + LD2402.initializing = 0; + return; + + default: + return; + } + LD2402.step = CMD_LD2402_Wait_Timeout; + } +} + +void Ld2402EverySecond(void) { + static uint32_t person = 4; + if (!LD2402.report_type && !LD2402.initializing) { + AddLog(LOG_LEVEL_INFO, PSTR(D_LD2402_LOG_PREFIX "Trying to reconnect.")); + Ld2402ExecQuickCmnd(LD2402_CMND_READ_VERSION); + return; + } + + if (!LD2402.timer && (LD2402.person == person)) { return; } + if (LD2402.timer) { --LD2402.timer; } + if (LD2402.timer && (LD2402.person == person)) { return; } + if (LD2402.person != person) { person = LD2402.person; } + if (!LD2402.timer) { LD2402.timer = LD2402.follow; } + + MqttPublishSensor(); +} + +void Ld2402Detect(void) { + if (PinUsed(GPIO_LD2402_RX) && PinUsed(GPIO_LD2402_TX)) { + LD2402.buffer = (uint8_t*)malloc(LD2402_BUFFER_SIZE); + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LD2402_LOG_PREFIX "Buff size %d"), LD2402_BUFFER_SIZE); + if (!LD2402.buffer) { AddLog(LOG_LEVEL_DEBUG, PSTR(D_LD2402_LOG_PREFIX "No buff")); return; } + LD2402Serial = new TasmotaSerial(Pin(GPIO_LD2402_RX), Pin(GPIO_LD2402_TX), 2, 0, LD2402_BUFFER_SIZE); + if (LD2402Serial->begin(115200)) { + if (LD2402Serial->hardwareSerial()) { ClaimSerial(); } +#ifdef ESP32 + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LD2402_LOG_PREFIX "Serial UART%d"), LD2402Serial->getUart()); +#endif + volatile uint32_t i=0x01234567; + LD2402.is_big = (*((uint8_t*)(&i))) != 0x67; + if (!LD2402.busy) { + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LD2402_LOG_PREFIX "Starting initialization.")); + LD2402.initializing = true; + LD2402.step = LD2402_CMND_START_CONFIGURATION+CMD_LD2402_BOOT_DELAY; + LD2402.next_step = LD2402_CMND_READ_VERSION; + } + } + } +} + +/*********************************************************************************************\ + * Commands +\*********************************************************************************************/ + +#define D_CMD_MODE "Mode" +#define D_CMD_AUTOUPDATE "AutoUpdate" +#define D_CMD_STATUS "Status" +#define D_CMD_SETCOMMON "SetCommon" +#define D_CMD_SETMOTION "SetMotion" +#define D_CMD_SETMICRO "SetMicro" +#define D_CMD_HELP "Help" +#define D_CMD_REREAD "ReRead" +#define D_CMD_FOLLOW "Follow" + +const char kLd2402Commands[] PROGMEM = D_LD2402 "_|" // Prefix + D_CMD_MODE "|" D_CMD_AUTOUPDATE "|" D_CMD_STATUS "|" D_CMD_SETCOMMON "|" + D_CMD_SETMOTION "|" D_CMD_SETMICRO "|" D_CMD_HELP "|" D_CMD_REREAD "|" + D_CMD_FOLLOW; + +void (* const Ld2402Command[])(void) PROGMEM = { + &CmndLd2402Mode, &CmndLd2402AutoUpdate, &CmndLd2402Status, &CmndLd2402Common, + &CmndLd2402Motion, &CmndLd2402Micro, &CmndLd2402Help, &CmndLd2402ReRead, + &CmndLd2402Follow }; + +void CmndLd2402Help(void) { + Response_P(PSTR(D_COMMAND_PREFIX_JSON"\"%s"), D_CMD_HELP, "Available commands: "); + ResponseAppend_P(PSTR(D_LD2402 "_" D_CMD_MODE", ")); + ResponseAppend_P(PSTR(D_LD2402 "_" D_CMD_AUTOUPDATE", ")); + ResponseAppend_P(PSTR(D_LD2402 "_" D_CMD_STATUS", ")); + ResponseAppend_P(PSTR(D_LD2402 "_" D_CMD_SETCOMMON", ")); + ResponseAppend_P(PSTR(D_LD2402 "_" D_CMD_SETMOTION", ")); + ResponseAppend_P(PSTR(D_LD2402 "_" D_CMD_SETMICRO", ")); + ResponseAppend_P(PSTR(D_LD2402 "_" D_CMD_HELP", ")); + ResponseAppend_P(PSTR(D_LD2402 "_" D_CMD_REREAD", ")); + ResponseAppend_P(PSTR(D_LD2402 "_" D_CMD_FOLLOW"\"}")); +} + +void CmndLd2402Follow(void) { + if (ArgC() != 1) { + Response_P(PSTR(D_COMMAND_HELP_MSG), D_CMD_FOLLOW, "Args: 0|n (MQTT update normal|MQTT update every n second(s))"); + return; + } + char Argument[XdrvMailbox.data_len]; + ArgV(Argument,1); + LD2402.timer = atoi(Argument); + LD2402.follow = LD2402.timer; + Response_P(PSTR(D_COMMAND_PREFIX_JSON"%d}"), D_CMD_FOLLOW, LD2402.follow); +} + +void CmndLd2402Status(void) { + if (ArgC() != 1) { + Response_P(PSTR(D_COMMAND_HELP_MSG), D_CMD_STATUS, "Args: 0|1|2 (parameters|sensor|firmware)"); + return; + } + uint32_t status_type = 0; + if (ArgC() == 1) { + char Argument[XdrvMailbox.data_len]; + ArgV(Argument,1); + status_type = atoi(Argument); + } + + Response_P(PSTR("{\"" D_LD2402)); + if (1 == status_type) { + ResponseAppend_P(PSTR("SNS\":{")); + Ld2402ResponseAppendReport(); + } else if (2 == status_type) { + ResponseAppend_P(PSTR("FWR\":{\"Version\":\"%s\","),LD2402.version); + ResponseAppend_P(PSTR("\"SerialNumber\":\"%s\"}}"),LD2402.serial_number); + } else { + ResponseAppend_P(PSTR("\":{\"MaximumDistance\":%d,"), LD2402.max_distance); + ResponseAppend_P(PSTR("\"DisappearenceDelay\":%d,"), LD2402.disp_delay); + ResponseAppend_P(PSTR("\"MotionThresholds\":[")); + Ld2402ResponseAppendGates(LD2402.motion_threshold); + Ld2402ResponseAppendGates(LD2402.micro_threshold); + ResponseAppend_P(PSTR("]}}")); + } +} + +void CmndLd2402ReRead(void) { + if (LD2402.busy) { + Response_P(PSTR(D_BUSY_MSG)); + return; + } + if (ArgC()) { + Response_P(PSTR(D_COMMAND_HELP_MSG), D_CMD_REREAD, "No Args: Retrieves common and threshold data from device"); + return; + } + LD2402.cmnd_param[0] = LD2402_CMND_PARAM_MAX_DISTANCE; + Ld2402ExecConfigCmnd(LD2402_CMND_READ_PARAM); + Response_P(PSTR(D_COMMAND_HELP_MSG), D_CMD_REREAD, "Retrieving ... wait six seconds for it to complete"); +} + +void CmndLd2402Common(void) { + if (LD2402.busy) { + Response_P(PSTR(D_BUSY_MSG)); + return; + } + if (ArgC() != 2) { + Response_P(PSTR(D_COMMAND_HELP_MSG), D_CMD_SETCOMMON, "Args: MaximumDistance,DisappearanceDelay (decimeter,seconds)"); + return; + } + uint32_t param[2] = { 0 }; + ParseParameters(2, param); + if (param[0]>100) {param[0] = 100;} + if (param[0]<7) {param[0] = 7;} + if (param[1]<0) {param[1] = 0;} + if (param[1]>65535) {param[1] = 65535;} + LD2402.max_distance = param[0]; + LD2402.disp_delay = param[1]; + Ld2402LoadLastParam(LD2402_CMND_PARAM_MAX_DISTANCE); + Ld2402ExecConfigCmnd(LD2402_CMND_WRITE_PARAM); + CmndLd2402Status(); +} + +void CmndLd2402Mode(void) { + if (LD2402.busy) { + Response_P(PSTR(D_BUSY_MSG)); + return; + } + if (ArgC() != 1) { + Response_P(PSTR(D_COMMAND_HELP_MSG), D_CMD_MODE, "Args: 0|1 (normal|engineering)"); + return; + } + char Argument[XdrvMailbox.data_len]; + ArgV(Argument,1); + memset(LD2402.cmnd_param, 0x00, 6); + LD2402.cmnd_param[2] = atoi(Argument) ? 0x04 : 0x64; + Response_P(PSTR(D_COMMAND_PREFIX_JSON"%d}"), D_CMD_FOLLOW, (0x04 == LD2402.cmnd_param[2])); + Ld2402ExecConfigCmnd(LD2402_CMND_MODE); +} + +void CmndLd2402AutoUpdate(void) { + if (LD2402.busy) { + Response_P(PSTR(D_BUSY_MSG)); + return; + } + if (ArgC() != 3) { + Response_P(PSTR(D_COMMAND_HELP_MSG), D_CMD_AUTOUPDATE, "Args: trigger,keep,micro (magnification factor, 1.0 to 20.0)"); + return; + } + + char strbuf[24]; + for (uint32_t i = 3; i; i--) { + ArgV(strbuf, i); + float param = CharToFloat(strbuf); + LD2402.cmnd_param[(i-1)*2] = (param < 1.0f) ? 10.0f : (param > 20.0f ? 200.0f : param * 10.0f); + } + Ld2402ExecConfigCmnd(LD2402_CMND_AUTO_THRESHOLD); + Response_P(PSTR(D_COMMAND_HELP_MSG), D_CMD_REREAD, "Updating ..."); +} + +void CmndLd2402Motion(void) { + Ld2402WriteThresholds(LD2402.motion_threshold, LD2402_CMND_PARAM_MOTION_START); +} + +void CmndLd2402Micro(void) { + Ld2402WriteThresholds(LD2402.micro_threshold, LD2402_CMND_PARAM_MICRO_START); +} + +/*********************************************************************************************\ + * Presentation +\*********************************************************************************************/ + +#ifdef USE_WEBSERVER +const char HTTP_SNS_LD2402_DIS[] PROGMEM = + "{s}" D_LD2402 " " D_DISCONNECTED "{e}"; +const char HTTP_SNS_LD2402_CM[] PROGMEM = + "{s}" D_LD2402 " " D_DISTANCE "{m}%d " D_UNIT_CENTIMETER "{e}"; +const char HTTP_SNS_LD2402_MV[] PROGMEM = + "{s}" D_LD2402 " " D_DISTANCE " (!){m}%d " D_UNIT_CENTIMETER "{e}"; +const char HTTP_SNS_LD2402_UPD[] PROGMEM = + "{s}" D_LD2402 " " D_AUTO_UPDATE "{m}%d " D_UNIT_PERCENT "{e}"; + +void Ld2402Web(void) { + if (3 == LD2402.report_type) { + WSContentSend_PD(HTTP_SNS_LD2402_UPD, LD2402.auto_upd_progress); + } else if (2 == LD2402.report_type) { + WSContentSend_PD(HTTP_SNS_LD2402_CM, LD2402.detect_distance); + } else if (1 == LD2402.report_type) { + WSContentSend_PD((1 == LD2402.person ? HTTP_SNS_LD2402_MV : HTTP_SNS_LD2402_CM), LD2402.detect_distance); + } else { + WSContentSend_PD(HTTP_SNS_LD2402_DIS); + } +} +#endif + +void Ld2402Show(void) { + ResponseAppend_P(PSTR(",\"" D_LD2402 "\":{")); + Ld2402ResponseAppendReport(); +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns102(uint32_t function) { + bool result = false; + + if (FUNC_INIT == function) { + Ld2402Detect(); + } + else if (LD2402Serial) { + switch (function) { + case FUNC_LOOP: + case FUNC_SLEEP_LOOP: + Ld2402Input(); + break; + case FUNC_EVERY_50_MSECOND: + Ld2402EveryXMSecond(); + break; + case FUNC_EVERY_100_MSECOND: + break; + case FUNC_EVERY_SECOND: + Ld2402EverySecond(); + break; + case FUNC_JSON_APPEND: + Ld2402Show(); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + Ld2402Web(); + break; +#endif // USE_WEBSERVER + case FUNC_COMMAND: + result = DecodeCommand(kLd2402Commands, Ld2402Command); + break; + } + } + return result; +} + +#endif // USE_LD2402