ESPHome  2024.11.3
seeed_mr24hpc1.cpp
Go to the documentation of this file.
1 #include "seeed_mr24hpc1.h"
2 
3 #include "esphome/core/log.h"
4 
5 #include <utility>
6 
7 namespace esphome {
8 namespace seeed_mr24hpc1 {
9 
10 static const char *const TAG = "seeed_mr24hpc1";
11 
12 // Prints the component's configuration data. dump_config() prints all of the component's configuration
13 // items in an easy-to-read format, including the configuration key-value pairs.
15  ESP_LOGCONFIG(TAG, "MR24HPC1:");
16 #ifdef USE_TEXT_SENSOR
17  LOG_TEXT_SENSOR(" ", "Heartbeat Text Sensor", this->heartbeat_state_text_sensor_);
18  LOG_TEXT_SENSOR(" ", "Product Model Text Sensor", this->product_model_text_sensor_);
19  LOG_TEXT_SENSOR(" ", "Product ID Text Sensor", this->product_id_text_sensor_);
20  LOG_TEXT_SENSOR(" ", "Hardware Model Text Sensor", this->hardware_model_text_sensor_);
21  LOG_TEXT_SENSOR(" ", "Firware Verison Text Sensor", this->firware_version_text_sensor_);
22  LOG_TEXT_SENSOR(" ", "Keep Away Text Sensor", this->keep_away_text_sensor_);
23  LOG_TEXT_SENSOR(" ", "Motion Status Text Sensor", this->motion_status_text_sensor_);
24  LOG_TEXT_SENSOR(" ", "Custom Mode End Text Sensor", this->custom_mode_end_text_sensor_);
25 #endif
26 #ifdef USE_BINARY_SENSOR
27  LOG_BINARY_SENSOR(" ", "Has Target Binary Sensor", this->has_target_binary_sensor_);
28 #endif
29 #ifdef USE_SENSOR
30  LOG_SENSOR(" ", "Custom Presence Of Detection Sensor", this->custom_presence_of_detection_sensor_);
31  LOG_SENSOR(" ", "Movement Signs Sensor", this->movement_signs_sensor_);
32  LOG_SENSOR(" ", "Custom Motion Distance Sensor", this->custom_motion_distance_sensor_);
33  LOG_SENSOR(" ", "Custom Spatial Static Sensor", this->custom_spatial_static_value_sensor_);
34  LOG_SENSOR(" ", "Custom Spatial Motion Sensor", this->custom_spatial_motion_value_sensor_);
35  LOG_SENSOR(" ", "Custom Motion Speed Sensor", this->custom_motion_speed_sensor_);
36  LOG_SENSOR(" ", "Custom Mode Num Sensor", this->custom_mode_num_sensor_);
37 #endif
38 #ifdef USE_SWITCH
39  LOG_SWITCH(" ", "Underly Open Function Switch", this->underlying_open_function_switch_);
40 #endif
41 #ifdef USE_BUTTON
42  LOG_BUTTON(" ", "Restart Button", this->restart_button_);
43  LOG_BUTTON(" ", "Custom Set End Button", this->custom_set_end_button_);
44 #endif
45 #ifdef USE_SELECT
46  LOG_SELECT(" ", "Scene Mode Select", this->scene_mode_select_);
47  LOG_SELECT(" ", "Unman Time Select", this->unman_time_select_);
48  LOG_SELECT(" ", "Existence Boundary Select", this->existence_boundary_select_);
49  LOG_SELECT(" ", "Motion Boundary Select", this->motion_boundary_select_);
50 #endif
51 #ifdef USE_NUMBER
52  LOG_NUMBER(" ", "Sensitivity Number", this->sensitivity_number_);
53  LOG_NUMBER(" ", "Custom Mode Number", this->custom_mode_number_);
54  LOG_NUMBER(" ", "Existence Threshold Number", this->existence_threshold_number_);
55  LOG_NUMBER(" ", "Motion Threshold Number", this->motion_threshold_number_);
56  LOG_NUMBER(" ", "Motion Trigger Time Number", this->motion_trigger_number_);
57  LOG_NUMBER(" ", "Motion To Rest Time Number", this->motion_to_rest_number_);
58  LOG_NUMBER(" ", "Custom Unman Time Number", this->custom_unman_time_number_);
59 #endif
60 }
61 
62 // Initialisation functions
64  ESP_LOGCONFIG(TAG, "Setting up MR24HPC1...");
65  this->check_uart_settings(115200);
66 
67  if (this->custom_mode_number_ != nullptr) {
68  this->custom_mode_number_->publish_state(0); // Zero out the custom mode
69  }
70  if (this->custom_mode_num_sensor_ != nullptr) {
71  this->custom_mode_num_sensor_->publish_state(0);
72  }
73  if (this->custom_mode_end_text_sensor_ != nullptr) {
74  this->custom_mode_end_text_sensor_->publish_state("Not in custom mode");
75  }
76  this->set_custom_end_mode();
77  this->poll_time_base_func_check_ = true;
78  this->check_dev_inf_sign_ = true;
79  this->sg_start_query_data_ = STANDARD_FUNCTION_QUERY_PRODUCT_MODE;
80  this->sg_data_len_ = 0;
81  this->sg_frame_len_ = 0;
82  this->sg_recv_data_state_ = FRAME_IDLE;
83  this->s_output_info_switch_flag_ = OUTPUT_SWITCH_INIT;
84 
85  memset(this->c_product_mode_, 0, PRODUCT_BUF_MAX_SIZE);
86  memset(this->c_product_id_, 0, PRODUCT_BUF_MAX_SIZE);
87  memset(this->c_firmware_version_, 0, PRODUCT_BUF_MAX_SIZE);
88  memset(this->c_hardware_model_, 0, PRODUCT_BUF_MAX_SIZE);
89  memset(this->sg_frame_prase_buf_, 0, FRAME_BUF_MAX_SIZE);
90  memset(this->sg_frame_buf_, 0, FRAME_BUF_MAX_SIZE);
91 
92  this->set_interval(8000, [this]() { this->update_(); });
93  ESP_LOGCONFIG(TAG, "Set up MR24HPC1 complete");
94 }
95 
96 // Timed polling of radar data
97 void MR24HPC1Component::update_() {
98  this->get_radar_output_information_switch(); // Query the key status every so often
99  this->poll_time_base_func_check_ = true; // Query the base functionality information at regular intervals
100 }
101 
102 // main loop
104  uint8_t byte;
105 
106  // Is there data on the serial port
107  while (this->available()) {
108  this->read_byte(&byte);
109  this->r24_split_data_frame_(byte); // split data frame
110  }
111 
112  if ((this->s_output_info_switch_flag_ == OUTPUT_SWTICH_OFF) &&
113  (this->sg_start_query_data_ > CUSTOM_FUNCTION_QUERY_TIME_OF_ENTER_UNMANNED) && (!this->check_dev_inf_sign_)) {
114  this->sg_start_query_data_ = STANDARD_FUNCTION_QUERY_SCENE_MODE;
115  } else if ((this->s_output_info_switch_flag_ == OUTPUT_SWITCH_ON) &&
116  (this->sg_start_query_data_ < CUSTOM_FUNCTION_QUERY_EXISTENCE_BOUNDARY) && (!this->check_dev_inf_sign_)) {
117  this->sg_start_query_data_ = CUSTOM_FUNCTION_QUERY_EXISTENCE_BOUNDARY;
118  } else if (this->check_dev_inf_sign_ && (this->sg_start_query_data_ > STANDARD_FUNCTION_QUERY_HARDWARE_MODE)) {
119  // First time power up information polling
120  this->sg_start_query_data_ = STANDARD_FUNCTION_QUERY_PRODUCT_MODE;
121  }
122 
123  // Polling Functions
124  if (this->poll_time_base_func_check_) {
125  switch (this->sg_start_query_data_) {
127  this->get_product_mode();
128  this->sg_start_query_data_++;
129  break;
131  this->get_product_id();
132  this->sg_start_query_data_++;
133  break;
135  this->get_product_mode();
136  this->get_product_id();
137  this->get_firmware_version();
138  this->sg_start_query_data_++;
139  break;
140  case STANDARD_FUNCTION_QUERY_HARDWARE_MODE: // Above is the equipment information
141  this->get_product_mode();
142  this->get_product_id();
143  this->get_hardware_model();
144  this->sg_start_query_data_++;
145  this->check_dev_inf_sign_ = false;
146  break;
148  this->get_scene_mode();
149  this->sg_start_query_data_++;
150  break;
152  this->get_sensitivity();
153  this->sg_start_query_data_++;
154  break;
156  this->get_unmanned_time();
157  this->sg_start_query_data_++;
158  break;
160  this->get_human_status();
161  this->sg_start_query_data_++;
162  break;
164  this->get_human_motion_info();
165  this->sg_start_query_data_++;
166  break;
168  this->get_body_motion_params();
169  this->sg_start_query_data_++;
170  break;
171  case STANDARD_FUNCTION_QUERY_KEEPAWAY_STATUS: // The above is the basic functional information
172  this->get_keep_away();
173  this->sg_start_query_data_++;
174  break;
176  this->get_custom_mode();
177  this->sg_start_query_data_++;
178  break;
180  this->get_heartbeat_packet();
181  this->sg_start_query_data_++;
182  break;
184  this->get_existence_boundary();
185  this->sg_start_query_data_++;
186  break;
188  this->get_motion_boundary();
189  this->sg_start_query_data_++;
190  break;
192  this->get_existence_threshold();
193  this->sg_start_query_data_++;
194  break;
196  this->get_motion_threshold();
197  this->sg_start_query_data_++;
198  break;
200  this->get_motion_trigger_time();
201  this->sg_start_query_data_++;
202  break;
204  this->get_motion_to_rest_time();
205  this->sg_start_query_data_++;
206  break;
208  this->get_custom_unman_time();
209  this->sg_start_query_data_++;
210  if (this->s_output_info_switch_flag_ == OUTPUT_SWTICH_OFF) {
211  this->poll_time_base_func_check_ = false; // Avoiding high-speed polling that can cause the device to jam
212  }
213  break;
215  this->get_human_status();
216  this->sg_start_query_data_++;
217  break;
219  this->get_spatial_static_value();
220  this->sg_start_query_data_++;
221  break;
223  this->get_spatial_motion_value();
224  this->sg_start_query_data_++;
225  break;
228  this->sg_start_query_data_++;
229  break;
232  this->sg_start_query_data_++;
233  break;
236  this->sg_start_query_data_++;
237  this->poll_time_base_func_check_ = false; // Avoiding high-speed polling that can cause the device to jam
238  break;
239  default:
240  break;
241  }
242  }
243 }
244 
245 // Calculate CRC check digit
246 static uint8_t get_frame_crc_sum(const uint8_t *data, int len) {
247  unsigned int crc_sum = 0;
248  for (int i = 0; i < len - 3; i++) {
249  crc_sum += data[i];
250  }
251  return crc_sum & 0xff;
252 }
253 
254 // Check that the check digit is correct
255 static int get_frame_check_status(uint8_t *data, int len) {
256  uint8_t crc_sum = get_frame_crc_sum(data, len);
257  uint8_t verified = data[len - 3];
258  return (verified == crc_sum) ? 1 : 0;
259 }
260 
261 // split data frame
262 void MR24HPC1Component::r24_split_data_frame_(uint8_t value) {
263  switch (this->sg_recv_data_state_) {
264  case FRAME_IDLE: // starting value
265  if (FRAME_HEADER1_VALUE == value) {
266  this->sg_recv_data_state_ = FRAME_HEADER2;
267  }
268  break;
269  case FRAME_HEADER2:
270  if (FRAME_HEADER2_VALUE == value) {
271  this->sg_frame_buf_[0] = FRAME_HEADER1_VALUE;
272  this->sg_frame_buf_[1] = FRAME_HEADER2_VALUE;
273  this->sg_recv_data_state_ = FRAME_CTL_WORD;
274  } else {
275  this->sg_recv_data_state_ = FRAME_IDLE;
276  ESP_LOGD(TAG, "FRAME_IDLE ERROR value:%x", value);
277  }
278  break;
279  case FRAME_CTL_WORD:
280  this->sg_frame_buf_[2] = value;
281  this->sg_recv_data_state_ = FRAME_CMD_WORD;
282  break;
283  case FRAME_CMD_WORD:
284  this->sg_frame_buf_[3] = value;
285  this->sg_recv_data_state_ = FRAME_DATA_LEN_H;
286  break;
287  case FRAME_DATA_LEN_H:
288  if (value <= 4) {
289  this->sg_data_len_ = value * 256;
290  this->sg_frame_buf_[4] = value;
291  this->sg_recv_data_state_ = FRAME_DATA_LEN_L;
292  } else {
293  this->sg_data_len_ = 0;
294  this->sg_recv_data_state_ = FRAME_IDLE;
295  ESP_LOGD(TAG, "FRAME_DATA_LEN_H ERROR value:%x", value);
296  }
297  break;
298  case FRAME_DATA_LEN_L:
299  this->sg_data_len_ += value;
300  if (this->sg_data_len_ > 32) {
301  ESP_LOGD(TAG, "len=%d, FRAME_DATA_LEN_L ERROR value:%x", this->sg_data_len_, value);
302  this->sg_data_len_ = 0;
303  this->sg_recv_data_state_ = FRAME_IDLE;
304  } else {
305  this->sg_frame_buf_[5] = value;
306  this->sg_frame_len_ = 6;
307  this->sg_recv_data_state_ = FRAME_DATA_BYTES;
308  }
309  break;
310  case FRAME_DATA_BYTES:
311  this->sg_data_len_ -= 1;
312  this->sg_frame_buf_[this->sg_frame_len_++] = value;
313  if (this->sg_data_len_ <= 0) {
314  this->sg_recv_data_state_ = FRAME_DATA_CRC;
315  }
316  break;
317  case FRAME_DATA_CRC:
318  this->sg_frame_buf_[this->sg_frame_len_++] = value;
319  this->sg_recv_data_state_ = FRAME_TAIL1;
320  break;
321  case FRAME_TAIL1:
322  if (FRAME_TAIL1_VALUE == value) {
323  this->sg_recv_data_state_ = FRAME_TAIL2;
324  } else {
325  this->sg_recv_data_state_ = FRAME_IDLE;
326  this->sg_frame_len_ = 0;
327  this->sg_data_len_ = 0;
328  ESP_LOGD(TAG, "FRAME_TAIL1 ERROR value:%x", value);
329  }
330  break;
331  case FRAME_TAIL2:
332  if (FRAME_TAIL2_VALUE == value) {
333  this->sg_frame_buf_[this->sg_frame_len_++] = FRAME_TAIL1_VALUE;
334  this->sg_frame_buf_[this->sg_frame_len_++] = FRAME_TAIL2_VALUE;
335  memcpy(this->sg_frame_prase_buf_, this->sg_frame_buf_, this->sg_frame_len_);
336  if (get_frame_check_status(this->sg_frame_prase_buf_, this->sg_frame_len_)) {
337  this->r24_parse_data_frame_(this->sg_frame_prase_buf_, this->sg_frame_len_);
338  } else {
339  ESP_LOGD(TAG, "frame check failer!");
340  }
341  } else {
342  ESP_LOGD(TAG, "FRAME_TAIL2 ERROR value:%x", value);
343  }
344  memset(this->sg_frame_prase_buf_, 0, FRAME_BUF_MAX_SIZE);
345  memset(this->sg_frame_buf_, 0, FRAME_BUF_MAX_SIZE);
346  this->sg_frame_len_ = 0;
347  this->sg_data_len_ = 0;
348  this->sg_recv_data_state_ = FRAME_IDLE;
349  break;
350  default:
351  this->sg_recv_data_state_ = FRAME_IDLE;
352  }
353 }
354 
355 // Parses data frames related to product information
356 void MR24HPC1Component::r24_frame_parse_product_information_(uint8_t *data) {
357  uint16_t product_len = encode_uint16(data[FRAME_COMMAND_WORD_INDEX + 1], data[FRAME_COMMAND_WORD_INDEX + 2]);
358  if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_PRODUCT_MODE) {
359  if ((this->product_model_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) {
360  memset(this->c_product_mode_, 0, PRODUCT_BUF_MAX_SIZE);
361  memcpy(this->c_product_mode_, &data[FRAME_DATA_INDEX], product_len);
362  this->product_model_text_sensor_->publish_state(this->c_product_mode_);
363  } else {
364  ESP_LOGD(TAG, "Reply: get product_mode error!");
365  }
366  } else if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_PRODUCT_ID) {
367  if ((this->product_id_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) {
368  memset(this->c_product_id_, 0, PRODUCT_BUF_MAX_SIZE);
369  memcpy(this->c_product_id_, &data[FRAME_DATA_INDEX], product_len);
370  this->product_id_text_sensor_->publish_state(this->c_product_id_);
371  } else {
372  ESP_LOGD(TAG, "Reply: get productId error!");
373  }
374  } else if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_HARDWARE_MODEL) {
375  if ((this->hardware_model_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) {
376  memset(this->c_hardware_model_, 0, PRODUCT_BUF_MAX_SIZE);
377  memcpy(this->c_hardware_model_, &data[FRAME_DATA_INDEX], product_len);
378  this->hardware_model_text_sensor_->publish_state(this->c_hardware_model_);
379  ESP_LOGD(TAG, "Reply: get hardware_model :%s", this->c_hardware_model_);
380  } else {
381  ESP_LOGD(TAG, "Reply: get hardwareModel error!");
382  }
383  } else if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_FIRMWARE_VERSION) {
384  if ((this->firware_version_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) {
385  memset(this->c_firmware_version_, 0, PRODUCT_BUF_MAX_SIZE);
386  memcpy(this->c_firmware_version_, &data[FRAME_DATA_INDEX], product_len);
387  this->firware_version_text_sensor_->publish_state(this->c_firmware_version_);
388  } else {
389  ESP_LOGD(TAG, "Reply: get firmwareVersion error!");
390  }
391  }
392 }
393 
394 // Parsing the underlying open parameters
395 void MR24HPC1Component::r24_frame_parse_open_underlying_information_(uint8_t *data) {
396  if (data[FRAME_COMMAND_WORD_INDEX] == 0x00) {
397  if (this->underlying_open_function_switch_ != nullptr) {
398  this->underlying_open_function_switch_->publish_state(
399  data[FRAME_DATA_INDEX]); // Underlying Open Parameter Switch Status Updates
400  }
401  if (data[FRAME_DATA_INDEX]) {
402  this->s_output_info_switch_flag_ = OUTPUT_SWITCH_ON;
403  } else {
404  this->s_output_info_switch_flag_ = OUTPUT_SWTICH_OFF;
405  }
406  } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x01) {
407  if (this->custom_spatial_static_value_sensor_ != nullptr) {
408  this->custom_spatial_static_value_sensor_->publish_state(data[FRAME_DATA_INDEX]);
409  }
410  if (this->custom_presence_of_detection_sensor_ != nullptr) {
411  this->custom_presence_of_detection_sensor_->publish_state(data[FRAME_DATA_INDEX + 1] * 0.5f);
412  }
413  if (this->custom_spatial_motion_value_sensor_ != nullptr) {
414  this->custom_spatial_motion_value_sensor_->publish_state(data[FRAME_DATA_INDEX + 2]);
415  }
416  if (this->custom_motion_distance_sensor_ != nullptr) {
417  this->custom_motion_distance_sensor_->publish_state(data[FRAME_DATA_INDEX + 3] * 0.5f);
418  }
419  if (this->custom_motion_speed_sensor_ != nullptr) {
420  this->custom_motion_speed_sensor_->publish_state((data[FRAME_DATA_INDEX + 4] - 10) * 0.5f);
421  }
422  } else if ((data[FRAME_COMMAND_WORD_INDEX] == 0x06) || (data[FRAME_COMMAND_WORD_INDEX] == 0x86)) {
423  // none:0x00 close_to:0x01 far_away:0x02
424  if ((this->keep_away_text_sensor_ != nullptr) && (data[FRAME_DATA_INDEX] < 3)) {
425  this->keep_away_text_sensor_->publish_state(S_KEEP_AWAY_STR[data[FRAME_DATA_INDEX]]);
426  }
427  } else if ((this->movement_signs_sensor_ != nullptr) &&
428  ((data[FRAME_COMMAND_WORD_INDEX] == 0x07) || (data[FRAME_COMMAND_WORD_INDEX] == 0x87))) {
429  this->movement_signs_sensor_->publish_state(data[FRAME_DATA_INDEX]);
430  } else if ((this->existence_threshold_number_ != nullptr) &&
431  ((data[FRAME_COMMAND_WORD_INDEX] == 0x08) || (data[FRAME_COMMAND_WORD_INDEX] == 0x88))) {
432  this->existence_threshold_number_->publish_state(data[FRAME_DATA_INDEX]);
433  } else if ((this->motion_threshold_number_ != nullptr) &&
434  ((data[FRAME_COMMAND_WORD_INDEX] == 0x09) || (data[FRAME_COMMAND_WORD_INDEX] == 0x89))) {
435  this->motion_threshold_number_->publish_state(data[FRAME_DATA_INDEX]);
436  } else if ((this->existence_boundary_select_ != nullptr) &&
437  ((data[FRAME_COMMAND_WORD_INDEX] == 0x0a) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8a))) {
438  if (this->existence_boundary_select_->has_index(data[FRAME_DATA_INDEX] - 1)) {
439  this->existence_boundary_select_->publish_state(S_BOUNDARY_STR[data[FRAME_DATA_INDEX] - 1]);
440  }
441  } else if ((this->motion_boundary_select_ != nullptr) &&
442  ((data[FRAME_COMMAND_WORD_INDEX] == 0x0b) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8b))) {
443  if (this->motion_boundary_select_->has_index(data[FRAME_DATA_INDEX] - 1)) {
444  this->motion_boundary_select_->publish_state(S_BOUNDARY_STR[data[FRAME_DATA_INDEX] - 1]);
445  }
446  } else if ((this->motion_trigger_number_ != nullptr) &&
447  ((data[FRAME_COMMAND_WORD_INDEX] == 0x0c) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8c))) {
448  uint32_t motion_trigger_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1],
449  data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]);
450  this->motion_trigger_number_->publish_state(motion_trigger_time);
451  } else if ((this->motion_to_rest_number_ != nullptr) &&
452  ((data[FRAME_COMMAND_WORD_INDEX] == 0x0d) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8d))) {
453  uint32_t move_to_rest_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1],
454  data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]);
455  this->motion_to_rest_number_->publish_state(move_to_rest_time);
456  } else if ((this->custom_unman_time_number_ != nullptr) &&
457  ((data[FRAME_COMMAND_WORD_INDEX] == 0x0e) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8e))) {
458  uint32_t enter_unmanned_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1],
459  data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]);
460  float custom_unmanned_time = enter_unmanned_time / 1000.0;
461  this->custom_unman_time_number_->publish_state(custom_unmanned_time);
462  } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x80) {
463  if (data[FRAME_DATA_INDEX]) {
464  this->s_output_info_switch_flag_ = OUTPUT_SWITCH_ON;
465  } else {
466  this->s_output_info_switch_flag_ = OUTPUT_SWTICH_OFF;
467  }
468  if (this->underlying_open_function_switch_ != nullptr) {
469  this->underlying_open_function_switch_->publish_state(data[FRAME_DATA_INDEX]);
470  }
471  } else if ((this->custom_spatial_static_value_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x81)) {
472  this->custom_spatial_static_value_sensor_->publish_state(data[FRAME_DATA_INDEX]);
473  } else if ((this->custom_spatial_motion_value_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x82)) {
474  this->custom_spatial_motion_value_sensor_->publish_state(data[FRAME_DATA_INDEX]);
475  } else if ((this->custom_presence_of_detection_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x83)) {
476  this->custom_presence_of_detection_sensor_->publish_state(
477  S_PRESENCE_OF_DETECTION_RANGE_STR[data[FRAME_DATA_INDEX]]);
478  } else if ((this->custom_motion_distance_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x84)) {
479  this->custom_motion_distance_sensor_->publish_state(data[FRAME_DATA_INDEX] * 0.5f);
480  } else if ((this->custom_motion_speed_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x85)) {
481  this->custom_motion_speed_sensor_->publish_state((data[FRAME_DATA_INDEX] - 10) * 0.5f);
482  }
483 }
484 
485 void MR24HPC1Component::r24_parse_data_frame_(uint8_t *data, uint8_t len) {
486  switch (data[FRAME_CONTROL_WORD_INDEX]) {
487  case 0x01: {
488  if ((this->heartbeat_state_text_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x01)) {
489  this->heartbeat_state_text_sensor_->publish_state("Equipment Normal");
490  } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x02) {
491  ESP_LOGD(TAG, "Reply: query restart packet");
492  } else if (this->heartbeat_state_text_sensor_ != nullptr) {
493  this->heartbeat_state_text_sensor_->publish_state("Equipment Abnormal");
494  }
495  } break;
496  case 0x02: {
497  this->r24_frame_parse_product_information_(data);
498  } break;
499  case 0x05: {
500  this->r24_frame_parse_work_status_(data);
501  } break;
502  case 0x08: {
503  this->r24_frame_parse_open_underlying_information_(data);
504  } break;
505  case 0x80: {
506  this->r24_frame_parse_human_information_(data);
507  } break;
508  default:
509  ESP_LOGD(TAG, "control word:0x%02X not found", data[FRAME_CONTROL_WORD_INDEX]);
510  break;
511  }
512 }
513 
514 void MR24HPC1Component::r24_frame_parse_work_status_(uint8_t *data) {
515  if (data[FRAME_COMMAND_WORD_INDEX] == 0x01) {
516  ESP_LOGD(TAG, "Reply: get radar init status 0x%02X", data[FRAME_DATA_INDEX]);
517  } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x07) {
518  if ((this->scene_mode_select_ != nullptr) && (this->scene_mode_select_->has_index(data[FRAME_DATA_INDEX]))) {
519  this->scene_mode_select_->publish_state(S_SCENE_STR[data[FRAME_DATA_INDEX]]);
520  } else {
521  ESP_LOGD(TAG, "Select has index offset %d Error", data[FRAME_DATA_INDEX]);
522  }
523  } else if ((this->sensitivity_number_ != nullptr) &&
524  ((data[FRAME_COMMAND_WORD_INDEX] == 0x08) || (data[FRAME_COMMAND_WORD_INDEX] == 0x88))) {
525  // 1-3
526  this->sensitivity_number_->publish_state(data[FRAME_DATA_INDEX]);
527  } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x09) {
528  // 1-4
529  if (this->custom_mode_num_sensor_ != nullptr) {
530  this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]);
531  }
532  if (this->custom_mode_number_ != nullptr) {
533  this->custom_mode_number_->publish_state(0);
534  }
535  if (this->custom_mode_end_text_sensor_ != nullptr) {
536  this->custom_mode_end_text_sensor_->publish_state("Setup in progress...");
537  }
538  } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x81) {
539  ESP_LOGD(TAG, "Reply: get radar init status 0x%02X", data[FRAME_DATA_INDEX]);
540  } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x87) {
541  if ((this->scene_mode_select_ != nullptr) && (this->scene_mode_select_->has_index(data[FRAME_DATA_INDEX]))) {
542  this->scene_mode_select_->publish_state(S_SCENE_STR[data[FRAME_DATA_INDEX]]);
543  } else {
544  ESP_LOGD(TAG, "Select has index offset %d Error", data[FRAME_DATA_INDEX]);
545  }
546  } else if ((this->custom_mode_end_text_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x0A)) {
547  this->custom_mode_end_text_sensor_->publish_state("Set Success!");
548  } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x89) {
549  if (data[FRAME_DATA_INDEX] == 0) {
550  if (this->custom_mode_end_text_sensor_ != nullptr) {
551  this->custom_mode_end_text_sensor_->publish_state("Not in custom mode");
552  }
553  if (this->custom_mode_number_ != nullptr) {
554  this->custom_mode_number_->publish_state(0);
555  }
556  if (this->custom_mode_num_sensor_ != nullptr) {
557  this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]);
558  }
559  } else {
560  if (this->custom_mode_num_sensor_ != nullptr) {
561  this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]);
562  }
563  }
564  } else {
565  ESP_LOGD(TAG, "[%s] No found COMMAND_WORD(%02X) in Frame", __FUNCTION__, data[FRAME_COMMAND_WORD_INDEX]);
566  }
567 }
568 
569 void MR24HPC1Component::r24_frame_parse_human_information_(uint8_t *data) {
570  if ((this->has_target_binary_sensor_ != nullptr) &&
571  ((data[FRAME_COMMAND_WORD_INDEX] == 0x01) || (data[FRAME_COMMAND_WORD_INDEX] == 0x81))) {
572  this->has_target_binary_sensor_->publish_state(S_SOMEONE_EXISTS_STR[data[FRAME_DATA_INDEX]]);
573  } else if ((this->motion_status_text_sensor_ != nullptr) &&
574  ((data[FRAME_COMMAND_WORD_INDEX] == 0x02) || (data[FRAME_COMMAND_WORD_INDEX] == 0x82))) {
575  if (data[FRAME_DATA_INDEX] < 3) {
576  this->motion_status_text_sensor_->publish_state(S_MOTION_STATUS_STR[data[FRAME_DATA_INDEX]]);
577  }
578  } else if ((this->movement_signs_sensor_ != nullptr) &&
579  ((data[FRAME_COMMAND_WORD_INDEX] == 0x03) || (data[FRAME_COMMAND_WORD_INDEX] == 0x83))) {
580  this->movement_signs_sensor_->publish_state(data[FRAME_DATA_INDEX]);
581  } else if ((this->unman_time_select_ != nullptr) &&
582  ((data[FRAME_COMMAND_WORD_INDEX] == 0x0A) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8A))) {
583  // none:0x00 1s:0x01 30s:0x02 1min:0x03 2min:0x04 5min:0x05 10min:0x06 30min:0x07 1hour:0x08
584  if (data[FRAME_DATA_INDEX] < 9) {
585  this->unman_time_select_->publish_state(S_UNMANNED_TIME_STR[data[FRAME_DATA_INDEX]]);
586  }
587  } else if ((this->keep_away_text_sensor_ != nullptr) &&
588  ((data[FRAME_COMMAND_WORD_INDEX] == 0x0B) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8B))) {
589  // none:0x00 close_to:0x01 far_away:0x02
590  if (data[FRAME_DATA_INDEX] < 3) {
591  this->keep_away_text_sensor_->publish_state(S_KEEP_AWAY_STR[data[FRAME_DATA_INDEX]]);
592  }
593  } else {
594  ESP_LOGD(TAG, "[%s] No found COMMAND_WORD(%02X) in Frame", __FUNCTION__, data[FRAME_COMMAND_WORD_INDEX]);
595  }
596 }
597 
598 // Sending data frames
599 void MR24HPC1Component::send_query_(const uint8_t *query, size_t string_length) {
600  this->write_array(query, string_length);
601 }
602 
603 // Send Heartbeat Packet Command
604 void MR24HPC1Component::get_heartbeat_packet() { this->send_query_(GET_HEARTBEAT, sizeof(GET_HEARTBEAT)); }
605 
606 // Issuance of the underlying open parameter query command
608  this->send_query_(GET_RADAR_OUTPUT_INFORMATION_SWITCH, sizeof(GET_RADAR_OUTPUT_INFORMATION_SWITCH));
609 }
610 
611 // Issuance of product model orders
612 void MR24HPC1Component::get_product_mode() { this->send_query_(GET_PRODUCT_MODE, sizeof(GET_PRODUCT_MODE)); }
613 
614 // Issuing the Get Product ID command
615 void MR24HPC1Component::get_product_id() { this->send_query_(GET_PRODUCT_ID, sizeof(GET_PRODUCT_ID)); }
616 
617 // Issuing hardware model commands
618 void MR24HPC1Component::get_hardware_model() { this->send_query_(GET_HARDWARE_MODEL, sizeof(GET_HARDWARE_MODEL)); }
619 
620 // Issuing software version commands
622  this->send_query_(GET_FIRMWARE_VERSION, sizeof(GET_FIRMWARE_VERSION));
623 }
624 
625 void MR24HPC1Component::get_human_status() { this->send_query_(GET_HUMAN_STATUS, sizeof(GET_HUMAN_STATUS)); }
626 
628  this->send_query_(GET_HUMAN_MOTION_INFORMATION, sizeof(GET_HUMAN_MOTION_INFORMATION));
629 }
630 
632  this->send_query_(GET_BODY_MOTION_PARAMETERS, sizeof(GET_BODY_MOTION_PARAMETERS));
633 }
634 
635 void MR24HPC1Component::get_keep_away() { this->send_query_(GET_KEEP_AWAY, sizeof(GET_KEEP_AWAY)); }
636 
637 void MR24HPC1Component::get_scene_mode() { this->send_query_(GET_SCENE_MODE, sizeof(GET_SCENE_MODE)); }
638 
639 void MR24HPC1Component::get_sensitivity() { this->send_query_(GET_SENSITIVITY, sizeof(GET_SENSITIVITY)); }
640 
641 void MR24HPC1Component::get_unmanned_time() { this->send_query_(GET_UNMANNED_TIME, sizeof(GET_UNMANNED_TIME)); }
642 
643 void MR24HPC1Component::get_custom_mode() { this->send_query_(GET_CUSTOM_MODE, sizeof(GET_CUSTOM_MODE)); }
644 
646  this->send_query_(GET_EXISTENCE_BOUNDARY, sizeof(GET_EXISTENCE_BOUNDARY));
647 }
648 
649 void MR24HPC1Component::get_motion_boundary() { this->send_query_(GET_MOTION_BOUNDARY, sizeof(GET_MOTION_BOUNDARY)); }
650 
652  this->send_query_(GET_SPATIAL_STATIC_VALUE, sizeof(GET_SPATIAL_STATIC_VALUE));
653 }
654 
656  this->send_query_(GET_SPATIAL_MOTION_VALUE, sizeof(GET_SPATIAL_MOTION_VALUE));
657 }
658 
660  this->send_query_(GET_DISTANCE_OF_STATIC_OBJECT, sizeof(GET_DISTANCE_OF_STATIC_OBJECT));
661 }
662 
664  this->send_query_(GET_DISTANCE_OF_MOVING_OBJECT, sizeof(GET_DISTANCE_OF_MOVING_OBJECT));
665 }
666 
668  this->send_query_(GET_TARGET_MOVEMENT_SPEED, sizeof(GET_TARGET_MOVEMENT_SPEED));
669 }
670 
672  this->send_query_(GET_EXISTENCE_THRESHOLD, sizeof(GET_EXISTENCE_THRESHOLD));
673 }
674 
676  this->send_query_(GET_MOTION_THRESHOLD, sizeof(GET_MOTION_THRESHOLD));
677 }
678 
680  this->send_query_(GET_MOTION_TRIGGER_TIME, sizeof(GET_MOTION_TRIGGER_TIME));
681 }
682 
684  this->send_query_(GET_MOTION_TO_REST_TIME, sizeof(GET_MOTION_TO_REST_TIME));
685 }
686 
688  this->send_query_(GET_CUSTOM_UNMAN_TIME, sizeof(GET_CUSTOM_UNMAN_TIME));
689 }
690 
691 // Logic of setting: After setting, query whether the setting is successful or not!
692 
694  if (enable) {
695  this->send_query_(UNDERLYING_SWITCH_ON, sizeof(UNDERLYING_SWITCH_ON));
696  } else {
697  this->send_query_(UNDERLYING_SWITCH_OFF, sizeof(UNDERLYING_SWITCH_OFF));
698  }
699  if (this->keep_away_text_sensor_ != nullptr) {
700  this->keep_away_text_sensor_->publish_state("");
701  }
702  if (this->motion_status_text_sensor_ != nullptr) {
703  this->motion_status_text_sensor_->publish_state("");
704  }
705  if (this->custom_spatial_static_value_sensor_ != nullptr) {
706  this->custom_spatial_static_value_sensor_->publish_state(NAN);
707  }
708  if (this->custom_spatial_motion_value_sensor_ != nullptr) {
709  this->custom_spatial_motion_value_sensor_->publish_state(NAN);
710  }
711  if (this->custom_motion_distance_sensor_ != nullptr) {
712  this->custom_motion_distance_sensor_->publish_state(NAN);
713  }
714  if (this->custom_presence_of_detection_sensor_ != nullptr) {
715  this->custom_presence_of_detection_sensor_->publish_state(NAN);
716  }
717  if (this->custom_motion_speed_sensor_ != nullptr) {
718  this->custom_motion_speed_sensor_->publish_state(NAN);
719  }
720 }
721 
723  uint8_t send_data_len = 10;
724  uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x07, 0x00, 0x01, value, 0x00, 0x54, 0x43};
725  send_data[7] = get_frame_crc_sum(send_data, send_data_len);
726  this->send_query_(send_data, send_data_len);
727  if (this->custom_mode_number_ != nullptr) {
728  this->custom_mode_number_->publish_state(0);
729  }
730  if (this->custom_mode_num_sensor_ != nullptr) {
731  this->custom_mode_num_sensor_->publish_state(0);
732  }
733  this->get_scene_mode();
734  this->get_sensitivity();
735  this->get_custom_mode();
736  this->get_existence_boundary();
737  this->get_motion_boundary();
738  this->get_existence_threshold();
739  this->get_motion_threshold();
740  this->get_motion_trigger_time();
741  this->get_motion_to_rest_time();
742  this->get_custom_unman_time();
743 }
744 
746  if (value == 0x00)
747  return;
748  uint8_t send_data_len = 10;
749  uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x08, 0x00, 0x01, value, 0x00, 0x54, 0x43};
750  send_data[7] = get_frame_crc_sum(send_data, send_data_len);
751  this->send_query_(send_data, send_data_len);
752  this->get_scene_mode();
753  this->get_sensitivity();
754 }
755 
757  this->send_query_(SET_RESTART, sizeof(SET_RESTART));
758  this->check_dev_inf_sign_ = true;
759 }
760 
762  uint8_t send_data_len = 10;
763  uint8_t send_data[10] = {0x53, 0x59, 0x80, 0x0a, 0x00, 0x01, value, 0x00, 0x54, 0x43};
764  send_data[7] = get_frame_crc_sum(send_data, send_data_len);
765  this->send_query_(send_data, send_data_len);
766  this->get_unmanned_time();
767 }
768 
770  if (mode == 0) {
771  this->set_custom_end_mode(); // Equivalent to end setting
772  if (this->custom_mode_number_ != nullptr) {
773  this->custom_mode_number_->publish_state(0);
774  }
775  return;
776  }
777  uint8_t send_data_len = 10;
778  uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x09, 0x00, 0x01, mode, 0x00, 0x54, 0x43};
779  send_data[7] = get_frame_crc_sum(send_data, send_data_len);
780  this->send_query_(send_data, send_data_len);
781  this->get_existence_boundary();
782  this->get_motion_boundary();
783  this->get_existence_threshold();
784  this->get_motion_threshold();
785  this->get_motion_trigger_time();
786  this->get_motion_to_rest_time();
787  this->get_custom_unman_time();
788  this->get_custom_mode();
789  this->get_scene_mode();
790  this->get_sensitivity();
791 }
792 
794  uint8_t send_data_len = 10;
795  uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x0a, 0x00, 0x01, 0x0F, 0xCB, 0x54, 0x43};
796  this->send_query_(send_data, send_data_len);
797  if (this->custom_mode_number_ != nullptr) {
798  this->custom_mode_number_->publish_state(0); // Clear setpoints
799  }
800  this->get_existence_boundary();
801  this->get_motion_boundary();
802  this->get_existence_threshold();
803  this->get_motion_threshold();
804  this->get_motion_trigger_time();
805  this->get_motion_to_rest_time();
806  this->get_custom_unman_time();
807  this->get_custom_mode();
808  this->get_scene_mode();
809  this->get_sensitivity();
810 }
811 
813  if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
814  return; // You'll have to check that you're in custom mode to set it up
815  uint8_t send_data_len = 10;
816  uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x0A, 0x00, 0x01, (uint8_t) (value + 1), 0x00, 0x54, 0x43};
817  send_data[7] = get_frame_crc_sum(send_data, send_data_len);
818  this->send_query_(send_data, send_data_len);
819  this->get_existence_boundary();
820 }
821 
823  if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
824  return; // You'll have to check that you're in custom mode to set it up
825  uint8_t send_data_len = 10;
826  uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x0B, 0x00, 0x01, (uint8_t) (value + 1), 0x00, 0x54, 0x43};
827  send_data[7] = get_frame_crc_sum(send_data, send_data_len);
828  this->send_query_(send_data, send_data_len);
829  this->get_motion_boundary();
830 }
831 
833  if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
834  return; // You'll have to check that you're in custom mode to set it up
835  uint8_t send_data_len = 10;
836  uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x08, 0x00, 0x01, value, 0x00, 0x54, 0x43};
837  send_data[7] = get_frame_crc_sum(send_data, send_data_len);
838  this->send_query_(send_data, send_data_len);
839  this->get_existence_threshold();
840 }
841 
843  if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
844  return; // You'll have to check that you're in custom mode to set it up
845  uint8_t send_data_len = 10;
846  uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x09, 0x00, 0x01, value, 0x00, 0x54, 0x43};
847  send_data[7] = get_frame_crc_sum(send_data, send_data_len);
848  this->send_query_(send_data, send_data_len);
849  this->get_motion_threshold();
850 }
851 
853  if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
854  return; // You'll have to check that you're in custom mode to set it up
855  uint8_t send_data_len = 13;
856  uint8_t send_data[13] = {0x53, 0x59, 0x08, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, value, 0x00, 0x54, 0x43};
857  send_data[10] = get_frame_crc_sum(send_data, send_data_len);
858  this->send_query_(send_data, send_data_len);
859  this->get_motion_trigger_time();
860 }
861 
863  if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
864  return; // You'll have to check that you're in custom mode to set it up
865  uint8_t h8_num = (value >> 8) & 0xff;
866  uint8_t l8_num = value & 0xff;
867  uint8_t send_data_len = 13;
868  uint8_t send_data[13] = {0x53, 0x59, 0x08, 0x0D, 0x00, 0x04, 0x00, 0x00, h8_num, l8_num, 0x00, 0x54, 0x43};
869  send_data[10] = get_frame_crc_sum(send_data, send_data_len);
870  this->send_query_(send_data, send_data_len);
871  this->get_motion_to_rest_time();
872 }
873 
875  if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
876  return; // You'll have to check that you're in custom mode to set it up
877  uint32_t value_ms = value * 1000;
878  uint8_t h24_num = (value_ms >> 24) & 0xff;
879  uint8_t h16_num = (value_ms >> 16) & 0xff;
880  uint8_t h8_num = (value_ms >> 8) & 0xff;
881  uint8_t l8_num = value_ms & 0xff;
882  uint8_t send_data_len = 13;
883  uint8_t send_data[13] = {0x53, 0x59, 0x08, 0x0E, 0x00, 0x04, h24_num, h16_num, h8_num, l8_num, 0x00, 0x54, 0x43};
884  send_data[10] = get_frame_crc_sum(send_data, send_data_len);
885  this->send_query_(send_data, send_data_len);
886  this->get_custom_unman_time();
887 }
888 
889 } // namespace seeed_mr24hpc1
890 } // namespace esphome
void set_interval(const std::string &name, uint32_t interval, std::function< void()> &&f)
Set an interval function with a unique name.
Definition: component.cpp:52
void write_array(const uint8_t *data, size_t len)
Definition: uart.h:21
constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
Encode a 32-bit value given four bytes in most to least significant byte order.
Definition: helpers.h:187
void check_uart_settings(uint32_t baud_rate, uint8_t stop_bits=1, UARTParityOptions parity=UART_CONFIG_PARITY_NONE, uint8_t data_bits=8)
Check that the configuration of the UART bus matches the provided values and otherwise print a warnin...
Definition: uart.cpp:13
bool read_byte(uint8_t *data)
Definition: uart.h:29
BedjetMode mode
BedJet operating mode.
Definition: bedjet_codec.h:183
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition: helpers.h:183
std::string size_t len
Definition: helpers.h:293
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7