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