From 2e9159d3b14ab6e0f60ce7cb390fe1fb718d00e0 Mon Sep 17 00:00:00 2001 From: sen <126383355+screek-workshop@users.noreply.github.com> Date: Sat, 25 Mar 2023 17:38:01 +0800 Subject: [PATCH] sun-light yaml --- .../screek-humen-dectet-1w.yaml | 175 ++++++++ .../screek-mod-components/ld2410/__init__.py | 158 +++++++ .../ld2410/binary_sensor.py | 36 ++ .../screek-mod-components/ld2410/ld2410.cpp | 418 ++++++++++++++++++ .../screek-mod-components/ld2410/ld2410.h | 169 +++++++ .../screek-mod-components/ld2410/sensor.py | 64 +++ 6 files changed, 1020 insertions(+) create mode 100644 1w/yaml/sun-light version/screek-humen-dectet-1w.yaml create mode 100644 1w/yaml/sun-light version/screek-mod-components/ld2410/__init__.py create mode 100644 1w/yaml/sun-light version/screek-mod-components/ld2410/binary_sensor.py create mode 100644 1w/yaml/sun-light version/screek-mod-components/ld2410/ld2410.cpp create mode 100644 1w/yaml/sun-light version/screek-mod-components/ld2410/ld2410.h create mode 100644 1w/yaml/sun-light version/screek-mod-components/ld2410/sensor.py diff --git a/1w/yaml/sun-light version/screek-humen-dectet-1w.yaml b/1w/yaml/sun-light version/screek-humen-dectet-1w.yaml new file mode 100644 index 0000000..aac795d --- /dev/null +++ b/1w/yaml/sun-light version/screek-humen-dectet-1w.yaml @@ -0,0 +1,175 @@ +esphome: + name: screek-humen-dectet-1w + comment: Screek Human Presence Sensor 24GHz PS-HPS + friendly_name: Screek Human Presence Sensor + name_add_mac_suffix: True + platformio_options: + board_build.flash_mode: dio + project: + name: Screek.Human_Presence_Sensor + version: 1W + +external_components: + - source: screek-mod-components + +esp32: + board: esp32-c3-devkitm-1 + +logger: + +api: + +ota: + password: "YOUR_OTA_PASSWORD" + +wifi: + # ssid: !secret wifi_ssid + # password: !secret wifi_password + # fast_connect: True + + power_save_mode: NONE + # output_power: 20dB + # Enable fallback hotspot (captive portal) in case wifi connection fails + ap: + ssid: "SCREEK HUMAN-SENSOR" + +captive_portal: + +web_server: + port: 80 + +binary_sensor: + - platform: status + name: Online + id: ink_ha_connected + - platform: ld2410 + has_target: + name: Presence + has_moving_target: + name: Moving Target + has_still_target: + name: Still Target + +sensor: + - platform: template + id: sys_esp_temperature + name: ESP Temperature + lambda: return temperatureRead(); + unit_of_measurement: °C + device_class: TEMPERATURE + update_interval: 30s + entity_category: "diagnostic" + - platform: uptime + name: Uptime + id: sys_uptime + update_interval: 10s + - platform: wifi_signal + name: RSSI + id: wifi_signal_db + update_interval: 1s + entity_category: "diagnostic" + - platform: template + id: esp_memory + icon: mdi:memory + name: ESP Free Memory + lambda: return heap_caps_get_free_size(MALLOC_CAP_INTERNAL) / 1024; + unit_of_measurement: 'kB' + state_class: measurement + entity_category: "diagnostic" + - platform: ld2410 + moving_distance: + name : Moving Distance + id: moving_distance + still_distance: + name: Still Distance + id: still_distance + moving_energy: + name: Move Energy + still_energy: + name: Still Energy + detection_distance: + name: Detection Distance + light: + name: Sun Light + +light: + - platform: status_led + name: sys_status + pin: GPIO12 + internal: True + restore_mode: ALWAYS_OFF + - platform: status_led + name: sys_status + pin: GPIO13 + internal: True + restore_mode: ALWAYS_OFF + +time: + - platform: sntp + id: time_now + servers: + - ntp.aliyun.com + +uart: + id: uart1 + tx_pin: GPIO5 + rx_pin: GPIO4 + baud_rate: 256000 + parity: NONE + stop_bits: 1 + +ld2410: + timeout: 150s + id: ld2410_radar + # max_move_distance : 6m + # max_still_distance: 0.75m + # g0_move_threshold: 10 + # g0_still_threshold: 20 + # g1_move_threshold: 10 + # g1_still_threshold: 20 + # g2_move_threshold: 20 + # g2_still_threshold: 21 + # g3_move_threshold: 30 + # g3_still_threshold: 31 + # g4_move_threshold: 40 + # g4_still_threshold: 41 + # g5_move_threshold: 50 + # g5_still_threshold: 51 + # g6_move_threshold: 60 + # g6_still_threshold: 61 + # g7_move_threshold: 70 + # g7_still_threshold: 71 + # g8_move_threshold: 80 + # g8_still_threshold: 81 + +button: + - platform: template + name: "Enable LD2410 BLE" + entity_category: "config" + icon: mdi:bluetooth + on_press: + lambda: |- + id(ld2410_radar) -> ble_control(true); + - platform: template + name: "Disable LD2410 BLE" + entity_category: "config" + icon: mdi:bluetooth-off + on_press: + lambda: |- + id(ld2410_radar) -> ble_control(false); + - platform: template + name: "LD2410 Reboot" + icon: mdi:radar + entity_category: "config" + on_press: + lambda: |- + // auto* radar = LD2410Component::get(ld2410); + // radar -> roboot(); + id(ld2410_radar) -> reboot(); + - platform: restart + icon: mdi:power-cycle + name: "ESP Reboot" + - platform: factory_reset + disabled_by_default: True + name: Factory Reset + id: factory_reset_all \ No newline at end of file diff --git a/1w/yaml/sun-light version/screek-mod-components/ld2410/__init__.py b/1w/yaml/sun-light version/screek-mod-components/ld2410/__init__.py new file mode 100644 index 0000000..be39cc2 --- /dev/null +++ b/1w/yaml/sun-light version/screek-mod-components/ld2410/__init__.py @@ -0,0 +1,158 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import uart +from esphome.const import CONF_ID, CONF_TIMEOUT +from esphome import automation +from esphome.automation import maybe_simple_id + +DEPENDENCIES = ["uart"] +CODEOWNERS = ["@sebcaps"] +MULTI_CONF = True + +ld2410_ns = cg.esphome_ns.namespace("ld2410") +LD2410Component = ld2410_ns.class_("LD2410Component", cg.Component, uart.UARTDevice) +LD2410Restart = ld2410_ns.class_("LD2410Restart", automation.Action) +CONF_LD2410_ID = "ld2410_id" +CONF_MAX_MOVE_DISTANCE = "max_move_distance" +CONF_MAX_STILL_DISTANCE = "max_still_distance" +CONF_G0_MOVE_THRESHOLD = "g0_move_threshold" +CONF_G0_STILL_THRESHOLD = "g0_still_threshold" +CONF_G1_MOVE_THRESHOLD = "g1_move_threshold" +CONF_G1_STILL_THRESHOLD = "g1_still_threshold" +CONF_G2_MOVE_THRESHOLD = "g2_move_threshold" +CONF_G2_STILL_THRESHOLD = "g2_still_threshold" +CONF_G3_MOVE_THRESHOLD = "g3_move_threshold" +CONF_G3_STILL_THRESHOLD = "g3_still_threshold" +CONF_G4_MOVE_THRESHOLD = "g4_move_threshold" +CONF_G4_STILL_THRESHOLD = "g4_still_threshold" +CONF_G5_MOVE_THRESHOLD = "g5_move_threshold" +CONF_G5_STILL_THRESHOLD = "g5_still_threshold" +CONF_G6_MOVE_THRESHOLD = "g6_move_threshold" +CONF_G6_STILL_THRESHOLD = "g6_still_threshold" +CONF_G7_MOVE_THRESHOLD = "g7_move_threshold" +CONF_G7_STILL_THRESHOLD = "g7_still_threshold" +CONF_G8_MOVE_THRESHOLD = "g8_move_threshold" +CONF_G8_STILL_THRESHOLD = "g8_still_threshold" + +DISTANCES = [0.75, 1.5, 2.25, 3, 3.75, 4.5, 5.25, 6] + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(LD2410Component), + cv.Optional(CONF_MAX_MOVE_DISTANCE, default="4.5m"): cv.All( + cv.distance, cv.one_of(*DISTANCES, float=True) + ), + cv.Optional(CONF_MAX_STILL_DISTANCE, default="4.5m"): cv.All( + cv.distance, cv.one_of(*DISTANCES, float=True) + ), + cv.Optional(CONF_TIMEOUT, default="5s"): cv.All( + cv.positive_time_period_seconds, + cv.Range(max=cv.TimePeriod(seconds=32767)), + ), + cv.Optional(CONF_G0_MOVE_THRESHOLD, default=50): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G0_STILL_THRESHOLD, default=0): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G1_MOVE_THRESHOLD, default=50): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G1_STILL_THRESHOLD, default=0): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G2_MOVE_THRESHOLD, default=40): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G2_STILL_THRESHOLD, default=40): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G3_MOVE_THRESHOLD, default=40): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G3_STILL_THRESHOLD, default=40): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G4_MOVE_THRESHOLD, default=40): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G4_STILL_THRESHOLD, default=40): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G5_MOVE_THRESHOLD, default=40): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G5_STILL_THRESHOLD, default=40): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G6_MOVE_THRESHOLD, default=30): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G6_STILL_THRESHOLD, default=15): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G7_MOVE_THRESHOLD, default=30): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G7_STILL_THRESHOLD, default=15): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G8_MOVE_THRESHOLD, default=30): cv.int_range( + min=0, max=100 + ), + cv.Optional(CONF_G8_STILL_THRESHOLD, default=15): cv.int_range( + min=0, max=100 + ), + } + ) + .extend(uart.UART_DEVICE_SCHEMA) + .extend(cv.COMPONENT_SCHEMA) +) + +FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( + "ld2410", + baud_rate=256000, + require_tx=True, + require_rx=True, + parity="NONE", + stop_bits=1, +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) + cg.add(var.set_timeout(config[CONF_TIMEOUT])) + cg.add(var.set_max_move_distance(int(config[CONF_MAX_MOVE_DISTANCE] / 0.75))) + cg.add(var.set_max_still_distance(int(config[CONF_MAX_STILL_DISTANCE] / 0.75))) + cg.add( + var.set_range_config( + config[CONF_G0_MOVE_THRESHOLD], + config[CONF_G0_STILL_THRESHOLD], + config[CONF_G1_MOVE_THRESHOLD], + config[CONF_G1_STILL_THRESHOLD], + config[CONF_G2_MOVE_THRESHOLD], + config[CONF_G2_STILL_THRESHOLD], + config[CONF_G3_MOVE_THRESHOLD], + config[CONF_G3_STILL_THRESHOLD], + config[CONF_G4_MOVE_THRESHOLD], + config[CONF_G4_STILL_THRESHOLD], + config[CONF_G5_MOVE_THRESHOLD], + config[CONF_G5_STILL_THRESHOLD], + config[CONF_G6_MOVE_THRESHOLD], + config[CONF_G6_STILL_THRESHOLD], + config[CONF_G7_MOVE_THRESHOLD], + config[CONF_G7_STILL_THRESHOLD], + config[CONF_G8_MOVE_THRESHOLD], + config[CONF_G8_STILL_THRESHOLD], + ) + ) + + +CALIBRATION_ACTION_SCHEMA = maybe_simple_id( + { + cv.Required(CONF_ID): cv.use_id(LD2410Component), + } +) diff --git a/1w/yaml/sun-light version/screek-mod-components/ld2410/binary_sensor.py b/1w/yaml/sun-light version/screek-mod-components/ld2410/binary_sensor.py new file mode 100644 index 0000000..02f73d5 --- /dev/null +++ b/1w/yaml/sun-light version/screek-mod-components/ld2410/binary_sensor.py @@ -0,0 +1,36 @@ +import esphome.codegen as cg +from esphome.components import binary_sensor +import esphome.config_validation as cv +from esphome.const import DEVICE_CLASS_MOTION, DEVICE_CLASS_OCCUPANCY +from . import CONF_LD2410_ID, LD2410Component + +DEPENDENCIES = ["ld2410"] +CONF_HAS_TARGET = "has_target" +CONF_HAS_MOVING_TARGET = "has_moving_target" +CONF_HAS_STILL_TARGET = "has_still_target" + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), + cv.Optional(CONF_HAS_TARGET): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_OCCUPANCY + ), + cv.Optional(CONF_HAS_MOVING_TARGET): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_MOTION + ), + cv.Optional(CONF_HAS_STILL_TARGET): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_OCCUPANCY + ), +} + + +async def to_code(config): + ld2410_component = await cg.get_variable(config[CONF_LD2410_ID]) + if CONF_HAS_TARGET in config: + sens = await binary_sensor.new_binary_sensor(config[CONF_HAS_TARGET]) + cg.add(ld2410_component.set_target_sensor(sens)) + if CONF_HAS_MOVING_TARGET in config: + sens = await binary_sensor.new_binary_sensor(config[CONF_HAS_MOVING_TARGET]) + cg.add(ld2410_component.set_moving_target_sensor(sens)) + if CONF_HAS_STILL_TARGET in config: + sens = await binary_sensor.new_binary_sensor(config[CONF_HAS_STILL_TARGET]) + cg.add(ld2410_component.set_still_target_sensor(sens)) diff --git a/1w/yaml/sun-light version/screek-mod-components/ld2410/ld2410.cpp b/1w/yaml/sun-light version/screek-mod-components/ld2410/ld2410.cpp new file mode 100644 index 0000000..30c71f0 --- /dev/null +++ b/1w/yaml/sun-light version/screek-mod-components/ld2410/ld2410.cpp @@ -0,0 +1,418 @@ +#include "ld2410.h" + +#define highbyte(val) (uint8_t)((val) >> 8) +#define lowbyte(val) (uint8_t)((val) &0xff) + +namespace esphome { +namespace ld2410 { + +static const char *const TAG = "ld2410"; + +void LD2410Component::dump_config() { + ESP_LOGCONFIG(TAG, "LD2410:"); +#ifdef USE_BINARY_SENSOR + LOG_BINARY_SENSOR(" ", "HasTargetSensor", this->target_binary_sensor_); + LOG_BINARY_SENSOR(" ", "MovingSensor", this->moving_binary_sensor_); + LOG_BINARY_SENSOR(" ", "StillSensor", this->still_binary_sensor_); +#endif +#ifdef USE_SENSOR + LOG_SENSOR(" ", "Moving Distance", this->moving_target_distance_sensor_); + LOG_SENSOR(" ", "Still Distance", this->still_target_distance_sensor_); + LOG_SENSOR(" ", "Moving Energy", this->moving_target_energy_sensor_); + LOG_SENSOR(" ", "Still Energy", this->still_target_energy_sensor_); + LOG_SENSOR(" ", "Detection Distance", this->detection_distance_sensor_); + + // 回显光线模块设置(23年3月13日_17时28分_) + LOG_SENSOR(" ", "Light", this->light_sensor_); +#endif + this->set_config_mode_(true); + this->get_version_(); + this->set_config_mode_(false); + ESP_LOGCONFIG(TAG, " Firmware Version : %u.%u.%u%u%u%u", this->version_[0], this->version_[1], this->version_[2], + this->version_[3], this->version_[4], this->version_[5]); +} + +void LD2410Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up LD2410..."); + // ESP_LOGCONFIG(TAG, "Apply screek patch..."); + this->set_config_mode_(true); + // 使用蓝牙配置,取消这里的参数定义选项。(23年3月10日_20时50分_) + /* + this->set_max_distances_timeout_(this->max_move_distance_, this->max_still_distance_, this->timeout_); + // Configure Gates sensitivity + this->set_gate_threshold_(0, this->rg0_move_threshold_, this->rg0_still_threshold_); + this->set_gate_threshold_(1, this->rg1_move_threshold_, this->rg1_still_threshold_); + this->set_gate_threshold_(2, this->rg2_move_threshold_, this->rg2_still_threshold_); + this->set_gate_threshold_(3, this->rg3_move_threshold_, this->rg3_still_threshold_); + this->set_gate_threshold_(4, this->rg4_move_threshold_, this->rg4_still_threshold_); + this->set_gate_threshold_(5, this->rg5_move_threshold_, this->rg5_still_threshold_); + this->set_gate_threshold_(6, this->rg6_move_threshold_, this->rg6_still_threshold_); + this->set_gate_threshold_(7, this->rg7_move_threshold_, this->rg7_still_threshold_); + this->set_gate_threshold_(8, this->rg8_move_threshold_, this->rg8_still_threshold_); + */ + this->get_version_(); + this->set_config_mode_(false); + + // 开启工程模式!(23年3月13日_18时03分_) + // 因为会自动开启,这里就不太合适继续需要了。 + // this->factory_mode(true); + + ESP_LOGCONFIG(TAG, "Firmware Version : %u.%u.%u%u%u%u", this->version_[0], this->version_[1], this->version_[2], + this->version_[3], this->version_[4], this->version_[5]); + ESP_LOGCONFIG(TAG, "LD2410 setup complete."); +} + +void LD2410Component::loop() { + const int max_line_length = 80; + static uint8_t buffer[max_line_length]; + + while (available()) { + this->readline_(read(), buffer, max_line_length); + } +} + +// 发送命令给雷达!(23年3月13日_14时46分_) +void LD2410Component::send_command_(uint8_t command, uint8_t *command_value, int command_value_len) { + // lastCommandSuccess->publish_state(false); + + // frame start bytes + this->write_array(CMD_FRAME_HEADER, 4); + // length bytes + int len = 2; + if (command_value != nullptr) + len += command_value_len; + this->write_byte(lowbyte(len)); + this->write_byte(highbyte(len)); + + // command + this->write_byte(lowbyte(command)); + this->write_byte(highbyte(command)); + + // command value bytes + if (command_value != nullptr) { + for (int i = 0; i < command_value_len; i++) { + this->write_byte(command_value[i]); + } + } + // frame end bytes + this->write_array(CMD_FRAME_END, 4); + // FIXME to remove + delay(50); // NOLINT +} + +// https://cdn.arduino.cc/reference/en/language/functions/math/map/ +long map(long x, long in_min, long in_max, long out_min, long out_max) { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +void LD2410Component::handle_periodic_data_(uint8_t *buffer, int len) { + if (len < 12) + return; // 4 frame start bytes + 2 length bytes + 1 data end byte + 1 crc byte + 4 frame end bytes + if (buffer[0] != 0xF4 || buffer[1] != 0xF3 || buffer[2] != 0xF2 || buffer[3] != 0xF1) // check 4 frame start bytes + return; + if (buffer[7] != HEAD || buffer[len - 6] != END || buffer[len - 5] != CHECK) // Check constant values + return; // data head=0xAA, data end=0x55, crc=0x00 + + /* + Data Type: 6th + 0x01: Engineering mode + 0x02: Normal mode + */ + // char data_type = buffer[DATA_TYPES]; + /* + Target states: 9th + 0x00 = No target + 0x01 = Moving targets + 0x02 = Still targets + 0x03 = Moving+Still targets + */ +#ifdef USE_BINARY_SENSOR + char target_state = buffer[TARGET_STATES]; + if (this->target_binary_sensor_ != nullptr) { + this->target_binary_sensor_->publish_state(target_state != 0x00); + } +#endif + + /* + Reduce data update rate to prevent home assistant database size grow fast + */ + int32_t current_millis = millis(); + if (current_millis - last_periodic_millis < 1000) + return; + last_periodic_millis = current_millis; + +#ifdef USE_BINARY_SENSOR + if (this->moving_binary_sensor_ != nullptr) { + this->moving_binary_sensor_->publish_state(CHECK_BIT(target_state, 0)); + } + if (this->still_binary_sensor_ != nullptr) { + this->still_binary_sensor_->publish_state(CHECK_BIT(target_state, 1)); + } +#endif + /* + Moving target distance: 10~11th bytes + Moving target energy: 12th byte + Still target distance: 13~14th bytes + Still target energy: 15th byte + Detect distance: 16~17th bytes + */ +#ifdef USE_SENSOR + if (this->moving_target_distance_sensor_ != nullptr) { + int new_moving_target_distance = this->two_byte_to_int_(buffer[MOVING_TARGET_LOW], buffer[MOVING_TARGET_HIGH]); + if (this->moving_target_distance_sensor_->get_state() != new_moving_target_distance) + this->moving_target_distance_sensor_->publish_state(new_moving_target_distance); + } + if (this->moving_target_energy_sensor_ != nullptr) { + int new_moving_target_energy = buffer[MOVING_ENERGY]; + if (this->moving_target_energy_sensor_->get_state() != new_moving_target_energy) + this->moving_target_energy_sensor_->publish_state(new_moving_target_energy); + } + if (this->still_target_distance_sensor_ != nullptr) { + int new_still_target_distance = this->two_byte_to_int_(buffer[STILL_TARGET_LOW], buffer[STILL_TARGET_HIGH]); + if (this->still_target_distance_sensor_->get_state() != new_still_target_distance) + this->still_target_distance_sensor_->publish_state(new_still_target_distance); + } + if (this->still_target_energy_sensor_ != nullptr) { + int new_still_target_energy = buffer[STILL_ENERGY]; + if (this->still_target_energy_sensor_->get_state() != new_still_target_energy) + this->still_target_energy_sensor_->publish_state(new_still_target_energy); + } + if (this->detection_distance_sensor_ != nullptr) { + int new_detect_distance = this->two_byte_to_int_(buffer[DETECT_DISTANCE_LOW], buffer[DETECT_DISTANCE_HIGH]); + if (this->detection_distance_sensor_->get_state() != new_detect_distance) + this->detection_distance_sensor_->publish_state(new_detect_distance); + } + + if (this->light_sensor_ != nullptr) { + int data_type = buffer[6]; + int new_light = -1; + if (data_type == 0x01){ // 0x01 = factory mode + new_light = buffer[37]; + + new_light = map(new_light, 85, 255, 0, 100); + if (new_light < 0){ + new_light = 0; + } + if (new_light > 100){ + new_light = 100; + } + }else{ + int32_t now_millis = millis(); + if (now_millis - last_change_fatory_mode_millis > 2000){ + ESP_LOGD(TAG,"Normal mode no light, change to factory mode"); + this->factory_mode(true); + last_change_fatory_mode_millis = now_millis; + } + } + if (this->light_sensor_->get_state() != new_light){ + this->light_sensor_->publish_state(new_light); + } + } + +#endif + +} + +void LD2410Component::handle_ack_data_(uint8_t *buffer, int len) { + ESP_LOGV(TAG, "Handling ACK DATA for COMMAND"); + if (len < 10) { + ESP_LOGE(TAG, "Error with last command : incorrect length"); + return; + } + if (buffer[0] != 0xFD || buffer[1] != 0xFC || buffer[2] != 0xFB || buffer[3] != 0xFA) { // check 4 frame start bytes + ESP_LOGE(TAG, "Error with last command : incorrect Header"); + return; + } + if (buffer[COMMAND_STATUS] != 0x01) { + ESP_LOGE(TAG, "Error with last command : status != 0x01"); + return; + } + if (this->two_byte_to_int_(buffer[8], buffer[9]) != 0x00) { + ESP_LOGE(TAG, "Error with last command , last buffer was: %u , %u", buffer[8], buffer[9]); + return; + } + + switch (buffer[COMMAND]) { + case lowbyte(CMD_ENABLE_CONF): + ESP_LOGV(TAG, "Handled Enable conf command"); + break; + case lowbyte(CMD_DISABLE_CONF): + ESP_LOGV(TAG, "Handled Disabled conf command"); + break; + case lowbyte(CMD_VERSION): + ESP_LOGV(TAG, "FW Version is: %u.%u.%u%u%u%u", buffer[13], buffer[12], buffer[17], buffer[16], buffer[15], + buffer[14]); + this->version_[0] = buffer[13]; + this->version_[1] = buffer[12]; + this->version_[2] = buffer[17]; + this->version_[3] = buffer[16]; + this->version_[4] = buffer[15]; + this->version_[5] = buffer[14]; + + break; + case lowbyte(CMD_GATE_SENS): + ESP_LOGV(TAG, "Handled sensitivity command"); + break; + case lowbyte(CMD_QUERY): // Query parameters response + { + if (buffer[10] != 0xAA) + return; // value head=0xAA + /* + Moving distance range: 13th byte + Still distance range: 14th byte + */ + // TODO + // maxMovingDistanceRange->publish_state(buffer[12]); + // maxStillDistanceRange->publish_state(buffer[13]); + /* + Moving Sensitivities: 15~23th bytes + Still Sensitivities: 24~32th bytes + */ + for (int i = 0; i < 9; i++) { + moving_sensitivities[i] = buffer[14 + i]; + } + for (int i = 0; i < 9; i++) { + still_sensitivities[i] = buffer[23 + i]; + } + /* + None Duration: 33~34th bytes + */ + // noneDuration->publish_state(this->two_byte_to_int_(buffer[32], buffer[33])); + } break; + default: + break; + } +} + +void LD2410Component::readline_(int readch, uint8_t *buffer, int len) { + static int pos = 0; + + if (readch >= 0) { + if (pos < len - 1) { + buffer[pos++] = readch; + buffer[pos] = 0; + } else { + pos = 0; + } + if (pos >= 4) { + if (buffer[pos - 4] == 0xF8 && buffer[pos - 3] == 0xF7 && buffer[pos - 2] == 0xF6 && buffer[pos - 1] == 0xF5) { + ESP_LOGV(TAG, "Will handle Periodic Data"); + this->handle_periodic_data_(buffer, pos); + pos = 0; // Reset position index ready for next time + } else if (buffer[pos - 4] == 0x04 && buffer[pos - 3] == 0x03 && buffer[pos - 2] == 0x02 && + buffer[pos - 1] == 0x01) { + ESP_LOGV(TAG, "Will handle ACK Data"); + this->handle_ack_data_(buffer, pos); + pos = 0; // Reset position index ready for next time + } + } + } +} + +void LD2410Component::set_config_mode_(bool enable) { + uint8_t cmd = enable ? CMD_ENABLE_CONF : CMD_DISABLE_CONF; + uint8_t cmd_value[2] = {0x01, 0x00}; + this->send_command_(cmd, enable ? cmd_value : nullptr, 2); +} + +void LD2410Component::query_parameters_() { this->send_command_(CMD_QUERY, nullptr, 0); } +void LD2410Component::get_version_() { this->send_command_(CMD_VERSION, nullptr, 0); } + +void LD2410Component::set_max_distances_timeout_(uint8_t max_moving_distance_range, uint8_t max_still_distance_range, + uint16_t timeout) { + uint8_t value[18] = {0x00, + 0x00, + lowbyte(max_moving_distance_range), + highbyte(max_moving_distance_range), + 0x00, + 0x00, + 0x01, + 0x00, + lowbyte(max_still_distance_range), + highbyte(max_still_distance_range), + 0x00, + 0x00, + 0x02, + 0x00, + lowbyte(timeout), + highbyte(timeout), + 0x00, + 0x00}; + this->send_command_(CMD_MAXDIST_DURATION, value, 18); + this->query_parameters_(); +} +void LD2410Component::set_gate_threshold_(uint8_t gate, uint8_t motionsens, uint8_t stillsens) { + // reference + // https://drive.google.com/drive/folders/1p4dhbEJA3YubyIjIIC7wwVsSo8x29Fq-?spm=a2g0o.detail.1000023.17.93465697yFwVxH + // Send data: configure the motion sensitivity of distance gate 3 to 40, and the static sensitivity of 40 + // 00 00 (gate) + // 03 00 00 00 (gate number) + // 01 00 (motion sensitivity) + // 28 00 00 00 (value) + // 02 00 (still sensitivtiy) + // 28 00 00 00 (value) + uint8_t value[18] = {0x00, 0x00, lowbyte(gate), highbyte(gate), 0x00, 0x00, + 0x01, 0x00, lowbyte(motionsens), highbyte(motionsens), 0x00, 0x00, + 0x02, 0x00, lowbyte(stillsens), highbyte(stillsens), 0x00, 0x00}; + this->send_command_(CMD_GATE_SENS, value, 18); +} + +// 额外增加的命令到这里去(23年3月13日_14时57分_) +void LD2410Component::factoryReset() + { + this->set_config_mode_(true); + + uint8_t cmd = 0x00A2; + this -> send_command_(cmd, nullptr, 0); + } + +void LD2410Component::reboot() +{ + ESP_LOGD(TAG, "reboot ld2410b..."); + this->set_config_mode_(true); + + uint8_t cmd = 0x00A3; + this -> send_command_(cmd, nullptr, 0); + // not need to exit config mode because the ld2410 will reboot automatically +} + +void LD2410Component::ble_control(bool enable) +{ + this->set_config_mode_(true); + uint8_t CMD_BLE_CONF = 0x00A4; + uint8_t CMD_REBOOT = 0x00A3; + + uint8_t cmd_value[2] = {0x00, 0x00}; + + if (enable){ + cmd_value[0] = 0x01; + + ESP_LOGD(TAG, "Disable BLE..."); + }else{ + ESP_LOGD(TAG, "Enable BLE..."); + } + + this -> send_command_(CMD_BLE_CONF, cmd_value, 2); + + //this -> send_command_(CMD_REBOOT, nullptr, 0); + + this->set_config_mode_(false); + + this -> reboot(); +} + +void LD2410Component::factory_mode(bool enable){ + uint8_t CMD_FACTORY_ON = 0x0062; + uint8_t CMD_FACTORY_OFF = 0x0063; + this->set_config_mode_(true); + + uint8_t cmd = enable ? CMD_FACTORY_ON: CMD_FACTORY_OFF; + + this->send_command_(cmd, nullptr, 0); + + this->set_config_mode_(false); + +} + +} // namespace ld2410 +} // namespace esphome diff --git a/1w/yaml/sun-light version/screek-mod-components/ld2410/ld2410.h b/1w/yaml/sun-light version/screek-mod-components/ld2410/ld2410.h new file mode 100644 index 0000000..0336811 --- /dev/null +++ b/1w/yaml/sun-light version/screek-mod-components/ld2410/ld2410.h @@ -0,0 +1,169 @@ +#pragma once +#include "esphome/core/defines.h" +#include "esphome/core/component.h" +#ifdef USE_BINARY_SENSOR +#include "esphome/components/binary_sensor/binary_sensor.h" +#endif +#ifdef USE_SENSOR +#include "esphome/components/sensor/sensor.h" +#endif +#include "esphome/components/uart/uart.h" +#include "esphome/core/automation.h" +#include "esphome/core/helpers.h" + +namespace esphome { +namespace ld2410 { + +#define CHECK_BIT(var, pos) (((var) >> (pos)) & 1) + +// Commands +static const uint8_t CMD_ENABLE_CONF = 0x00FF; +static const uint8_t CMD_DISABLE_CONF = 0x00FE; +static const uint8_t CMD_MAXDIST_DURATION = 0x0060; +static const uint8_t CMD_QUERY = 0x0061; +static const uint8_t CMD_GATE_SENS = 0x0064; +static const uint8_t CMD_VERSION = 0x00A0; + +// Commands values +static const uint8_t CMD_MAX_MOVE_VALUE = 0x0000; +static const uint8_t CMD_MAX_STILL_VALUE = 0x0001; +static const uint8_t CMD_DURATION_VALUE = 0x0002; +// Command Header & Footer +static const uint8_t CMD_FRAME_HEADER[4] = {0xFD, 0xFC, 0xFB, 0xFA}; +static const uint8_t CMD_FRAME_END[4] = {0x04, 0x03, 0x02, 0x01}; +// Data Header & Footer +static const uint8_t DATA_FRAME_HEADER[4] = {0xF4, 0xF3, 0xF2, 0xF1}; +static const uint8_t DATA_FRAME_END[4] = {0xF8, 0xF7, 0xF6, 0xF5}; +/* +Data Type: 6th byte +Target states: 9th byte + Moving target distance: 10~11th bytes + Moving target energy: 12th byte + Still target distance: 13~14th bytes + Still target energy: 15th byte + Detect distance: 16~17th bytes +*/ +enum PeriodicDataStructure : uint8_t { + DATA_TYPES = 5, + TARGET_STATES = 8, + MOVING_TARGET_LOW = 9, + MOVING_TARGET_HIGH = 10, + MOVING_ENERGY = 11, + STILL_TARGET_LOW = 12, + STILL_TARGET_HIGH = 13, + STILL_ENERGY = 14, + DETECT_DISTANCE_LOW = 15, + DETECT_DISTANCE_HIGH = 16, +}; +// 上报数据的固定结构。(23年3月13日_16时54分_) +enum PeriodicDataValue : uint8_t { HEAD = 0XAA, END = 0x55, CHECK = 0x00 }; + +enum AckDataStructure : uint8_t { COMMAND = 6, COMMAND_STATUS = 7 }; + +// char cmd[2] = {enable ? 0xFF : 0xFE, 0x00}; +class LD2410Component : public Component, public uart::UARTDevice { +#ifdef USE_SENSOR + SUB_SENSOR(moving_target_distance) + SUB_SENSOR(still_target_distance) + SUB_SENSOR(moving_target_energy) + SUB_SENSOR(still_target_energy) + SUB_SENSOR(detection_distance) + SUB_SENSOR(light) +#endif + + public: + void setup() override; + void dump_config() override; + void loop() override; + +#ifdef USE_BINARY_SENSOR + void set_target_sensor(binary_sensor::BinarySensor *sens) { this->target_binary_sensor_ = sens; }; + void set_moving_target_sensor(binary_sensor::BinarySensor *sens) { this->moving_binary_sensor_ = sens; }; + void set_still_target_sensor(binary_sensor::BinarySensor *sens) { this->still_binary_sensor_ = sens; }; +#endif + + void set_timeout(uint16_t value) { this->timeout_ = value; }; + void set_max_move_distance(uint8_t value) { this->max_move_distance_ = value; }; + void set_max_still_distance(uint8_t value) { this->max_still_distance_ = value; }; + void set_range_config(int rg0_move, int rg0_still, int rg1_move, int rg1_still, int rg2_move, int rg2_still, + int rg3_move, int rg3_still, int rg4_move, int rg4_still, int rg5_move, int rg5_still, + int rg6_move, int rg6_still, int rg7_move, int rg7_still, int rg8_move, int rg8_still) { + this->rg0_move_threshold_ = rg0_move; + this->rg0_still_threshold_ = rg0_still; + this->rg1_move_threshold_ = rg1_move; + this->rg1_still_threshold_ = rg1_still; + this->rg2_move_threshold_ = rg2_move; + this->rg2_still_threshold_ = rg2_still; + this->rg3_move_threshold_ = rg3_move; + this->rg3_still_threshold_ = rg3_still; + this->rg4_move_threshold_ = rg4_move; + this->rg4_still_threshold_ = rg4_still; + this->rg5_move_threshold_ = rg5_move; + this->rg5_still_threshold_ = rg5_still; + this->rg6_move_threshold_ = rg6_move; + this->rg6_still_threshold_ = rg6_still; + this->rg7_move_threshold_ = rg7_move; + this->rg7_still_threshold_ = rg7_still; + this->rg8_move_threshold_ = rg8_move; + this->rg8_still_threshold_ = rg8_still; + }; + int moving_sensitivities[9] = {0}; + int still_sensitivities[9] = {0}; + + int32_t last_periodic_millis = millis(); + + /// @brief 上次改变工程模式的时间,用来防止改变频率太高了。(23年3月13日_18时07分_) + int32_t last_change_fatory_mode_millis = 0; + + // 增加一些额外的命令,比如重启,开关蓝牙。(23年3月13日_14时44分_) + // https://github.com/rain931215/ESPHome-LD2410/blob/main/ld2410_uart.h + + /// 恢复出厂设置!(23年3月13日_14时48分_) + void factoryReset(); + + // 重启(23年3月13日_14时48分_) + void reboot(); + + /// @brief 蓝牙开关 + /// (23年3月13日_15时22分_) + void ble_control(bool enable); + + /// @brief 开关工程模式 + /// @param enable 开关 + /// 用来快速切换工程模式用的。(23年3月13日_17时59分_) + void factory_mode(bool enable); + + protected: +#ifdef USE_BINARY_SENSOR + binary_sensor::BinarySensor *target_binary_sensor_{nullptr}; + binary_sensor::BinarySensor *moving_binary_sensor_{nullptr}; + binary_sensor::BinarySensor *still_binary_sensor_{nullptr}; +#endif + + std::vector rx_buffer_; + int two_byte_to_int_(char firstbyte, char secondbyte) { return (int16_t)(secondbyte << 8) + firstbyte; } + void send_command_(uint8_t command_str, uint8_t *command_value, int command_value_len); + + void set_max_distances_timeout_(uint8_t max_moving_distance_range, uint8_t max_still_distance_range, + uint16_t timeout); + void set_gate_threshold_(uint8_t gate, uint8_t motionsens, uint8_t stillsens); + void set_config_mode_(bool enable); + void handle_periodic_data_(uint8_t *buffer, int len); + void handle_ack_data_(uint8_t *buffer, int len); + void readline_(int readch, uint8_t *buffer, int len); + void query_parameters_(); + void get_version_(); + + uint16_t timeout_; + uint8_t max_move_distance_; + uint8_t max_still_distance_; + + uint8_t version_[6]; + uint8_t rg0_move_threshold_, rg0_still_threshold_, rg1_move_threshold_, rg1_still_threshold_, rg2_move_threshold_, + rg2_still_threshold_, rg3_move_threshold_, rg3_still_threshold_, rg4_move_threshold_, rg4_still_threshold_, + rg5_move_threshold_, rg5_still_threshold_, rg6_move_threshold_, rg6_still_threshold_, rg7_move_threshold_, + rg7_still_threshold_, rg8_move_threshold_, rg8_still_threshold_; +}; + +} // namespace ld2410 +} // namespace esphome diff --git a/1w/yaml/sun-light version/screek-mod-components/ld2410/sensor.py b/1w/yaml/sun-light version/screek-mod-components/ld2410/sensor.py new file mode 100644 index 0000000..1a118f5 --- /dev/null +++ b/1w/yaml/sun-light version/screek-mod-components/ld2410/sensor.py @@ -0,0 +1,64 @@ +import esphome.codegen as cg +from esphome.components import sensor +import esphome.config_validation as cv +from esphome.const import ( + DEVICE_CLASS_DISTANCE, + DEVICE_CLASS_ENERGY, + UNIT_CENTIMETER, + UNIT_PERCENT, + DEVICE_CLASS_ILLUMINANCE, + UNIT_EMPTY, + UNIT_LUX, +) +from . import CONF_LD2410_ID, LD2410Component + +DEPENDENCIES = ["ld2410"] +CONF_MOVING_DISTANCE = "moving_distance" +CONF_STILL_DISTANCE = "still_distance" +CONF_MOVING_ENERGY = "moving_energy" +CONF_STILL_ENERGY = "still_energy" +CONF_DETECTION_DISTANCE = "detection_distance" +CONF_LIGHT = "light" + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component), + cv.Optional(CONF_MOVING_DISTANCE): sensor.sensor_schema( + device_class=DEVICE_CLASS_DISTANCE, unit_of_measurement=UNIT_CENTIMETER + ), + cv.Optional(CONF_STILL_DISTANCE): sensor.sensor_schema( + device_class=DEVICE_CLASS_DISTANCE, unit_of_measurement=UNIT_CENTIMETER + ), + cv.Optional(CONF_MOVING_ENERGY): sensor.sensor_schema( + device_class=DEVICE_CLASS_ENERGY, unit_of_measurement=UNIT_PERCENT + ), + cv.Optional(CONF_STILL_ENERGY): sensor.sensor_schema( + device_class=DEVICE_CLASS_ENERGY, unit_of_measurement=UNIT_PERCENT + ), + cv.Optional(CONF_DETECTION_DISTANCE): sensor.sensor_schema( + device_class=DEVICE_CLASS_DISTANCE, unit_of_measurement=UNIT_CENTIMETER + ), + cv.Optional(CONF_LIGHT): sensor.sensor_schema( + device_class=DEVICE_CLASS_ILLUMINANCE, unit_of_measurement=UNIT_PERCENT + ), +} + +async def to_code(config): + ld2410_component = await cg.get_variable(config[CONF_LD2410_ID]) + if CONF_MOVING_DISTANCE in config: + sens = await sensor.new_sensor(config[CONF_MOVING_DISTANCE]) + cg.add(ld2410_component.set_moving_target_distance_sensor(sens)) + if CONF_STILL_DISTANCE in config: + sens = await sensor.new_sensor(config[CONF_STILL_DISTANCE]) + cg.add(ld2410_component.set_still_target_distance_sensor(sens)) + if CONF_MOVING_ENERGY in config: + sens = await sensor.new_sensor(config[CONF_MOVING_ENERGY]) + cg.add(ld2410_component.set_moving_target_energy_sensor(sens)) + if CONF_STILL_ENERGY in config: + sens = await sensor.new_sensor(config[CONF_STILL_ENERGY]) + cg.add(ld2410_component.set_still_target_energy_sensor(sens)) + if CONF_DETECTION_DISTANCE in config: + sens = await sensor.new_sensor(config[CONF_DETECTION_DISTANCE]) + cg.add(ld2410_component.set_detection_distance_sensor(sens)) + if CONF_LIGHT in config: + sens = await sensor.new_sensor(config[CONF_LIGHT]) + cg.add(ld2410_component.set_light_sensor(sens)) \ No newline at end of file