mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Merge branch 'duplicate_client_peername' into integration
This commit is contained in:
		| @@ -73,7 +73,6 @@ void APIConnection::start() { | ||||
|     return; | ||||
|   } | ||||
|   this->client_info_ = helper_->getpeername(); | ||||
|   this->client_peername_ = this->client_info_; | ||||
|   this->helper_->set_log_info(this->client_info_); | ||||
| } | ||||
|  | ||||
| @@ -1541,12 +1540,11 @@ bool APIConnection::try_send_log_message(int level, const char *tag, const char | ||||
|  | ||||
| HelloResponse APIConnection::hello(const HelloRequest &msg) { | ||||
|   this->client_info_ = msg.client_info; | ||||
|   this->client_peername_ = this->helper_->getpeername(); | ||||
|   this->helper_->set_log_info(this->get_client_combined_info()); | ||||
|   this->client_api_version_major_ = msg.api_version_major; | ||||
|   this->client_api_version_minor_ = msg.api_version_minor; | ||||
|   ESP_LOGV(TAG, "Hello from client: '%s' | %s | API Version %" PRIu32 ".%" PRIu32, this->client_info_.c_str(), | ||||
|            this->client_peername_.c_str(), this->client_api_version_major_, this->client_api_version_minor_); | ||||
|            this->helper_->getpeername().c_str(), this->client_api_version_major_, this->client_api_version_minor_); | ||||
|  | ||||
|   HelloResponse resp; | ||||
|   resp.api_version_major = 1; | ||||
| @@ -1566,7 +1564,7 @@ ConnectResponse APIConnection::connect(const ConnectRequest &msg) { | ||||
|   if (correct) { | ||||
|     ESP_LOGD(TAG, "%s connected", this->get_client_combined_info().c_str()); | ||||
|     this->connection_state_ = ConnectionState::AUTHENTICATED; | ||||
|     this->parent_->get_client_connected_trigger()->trigger(this->client_info_, this->client_peername_); | ||||
|     this->parent_->get_client_connected_trigger()->trigger(this->client_info_, this->helper_->getpeername()); | ||||
| #ifdef USE_HOMEASSISTANT_TIME | ||||
|     if (homeassistant::global_homeassistant_time != nullptr) { | ||||
|       this->send_time_request(); | ||||
|   | ||||
| @@ -275,11 +275,12 @@ class APIConnection : public APIServerConnection { | ||||
|   bool send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) override; | ||||
|  | ||||
|   std::string get_client_combined_info() const { | ||||
|     if (this->client_info_ == this->client_peername_) { | ||||
|     std::string peername = this->helper_->getpeername(); | ||||
|     if (this->client_info_ == peername) { | ||||
|       // Before Hello message, both are the same (just IP:port) | ||||
|       return this->client_info_; | ||||
|     } | ||||
|     return this->client_info_ + " (" + this->client_peername_ + ")"; | ||||
|     return this->client_info_ + " (" + peername + ")"; | ||||
|   } | ||||
|  | ||||
|   // Buffer allocator methods for batch processing | ||||
| @@ -454,7 +455,6 @@ class APIConnection : public APIServerConnection { | ||||
|  | ||||
|   // Strings (12 bytes each on 32-bit) | ||||
|   std::string client_info_; | ||||
|   std::string client_peername_; | ||||
|  | ||||
|   // 2-byte aligned types | ||||
|   uint16_t client_api_version_major_{0}; | ||||
|   | ||||
| @@ -184,7 +184,7 @@ void APIServer::loop() { | ||||
|     } | ||||
|  | ||||
|     // Rare case: handle disconnection | ||||
|     this->client_disconnected_trigger_->trigger(client->client_info_, client->client_peername_); | ||||
|     this->client_disconnected_trigger_->trigger(client->client_info_, client->helper_->getpeername()); | ||||
|     ESP_LOGV(TAG, "Remove connection %s", client->client_info_.c_str()); | ||||
|  | ||||
|     // Swap with the last element and pop (avoids expensive vector shifts) | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
|  | ||||
| #include "esphome/core/application.h" | ||||
|  | ||||
| #define CHECK_BIT(var, pos) (((var) >> (pos)) & 1) | ||||
| #define highbyte(val) (uint8_t)((val) >> 8) | ||||
| #define lowbyte(val) (uint8_t)((val) &0xff) | ||||
|  | ||||
| @@ -17,8 +18,162 @@ namespace esphome { | ||||
| namespace ld2410 { | ||||
|  | ||||
| static const char *const TAG = "ld2410"; | ||||
| static const char *const NO_MAC = "08:05:04:03:02:01"; | ||||
| static const char *const UNKNOWN_MAC = "unknown"; | ||||
| static const char *const VERSION_FMT = "%u.%02X.%02X%02X%02X%02X"; | ||||
|  | ||||
| LD2410Component::LD2410Component() {} | ||||
| enum BaudRateStructure : uint8_t { | ||||
|   BAUD_RATE_9600 = 1, | ||||
|   BAUD_RATE_19200 = 2, | ||||
|   BAUD_RATE_38400 = 3, | ||||
|   BAUD_RATE_57600 = 4, | ||||
|   BAUD_RATE_115200 = 5, | ||||
|   BAUD_RATE_230400 = 6, | ||||
|   BAUD_RATE_256000 = 7, | ||||
|   BAUD_RATE_460800 = 8, | ||||
| }; | ||||
|  | ||||
| enum DistanceResolutionStructure : uint8_t { | ||||
|   DISTANCE_RESOLUTION_0_2 = 0x01, | ||||
|   DISTANCE_RESOLUTION_0_75 = 0x00, | ||||
| }; | ||||
|  | ||||
| enum LightFunctionStructure : uint8_t { | ||||
|   LIGHT_FUNCTION_OFF = 0x00, | ||||
|   LIGHT_FUNCTION_BELOW = 0x01, | ||||
|   LIGHT_FUNCTION_ABOVE = 0x02, | ||||
| }; | ||||
|  | ||||
| enum OutPinLevelStructure : uint8_t { | ||||
|   OUT_PIN_LEVEL_LOW = 0x00, | ||||
|   OUT_PIN_LEVEL_HIGH = 0x01, | ||||
| }; | ||||
|  | ||||
| enum PeriodicDataStructure : uint8_t { | ||||
|   DATA_TYPES = 6, | ||||
|   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, | ||||
|   MOVING_SENSOR_START = 19, | ||||
|   STILL_SENSOR_START = 28, | ||||
|   LIGHT_SENSOR = 37, | ||||
|   OUT_PIN_SENSOR = 38, | ||||
| }; | ||||
|  | ||||
| enum PeriodicDataValue : uint8_t { | ||||
|   HEAD = 0xAA, | ||||
|   END = 0x55, | ||||
|   CHECK = 0x00, | ||||
| }; | ||||
|  | ||||
| enum AckDataStructure : uint8_t { | ||||
|   COMMAND = 6, | ||||
|   COMMAND_STATUS = 7, | ||||
| }; | ||||
|  | ||||
| // Memory-efficient lookup tables | ||||
| struct StringToUint8 { | ||||
|   const char *str; | ||||
|   uint8_t value; | ||||
| }; | ||||
|  | ||||
| struct Uint8ToString { | ||||
|   uint8_t value; | ||||
|   const char *str; | ||||
| }; | ||||
|  | ||||
| constexpr StringToUint8 BAUD_RATES_BY_STR[] = { | ||||
|     {"9600", BAUD_RATE_9600},     {"19200", BAUD_RATE_19200},   {"38400", BAUD_RATE_38400}, | ||||
|     {"57600", BAUD_RATE_57600},   {"115200", BAUD_RATE_115200}, {"230400", BAUD_RATE_230400}, | ||||
|     {"256000", BAUD_RATE_256000}, {"460800", BAUD_RATE_460800}, | ||||
| }; | ||||
|  | ||||
| constexpr StringToUint8 DISTANCE_RESOLUTIONS_BY_STR[] = { | ||||
|     {"0.2m", DISTANCE_RESOLUTION_0_2}, | ||||
|     {"0.75m", DISTANCE_RESOLUTION_0_75}, | ||||
| }; | ||||
|  | ||||
| constexpr Uint8ToString DISTANCE_RESOLUTIONS_BY_UINT[] = { | ||||
|     {DISTANCE_RESOLUTION_0_2, "0.2m"}, | ||||
|     {DISTANCE_RESOLUTION_0_75, "0.75m"}, | ||||
| }; | ||||
|  | ||||
| constexpr StringToUint8 LIGHT_FUNCTIONS_BY_STR[] = { | ||||
|     {"off", LIGHT_FUNCTION_OFF}, | ||||
|     {"below", LIGHT_FUNCTION_BELOW}, | ||||
|     {"above", LIGHT_FUNCTION_ABOVE}, | ||||
| }; | ||||
|  | ||||
| constexpr Uint8ToString LIGHT_FUNCTIONS_BY_UINT[] = { | ||||
|     {LIGHT_FUNCTION_OFF, "off"}, | ||||
|     {LIGHT_FUNCTION_BELOW, "below"}, | ||||
|     {LIGHT_FUNCTION_ABOVE, "above"}, | ||||
| }; | ||||
|  | ||||
| constexpr StringToUint8 OUT_PIN_LEVELS_BY_STR[] = { | ||||
|     {"low", OUT_PIN_LEVEL_LOW}, | ||||
|     {"high", OUT_PIN_LEVEL_HIGH}, | ||||
| }; | ||||
|  | ||||
| constexpr Uint8ToString OUT_PIN_LEVELS_BY_UINT[] = { | ||||
|     {OUT_PIN_LEVEL_LOW, "low"}, | ||||
|     {OUT_PIN_LEVEL_HIGH, "high"}, | ||||
| }; | ||||
|  | ||||
| // Helper functions for lookups | ||||
| template<size_t N> uint8_t find_uint8(const StringToUint8 (&arr)[N], const std::string &str) { | ||||
|   for (const auto &entry : arr) { | ||||
|     if (str == entry.str) | ||||
|       return entry.value; | ||||
|   } | ||||
|   return 0xFF;  // Not found | ||||
| } | ||||
|  | ||||
| template<size_t N> const char *find_str(const Uint8ToString (&arr)[N], uint8_t value) { | ||||
|   for (const auto &entry : arr) { | ||||
|     if (value == entry.value) | ||||
|       return entry.str; | ||||
|   } | ||||
|   return "";  // Not found | ||||
| } | ||||
|  | ||||
| // Commands | ||||
| static const uint8_t CMD_ENABLE_CONF = 0xFF; | ||||
| static const uint8_t CMD_DISABLE_CONF = 0xFE; | ||||
| static const uint8_t CMD_ENABLE_ENG = 0x62; | ||||
| static const uint8_t CMD_DISABLE_ENG = 0x63; | ||||
| static const uint8_t CMD_MAXDIST_DURATION = 0x60; | ||||
| static const uint8_t CMD_QUERY = 0x61; | ||||
| static const uint8_t CMD_GATE_SENS = 0x64; | ||||
| static const uint8_t CMD_VERSION = 0xA0; | ||||
| static const uint8_t CMD_QUERY_DISTANCE_RESOLUTION = 0xAB; | ||||
| static const uint8_t CMD_SET_DISTANCE_RESOLUTION = 0xAA; | ||||
| static const uint8_t CMD_QUERY_LIGHT_CONTROL = 0xAE; | ||||
| static const uint8_t CMD_SET_LIGHT_CONTROL = 0xAD; | ||||
| static const uint8_t CMD_SET_BAUD_RATE = 0xA1; | ||||
| static const uint8_t CMD_BT_PASSWORD = 0xA9; | ||||
| static const uint8_t CMD_MAC = 0xA5; | ||||
| static const uint8_t CMD_RESET = 0xA2; | ||||
| static const uint8_t CMD_RESTART = 0xA3; | ||||
| static const uint8_t CMD_BLUETOOTH = 0xA4; | ||||
| // Commands values | ||||
| static const uint8_t CMD_MAX_MOVE_VALUE = 0x00; | ||||
| static const uint8_t CMD_MAX_STILL_VALUE = 0x01; | ||||
| static const uint8_t CMD_DURATION_VALUE = 0x02; | ||||
| // 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}; | ||||
|  | ||||
| static inline int two_byte_to_int(char firstbyte, char secondbyte) { return (int16_t) (secondbyte << 8) + firstbyte; } | ||||
|  | ||||
| void LD2410Component::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "LD2410:"); | ||||
| @@ -78,7 +233,7 @@ void LD2410Component::dump_config() { | ||||
|                 "  Throttle: %ums\n" | ||||
|                 "  MAC address: %s\n" | ||||
|                 "  Firmware version: %s", | ||||
|                 this->throttle_, const_cast<char *>(this->mac_.c_str()), const_cast<char *>(this->version_.c_str())); | ||||
|                 this->throttle_, this->mac_ == NO_MAC ? UNKNOWN_MAC : this->mac_.c_str(), this->version_.c_str()); | ||||
| } | ||||
|  | ||||
| void LD2410Component::setup() { | ||||
| @@ -200,7 +355,7 @@ void LD2410Component::handle_periodic_data_(uint8_t *buffer, int len) { | ||||
|   */ | ||||
| #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]); | ||||
|     int new_moving_target_distance = ld2410::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); | ||||
|   } | ||||
| @@ -210,7 +365,7 @@ void LD2410Component::handle_periodic_data_(uint8_t *buffer, int len) { | ||||
|       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]); | ||||
|     int new_still_target_distance = ld2410::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); | ||||
|   } | ||||
| @@ -220,7 +375,7 @@ void LD2410Component::handle_periodic_data_(uint8_t *buffer, int len) { | ||||
|       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]); | ||||
|     int new_detect_distance = ld2410::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); | ||||
|   } | ||||
| @@ -282,25 +437,6 @@ void LD2410Component::handle_periodic_data_(uint8_t *buffer, int len) { | ||||
| #endif | ||||
| } | ||||
|  | ||||
| const char VERSION_FMT[] = "%u.%02X.%02X%02X%02X%02X"; | ||||
|  | ||||
| std::string format_version(uint8_t *buffer) { | ||||
|   std::string::size_type version_size = 256; | ||||
|   std::string version; | ||||
|   do { | ||||
|     version.resize(version_size + 1); | ||||
|     version_size = std::snprintf(&version[0], version.size(), VERSION_FMT, buffer[13], buffer[12], buffer[17], | ||||
|                                  buffer[16], buffer[15], buffer[14]); | ||||
|   } while (version_size + 1 > version.size()); | ||||
|   version.resize(version_size); | ||||
|   return version; | ||||
| } | ||||
|  | ||||
| const char MAC_FMT[] = "%02X:%02X:%02X:%02X:%02X:%02X"; | ||||
|  | ||||
| const std::string UNKNOWN_MAC("unknown"); | ||||
| const std::string NO_MAC("08:05:04:03:02:01"); | ||||
|  | ||||
| #ifdef USE_NUMBER | ||||
| std::function<void(void)> set_number_value(number::Number *n, float value) { | ||||
|   float normalized_value = value * 1.0; | ||||
| @@ -326,7 +462,7 @@ bool LD2410Component::handle_ack_data_(uint8_t *buffer, int len) { | ||||
|     ESP_LOGE(TAG, "Invalid status"); | ||||
|     return true; | ||||
|   } | ||||
|   if (this->two_byte_to_int_(buffer[8], buffer[9]) != 0x00) { | ||||
|   if (ld2410::two_byte_to_int(buffer[8], buffer[9]) != 0x00) { | ||||
|     ESP_LOGE(TAG, "Invalid command: %u, %u", buffer[8], buffer[9]); | ||||
|     return true; | ||||
|   } | ||||
| @@ -347,8 +483,8 @@ bool LD2410Component::handle_ack_data_(uint8_t *buffer, int len) { | ||||
| #endif | ||||
|       break; | ||||
|     case lowbyte(CMD_VERSION): | ||||
|       this->version_ = format_version(buffer); | ||||
|       ESP_LOGV(TAG, "Firmware version: %s", const_cast<char *>(this->version_.c_str())); | ||||
|       this->version_ = str_sprintf(VERSION_FMT, buffer[13], buffer[12], buffer[17], buffer[16], buffer[15], buffer[14]); | ||||
|       ESP_LOGV(TAG, "Firmware version: %s", this->version_.c_str()); | ||||
| #ifdef USE_TEXT_SENSOR | ||||
|       if (this->version_text_sensor_ != nullptr) { | ||||
|         this->version_text_sensor_->publish_state(this->version_); | ||||
| @@ -357,8 +493,8 @@ bool LD2410Component::handle_ack_data_(uint8_t *buffer, int len) { | ||||
|       break; | ||||
|     case lowbyte(CMD_QUERY_DISTANCE_RESOLUTION): { | ||||
|       std::string distance_resolution = | ||||
|           DISTANCE_RESOLUTION_INT_TO_ENUM.at(this->two_byte_to_int_(buffer[10], buffer[11])); | ||||
|       ESP_LOGV(TAG, "Distance resolution: %s", const_cast<char *>(distance_resolution.c_str())); | ||||
|           find_str(DISTANCE_RESOLUTIONS_BY_UINT, ld2410::two_byte_to_int(buffer[10], buffer[11])); | ||||
|       ESP_LOGV(TAG, "Distance resolution: %s", distance_resolution.c_str()); | ||||
| #ifdef USE_SELECT | ||||
|       if (this->distance_resolution_select_ != nullptr && | ||||
|           this->distance_resolution_select_->state != distance_resolution) { | ||||
| @@ -367,9 +503,9 @@ bool LD2410Component::handle_ack_data_(uint8_t *buffer, int len) { | ||||
| #endif | ||||
|     } break; | ||||
|     case lowbyte(CMD_QUERY_LIGHT_CONTROL): { | ||||
|       this->light_function_ = LIGHT_FUNCTION_INT_TO_ENUM.at(buffer[10]); | ||||
|       this->light_function_ = find_str(LIGHT_FUNCTIONS_BY_UINT, buffer[10]); | ||||
|       this->light_threshold_ = buffer[11] * 1.0; | ||||
|       this->out_pin_level_ = OUT_PIN_LEVEL_INT_TO_ENUM.at(buffer[12]); | ||||
|       this->out_pin_level_ = find_str(OUT_PIN_LEVELS_BY_UINT, buffer[12]); | ||||
|       ESP_LOGV(TAG, "Light function: %s", const_cast<char *>(this->light_function_.c_str())); | ||||
|       ESP_LOGV(TAG, "Light threshold: %f", this->light_threshold_); | ||||
|       ESP_LOGV(TAG, "Out pin level: %s", const_cast<char *>(this->out_pin_level_.c_str())); | ||||
| @@ -402,7 +538,7 @@ bool LD2410Component::handle_ack_data_(uint8_t *buffer, int len) { | ||||
| #endif | ||||
| #ifdef USE_SWITCH | ||||
|       if (this->bluetooth_switch_ != nullptr) { | ||||
|         this->bluetooth_switch_->publish_state(this->mac_ != UNKNOWN_MAC); | ||||
|         this->bluetooth_switch_->publish_state(this->mac_ != NO_MAC); | ||||
|       } | ||||
| #endif | ||||
|       break; | ||||
| @@ -448,7 +584,7 @@ bool LD2410Component::handle_ack_data_(uint8_t *buffer, int len) { | ||||
|       /* | ||||
|         None Duration: 33~34th bytes | ||||
|       */ | ||||
|       updates.push_back(set_number_value(this->timeout_number_, this->two_byte_to_int_(buffer[32], buffer[33]))); | ||||
|       updates.push_back(set_number_value(this->timeout_number_, ld2410::two_byte_to_int(buffer[32], buffer[33]))); | ||||
|       for (auto &update : updates) { | ||||
|         update(); | ||||
|       } | ||||
| @@ -505,14 +641,14 @@ void LD2410Component::set_bluetooth(bool enable) { | ||||
|  | ||||
| void LD2410Component::set_distance_resolution(const std::string &state) { | ||||
|   this->set_config_mode_(true); | ||||
|   uint8_t cmd_value[2] = {DISTANCE_RESOLUTION_ENUM_TO_INT.at(state), 0x00}; | ||||
|   uint8_t cmd_value[2] = {find_uint8(DISTANCE_RESOLUTIONS_BY_STR, state), 0x00}; | ||||
|   this->send_command_(CMD_SET_DISTANCE_RESOLUTION, cmd_value, 2); | ||||
|   this->set_timeout(200, [this]() { this->restart_and_read_all_info(); }); | ||||
| } | ||||
|  | ||||
| void LD2410Component::set_baud_rate(const std::string &state) { | ||||
|   this->set_config_mode_(true); | ||||
|   uint8_t cmd_value[2] = {BAUD_RATE_ENUM_TO_INT.at(state), 0x00}; | ||||
|   uint8_t cmd_value[2] = {find_uint8(BAUD_RATES_BY_STR, state), 0x00}; | ||||
|   this->send_command_(CMD_SET_BAUD_RATE, cmd_value, 2); | ||||
|   this->set_timeout(200, [this]() { this->restart_(); }); | ||||
| } | ||||
| @@ -646,9 +782,9 @@ void LD2410Component::set_light_out_control() { | ||||
|     return; | ||||
|   } | ||||
|   this->set_config_mode_(true); | ||||
|   uint8_t light_function = LIGHT_FUNCTION_ENUM_TO_INT.at(this->light_function_); | ||||
|   uint8_t light_function = find_uint8(LIGHT_FUNCTIONS_BY_STR, this->light_function_); | ||||
|   uint8_t light_threshold = static_cast<uint8_t>(this->light_threshold_); | ||||
|   uint8_t out_pin_level = OUT_PIN_LEVEL_ENUM_TO_INT.at(this->out_pin_level_); | ||||
|   uint8_t out_pin_level = find_uint8(OUT_PIN_LEVELS_BY_STR, this->out_pin_level_); | ||||
|   uint8_t value[4] = {light_function, light_threshold, out_pin_level, 0x00}; | ||||
|   this->send_command_(CMD_SET_LIGHT_CONTROL, value, 4); | ||||
|   delay(50);  // NOLINT | ||||
|   | ||||
| @@ -26,114 +26,9 @@ | ||||
| #include "esphome/core/automation.h" | ||||
| #include "esphome/core/helpers.h" | ||||
|  | ||||
| #include <map> | ||||
|  | ||||
| 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_ENABLE_ENG = 0x0062; | ||||
| static const uint8_t CMD_DISABLE_ENG = 0x0063; | ||||
| 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; | ||||
| static const uint8_t CMD_QUERY_DISTANCE_RESOLUTION = 0x00AB; | ||||
| static const uint8_t CMD_SET_DISTANCE_RESOLUTION = 0x00AA; | ||||
| static const uint8_t CMD_QUERY_LIGHT_CONTROL = 0x00AE; | ||||
| static const uint8_t CMD_SET_LIGHT_CONTROL = 0x00AD; | ||||
| static const uint8_t CMD_SET_BAUD_RATE = 0x00A1; | ||||
| static const uint8_t CMD_BT_PASSWORD = 0x00A9; | ||||
| static const uint8_t CMD_MAC = 0x00A5; | ||||
| static const uint8_t CMD_RESET = 0x00A2; | ||||
| static const uint8_t CMD_RESTART = 0x00A3; | ||||
| static const uint8_t CMD_BLUETOOTH = 0x00A4; | ||||
|  | ||||
| enum BaudRateStructure : uint8_t { | ||||
|   BAUD_RATE_9600 = 1, | ||||
|   BAUD_RATE_19200 = 2, | ||||
|   BAUD_RATE_38400 = 3, | ||||
|   BAUD_RATE_57600 = 4, | ||||
|   BAUD_RATE_115200 = 5, | ||||
|   BAUD_RATE_230400 = 6, | ||||
|   BAUD_RATE_256000 = 7, | ||||
|   BAUD_RATE_460800 = 8 | ||||
| }; | ||||
|  | ||||
| static const std::map<std::string, uint8_t> BAUD_RATE_ENUM_TO_INT{ | ||||
|     {"9600", BAUD_RATE_9600},     {"19200", BAUD_RATE_19200},   {"38400", BAUD_RATE_38400}, | ||||
|     {"57600", BAUD_RATE_57600},   {"115200", BAUD_RATE_115200}, {"230400", BAUD_RATE_230400}, | ||||
|     {"256000", BAUD_RATE_256000}, {"460800", BAUD_RATE_460800}}; | ||||
|  | ||||
| enum DistanceResolutionStructure : uint8_t { DISTANCE_RESOLUTION_0_2 = 0x01, DISTANCE_RESOLUTION_0_75 = 0x00 }; | ||||
|  | ||||
| static const std::map<std::string, uint8_t> DISTANCE_RESOLUTION_ENUM_TO_INT{{"0.2m", DISTANCE_RESOLUTION_0_2}, | ||||
|                                                                             {"0.75m", DISTANCE_RESOLUTION_0_75}}; | ||||
| static const std::map<uint8_t, std::string> DISTANCE_RESOLUTION_INT_TO_ENUM{{DISTANCE_RESOLUTION_0_2, "0.2m"}, | ||||
|                                                                             {DISTANCE_RESOLUTION_0_75, "0.75m"}}; | ||||
|  | ||||
| enum LightFunctionStructure : uint8_t { | ||||
|   LIGHT_FUNCTION_OFF = 0x00, | ||||
|   LIGHT_FUNCTION_BELOW = 0x01, | ||||
|   LIGHT_FUNCTION_ABOVE = 0x02 | ||||
| }; | ||||
|  | ||||
| static const std::map<std::string, uint8_t> LIGHT_FUNCTION_ENUM_TO_INT{ | ||||
|     {"off", LIGHT_FUNCTION_OFF}, {"below", LIGHT_FUNCTION_BELOW}, {"above", LIGHT_FUNCTION_ABOVE}}; | ||||
| static const std::map<uint8_t, std::string> LIGHT_FUNCTION_INT_TO_ENUM{ | ||||
|     {LIGHT_FUNCTION_OFF, "off"}, {LIGHT_FUNCTION_BELOW, "below"}, {LIGHT_FUNCTION_ABOVE, "above"}}; | ||||
|  | ||||
| enum OutPinLevelStructure : uint8_t { OUT_PIN_LEVEL_LOW = 0x00, OUT_PIN_LEVEL_HIGH = 0x01 }; | ||||
|  | ||||
| static const std::map<std::string, uint8_t> OUT_PIN_LEVEL_ENUM_TO_INT{{"low", OUT_PIN_LEVEL_LOW}, | ||||
|                                                                       {"high", OUT_PIN_LEVEL_HIGH}}; | ||||
| static const std::map<uint8_t, std::string> OUT_PIN_LEVEL_INT_TO_ENUM{{OUT_PIN_LEVEL_LOW, "low"}, | ||||
|                                                                       {OUT_PIN_LEVEL_HIGH, "high"}}; | ||||
|  | ||||
| // 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 = 6, | ||||
|   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, | ||||
|   MOVING_SENSOR_START = 19, | ||||
|   STILL_SENSOR_START = 28, | ||||
|   LIGHT_SENSOR = 37, | ||||
|   OUT_PIN_SENSOR = 38, | ||||
| }; | ||||
| 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) | ||||
| @@ -176,7 +71,6 @@ class LD2410Component : public Component, public uart::UARTDevice { | ||||
| #endif | ||||
|  | ||||
|  public: | ||||
|   LD2410Component(); | ||||
|   void setup() override; | ||||
|   void dump_config() override; | ||||
|   void loop() override; | ||||
| @@ -202,7 +96,6 @@ class LD2410Component : public Component, public uart::UARTDevice { | ||||
|   void factory_reset(); | ||||
|  | ||||
|  protected: | ||||
|   int two_byte_to_int_(char firstbyte, char secondbyte) { return (int16_t) (secondbyte << 8) + firstbyte; } | ||||
|   void send_command_(uint8_t command_str, const uint8_t *command_value, int command_value_len); | ||||
|   void set_config_mode_(bool enable); | ||||
|   void handle_periodic_data_(uint8_t *buffer, int len); | ||||
| @@ -215,14 +108,14 @@ class LD2410Component : public Component, public uart::UARTDevice { | ||||
|   void get_light_control_(); | ||||
|   void restart_(); | ||||
|  | ||||
|   int32_t last_periodic_millis_ = millis(); | ||||
|   int32_t last_engineering_mode_change_millis_ = millis(); | ||||
|   int32_t last_periodic_millis_ = 0; | ||||
|   int32_t last_engineering_mode_change_millis_ = 0; | ||||
|   uint16_t throttle_; | ||||
|   float light_threshold_ = -1; | ||||
|   std::string version_; | ||||
|   std::string mac_; | ||||
|   std::string out_pin_level_; | ||||
|   std::string light_function_; | ||||
|   float light_threshold_ = -1; | ||||
| #ifdef USE_NUMBER | ||||
|   std::vector<number::Number *> gate_still_threshold_numbers_ = std::vector<number::Number *>(9); | ||||
|   std::vector<number::Number *> gate_move_threshold_numbers_ = std::vector<number::Number *>(9); | ||||
|   | ||||
| @@ -21,20 +21,105 @@ static const char *const NO_MAC = "08:05:04:03:02:01"; | ||||
| static const char *const UNKNOWN_MAC = "unknown"; | ||||
| static const char *const VERSION_FMT = "%u.%02X.%02X%02X%02X%02X"; | ||||
|  | ||||
| enum BaudRateStructure : uint8_t { | ||||
|   BAUD_RATE_9600 = 1, | ||||
|   BAUD_RATE_19200 = 2, | ||||
|   BAUD_RATE_38400 = 3, | ||||
|   BAUD_RATE_57600 = 4, | ||||
|   BAUD_RATE_115200 = 5, | ||||
|   BAUD_RATE_230400 = 6, | ||||
|   BAUD_RATE_256000 = 7, | ||||
|   BAUD_RATE_460800 = 8 | ||||
| }; | ||||
|  | ||||
| // Zone type struct | ||||
| enum ZoneTypeStructure : uint8_t { | ||||
|   ZONE_DISABLED = 0, | ||||
|   ZONE_DETECTION = 1, | ||||
|   ZONE_FILTER = 2, | ||||
| }; | ||||
|  | ||||
| enum PeriodicDataStructure : uint8_t { | ||||
|   TARGET_X = 4, | ||||
|   TARGET_Y = 6, | ||||
|   TARGET_SPEED = 8, | ||||
|   TARGET_RESOLUTION = 10, | ||||
| }; | ||||
|  | ||||
| enum PeriodicDataValue : uint8_t { | ||||
|   HEAD = 0xAA, | ||||
|   END = 0x55, | ||||
|   CHECK = 0x00, | ||||
| }; | ||||
|  | ||||
| enum AckDataStructure : uint8_t { | ||||
|   COMMAND = 6, | ||||
|   COMMAND_STATUS = 7, | ||||
| }; | ||||
|  | ||||
| // Memory-efficient lookup tables | ||||
| struct StringToUint8 { | ||||
|   const char *str; | ||||
|   uint8_t value; | ||||
| }; | ||||
|  | ||||
| struct Uint8ToString { | ||||
|   uint8_t value; | ||||
|   const char *str; | ||||
| }; | ||||
|  | ||||
| constexpr StringToUint8 BAUD_RATES_BY_STR[] = { | ||||
|     {"9600", BAUD_RATE_9600},     {"19200", BAUD_RATE_19200},   {"38400", BAUD_RATE_38400}, | ||||
|     {"57600", BAUD_RATE_57600},   {"115200", BAUD_RATE_115200}, {"230400", BAUD_RATE_230400}, | ||||
|     {"256000", BAUD_RATE_256000}, {"460800", BAUD_RATE_460800}, | ||||
| }; | ||||
|  | ||||
| constexpr Uint8ToString ZONE_TYPE_BY_UINT[] = { | ||||
|     {ZONE_DISABLED, "Disabled"}, | ||||
|     {ZONE_DETECTION, "Detection"}, | ||||
|     {ZONE_FILTER, "Filter"}, | ||||
| }; | ||||
|  | ||||
| constexpr StringToUint8 ZONE_TYPE_BY_STR[] = { | ||||
|     {"Disabled", ZONE_DISABLED}, | ||||
|     {"Detection", ZONE_DETECTION}, | ||||
|     {"Filter", ZONE_FILTER}, | ||||
| }; | ||||
|  | ||||
| // Helper functions for lookups | ||||
| template<size_t N> uint8_t find_uint8(const StringToUint8 (&arr)[N], const std::string &str) { | ||||
|   for (const auto &entry : arr) { | ||||
|     if (str == entry.str) | ||||
|       return entry.value; | ||||
|   } | ||||
|   return 0xFF;  // Not found | ||||
| } | ||||
|  | ||||
| template<size_t N> const char *find_str(const Uint8ToString (&arr)[N], uint8_t value) { | ||||
|   for (const auto &entry : arr) { | ||||
|     if (value == entry.value) | ||||
|       return entry.str; | ||||
|   } | ||||
|   return "";  // Not found | ||||
| } | ||||
|  | ||||
| // LD2450 serial 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}; | ||||
| // LD2450 UART Serial Commands | ||||
| static const uint8_t CMD_ENABLE_CONF = 0x00FF; | ||||
| static const uint8_t CMD_DISABLE_CONF = 0x00FE; | ||||
| static const uint8_t CMD_VERSION = 0x00A0; | ||||
| static const uint8_t CMD_MAC = 0x00A5; | ||||
| static const uint8_t CMD_RESET = 0x00A2; | ||||
| static const uint8_t CMD_RESTART = 0x00A3; | ||||
| static const uint8_t CMD_BLUETOOTH = 0x00A4; | ||||
| static const uint8_t CMD_SINGLE_TARGET_MODE = 0x0080; | ||||
| static const uint8_t CMD_MULTI_TARGET_MODE = 0x0090; | ||||
| static const uint8_t CMD_QUERY_TARGET_MODE = 0x0091; | ||||
| static const uint8_t CMD_SET_BAUD_RATE = 0x00A1; | ||||
| static const uint8_t CMD_QUERY_ZONE = 0x00C1; | ||||
| static const uint8_t CMD_SET_ZONE = 0x00C2; | ||||
| static const uint8_t CMD_ENABLE_CONF = 0xFF; | ||||
| static const uint8_t CMD_DISABLE_CONF = 0xFE; | ||||
| static const uint8_t CMD_VERSION = 0xA0; | ||||
| static const uint8_t CMD_MAC = 0xA5; | ||||
| static const uint8_t CMD_RESET = 0xA2; | ||||
| static const uint8_t CMD_RESTART = 0xA3; | ||||
| static const uint8_t CMD_BLUETOOTH = 0xA4; | ||||
| static const uint8_t CMD_SINGLE_TARGET_MODE = 0x80; | ||||
| static const uint8_t CMD_MULTI_TARGET_MODE = 0x90; | ||||
| static const uint8_t CMD_QUERY_TARGET_MODE = 0x91; | ||||
| static const uint8_t CMD_SET_BAUD_RATE = 0xA1; | ||||
| static const uint8_t CMD_QUERY_ZONE = 0xC1; | ||||
| static const uint8_t CMD_SET_ZONE = 0xC2; | ||||
|  | ||||
| static inline uint16_t convert_seconds_to_ms(uint16_t value) { return value * 1000; }; | ||||
|  | ||||
| @@ -720,7 +805,7 @@ void LD2450Component::set_bluetooth(bool enable) { | ||||
| // Set Baud rate | ||||
| void LD2450Component::set_baud_rate(const std::string &state) { | ||||
|   this->set_config_mode_(true); | ||||
|   uint8_t cmd_value[2] = {BAUD_RATE_ENUM_TO_INT.at(state), 0x00}; | ||||
|   uint8_t cmd_value[2] = {find_uint8(BAUD_RATES_BY_STR, state), 0x00}; | ||||
|   this->send_command_(CMD_SET_BAUD_RATE, cmd_value, 2); | ||||
|   this->set_timeout(200, [this]() { this->restart_(); }); | ||||
| } | ||||
| @@ -728,7 +813,7 @@ void LD2450Component::set_baud_rate(const std::string &state) { | ||||
| // Set Zone Type - one of: Disabled, Detection, Filter | ||||
| void LD2450Component::set_zone_type(const std::string &state) { | ||||
|   ESP_LOGV(TAG, "Set zone type: %s", state.c_str()); | ||||
|   uint8_t zone_type = ZONE_TYPE_ENUM_TO_INT.at(state); | ||||
|   uint8_t zone_type = find_uint8(ZONE_TYPE_BY_STR, state); | ||||
|   this->zone_type_ = zone_type; | ||||
|   this->send_set_zone_command_(); | ||||
| } | ||||
| @@ -736,7 +821,7 @@ void LD2450Component::set_zone_type(const std::string &state) { | ||||
| // Publish Zone Type to Select component | ||||
| void LD2450Component::publish_zone_type() { | ||||
| #ifdef USE_SELECT | ||||
|   std::string zone_type = ZONE_TYPE_INT_TO_ENUM.at(static_cast<ZoneTypeStructure>(this->zone_type_)); | ||||
|   std::string zone_type = find_str(ZONE_TYPE_BY_UINT, this->zone_type_); | ||||
|   if (this->zone_type_select_ != nullptr) { | ||||
|     this->zone_type_select_->publish_state(zone_type); | ||||
|   } | ||||
|   | ||||
| @@ -1,7 +1,5 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <iomanip> | ||||
| #include <map> | ||||
| #include "esphome/components/uart/uart.h" | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/defines.h" | ||||
| @@ -66,49 +64,6 @@ struct ZoneOfNumbers { | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| enum BaudRateStructure : uint8_t { | ||||
|   BAUD_RATE_9600 = 1, | ||||
|   BAUD_RATE_19200 = 2, | ||||
|   BAUD_RATE_38400 = 3, | ||||
|   BAUD_RATE_57600 = 4, | ||||
|   BAUD_RATE_115200 = 5, | ||||
|   BAUD_RATE_230400 = 6, | ||||
|   BAUD_RATE_256000 = 7, | ||||
|   BAUD_RATE_460800 = 8 | ||||
| }; | ||||
|  | ||||
| // Convert baud rate enum to int | ||||
| static const std::map<std::string, uint8_t> BAUD_RATE_ENUM_TO_INT{ | ||||
|     {"9600", BAUD_RATE_9600},     {"19200", BAUD_RATE_19200},   {"38400", BAUD_RATE_38400}, | ||||
|     {"57600", BAUD_RATE_57600},   {"115200", BAUD_RATE_115200}, {"230400", BAUD_RATE_230400}, | ||||
|     {"256000", BAUD_RATE_256000}, {"460800", BAUD_RATE_460800}}; | ||||
|  | ||||
| // Zone type struct | ||||
| enum ZoneTypeStructure : uint8_t { ZONE_DISABLED = 0, ZONE_DETECTION = 1, ZONE_FILTER = 2 }; | ||||
|  | ||||
| // Convert zone type int to enum | ||||
| static const std::map<ZoneTypeStructure, std::string> ZONE_TYPE_INT_TO_ENUM{ | ||||
|     {ZONE_DISABLED, "Disabled"}, {ZONE_DETECTION, "Detection"}, {ZONE_FILTER, "Filter"}}; | ||||
|  | ||||
| // Convert zone type enum to int | ||||
| static const std::map<std::string, uint8_t> ZONE_TYPE_ENUM_TO_INT{ | ||||
|     {"Disabled", ZONE_DISABLED}, {"Detection", ZONE_DETECTION}, {"Filter", ZONE_FILTER}}; | ||||
|  | ||||
| // LD2450 serial 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}; | ||||
|  | ||||
| enum PeriodicDataStructure : uint8_t { | ||||
|   TARGET_X = 4, | ||||
|   TARGET_Y = 6, | ||||
|   TARGET_SPEED = 8, | ||||
|   TARGET_RESOLUTION = 10, | ||||
| }; | ||||
|  | ||||
| enum PeriodicDataValue : uint8_t { HEAD = 0xAA, END = 0x55, CHECK = 0x00 }; | ||||
|  | ||||
| enum AckDataStructure : uint8_t { COMMAND = 6, COMMAND_STATUS = 7 }; | ||||
|  | ||||
| class LD2450Component : public Component, public uart::UARTDevice { | ||||
| #ifdef USE_SENSOR | ||||
|   SUB_SENSOR(target_count) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user