ESPHome 2026.5.0b1
Loading...
Searching...
No Matches
seeed_mr24hpc1.cpp
Go to the documentation of this file.
1#include "seeed_mr24hpc1.h"
2
4#include "esphome/core/log.h"
5
6#include <utility>
7
9
10static 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#ifdef USE_NUMBER
65 if (this->custom_mode_number_ != nullptr) {
66 this->custom_mode_number_->publish_state(0); // Zero out the custom mode
67 }
68#endif
69#ifdef USE_SENSOR
70 if (this->custom_mode_num_sensor_ != nullptr) {
71 this->custom_mode_num_sensor_->publish_state(0);
72 }
73#endif
74#ifdef USE_TEXT_SENSOR
75 if (this->custom_mode_end_text_sensor_ != nullptr) {
76 this->custom_mode_end_text_sensor_->publish_state("Not in custom mode");
77 }
78#endif
79 this->set_custom_end_mode();
80 this->poll_time_base_func_check_ = true;
81 this->check_dev_inf_sign_ = true;
82 this->sg_start_query_data_ = STANDARD_FUNCTION_QUERY_PRODUCT_MODE;
83 this->sg_data_len_ = 0;
84 this->sg_frame_len_ = 0;
85 this->sg_recv_data_state_ = FRAME_IDLE;
86 this->s_output_info_switch_flag_ = OUTPUT_SWITCH_INIT;
87
88 memset(this->c_product_mode_, 0, PRODUCT_BUF_MAX_SIZE);
89 memset(this->c_product_id_, 0, PRODUCT_BUF_MAX_SIZE);
90 memset(this->c_firmware_version_, 0, PRODUCT_BUF_MAX_SIZE);
91 memset(this->c_hardware_model_, 0, PRODUCT_BUF_MAX_SIZE);
92 memset(this->sg_frame_prase_buf_, 0, FRAME_BUF_MAX_SIZE);
93 memset(this->sg_frame_buf_, 0, FRAME_BUF_MAX_SIZE);
94
95 this->set_interval(8000, [this]() { this->update_(); });
96}
97
98// Timed polling of radar data
99void MR24HPC1Component::update_() {
100 this->get_radar_output_information_switch(); // Query the key status every so often
101 this->poll_time_base_func_check_ = true; // Query the base functionality information at regular intervals
102}
103
104// main loop
106 // Read all available bytes in batches to reduce UART call overhead.
107 size_t avail = this->available();
108 uint8_t buf[64];
109 while (avail > 0) {
110 size_t to_read = std::min(avail, sizeof(buf));
111 if (!this->read_array(buf, to_read)) {
112 break;
113 }
114 avail -= to_read;
115
116 for (size_t i = 0; i < to_read; i++) {
117 this->r24_split_data_frame_(buf[i]); // split data frame
118 }
119 }
120
121 if ((this->s_output_info_switch_flag_ == OUTPUT_SWTICH_OFF) &&
122 (this->sg_start_query_data_ > CUSTOM_FUNCTION_QUERY_TIME_OF_ENTER_UNMANNED) && (!this->check_dev_inf_sign_)) {
123 this->sg_start_query_data_ = STANDARD_FUNCTION_QUERY_SCENE_MODE;
124 } else if ((this->s_output_info_switch_flag_ == OUTPUT_SWITCH_ON) &&
125 (this->sg_start_query_data_ < CUSTOM_FUNCTION_QUERY_EXISTENCE_BOUNDARY) && (!this->check_dev_inf_sign_)) {
126 this->sg_start_query_data_ = CUSTOM_FUNCTION_QUERY_EXISTENCE_BOUNDARY;
127 } else if (this->check_dev_inf_sign_ && (this->sg_start_query_data_ > STANDARD_FUNCTION_QUERY_HARDWARE_MODE)) {
128 // First time power up information polling
129 this->sg_start_query_data_ = STANDARD_FUNCTION_QUERY_PRODUCT_MODE;
130 }
131
132 // Polling Functions
133 if (this->poll_time_base_func_check_) {
134 switch (this->sg_start_query_data_) {
136 this->get_product_mode();
137 this->sg_start_query_data_++;
138 break;
140 this->get_product_id();
141 this->sg_start_query_data_++;
142 break;
144 this->get_product_mode();
145 this->get_product_id();
146 this->get_firmware_version();
147 this->sg_start_query_data_++;
148 break;
149 case STANDARD_FUNCTION_QUERY_HARDWARE_MODE: // Above is the equipment information
150 this->get_product_mode();
151 this->get_product_id();
152 this->get_hardware_model();
153 this->sg_start_query_data_++;
154 this->check_dev_inf_sign_ = false;
155 break;
157 this->get_scene_mode();
158 this->sg_start_query_data_++;
159 break;
161 this->get_sensitivity();
162 this->sg_start_query_data_++;
163 break;
165 this->get_unmanned_time();
166 this->sg_start_query_data_++;
167 break;
169 this->get_human_status();
170 this->sg_start_query_data_++;
171 break;
173 this->get_human_motion_info();
174 this->sg_start_query_data_++;
175 break;
178 this->sg_start_query_data_++;
179 break;
180 case STANDARD_FUNCTION_QUERY_KEEPAWAY_STATUS: // The above is the basic functional information
181 this->get_keep_away();
182 this->sg_start_query_data_++;
183 break;
185 this->get_custom_mode();
186 this->sg_start_query_data_++;
187 break;
189 this->get_heartbeat_packet();
190 this->sg_start_query_data_++;
191 break;
194 this->sg_start_query_data_++;
195 break;
197 this->get_motion_boundary();
198 this->sg_start_query_data_++;
199 break;
202 this->sg_start_query_data_++;
203 break;
205 this->get_motion_threshold();
206 this->sg_start_query_data_++;
207 break;
210 this->sg_start_query_data_++;
211 break;
214 this->sg_start_query_data_++;
215 break;
217 this->get_custom_unman_time();
218 this->sg_start_query_data_++;
219 if (this->s_output_info_switch_flag_ == OUTPUT_SWTICH_OFF) {
220 this->poll_time_base_func_check_ = false; // Avoiding high-speed polling that can cause the device to jam
221 }
222 break;
224 this->get_human_status();
225 this->sg_start_query_data_++;
226 break;
229 this->sg_start_query_data_++;
230 break;
233 this->sg_start_query_data_++;
234 break;
237 this->sg_start_query_data_++;
238 break;
241 this->sg_start_query_data_++;
242 break;
245 this->sg_start_query_data_++;
246 this->poll_time_base_func_check_ = false; // Avoiding high-speed polling that can cause the device to jam
247 break;
248 default:
249 break;
250 }
251 }
252}
253
254// Calculate CRC check digit
255static uint8_t get_frame_crc_sum(const uint8_t *data, int len) {
256 unsigned int crc_sum = 0;
257 for (int i = 0; i < len - 3; i++) {
258 crc_sum += data[i];
259 }
260 return crc_sum & 0xff;
261}
262
263// Check that the check digit is correct
264static int get_frame_check_status(uint8_t *data, int len) {
265 uint8_t crc_sum = get_frame_crc_sum(data, len);
266 uint8_t verified = data[len - 3];
267 return (verified == crc_sum) ? 1 : 0;
268}
269
270// split data frame
271void MR24HPC1Component::r24_split_data_frame_(uint8_t value) {
272 switch (this->sg_recv_data_state_) {
273 case FRAME_IDLE: // starting value
274 if (FRAME_HEADER1_VALUE == value) {
275 this->sg_recv_data_state_ = FRAME_HEADER2;
276 }
277 break;
278 case FRAME_HEADER2:
279 if (FRAME_HEADER2_VALUE == value) {
280 this->sg_frame_buf_[0] = FRAME_HEADER1_VALUE;
281 this->sg_frame_buf_[1] = FRAME_HEADER2_VALUE;
282 this->sg_recv_data_state_ = FRAME_CTL_WORD;
283 } else {
284 this->sg_recv_data_state_ = FRAME_IDLE;
285 ESP_LOGD(TAG, "FRAME_IDLE ERROR value:%x", value);
286 }
287 break;
288 case FRAME_CTL_WORD:
289 this->sg_frame_buf_[2] = value;
290 this->sg_recv_data_state_ = FRAME_CMD_WORD;
291 break;
292 case FRAME_CMD_WORD:
293 this->sg_frame_buf_[3] = value;
294 this->sg_recv_data_state_ = FRAME_DATA_LEN_H;
295 break;
296 case FRAME_DATA_LEN_H:
297 if (value == 0) {
298 this->sg_frame_buf_[4] = value;
299 this->sg_recv_data_state_ = FRAME_DATA_LEN_L;
300 } else {
301 this->sg_recv_data_state_ = FRAME_IDLE;
302 ESP_LOGD(TAG, "FRAME_DATA_LEN_H ERROR value:%x", value);
303 }
304 break;
305 case FRAME_DATA_LEN_L:
306 this->sg_data_len_ = value;
307 if (this->sg_data_len_ == 0 || this->sg_data_len_ > 32) {
308 ESP_LOGD(TAG, "len=%d, FRAME_DATA_LEN_L ERROR value:%x", this->sg_data_len_, value);
309 this->sg_data_len_ = 0;
310 this->sg_recv_data_state_ = FRAME_IDLE;
311 } else {
312 this->sg_frame_buf_[5] = value;
313 this->sg_frame_len_ = 6;
314 this->sg_recv_data_state_ = FRAME_DATA_BYTES;
315 }
316 break;
317 case FRAME_DATA_BYTES:
318 this->sg_frame_buf_[this->sg_frame_len_++] = value;
319 if (--this->sg_data_len_ == 0) {
320 this->sg_recv_data_state_ = FRAME_DATA_CRC;
321 }
322 break;
323 case FRAME_DATA_CRC:
324 this->sg_frame_buf_[this->sg_frame_len_++] = value;
325 this->sg_recv_data_state_ = FRAME_TAIL1;
326 break;
327 case FRAME_TAIL1:
328 if (FRAME_TAIL1_VALUE == value) {
329 this->sg_recv_data_state_ = FRAME_TAIL2;
330 } else {
331 this->sg_recv_data_state_ = FRAME_IDLE;
332 this->sg_frame_len_ = 0;
333 this->sg_data_len_ = 0;
334 ESP_LOGD(TAG, "FRAME_TAIL1 ERROR value:%x", value);
335 }
336 break;
337 case FRAME_TAIL2:
338 if (FRAME_TAIL2_VALUE == value) {
339 this->sg_frame_buf_[this->sg_frame_len_++] = FRAME_TAIL1_VALUE;
340 this->sg_frame_buf_[this->sg_frame_len_++] = FRAME_TAIL2_VALUE;
341 memcpy(this->sg_frame_prase_buf_, this->sg_frame_buf_, this->sg_frame_len_);
342 if (get_frame_check_status(this->sg_frame_prase_buf_, this->sg_frame_len_)) {
343 this->r24_parse_data_frame_(this->sg_frame_prase_buf_, this->sg_frame_len_);
344 } else {
345 ESP_LOGD(TAG, "frame check failer!");
346 }
347 } else {
348 ESP_LOGD(TAG, "FRAME_TAIL2 ERROR value:%x", value);
349 }
350 memset(this->sg_frame_prase_buf_, 0, FRAME_BUF_MAX_SIZE);
351 memset(this->sg_frame_buf_, 0, FRAME_BUF_MAX_SIZE);
352 this->sg_frame_len_ = 0;
353 this->sg_data_len_ = 0;
354 this->sg_recv_data_state_ = FRAME_IDLE;
355 break;
356 default:
357 this->sg_recv_data_state_ = FRAME_IDLE;
358 }
359}
360
361// Parses data frames related to product information
362void MR24HPC1Component::r24_frame_parse_product_information_(uint8_t *data) {
363#ifdef USE_TEXT_SENSOR
364 uint16_t product_len = encode_uint16(data[FRAME_COMMAND_WORD_INDEX + 1], data[FRAME_COMMAND_WORD_INDEX + 2]);
365 if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_PRODUCT_MODE) {
366 if ((this->product_model_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) {
367 memset(this->c_product_mode_, 0, PRODUCT_BUF_MAX_SIZE);
368 memcpy(this->c_product_mode_, &data[FRAME_DATA_INDEX], product_len);
369 this->product_model_text_sensor_->publish_state(this->c_product_mode_);
370 } else {
371 ESP_LOGD(TAG, "Reply: get product_mode error!");
372 }
373 } else if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_PRODUCT_ID) {
374 if ((this->product_id_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) {
375 memset(this->c_product_id_, 0, PRODUCT_BUF_MAX_SIZE);
376 memcpy(this->c_product_id_, &data[FRAME_DATA_INDEX], product_len);
377 this->product_id_text_sensor_->publish_state(this->c_product_id_);
378 } else {
379 ESP_LOGD(TAG, "Reply: get productId error!");
380 }
381 } else if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_HARDWARE_MODEL) {
382 if ((this->hardware_model_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) {
383 memset(this->c_hardware_model_, 0, PRODUCT_BUF_MAX_SIZE);
384 memcpy(this->c_hardware_model_, &data[FRAME_DATA_INDEX], product_len);
385 this->hardware_model_text_sensor_->publish_state(this->c_hardware_model_);
386 ESP_LOGD(TAG, "Reply: get hardware_model :%s", this->c_hardware_model_);
387 } else {
388 ESP_LOGD(TAG, "Reply: get hardwareModel error!");
389 }
390 } else if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_FIRMWARE_VERSION) {
391 if ((this->firware_version_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) {
392 memset(this->c_firmware_version_, 0, PRODUCT_BUF_MAX_SIZE);
393 memcpy(this->c_firmware_version_, &data[FRAME_DATA_INDEX], product_len);
394 this->firware_version_text_sensor_->publish_state(this->c_firmware_version_);
395 } else {
396 ESP_LOGD(TAG, "Reply: get firmwareVersion error!");
397 }
398 }
399#endif
400}
401
402// Parsing the underlying open parameters
403void MR24HPC1Component::r24_frame_parse_open_underlying_information_(uint8_t *data) {
404 switch (data[FRAME_COMMAND_WORD_INDEX]) {
405 case 0x00:
406 case 0x80:
407#ifdef USE_SWITCH
408 if (this->underlying_open_function_switch_ != nullptr) {
409 this->underlying_open_function_switch_->publish_state(data[FRAME_DATA_INDEX]);
410 }
411#endif
412 this->s_output_info_switch_flag_ = data[FRAME_DATA_INDEX] ? OUTPUT_SWITCH_ON : OUTPUT_SWTICH_OFF;
413 break;
414#ifdef USE_SENSOR
415 case 0x01:
416 if (this->custom_spatial_static_value_sensor_ != nullptr) {
417 this->custom_spatial_static_value_sensor_->publish_state(data[FRAME_DATA_INDEX]);
418 }
419 if (this->custom_presence_of_detection_sensor_ != nullptr) {
420 this->custom_presence_of_detection_sensor_->publish_state(data[FRAME_DATA_INDEX + 1] * 0.5f);
421 }
422 if (this->custom_spatial_motion_value_sensor_ != nullptr) {
423 this->custom_spatial_motion_value_sensor_->publish_state(data[FRAME_DATA_INDEX + 2]);
424 }
425 if (this->custom_motion_distance_sensor_ != nullptr) {
426 this->custom_motion_distance_sensor_->publish_state(data[FRAME_DATA_INDEX + 3] * 0.5f);
427 }
428 if (this->custom_motion_speed_sensor_ != nullptr) {
429 this->custom_motion_speed_sensor_->publish_state((data[FRAME_DATA_INDEX + 4] - 10) * 0.5f);
430 }
431 break;
432 case 0x07:
433 case 0x87:
434 if (this->movement_signs_sensor_ != nullptr) {
435 this->movement_signs_sensor_->publish_state(data[FRAME_DATA_INDEX]);
436 }
437 break;
438 case 0x81:
439 if (this->custom_spatial_static_value_sensor_ != nullptr) {
440 this->custom_spatial_static_value_sensor_->publish_state(data[FRAME_DATA_INDEX]);
441 }
442 break;
443 case 0x82:
444 if (this->custom_spatial_motion_value_sensor_ != nullptr) {
445 this->custom_spatial_motion_value_sensor_->publish_state(data[FRAME_DATA_INDEX]);
446 }
447 break;
448 case 0x83:
449 if (this->custom_presence_of_detection_sensor_ != nullptr &&
450 data[FRAME_DATA_INDEX] < std::size(S_PRESENCE_OF_DETECTION_RANGE_STR)) {
451 this->custom_presence_of_detection_sensor_->publish_state(
452 S_PRESENCE_OF_DETECTION_RANGE_STR[data[FRAME_DATA_INDEX]]);
453 }
454 break;
455 case 0x84:
456 if (this->custom_motion_distance_sensor_ != nullptr) {
457 this->custom_motion_distance_sensor_->publish_state(data[FRAME_DATA_INDEX] * 0.5f);
458 }
459 break;
460 case 0x85:
461 if (this->custom_motion_speed_sensor_ != nullptr) {
462 this->custom_motion_speed_sensor_->publish_state((data[FRAME_DATA_INDEX] - 10) * 0.5f);
463 }
464 break;
465#endif
466#ifdef USE_TEXT_SENSOR
467 case 0x06:
468 case 0x86:
469 // none:0x00 close_to:0x01 far_away:0x02
470 if ((this->keep_away_text_sensor_ != nullptr) && (data[FRAME_DATA_INDEX] < 3)) {
471 this->keep_away_text_sensor_->publish_state(S_KEEP_AWAY_STR[data[FRAME_DATA_INDEX]]);
472 }
473 break;
474#endif
475#ifdef USE_NUMBER
476 case 0x08:
477 case 0x88:
478 if (this->existence_threshold_number_ != nullptr) {
479 this->existence_threshold_number_->publish_state(data[FRAME_DATA_INDEX]);
480 }
481 break;
482 case 0x09:
483 case 0x89:
484 if (this->motion_threshold_number_ != nullptr) {
485 this->motion_threshold_number_->publish_state(data[FRAME_DATA_INDEX]);
486 }
487 break;
488 case 0x0c:
489 case 0x8c:
490 if (this->motion_trigger_number_ != nullptr) {
491 uint32_t motion_trigger_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1],
492 data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]);
493 this->motion_trigger_number_->publish_state(motion_trigger_time);
494 }
495 break;
496 case 0x0d:
497 case 0x8d:
498 if (this->motion_to_rest_number_ != nullptr) {
499 uint32_t move_to_rest_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1],
500 data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]);
501 this->motion_to_rest_number_->publish_state(move_to_rest_time);
502 }
503 break;
504 case 0x0e:
505 case 0x8e:
506 if (this->custom_unman_time_number_ != nullptr) {
507 uint32_t enter_unmanned_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1],
508 data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]);
509 this->custom_unman_time_number_->publish_state(enter_unmanned_time / 1000.0f);
510 }
511 break;
512#endif
513#ifdef USE_SELECT
514 case 0x0a:
515 case 0x8a:
516 if (this->existence_boundary_select_ != nullptr) {
517 if (this->existence_boundary_select_->has_index(data[FRAME_DATA_INDEX] - 1)) {
518 this->existence_boundary_select_->publish_state(data[FRAME_DATA_INDEX] - 1);
519 }
520 }
521 break;
522 case 0x0b:
523 case 0x8b:
524 if (this->motion_boundary_select_ != nullptr) {
525 if (this->motion_boundary_select_->has_index(data[FRAME_DATA_INDEX] - 1)) {
526 this->motion_boundary_select_->publish_state(data[FRAME_DATA_INDEX] - 1);
527 }
528 }
529 break;
530#endif
531 }
532}
533
534void MR24HPC1Component::r24_parse_data_frame_(uint8_t *data, uint8_t len) {
535 switch (data[FRAME_CONTROL_WORD_INDEX]) {
536 case 0x01: {
537 if (data[FRAME_COMMAND_WORD_INDEX] == 0x02) {
538 ESP_LOGD(TAG, "Reply: query restart packet");
539 break;
540 }
541#ifdef USE_TEXT_SENSOR
542 if (this->heartbeat_state_text_sensor_ != nullptr) {
543 this->heartbeat_state_text_sensor_->publish_state(
544 data[FRAME_COMMAND_WORD_INDEX] == 0x01 ? "Equipment Normal" : "Equipment Abnormal");
545 }
546#endif
547 } break;
548 case 0x02: {
549 this->r24_frame_parse_product_information_(data);
550 } break;
551 case 0x05: {
552 this->r24_frame_parse_work_status_(data);
553 } break;
554 case 0x08: {
555 this->r24_frame_parse_open_underlying_information_(data);
556 } break;
557 case 0x80: {
558 this->r24_frame_parse_human_information_(data);
559 } break;
560 default:
561 ESP_LOGD(TAG, "control word:0x%02X not found", data[FRAME_CONTROL_WORD_INDEX]);
562 break;
563 }
564}
565
566void MR24HPC1Component::r24_frame_parse_work_status_(uint8_t *data) {
567 switch (data[FRAME_COMMAND_WORD_INDEX]) {
568 case 0x01:
569 case 0x81:
570 ESP_LOGD(TAG, "Reply: get radar init status 0x%02X", data[FRAME_DATA_INDEX]);
571 break;
572 case 0x09:
573#ifdef USE_SENSOR
574 if (this->custom_mode_num_sensor_ != nullptr) {
575 this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]);
576 }
577#endif
578#ifdef USE_NUMBER
579 if (this->custom_mode_number_ != nullptr) {
580 this->custom_mode_number_->publish_state(0);
581 }
582#endif
583#ifdef USE_TEXT_SENSOR
584 if (this->custom_mode_end_text_sensor_ != nullptr) {
585 this->custom_mode_end_text_sensor_->publish_state("Setup in progress");
586 }
587#endif
588 break;
589 case 0x89:
590#ifdef USE_SENSOR
591 if (this->custom_mode_num_sensor_ != nullptr) {
592 this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]);
593 }
594#endif
595 if (data[FRAME_DATA_INDEX] == 0) {
596#ifdef USE_TEXT_SENSOR
597 if (this->custom_mode_end_text_sensor_ != nullptr) {
598 this->custom_mode_end_text_sensor_->publish_state("Not in custom mode");
599 }
600#endif
601#ifdef USE_NUMBER
602 if (this->custom_mode_number_ != nullptr) {
603 this->custom_mode_number_->publish_state(0);
604 }
605#endif
606 }
607 break;
608#ifdef USE_SELECT
609 case 0x07:
610 case 0x87:
611 if ((this->scene_mode_select_ != nullptr) && (this->scene_mode_select_->has_index(data[FRAME_DATA_INDEX]))) {
612 this->scene_mode_select_->publish_state(data[FRAME_DATA_INDEX]);
613 } else {
614 ESP_LOGD(TAG, "Select has index offset %d Error", data[FRAME_DATA_INDEX]);
615 }
616 break;
617#endif
618#ifdef USE_NUMBER
619 case 0x08:
620 case 0x88:
621 if (this->sensitivity_number_ != nullptr) {
622 this->sensitivity_number_->publish_state(data[FRAME_DATA_INDEX]);
623 }
624 break;
625#endif
626#ifdef USE_TEXT_SENSOR
627 case 0x0A:
628 if (this->custom_mode_end_text_sensor_ != nullptr) {
629 this->custom_mode_end_text_sensor_->publish_state("Set Success!");
630 }
631 break;
632#endif
633 default:
634 ESP_LOGD(TAG, "[%s] No found COMMAND_WORD(%02X) in Frame", __FUNCTION__, data[FRAME_COMMAND_WORD_INDEX]);
635 break;
636 }
637}
638
639void MR24HPC1Component::r24_frame_parse_human_information_(uint8_t *data) {
640 switch (data[FRAME_COMMAND_WORD_INDEX]) {
641#ifdef USE_BINARY_SENSOR
642 case 0x01:
643 case 0x81:
644 if (this->has_target_binary_sensor_ != nullptr && data[FRAME_DATA_INDEX] < std::size(S_SOMEONE_EXISTS_STR)) {
645 this->has_target_binary_sensor_->publish_state(S_SOMEONE_EXISTS_STR[data[FRAME_DATA_INDEX]]);
646 }
647 break;
648#endif
649#ifdef USE_SENSOR
650 case 0x03:
651 case 0x83:
652 if (this->movement_signs_sensor_ != nullptr) {
653 this->movement_signs_sensor_->publish_state(data[FRAME_DATA_INDEX]);
654 }
655 break;
656#endif
657#ifdef USE_TEXT_SENSOR
658 case 0x02:
659 case 0x82:
660 if ((this->motion_status_text_sensor_ != nullptr) && (data[FRAME_DATA_INDEX] < 3)) {
661 this->motion_status_text_sensor_->publish_state(S_MOTION_STATUS_STR[data[FRAME_DATA_INDEX]]);
662 }
663 break;
664 case 0x0B:
665 case 0x8B:
666 // none:0x00 close_to:0x01 far_away:0x02
667 if ((this->keep_away_text_sensor_ != nullptr) && (data[FRAME_DATA_INDEX] < 3)) {
668 this->keep_away_text_sensor_->publish_state(S_KEEP_AWAY_STR[data[FRAME_DATA_INDEX]]);
669 }
670 break;
671#endif
672#ifdef USE_SELECT
673 case 0x0A:
674 case 0x8A:
675 // none:0x00 1s:0x01 30s:0x02 1min:0x03 2min:0x04 5min:0x05 10min:0x06 30min:0x07 1hour:0x08
676 if ((this->unman_time_select_ != nullptr) && (data[FRAME_DATA_INDEX] < 9)) {
677 this->unman_time_select_->publish_state(data[FRAME_DATA_INDEX]);
678 }
679 break;
680#endif
681 default:
682 ESP_LOGD(TAG, "[%s] No found COMMAND_WORD(%02X) in Frame", __FUNCTION__, data[FRAME_COMMAND_WORD_INDEX]);
683 break;
684 }
685}
686
687// Sending data frames
688void MR24HPC1Component::send_query_(const uint8_t *query, size_t string_length) {
689 this->write_array(query, string_length);
690}
691
692// Send Heartbeat Packet Command
693void MR24HPC1Component::get_heartbeat_packet() { this->send_query_(GET_HEARTBEAT, sizeof(GET_HEARTBEAT)); }
694
695// Issuance of the underlying open parameter query command
697 this->send_query_(GET_RADAR_OUTPUT_INFORMATION_SWITCH, sizeof(GET_RADAR_OUTPUT_INFORMATION_SWITCH));
698}
699
700// Issuance of product model orders
701void MR24HPC1Component::get_product_mode() { this->send_query_(GET_PRODUCT_MODE, sizeof(GET_PRODUCT_MODE)); }
702
703// Issuing the Get Product ID command
704void MR24HPC1Component::get_product_id() { this->send_query_(GET_PRODUCT_ID, sizeof(GET_PRODUCT_ID)); }
705
706// Issuing hardware model commands
707void MR24HPC1Component::get_hardware_model() { this->send_query_(GET_HARDWARE_MODEL, sizeof(GET_HARDWARE_MODEL)); }
708
709// Issuing software version commands
711 this->send_query_(GET_FIRMWARE_VERSION, sizeof(GET_FIRMWARE_VERSION));
712}
713
714void MR24HPC1Component::get_human_status() { this->send_query_(GET_HUMAN_STATUS, sizeof(GET_HUMAN_STATUS)); }
715
717 this->send_query_(GET_HUMAN_MOTION_INFORMATION, sizeof(GET_HUMAN_MOTION_INFORMATION));
718}
719
721 this->send_query_(GET_BODY_MOTION_PARAMETERS, sizeof(GET_BODY_MOTION_PARAMETERS));
722}
723
724void MR24HPC1Component::get_keep_away() { this->send_query_(GET_KEEP_AWAY, sizeof(GET_KEEP_AWAY)); }
725
726void MR24HPC1Component::get_scene_mode() { this->send_query_(GET_SCENE_MODE, sizeof(GET_SCENE_MODE)); }
727
728void MR24HPC1Component::get_sensitivity() { this->send_query_(GET_SENSITIVITY, sizeof(GET_SENSITIVITY)); }
729
730void MR24HPC1Component::get_unmanned_time() { this->send_query_(GET_UNMANNED_TIME, sizeof(GET_UNMANNED_TIME)); }
731
732void MR24HPC1Component::get_custom_mode() { this->send_query_(GET_CUSTOM_MODE, sizeof(GET_CUSTOM_MODE)); }
733
735 this->send_query_(GET_EXISTENCE_BOUNDARY, sizeof(GET_EXISTENCE_BOUNDARY));
736}
737
738void MR24HPC1Component::get_motion_boundary() { this->send_query_(GET_MOTION_BOUNDARY, sizeof(GET_MOTION_BOUNDARY)); }
739
741 this->send_query_(GET_SPATIAL_STATIC_VALUE, sizeof(GET_SPATIAL_STATIC_VALUE));
742}
743
745 this->send_query_(GET_SPATIAL_MOTION_VALUE, sizeof(GET_SPATIAL_MOTION_VALUE));
746}
747
749 this->send_query_(GET_DISTANCE_OF_STATIC_OBJECT, sizeof(GET_DISTANCE_OF_STATIC_OBJECT));
750}
751
753 this->send_query_(GET_DISTANCE_OF_MOVING_OBJECT, sizeof(GET_DISTANCE_OF_MOVING_OBJECT));
754}
755
757 this->send_query_(GET_TARGET_MOVEMENT_SPEED, sizeof(GET_TARGET_MOVEMENT_SPEED));
758}
759
761 this->send_query_(GET_EXISTENCE_THRESHOLD, sizeof(GET_EXISTENCE_THRESHOLD));
762}
763
765 this->send_query_(GET_MOTION_THRESHOLD, sizeof(GET_MOTION_THRESHOLD));
766}
767
769 this->send_query_(GET_MOTION_TRIGGER_TIME, sizeof(GET_MOTION_TRIGGER_TIME));
770}
771
773 this->send_query_(GET_MOTION_TO_REST_TIME, sizeof(GET_MOTION_TO_REST_TIME));
774}
775
777 this->send_query_(GET_CUSTOM_UNMAN_TIME, sizeof(GET_CUSTOM_UNMAN_TIME));
778}
779
780// Logic of setting: After setting, query whether the setting is successful or not!
781
783 if (enable) {
784 this->send_query_(UNDERLYING_SWITCH_ON, sizeof(UNDERLYING_SWITCH_ON));
785 } else {
786 this->send_query_(UNDERLYING_SWITCH_OFF, sizeof(UNDERLYING_SWITCH_OFF));
787 }
788#ifdef USE_TEXT_SENSOR
789 if (this->keep_away_text_sensor_ != nullptr) {
790 this->keep_away_text_sensor_->publish_state("");
791 }
792 if (this->motion_status_text_sensor_ != nullptr) {
793 this->motion_status_text_sensor_->publish_state("");
794 }
795#endif
796#ifdef USE_SENSOR
797 if (this->custom_spatial_static_value_sensor_ != nullptr) {
798 this->custom_spatial_static_value_sensor_->publish_state(NAN);
799 }
800 if (this->custom_spatial_motion_value_sensor_ != nullptr) {
801 this->custom_spatial_motion_value_sensor_->publish_state(NAN);
802 }
803 if (this->custom_motion_distance_sensor_ != nullptr) {
804 this->custom_motion_distance_sensor_->publish_state(NAN);
805 }
806 if (this->custom_presence_of_detection_sensor_ != nullptr) {
807 this->custom_presence_of_detection_sensor_->publish_state(NAN);
808 }
809 if (this->custom_motion_speed_sensor_ != nullptr) {
810 this->custom_motion_speed_sensor_->publish_state(NAN);
811 }
812#endif
813}
814
816 uint8_t send_data_len = 10;
817 uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x07, 0x00, 0x01, value, 0x00, 0x54, 0x43};
818 send_data[7] = get_frame_crc_sum(send_data, send_data_len);
819 this->send_query_(send_data, send_data_len);
820#ifdef USE_NUMBER
821 if (this->custom_mode_number_ != nullptr) {
822 this->custom_mode_number_->publish_state(0);
823 }
824#endif
825#ifdef USE_SENSOR
826 if (this->custom_mode_num_sensor_ != nullptr) {
827 this->custom_mode_num_sensor_->publish_state(0);
828 }
829#endif
830 this->get_scene_mode();
831 this->get_sensitivity();
832 this->get_custom_mode();
834 this->get_motion_boundary();
836 this->get_motion_threshold();
839 this->get_custom_unman_time();
840}
841
843 if (value == 0x00)
844 return;
845 uint8_t send_data_len = 10;
846 uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x08, 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_scene_mode();
850 this->get_sensitivity();
851}
852
854 this->send_query_(SET_RESTART, sizeof(SET_RESTART));
855 this->check_dev_inf_sign_ = true;
856}
857
859 uint8_t send_data_len = 10;
860 uint8_t send_data[10] = {0x53, 0x59, 0x80, 0x0a, 0x00, 0x01, value, 0x00, 0x54, 0x43};
861 send_data[7] = get_frame_crc_sum(send_data, send_data_len);
862 this->send_query_(send_data, send_data_len);
863 this->get_unmanned_time();
864}
865
867 if (mode == 0) {
868 this->set_custom_end_mode(); // Equivalent to end setting
869#ifdef USE_NUMBER
870 if (this->custom_mode_number_ != nullptr) {
871 this->custom_mode_number_->publish_state(0);
872 }
873#endif
874 return;
875 }
876 uint8_t send_data_len = 10;
877 uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x09, 0x00, 0x01, mode, 0x00, 0x54, 0x43};
878 send_data[7] = get_frame_crc_sum(send_data, send_data_len);
879 this->send_query_(send_data, send_data_len);
881 this->get_motion_boundary();
883 this->get_motion_threshold();
886 this->get_custom_unman_time();
887 this->get_custom_mode();
888 this->get_scene_mode();
889 this->get_sensitivity();
890}
891
893 uint8_t send_data_len = 10;
894 uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x0a, 0x00, 0x01, 0x0F, 0xCB, 0x54, 0x43};
895 this->send_query_(send_data, send_data_len);
896#ifdef USE_NUMBER
897 if (this->custom_mode_number_ != nullptr) {
898 this->custom_mode_number_->publish_state(0); // Clear setpoints
899 }
900#endif
902 this->get_motion_boundary();
904 this->get_motion_threshold();
907 this->get_custom_unman_time();
908 this->get_custom_mode();
909 this->get_scene_mode();
910 this->get_sensitivity();
911}
912
914#ifdef USE_SENSOR
915 if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
916 return; // You'll have to check that you're in custom mode to set it up
917#endif
918 uint8_t send_data_len = 10;
919 uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x0A, 0x00, 0x01, (uint8_t) (value + 1), 0x00, 0x54, 0x43};
920 send_data[7] = get_frame_crc_sum(send_data, send_data_len);
921 this->send_query_(send_data, send_data_len);
923}
924
926#ifdef USE_SENSOR
927 if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
928 return; // You'll have to check that you're in custom mode to set it up
929#endif
930 uint8_t send_data_len = 10;
931 uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x0B, 0x00, 0x01, (uint8_t) (value + 1), 0x00, 0x54, 0x43};
932 send_data[7] = get_frame_crc_sum(send_data, send_data_len);
933 this->send_query_(send_data, send_data_len);
934 this->get_motion_boundary();
935}
936
938#ifdef USE_SENSOR
939 if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
940 return; // You'll have to check that you're in custom mode to set it up
941#endif
942 uint8_t send_data_len = 10;
943 uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x08, 0x00, 0x01, value, 0x00, 0x54, 0x43};
944 send_data[7] = get_frame_crc_sum(send_data, send_data_len);
945 this->send_query_(send_data, send_data_len);
947}
948
950#ifdef USE_SENSOR
951 if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
952 return; // You'll have to check that you're in custom mode to set it up
953#endif
954 uint8_t send_data_len = 10;
955 uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x09, 0x00, 0x01, value, 0x00, 0x54, 0x43};
956 send_data[7] = get_frame_crc_sum(send_data, send_data_len);
957 this->send_query_(send_data, send_data_len);
958 this->get_motion_threshold();
959}
960
962#ifdef USE_SENSOR
963 if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
964 return; // You'll have to check that you're in custom mode to set it up
965#endif
966 uint8_t send_data_len = 13;
967 uint8_t send_data[13] = {0x53, 0x59, 0x08, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, value, 0x00, 0x54, 0x43};
968 send_data[10] = get_frame_crc_sum(send_data, send_data_len);
969 this->send_query_(send_data, send_data_len);
971}
972
974#ifdef USE_SENSOR
975 if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
976 return; // You'll have to check that you're in custom mode to set it up
977#endif
978 uint8_t h8_num = (value >> 8) & 0xff;
979 uint8_t l8_num = value & 0xff;
980 uint8_t send_data_len = 13;
981 uint8_t send_data[13] = {0x53, 0x59, 0x08, 0x0D, 0x00, 0x04, 0x00, 0x00, h8_num, l8_num, 0x00, 0x54, 0x43};
982 send_data[10] = get_frame_crc_sum(send_data, send_data_len);
983 this->send_query_(send_data, send_data_len);
985}
986
988#ifdef USE_SENSOR
989 if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
990 return; // You'll have to check that you're in custom mode to set it up
991#endif
992 uint32_t value_ms = value * 1000;
993 uint8_t h24_num = (value_ms >> 24) & 0xff;
994 uint8_t h16_num = (value_ms >> 16) & 0xff;
995 uint8_t h8_num = (value_ms >> 8) & 0xff;
996 uint8_t l8_num = value_ms & 0xff;
997 uint8_t send_data_len = 13;
998 uint8_t send_data[13] = {0x53, 0x59, 0x08, 0x0E, 0x00, 0x04, h24_num, h16_num, h8_num, l8_num, 0x00, 0x54, 0x43};
999 send_data[10] = get_frame_crc_sum(send_data, send_data_len);
1000 this->send_query_(send_data, send_data_len);
1001 this->get_custom_unman_time();
1002}
1003
1004} // namespace esphome::seeed_mr24hpc1
BedjetMode mode
BedJet operating mode.
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") void set_interval(const std voi set_interval)(const char *name, uint32_t interval, std::function< void()> &&f)
Set an interval function with a unique name.
Definition component.h:417
optional< std::array< uint8_t, N > > read_array()
Definition uart.h:38
void write_array(const uint8_t *data, size_t len)
Definition uart.h:26
const std::vector< uint8_t > & data
std::string size_t len
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:867
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:859
static void uint32_t