diff --git a/esphome/components/seeed_mr60fda2/binary_sensor.py b/esphome/components/seeed_mr60fda2/binary_sensor.py index dc11005c11..1abb026926 100644 --- a/esphome/components/seeed_mr60fda2/binary_sensor.py +++ b/esphome/components/seeed_mr60fda2/binary_sensor.py @@ -1,24 +1,33 @@ import esphome.codegen as cg from esphome.components import binary_sensor import esphome.config_validation as cv -from esphome.const import DEVICE_CLASS_OCCUPANCY +from esphome.const import DEVICE_CLASS_OCCUPANCY, DEVICE_CLASS_SAFETY from . import CONF_MR60FDA2_ID, MR60FDA2Component DEPENDENCIES = ["seeed_mr60fda2"] CONF_PEOPLE_EXIST = "people_exist" +CONF_IS_FALL = "is_fall" CONFIG_SCHEMA = { cv.GenerateID(CONF_MR60FDA2_ID): cv.use_id(MR60FDA2Component), cv.Optional(CONF_PEOPLE_EXIST): binary_sensor.binary_sensor_schema( device_class=DEVICE_CLASS_OCCUPANCY, icon="mdi:motion-sensor" ), + cv.Optional(CONF_IS_FALL): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_SAFETY, icon="mdi:emergency" + ), } async def to_code(config): mr60fda2_component = await cg.get_variable(config[CONF_MR60FDA2_ID]) + if people_exist_config := config.get(CONF_PEOPLE_EXIST): sens = await binary_sensor.new_binary_sensor(people_exist_config) cg.add(mr60fda2_component.set_people_exist_binary_sensor(sens)) + + if is_fall_config := config.get(CONF_IS_FALL): + sens = await binary_sensor.new_binary_sensor(is_fall_config) + cg.add(mr60fda2_component.set_is_fall_binary_sensor(sens)) \ No newline at end of file diff --git a/esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp b/esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp index d3e5491437..7cf57d1642 100644 --- a/esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp +++ b/esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp @@ -14,6 +14,7 @@ void MR60FDA2Component::dump_config() { ESP_LOGCONFIG(TAG, "MR60FDA2:"); #ifdef USE_BINARY_SENSOR LOG_BINARY_SENSOR(" ", "People Exist Binary Sensor", this->people_exist_binary_sensor_); + LOG_BINARY_SENSOR(" ", "Is Fall Binary Sensor", this->is_fall_binary_sensor_); #endif #ifdef USE_BUTTON LOG_BUTTON(" ", "Get Radar Parameters Button", this->get_radar_parameters_button_); @@ -24,9 +25,6 @@ void MR60FDA2Component::dump_config() { LOG_SELECT(" ", "Height Threshold Select", this->height_threshold_select_); LOG_SELECT(" ", "Sensitivity Select", this->sensitivity_select_); #endif -#ifdef USE_TEXT_SENSOR - LOG_TEXT_SENSOR(" ", "Is Fall Text Sensor", this->is_fall_text_sensor_); -#endif } // Initialisation functions @@ -73,7 +71,7 @@ void MR60FDA2Component::loop() { * @param len The length of the byte array. * @return The calculated checksum. */ -uint8_t MR60FDA2Component::calculate_checksum_(const uint8_t *data, size_t len) { +static uint8_t calculate_checksum_(const uint8_t *data, size_t len) { uint8_t checksum = 0; for (size_t i = 0; i < len; i++) { checksum ^= data[i]; @@ -93,11 +91,11 @@ uint8_t MR60FDA2Component::calculate_checksum_(const uint8_t *data, size_t len) * @param expected_checksum The expected checksum. * @return True if the checksum is valid, false otherwise. */ -bool MR60FDA2Component::validate_checksum_(const uint8_t *data, size_t len, uint8_t expected_checksum) { +static bool validate_checksum_(const uint8_t *data, size_t len, uint8_t expected_checksum) { return calculate_checksum_(data, len) == expected_checksum; } -uint8_t MR60FDA2Component::find_nearest_index_(float value, const float *arr, int size) { +static uint8_t find_nearest_index_(float value, const float *arr, int size) { int nearest_index = 0; float min_diff = std::abs(value - arr[0]); for (int i = 1; i < size; ++i) { @@ -167,8 +165,8 @@ void MR60FDA2Component::split_frame_(uint8_t buffer) { this->current_frame_type_ += buffer; if ((this->current_frame_type_ == IS_FALL_TYPE_BUFFER) || (this->current_frame_type_ == PEOPLE_EXIST_TYPE_BUFFER) || - (this->current_frame_type_ == RUSULT_INSTALL_HEIGHT) || (this->current_frame_type_ == RUSULT_PARAMETERS) || - (this->current_frame_type_ == RUSULT_HEIGHT_THRESHOLD) || (this->current_frame_type_ == RUSULT_SENSITIVITY)) { + (this->current_frame_type_ == RESULT_INSTALL_HEIGHT) || (this->current_frame_type_ == RESULT_PARAMETERS) || + (this->current_frame_type_ == RESULT_HEIGHT_THRESHOLD) || (this->current_frame_type_ == RESULT_SENSITIVITY)) { this->current_frame_len_++; this->current_frame_buf_[this->current_frame_len_ - 1] = buffer; this->current_frame_locate_++; @@ -183,22 +181,14 @@ void MR60FDA2Component::split_frame_(uint8_t buffer) { } break; case LOCATE_HEAD_CKSUM_FRAME: - if (this->validate_checksum_(this->current_frame_buf_, this->current_frame_len_, buffer)) { + if (validate_checksum_(this->current_frame_buf_, this->current_frame_len_, buffer)) { this->current_frame_len_++; this->current_frame_buf_[this->current_frame_len_ - 1] = buffer; this->current_frame_locate_++; } else { ESP_LOGD(TAG, "HEAD_CKSUM_FRAME ERROR: 0x%02x", buffer); - ESP_LOGD(TAG, "GET CURRENT_FRAME: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", - this->current_frame_buf_[this->current_frame_len_ - 9], - this->current_frame_buf_[this->current_frame_len_ - 8], - this->current_frame_buf_[this->current_frame_len_ - 7], - this->current_frame_buf_[this->current_frame_len_ - 6], - this->current_frame_buf_[this->current_frame_len_ - 5], - this->current_frame_buf_[this->current_frame_len_ - 4], - this->current_frame_buf_[this->current_frame_len_ - 3], - this->current_frame_buf_[this->current_frame_len_ - 2], - this->current_frame_buf_[this->current_frame_len_ - 1], buffer); + ESP_LOGV(TAG, "FRAME: %s", format_hex_pretty(this->current_frame_buf_, this->current_frame_len_).c_str(), + buffer); this->current_frame_locate_ = LOCATE_FRAME_HEADER; } break; @@ -215,23 +205,15 @@ void MR60FDA2Component::split_frame_(uint8_t buffer) { } break; case LOCATE_DATA_CKSUM_FRAME: - if (this->validate_checksum_(this->current_data_buf_, this->current_data_frame_len_, buffer)) { + if (validate_checksum_(this->current_data_buf_, this->current_data_frame_len_, buffer)) { this->current_frame_len_++; this->current_frame_buf_[this->current_frame_len_ - 1] = buffer; this->current_frame_locate_++; this->process_frame_(); } else { ESP_LOGD(TAG, "DATA_CKSUM_FRAME ERROR: 0x%02x", buffer); - ESP_LOGD(TAG, "GET CURRENT_FRAME: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", - this->current_frame_buf_[this->current_frame_len_ - 9], - this->current_frame_buf_[this->current_frame_len_ - 8], - this->current_frame_buf_[this->current_frame_len_ - 7], - this->current_frame_buf_[this->current_frame_len_ - 6], - this->current_frame_buf_[this->current_frame_len_ - 5], - this->current_frame_buf_[this->current_frame_len_ - 4], - this->current_frame_buf_[this->current_frame_len_ - 3], - this->current_frame_buf_[this->current_frame_len_ - 2], - this->current_frame_buf_[this->current_frame_len_ - 1], buffer); + ESP_LOGV(TAG, "GET CURRENT_FRAME: %s", + format_hex_pretty(this->current_frame_buf_, this->current_frame_len_).c_str(), buffer); this->current_frame_locate_ = LOCATE_FRAME_HEADER; } break; @@ -243,12 +225,8 @@ void MR60FDA2Component::split_frame_(uint8_t buffer) { void MR60FDA2Component::process_frame_() { switch (this->current_frame_type_) { case IS_FALL_TYPE_BUFFER: - if (this->is_fall_text_sensor_ != nullptr) { - if (this->current_frame_buf_[LEN_TO_HEAD_CKSUM] == 0) { - this->is_fall_text_sensor_->publish_state("Normal"); - } else if (this->current_frame_buf_[LEN_TO_HEAD_CKSUM] == 1) { - this->is_fall_text_sensor_->publish_state("Falling"); - } + if (this->is_fall_binary_sensor_ != nullptr) { + this->is_fall_binary_sensor_->publish_state(this->current_frame_buf_[LEN_TO_HEAD_CKSUM]); } this->current_frame_locate_ = LOCATE_FRAME_HEADER; break; @@ -257,7 +235,7 @@ void MR60FDA2Component::process_frame_() { this->people_exist_binary_sensor_->publish_state(this->current_frame_buf_[LEN_TO_HEAD_CKSUM]); this->current_frame_locate_ = LOCATE_FRAME_HEADER; break; - case RUSULT_INSTALL_HEIGHT: + case RESULT_INSTALL_HEIGHT: if (this->current_data_buf_[0]) { ESP_LOGD(TAG, "Successfully set the mounting height"); } else { @@ -265,7 +243,7 @@ void MR60FDA2Component::process_frame_() { } this->current_frame_locate_ = LOCATE_FRAME_HEADER; break; - case RUSULT_HEIGHT_THRESHOLD: + case RESULT_HEIGHT_THRESHOLD: if (this->current_data_buf_[0]) { ESP_LOGD(TAG, "Successfully set the height threshold"); } else { @@ -273,7 +251,7 @@ void MR60FDA2Component::process_frame_() { } this->current_frame_locate_ = LOCATE_FRAME_HEADER; break; - case RUSULT_SENSITIVITY: + case RESULT_SENSITIVITY: if (this->current_data_buf_[0]) { ESP_LOGD(TAG, "Successfully set the sensitivity"); } else { @@ -281,7 +259,7 @@ void MR60FDA2Component::process_frame_() { } this->current_frame_locate_ = LOCATE_FRAME_HEADER; break; - case RUSULT_PARAMETERS: + case RESULT_PARAMETERS: // ESP_LOGD( // TAG, // "GET CURRENT_FRAME: 0x%02x 0x%02x 0x%02x 0x%02x, 0x%02x 0x%02x 0x%02x 0x%02x, 0x%02x 0x%02x 0x%02x 0x%02x", @@ -297,24 +275,21 @@ void MR60FDA2Component::process_frame_() { // this->current_data_buf_[6], this->current_data_buf_[7], this->current_data_buf_[8], // this->current_data_buf_[9], this->current_data_buf_[10], this->current_data_buf_[11]); this->current_install_height_int_ = - (static_cast(current_data_buf_[3]) << 24) | (static_cast(current_data_buf_[2]) << 16) | - (static_cast(current_data_buf_[1]) << 8) | static_cast(current_data_buf_[0]); + encode_uint32(current_data_buf_[3], current_data_buf_[2], current_data_buf_[1], current_data_buf_[0]); float install_height_float; memcpy(&install_height_float, ¤t_install_height_int_, sizeof(float)); select_index_ = find_nearest_index_(install_height_float, INSTALL_HEIGHT, 7); - this->install_height_select_->publish_state(INSTALL_HEIGHT_STR[select_index_]); + this->install_height_select_->publish_state(this->install_height_select_.at(select_index_)); this->current_height_threshold_int_ = - (static_cast(current_data_buf_[7]) << 24) | (static_cast(current_data_buf_[6]) << 16) | - (static_cast(current_data_buf_[5]) << 8) | static_cast(current_data_buf_[4]); + encode_uint32(current_data_buf_[7], current_data_buf_[6], current_data_buf_[5], current_data_buf_[4]); float height_threshold_float; memcpy(&height_threshold_float, ¤t_height_threshold_int_, sizeof(float)); select_index_ = find_nearest_index_(height_threshold_float, HEIGHT_THRESHOLD, 7); - this->height_threshold_select_->publish_state(HEIGHT_THRESHOLD_STR[select_index_]); + this->height_threshold_select_->publish_state(this->height_threshold_select_.at(select_index_)); this->current_sensitivity_ = - (static_cast(current_data_buf_[11]) << 24) | (static_cast(current_data_buf_[10]) << 16) | - (static_cast(current_data_buf_[9]) << 8) | static_cast(current_data_buf_[8]); + encode_uint32(current_data_buf_[11], current_data_buf_[10], current_data_buf_[9], current_data_buf_[8]); select_index_ = find_nearest_index_(this->current_sensitivity_, SENSITIVITY, 3); - this->sensitivity_select_->publish_state(SENSITIVITY_STR[select_index_]); + this->sensitivity_select_->publish_state(this->sensitivity_select_.at(select_index_)); ESP_LOGD(TAG, "Mounting height: %.2f, Height threshold: %.2f, Sensitivity: %u", install_height_float, height_threshold_float, this->current_sensitivity_); this->current_frame_locate_ = LOCATE_FRAME_HEADER; @@ -373,11 +348,7 @@ void MR60FDA2Component::set_install_height(uint8_t index) { send_data[12] = calculate_checksum_(data_frame, 4); this->send_query_(send_data, 13); - ESP_LOGD(TAG, - "SEND INSTALL HEIGHT FRAME: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x " - "0x%02x 0x%02x", - send_data[0], send_data[1], send_data[2], send_data[3], send_data[4], send_data[5], send_data[6], - send_data[7], send_data[8], send_data[9], send_data[10], send_data[11], send_data[12]); + ESP_LOGV(TAG, "SEND INSTALL HEIGHT FRAME: %s", format_hex_pretty(send_data, 13).c_str()); } void MR60FDA2Component::set_height_threshold(uint8_t index) { @@ -392,11 +363,7 @@ void MR60FDA2Component::set_height_threshold(uint8_t index) { send_data[12] = calculate_checksum_(data_frame, 4); this->send_query_(send_data, 13); - ESP_LOGD(TAG, - "SEND HEIGHT THRESHOLD: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x " - "0x%02x 0x%02x", - send_data[0], send_data[1], send_data[2], send_data[3], send_data[4], send_data[5], send_data[6], - send_data[7], send_data[8], send_data[9], send_data[10], send_data[11], send_data[12]); + ESP_LOGV(TAG, "SEND HEIGHT THRESHOLD: %s", format_hex_pretty(send_data, 13).c_str()); } void MR60FDA2Component::set_sensitivity(uint8_t index) { @@ -411,25 +378,19 @@ void MR60FDA2Component::set_sensitivity(uint8_t index) { send_data[12] = calculate_checksum_(data_frame, 4); this->send_query_(send_data, 13); - ESP_LOGD(TAG, - "SEND SET SENSITIVITY: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x " - "0x%02x 0x%02x", - send_data[0], send_data[1], send_data[2], send_data[3], send_data[4], send_data[5], send_data[6], - send_data[7], send_data[8], send_data[9], send_data[10], send_data[11], send_data[12]); + ESP_LOGV(TAG, "SEND SET SENSITIVITY: %s", format_hex_pretty(send_data, 13).c_str()); } void MR60FDA2Component::get_radar_parameters() { uint8_t send_data[8] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x06, 0xF6}; this->send_query_(send_data, 8); - ESP_LOGD(TAG, "SEND GET PARAMETERS: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", send_data[0], - send_data[1], send_data[2], send_data[3], send_data[4], send_data[5], send_data[6], send_data[7]); + ESP_LOGV(TAG, "SEND GET PARAMETERS: %s", format_hex_pretty(send_data, 8).c_str()); } void MR60FDA2Component::reset_radar() { uint8_t send_data[8] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x21, 0x10, 0xCF}; this->send_query_(send_data, 8); - ESP_LOGD(TAG, "SEND RESET: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", send_data[0], send_data[1], - send_data[2], send_data[3], send_data[4], send_data[5], send_data[6], send_data[7]); + ESP_LOGV(TAG, "SEND RESET: %s", format_hex_pretty(send_data, 8).c_str()); this->get_radar_parameters(); } diff --git a/esphome/components/seeed_mr60fda2/seeed_mr60fda2.h b/esphome/components/seeed_mr60fda2/seeed_mr60fda2.h index e5fef35267..25e7caea59 100644 --- a/esphome/components/seeed_mr60fda2/seeed_mr60fda2.h +++ b/esphome/components/seeed_mr60fda2/seeed_mr60fda2.h @@ -30,10 +30,10 @@ static const uint8_t LEN_TO_DATA_FRAME = 9; static const uint8_t FRAME_HEADER_BUFFER = 0x01; static const uint16_t IS_FALL_TYPE_BUFFER = 0x0E02; static const uint16_t PEOPLE_EXIST_TYPE_BUFFER = 0x0F09; -static const uint16_t RUSULT_INSTALL_HEIGHT = 0x0E04; -static const uint16_t RUSULT_PARAMETERS = 0x0E06; -static const uint16_t RUSULT_HEIGHT_THRESHOLD = 0x0E08; -static const uint16_t RUSULT_SENSITIVITY = 0x0E0A; +static const uint16_t RESULT_INSTALL_HEIGHT = 0x0E04; +static const uint16_t RESULT_PARAMETERS = 0x0E06; +static const uint16_t RESULT_HEIGHT_THRESHOLD = 0x0E08; +static const uint16_t RESULT_SENSITIVITY = 0x0E0A; enum FrameLocation { LOCATE_FRAME_HEADER, @@ -61,6 +61,7 @@ class MR60FDA2Component : public Component, public uart::UARTDevice { // The class name must be the name defined by text_sensor.py #ifdef USE_BINARY_SENSOR SUB_BINARY_SENSOR(people_exist) + SUB_BINARY_SENSOR(is_fall) #endif #ifdef USE_BUTTON SUB_BUTTON(get_radar_parameters) @@ -71,9 +72,6 @@ class MR60FDA2Component : public Component, SUB_SELECT(height_threshold) SUB_SELECT(sensitivity) #endif -#ifdef USE_TEXT_SENSOR - SUB_TEXT_SENSOR(is_fall) -#endif protected: uint8_t current_frame_locate_; @@ -88,14 +86,11 @@ class MR60FDA2Component : public Component, uint8_t current_sensitivity_; uint8_t select_index_; - bool validate_checksum_(const uint8_t *data, size_t len, uint8_t expected_checksum); - uint8_t calculate_checksum_(const uint8_t *data, size_t len); void split_frame_(uint8_t buffer); void process_frame_(); void send_query_(uint8_t *query, size_t string_length); void float_to_bytes_(float value, unsigned char *bytes); void int_to_bytes_(uint32_t value, unsigned char *bytes); - uint8_t find_nearest_index_(float value, const float *arr, int size); public: float get_setup_priority() const override { return esphome::setup_priority::LATE; }