ESPHome 2026.3.0
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 == 0) {
301 this->sg_frame_buf_[4] = value;
302 this->sg_recv_data_state_ = FRAME_DATA_LEN_L;
303 } else {
304 this->sg_recv_data_state_ = FRAME_IDLE;
305 ESP_LOGD(TAG, "FRAME_DATA_LEN_H ERROR value:%x", value);
306 }
307 break;
308 case FRAME_DATA_LEN_L:
309 this->sg_data_len_ = value;
310 if (this->sg_data_len_ == 0 || this->sg_data_len_ > 32) {
311 ESP_LOGD(TAG, "len=%d, FRAME_DATA_LEN_L ERROR value:%x", this->sg_data_len_, value);
312 this->sg_data_len_ = 0;
313 this->sg_recv_data_state_ = FRAME_IDLE;
314 } else {
315 this->sg_frame_buf_[5] = value;
316 this->sg_frame_len_ = 6;
317 this->sg_recv_data_state_ = FRAME_DATA_BYTES;
318 }
319 break;
320 case FRAME_DATA_BYTES:
321 this->sg_frame_buf_[this->sg_frame_len_++] = value;
322 if (--this->sg_data_len_ == 0) {
323 this->sg_recv_data_state_ = FRAME_DATA_CRC;
324 }
325 break;
326 case FRAME_DATA_CRC:
327 this->sg_frame_buf_[this->sg_frame_len_++] = value;
328 this->sg_recv_data_state_ = FRAME_TAIL1;
329 break;
330 case FRAME_TAIL1:
331 if (FRAME_TAIL1_VALUE == value) {
332 this->sg_recv_data_state_ = FRAME_TAIL2;
333 } else {
334 this->sg_recv_data_state_ = FRAME_IDLE;
335 this->sg_frame_len_ = 0;
336 this->sg_data_len_ = 0;
337 ESP_LOGD(TAG, "FRAME_TAIL1 ERROR value:%x", value);
338 }
339 break;
340 case FRAME_TAIL2:
341 if (FRAME_TAIL2_VALUE == value) {
342 this->sg_frame_buf_[this->sg_frame_len_++] = FRAME_TAIL1_VALUE;
343 this->sg_frame_buf_[this->sg_frame_len_++] = FRAME_TAIL2_VALUE;
344 memcpy(this->sg_frame_prase_buf_, this->sg_frame_buf_, this->sg_frame_len_);
345 if (get_frame_check_status(this->sg_frame_prase_buf_, this->sg_frame_len_)) {
346 this->r24_parse_data_frame_(this->sg_frame_prase_buf_, this->sg_frame_len_);
347 } else {
348 ESP_LOGD(TAG, "frame check failer!");
349 }
350 } else {
351 ESP_LOGD(TAG, "FRAME_TAIL2 ERROR value:%x", value);
352 }
353 memset(this->sg_frame_prase_buf_, 0, FRAME_BUF_MAX_SIZE);
354 memset(this->sg_frame_buf_, 0, FRAME_BUF_MAX_SIZE);
355 this->sg_frame_len_ = 0;
356 this->sg_data_len_ = 0;
357 this->sg_recv_data_state_ = FRAME_IDLE;
358 break;
359 default:
360 this->sg_recv_data_state_ = FRAME_IDLE;
361 }
362}
363
364// Parses data frames related to product information
365void MR24HPC1Component::r24_frame_parse_product_information_(uint8_t *data) {
366#ifdef USE_TEXT_SENSOR
367 uint16_t product_len = encode_uint16(data[FRAME_COMMAND_WORD_INDEX + 1], data[FRAME_COMMAND_WORD_INDEX + 2]);
368 if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_PRODUCT_MODE) {
369 if ((this->product_model_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) {
370 memset(this->c_product_mode_, 0, PRODUCT_BUF_MAX_SIZE);
371 memcpy(this->c_product_mode_, &data[FRAME_DATA_INDEX], product_len);
372 this->product_model_text_sensor_->publish_state(this->c_product_mode_);
373 } else {
374 ESP_LOGD(TAG, "Reply: get product_mode error!");
375 }
376 } else if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_PRODUCT_ID) {
377 if ((this->product_id_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) {
378 memset(this->c_product_id_, 0, PRODUCT_BUF_MAX_SIZE);
379 memcpy(this->c_product_id_, &data[FRAME_DATA_INDEX], product_len);
380 this->product_id_text_sensor_->publish_state(this->c_product_id_);
381 } else {
382 ESP_LOGD(TAG, "Reply: get productId error!");
383 }
384 } else if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_HARDWARE_MODEL) {
385 if ((this->hardware_model_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) {
386 memset(this->c_hardware_model_, 0, PRODUCT_BUF_MAX_SIZE);
387 memcpy(this->c_hardware_model_, &data[FRAME_DATA_INDEX], product_len);
388 this->hardware_model_text_sensor_->publish_state(this->c_hardware_model_);
389 ESP_LOGD(TAG, "Reply: get hardware_model :%s", this->c_hardware_model_);
390 } else {
391 ESP_LOGD(TAG, "Reply: get hardwareModel error!");
392 }
393 } else if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_FIRMWARE_VERSION) {
394 if ((this->firware_version_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) {
395 memset(this->c_firmware_version_, 0, PRODUCT_BUF_MAX_SIZE);
396 memcpy(this->c_firmware_version_, &data[FRAME_DATA_INDEX], product_len);
397 this->firware_version_text_sensor_->publish_state(this->c_firmware_version_);
398 } else {
399 ESP_LOGD(TAG, "Reply: get firmwareVersion error!");
400 }
401 }
402#endif
403}
404
405// Parsing the underlying open parameters
406void MR24HPC1Component::r24_frame_parse_open_underlying_information_(uint8_t *data) {
407 switch (data[FRAME_COMMAND_WORD_INDEX]) {
408 case 0x00:
409 case 0x80:
410#ifdef USE_SWITCH
411 if (this->underlying_open_function_switch_ != nullptr) {
412 this->underlying_open_function_switch_->publish_state(data[FRAME_DATA_INDEX]);
413 }
414#endif
415 this->s_output_info_switch_flag_ = data[FRAME_DATA_INDEX] ? OUTPUT_SWITCH_ON : OUTPUT_SWTICH_OFF;
416 break;
417#ifdef USE_SENSOR
418 case 0x01:
419 if (this->custom_spatial_static_value_sensor_ != nullptr) {
420 this->custom_spatial_static_value_sensor_->publish_state(data[FRAME_DATA_INDEX]);
421 }
422 if (this->custom_presence_of_detection_sensor_ != nullptr) {
423 this->custom_presence_of_detection_sensor_->publish_state(data[FRAME_DATA_INDEX + 1] * 0.5f);
424 }
425 if (this->custom_spatial_motion_value_sensor_ != nullptr) {
426 this->custom_spatial_motion_value_sensor_->publish_state(data[FRAME_DATA_INDEX + 2]);
427 }
428 if (this->custom_motion_distance_sensor_ != nullptr) {
429 this->custom_motion_distance_sensor_->publish_state(data[FRAME_DATA_INDEX + 3] * 0.5f);
430 }
431 if (this->custom_motion_speed_sensor_ != nullptr) {
432 this->custom_motion_speed_sensor_->publish_state((data[FRAME_DATA_INDEX + 4] - 10) * 0.5f);
433 }
434 break;
435 case 0x07:
436 case 0x87:
437 if (this->movement_signs_sensor_ != nullptr) {
438 this->movement_signs_sensor_->publish_state(data[FRAME_DATA_INDEX]);
439 }
440 break;
441 case 0x81:
442 if (this->custom_spatial_static_value_sensor_ != nullptr) {
443 this->custom_spatial_static_value_sensor_->publish_state(data[FRAME_DATA_INDEX]);
444 }
445 break;
446 case 0x82:
447 if (this->custom_spatial_motion_value_sensor_ != nullptr) {
448 this->custom_spatial_motion_value_sensor_->publish_state(data[FRAME_DATA_INDEX]);
449 }
450 break;
451 case 0x83:
452 if (this->custom_presence_of_detection_sensor_ != nullptr &&
453 data[FRAME_DATA_INDEX] < std::size(S_PRESENCE_OF_DETECTION_RANGE_STR)) {
454 this->custom_presence_of_detection_sensor_->publish_state(
455 S_PRESENCE_OF_DETECTION_RANGE_STR[data[FRAME_DATA_INDEX]]);
456 }
457 break;
458 case 0x84:
459 if (this->custom_motion_distance_sensor_ != nullptr) {
460 this->custom_motion_distance_sensor_->publish_state(data[FRAME_DATA_INDEX] * 0.5f);
461 }
462 break;
463 case 0x85:
464 if (this->custom_motion_speed_sensor_ != nullptr) {
465 this->custom_motion_speed_sensor_->publish_state((data[FRAME_DATA_INDEX] - 10) * 0.5f);
466 }
467 break;
468#endif
469#ifdef USE_TEXT_SENSOR
470 case 0x06:
471 case 0x86:
472 // none:0x00 close_to:0x01 far_away:0x02
473 if ((this->keep_away_text_sensor_ != nullptr) && (data[FRAME_DATA_INDEX] < 3)) {
474 this->keep_away_text_sensor_->publish_state(S_KEEP_AWAY_STR[data[FRAME_DATA_INDEX]]);
475 }
476 break;
477#endif
478#ifdef USE_NUMBER
479 case 0x08:
480 case 0x88:
481 if (this->existence_threshold_number_ != nullptr) {
482 this->existence_threshold_number_->publish_state(data[FRAME_DATA_INDEX]);
483 }
484 break;
485 case 0x09:
486 case 0x89:
487 if (this->motion_threshold_number_ != nullptr) {
488 this->motion_threshold_number_->publish_state(data[FRAME_DATA_INDEX]);
489 }
490 break;
491 case 0x0c:
492 case 0x8c:
493 if (this->motion_trigger_number_ != nullptr) {
494 uint32_t motion_trigger_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1],
495 data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]);
496 this->motion_trigger_number_->publish_state(motion_trigger_time);
497 }
498 break;
499 case 0x0d:
500 case 0x8d:
501 if (this->motion_to_rest_number_ != nullptr) {
502 uint32_t move_to_rest_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1],
503 data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]);
504 this->motion_to_rest_number_->publish_state(move_to_rest_time);
505 }
506 break;
507 case 0x0e:
508 case 0x8e:
509 if (this->custom_unman_time_number_ != nullptr) {
510 uint32_t enter_unmanned_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1],
511 data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]);
512 this->custom_unman_time_number_->publish_state(enter_unmanned_time / 1000.0f);
513 }
514 break;
515#endif
516#ifdef USE_SELECT
517 case 0x0a:
518 case 0x8a:
519 if (this->existence_boundary_select_ != nullptr) {
520 if (this->existence_boundary_select_->has_index(data[FRAME_DATA_INDEX] - 1)) {
521 this->existence_boundary_select_->publish_state(data[FRAME_DATA_INDEX] - 1);
522 }
523 }
524 break;
525 case 0x0b:
526 case 0x8b:
527 if (this->motion_boundary_select_ != nullptr) {
528 if (this->motion_boundary_select_->has_index(data[FRAME_DATA_INDEX] - 1)) {
529 this->motion_boundary_select_->publish_state(data[FRAME_DATA_INDEX] - 1);
530 }
531 }
532 break;
533#endif
534 }
535}
536
537void MR24HPC1Component::r24_parse_data_frame_(uint8_t *data, uint8_t len) {
538 switch (data[FRAME_CONTROL_WORD_INDEX]) {
539 case 0x01: {
540 if (data[FRAME_COMMAND_WORD_INDEX] == 0x02) {
541 ESP_LOGD(TAG, "Reply: query restart packet");
542 break;
543 }
544#ifdef USE_TEXT_SENSOR
545 if (this->heartbeat_state_text_sensor_ != nullptr) {
546 this->heartbeat_state_text_sensor_->publish_state(
547 data[FRAME_COMMAND_WORD_INDEX] == 0x01 ? "Equipment Normal" : "Equipment Abnormal");
548 }
549#endif
550 } break;
551 case 0x02: {
552 this->r24_frame_parse_product_information_(data);
553 } break;
554 case 0x05: {
555 this->r24_frame_parse_work_status_(data);
556 } break;
557 case 0x08: {
558 this->r24_frame_parse_open_underlying_information_(data);
559 } break;
560 case 0x80: {
561 this->r24_frame_parse_human_information_(data);
562 } break;
563 default:
564 ESP_LOGD(TAG, "control word:0x%02X not found", data[FRAME_CONTROL_WORD_INDEX]);
565 break;
566 }
567}
568
569void MR24HPC1Component::r24_frame_parse_work_status_(uint8_t *data) {
570 switch (data[FRAME_COMMAND_WORD_INDEX]) {
571 case 0x01:
572 case 0x81:
573 ESP_LOGD(TAG, "Reply: get radar init status 0x%02X", data[FRAME_DATA_INDEX]);
574 break;
575 case 0x09:
576#ifdef USE_SENSOR
577 if (this->custom_mode_num_sensor_ != nullptr) {
578 this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]);
579 }
580#endif
581#ifdef USE_NUMBER
582 if (this->custom_mode_number_ != nullptr) {
583 this->custom_mode_number_->publish_state(0);
584 }
585#endif
586#ifdef USE_TEXT_SENSOR
587 if (this->custom_mode_end_text_sensor_ != nullptr) {
588 this->custom_mode_end_text_sensor_->publish_state("Setup in progress");
589 }
590#endif
591 break;
592 case 0x89:
593#ifdef USE_SENSOR
594 if (this->custom_mode_num_sensor_ != nullptr) {
595 this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]);
596 }
597#endif
598 if (data[FRAME_DATA_INDEX] == 0) {
599#ifdef USE_TEXT_SENSOR
600 if (this->custom_mode_end_text_sensor_ != nullptr) {
601 this->custom_mode_end_text_sensor_->publish_state("Not in custom mode");
602 }
603#endif
604#ifdef USE_NUMBER
605 if (this->custom_mode_number_ != nullptr) {
606 this->custom_mode_number_->publish_state(0);
607 }
608#endif
609 }
610 break;
611#ifdef USE_SELECT
612 case 0x07:
613 case 0x87:
614 if ((this->scene_mode_select_ != nullptr) && (this->scene_mode_select_->has_index(data[FRAME_DATA_INDEX]))) {
615 this->scene_mode_select_->publish_state(data[FRAME_DATA_INDEX]);
616 } else {
617 ESP_LOGD(TAG, "Select has index offset %d Error", data[FRAME_DATA_INDEX]);
618 }
619 break;
620#endif
621#ifdef USE_NUMBER
622 case 0x08:
623 case 0x88:
624 if (this->sensitivity_number_ != nullptr) {
625 this->sensitivity_number_->publish_state(data[FRAME_DATA_INDEX]);
626 }
627 break;
628#endif
629#ifdef USE_TEXT_SENSOR
630 case 0x0A:
631 if (this->custom_mode_end_text_sensor_ != nullptr) {
632 this->custom_mode_end_text_sensor_->publish_state("Set Success!");
633 }
634 break;
635#endif
636 default:
637 ESP_LOGD(TAG, "[%s] No found COMMAND_WORD(%02X) in Frame", __FUNCTION__, data[FRAME_COMMAND_WORD_INDEX]);
638 break;
639 }
640}
641
642void MR24HPC1Component::r24_frame_parse_human_information_(uint8_t *data) {
643 switch (data[FRAME_COMMAND_WORD_INDEX]) {
644#ifdef USE_BINARY_SENSOR
645 case 0x01:
646 case 0x81:
647 if (this->has_target_binary_sensor_ != nullptr && data[FRAME_DATA_INDEX] < std::size(S_SOMEONE_EXISTS_STR)) {
648 this->has_target_binary_sensor_->publish_state(S_SOMEONE_EXISTS_STR[data[FRAME_DATA_INDEX]]);
649 }
650 break;
651#endif
652#ifdef USE_SENSOR
653 case 0x03:
654 case 0x83:
655 if (this->movement_signs_sensor_ != nullptr) {
656 this->movement_signs_sensor_->publish_state(data[FRAME_DATA_INDEX]);
657 }
658 break;
659#endif
660#ifdef USE_TEXT_SENSOR
661 case 0x02:
662 case 0x82:
663 if ((this->motion_status_text_sensor_ != nullptr) && (data[FRAME_DATA_INDEX] < 3)) {
664 this->motion_status_text_sensor_->publish_state(S_MOTION_STATUS_STR[data[FRAME_DATA_INDEX]]);
665 }
666 break;
667 case 0x0B:
668 case 0x8B:
669 // none:0x00 close_to:0x01 far_away:0x02
670 if ((this->keep_away_text_sensor_ != nullptr) && (data[FRAME_DATA_INDEX] < 3)) {
671 this->keep_away_text_sensor_->publish_state(S_KEEP_AWAY_STR[data[FRAME_DATA_INDEX]]);
672 }
673 break;
674#endif
675#ifdef USE_SELECT
676 case 0x0A:
677 case 0x8A:
678 // none:0x00 1s:0x01 30s:0x02 1min:0x03 2min:0x04 5min:0x05 10min:0x06 30min:0x07 1hour:0x08
679 if ((this->unman_time_select_ != nullptr) && (data[FRAME_DATA_INDEX] < 9)) {
680 this->unman_time_select_->publish_state(data[FRAME_DATA_INDEX]);
681 }
682 break;
683#endif
684 default:
685 ESP_LOGD(TAG, "[%s] No found COMMAND_WORD(%02X) in Frame", __FUNCTION__, data[FRAME_COMMAND_WORD_INDEX]);
686 break;
687 }
688}
689
690// Sending data frames
691void MR24HPC1Component::send_query_(const uint8_t *query, size_t string_length) {
692 this->write_array(query, string_length);
693}
694
695// Send Heartbeat Packet Command
696void MR24HPC1Component::get_heartbeat_packet() { this->send_query_(GET_HEARTBEAT, sizeof(GET_HEARTBEAT)); }
697
698// Issuance of the underlying open parameter query command
700 this->send_query_(GET_RADAR_OUTPUT_INFORMATION_SWITCH, sizeof(GET_RADAR_OUTPUT_INFORMATION_SWITCH));
701}
702
703// Issuance of product model orders
704void MR24HPC1Component::get_product_mode() { this->send_query_(GET_PRODUCT_MODE, sizeof(GET_PRODUCT_MODE)); }
705
706// Issuing the Get Product ID command
707void MR24HPC1Component::get_product_id() { this->send_query_(GET_PRODUCT_ID, sizeof(GET_PRODUCT_ID)); }
708
709// Issuing hardware model commands
710void MR24HPC1Component::get_hardware_model() { this->send_query_(GET_HARDWARE_MODEL, sizeof(GET_HARDWARE_MODEL)); }
711
712// Issuing software version commands
714 this->send_query_(GET_FIRMWARE_VERSION, sizeof(GET_FIRMWARE_VERSION));
715}
716
717void MR24HPC1Component::get_human_status() { this->send_query_(GET_HUMAN_STATUS, sizeof(GET_HUMAN_STATUS)); }
718
720 this->send_query_(GET_HUMAN_MOTION_INFORMATION, sizeof(GET_HUMAN_MOTION_INFORMATION));
721}
722
724 this->send_query_(GET_BODY_MOTION_PARAMETERS, sizeof(GET_BODY_MOTION_PARAMETERS));
725}
726
727void MR24HPC1Component::get_keep_away() { this->send_query_(GET_KEEP_AWAY, sizeof(GET_KEEP_AWAY)); }
728
729void MR24HPC1Component::get_scene_mode() { this->send_query_(GET_SCENE_MODE, sizeof(GET_SCENE_MODE)); }
730
731void MR24HPC1Component::get_sensitivity() { this->send_query_(GET_SENSITIVITY, sizeof(GET_SENSITIVITY)); }
732
733void MR24HPC1Component::get_unmanned_time() { this->send_query_(GET_UNMANNED_TIME, sizeof(GET_UNMANNED_TIME)); }
734
735void MR24HPC1Component::get_custom_mode() { this->send_query_(GET_CUSTOM_MODE, sizeof(GET_CUSTOM_MODE)); }
736
738 this->send_query_(GET_EXISTENCE_BOUNDARY, sizeof(GET_EXISTENCE_BOUNDARY));
739}
740
741void MR24HPC1Component::get_motion_boundary() { this->send_query_(GET_MOTION_BOUNDARY, sizeof(GET_MOTION_BOUNDARY)); }
742
744 this->send_query_(GET_SPATIAL_STATIC_VALUE, sizeof(GET_SPATIAL_STATIC_VALUE));
745}
746
748 this->send_query_(GET_SPATIAL_MOTION_VALUE, sizeof(GET_SPATIAL_MOTION_VALUE));
749}
750
752 this->send_query_(GET_DISTANCE_OF_STATIC_OBJECT, sizeof(GET_DISTANCE_OF_STATIC_OBJECT));
753}
754
756 this->send_query_(GET_DISTANCE_OF_MOVING_OBJECT, sizeof(GET_DISTANCE_OF_MOVING_OBJECT));
757}
758
760 this->send_query_(GET_TARGET_MOVEMENT_SPEED, sizeof(GET_TARGET_MOVEMENT_SPEED));
761}
762
764 this->send_query_(GET_EXISTENCE_THRESHOLD, sizeof(GET_EXISTENCE_THRESHOLD));
765}
766
768 this->send_query_(GET_MOTION_THRESHOLD, sizeof(GET_MOTION_THRESHOLD));
769}
770
772 this->send_query_(GET_MOTION_TRIGGER_TIME, sizeof(GET_MOTION_TRIGGER_TIME));
773}
774
776 this->send_query_(GET_MOTION_TO_REST_TIME, sizeof(GET_MOTION_TO_REST_TIME));
777}
778
780 this->send_query_(GET_CUSTOM_UNMAN_TIME, sizeof(GET_CUSTOM_UNMAN_TIME));
781}
782
783// Logic of setting: After setting, query whether the setting is successful or not!
784
786 if (enable) {
787 this->send_query_(UNDERLYING_SWITCH_ON, sizeof(UNDERLYING_SWITCH_ON));
788 } else {
789 this->send_query_(UNDERLYING_SWITCH_OFF, sizeof(UNDERLYING_SWITCH_OFF));
790 }
791#ifdef USE_TEXT_SENSOR
792 if (this->keep_away_text_sensor_ != nullptr) {
793 this->keep_away_text_sensor_->publish_state("");
794 }
795 if (this->motion_status_text_sensor_ != nullptr) {
796 this->motion_status_text_sensor_->publish_state("");
797 }
798#endif
799#ifdef USE_SENSOR
800 if (this->custom_spatial_static_value_sensor_ != nullptr) {
801 this->custom_spatial_static_value_sensor_->publish_state(NAN);
802 }
803 if (this->custom_spatial_motion_value_sensor_ != nullptr) {
804 this->custom_spatial_motion_value_sensor_->publish_state(NAN);
805 }
806 if (this->custom_motion_distance_sensor_ != nullptr) {
807 this->custom_motion_distance_sensor_->publish_state(NAN);
808 }
809 if (this->custom_presence_of_detection_sensor_ != nullptr) {
810 this->custom_presence_of_detection_sensor_->publish_state(NAN);
811 }
812 if (this->custom_motion_speed_sensor_ != nullptr) {
813 this->custom_motion_speed_sensor_->publish_state(NAN);
814 }
815#endif
816}
817
819 uint8_t send_data_len = 10;
820 uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x07, 0x00, 0x01, value, 0x00, 0x54, 0x43};
821 send_data[7] = get_frame_crc_sum(send_data, send_data_len);
822 this->send_query_(send_data, send_data_len);
823#ifdef USE_NUMBER
824 if (this->custom_mode_number_ != nullptr) {
825 this->custom_mode_number_->publish_state(0);
826 }
827#endif
828#ifdef USE_SENSOR
829 if (this->custom_mode_num_sensor_ != nullptr) {
830 this->custom_mode_num_sensor_->publish_state(0);
831 }
832#endif
833 this->get_scene_mode();
834 this->get_sensitivity();
835 this->get_custom_mode();
837 this->get_motion_boundary();
839 this->get_motion_threshold();
842 this->get_custom_unman_time();
843}
844
846 if (value == 0x00)
847 return;
848 uint8_t send_data_len = 10;
849 uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x08, 0x00, 0x01, value, 0x00, 0x54, 0x43};
850 send_data[7] = get_frame_crc_sum(send_data, send_data_len);
851 this->send_query_(send_data, send_data_len);
852 this->get_scene_mode();
853 this->get_sensitivity();
854}
855
857 this->send_query_(SET_RESTART, sizeof(SET_RESTART));
858 this->check_dev_inf_sign_ = true;
859}
860
862 uint8_t send_data_len = 10;
863 uint8_t send_data[10] = {0x53, 0x59, 0x80, 0x0a, 0x00, 0x01, value, 0x00, 0x54, 0x43};
864 send_data[7] = get_frame_crc_sum(send_data, send_data_len);
865 this->send_query_(send_data, send_data_len);
866 this->get_unmanned_time();
867}
868
870 if (mode == 0) {
871 this->set_custom_end_mode(); // Equivalent to end setting
872#ifdef USE_NUMBER
873 if (this->custom_mode_number_ != nullptr) {
874 this->custom_mode_number_->publish_state(0);
875 }
876#endif
877 return;
878 }
879 uint8_t send_data_len = 10;
880 uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x09, 0x00, 0x01, mode, 0x00, 0x54, 0x43};
881 send_data[7] = get_frame_crc_sum(send_data, send_data_len);
882 this->send_query_(send_data, send_data_len);
884 this->get_motion_boundary();
886 this->get_motion_threshold();
889 this->get_custom_unman_time();
890 this->get_custom_mode();
891 this->get_scene_mode();
892 this->get_sensitivity();
893}
894
896 uint8_t send_data_len = 10;
897 uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x0a, 0x00, 0x01, 0x0F, 0xCB, 0x54, 0x43};
898 this->send_query_(send_data, send_data_len);
899#ifdef USE_NUMBER
900 if (this->custom_mode_number_ != nullptr) {
901 this->custom_mode_number_->publish_state(0); // Clear setpoints
902 }
903#endif
905 this->get_motion_boundary();
907 this->get_motion_threshold();
910 this->get_custom_unman_time();
911 this->get_custom_mode();
912 this->get_scene_mode();
913 this->get_sensitivity();
914}
915
917#ifdef USE_SENSOR
918 if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
919 return; // You'll have to check that you're in custom mode to set it up
920#endif
921 uint8_t send_data_len = 10;
922 uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x0A, 0x00, 0x01, (uint8_t) (value + 1), 0x00, 0x54, 0x43};
923 send_data[7] = get_frame_crc_sum(send_data, send_data_len);
924 this->send_query_(send_data, send_data_len);
926}
927
929#ifdef USE_SENSOR
930 if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
931 return; // You'll have to check that you're in custom mode to set it up
932#endif
933 uint8_t send_data_len = 10;
934 uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x0B, 0x00, 0x01, (uint8_t) (value + 1), 0x00, 0x54, 0x43};
935 send_data[7] = get_frame_crc_sum(send_data, send_data_len);
936 this->send_query_(send_data, send_data_len);
937 this->get_motion_boundary();
938}
939
941#ifdef USE_SENSOR
942 if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
943 return; // You'll have to check that you're in custom mode to set it up
944#endif
945 uint8_t send_data_len = 10;
946 uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x08, 0x00, 0x01, value, 0x00, 0x54, 0x43};
947 send_data[7] = get_frame_crc_sum(send_data, send_data_len);
948 this->send_query_(send_data, send_data_len);
950}
951
953#ifdef USE_SENSOR
954 if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
955 return; // You'll have to check that you're in custom mode to set it up
956#endif
957 uint8_t send_data_len = 10;
958 uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x09, 0x00, 0x01, value, 0x00, 0x54, 0x43};
959 send_data[7] = get_frame_crc_sum(send_data, send_data_len);
960 this->send_query_(send_data, send_data_len);
961 this->get_motion_threshold();
962}
963
965#ifdef USE_SENSOR
966 if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
967 return; // You'll have to check that you're in custom mode to set it up
968#endif
969 uint8_t send_data_len = 13;
970 uint8_t send_data[13] = {0x53, 0x59, 0x08, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, value, 0x00, 0x54, 0x43};
971 send_data[10] = get_frame_crc_sum(send_data, send_data_len);
972 this->send_query_(send_data, send_data_len);
974}
975
977#ifdef USE_SENSOR
978 if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
979 return; // You'll have to check that you're in custom mode to set it up
980#endif
981 uint8_t h8_num = (value >> 8) & 0xff;
982 uint8_t l8_num = value & 0xff;
983 uint8_t send_data_len = 13;
984 uint8_t send_data[13] = {0x53, 0x59, 0x08, 0x0D, 0x00, 0x04, 0x00, 0x00, h8_num, l8_num, 0x00, 0x54, 0x43};
985 send_data[10] = get_frame_crc_sum(send_data, send_data_len);
986 this->send_query_(send_data, send_data_len);
988}
989
991#ifdef USE_SENSOR
992 if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0))
993 return; // You'll have to check that you're in custom mode to set it up
994#endif
995 uint32_t value_ms = value * 1000;
996 uint8_t h24_num = (value_ms >> 24) & 0xff;
997 uint8_t h16_num = (value_ms >> 16) & 0xff;
998 uint8_t h8_num = (value_ms >> 8) & 0xff;
999 uint8_t l8_num = value_ms & 0xff;
1000 uint8_t send_data_len = 13;
1001 uint8_t send_data[13] = {0x53, 0x59, 0x08, 0x0E, 0x00, 0x04, h24_num, h16_num, h8_num, l8_num, 0x00, 0x54, 0x43};
1002 send_data[10] = get_frame_crc_sum(send_data, send_data_len);
1003 this->send_query_(send_data, send_data_len);
1004 this->get_custom_unman_time();
1005}
1006
1007} // namespace seeed_mr24hpc1
1008} // 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:358
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:892
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:736
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:728
static void uint32_t