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