├── .gitignore ├── images ├── ld2410.jpg ├── ld2410.png ├── ld2410c.jpg └── ld2410c.png ├── library.properties ├── examples ├── auto_thresholds │ ├── board_select.h │ └── auto_thresholds.ino ├── factory_reset │ ├── board_select.h │ └── factory_reset.ino ├── modify_parameters │ ├── board_select.h │ └── modify_parameters.ino ├── print_parameters │ ├── board_select.h │ └── print_parameters.ino ├── set_baud_rate │ ├── board_select.h │ └── set_baud_rate.ino ├── set_bt_password │ ├── board_select.h │ └── set_bt_password.ino └── sensor_data │ ├── board_select.h │ └── sensor_data.ino ├── LICENSE ├── README.md └── src ├── MyLD2410.h └── MyLD2410.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | -------------------------------------------------------------------------------- /images/ld2410.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iavorvel/MyLD2410/HEAD/images/ld2410.jpg -------------------------------------------------------------------------------- /images/ld2410.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iavorvel/MyLD2410/HEAD/images/ld2410.png -------------------------------------------------------------------------------- /images/ld2410c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iavorvel/MyLD2410/HEAD/images/ld2410c.jpg -------------------------------------------------------------------------------- /images/ld2410c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iavorvel/MyLD2410/HEAD/images/ld2410c.png -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=MyLD2410 2 | version=1.2.7 3 | author=Iavor Veltchev 4 | maintainer=Iavor Veltchev 5 | sentence=An Arduino/ESP32 library for the LD2410 presence sensor, including HLK-LD2410B and HLK-LD2410C. 6 | paragraph=This library was built from scratch and covers the complete set of serial commands for the HLK-LD2410 presence sensor. The latest firmware version 2.44 is supported, providing auxiliary illumination-based controls and automatic thresholds detection. 7 | category=Sensors 8 | url=https://github.com/iavorvel/MyLD2410 9 | architectures=* 10 | includes=MyLD2410.h 11 | -------------------------------------------------------------------------------- /examples/auto_thresholds/board_select.h: -------------------------------------------------------------------------------- 1 | #if defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_AVR_LEONARDO) 2 | // ARDUINO_SAMD_NANO_33_IOT RX_PIN is D1, TX_PIN is D0 3 | // ARDUINO_AVR_LEONARDO RX_PIN(RXI) is D0, TX_PIN(TXO) is D1 4 | #define sensorSerial Serial1 5 | #elif defined(ARDUINO_XIAO_ESP32C3) || defined(ARDUINO_XIAO_ESP32C6) 6 | // RX_PIN is D7, TX_PIN is D6 7 | #define sensorSerial Serial0 8 | #elif defined(ESP32) 9 | // Other ESP32 device - choose available GPIO pins 10 | #define sensorSerial Serial1 11 | #if defined(ARDUINO_ESP32S3_DEV) 12 | #define RX_PIN 18 13 | #define TX_PIN 17 14 | #else 15 | #define RX_PIN 16 16 | #define TX_PIN 17 17 | #endif 18 | #else 19 | #error "This sketch only works on ESP32, Arduino Nano 33IoT, and Arduino Leonardo (Pro-Micro)" 20 | #endif 21 | -------------------------------------------------------------------------------- /examples/factory_reset/board_select.h: -------------------------------------------------------------------------------- 1 | #if defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_AVR_LEONARDO) 2 | // ARDUINO_SAMD_NANO_33_IOT RX_PIN is D1, TX_PIN is D0 3 | // ARDUINO_AVR_LEONARDO RX_PIN(RXI) is D0, TX_PIN(TXO) is D1 4 | #define sensorSerial Serial1 5 | #elif defined(ARDUINO_XIAO_ESP32C3) || defined(ARDUINO_XIAO_ESP32C6) 6 | // RX_PIN is D7, TX_PIN is D6 7 | #define sensorSerial Serial0 8 | #elif defined(ESP32) 9 | // Other ESP32 device - choose available GPIO pins 10 | #define sensorSerial Serial1 11 | #if defined(ARDUINO_ESP32S3_DEV) 12 | #define RX_PIN 18 13 | #define TX_PIN 17 14 | #else 15 | #define RX_PIN 16 16 | #define TX_PIN 17 17 | #endif 18 | #else 19 | #error "This sketch only works on ESP32, Arduino Nano 33IoT, and Arduino Leonardo (Pro-Micro)" 20 | #endif 21 | -------------------------------------------------------------------------------- /examples/modify_parameters/board_select.h: -------------------------------------------------------------------------------- 1 | #if defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_AVR_LEONARDO) 2 | // ARDUINO_SAMD_NANO_33_IOT RX_PIN is D1, TX_PIN is D0 3 | // ARDUINO_AVR_LEONARDO RX_PIN(RXI) is D0, TX_PIN(TXO) is D1 4 | #define sensorSerial Serial1 5 | #elif defined(ARDUINO_XIAO_ESP32C3) || defined(ARDUINO_XIAO_ESP32C6) 6 | // RX_PIN is D7, TX_PIN is D6 7 | #define sensorSerial Serial0 8 | #elif defined(ESP32) 9 | // Other ESP32 device - choose available GPIO pins 10 | #define sensorSerial Serial1 11 | #if defined(ARDUINO_ESP32S3_DEV) 12 | #define RX_PIN 18 13 | #define TX_PIN 17 14 | #else 15 | #define RX_PIN 16 16 | #define TX_PIN 17 17 | #endif 18 | #else 19 | #error "This sketch only works on ESP32, Arduino Nano 33IoT, and Arduino Leonardo (Pro-Micro)" 20 | #endif 21 | -------------------------------------------------------------------------------- /examples/print_parameters/board_select.h: -------------------------------------------------------------------------------- 1 | #if defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_AVR_LEONARDO) 2 | // ARDUINO_SAMD_NANO_33_IOT RX_PIN is D1, TX_PIN is D0 3 | // ARDUINO_AVR_LEONARDO RX_PIN(RXI) is D0, TX_PIN(TXO) is D1 4 | #define sensorSerial Serial1 5 | #elif defined(ARDUINO_XIAO_ESP32C3) || defined(ARDUINO_XIAO_ESP32C6) 6 | // RX_PIN is D7, TX_PIN is D6 7 | #define sensorSerial Serial0 8 | #elif defined(ESP32) 9 | // Other ESP32 device - choose available GPIO pins 10 | #define sensorSerial Serial1 11 | #if defined(ARDUINO_ESP32S3_DEV) 12 | #define RX_PIN 18 13 | #define TX_PIN 17 14 | #else 15 | #define RX_PIN 16 16 | #define TX_PIN 17 17 | #endif 18 | #else 19 | #error "This sketch only works on ESP32, Arduino Nano 33IoT, and Arduino Leonardo (Pro-Micro)" 20 | #endif 21 | -------------------------------------------------------------------------------- /examples/set_baud_rate/board_select.h: -------------------------------------------------------------------------------- 1 | #if defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_AVR_LEONARDO) 2 | // ARDUINO_SAMD_NANO_33_IOT RX_PIN is D1, TX_PIN is D0 3 | // ARDUINO_AVR_LEONARDO RX_PIN(RXI) is D0, TX_PIN(TXO) is D1 4 | #define sensorSerial Serial1 5 | #elif defined(ARDUINO_XIAO_ESP32C3) || defined(ARDUINO_XIAO_ESP32C6) 6 | // RX_PIN is D7, TX_PIN is D6 7 | #define sensorSerial Serial0 8 | #elif defined(ESP32) 9 | // Other ESP32 device - choose available GPIO pins 10 | #define sensorSerial Serial1 11 | #if defined(ARDUINO_ESP32S3_DEV) 12 | #define RX_PIN 18 13 | #define TX_PIN 17 14 | #else 15 | #define RX_PIN 16 16 | #define TX_PIN 17 17 | #endif 18 | #else 19 | #error "This sketch only works on ESP32, Arduino Nano 33IoT, and Arduino Leonardo (Pro-Micro)" 20 | #endif 21 | -------------------------------------------------------------------------------- /examples/set_bt_password/board_select.h: -------------------------------------------------------------------------------- 1 | #if defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_AVR_LEONARDO) 2 | // ARDUINO_SAMD_NANO_33_IOT RX_PIN is D1, TX_PIN is D0 3 | // ARDUINO_AVR_LEONARDO RX_PIN(RXI) is D0, TX_PIN(TXO) is D1 4 | #define sensorSerial Serial1 5 | #elif defined(ARDUINO_XIAO_ESP32C3) || defined(ARDUINO_XIAO_ESP32C6) 6 | // RX_PIN is D7, TX_PIN is D6 7 | #define sensorSerial Serial0 8 | #elif defined(ESP32) 9 | // Other ESP32 device - choose available GPIO pins 10 | #define sensorSerial Serial1 11 | #if defined(ARDUINO_ESP32S3_DEV) 12 | #define RX_PIN 18 13 | #define TX_PIN 17 14 | #else 15 | #define RX_PIN 16 16 | #define TX_PIN 17 17 | #endif 18 | #else 19 | #error "This sketch only works on ESP32, Arduino Nano 33IoT, and Arduino Leonardo (Pro-Micro)" 20 | #endif 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Iavor Veltchev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/sensor_data/board_select.h: -------------------------------------------------------------------------------- 1 | #if defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_AVR_LEONARDO) 2 | // ARDUINO_SAMD_NANO_33_IOT RX_PIN is D1, TX_PIN is D0 3 | // ARDUINO_AVR_LEONARDO RX_PIN(RXI) is D0, TX_PIN(TXO) is D1 4 | #define sensorSerial Serial1 5 | #elif defined(ARDUINO_XIAO_ESP32C3) || defined(ARDUINO_XIAO_ESP32C6) 6 | // RX_PIN is D7, TX_PIN is D6 7 | #define sensorSerial Serial0 8 | #elif defined(ESP32) 9 | // Other ESP32 device - choose available GPIO pins 10 | #define sensorSerial Serial1 11 | #if defined(ARDUINO_ESP32S3_DEV) 12 | #define RX_PIN 18 13 | #define TX_PIN 17 14 | #else 15 | #define RX_PIN 16 16 | #define TX_PIN 17 17 | #endif 18 | #elif defined(ARDUINO_AVR_NANO) || defined(ARDUINO_AVR_UNO) 19 | // You may use SoftwareSerial, but at a lower baud rate (38400 works well) 20 | #include 21 | SoftwareSerial sSerial(10, 11); // RX, TX 22 | #define sensorSerial sSerial 23 | // This baud rate must be explicitly set once by running the "set_baud_rate.ino" example 24 | // on a board with a hardware UART 25 | #define LD2410_BAUD_RATE 38400 26 | #else 27 | #error "This sketch only works on ESP32, Arduino Nano 33IoT, Arduino Nano/Uno, and Arduino Leonardo (Pro-Micro)" 28 | #endif 29 | -------------------------------------------------------------------------------- /examples/set_bt_password/set_bt_password.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This program sets/resets the Bluetooth password of the HLK-LD2410 3 | presence sensor. 4 | 5 | To set the BT password to "passwd", run the sketch as is. 6 | To reset the BT password to "HiLink", uncomment line 32 and run the sketch 7 | #define RESET_PASSWORD 8 | 9 | #define SERIAL_BAUD_RATE sets the serial monitor baud rate 10 | 11 | Communication with the sensor is handled by the 12 | "MyLD2410" library Copyright (c) Iavor Veltchev 2024 13 | 14 | Use only hardware UART at the default baud rate 256000, 15 | or change the #define LD2410_BAUD_RATE to match your sensor. 16 | For ESP32 or other boards that allow dynamic UART pins, 17 | modify the RX_PIN and TX_PIN defines in "./board_select.h" 18 | 19 | Connection diagram: 20 | Arduino/ESP32 RX -- TX LD2410 21 | Arduino/ESP32 TX -- RX LD2410 22 | Arduino/ESP32 GND -- GND LD2410 23 | Provide sufficient power to the sensor Vcc (200mA, 5-12V) 24 | */ 25 | #include "./board_select.h" 26 | // Change the communication baud rate here, if necessary 27 | // #define LD2410_BAUD_RATE 256000 28 | #include "MyLD2410.h" 29 | 30 | // User defines 31 | // #define DEBUG_MODE 32 | // #define RESET_PASSWORD 33 | #define SERIAL_BAUD_RATE 115200 34 | 35 | 36 | #ifdef DEBUG_MODE 37 | MyLD2410 sensor(sensorSerial, true); 38 | #else 39 | MyLD2410 sensor(sensorSerial); 40 | #endif 41 | 42 | #ifndef RESET_PASSWORD 43 | String NewPassword("passwd"); 44 | #endif 45 | 46 | void setup() { 47 | Serial.begin(SERIAL_BAUD_RATE); 48 | #if defined(ARDUINO_XIAO_ESP32C3) || defined(ARDUINO_XIAO_ESP32C6) || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_AVR_LEONARDO) 49 | sensorSerial.begin(LD2410_BAUD_RATE); 50 | #else 51 | sensorSerial.begin(LD2410_BAUD_RATE, SERIAL_8N1, RX_PIN, TX_PIN); 52 | #endif 53 | delay(2000); 54 | Serial.println(__FILE__); 55 | if (!sensor.begin()) { 56 | Serial.println("Failed to communicate with the sensor."); 57 | while (true) {} 58 | } 59 | 60 | Serial.println("Established communication with the sensor."); 61 | 62 | #ifdef RESET_PASSWORD 63 | Serial.println("Setting the Bluetooth password to: \"HiLink\""); 64 | if (sensor.resetBTpassword()) 65 | Serial.println(" + Success!"); 66 | else 67 | Serial.println(" - Fail!"); 68 | #else 69 | Serial.print("Setting the Bluetooth password to: \""); 70 | Serial.print(NewPassword); 71 | Serial.println('\"'); 72 | if (sensor.setBTpassword(NewPassword)) 73 | Serial.println(" + Success!"); 74 | else 75 | Serial.println(" - Fail!"); 76 | #endif 77 | } 78 | 79 | void loop() { 80 | } -------------------------------------------------------------------------------- /examples/set_baud_rate/set_baud_rate.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This program sets the serial baud rate of the HLK-LD2410 3 | presence sensor. 4 | 5 | Use these two lines to the correct values: 6 | [line 30] #define CURRENT_BAUD_RATE LD2410_BAUD_RATE 7 | [line 31] #define NEW_BAUD_RATE 115200 8 | 9 | #define SERIAL_BAUD_RATE sets the serial monitor baud rate 10 | 11 | Communication with the sensor is handled by the 12 | "MyLD2410" library Copyright (c) Iavor Veltchev 2024 13 | 14 | Use only hardware UART at the default baud rate 256000, 15 | or change the #define LD2410_BAUD_RATE to match your sensor. 16 | For ESP32 or other boards that allow dynamic UART pins, 17 | modify the RX_PIN and TX_PIN defines in "./board_select.h" 18 | 19 | Connection diagram: 20 | Arduino/ESP32 RX -- TX LD2410 21 | Arduino/ESP32 TX -- RX LD2410 22 | Arduino/ESP32 GND -- GND LD2410 23 | Provide sufficient power to the sensor Vcc (200mA, 5-12V) 24 | */ 25 | #include "./board_select.h" 26 | #include "MyLD2410.h" 27 | 28 | // User defines 29 | // #define DEBUG_MODE 30 | #define CURRENT_BAUD_RATE LD2410_BAUD_RATE 31 | #define NEW_BAUD_RATE 38400 32 | #define SERIAL_BAUD_RATE 115200 33 | 34 | 35 | #ifdef DEBUG_MODE 36 | MyLD2410 sensor(sensorSerial, true); 37 | #else 38 | MyLD2410 sensor(sensorSerial); 39 | #endif 40 | 41 | uint32_t BAUDS[9]{ 0, 9600, 19200, 38400, 57600, 115200, 230400, 256000, 460800 }; 42 | 43 | void setup() { 44 | Serial.begin(SERIAL_BAUD_RATE); 45 | #if defined(ARDUINO_XIAO_ESP32C3) || defined(ARDUINO_XIAO_ESP32C6) || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_AVR_LEONARDO) 46 | sensorSerial.begin(CURRENT_BAUD_RATE); 47 | #else 48 | sensorSerial.begin(CURRENT_BAUD_RATE, SERIAL_8N1, RX_PIN, TX_PIN); 49 | #endif 50 | delay(2000); 51 | Serial.println(__FILE__); 52 | 53 | byte newBaudIndex = 0; 54 | for (byte i = 1; i < 9; i++) 55 | if (NEW_BAUD_RATE == BAUDS[i]) { 56 | newBaudIndex = i; 57 | break; 58 | } 59 | 60 | if (!newBaudIndex) { 61 | Serial.print("Invalid NEW_BAUD_RATE value: "); 62 | Serial.println(NEW_BAUD_RATE); 63 | while (true) {} 64 | } 65 | 66 | if (!sensor.begin()) { 67 | Serial.print("Failed to communicate with the sensor at "); 68 | Serial.print(CURRENT_BAUD_RATE); 69 | Serial.println(" baud..."); 70 | while (true) {} 71 | } 72 | Serial.println("Established communication with the sensor at "); 73 | Serial.print(CURRENT_BAUD_RATE); 74 | Serial.println(" baud!"); 75 | 76 | Serial.print("Changing the baud to "); 77 | Serial.println(NEW_BAUD_RATE); 78 | 79 | if (!sensor.setBaud(newBaudIndex)) { 80 | Serial.print(" ***Failed! The baud rate is still "); 81 | Serial.println(CURRENT_BAUD_RATE); 82 | while (true) {} 83 | } 84 | Serial.print(" +Sucess!\nYour sensor is rebooting with the new baud rate "); 85 | Serial.println(NEW_BAUD_RATE); 86 | 87 | sensorSerial.end(); 88 | delay(1000); 89 | 90 | #if defined(ARDUINO_XIAO_ESP32C3) || defined(ARDUINO_XIAO_ESP32C6) || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_AVR_LEONARDO) 91 | sensorSerial.begin(NEW_BAUD_RATE); 92 | #else 93 | sensorSerial.begin(NEW_BAUD_RATE, SERIAL_8N1, RX_PIN, TX_PIN); 94 | #endif 95 | delay(1000); 96 | if (!sensor.begin()) { 97 | Serial.print("Failed to communicate with the sensor at "); 98 | Serial.print(NEW_BAUD_RATE); 99 | Serial.println(" baud..."); 100 | } else { 101 | Serial.println("Established communication with the sensor at "); 102 | Serial.print(NEW_BAUD_RATE); 103 | Serial.println(" baud!"); 104 | } 105 | } 106 | 107 | void loop() { 108 | } -------------------------------------------------------------------------------- /examples/print_parameters/print_parameters.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This program prints the current setup parameters 3 | of the HLK-LD2410 presence sensor. 4 | 5 | #define SERIAL_BAUD_RATE sets the serial monitor baud rate 6 | 7 | Communication with the sensor is handled by the 8 | "MyLD2410" library Copyright (c) Iavor Veltchev 2024 9 | 10 | Use only hardware UART at the default baud rate 256000, 11 | or change the #define LD2410_BAUD_RATE to match your sensor. 12 | For ESP32 or other boards that allow dynamic UART pins, 13 | modify the RX_PIN and TX_PIN defines in "./board_select.h" 14 | 15 | Connection diagram: 16 | Arduino/ESP32 RX -- TX LD2410 17 | Arduino/ESP32 TX -- RX LD2410 18 | Arduino/ESP32 GND -- GND LD2410 19 | Provide sufficient power to the sensor Vcc (200mA, 5-12V) 20 | */ 21 | #include "./board_select.h" 22 | //Change the communication baud rate here, if necessary 23 | //#define LD2410_BAUD_RATE 256000 24 | #include "MyLD2410.h" 25 | 26 | // User defines 27 | #define SERIAL_BAUD_RATE 115200 28 | 29 | MyLD2410 sensor(sensorSerial); 30 | 31 | void printValue(const byte &val) { 32 | Serial.print(' '); 33 | Serial.print(val); 34 | } 35 | 36 | void printParameters() { 37 | sensor.configMode(); 38 | sensor.requestParameters(); 39 | Serial.print("Firmware: "); 40 | String fw(sensor.getFirmware()); 41 | Serial.println(fw); 42 | if (!fw.startsWith(LD2410_LATEST_FIRMWARE)) { 43 | Serial.print("To get the lastest features, upgrade your firmware to "); 44 | Serial.println(LD2410_LATEST_FIRMWARE); 45 | } 46 | Serial.print("Protocol version: "); 47 | Serial.println(sensor.getVersion()); 48 | Serial.print("Bluetooth MAC address: "); 49 | Serial.println(sensor.getMACstr()); 50 | 51 | const MyLD2410::ValuesArray &mThr = sensor.getMovingThresholds(); 52 | const MyLD2410::ValuesArray &sThr = sensor.getStationaryThresholds(); 53 | 54 | Serial.print("Resolution (gate-width): "); 55 | Serial.print(sensor.getResolution()); 56 | Serial.print("cm\nMax range: "); 57 | Serial.print(sensor.getRange_cm()); 58 | Serial.print("cm\nMoving thresholds [0,"); 59 | Serial.print(mThr.N); 60 | Serial.print("]:"); 61 | //Print using global function 62 | mThr.forEach(printValue); 63 | Serial.print("\nStationary thresholds[0,"); 64 | Serial.print(sThr.N); 65 | Serial.print("]:"); 66 | //Print using lambda 67 | sThr.forEach([](const byte &val) { 68 | Serial.print(' '); 69 | Serial.print(val); 70 | }); 71 | Serial.print("\nNo-one window: "); 72 | Serial.print(sensor.getNoOneWindow()); 73 | Serial.println('s'); 74 | 75 | //For firmware >= 2.44 76 | if (sensor.requestAuxConfig()) { 77 | Serial.print("Auxiliary Configuration: "); 78 | switch (sensor.getLightControl()) { 79 | case LightControl::NO_LIGHT_CONTROL: 80 | Serial.println("no light control"); 81 | break; 82 | case LightControl::LIGHT_BELOW_THRESHOLD: 83 | Serial.println("active when light is below the threshold of "); 84 | Serial.println(sensor.getLightThreshold()); 85 | break; 86 | case LightControl::LIGHT_ABOVE_THRESHOLD: 87 | Serial.println("active when light is above the threshold of "); 88 | Serial.println(sensor.getLightThreshold()); 89 | break; 90 | default: 91 | break; 92 | } 93 | switch (sensor.getOutputControl()) { 94 | case OutputControl::DEFAULT_LOW: 95 | Serial.println("Default output level: LOW"); 96 | break; 97 | case OutputControl::DEFAULT_HIGH: 98 | Serial.println("Default output level: HIGH"); 99 | break; 100 | default: 101 | break; 102 | } 103 | } 104 | sensor.configMode(false); 105 | } 106 | 107 | void setup() { 108 | Serial.begin(SERIAL_BAUD_RATE); 109 | #if defined(ARDUINO_XIAO_ESP32C3) || defined(ARDUINO_XIAO_ESP32C6) || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_AVR_LEONARDO) 110 | sensorSerial.begin(LD2410_BAUD_RATE); 111 | #else 112 | sensorSerial.begin(LD2410_BAUD_RATE, SERIAL_8N1, RX_PIN, TX_PIN); 113 | #endif 114 | delay(2000); 115 | Serial.println(__FILE__); 116 | if (!sensor.begin()) { 117 | Serial.println("Failed to communicate with the sensor."); 118 | while (true) {} 119 | } 120 | 121 | printParameters(); 122 | 123 | delay(2000); 124 | Serial.println("Done!"); 125 | } 126 | 127 | void loop() { 128 | } 129 | -------------------------------------------------------------------------------- /examples/factory_reset/factory_reset.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This program performs a factory reset 3 | of the HLK-LD2410 presence sensor. 4 | 5 | #define SERIAL_BAUD_RATE sets the serial monitor baud rate 6 | 7 | Communication with the sensor is handled by the 8 | "MyLD2410" library Copyright (c) Iavor Veltchev 2024 9 | 10 | Use only hardware UART at the default baud rate 256000, 11 | or change the #define LD2410_BAUD_RATE to match your sensor. 12 | For ESP32 or other boards that allow dynamic UART pins, 13 | modify the RX_PIN and TX_PIN defines in "./board_select.h" 14 | 15 | Connection diagram: 16 | Arduino/ESP32 RX -- TX LD2410 17 | Arduino/ESP32 TX -- RX LD2410 18 | Arduino/ESP32 GND -- GND LD2410 19 | Provide sufficient power to the sensor Vcc (200mA, 5-12V) 20 | */ 21 | #include "./board_select.h" 22 | //Change the communication baud rate here, if necessary 23 | //#define LD2410_BAUD_RATE 256000 24 | #include "MyLD2410.h" 25 | 26 | // User defines 27 | #define SERIAL_BAUD_RATE 115200 28 | 29 | MyLD2410 sensor(sensorSerial); 30 | 31 | void printValue(const byte &val) { 32 | Serial.print(' '); 33 | Serial.print(val); 34 | } 35 | 36 | void printParameters() { 37 | sensor.configMode(); 38 | sensor.requestParameters(); 39 | Serial.print("Firmware: "); 40 | String fw(sensor.getFirmware()); 41 | Serial.println(fw); 42 | if (!fw.startsWith(LD2410_LATEST_FIRMWARE)) { 43 | Serial.print("To get the lastest features, upgrade your firmware to "); 44 | Serial.println(LD2410_LATEST_FIRMWARE); 45 | } 46 | Serial.print("Protocol version: "); 47 | Serial.println(sensor.getVersion()); 48 | Serial.print("Bluetooth MAC address: "); 49 | Serial.println(sensor.getMACstr()); 50 | 51 | const MyLD2410::ValuesArray &mThr = sensor.getMovingThresholds(); 52 | const MyLD2410::ValuesArray &sThr = sensor.getStationaryThresholds(); 53 | 54 | Serial.print("Resolution (gate-width): "); 55 | Serial.print(sensor.getResolution()); 56 | Serial.print("cm\nMax range: "); 57 | Serial.print(sensor.getRange_cm()); 58 | Serial.print("cm\nMoving thresholds [0,"); 59 | Serial.print(mThr.N); 60 | Serial.print("]:"); 61 | //Print using global function 62 | mThr.forEach(printValue); 63 | Serial.print("\nStationary thresholds[0,"); 64 | Serial.print(sThr.N); 65 | Serial.print("]:"); 66 | //Print using lambda 67 | sThr.forEach([](const byte &val) { 68 | Serial.print(' '); 69 | Serial.print(val); 70 | }); 71 | Serial.print("\nNo-one window: "); 72 | Serial.print(sensor.getNoOneWindow()); 73 | Serial.println('s'); 74 | 75 | //For firmware >= 2.44 76 | if (sensor.requestAuxConfig()) { 77 | Serial.print("Auxiliary Configuration: "); 78 | switch (sensor.getLightControl()) { 79 | case LightControl::NO_LIGHT_CONTROL: 80 | Serial.println("no light control"); 81 | break; 82 | case LightControl::LIGHT_BELOW_THRESHOLD: 83 | Serial.println("active when light is below the threshold of "); 84 | Serial.println(sensor.getLightThreshold()); 85 | break; 86 | case LightControl::LIGHT_ABOVE_THRESHOLD: 87 | Serial.println("active when light is above the threshold of "); 88 | Serial.println(sensor.getLightThreshold()); 89 | break; 90 | default: 91 | break; 92 | } 93 | switch (sensor.getOutputControl()) { 94 | case OutputControl::DEFAULT_LOW: 95 | Serial.println("Default output level: LOW"); 96 | break; 97 | case OutputControl::DEFAULT_HIGH: 98 | Serial.println("Default output level: HIGH"); 99 | break; 100 | default: 101 | break; 102 | } 103 | } 104 | sensor.configMode(false); 105 | } 106 | 107 | void setup() { 108 | Serial.begin(SERIAL_BAUD_RATE); 109 | #if defined(ARDUINO_XIAO_ESP32C3) || defined(ARDUINO_XIAO_ESP32C6) || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_AVR_LEONARDO) 110 | sensorSerial.begin(LD2410_BAUD_RATE); 111 | #else 112 | sensorSerial.begin(LD2410_BAUD_RATE, SERIAL_8N1, RX_PIN, TX_PIN); 113 | #endif 114 | delay(2000); 115 | Serial.println(__FILE__); 116 | if (!sensor.begin()) { 117 | Serial.println("Failed to communicate with the sensor."); 118 | while (true) {} 119 | } 120 | 121 | printParameters(); 122 | 123 | delay(2000); 124 | Serial.print("\nExecuting factory reset... "); 125 | if (sensor.setGateParameters(0, 0, 0) && sensor.setGateParameters(1, 0, 0) && sensor.requestReset()) { 126 | Serial.println("Done!\n"); 127 | printParameters(); 128 | } else Serial.println("Fail\n"); 129 | } 130 | 131 | void loop() { 132 | } 133 | -------------------------------------------------------------------------------- /examples/sensor_data/sensor_data.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This program reads all data received from 3 | the HLK-LD2410 presence sensor and periodically 4 | prints the values to the serial monitor. 5 | 6 | Several #defines control the behavior of the program: 7 | #define SERIAL_BAUD_RATE sets the serial monitor baud rate 8 | 9 | #define ENHANCED_MODE enables the enhanced (engineering) 10 | mode of the sensor. Comment that line to switch to basic mode. 11 | 12 | #define DEBUG_MODE enables the printing of debug information 13 | (all received frames are printed). Comment the line to disable 14 | debugging. 15 | 16 | Communication with the sensor is handled by the 17 | "MyLD2410" library Copyright (c) Iavor Veltchev 2024 18 | 19 | Use only hardware UART at the default baud rate 256000, 20 | or change the #define LD2410_BAUD_RATE to match your sensor. 21 | For ESP32 or other boards that allow dynamic UART pins, 22 | modify the RX_PIN and TX_PIN defines in "./board_select.h" 23 | 24 | Connection diagram: 25 | Arduino/ESP32 RX -- TX LD2410 26 | Arduino/ESP32 TX -- RX LD2410 27 | Arduino/ESP32 GND -- GND LD2410 28 | Provide sufficient power to the sensor Vcc (200mA, 5-12V) 29 | */ 30 | #include "./board_select.h" 31 | // Change the communication baud rate here, if previously configured 32 | // #define LD2410_BAUD_RATE 256000 33 | #include "MyLD2410.h" 34 | 35 | // User defines 36 | // #define DEBUG_MODE 37 | #define ENHANCED_MODE 38 | #define SERIAL_BAUD_RATE 115200 39 | 40 | 41 | #ifdef DEBUG_MODE 42 | MyLD2410 sensor(sensorSerial, true); 43 | #else 44 | MyLD2410 sensor(sensorSerial); 45 | #endif 46 | 47 | const unsigned long printEvery = 1000; // print every second 48 | 49 | void printValue(const byte &val) { 50 | Serial.print(' '); 51 | Serial.print(val); 52 | } 53 | 54 | void printData() { 55 | Serial.print("Data frame #: "); 56 | Serial.println(sensor.getFrameCount()); 57 | Serial.print("Time stamp [ms]: "); 58 | Serial.println(sensor.getTimestamp()); 59 | Serial.print(sensor.statusString()); 60 | if (sensor.presenceDetected()) { 61 | Serial.print(", distance: "); 62 | Serial.print(sensor.detectedDistance()); 63 | Serial.print("cm"); 64 | } 65 | Serial.println(); 66 | if (sensor.movingTargetDetected()) { 67 | Serial.print(" MOVING = "); 68 | Serial.print(sensor.movingTargetSignal()); 69 | Serial.print("@"); 70 | Serial.print(sensor.movingTargetDistance()); 71 | Serial.print("cm "); 72 | if (sensor.inEnhancedMode()) { 73 | Serial.print("\n signals->["); 74 | sensor.getMovingSignals().forEach(printValue); 75 | Serial.print(" ] thresholds:["); 76 | sensor.getMovingThresholds().forEach(printValue); 77 | Serial.print(" ]"); 78 | } 79 | Serial.println(); 80 | } 81 | if (sensor.stationaryTargetDetected()) { 82 | Serial.print(" STATIONARY= "); 83 | Serial.print(sensor.stationaryTargetSignal()); 84 | Serial.print("@"); 85 | Serial.print(sensor.stationaryTargetDistance()); 86 | Serial.print("cm "); 87 | if (sensor.inEnhancedMode()) { 88 | Serial.print("\n signals->["); 89 | sensor.getStationarySignals().forEach(printValue); 90 | Serial.print(" ] thresholds:["); 91 | sensor.getStationaryThresholds().forEach(printValue); 92 | Serial.print(" ]"); 93 | } 94 | Serial.println(); 95 | } 96 | 97 | if (sensor.inEnhancedMode() && (sensor.getFirmwareMajor() > 1)) { 98 | Serial.print("Light level: "); 99 | Serial.println(sensor.getLightLevel()); 100 | Serial.print("Output level: "); 101 | Serial.println((sensor.getOutLevel()) ? "HIGH" : "LOW"); 102 | } 103 | 104 | Serial.println(); 105 | } 106 | 107 | void setup() { 108 | Serial.begin(SERIAL_BAUD_RATE); 109 | #if defined(ARDUINO_XIAO_ESP32C3) || defined(ARDUINO_XIAO_ESP32C6) || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_AVR_LEONARDO) || defined(ARDUINO_AVR_NANO) || defined(ARDUINO_AVR_UNO) 110 | sensorSerial.begin(LD2410_BAUD_RATE); 111 | #else 112 | sensorSerial.begin(LD2410_BAUD_RATE, SERIAL_8N1, RX_PIN, TX_PIN); 113 | #endif 114 | delay(2000); 115 | Serial.println(__FILE__); 116 | if (!sensor.begin()) { 117 | Serial.println("Failed to communicate with the sensor."); 118 | while (true) {} 119 | } 120 | 121 | #ifdef ENHANCED_MODE 122 | sensor.enhancedMode(); 123 | #else 124 | sensor.enhancedMode(false); 125 | #endif 126 | 127 | delay(printEvery); 128 | } 129 | 130 | void loop() { 131 | static unsigned long nextPrint = 0; 132 | if ((sensor.check() == MyLD2410::Response::DATA) && (millis() >= nextPrint)) { 133 | nextPrint = millis() + printEvery; 134 | printData(); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /examples/auto_thresholds/auto_thresholds.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This program utilizes the automatic thresholds detection that 3 | was introduced in firmware 2.44 for the HLK-LD2410 presence sensor. 4 | 5 | #define SERIAL_BAUD_RATE sets the serial monitor baud rate 6 | 7 | Communication with the sensor is handled by the 8 | "MyLD2410" library Copyright (c) Iavor Veltchev 2025 9 | 10 | Use only hardware UART at the default baud rate 256000, 11 | or change the #define LD2410_BAUD_RATE to match your sensor. 12 | For ESP32 or other boards that allow dynamic UART pins, 13 | modify the RX_PIN and TX_PIN defines in "./board_select.h" 14 | 15 | Connection diagram: 16 | Arduino/ESP32 RX -- TX LD2410 17 | Arduino/ESP32 TX -- RX LD2410 18 | Arduino/ESP32 GND -- GND LD2410 19 | Provide sufficient power to the sensor Vcc (200mA, 5-12V) 20 | */ 21 | #include "./board_select.h" 22 | //Change the communication baud rate here, if necessary 23 | //#define LD2410_BAUD_RATE 256000 24 | #include "MyLD2410.h" 25 | 26 | // User defines 27 | #define SERIAL_BAUD_RATE 115200 28 | 29 | MyLD2410 sensor(sensorSerial); 30 | 31 | void printValue(const byte &val) { 32 | Serial.print(' '); 33 | Serial.print(val); 34 | } 35 | 36 | void printParameters() { 37 | sensor.configMode(); 38 | sensor.requestParameters(); 39 | Serial.print("Firmware: "); 40 | String fw(sensor.getFirmware()); 41 | Serial.println(fw); 42 | if (!fw.startsWith(LD2410_LATEST_FIRMWARE)) { 43 | Serial.print("To get the lastest features, upgrade your firmware to "); 44 | Serial.println(LD2410_LATEST_FIRMWARE); 45 | } 46 | Serial.print("Protocol version: "); 47 | Serial.println(sensor.getVersion()); 48 | Serial.print("Bluetooth MAC address: "); 49 | Serial.println(sensor.getMACstr()); 50 | 51 | const MyLD2410::ValuesArray &mThr = sensor.getMovingThresholds(); 52 | const MyLD2410::ValuesArray &sThr = sensor.getStationaryThresholds(); 53 | 54 | Serial.print("Resolution (gate-width): "); 55 | Serial.print(sensor.getResolution()); 56 | Serial.print("cm\nMax range: "); 57 | Serial.print(sensor.getRange_cm()); 58 | Serial.print("cm\nMoving thresholds [0,"); 59 | Serial.print(mThr.N); 60 | Serial.print("]:"); 61 | //Print using global function 62 | mThr.forEach(printValue); 63 | Serial.print("\nStationary thresholds[0,"); 64 | Serial.print(sThr.N); 65 | Serial.print("]:"); 66 | //Print using lambda 67 | sThr.forEach([](const byte &val) { 68 | Serial.print(' '); 69 | Serial.print(val); 70 | }); 71 | Serial.print("\nNo-one window: "); 72 | Serial.print(sensor.getNoOneWindow()); 73 | Serial.println('s'); 74 | 75 | //For firmware >= 2.44 76 | if (sensor.requestAuxConfig()) { 77 | Serial.print("Auxiliary Configuration: "); 78 | switch (sensor.getLightControl()) { 79 | case LightControl::NO_LIGHT_CONTROL: 80 | Serial.println("no light control"); 81 | break; 82 | case LightControl::LIGHT_BELOW_THRESHOLD: 83 | Serial.println("active when light is below the threshold of "); 84 | Serial.println(sensor.getLightThreshold()); 85 | break; 86 | case LightControl::LIGHT_ABOVE_THRESHOLD: 87 | Serial.println("active when light is above the threshold of "); 88 | Serial.println(sensor.getLightThreshold()); 89 | break; 90 | default: 91 | break; 92 | } 93 | switch (sensor.getOutputControl()) { 94 | case OutputControl::DEFAULT_LOW: 95 | Serial.println("Default output level: LOW"); 96 | break; 97 | case OutputControl::DEFAULT_HIGH: 98 | Serial.println("Default output level: HIGH"); 99 | break; 100 | default: 101 | break; 102 | } 103 | } 104 | sensor.configMode(false); 105 | } 106 | 107 | void setup() { 108 | Serial.begin(SERIAL_BAUD_RATE); 109 | #if defined(ARDUINO_XIAO_ESP32C3) || defined(ARDUINO_XIAO_ESP32C6) || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_AVR_LEONARDO) 110 | sensorSerial.begin(LD2410_BAUD_RATE); 111 | #else 112 | sensorSerial.begin(LD2410_BAUD_RATE, SERIAL_8N1, RX_PIN, TX_PIN); 113 | #endif 114 | delay(2000); 115 | Serial.println(__FILE__); 116 | if (!sensor.begin()) { 117 | Serial.println("Failed to communicate with the sensor."); 118 | while (true) {} 119 | } 120 | 121 | Serial.println("Initial sensor parameters\n-------------------------"); 122 | printParameters(); 123 | if (sensor.autoThresholds()) { 124 | Serial.println("\n************\nYOU HAVE 10 SECONDS TO LEAVE THE ROOM!!!\n************"); 125 | delay(10000); 126 | Serial.print("In progress "); 127 | while (true) { 128 | switch (sensor.getAutoStatus()) { 129 | case AutoStatus::IN_PROGRESS: 130 | Serial.print('.'); 131 | delay(2000); 132 | break; 133 | case AutoStatus::COMPLETED: 134 | Serial.println("\nSUCCESS!!!"); 135 | Serial.println("Final sensor parameters\n-----------------------"); 136 | printParameters(); 137 | Serial.println("Done!"); 138 | return; 139 | case AutoStatus::NOT_IN_PROGRESS: 140 | Serial.println("\nStopped. Motion detected?"); 141 | printParameters(); 142 | Serial.print("Performing factory reset... "); 143 | delay(2000); 144 | if (sensor.requestReset()) Serial.println("Done!"); 145 | else Serial.println("Fail..."); 146 | printParameters(); 147 | Serial.println("Bye"); 148 | return; 149 | default: 150 | break; 151 | } 152 | } 153 | } else { 154 | Serial.println("Automatic thresholds configuration failed..."); 155 | Serial.println("Is the firmware < 2.44?"); 156 | sensor.requestReboot(); 157 | printParameters(); 158 | Serial.println("Bye"); 159 | } 160 | } 161 | 162 | void loop() { 163 | } 164 | -------------------------------------------------------------------------------- /examples/modify_parameters/modify_parameters.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This program demonstrates how to modify the setup parameters 3 | of the HLK-LD2410 presence sensor. 4 | 5 | #define SERIAL_BAUD_RATE sets the serial monitor baud rate 6 | 7 | Communication with the sensor is handled by the 8 | "MyLD2410" library Copyright (c) Iavor Veltchev 2024 9 | 10 | Use only hardware UART at the default baud rate 256000, 11 | or change the #define LD2410_BAUD_RATE to match your sensor. 12 | For ESP32 or other boards that allow dynamic UART pins, 13 | modify the RX_PIN and TX_PIN defines in "./board_select.h" 14 | 15 | Connection diagram: 16 | Arduino/ESP32 RX -- TX LD2410 17 | Arduino/ESP32 TX -- RX LD2410 18 | Arduino/ESP32 GND -- GND LD2410 19 | Provide sufficient power to the sensor Vcc (200mA, 5-12V) 20 | */ 21 | #include "./board_select.h" 22 | // Change the communication baud rate here, if necessary 23 | // #define LD2410_BAUD_RATE 256000 24 | #include "MyLD2410.h" 25 | 26 | // User defines 27 | #define SERIAL_BAUD_RATE 115200 28 | 29 | MyLD2410 sensor(sensorSerial); 30 | 31 | bool restore = true; 32 | byte maxMovingGate, maxStationaryGate, noOneWindow; 33 | bool fineRes; 34 | MyLD2410::ValuesArray movingParameters, stationaryParameters; 35 | 36 | void printValue(const byte &val) { 37 | Serial.print(' '); 38 | Serial.print(val); 39 | } 40 | 41 | void printParameters(bool first = false) { 42 | sensor.configMode(); 43 | sensor.requestParameters(); 44 | if (first) { 45 | Serial.print("Firmware: "); 46 | Serial.println(sensor.getFirmware()); 47 | Serial.print("Protocol version: "); 48 | Serial.println(sensor.getVersion()); 49 | Serial.print("Bluetooth MAC address: "); 50 | Serial.println(sensor.getMACstr()); 51 | } 52 | const MyLD2410::ValuesArray &mThr = sensor.getMovingThresholds(); 53 | const MyLD2410::ValuesArray &sThr = sensor.getStationaryThresholds(); 54 | 55 | Serial.print("Resolution (gate-width): "); 56 | Serial.print(sensor.getResolution()); 57 | Serial.print("cm\nMax range: "); 58 | Serial.print(sensor.getRange_cm()); 59 | Serial.print("cm\nMoving thresholds [0,"); 60 | Serial.print(mThr.N); 61 | Serial.print("]:"); 62 | mThr.forEach(printValue); 63 | Serial.print("\nStationary thresholds[0,"); 64 | Serial.print(sThr.N); 65 | Serial.print("]:"); 66 | sThr.forEach(printValue); 67 | Serial.print("\nNo-one window: "); 68 | Serial.print(sensor.getNoOneWindow()); 69 | Serial.println('s'); 70 | 71 | sensor.configMode(false); 72 | } 73 | 74 | void setup() { 75 | Serial.begin(SERIAL_BAUD_RATE); 76 | #if defined(ARDUINO_XIAO_ESP32C3) || defined(ARDUINO_XIAO_ESP32C6) || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_AVR_LEONARDO) 77 | sensorSerial.begin(LD2410_BAUD_RATE); 78 | #else 79 | sensorSerial.begin(LD2410_BAUD_RATE, SERIAL_8N1, RX_PIN, TX_PIN); 80 | #endif 81 | delay(2000); 82 | Serial.println(__FILE__); 83 | if (!sensor.begin()) { 84 | Serial.println("Failed to communicate with the sensor."); 85 | while (true) { 86 | } 87 | } 88 | 89 | Serial.println("Current set of parameters"); 90 | printParameters(true); 91 | fineRes = (sensor.getResolution() == 20); 92 | noOneWindow = sensor.getNoOneWindow(); 93 | movingParameters = sensor.getMovingThresholds(); 94 | stationaryParameters = sensor.getStationaryThresholds(); 95 | 96 | delay(2000); 97 | // Set the no-one window parameter to 3 seconds 98 | Serial.println("\nSetting the no-one window to 3 seconds"); 99 | if (sensor.setNoOneWindow(3)) 100 | printParameters(); 101 | else { 102 | Serial.println("Fail"); 103 | return; 104 | } 105 | 106 | delay(2000); 107 | // Change the resolution fine->coarse or coarse->fine 108 | Serial.print("\nSetting the resolution (gate-width) to "); 109 | Serial.print(((fineRes) ? 75 : 20)); 110 | Serial.println("cm"); 111 | if (sensor.setResolution(!fineRes)) 112 | printParameters(); 113 | else { 114 | Serial.println("Fail"); 115 | return; 116 | } 117 | 118 | delay(2000); 119 | // Set the maximum moving gate parameter to 4 120 | Serial.println("\nSetting the maximum moving gate parameter to 4"); 121 | if (sensor.setMaxMovingGate(4)) 122 | printParameters(); 123 | else { 124 | Serial.println("Fail"); 125 | return; 126 | } 127 | 128 | delay(2000); 129 | // Set the maximum stationary gate parameter to 5 130 | Serial.println("\nSetting the maximum stationary gate parameter to 5"); 131 | if (sensor.setMaxStationaryGate(5)) 132 | printParameters(); 133 | else { 134 | Serial.println("Fail"); 135 | return; 136 | } 137 | 138 | delay(2000); 139 | // Set the thresholds of all gates to 35 (moving) and 45 (stationary) 140 | Serial.println("\nSetting the thresholds of all gates to 35 (moving) and 45 (stationary)"); 141 | if (sensor.setGateParameters(0xFF, 35, 45)) 142 | printParameters(); 143 | else { 144 | Serial.println("Fail"); 145 | return; 146 | } 147 | 148 | delay(2000); 149 | // Set the moving target threshold of gate 3 to 15 150 | Serial.println("\nSetting the moving target threshold of gate 3 to 15"); 151 | if (sensor.setMovingThreshold(3, 15)) 152 | printParameters(); 153 | else { 154 | Serial.println("Fail"); 155 | return; 156 | } 157 | 158 | delay(2000); 159 | // Set the stationary target threshold of gate 3 to 25 160 | Serial.println("\nSetting the stationary target threshold of gate 3 to 25"); 161 | if (sensor.setStationaryThreshold(3, 25)) 162 | printParameters(); 163 | else { 164 | Serial.println("Fail"); 165 | return; 166 | } 167 | 168 | Serial.println("\nSuccess!"); 169 | } 170 | 171 | void loop() { 172 | if (restore) { 173 | restore = false; 174 | Serial.println("\nRestoring the original settings"); 175 | delay(2000); 176 | if (sensor.setResolution(fineRes) && sensor.setGateParameters(movingParameters, stationaryParameters, noOneWindow)) { 177 | printParameters(); 178 | Serial.println("Done!"); 179 | } else { 180 | Serial.println("\nO-oh, something went wrong..."); 181 | Serial.println("\nLoad the \"factory_reset\" sketch to restore the defaults..."); 182 | } 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MyLD2410 Arduino Library 2 | ## Introduction 3 | 4 | This library covers the complete set of serial commands for the LD2410 presence sensor, including HLK-LD2410B and HLK-LD2410C. It has no external dependencies and will work on any Arduino and ESP32 board. 5 | 6 | The latest firmware version 2.44 is supported, providing auxiliary illumination-based controls and automatic thresholds detection. 7 | 8 | HLK-LD2410C
9 | ![LD2410C](images/ld2410c.png) 10 | 11 | HLK-LD2410B
12 | ![LD2410B](images/ld2410.png) 13 | 14 | ## Installation 15 | 16 | 1. It is recommended to install this library from the Arduino Library Manager (search for "MyLD2410"). However, if the Arduino Library Manager does not find it, or you prefer to install it yourself, download or clone this repository. 17 | 18 | - Unzip the downloaded archive in the Arduino/libraries folder. 19 | 20 | - Restart the Arduino IDE. 21 | 22 | 1. Include the header file: `#include ` in your sketch. 23 | 24 | ## Documentation 25 | 26 | [MyLD2410 Documentation](https://iavorvel.github.io/site/MyLD2410/classMyLD2410.html) 27 | 28 | 29 | ## Usage 30 | * Decide which **hardware** serial stream you'll be using for communication. For 5V Arduino boards you must use a voltage divider (1:2 or 2:3) on the TX line to protect the RX pin of the sensor, which operates at 3.3V. 31 | 32 | `#define sensorSerial Serial1` 33 | 34 | 35 | | Board | Serial | RX pin | Tx pin | 36 | |--------|--------|:--:|:--:| 37 | | ESP32 WROOM-32 | Serial1 | 16 | 17 | 38 | | ESP32-S3 WROOM | Serial1 | 18 | 17 | 39 | | Xiao-ESP32-c3 | Serial0 | D7 | D6 | 40 | | Xiao-ESP32-c6 | Serial0 | D7 | D6 | 41 | | Adruino Nano 33 IoT | Serial1 | D1 | D0 | 42 | | Adruino Pro-Micro (Leonardo, **5V!**) | Serial1 | D0 | D1 | 43 | 44 | * Create a global instance of the sensor object 45 | 46 | ```c++ 47 | MyLD2410 sensor(sensorSerial); 48 | ``` 49 | 50 | * In the `setup()` function, begin serial communication with baud rate `LD2420_BAUD_RATE` (256000). On ESP32-WROOM: RX_PIN(16), TX_PIN(17). Check the exact pin numbers for your board. Then call `sensor.begin()` to begin communication with the sensor. 51 | 52 | ```c++ 53 | sensorSerial.begin(LD2410_BAUD_RATE, SERIAL_8N1, RX_PIN, TX_PIN); 54 | 55 | if (!sensor.begin()) { 56 | Serial.println("Failed to communicate with the sensor"); 57 | while (true); 58 | } 59 | ``` 60 | 61 | * In the `loop()` function, call as often as possible `sensor.check()`. This function returns: 62 | 63 | 1. `MyLD2410::DATA` if a data frame is received 64 | 65 | 1. `MyLD2410::ACK` if a command-response frame is received 66 | 67 | 1. `MyLD2410::FAIL` if no useful information was processed 68 | 69 | * Use the many convenience functions to extract/modify the sensor data (see the examples below). 70 | 71 | * There is a useful **Debug** feature that prints all frames received from the sensor. To enable debugging you instantiate the sensor with a second argument set to true: 72 | 73 | `MyLD2410 sensor(sensorSerial, true);` 74 | 75 | Debugging can be enabled and disabled at runtime with `sensor.debugOn();` and `sensor.debugOff();` 76 | 77 | ## Examples 78 | * Once the library is installed, navigate to: `File`→`Examples`→`MyLD2410` to play with the examples. They are automatically configured for some popular boards (see the table above). For other boards, minor (trivial) modifications may be necessary. Study the `board_select.h` header file in each example. 79 | 80 | 1. `sensor_data` - retrieves all data frames from the sensor and outputs useful information every second. Handles both basic and enhanced (engineering) modes. 81 | 82 | Sample output: 83 | ```text 84 | Both moving and stationary, distance: 131cm 85 | MOVING = 100@30cm 86 | signals->[ 100 100 31 36 34 30 10 3 6 ] thresholds:[ 50 50 40 30 20 15 15 15 15 ] 87 | STATIONARY= 100@263cm 88 | signals->[ 0 0 82 100 100 79 79 71 35 ] thresholds:[ 0 0 40 40 30 30 20 20 20 ] 89 | Light level: 175 90 | Output level: HIGH 91 | ``` 92 | 93 | ```text 94 | No target 95 | Light level: 163 96 | Output level: LOW 97 | ``` 98 | 99 | 1. `print_parameters`- prints the current device parameters. Note your firmware version and upgrade it using the Bluetooth app to get the latest features. 100 | 101 | Sample output: 102 | ```text 103 | Firmware: 2.44.24073110 104 | Protocol version: 1 105 | Bluetooth MAC address: 49:AF:7B:68:81:28 106 | Resolution (gate-width): 75cm 107 | Max range: 675cm 108 | Moving thresholds [0,8]: 50 50 40 30 20 15 15 15 15 109 | Stationary thresholds[0,8]: 0 0 40 40 30 30 20 20 20 110 | No-one window: 5s 111 | Auxiliary Configuration: no light control 112 | Default output level: LOW 113 | Done! 114 | ``` 115 | 116 | 1. `factory_reset` - restores the factory default values of the sensor parameters. 117 | 118 | 1. `modify_parameters` - demonstrates how to modify various sensor parameters. At the end, the original state of the sensor is restored. 119 | 120 | 1. `auto_thresholds` - automatically detect the thresholds for the particular environment. This feature was introduced in firmware **version 2.44**. 121 | 122 | 1. `set_bt_password` - sets a new Bluetooth password, or resets the password to its default value "HiLink". _Be careful not to get locked out of your sensor._ 123 | 124 | - The password must be 6 characters long. If you enter a longer password (on line 54), it will be truncated to 6 characters. 125 | 126 | - If you provide a shorter one, it will be padded with spaces (0x20). 127 | 128 | - To restore the default password, uncomment the line `#define RESET_PASSWORD` and flash the sketch again. 129 | 130 | 1. `set_baud_rate` - sets and tests a new baud rate for communication with the sensor. _Be careful not to get locked out of your sensor._ 131 | 132 | - This is useful when you intend to use the LD2410 sensor on a board like Arduino Nano/Uno. First lower the baud rate to 38400 and then use `SoftwareSerial` to communicate on pins 10 (RX) and 11 (TX). Check out the `board_select.h` header file in `sensor_data`. 133 | 134 | ## Have fun! 135 | -------------------------------------------------------------------------------- /src/MyLD2410.h: -------------------------------------------------------------------------------- 1 | #ifndef MY_LD2410_H 2 | #define MY_LD2410_H 3 | 4 | /* 5 | 6 | MyLD2410 library 7 | An Arduino library for the LD2410 presence sensor, including HLK-LD2410B and HLK-LD2410C. 8 | https://github.com/iavorvel/MyLD2410 9 | 10 | */ 11 | 12 | /** 13 | * @file MyLD2410.h 14 | */ 15 | 16 | #include 17 | #ifndef LD2410_BAUD_RATE 18 | #define LD2410_BAUD_RATE 256000 19 | #endif 20 | #define LD2410_BUFFER_SIZE 0x40 21 | #define LD2410_LATEST_FIRMWARE "2.44" 22 | 23 | /** 24 | * @brief The auxiliary light control status 25 | */ 26 | enum class LightControl 27 | { 28 | NOT_SET = -1, 29 | NO_LIGHT_CONTROL, 30 | LIGHT_BELOW_THRESHOLD, 31 | LIGHT_ABOVE_THRESHOLD 32 | }; 33 | 34 | /** 35 | * @brief The auxiliary output control status 36 | */ 37 | enum class OutputControl 38 | { 39 | NOT_SET = -1, 40 | DEFAULT_LOW, 41 | DEFAULT_HIGH, 42 | }; 43 | 44 | /** 45 | * @brief The status of the auto-thresholds routine 46 | */ 47 | enum class AutoStatus 48 | { 49 | NOT_SET = -1, 50 | NOT_IN_PROGRESS, 51 | IN_PROGRESS, 52 | COMPLETED 53 | }; 54 | 55 | class MyLD2410 56 | { 57 | public: 58 | enum Response 59 | { 60 | FAIL = 0, 61 | ACK, 62 | DATA 63 | }; 64 | struct ValuesArray 65 | { 66 | byte values[9]; 67 | byte N = 0; 68 | 69 | void setN(byte n) 70 | { 71 | N = (n <= 8) ? n : 8; 72 | } 73 | ValuesArray &operator=(const ValuesArray &other) 74 | { 75 | if (this != &other) 76 | { 77 | N = other.N; 78 | for (byte i = 0; i <= N; i++) 79 | values[i] = other.values[i]; 80 | } 81 | return *this; 82 | } 83 | template 84 | void forEach(ByteHandler func) const 85 | { 86 | for (byte i = 0; i <= N; i++) 87 | func(values[i]); 88 | } 89 | }; 90 | struct SensorData 91 | { 92 | byte status; 93 | unsigned long timestamp; 94 | unsigned long mTargetDistance; 95 | byte mTargetSignal; 96 | unsigned long sTargetDistance; 97 | byte sTargetSignal; 98 | unsigned long distance; 99 | // Enhanced data 100 | ValuesArray mTargetSignals; 101 | ValuesArray sTargetSignals; 102 | }; 103 | 104 | private: 105 | SensorData sData; 106 | ValuesArray stationaryThresholds; 107 | ValuesArray movingThresholds; 108 | byte maxRange = 0; 109 | byte noOne_window = 0; 110 | byte lightLevel = 0; 111 | byte outLevel = 0; 112 | byte lightThreshold = 0; 113 | LightControl lightControl = LightControl::NOT_SET; 114 | OutputControl outputControl = OutputControl::NOT_SET; 115 | AutoStatus autoStatus = AutoStatus::NOT_SET; 116 | unsigned long version = 0; 117 | unsigned long bufferSize = 0; 118 | unsigned long dataFrames = 0; 119 | byte MAC[6]; 120 | String MACstr = ""; 121 | String firmware = ""; 122 | byte firmwareMajor = 0; 123 | byte firmwareMinor = 0; 124 | int fineRes = -1; 125 | bool isEnhanced = false; 126 | bool isConfig = false; 127 | byte inBuf[LD2410_BUFFER_SIZE]; 128 | byte inBufI = 0; 129 | byte headBuf[4]; 130 | byte headBufI = 0; 131 | Stream *sensor; 132 | bool _debug = false; 133 | bool isDataValid(); 134 | bool readFrame(); 135 | bool sendCommand(const byte *command); 136 | bool processAck(); 137 | bool processData(); 138 | 139 | public: 140 | /** 141 | * @brief Construct a new MyLD2410 object 142 | * 143 | * @param serial - a reference to a stream object (sensorSerial) 144 | * @param debug - a flag that controls whether debug data will be sent to Serial 145 | */ 146 | MyLD2410(Stream &serial, bool debug = false); 147 | 148 | // CONTROLS 149 | 150 | /** 151 | * @brief Call this function in setup() to ascertain whether the device is responding 152 | */ 153 | bool begin(); 154 | 155 | /** 156 | * @brief Call this function to gracefully close the sensor. Useful for entering sleep mode. 157 | */ 158 | void end(); 159 | 160 | /** 161 | * @brief Set the debug flag 162 | * 163 | */ 164 | void debugOn(); 165 | 166 | /** 167 | * @brief Reset the debug flag 168 | * 169 | */ 170 | void debugOff(); 171 | 172 | /** 173 | @brief Call this function in the main loop 174 | @return MyLD2410::DATA = (evaluates to true) if the latest frame contained data 175 | @return MyLD2410::ACK = (evaluates to true) if the latest frame contained a reply to a command 176 | @return MyLD2410::FAIL = (evaluates to false) if no useful info was processed 177 | */ 178 | Response check(); 179 | 180 | // GETTERS 181 | 182 | /** 183 | * @brief Check whether the device is in config mode 184 | * (accepts commands) 185 | */ 186 | bool inConfigMode(); 187 | 188 | /** 189 | * @brief Check whether the device is in basic mode 190 | * (continuously sends basic presence data) 191 | */ 192 | bool inBasicMode(); 193 | 194 | /** 195 | * @brief Check whether the device is in enhanced mode 196 | * (continuously sends enhanced presence data) 197 | */ 198 | bool inEnhancedMode(); 199 | 200 | /** 201 | * @brief Get the status of the sensor: 202 | * 0 - No presence; 203 | * 1 - Moving only; 204 | * 2 - Stationary only; 205 | * 3 - Both moving and stationary; 206 | * 4 - Auto thresholds in progress; 207 | * 5 - Auto thresholds successful; 208 | * 6 - Auto thresholds failed; 209 | * 255 - The sensor status is invalid 210 | * 211 | * @return byte 212 | */ 213 | byte getStatus(); 214 | 215 | /** 216 | * @brief Get the presence status as a c-string 217 | * 218 | * @return const char* : 219 | * "No target", 220 | * "Moving only", 221 | * "Stationary only", 222 | * "Both moving and stationary", 223 | * "Auto thresholds in progress", 224 | * "Auto thresholds successful", 225 | * "Auto thresholds failed". 226 | */ 227 | const char *statusString(); 228 | 229 | /** 230 | * @brief Get the time (in milliseconds) of the last successfully received data frame 231 | */ 232 | unsigned long getTimestamp(); 233 | 234 | /** 235 | * @brief Get the number of data frames received so far 236 | * 237 | * @return unsigned long 238 | */ 239 | unsigned long getFrameCount(); 240 | 241 | /** 242 | * @brief Check whether presence was detected in the latest frame 243 | */ 244 | bool presenceDetected(); 245 | 246 | /** 247 | * @brief Check whether a stationary target was detected in the latest frame 248 | */ 249 | bool stationaryTargetDetected(); 250 | 251 | /** 252 | * @brief Get the distance to the stationary target in [cm] 253 | * 254 | * @return unsigned long - distance in [cm] 255 | */ 256 | unsigned long stationaryTargetDistance(); 257 | 258 | /** 259 | * @brief Get the signal from the stationary target 260 | * 261 | * @return byte - signal value [0 - 100] 262 | */ 263 | byte stationaryTargetSignal(); 264 | 265 | /** 266 | * @brief Get the Stationary Signals object, if in enhanced mode 267 | * 268 | * @return const MyLD2410::ValuesArray& - the signals for each detection gate 269 | */ 270 | const ValuesArray &getStationarySignals(); 271 | 272 | /** 273 | * @brief Check whether a moving target was detected in the latest frame 274 | */ 275 | bool movingTargetDetected(); 276 | 277 | /** 278 | * @brief Get the distance to the moving target in [cm] 279 | * 280 | * @return unsigned long - distance in [cm] 281 | */ 282 | unsigned long movingTargetDistance(); 283 | 284 | /** 285 | * @brief Get the signal from the moving target 286 | * 287 | * @return byte - signal value [0 - 100] 288 | */ 289 | byte movingTargetSignal(); 290 | 291 | /** 292 | * @brief Get the Moving Signals object, if in enhanced mode 293 | * 294 | * @return const MyLD2410::ValuesArray& - the signals for each detection gate 295 | */ 296 | const ValuesArray &getMovingSignals(); 297 | 298 | /** 299 | * @brief Get the detected distance 300 | * 301 | * @return unsigned long - distance in [cm] 302 | */ 303 | unsigned long detectedDistance(); 304 | 305 | /** 306 | * @brief Get the Bluetooth MAC address as an array byte[6] 307 | * 308 | * @return const byte* 309 | */ 310 | const byte *getMAC(); 311 | 312 | /** 313 | * @brief Get the Bluetooth MAC address as a String 314 | * 315 | * @return String 316 | */ 317 | String getMACstr(); 318 | 319 | /** 320 | * @brief Get the Firmware as a String 321 | * 322 | * @return String 323 | */ 324 | String getFirmware(); 325 | 326 | /** 327 | * @brief Get the Firmware Major 328 | * 329 | * @return byte 330 | */ 331 | byte getFirmwareMajor(); 332 | 333 | /** 334 | * @brief Get the Firmware Minor 335 | * 336 | * @return byte 337 | */ 338 | byte getFirmwareMinor(); 339 | 340 | /** 341 | * @brief Get the protocol version 342 | * 343 | * @return unsigned long 344 | */ 345 | unsigned long getVersion(); 346 | 347 | /** 348 | * @brief Get the SensorData object 349 | * 350 | * @return const SensorData& 351 | */ 352 | const SensorData &getSensorData(); 353 | 354 | /** 355 | * @brief Get the sensor resolution (gate-width) in [cm] 356 | * 357 | * @return byte either 20 or 75 on success, 0 on failure 358 | */ 359 | byte getResolution(); 360 | 361 | // parameters 362 | 363 | /** 364 | * @brief Get the detection thresholds for moving targets 365 | * 366 | * @return const ValuesArray& 367 | */ 368 | const ValuesArray &getMovingThresholds(); 369 | 370 | /** 371 | * @brief Get the detection thresholds for stationary targets 372 | * 373 | * @return const ValuesArray& 374 | */ 375 | const ValuesArray &getStationaryThresholds(); 376 | 377 | /** 378 | * @brief Get the maximum detection gate 379 | * 380 | * @return byte 381 | */ 382 | byte getRange(); 383 | 384 | /** 385 | * @brief Get the maximum detection range in [cm] 386 | * 387 | * @return unsigned long 388 | */ 389 | unsigned long getRange_cm(); 390 | 391 | /** 392 | * @brief Get the time-lag of "no presence" in [s]. 393 | * The sensor begins reporting "no presence" 394 | * only after no motion has been detected for that many seconds. 395 | * 396 | * @return byte 397 | */ 398 | byte getNoOneWindow(); 399 | // end parameters 400 | 401 | // REQUESTS 402 | 403 | /** 404 | * @brief Request config mode 405 | * 406 | * @param enable [true]/false 407 | * @return true on success 408 | */ 409 | bool configMode(bool enable = true); 410 | 411 | /** 412 | * @brief Request enhanced mode 413 | * 414 | * @param enable [true]/false 415 | * @return true on success 416 | */ 417 | bool enhancedMode(bool enable = true); 418 | 419 | /** 420 | * @brief Request the current auxiliary configuration 421 | * 422 | * @return true on success 423 | */ 424 | bool requestAuxConfig(); 425 | 426 | /** 427 | * @brief Begin the automatic threshold detection routine 428 | * (firmware >= 2.44) 429 | * 430 | * @param _timeout - allow for timeout [s] to leave the room 431 | * @return true on success 432 | */ 433 | bool autoThresholds(byte _timeout = 10); 434 | 435 | /** 436 | * @brief Get the status of the automatic threshold detection routine 437 | * (firmware >= 2.44) 438 | * 439 | * @return AutoStatus 440 | */ 441 | AutoStatus getAutoStatus(); 442 | 443 | /** 444 | * @brief Request the Bluetooth MAC address 445 | * 446 | * @return true on success 447 | */ 448 | bool requestMAC(); 449 | 450 | /** 451 | * @brief Request the Firmware 452 | * 453 | * @return true on success 454 | */ 455 | bool requestFirmware(); 456 | 457 | /** 458 | * @brief Request the resolution (gate-width) 459 | * 460 | * @return true on success 461 | */ 462 | bool requestResolution(); 463 | 464 | /** 465 | * @brief Set the resolution of the sensor 466 | * 467 | * @param fine true=20cm; [false]=75cm 468 | * @return true on success 469 | */ 470 | bool setResolution(bool fine = false); 471 | 472 | /** 473 | * @brief Request the sensor parameters: 474 | * range, motion thresholds, stationary thresholds, no-one window 475 | * 476 | * @return true on success 477 | */ 478 | bool requestParameters(); 479 | 480 | /** 481 | * @brief Set the gate parameters for a particular gate, or for all gates at once 482 | * 483 | * @param gate the gate to configure; 484 | * pass a value greater than 8 (e.g 0xFF) to apply the same thresholds to all gates 485 | * @param movingThreshold [0 - 100] 486 | * @param stationaryThreshold [0 - 100] 487 | * @return true on success 488 | */ 489 | bool setGateParameters(byte gate, byte movingThreshold, byte stationaryThreshold); 490 | 491 | /** 492 | * @brief Set the moving target threshold for a particular gate 493 | * 494 | * @param gate the gate to configure [0 - 8] 495 | * @param movingThreshold [0 - 100] 496 | * @return true on success 497 | */ 498 | bool setMovingThreshold(byte gate, byte movingThreshold); 499 | 500 | /** 501 | * @brief Set the stationary target threshold for a particular gate 502 | * 503 | * @param gate the gate to configure [0 - 8] 504 | * @param stationaryhreshold [0 - 100] 505 | * @return true on success 506 | */ 507 | bool setStationaryThreshold(byte gate, byte stationaryThreshold); 508 | 509 | /** 510 | * @brief Set the parameters for all gates at once, as well as the no-one window 511 | * 512 | * @param moving_thresholds as a ValueArray 513 | * @param stationary_thresholds as a ValueArray 514 | * @param noOneWindow 515 | * @return true on success 516 | */ 517 | bool 518 | setGateParameters(const ValuesArray &moving_thresholds, const ValuesArray &stationary_thresholds, byte noOneWindow = 5); 519 | 520 | /** 521 | * @brief Set the detection range for moving targets, stationary targets, as well as the no-one window 522 | * 523 | * @param movingGate 524 | * @param stationaryGate 525 | * @param noOneWindow 526 | * @return true on success 527 | */ 528 | bool setMaxGate(byte movingGate, byte stationaryGate, byte noOneWindow = 5); 529 | 530 | /** 531 | * @brief Set the no-one window parameter 532 | * 533 | * @param noOneWindow in [s] 534 | * @return true on success 535 | */ 536 | bool setNoOneWindow(byte noOneWindow); 537 | 538 | /** 539 | * @brief Set the maximum moving gate 540 | * 541 | * @param movingGate 542 | * @return true on success 543 | */ 544 | bool setMaxMovingGate(byte movingGate); 545 | 546 | /** 547 | * @brief Set the maximum stationary gate 548 | * 549 | * @param stationaryGate 550 | * @return true on success 551 | */ 552 | bool setMaxStationaryGate(byte stationaryGate); 553 | 554 | /** 555 | * @brief Get the maximum moving gate 556 | * 557 | * @return the maximum moving-target gate 558 | */ 559 | byte getMaxMovingGate(); 560 | 561 | /** 562 | * @brief Get the maximum stationary gate 563 | * 564 | * @return the maximum stationary-target gate 565 | */ 566 | byte getMaxStationaryGate(); 567 | 568 | /** 569 | * @brief Request reset to factory default parameters 570 | * 571 | * @return true on success 572 | */ 573 | bool requestReset(); 574 | 575 | /** 576 | * @brief Request reboot 577 | * 578 | * @return true on success 579 | */ 580 | bool requestReboot(); 581 | 582 | /** 583 | * @brief Turn Bluetooth ON 584 | * 585 | * @return true on success 586 | */ 587 | bool requestBTon(); 588 | 589 | /** 590 | * @brief Turn Bluetooth OFF 591 | * 592 | * @return true on success 593 | */ 594 | bool requestBToff(); 595 | 596 | /** 597 | * @brief Set a new BT password. 598 | * 599 | * The BT password must be 6 characters long. If the string is shorter, it will be padded with spaces '\20'. If it is longer, only the first 6 characters will be used. 600 | * 601 | * @param passwd c-string 602 | * @return true on success 603 | */ 604 | bool setBTpassword(const char *passwd); 605 | 606 | /** 607 | * @brief Set a new BT password. 608 | * 609 | * The BT password must be 6 characters long. If the string is shorter, it will be padded with spaces '\20'. If it is longer, only the first 6 characters will be used. 610 | * 611 | * @param passwd Arduino String 612 | * @return true on success 613 | */ 614 | bool setBTpassword(const String &passwd); 615 | 616 | /** 617 | * @brief Reset the BT password 618 | * 619 | * @return true on success 620 | */ 621 | bool resetBTpassword(); 622 | 623 | /** 624 | * @brief Reset the serial baud rate. The sensor reboots at the new rate on success 625 | * 626 | * @return true on success 627 | */ 628 | bool setBaud(byte baud); 629 | 630 | /** 631 | * @brief Get the Light Level 632 | * 633 | * @return byte 634 | */ 635 | byte getLightLevel(); 636 | 637 | /** 638 | * @brief Get the Light Control parameter 639 | * 640 | * @return LightControl enum 641 | */ 642 | LightControl getLightControl(); 643 | 644 | /** 645 | * @brief Set the Auxiliary Control parameters 646 | * 647 | * @param light_control 648 | * @param light_threshold 649 | * @param output_control 650 | * 651 | * @return true on success 652 | */ 653 | bool setAuxControl(LightControl light_control, byte light_threshold, OutputControl output_control); 654 | 655 | /** 656 | * @brief Reset the Auxiliary Control parameters to their default values 657 | * 658 | * @return true on success 659 | */ 660 | bool resetAuxControl(); 661 | 662 | /** 663 | * @brief Get the Light Threshold 664 | * 665 | * @return byte 666 | */ 667 | byte getLightThreshold(); 668 | 669 | /** 670 | * @brief Get the Output Control parameter 671 | * 672 | * @return OutputControl enum 673 | */ 674 | OutputControl getOutputControl(); 675 | 676 | /** 677 | * @brief Get the Light Level 678 | * 679 | * @return byte 680 | */ 681 | byte getOutLevel(); 682 | }; 683 | 684 | #endif // MY_LD2410_H 685 | -------------------------------------------------------------------------------- /src/MyLD2410.cpp: -------------------------------------------------------------------------------- 1 | #include "MyLD2410.h" 2 | 3 | /*** BEGIN LD2410 namespace ***/ 4 | namespace LD2410 5 | { 6 | const char *tStatus[7]{ 7 | "No target", 8 | "Moving only", 9 | "Stationary only", 10 | "Both moving and stationary", 11 | "Auto thresholds in progress", 12 | "Auto thresholds successful", 13 | "Auto thresholds failed"}; 14 | const byte headData[4]{0xF4, 0xF3, 0xF2, 0xF1}; 15 | const byte tailData[4]{0xF8, 0xF7, 0xF6, 0xF5}; 16 | const byte headConfig[4]{0xFD, 0xFC, 0xFB, 0xFA}; 17 | const byte tailConfig[4]{4, 3, 2, 1}; 18 | const byte configEnable[6]{4, 0, 0xFF, 0, 1, 0}; 19 | const byte configDisable[4]{2, 0, 0xFE, 0}; 20 | const byte MAC[6]{4, 0, 0xA5, 0, 1, 0}; 21 | const byte firmware[4]{2, 0, 0xA0, 0}; 22 | const byte res[4]{2, 0, 0xAB, 0}; 23 | const byte resCoarse[6]{4, 0, 0xAA, 0, 0, 0}; 24 | const byte resFine[6]{4, 0, 0xAA, 0, 1, 0}; 25 | const byte changeBaud[6]{4, 0, 0xA1, 0, 7, 0}; 26 | const byte reset[4]{2, 0, 0xA2, 0}; 27 | const byte reboot[4]{2, 0, 0xA3, 0}; 28 | const byte BTon[6]{4, 0, 0xA4, 0, 1, 0}; 29 | const byte BToff[6]{4, 0, 0xA4, 0, 0, 0}; 30 | const byte BTpasswd[10]{8, 0, 0xA9, 0, 0x48, 0x69, 0x4C, 0x69, 0x6E, 0x6B}; 31 | const byte param[4]{2, 0, 0x61, 0}; 32 | const byte engOn[4]{2, 0, 0x62, 0}; 33 | const byte engOff[4]{2, 0, 0x63, 0}; 34 | const byte auxQuery[4]{2, 0, 0xAE, 0}; 35 | const byte auxConfig[8]{6, 0, 0xAD, 0, 0, 0x80, 0, 0}; 36 | const byte autoBegin[6]{4, 0, 0x0B, 0, 0x0A, 0}; 37 | const byte autoQuery[4]{2, 0, 0x1B, 0}; 38 | byte gateParam[0x16]{0x14, 0, 0x64, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0}; 39 | byte maxGate[0x16]{0x14, 0, 0x60, 0, 0, 0, 8, 0, 0, 0, 1, 0, 8, 0, 0, 0, 2, 0, 5, 0, 0, 0}; 40 | 41 | String byte2hex(byte b, bool addZero = true) 42 | { 43 | String bStr(b, HEX); 44 | bStr.toUpperCase(); 45 | if (addZero && (bStr.length() == 1)) 46 | return "0" + bStr; 47 | return bStr; 48 | } 49 | void printBuf(const byte *buf, byte size) 50 | { 51 | for (byte i = 0; i < size; i++) 52 | { 53 | Serial.print(byte2hex(buf[i])); 54 | Serial.print(' '); 55 | } 56 | Serial.println(); 57 | Serial.flush(); 58 | } 59 | bool bufferEndsWith(const byte *buf, int iMax, const byte *other) 60 | { 61 | for (int j = 3; j >= 0; j--) 62 | { 63 | if (--iMax < 0) 64 | iMax = 3; 65 | if (buf[iMax] != other[j]) 66 | return false; 67 | } 68 | return true; 69 | } 70 | } 71 | /*** END LD2410 namespace ***/ 72 | 73 | MyLD2410::Response MyLD2410::check() 74 | { 75 | while (sensor->available()) 76 | { 77 | headBuf[headBufI++] = byte(sensor->read()); 78 | headBufI %= 4; 79 | if (LD2410::bufferEndsWith(headBuf, headBufI, LD2410::headConfig) && processAck()) 80 | return ACK; 81 | if (LD2410::bufferEndsWith(headBuf, headBufI, LD2410::headData) && processData()) 82 | return DATA; 83 | } 84 | return FAIL; 85 | } 86 | 87 | bool MyLD2410::sendCommand(const byte *command) 88 | { 89 | byte size = command[0] + 2; 90 | // LD2410::printBuf(command, size); 91 | sensor->write(LD2410::headConfig, 4); 92 | sensor->write(command, size); 93 | sensor->write(LD2410::tailConfig, 4); 94 | sensor->flush(); 95 | unsigned long giveUp = millis() + 2000UL; 96 | while (millis() < giveUp) 97 | { 98 | while (sensor->available()) 99 | { 100 | headBuf[headBufI++] = byte(sensor->read()); 101 | headBufI %= 4; 102 | if (LD2410::bufferEndsWith(headBuf, headBufI, LD2410::headConfig)) 103 | return processAck(); 104 | } 105 | } 106 | return false; 107 | } 108 | 109 | bool MyLD2410::readFrame() 110 | { 111 | int frameSize = -1, bytes = 2; 112 | inBufI = 0; 113 | unsigned long frameTimeout = millis() + 100; 114 | while (bytes) // read two bytes for frame size 115 | { 116 | 117 | if (sensor->available()) 118 | { 119 | inBuf[inBufI++] = byte(sensor->read()); 120 | bytes--; 121 | } 122 | else if (millis() > frameTimeout) 123 | return false; // timeout 124 | } 125 | 126 | frameSize = (inBuf[0]) | (inBuf[1] << 8); 127 | 128 | if (frameSize <= 0) 129 | return false; // Corrupted frame received 130 | frameSize += 4; 131 | if (frameSize > LD2410_BUFFER_SIZE) 132 | return false; // Frame too large, discard 133 | 134 | inBufI = 0; 135 | frameTimeout = millis() + 100; 136 | while (frameSize > 0) // read the rest of the frame 137 | { 138 | if (sensor->available()) 139 | { 140 | inBuf[inBufI++] = byte(sensor->read()); 141 | frameSize--; 142 | } 143 | else if (millis() > frameTimeout) 144 | return false; // timeout 145 | } 146 | return true; 147 | } 148 | 149 | bool MyLD2410::processAck() 150 | { 151 | if (!readFrame()) 152 | return false; 153 | if (_debug) 154 | LD2410::printBuf(inBuf, inBufI); 155 | if (!LD2410::bufferEndsWith(inBuf, inBufI, LD2410::tailConfig)) 156 | return false; 157 | unsigned long command = inBuf[0] | (inBuf[1] << 8); 158 | if (inBuf[2] | (inBuf[3] << 8)) 159 | return false; 160 | switch (command) 161 | { 162 | case 0x1FF: // entered config mode 163 | isConfig = true; 164 | version = inBuf[4] | (inBuf[5] << 8); 165 | bufferSize = inBuf[6] | (inBuf[7] << 8); 166 | break; 167 | case 0x1FE: // exited config mode 168 | isConfig = false; 169 | break; 170 | case 0x1A5: // MAC 171 | for (int i = 0; i < 6; i++) 172 | MAC[i] = inBuf[i + 4]; 173 | MACstr = LD2410::byte2hex(MAC[0]); 174 | for (int i = 1; i < 6; i++) 175 | MACstr += ":" + LD2410::byte2hex(MAC[i]); 176 | break; 177 | case 0x1A0: // Firmware 178 | firmware = LD2410::byte2hex(inBuf[7], false); 179 | firmware += "." + LD2410::byte2hex(inBuf[6]); 180 | firmware += "." + LD2410::byte2hex(inBuf[11]); 181 | firmware += LD2410::byte2hex(inBuf[10]); 182 | firmware += LD2410::byte2hex(inBuf[9]); 183 | firmware += LD2410::byte2hex(inBuf[8]); 184 | firmwareMajor = inBuf[7]; 185 | firmwareMinor = inBuf[6]; 186 | break; 187 | case 0x1AB: // Query Resolution 188 | fineRes = (inBuf[4]); 189 | break; 190 | case 0x1AE: // Query auxiliary control parameters 191 | lightControl = LightControl(inBuf[4]); 192 | lightThreshold = inBuf[5]; 193 | outputControl = OutputControl(inBuf[6]); 194 | break; 195 | case 0x11B: 196 | autoStatus = AutoStatus(inBuf[4]); 197 | break; 198 | case 0x1A3: // Reboot 199 | isEnhanced = false; 200 | isConfig = false; 201 | break; 202 | case 0x161: // Query parameters 203 | maxRange = inBuf[5]; 204 | movingThresholds.setN(inBuf[6]); 205 | stationaryThresholds.setN(inBuf[7]); 206 | for (byte i = 0; i <= movingThresholds.N; i++) 207 | movingThresholds.values[i] = inBuf[8 + i]; 208 | for (byte i = 0; i <= stationaryThresholds.N; i++) 209 | stationaryThresholds.values[i] = inBuf[17 + i]; 210 | noOne_window = inBuf[26] | (inBuf[27] << 8); 211 | break; 212 | case 0x162: 213 | isEnhanced = true; 214 | break; 215 | case 0x163: 216 | isEnhanced = false; 217 | break; 218 | case 0x164: 219 | if (LD2410::gateParam[7] == 0xFF) 220 | LD2410::gateParam[7] = 0; 221 | } 222 | return (true); 223 | } 224 | 225 | bool MyLD2410::processData() 226 | { 227 | if (!readFrame()) 228 | return false; 229 | unsigned long now = millis(); 230 | if (_debug) 231 | { 232 | Serial.print('#'); 233 | Serial.print(dataFrames + 1); 234 | Serial.print(" ["); 235 | Serial.print(now); 236 | Serial.print("ms] : "); 237 | LD2410::printBuf(inBuf, inBufI); 238 | } 239 | if (!LD2410::bufferEndsWith(inBuf, inBufI, LD2410::tailData)) 240 | return false; 241 | if (((inBuf[0] == 1) || (inBuf[0] == 2)) && (inBuf[1] == 0xAA)) 242 | { // Basic mode and Enhanced 243 | ++dataFrames; 244 | sData.timestamp = now; 245 | sData.status = inBuf[2] & 7; 246 | sData.mTargetDistance = inBuf[3] | (inBuf[4] << 8); 247 | sData.mTargetSignal = inBuf[5]; 248 | sData.sTargetDistance = inBuf[6] | (inBuf[7] << 8); 249 | sData.sTargetSignal = inBuf[8]; 250 | sData.distance = inBuf[9] | (inBuf[10] << 8); 251 | if (inBuf[0] == 1) 252 | { // Enhanced mode only 253 | isEnhanced = true; 254 | sData.mTargetSignals.setN(inBuf[11]); 255 | sData.sTargetSignals.setN(inBuf[12]); 256 | byte *p = inBuf + 13; 257 | for (byte i = 0; i <= sData.mTargetSignals.N; i++) 258 | sData.mTargetSignals.values[i] = *(p++); 259 | for (byte i = 0; i <= sData.sTargetSignals.N; i++) 260 | sData.sTargetSignals.values[i] = *(p++); 261 | lightLevel = *(p++); 262 | outLevel = *p; 263 | } 264 | else 265 | { // Basic mode only 266 | isEnhanced = false; 267 | sData.mTargetSignals.setN(0); 268 | sData.sTargetSignals.setN(0); 269 | lightLevel = 0; 270 | outLevel = 0; 271 | } 272 | } 273 | else 274 | return false; 275 | return true; 276 | } 277 | 278 | /** 279 | @brief Construct from a serial stream object 280 | */ 281 | MyLD2410::MyLD2410(Stream &serial, bool debug) 282 | { 283 | sensor = &serial; 284 | _debug = debug; 285 | } 286 | 287 | bool MyLD2410::begin() 288 | { 289 | // Wait for the sensor to come online, or to timeout. 290 | unsigned long giveUp = millis() + 2000UL; 291 | bool online = false; 292 | isConfig = false; 293 | sendCommand(LD2410::configDisable); 294 | while (millis() < giveUp) 295 | { 296 | if (check()) 297 | { 298 | online = true; 299 | break; 300 | } 301 | delay(110); 302 | } 303 | return online; 304 | } 305 | 306 | void MyLD2410::end() 307 | { 308 | isConfig = false; 309 | isEnhanced = false; 310 | } 311 | 312 | void MyLD2410::debugOn() 313 | { 314 | _debug = true; 315 | } 316 | 317 | void MyLD2410::debugOff() 318 | { 319 | _debug = false; 320 | } 321 | 322 | bool MyLD2410::inConfigMode() 323 | { 324 | return isConfig; 325 | } 326 | 327 | bool MyLD2410::inBasicMode() 328 | { 329 | return !isEnhanced; 330 | } 331 | 332 | bool MyLD2410::inEnhancedMode() 333 | { 334 | return isEnhanced; 335 | } 336 | 337 | byte MyLD2410::getStatus() 338 | { 339 | return (isDataValid()) ? sData.status : 0xFF; 340 | } 341 | 342 | const char *MyLD2410::statusString() 343 | { 344 | return LD2410::tStatus[sData.status]; 345 | } 346 | 347 | unsigned long MyLD2410::getTimestamp() 348 | { 349 | return sData.timestamp; 350 | } 351 | 352 | unsigned long MyLD2410::getFrameCount() 353 | { 354 | return dataFrames; 355 | } 356 | 357 | bool MyLD2410::isDataValid() 358 | { 359 | return (millis() < sData.timestamp + 500UL); 360 | } 361 | 362 | bool MyLD2410::presenceDetected() 363 | { 364 | return isDataValid() && (sData.status) && (sData.status < 4); // 1,2,3 365 | } 366 | 367 | bool MyLD2410::stationaryTargetDetected() 368 | { 369 | return isDataValid() && ((sData.status == 2) || (sData.status == 3)); // 2,3 370 | } 371 | 372 | unsigned long MyLD2410::stationaryTargetDistance() 373 | { 374 | return sData.sTargetDistance; 375 | } 376 | 377 | byte MyLD2410::stationaryTargetSignal() 378 | { 379 | return sData.sTargetSignal; 380 | } 381 | 382 | const MyLD2410::ValuesArray &MyLD2410::getStationarySignals() 383 | { 384 | return sData.sTargetSignals; 385 | } 386 | 387 | bool MyLD2410::movingTargetDetected() 388 | { 389 | return isDataValid() && ((sData.status == 1) || (sData.status == 3)); // 1,3 390 | } 391 | 392 | unsigned long MyLD2410::movingTargetDistance() 393 | { 394 | return sData.mTargetDistance; 395 | } 396 | 397 | byte MyLD2410::movingTargetSignal() 398 | { 399 | return sData.mTargetSignal; 400 | } 401 | 402 | const MyLD2410::ValuesArray &MyLD2410::getMovingSignals() 403 | { 404 | return sData.mTargetSignals; 405 | } 406 | 407 | unsigned long MyLD2410::detectedDistance() 408 | { 409 | return sData.distance; 410 | } 411 | 412 | const byte *MyLD2410::getMAC() 413 | { 414 | if (MACstr.length() == 0) 415 | requestMAC(); 416 | return MAC; 417 | } 418 | 419 | String MyLD2410::getMACstr() 420 | { 421 | if (MACstr.length() == 0) 422 | requestMAC(); 423 | return MACstr; 424 | } 425 | 426 | String MyLD2410::getFirmware() 427 | { 428 | if (firmware.length() == 0) 429 | requestFirmware(); 430 | return firmware; 431 | } 432 | 433 | byte MyLD2410::getFirmwareMajor() 434 | { 435 | if (!firmwareMajor) 436 | requestFirmware(); 437 | return firmwareMajor; 438 | } 439 | 440 | byte MyLD2410::getFirmwareMinor() 441 | { 442 | if (!firmwareMajor) 443 | requestFirmware(); 444 | return firmwareMinor; 445 | } 446 | 447 | unsigned long MyLD2410::getVersion() 448 | { 449 | if (version == 0) 450 | { 451 | configMode(); 452 | configMode(false); 453 | } 454 | return version; 455 | } 456 | 457 | const MyLD2410::SensorData &MyLD2410::getSensorData() 458 | { 459 | return sData; 460 | } 461 | 462 | const MyLD2410::ValuesArray &MyLD2410::getMovingThresholds() 463 | { 464 | if (!maxRange) 465 | requestParameters(); 466 | return movingThresholds; 467 | } 468 | 469 | const MyLD2410::ValuesArray &MyLD2410::getStationaryThresholds() 470 | { 471 | if (!maxRange) 472 | requestParameters(); 473 | return stationaryThresholds; 474 | } 475 | 476 | byte MyLD2410::getRange() 477 | { 478 | if (!maxRange) 479 | requestParameters(); 480 | return maxRange; 481 | } 482 | 483 | unsigned long MyLD2410::getRange_cm() 484 | { 485 | return (getRange() + 1) * getResolution(); 486 | } 487 | 488 | byte MyLD2410::getNoOneWindow() 489 | { 490 | if (!maxRange) 491 | requestParameters(); 492 | return noOne_window; 493 | } 494 | 495 | bool MyLD2410::configMode(bool enable) 496 | { 497 | if (enable && !isConfig) 498 | return sendCommand(LD2410::configEnable); 499 | if (!enable && isConfig) 500 | return sendCommand(LD2410::configDisable); 501 | return false; 502 | } 503 | 504 | bool MyLD2410::enhancedMode(bool enable) 505 | { 506 | if (isConfig) 507 | return sendCommand(((enable) ? LD2410::engOn : LD2410::engOff)); 508 | else 509 | return configMode() && sendCommand(((enable) ? LD2410::engOn : LD2410::engOff)) && configMode(false); 510 | } 511 | 512 | bool MyLD2410::requestAuxConfig() 513 | { 514 | if (isConfig) 515 | return sendCommand(LD2410::auxQuery); 516 | return configMode() && sendCommand(LD2410::auxQuery) && configMode(false); 517 | } 518 | 519 | bool MyLD2410::autoThresholds(byte _timeout) 520 | { 521 | byte cmd[6]; 522 | memcpy(cmd, LD2410::autoBegin, 6); 523 | if (_timeout) 524 | cmd[4] = _timeout; 525 | if (isConfig) 526 | return sendCommand(cmd); 527 | return configMode() && sendCommand(cmd) && configMode(false); 528 | } 529 | 530 | AutoStatus MyLD2410::getAutoStatus() 531 | { 532 | bool res = false; 533 | if (isConfig) 534 | res = sendCommand(LD2410::autoQuery); 535 | else 536 | res = configMode() && sendCommand(LD2410::autoQuery) && configMode(false); 537 | if (res) 538 | return autoStatus; 539 | return AutoStatus::NOT_SET; 540 | } 541 | 542 | bool MyLD2410::requestMAC() 543 | { 544 | if (isConfig) 545 | return sendCommand(LD2410::MAC); 546 | return configMode() && sendCommand(LD2410::MAC) && configMode(false); 547 | } 548 | 549 | bool MyLD2410::requestFirmware() 550 | { 551 | if (isConfig) 552 | return sendCommand(LD2410::firmware); 553 | return configMode() && sendCommand(LD2410::firmware) && configMode(false); 554 | } 555 | 556 | bool MyLD2410::requestResolution() 557 | { 558 | if (isConfig) 559 | return sendCommand(LD2410::res); 560 | return configMode() && sendCommand(LD2410::res) && configMode(false); 561 | } 562 | 563 | bool MyLD2410::setResolution(bool fine) 564 | { 565 | if (isConfig && sendCommand(((fine) ? LD2410::resFine : LD2410::resCoarse))) 566 | return sendCommand(LD2410::res); 567 | return configMode() && sendCommand(((fine) ? LD2410::resFine : LD2410::resCoarse)) && sendCommand(LD2410::res) && configMode(false); 568 | } 569 | 570 | bool MyLD2410::requestParameters() 571 | { 572 | if (isConfig) 573 | return sendCommand(LD2410::param); 574 | return configMode() && sendCommand(LD2410::param) && configMode(false); 575 | } 576 | 577 | bool MyLD2410::setGateParameters(byte gate, byte movingThreshold, byte stationaryThreshold) 578 | { 579 | if (movingThreshold > 100) 580 | movingThreshold = 100; 581 | if (stationaryThreshold > 100) 582 | stationaryThreshold = 100; 583 | byte *cmd = LD2410::gateParam; 584 | if (gate > 8) 585 | { 586 | cmd[6] = 0xFF; 587 | cmd[7] = 0xFF; 588 | } 589 | else 590 | { 591 | cmd[6] = gate; 592 | cmd[7] = 0; 593 | } 594 | cmd[12] = movingThreshold; 595 | cmd[18] = stationaryThreshold; 596 | if (isConfig) 597 | return sendCommand(cmd) && sendCommand(LD2410::param); 598 | return configMode() && sendCommand(cmd) && sendCommand(LD2410::param) && configMode(false); 599 | } 600 | 601 | bool MyLD2410::setMovingThreshold(byte gate, byte movingThreshold) 602 | { 603 | if (gate > 8) 604 | return false; 605 | if (!stationaryThresholds.N) 606 | requestParameters(); 607 | return setGateParameters(gate, movingThreshold, stationaryThresholds.values[gate]); 608 | } 609 | 610 | bool MyLD2410::setStationaryThreshold(byte gate, byte stationaryThreshold) 611 | { 612 | if (gate > 8) 613 | return false; 614 | if (!movingThresholds.N) 615 | requestParameters(); 616 | return setGateParameters(gate, movingThresholds.values[gate], stationaryThreshold); 617 | } 618 | 619 | bool MyLD2410::setMaxGate(byte movingGate, byte staticGate, byte noOneWindow) 620 | { 621 | if (movingGate > 8) 622 | movingGate = 8; 623 | if (staticGate > 8) 624 | staticGate = 8; 625 | byte *cmd = LD2410::maxGate; 626 | cmd[6] = movingGate; 627 | cmd[12] = staticGate; 628 | cmd[18] = noOneWindow; 629 | if (isConfig && sendCommand(cmd)) 630 | return sendCommand(LD2410::param); 631 | return configMode() && sendCommand(cmd) && sendCommand(LD2410::param) && configMode(false); 632 | } 633 | 634 | bool MyLD2410::setGateParameters( 635 | const ValuesArray &moving_thresholds, 636 | const ValuesArray &stationary_thresholds, 637 | byte noOneWindow) 638 | { 639 | if (!isConfig) 640 | configMode(); 641 | bool success = isConfig; 642 | if (success) 643 | { 644 | for (byte i = 0; i < 9; i++) 645 | { 646 | if (!setGateParameters(i, moving_thresholds.values[i], stationary_thresholds.values[i])) 647 | { 648 | success = false; 649 | break; 650 | } 651 | delay(20); 652 | } 653 | } 654 | return success && setMaxGate(moving_thresholds.N, stationary_thresholds.N, noOneWindow) && configMode(false); 655 | } 656 | 657 | bool MyLD2410::setNoOneWindow(byte noOneWindow) 658 | { 659 | if (!maxRange) 660 | requestParameters(); 661 | if (noOne_window == noOneWindow) 662 | return true; 663 | return setMaxGate(movingThresholds.N, stationaryThresholds.N, noOneWindow); 664 | } 665 | 666 | bool MyLD2410::setMaxMovingGate(byte movingGate) 667 | { 668 | if (!maxRange) 669 | requestParameters(); 670 | if (movingThresholds.N == movingGate) 671 | return true; 672 | if (!noOne_window) 673 | noOne_window = 5; 674 | if (movingGate > 8) 675 | movingGate = 8; 676 | return setMaxGate(movingGate, stationaryThresholds.N, noOne_window); 677 | } 678 | 679 | bool MyLD2410::setMaxStationaryGate(byte stationaryGate) 680 | { 681 | if (!maxRange) 682 | requestParameters(); 683 | if (stationaryThresholds.N == stationaryGate) 684 | return true; 685 | if (!noOne_window) 686 | noOne_window = 5; 687 | if (stationaryGate > 8) 688 | stationaryGate = 8; 689 | return setMaxGate(movingThresholds.N, stationaryGate, noOne_window); 690 | } 691 | 692 | byte MyLD2410::getMaxMovingGate() 693 | { 694 | if (!movingThresholds.N) 695 | requestParameters(); 696 | return movingThresholds.N; 697 | } 698 | 699 | byte MyLD2410::getMaxStationaryGate() 700 | { 701 | if (!stationaryThresholds.N) 702 | requestParameters(); 703 | return stationaryThresholds.N; 704 | } 705 | 706 | bool MyLD2410::requestReset() 707 | { 708 | if (isConfig) 709 | return sendCommand(LD2410::reset) && sendCommand(LD2410::param) && sendCommand(LD2410::res); 710 | return configMode() && sendCommand(LD2410::reset) && sendCommand(LD2410::param) && sendCommand(LD2410::res) && configMode(false); 711 | } 712 | 713 | bool MyLD2410::requestReboot() 714 | { 715 | if (isConfig) 716 | return sendCommand(LD2410::reboot); 717 | return configMode() && sendCommand(LD2410::reboot); 718 | } 719 | 720 | bool MyLD2410::requestBTon() 721 | { 722 | if (isConfig) 723 | return sendCommand(LD2410::BTon); 724 | return configMode() && sendCommand(LD2410::BTon) && configMode(false); 725 | } 726 | 727 | bool MyLD2410::requestBToff() 728 | { 729 | if (isConfig) 730 | return sendCommand(LD2410::BToff); 731 | return configMode() && sendCommand(LD2410::BToff) && configMode(false); 732 | } 733 | 734 | bool MyLD2410::setBTpassword(const char *passwd) 735 | { 736 | byte cmd[10]; 737 | for (unsigned int i = 0; i < 4; i++) 738 | cmd[i] = LD2410::BTpasswd[i]; 739 | 740 | for (unsigned int i = 0; i < 6; i++) 741 | { 742 | if (i < strlen(passwd)) 743 | cmd[4 + i] = byte(passwd[i]); 744 | else 745 | cmd[4 + i] = byte(' '); 746 | } 747 | if (isConfig) 748 | return sendCommand(cmd); 749 | return configMode() && sendCommand(cmd) && configMode(false); 750 | } 751 | 752 | bool MyLD2410::setBTpassword(const String &passwd) 753 | { 754 | return setBTpassword(passwd.c_str()); 755 | } 756 | 757 | bool MyLD2410::resetBTpassword() 758 | { 759 | if (isConfig) 760 | return sendCommand(LD2410::BTpasswd); 761 | return configMode() && sendCommand(LD2410::BTpasswd) && configMode(false); 762 | } 763 | 764 | bool MyLD2410::setBaud(byte baud) 765 | { 766 | if ((baud < 1) || (baud > 8)) 767 | return false; 768 | byte cmd[6]; 769 | memcpy(cmd, LD2410::changeBaud, 6); 770 | cmd[4] = baud; 771 | if (isConfig) 772 | return sendCommand(cmd) && requestReboot(); 773 | return configMode() && sendCommand(cmd) && requestReboot(); 774 | } 775 | 776 | byte MyLD2410::getResolution() 777 | { 778 | if (fineRes >= 0) 779 | return ((fineRes == 1) ? 20 : 75); 780 | if (isConfig) 781 | { 782 | if (sendCommand(LD2410::res)) 783 | return getResolution(); 784 | } 785 | else 786 | { 787 | if (configMode() && sendCommand(LD2410::res) && configMode(false)) 788 | return getResolution(); 789 | } 790 | return 0; 791 | } 792 | 793 | byte MyLD2410::getLightLevel() 794 | { 795 | return lightLevel; 796 | } 797 | 798 | LightControl MyLD2410::getLightControl() 799 | { 800 | if (lightControl == LightControl::NOT_SET) 801 | requestAuxConfig(); 802 | return lightControl; 803 | } 804 | 805 | byte MyLD2410::getLightThreshold() 806 | { 807 | if (lightControl == LightControl::NOT_SET) 808 | requestAuxConfig(); 809 | return lightThreshold; 810 | } 811 | 812 | OutputControl MyLD2410::getOutputControl() 813 | { 814 | if (outputControl == OutputControl::NOT_SET) 815 | requestAuxConfig(); 816 | return outputControl; 817 | } 818 | 819 | bool MyLD2410::setAuxControl( 820 | LightControl light_control, 821 | byte light_threshold, 822 | OutputControl output_control) 823 | { 824 | byte cmd[8]; 825 | memcpy(cmd, LD2410::auxConfig, 8); 826 | cmd[4] = byte(light_control); 827 | cmd[5] = light_threshold; 828 | cmd[6] = byte(output_control); 829 | if (isConfig) 830 | return sendCommand(cmd) && requestAuxConfig(); 831 | return configMode() && sendCommand(cmd) && requestAuxConfig() && configMode(false); 832 | } 833 | 834 | bool MyLD2410::resetAuxControl() 835 | { 836 | if (isConfig) 837 | return sendCommand(LD2410::auxConfig) && requestAuxConfig(); 838 | return configMode() && sendCommand(LD2410::auxConfig) && requestAuxConfig() && configMode(false); 839 | } 840 | 841 | byte MyLD2410::getOutLevel() 842 | { 843 | return outLevel; 844 | } 845 | --------------------------------------------------------------------------------