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