mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-29 22:24:26 +00:00 
			
		
		
		
	Add Seeed Studio mmWave Kit MR24HPC1 (#5761)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Peter Pan <twinkle-pirate@hotmail.com>
This commit is contained in:
		| @@ -290,6 +290,7 @@ esphome/components/scd4x/* @martgras @sjtrny | ||||
| esphome/components/script/* @esphome/core | ||||
| esphome/components/sdm_meter/* @jesserockz @polyfaces | ||||
| esphome/components/sdp3x/* @Azimath | ||||
| esphome/components/seeed_mr24hpc1/* @limengdu | ||||
| esphome/components/selec_meter/* @sourabhjaiswal | ||||
| esphome/components/select/* @esphome/core | ||||
| esphome/components/sen0321/* @notjj | ||||
|   | ||||
							
								
								
									
										51
									
								
								esphome/components/seeed_mr24hpc1/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								esphome/components/seeed_mr24hpc1/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import uart | ||||
| from esphome.const import CONF_ID | ||||
|  | ||||
| DEPENDENCIES = ["uart"] | ||||
| # is the code owner of the relevant code base | ||||
| CODEOWNERS = ["@limengdu"] | ||||
| # The current component or platform can be configured or defined multiple times in the same configuration file. | ||||
| MULTI_CONF = True | ||||
|  | ||||
| # This line of code creates a new namespace called mr24hpc1_ns. | ||||
| # This namespace will be used as a prefix for all classes, functions and variables associated with the mr24hpc1_ns component, ensuring that they do not conflict with the names of other components. | ||||
| mr24hpc1_ns = cg.esphome_ns.namespace("seeed_mr24hpc1") | ||||
| # This MR24HPC1Component class will be a periodically polled UART device | ||||
| MR24HPC1Component = mr24hpc1_ns.class_( | ||||
|     "MR24HPC1Component", cg.Component, uart.UARTDevice | ||||
| ) | ||||
|  | ||||
| CONF_MR24HPC1_ID = "mr24hpc1_id" | ||||
|  | ||||
| CONFIG_SCHEMA = ( | ||||
|     cv.Schema( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(MR24HPC1Component), | ||||
|         } | ||||
|     ) | ||||
|     .extend(uart.UART_DEVICE_SCHEMA) | ||||
|     .extend(cv.COMPONENT_SCHEMA) | ||||
| ) | ||||
|  | ||||
| # A verification mode was created to verify the configuration parameters of a UART device named "seeed_mr24hpc1". | ||||
| # This authentication mode requires that the device must have transmit and receive functionality, a parity mode of "NONE", and a stop bit of one. | ||||
| FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema( | ||||
|     "seeed_mr24hpc1", | ||||
|     require_tx=True, | ||||
|     require_rx=True, | ||||
|     parity="NONE", | ||||
|     stop_bits=1, | ||||
| ) | ||||
|  | ||||
|  | ||||
| # The async def keyword is used to define a concurrent function. | ||||
| # Concurrent functions are special functions designed to work with Python's asyncio library to support asynchronous I/O operations. | ||||
| async def to_code(config): | ||||
|     # This line of code creates a new Pvariable (a Python object representing a C++ variable) with the variable's ID taken from the configuration. | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     # This line of code registers the newly created Pvariable as a component so that ESPHome can manage it at runtime. | ||||
|     await cg.register_component(var, config) | ||||
|     # This line of code registers the newly created Pvariable as a device. | ||||
|     await uart.register_uart_device(var, config) | ||||
							
								
								
									
										23
									
								
								esphome/components/seeed_mr24hpc1/binary_sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								esphome/components/seeed_mr24hpc1/binary_sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import binary_sensor | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     DEVICE_CLASS_OCCUPANCY, | ||||
| ) | ||||
| from . import CONF_MR24HPC1_ID, MR24HPC1Component | ||||
|  | ||||
| CONF_HAS_TARGET = "has_target" | ||||
|  | ||||
| CONFIG_SCHEMA = { | ||||
|     cv.GenerateID(CONF_MR24HPC1_ID): cv.use_id(MR24HPC1Component), | ||||
|     cv.Optional(CONF_HAS_TARGET): binary_sensor.binary_sensor_schema( | ||||
|         device_class=DEVICE_CLASS_OCCUPANCY, icon="mdi:motion-sensor" | ||||
|     ), | ||||
| } | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) | ||||
|     if has_target_config := config.get(CONF_HAS_TARGET): | ||||
|         sens = await binary_sensor.new_binary_sensor(has_target_config) | ||||
|         cg.add(mr24hpc1_component.set_has_target_binary_sensor(sens)) | ||||
							
								
								
									
										42
									
								
								esphome/components/seeed_mr24hpc1/button/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								esphome/components/seeed_mr24hpc1/button/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import button | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     DEVICE_CLASS_RESTART, | ||||
|     ENTITY_CATEGORY_CONFIG, | ||||
|     ICON_RESTART_ALERT, | ||||
| ) | ||||
| from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns | ||||
|  | ||||
| RestartButton = mr24hpc1_ns.class_("RestartButton", button.Button) | ||||
| CustomSetEndButton = mr24hpc1_ns.class_("CustomSetEndButton", button.Button) | ||||
|  | ||||
| CONF_RESTART = "restart" | ||||
| CONF_CUSTOM_SET_END = "custom_set_end" | ||||
|  | ||||
| CONFIG_SCHEMA = { | ||||
|     cv.GenerateID(CONF_MR24HPC1_ID): cv.use_id(MR24HPC1Component), | ||||
|     cv.Optional(CONF_RESTART): button.button_schema( | ||||
|         RestartButton, | ||||
|         device_class=DEVICE_CLASS_RESTART, | ||||
|         entity_category=ENTITY_CATEGORY_CONFIG, | ||||
|         icon=ICON_RESTART_ALERT, | ||||
|     ), | ||||
|     cv.Optional(CONF_CUSTOM_SET_END): button.button_schema( | ||||
|         CustomSetEndButton, | ||||
|         entity_category=ENTITY_CATEGORY_CONFIG, | ||||
|         icon="mdi:cog", | ||||
|     ), | ||||
| } | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) | ||||
|     if restart_config := config.get(CONF_RESTART): | ||||
|         b = await button.new_button(restart_config) | ||||
|         await cg.register_parented(b, config[CONF_MR24HPC1_ID]) | ||||
|         cg.add(mr24hpc1_component.set_restart_button(b)) | ||||
|     if custom_set_end_config := config.get(CONF_CUSTOM_SET_END): | ||||
|         b = await button.new_button(custom_set_end_config) | ||||
|         await cg.register_parented(b, config[CONF_MR24HPC1_ID]) | ||||
|         cg.add(mr24hpc1_component.set_custom_set_end_button(b)) | ||||
| @@ -0,0 +1,9 @@ | ||||
| #include "custom_mode_end_button.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| void CustomSetEndButton::press_action() { this->parent_->set_custom_end_mode(); } | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/button/button.h" | ||||
| #include "../seeed_mr24hpc1.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| class CustomSetEndButton : public button::Button, public Parented<MR24HPC1Component> { | ||||
|  public: | ||||
|   CustomSetEndButton() = default; | ||||
|  | ||||
|  protected: | ||||
|   void press_action() override; | ||||
| }; | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,9 @@ | ||||
| #include "restart_button.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| void RestartButton::press_action() { this->parent_->set_restart(); } | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										18
									
								
								esphome/components/seeed_mr24hpc1/button/restart_button.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								esphome/components/seeed_mr24hpc1/button/restart_button.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/button/button.h" | ||||
| #include "../seeed_mr24hpc1.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| class RestartButton : public button::Button, public Parented<MR24HPC1Component> { | ||||
|  public: | ||||
|   RestartButton() = default; | ||||
|  | ||||
|  protected: | ||||
|   void press_action() override; | ||||
| }; | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										132
									
								
								esphome/components/seeed_mr24hpc1/number/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								esphome/components/seeed_mr24hpc1/number/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,132 @@ | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import number | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     ENTITY_CATEGORY_CONFIG, | ||||
| ) | ||||
| from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns | ||||
|  | ||||
| SensitivityNumber = mr24hpc1_ns.class_("SensitivityNumber", number.Number) | ||||
| CustomModeNumber = mr24hpc1_ns.class_("CustomModeNumber", number.Number) | ||||
| ExistenceThresholdNumber = mr24hpc1_ns.class_("ExistenceThresholdNumber", number.Number) | ||||
| MotionThresholdNumber = mr24hpc1_ns.class_("MotionThresholdNumber", number.Number) | ||||
| MotionTriggerTimeNumber = mr24hpc1_ns.class_("MotionTriggerTimeNumber", number.Number) | ||||
| MotionToRestTimeNumber = mr24hpc1_ns.class_("MotionToRestTimeNumber", number.Number) | ||||
| CustomUnmanTimeNumber = mr24hpc1_ns.class_("CustomUnmanTimeNumber", number.Number) | ||||
|  | ||||
| CONF_SENSITIVITY = "sensitivity" | ||||
| CONF_CUSTOM_MODE = "custom_mode" | ||||
| CONF_EXISTENCE_THRESHOLD = "existence_threshold" | ||||
| CONF_MOTION_THRESHOLD = "motion_threshold" | ||||
| CONF_MOTION_TRIGGER = "motion_trigger" | ||||
| CONF_MOTION_TO_REST = "motion_to_rest" | ||||
| CONF_CUSTOM_UNMAN_TIME = "custom_unman_time" | ||||
|  | ||||
| CONFIG_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.GenerateID(CONF_MR24HPC1_ID): cv.use_id(MR24HPC1Component), | ||||
|         cv.Optional(CONF_SENSITIVITY): number.number_schema( | ||||
|             SensitivityNumber, | ||||
|             entity_category=ENTITY_CATEGORY_CONFIG, | ||||
|             icon="mdi:archive-check-outline", | ||||
|         ), | ||||
|         cv.Optional(CONF_CUSTOM_MODE): number.number_schema( | ||||
|             CustomModeNumber, | ||||
|             entity_category=ENTITY_CATEGORY_CONFIG, | ||||
|             icon="mdi:cog", | ||||
|         ), | ||||
|         cv.Optional(CONF_EXISTENCE_THRESHOLD): number.number_schema( | ||||
|             ExistenceThresholdNumber, | ||||
|             entity_category=ENTITY_CATEGORY_CONFIG, | ||||
|         ), | ||||
|         cv.Optional(CONF_MOTION_THRESHOLD): number.number_schema( | ||||
|             MotionThresholdNumber, | ||||
|             entity_category=ENTITY_CATEGORY_CONFIG, | ||||
|         ), | ||||
|         cv.Optional(CONF_MOTION_TRIGGER): number.number_schema( | ||||
|             MotionTriggerTimeNumber, | ||||
|             entity_category=ENTITY_CATEGORY_CONFIG, | ||||
|             icon="mdi:camera-timer", | ||||
|             unit_of_measurement="ms", | ||||
|         ), | ||||
|         cv.Optional(CONF_MOTION_TO_REST): number.number_schema( | ||||
|             MotionToRestTimeNumber, | ||||
|             entity_category=ENTITY_CATEGORY_CONFIG, | ||||
|             icon="mdi:camera-timer", | ||||
|             unit_of_measurement="ms", | ||||
|         ), | ||||
|         cv.Optional(CONF_CUSTOM_UNMAN_TIME): number.number_schema( | ||||
|             CustomUnmanTimeNumber, | ||||
|             entity_category=ENTITY_CATEGORY_CONFIG, | ||||
|             icon="mdi:camera-timer", | ||||
|             unit_of_measurement="s", | ||||
|         ), | ||||
|     } | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) | ||||
|     if sensitivity_config := config.get(CONF_SENSITIVITY): | ||||
|         n = await number.new_number( | ||||
|             sensitivity_config, | ||||
|             min_value=0, | ||||
|             max_value=3, | ||||
|             step=1, | ||||
|         ) | ||||
|         await cg.register_parented(n, mr24hpc1_component) | ||||
|         cg.add(mr24hpc1_component.set_sensitivity_number(n)) | ||||
|     if custom_mode_config := config.get(CONF_CUSTOM_MODE): | ||||
|         n = await number.new_number( | ||||
|             custom_mode_config, | ||||
|             min_value=0, | ||||
|             max_value=4, | ||||
|             step=1, | ||||
|         ) | ||||
|         await cg.register_parented(n, mr24hpc1_component) | ||||
|         cg.add(mr24hpc1_component.set_custom_mode_number(n)) | ||||
|     if existence_threshold_config := config.get(CONF_EXISTENCE_THRESHOLD): | ||||
|         n = await number.new_number( | ||||
|             existence_threshold_config, | ||||
|             min_value=0, | ||||
|             max_value=250, | ||||
|             step=1, | ||||
|         ) | ||||
|         await cg.register_parented(n, mr24hpc1_component) | ||||
|         cg.add(mr24hpc1_component.set_existence_threshold_number(n)) | ||||
|     if motion_threshold_config := config.get(CONF_MOTION_THRESHOLD): | ||||
|         n = await number.new_number( | ||||
|             motion_threshold_config, | ||||
|             min_value=0, | ||||
|             max_value=250, | ||||
|             step=1, | ||||
|         ) | ||||
|         await cg.register_parented(n, mr24hpc1_component) | ||||
|         cg.add(mr24hpc1_component.set_motion_threshold_number(n)) | ||||
|     if motion_trigger_config := config.get(CONF_MOTION_TRIGGER): | ||||
|         n = await number.new_number( | ||||
|             motion_trigger_config, | ||||
|             min_value=0, | ||||
|             max_value=150, | ||||
|             step=1, | ||||
|         ) | ||||
|         await cg.register_parented(n, mr24hpc1_component) | ||||
|         cg.add(mr24hpc1_component.set_motion_trigger_number(n)) | ||||
|     if motion_to_rest_config := config.get(CONF_MOTION_TO_REST): | ||||
|         n = await number.new_number( | ||||
|             motion_to_rest_config, | ||||
|             min_value=0, | ||||
|             max_value=3000, | ||||
|             step=1, | ||||
|         ) | ||||
|         await cg.register_parented(n, mr24hpc1_component) | ||||
|         cg.add(mr24hpc1_component.set_motion_to_rest_number(n)) | ||||
|     if custom_unman_time_config := config.get(CONF_CUSTOM_UNMAN_TIME): | ||||
|         n = await number.new_number( | ||||
|             custom_unman_time_config, | ||||
|             min_value=0, | ||||
|             max_value=3600, | ||||
|             step=1, | ||||
|         ) | ||||
|         await cg.register_parented(n, mr24hpc1_component) | ||||
|         cg.add(mr24hpc1_component.set_custom_unman_time_number(n)) | ||||
| @@ -0,0 +1,12 @@ | ||||
| #include "custom_mode_number.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| void CustomModeNumber::control(float value) { | ||||
|   this->publish_state(value); | ||||
|   this->parent_->set_custom_mode(value); | ||||
| } | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/number/number.h" | ||||
| #include "../seeed_mr24hpc1.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| class CustomModeNumber : public number::Number, public Parented<MR24HPC1Component> { | ||||
|  public: | ||||
|   CustomModeNumber() = default; | ||||
|  | ||||
|  protected: | ||||
|   void control(float value) override; | ||||
| }; | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,9 @@ | ||||
| #include "custom_unman_time_number.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| void CustomUnmanTimeNumber::control(float value) { this->parent_->set_custom_unman_time(value); } | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/number/number.h" | ||||
| #include "../seeed_mr24hpc1.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| class CustomUnmanTimeNumber : public number::Number, public Parented<MR24HPC1Component> { | ||||
|  public: | ||||
|   CustomUnmanTimeNumber() = default; | ||||
|  | ||||
|  protected: | ||||
|   void control(float value) override; | ||||
| }; | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,9 @@ | ||||
| #include "existence_threshold_number.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| void ExistenceThresholdNumber::control(float value) { this->parent_->set_existence_threshold(value); } | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/number/number.h" | ||||
| #include "../seeed_mr24hpc1.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| class ExistenceThresholdNumber : public number::Number, public Parented<MR24HPC1Component> { | ||||
|  public: | ||||
|   ExistenceThresholdNumber() = default; | ||||
|  | ||||
|  protected: | ||||
|   void control(float value) override; | ||||
| }; | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,9 @@ | ||||
| #include "motion_threshold_number.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| void MotionThresholdNumber::control(float value) { this->parent_->set_motion_threshold(value); } | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/number/number.h" | ||||
| #include "../seeed_mr24hpc1.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| class MotionThresholdNumber : public number::Number, public Parented<MR24HPC1Component> { | ||||
|  public: | ||||
|   MotionThresholdNumber() = default; | ||||
|  | ||||
|  protected: | ||||
|   void control(float value) override; | ||||
| }; | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,9 @@ | ||||
| #include "motion_trigger_time_number.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| void MotionTriggerTimeNumber::control(float value) { this->parent_->set_motion_trigger_time(value); } | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/number/number.h" | ||||
| #include "../seeed_mr24hpc1.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| class MotionTriggerTimeNumber : public number::Number, public Parented<MR24HPC1Component> { | ||||
|  public: | ||||
|   MotionTriggerTimeNumber() = default; | ||||
|  | ||||
|  protected: | ||||
|   void control(float value) override; | ||||
| }; | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,9 @@ | ||||
| #include "motiontorest_time_number.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| void MotionToRestTimeNumber::control(float value) { this->parent_->set_motion_to_rest_time(value); } | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/number/number.h" | ||||
| #include "../seeed_mr24hpc1.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| class MotionToRestTimeNumber : public number::Number, public Parented<MR24HPC1Component> { | ||||
|  public: | ||||
|   MotionToRestTimeNumber() = default; | ||||
|  | ||||
|  protected: | ||||
|   void control(float value) override; | ||||
| }; | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,9 @@ | ||||
| #include "sensitivity_number.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| void SensitivityNumber::control(float value) { this->parent_->set_sensitivity(value); } | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/number/number.h" | ||||
| #include "../seeed_mr24hpc1.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| class SensitivityNumber : public number::Number, public Parented<MR24HPC1Component> { | ||||
|  public: | ||||
|   SensitivityNumber() = default; | ||||
|  | ||||
|  protected: | ||||
|   void control(float value) override; | ||||
| }; | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										890
									
								
								esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										890
									
								
								esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,890 @@ | ||||
| #include "seeed_mr24hpc1.h" | ||||
|  | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| #include <utility> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| static const char *const TAG = "seeed_mr24hpc1"; | ||||
|  | ||||
| // Prints the component's configuration data. dump_config() prints all of the component's configuration | ||||
| // items in an easy-to-read format, including the configuration key-value pairs. | ||||
| void MR24HPC1Component::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "MR24HPC1:"); | ||||
| #ifdef USE_TEXT_SENSOR | ||||
|   LOG_TEXT_SENSOR(" ", "Heartbeat Text Sensor", this->heartbeat_state_text_sensor_); | ||||
|   LOG_TEXT_SENSOR(" ", "Product Model Text Sensor", this->product_model_text_sensor_); | ||||
|   LOG_TEXT_SENSOR(" ", "Product ID Text Sensor", this->product_id_text_sensor_); | ||||
|   LOG_TEXT_SENSOR(" ", "Hardware Model Text Sensor", this->hardware_model_text_sensor_); | ||||
|   LOG_TEXT_SENSOR(" ", "Firware Verison Text Sensor", this->firware_version_text_sensor_); | ||||
|   LOG_TEXT_SENSOR(" ", "Keep Away Text Sensor", this->keep_away_text_sensor_); | ||||
|   LOG_TEXT_SENSOR(" ", "Motion Status Text Sensor", this->motion_status_text_sensor_); | ||||
|   LOG_TEXT_SENSOR(" ", "Custom Mode End Text Sensor", this->custom_mode_end_text_sensor_); | ||||
| #endif | ||||
| #ifdef USE_BINARY_SENSOR | ||||
|   LOG_BINARY_SENSOR(" ", "Has Target Binary Sensor", this->has_target_binary_sensor_); | ||||
| #endif | ||||
| #ifdef USE_SENSOR | ||||
|   LOG_SENSOR(" ", "Custom Presence Of Detection Sensor", this->custom_presence_of_detection_sensor_); | ||||
|   LOG_SENSOR(" ", "Movement Signs Sensor", this->movement_signs_sensor_); | ||||
|   LOG_SENSOR(" ", "Custom Motion Distance Sensor", this->custom_motion_distance_sensor_); | ||||
|   LOG_SENSOR(" ", "Custom Spatial Static Sensor", this->custom_spatial_static_value_sensor_); | ||||
|   LOG_SENSOR(" ", "Custom Spatial Motion Sensor", this->custom_spatial_motion_value_sensor_); | ||||
|   LOG_SENSOR(" ", "Custom Motion Speed Sensor", this->custom_motion_speed_sensor_); | ||||
|   LOG_SENSOR(" ", "Custom Mode Num Sensor", this->custom_mode_num_sensor_); | ||||
| #endif | ||||
| #ifdef USE_SWITCH | ||||
|   LOG_SWITCH(" ", "Underly Open Function Switch", this->underlying_open_function_switch_); | ||||
| #endif | ||||
| #ifdef USE_BUTTON | ||||
|   LOG_BUTTON(" ", "Restart Button", this->restart_button_); | ||||
|   LOG_BUTTON(" ", "Custom Set End Button", this->custom_set_end_button_); | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
|   LOG_SELECT(" ", "Scene Mode Select", this->scene_mode_select_); | ||||
|   LOG_SELECT(" ", "Unman Time Select", this->unman_time_select_); | ||||
|   LOG_SELECT(" ", "Existence Boundary Select", this->existence_boundary_select_); | ||||
|   LOG_SELECT(" ", "Motion Boundary Select", this->motion_boundary_select_); | ||||
| #endif | ||||
| #ifdef USE_NUMBER | ||||
|   LOG_NUMBER(" ", "Sensitivity Number", this->sensitivity_number_); | ||||
|   LOG_NUMBER(" ", "Custom Mode Number", this->custom_mode_number_); | ||||
|   LOG_NUMBER(" ", "Existence Threshold Number", this->existence_threshold_number_); | ||||
|   LOG_NUMBER(" ", "Motion Threshold Number", this->motion_threshold_number_); | ||||
|   LOG_NUMBER(" ", "Motion Trigger Time Number", this->motion_trigger_number_); | ||||
|   LOG_NUMBER(" ", "Motion To Rest Time Number", this->motion_to_rest_number_); | ||||
|   LOG_NUMBER(" ", "Custom Unman Time Number", this->custom_unman_time_number_); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| // Initialisation functions | ||||
| void MR24HPC1Component::setup() { | ||||
|   ESP_LOGCONFIG(TAG, "Setting up MR24HPC1..."); | ||||
|   this->check_uart_settings(115200); | ||||
|  | ||||
|   if (this->custom_mode_number_ != nullptr) { | ||||
|     this->custom_mode_number_->publish_state(0);  // Zero out the custom mode | ||||
|   } | ||||
|   if (this->custom_mode_num_sensor_ != nullptr) { | ||||
|     this->custom_mode_num_sensor_->publish_state(0); | ||||
|   } | ||||
|   if (this->custom_mode_end_text_sensor_ != nullptr) { | ||||
|     this->custom_mode_end_text_sensor_->publish_state("Not in custom mode"); | ||||
|   } | ||||
|   this->set_custom_end_mode(); | ||||
|   this->poll_time_base_func_check_ = true; | ||||
|   this->check_dev_inf_sign_ = true; | ||||
|   this->sg_start_query_data_ = STANDARD_FUNCTION_QUERY_PRODUCT_MODE; | ||||
|   this->sg_data_len_ = 0; | ||||
|   this->sg_frame_len_ = 0; | ||||
|   this->sg_recv_data_state_ = FRAME_IDLE; | ||||
|   this->s_output_info_switch_flag_ = OUTPUT_SWITCH_INIT; | ||||
|  | ||||
|   memset(this->c_product_mode_, 0, PRODUCT_BUF_MAX_SIZE); | ||||
|   memset(this->c_product_id_, 0, PRODUCT_BUF_MAX_SIZE); | ||||
|   memset(this->c_firmware_version_, 0, PRODUCT_BUF_MAX_SIZE); | ||||
|   memset(this->c_hardware_model_, 0, PRODUCT_BUF_MAX_SIZE); | ||||
|   memset(this->sg_frame_prase_buf_, 0, FRAME_BUF_MAX_SIZE); | ||||
|   memset(this->sg_frame_buf_, 0, FRAME_BUF_MAX_SIZE); | ||||
|  | ||||
|   this->set_interval(8000, [this]() { this->update_(); }); | ||||
|   ESP_LOGCONFIG(TAG, "Set up MR24HPC1 complete"); | ||||
| } | ||||
|  | ||||
| // Timed polling of radar data | ||||
| void MR24HPC1Component::update_() { | ||||
|   this->get_radar_output_information_switch();  // Query the key status every so often | ||||
|   this->poll_time_base_func_check_ = true;      // Query the base functionality information at regular intervals | ||||
| } | ||||
|  | ||||
| // main loop | ||||
| void MR24HPC1Component::loop() { | ||||
|   uint8_t byte; | ||||
|  | ||||
|   // Is there data on the serial port | ||||
|   while (this->available()) { | ||||
|     this->read_byte(&byte); | ||||
|     this->r24_split_data_frame_(byte);  // split data frame | ||||
|   } | ||||
|  | ||||
|   if ((this->s_output_info_switch_flag_ == OUTPUT_SWTICH_OFF) && | ||||
|       (this->sg_start_query_data_ > CUSTOM_FUNCTION_QUERY_TIME_OF_ENTER_UNMANNED) && (!this->check_dev_inf_sign_)) { | ||||
|     this->sg_start_query_data_ = STANDARD_FUNCTION_QUERY_SCENE_MODE; | ||||
|   } else if ((this->s_output_info_switch_flag_ == OUTPUT_SWITCH_ON) && | ||||
|              (this->sg_start_query_data_ < CUSTOM_FUNCTION_QUERY_EXISTENCE_BOUNDARY) && (!this->check_dev_inf_sign_)) { | ||||
|     this->sg_start_query_data_ = CUSTOM_FUNCTION_QUERY_EXISTENCE_BOUNDARY; | ||||
|   } else if (this->check_dev_inf_sign_ && (this->sg_start_query_data_ > STANDARD_FUNCTION_QUERY_HARDWARE_MODE)) { | ||||
|     // First time power up information polling | ||||
|     this->sg_start_query_data_ = STANDARD_FUNCTION_QUERY_PRODUCT_MODE; | ||||
|   } | ||||
|  | ||||
|   // Polling Functions | ||||
|   if (this->poll_time_base_func_check_) { | ||||
|     switch (this->sg_start_query_data_) { | ||||
|       case STANDARD_FUNCTION_QUERY_PRODUCT_MODE: | ||||
|         this->get_product_mode(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case STANDARD_FUNCTION_QUERY_PRODUCT_ID: | ||||
|         this->get_product_id(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case STANDARD_FUNCTION_QUERY_FIRMWARE_VERSION: | ||||
|         this->get_product_mode(); | ||||
|         this->get_product_id(); | ||||
|         this->get_firmware_version(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case STANDARD_FUNCTION_QUERY_HARDWARE_MODE:  // Above is the equipment information | ||||
|         this->get_product_mode(); | ||||
|         this->get_product_id(); | ||||
|         this->get_hardware_model(); | ||||
|         this->sg_start_query_data_++; | ||||
|         this->check_dev_inf_sign_ = false; | ||||
|         break; | ||||
|       case STANDARD_FUNCTION_QUERY_SCENE_MODE: | ||||
|         this->get_scene_mode(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case STANDARD_FUNCTION_QUERY_SENSITIVITY: | ||||
|         this->get_sensitivity(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case STANDARD_FUNCTION_QUERY_UNMANNED_TIME: | ||||
|         this->get_unmanned_time(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case STANDARD_FUNCTION_QUERY_HUMAN_STATUS: | ||||
|         this->get_human_status(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case STANDARD_FUNCTION_QUERY_HUMAN_MOTION_INF: | ||||
|         this->get_human_motion_info(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case STANDARD_FUNCTION_QUERY_BODY_MOVE_PARAMETER: | ||||
|         this->get_body_motion_params(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case STANDARD_FUNCTION_QUERY_KEEPAWAY_STATUS:  // The above is the basic functional information | ||||
|         this->get_keep_away(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case STANDARD_QUERY_CUSTOM_MODE: | ||||
|         this->get_custom_mode(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case STANDARD_FUNCTION_QUERY_HEARTBEAT_STATE: | ||||
|         this->get_heartbeat_packet(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case CUSTOM_FUNCTION_QUERY_EXISTENCE_BOUNDARY: | ||||
|         this->get_existence_boundary(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case CUSTOM_FUNCTION_QUERY_MOTION_BOUNDARY: | ||||
|         this->get_motion_boundary(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case CUSTOM_FUNCTION_QUERY_EXISTENCE_THRESHOLD: | ||||
|         this->get_existence_threshold(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case CUSTOM_FUNCTION_QUERY_MOTION_THRESHOLD: | ||||
|         this->get_motion_threshold(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case CUSTOM_FUNCTION_QUERY_MOTION_TRIGGER_TIME: | ||||
|         this->get_motion_trigger_time(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case CUSTOM_FUNCTION_QUERY_MOTION_TO_REST_TIME: | ||||
|         this->get_motion_to_rest_time(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case CUSTOM_FUNCTION_QUERY_TIME_OF_ENTER_UNMANNED: | ||||
|         this->get_custom_unman_time(); | ||||
|         this->sg_start_query_data_++; | ||||
|         if (this->s_output_info_switch_flag_ == OUTPUT_SWTICH_OFF) { | ||||
|           this->poll_time_base_func_check_ = false;  // Avoiding high-speed polling that can cause the device to jam | ||||
|         } | ||||
|         break; | ||||
|       case UNDERLY_FUNCTION_QUERY_HUMAN_STATUS: | ||||
|         this->get_human_status(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case UNDERLY_FUNCTION_QUERY_SPATIAL_STATIC_VALUE: | ||||
|         this->get_spatial_static_value(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case UNDERLY_FUNCTION_QUERY_SPATIAL_MOTION_VALUE: | ||||
|         this->get_spatial_motion_value(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case UNDERLY_FUNCTION_QUERY_DISTANCE_OF_STATIC_OBJECT: | ||||
|         this->get_distance_of_static_object(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case UNDERLY_FUNCTION_QUERY_DISTANCE_OF_MOVING_OBJECT: | ||||
|         this->get_distance_of_moving_object(); | ||||
|         this->sg_start_query_data_++; | ||||
|         break; | ||||
|       case UNDERLY_FUNCTION_QUERY_TARGET_MOVEMENT_SPEED: | ||||
|         this->get_target_movement_speed(); | ||||
|         this->sg_start_query_data_++; | ||||
|         this->poll_time_base_func_check_ = false;  // Avoiding high-speed polling that can cause the device to jam | ||||
|         break; | ||||
|       default: | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Calculate CRC check digit | ||||
| static uint8_t get_frame_crc_sum(const uint8_t *data, int len) { | ||||
|   unsigned int crc_sum = 0; | ||||
|   for (int i = 0; i < len - 3; i++) { | ||||
|     crc_sum += data[i]; | ||||
|   } | ||||
|   return crc_sum & 0xff; | ||||
| } | ||||
|  | ||||
| // Check that the check digit is correct | ||||
| static int get_frame_check_status(uint8_t *data, int len) { | ||||
|   uint8_t crc_sum = get_frame_crc_sum(data, len); | ||||
|   uint8_t verified = data[len - 3]; | ||||
|   return (verified == crc_sum) ? 1 : 0; | ||||
| } | ||||
|  | ||||
| // split data frame | ||||
| void MR24HPC1Component::r24_split_data_frame_(uint8_t value) { | ||||
|   switch (this->sg_recv_data_state_) { | ||||
|     case FRAME_IDLE:  // starting value | ||||
|       if (FRAME_HEADER1_VALUE == value) { | ||||
|         this->sg_recv_data_state_ = FRAME_HEADER2; | ||||
|       } | ||||
|       break; | ||||
|     case FRAME_HEADER2: | ||||
|       if (FRAME_HEADER2_VALUE == value) { | ||||
|         this->sg_frame_buf_[0] = FRAME_HEADER1_VALUE; | ||||
|         this->sg_frame_buf_[1] = FRAME_HEADER2_VALUE; | ||||
|         this->sg_recv_data_state_ = FRAME_CTL_WORD; | ||||
|       } else { | ||||
|         this->sg_recv_data_state_ = FRAME_IDLE; | ||||
|         ESP_LOGD(TAG, "FRAME_IDLE ERROR value:%x", value); | ||||
|       } | ||||
|       break; | ||||
|     case FRAME_CTL_WORD: | ||||
|       this->sg_frame_buf_[2] = value; | ||||
|       this->sg_recv_data_state_ = FRAME_CMD_WORD; | ||||
|       break; | ||||
|     case FRAME_CMD_WORD: | ||||
|       this->sg_frame_buf_[3] = value; | ||||
|       this->sg_recv_data_state_ = FRAME_DATA_LEN_H; | ||||
|       break; | ||||
|     case FRAME_DATA_LEN_H: | ||||
|       if (value <= 4) { | ||||
|         this->sg_data_len_ = value * 256; | ||||
|         this->sg_frame_buf_[4] = value; | ||||
|         this->sg_recv_data_state_ = FRAME_DATA_LEN_L; | ||||
|       } else { | ||||
|         this->sg_data_len_ = 0; | ||||
|         this->sg_recv_data_state_ = FRAME_IDLE; | ||||
|         ESP_LOGD(TAG, "FRAME_DATA_LEN_H ERROR value:%x", value); | ||||
|       } | ||||
|       break; | ||||
|     case FRAME_DATA_LEN_L: | ||||
|       this->sg_data_len_ += value; | ||||
|       if (this->sg_data_len_ > 32) { | ||||
|         ESP_LOGD(TAG, "len=%d, FRAME_DATA_LEN_L ERROR value:%x", this->sg_data_len_, value); | ||||
|         this->sg_data_len_ = 0; | ||||
|         this->sg_recv_data_state_ = FRAME_IDLE; | ||||
|       } else { | ||||
|         this->sg_frame_buf_[5] = value; | ||||
|         this->sg_frame_len_ = 6; | ||||
|         this->sg_recv_data_state_ = FRAME_DATA_BYTES; | ||||
|       } | ||||
|       break; | ||||
|     case FRAME_DATA_BYTES: | ||||
|       this->sg_data_len_ -= 1; | ||||
|       this->sg_frame_buf_[this->sg_frame_len_++] = value; | ||||
|       if (this->sg_data_len_ <= 0) { | ||||
|         this->sg_recv_data_state_ = FRAME_DATA_CRC; | ||||
|       } | ||||
|       break; | ||||
|     case FRAME_DATA_CRC: | ||||
|       this->sg_frame_buf_[this->sg_frame_len_++] = value; | ||||
|       this->sg_recv_data_state_ = FRAME_TAIL1; | ||||
|       break; | ||||
|     case FRAME_TAIL1: | ||||
|       if (FRAME_TAIL1_VALUE == value) { | ||||
|         this->sg_recv_data_state_ = FRAME_TAIL2; | ||||
|       } else { | ||||
|         this->sg_recv_data_state_ = FRAME_IDLE; | ||||
|         this->sg_frame_len_ = 0; | ||||
|         this->sg_data_len_ = 0; | ||||
|         ESP_LOGD(TAG, "FRAME_TAIL1 ERROR value:%x", value); | ||||
|       } | ||||
|       break; | ||||
|     case FRAME_TAIL2: | ||||
|       if (FRAME_TAIL2_VALUE == value) { | ||||
|         this->sg_frame_buf_[this->sg_frame_len_++] = FRAME_TAIL1_VALUE; | ||||
|         this->sg_frame_buf_[this->sg_frame_len_++] = FRAME_TAIL2_VALUE; | ||||
|         memcpy(this->sg_frame_prase_buf_, this->sg_frame_buf_, this->sg_frame_len_); | ||||
|         if (get_frame_check_status(this->sg_frame_prase_buf_, this->sg_frame_len_)) { | ||||
|           this->r24_parse_data_frame_(this->sg_frame_prase_buf_, this->sg_frame_len_); | ||||
|         } else { | ||||
|           ESP_LOGD(TAG, "frame check failer!"); | ||||
|         } | ||||
|       } else { | ||||
|         ESP_LOGD(TAG, "FRAME_TAIL2 ERROR value:%x", value); | ||||
|       } | ||||
|       memset(this->sg_frame_prase_buf_, 0, FRAME_BUF_MAX_SIZE); | ||||
|       memset(this->sg_frame_buf_, 0, FRAME_BUF_MAX_SIZE); | ||||
|       this->sg_frame_len_ = 0; | ||||
|       this->sg_data_len_ = 0; | ||||
|       this->sg_recv_data_state_ = FRAME_IDLE; | ||||
|       break; | ||||
|     default: | ||||
|       this->sg_recv_data_state_ = FRAME_IDLE; | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Parses data frames related to product information | ||||
| void MR24HPC1Component::r24_frame_parse_product_information_(uint8_t *data) { | ||||
|   uint16_t product_len = encode_uint16(data[FRAME_COMMAND_WORD_INDEX + 1], data[FRAME_COMMAND_WORD_INDEX + 2]); | ||||
|   if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_PRODUCT_MODE) { | ||||
|     if ((this->product_model_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) { | ||||
|       memset(this->c_product_mode_, 0, PRODUCT_BUF_MAX_SIZE); | ||||
|       memcpy(this->c_product_mode_, &data[FRAME_DATA_INDEX], product_len); | ||||
|       this->product_model_text_sensor_->publish_state(this->c_product_mode_); | ||||
|     } else { | ||||
|       ESP_LOGD(TAG, "Reply: get product_mode error!"); | ||||
|     } | ||||
|   } else if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_PRODUCT_ID) { | ||||
|     if ((this->product_id_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) { | ||||
|       memset(this->c_product_id_, 0, PRODUCT_BUF_MAX_SIZE); | ||||
|       memcpy(this->c_product_id_, &data[FRAME_DATA_INDEX], product_len); | ||||
|       this->product_id_text_sensor_->publish_state(this->c_product_id_); | ||||
|     } else { | ||||
|       ESP_LOGD(TAG, "Reply: get productId error!"); | ||||
|     } | ||||
|   } else if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_HARDWARE_MODEL) { | ||||
|     if ((this->hardware_model_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) { | ||||
|       memset(this->c_hardware_model_, 0, PRODUCT_BUF_MAX_SIZE); | ||||
|       memcpy(this->c_hardware_model_, &data[FRAME_DATA_INDEX], product_len); | ||||
|       this->hardware_model_text_sensor_->publish_state(this->c_hardware_model_); | ||||
|       ESP_LOGD(TAG, "Reply: get hardware_model :%s", this->c_hardware_model_); | ||||
|     } else { | ||||
|       ESP_LOGD(TAG, "Reply: get hardwareModel error!"); | ||||
|     } | ||||
|   } else if (data[FRAME_COMMAND_WORD_INDEX] == COMMAND_FIRMWARE_VERSION) { | ||||
|     if ((this->firware_version_text_sensor_ != nullptr) && (product_len < PRODUCT_BUF_MAX_SIZE)) { | ||||
|       memset(this->c_firmware_version_, 0, PRODUCT_BUF_MAX_SIZE); | ||||
|       memcpy(this->c_firmware_version_, &data[FRAME_DATA_INDEX], product_len); | ||||
|       this->firware_version_text_sensor_->publish_state(this->c_firmware_version_); | ||||
|     } else { | ||||
|       ESP_LOGD(TAG, "Reply: get firmwareVersion error!"); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Parsing the underlying open parameters | ||||
| void MR24HPC1Component::r24_frame_parse_open_underlying_information_(uint8_t *data) { | ||||
|   if (data[FRAME_COMMAND_WORD_INDEX] == 0x00) { | ||||
|     if (this->underlying_open_function_switch_ != nullptr) { | ||||
|       this->underlying_open_function_switch_->publish_state( | ||||
|           data[FRAME_DATA_INDEX]);  // Underlying Open Parameter Switch Status Updates | ||||
|     } | ||||
|     if (data[FRAME_DATA_INDEX]) { | ||||
|       this->s_output_info_switch_flag_ = OUTPUT_SWITCH_ON; | ||||
|     } else { | ||||
|       this->s_output_info_switch_flag_ = OUTPUT_SWTICH_OFF; | ||||
|     } | ||||
|   } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x01) { | ||||
|     if (this->custom_spatial_static_value_sensor_ != nullptr) { | ||||
|       this->custom_spatial_static_value_sensor_->publish_state(data[FRAME_DATA_INDEX]); | ||||
|     } | ||||
|     if (this->custom_presence_of_detection_sensor_ != nullptr) { | ||||
|       this->custom_presence_of_detection_sensor_->publish_state(data[FRAME_DATA_INDEX + 1] * 0.5f); | ||||
|     } | ||||
|     if (this->custom_spatial_motion_value_sensor_ != nullptr) { | ||||
|       this->custom_spatial_motion_value_sensor_->publish_state(data[FRAME_DATA_INDEX + 2]); | ||||
|     } | ||||
|     if (this->custom_motion_distance_sensor_ != nullptr) { | ||||
|       this->custom_motion_distance_sensor_->publish_state(data[FRAME_DATA_INDEX + 3] * 0.5f); | ||||
|     } | ||||
|     if (this->custom_motion_speed_sensor_ != nullptr) { | ||||
|       this->custom_motion_speed_sensor_->publish_state((data[FRAME_DATA_INDEX + 4] - 10) * 0.5f); | ||||
|     } | ||||
|   } else if ((data[FRAME_COMMAND_WORD_INDEX] == 0x06) || (data[FRAME_COMMAND_WORD_INDEX] == 0x86)) { | ||||
|     // none:0x00  close_to:0x01  far_away:0x02 | ||||
|     if ((this->keep_away_text_sensor_ != nullptr) && (data[FRAME_DATA_INDEX] < 3)) { | ||||
|       this->keep_away_text_sensor_->publish_state(S_KEEP_AWAY_STR[data[FRAME_DATA_INDEX]]); | ||||
|     } | ||||
|   } else if ((this->movement_signs_sensor_ != nullptr) && | ||||
|              ((data[FRAME_COMMAND_WORD_INDEX] == 0x07) || (data[FRAME_COMMAND_WORD_INDEX] == 0x87))) { | ||||
|     this->movement_signs_sensor_->publish_state(data[FRAME_DATA_INDEX]); | ||||
|   } else if ((this->existence_threshold_number_ != nullptr) && | ||||
|              ((data[FRAME_COMMAND_WORD_INDEX] == 0x08) || (data[FRAME_COMMAND_WORD_INDEX] == 0x88))) { | ||||
|     this->existence_threshold_number_->publish_state(data[FRAME_DATA_INDEX]); | ||||
|   } else if ((this->motion_threshold_number_ != nullptr) && | ||||
|              ((data[FRAME_COMMAND_WORD_INDEX] == 0x09) || (data[FRAME_COMMAND_WORD_INDEX] == 0x89))) { | ||||
|     this->motion_threshold_number_->publish_state(data[FRAME_DATA_INDEX]); | ||||
|   } else if ((this->existence_boundary_select_ != nullptr) && | ||||
|              ((data[FRAME_COMMAND_WORD_INDEX] == 0x0a) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8a))) { | ||||
|     if (this->existence_boundary_select_->has_index(data[FRAME_DATA_INDEX] - 1)) { | ||||
|       this->existence_boundary_select_->publish_state(S_BOUNDARY_STR[data[FRAME_DATA_INDEX] - 1]); | ||||
|     } | ||||
|   } else if ((this->motion_boundary_select_ != nullptr) && | ||||
|              ((data[FRAME_COMMAND_WORD_INDEX] == 0x0b) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8b))) { | ||||
|     if (this->motion_boundary_select_->has_index(data[FRAME_DATA_INDEX] - 1)) { | ||||
|       this->motion_boundary_select_->publish_state(S_BOUNDARY_STR[data[FRAME_DATA_INDEX] - 1]); | ||||
|     } | ||||
|   } else if ((this->motion_trigger_number_ != nullptr) && | ||||
|              ((data[FRAME_COMMAND_WORD_INDEX] == 0x0c) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8c))) { | ||||
|     uint32_t motion_trigger_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1], | ||||
|                                                  data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]); | ||||
|     this->motion_trigger_number_->publish_state(motion_trigger_time); | ||||
|   } else if ((this->motion_to_rest_number_ != nullptr) && | ||||
|              ((data[FRAME_COMMAND_WORD_INDEX] == 0x0d) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8d))) { | ||||
|     uint32_t move_to_rest_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1], | ||||
|                                                data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]); | ||||
|     this->motion_to_rest_number_->publish_state(move_to_rest_time); | ||||
|   } else if ((this->custom_unman_time_number_ != nullptr) && | ||||
|              ((data[FRAME_COMMAND_WORD_INDEX] == 0x0e) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8e))) { | ||||
|     uint32_t enter_unmanned_time = encode_uint32(data[FRAME_DATA_INDEX], data[FRAME_DATA_INDEX + 1], | ||||
|                                                  data[FRAME_DATA_INDEX + 2], data[FRAME_DATA_INDEX + 3]); | ||||
|     float custom_unmanned_time = enter_unmanned_time / 1000.0; | ||||
|     this->custom_unman_time_number_->publish_state(custom_unmanned_time); | ||||
|   } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x80) { | ||||
|     if (data[FRAME_DATA_INDEX]) { | ||||
|       this->s_output_info_switch_flag_ = OUTPUT_SWITCH_ON; | ||||
|     } else { | ||||
|       this->s_output_info_switch_flag_ = OUTPUT_SWTICH_OFF; | ||||
|     } | ||||
|     if (this->underlying_open_function_switch_ != nullptr) { | ||||
|       this->underlying_open_function_switch_->publish_state(data[FRAME_DATA_INDEX]); | ||||
|     } | ||||
|   } else if ((this->custom_spatial_static_value_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x81)) { | ||||
|     this->custom_spatial_static_value_sensor_->publish_state(data[FRAME_DATA_INDEX]); | ||||
|   } else if ((this->custom_spatial_motion_value_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x82)) { | ||||
|     this->custom_spatial_motion_value_sensor_->publish_state(data[FRAME_DATA_INDEX]); | ||||
|   } else if ((this->custom_presence_of_detection_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x83)) { | ||||
|     this->custom_presence_of_detection_sensor_->publish_state( | ||||
|         S_PRESENCE_OF_DETECTION_RANGE_STR[data[FRAME_DATA_INDEX]]); | ||||
|   } else if ((this->custom_motion_distance_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x84)) { | ||||
|     this->custom_motion_distance_sensor_->publish_state(data[FRAME_DATA_INDEX] * 0.5f); | ||||
|   } else if ((this->custom_motion_speed_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x85)) { | ||||
|     this->custom_motion_speed_sensor_->publish_state((data[FRAME_DATA_INDEX] - 10) * 0.5f); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::r24_parse_data_frame_(uint8_t *data, uint8_t len) { | ||||
|   switch (data[FRAME_CONTROL_WORD_INDEX]) { | ||||
|     case 0x01: { | ||||
|       if ((this->heartbeat_state_text_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x01)) { | ||||
|         this->heartbeat_state_text_sensor_->publish_state("Equipment Normal"); | ||||
|       } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x02) { | ||||
|         ESP_LOGD(TAG, "Reply: query restart packet"); | ||||
|       } else if (this->heartbeat_state_text_sensor_ != nullptr) { | ||||
|         this->heartbeat_state_text_sensor_->publish_state("Equipment Abnormal"); | ||||
|       } | ||||
|     } break; | ||||
|     case 0x02: { | ||||
|       this->r24_frame_parse_product_information_(data); | ||||
|     } break; | ||||
|     case 0x05: { | ||||
|       this->r24_frame_parse_work_status_(data); | ||||
|     } break; | ||||
|     case 0x08: { | ||||
|       this->r24_frame_parse_open_underlying_information_(data); | ||||
|     } break; | ||||
|     case 0x80: { | ||||
|       this->r24_frame_parse_human_information_(data); | ||||
|     } break; | ||||
|     default: | ||||
|       ESP_LOGD(TAG, "control word:0x%02X not found", data[FRAME_CONTROL_WORD_INDEX]); | ||||
|       break; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::r24_frame_parse_work_status_(uint8_t *data) { | ||||
|   if (data[FRAME_COMMAND_WORD_INDEX] == 0x01) { | ||||
|     ESP_LOGD(TAG, "Reply: get radar init status 0x%02X", data[FRAME_DATA_INDEX]); | ||||
|   } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x07) { | ||||
|     if ((this->scene_mode_select_ != nullptr) && (this->scene_mode_select_->has_index(data[FRAME_DATA_INDEX]))) { | ||||
|       this->scene_mode_select_->publish_state(S_SCENE_STR[data[FRAME_DATA_INDEX]]); | ||||
|     } else { | ||||
|       ESP_LOGD(TAG, "Select has index offset %d Error", data[FRAME_DATA_INDEX]); | ||||
|     } | ||||
|   } else if ((this->sensitivity_number_ != nullptr) && | ||||
|              ((data[FRAME_COMMAND_WORD_INDEX] == 0x08) || (data[FRAME_COMMAND_WORD_INDEX] == 0x88))) { | ||||
|     // 1-3 | ||||
|     this->sensitivity_number_->publish_state(data[FRAME_DATA_INDEX]); | ||||
|   } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x09) { | ||||
|     // 1-4 | ||||
|     if (this->custom_mode_num_sensor_ != nullptr) { | ||||
|       this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]); | ||||
|     } | ||||
|     if (this->custom_mode_number_ != nullptr) { | ||||
|       this->custom_mode_number_->publish_state(0); | ||||
|     } | ||||
|     if (this->custom_mode_end_text_sensor_ != nullptr) { | ||||
|       this->custom_mode_end_text_sensor_->publish_state("Setup in progress..."); | ||||
|     } | ||||
|   } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x81) { | ||||
|     ESP_LOGD(TAG, "Reply: get radar init status 0x%02X", data[FRAME_DATA_INDEX]); | ||||
|   } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x87) { | ||||
|     if ((this->scene_mode_select_ != nullptr) && (this->scene_mode_select_->has_index(data[FRAME_DATA_INDEX]))) { | ||||
|       this->scene_mode_select_->publish_state(S_SCENE_STR[data[FRAME_DATA_INDEX]]); | ||||
|     } else { | ||||
|       ESP_LOGD(TAG, "Select has index offset %d Error", data[FRAME_DATA_INDEX]); | ||||
|     } | ||||
|   } else if ((this->custom_mode_end_text_sensor_ != nullptr) && (data[FRAME_COMMAND_WORD_INDEX] == 0x0A)) { | ||||
|     this->custom_mode_end_text_sensor_->publish_state("Set Success!"); | ||||
|   } else if (data[FRAME_COMMAND_WORD_INDEX] == 0x89) { | ||||
|     if (data[FRAME_DATA_INDEX] == 0) { | ||||
|       if (this->custom_mode_end_text_sensor_ != nullptr) { | ||||
|         this->custom_mode_end_text_sensor_->publish_state("Not in custom mode"); | ||||
|       } | ||||
|       if (this->custom_mode_number_ != nullptr) { | ||||
|         this->custom_mode_number_->publish_state(0); | ||||
|       } | ||||
|       if (this->custom_mode_num_sensor_ != nullptr) { | ||||
|         this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]); | ||||
|       } | ||||
|     } else { | ||||
|       if (this->custom_mode_num_sensor_ != nullptr) { | ||||
|         this->custom_mode_num_sensor_->publish_state(data[FRAME_DATA_INDEX]); | ||||
|       } | ||||
|     } | ||||
|   } else { | ||||
|     ESP_LOGD(TAG, "[%s] No found COMMAND_WORD(%02X) in Frame", __FUNCTION__, data[FRAME_COMMAND_WORD_INDEX]); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::r24_frame_parse_human_information_(uint8_t *data) { | ||||
|   if ((this->has_target_binary_sensor_ != nullptr) && | ||||
|       ((data[FRAME_COMMAND_WORD_INDEX] == 0x01) || (data[FRAME_COMMAND_WORD_INDEX] == 0x81))) { | ||||
|     this->has_target_binary_sensor_->publish_state(S_SOMEONE_EXISTS_STR[data[FRAME_DATA_INDEX]]); | ||||
|   } else if ((this->motion_status_text_sensor_ != nullptr) && | ||||
|              ((data[FRAME_COMMAND_WORD_INDEX] == 0x02) || (data[FRAME_COMMAND_WORD_INDEX] == 0x82))) { | ||||
|     if (data[FRAME_DATA_INDEX] < 3) { | ||||
|       this->motion_status_text_sensor_->publish_state(S_MOTION_STATUS_STR[data[FRAME_DATA_INDEX]]); | ||||
|     } | ||||
|   } else if ((this->movement_signs_sensor_ != nullptr) && | ||||
|              ((data[FRAME_COMMAND_WORD_INDEX] == 0x03) || (data[FRAME_COMMAND_WORD_INDEX] == 0x83))) { | ||||
|     this->movement_signs_sensor_->publish_state(data[FRAME_DATA_INDEX]); | ||||
|   } else if ((this->unman_time_select_ != nullptr) && | ||||
|              ((data[FRAME_COMMAND_WORD_INDEX] == 0x0A) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8A))) { | ||||
|     // none:0x00  1s:0x01 30s:0x02 1min:0x03 2min:0x04 5min:0x05 10min:0x06 30min:0x07 1hour:0x08 | ||||
|     if (data[FRAME_DATA_INDEX] < 9) { | ||||
|       this->unman_time_select_->publish_state(S_UNMANNED_TIME_STR[data[FRAME_DATA_INDEX]]); | ||||
|     } | ||||
|   } else if ((this->keep_away_text_sensor_ != nullptr) && | ||||
|              ((data[FRAME_COMMAND_WORD_INDEX] == 0x0B) || (data[FRAME_COMMAND_WORD_INDEX] == 0x8B))) { | ||||
|     // none:0x00  close_to:0x01  far_away:0x02 | ||||
|     if (data[FRAME_DATA_INDEX] < 3) { | ||||
|       this->keep_away_text_sensor_->publish_state(S_KEEP_AWAY_STR[data[FRAME_DATA_INDEX]]); | ||||
|     } | ||||
|   } else { | ||||
|     ESP_LOGD(TAG, "[%s] No found COMMAND_WORD(%02X) in Frame", __FUNCTION__, data[FRAME_COMMAND_WORD_INDEX]); | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Sending data frames | ||||
| void MR24HPC1Component::send_query_(const uint8_t *query, size_t string_length) { | ||||
|   this->write_array(query, string_length); | ||||
| } | ||||
|  | ||||
| // Send Heartbeat Packet Command | ||||
| void MR24HPC1Component::get_heartbeat_packet() { this->send_query_(GET_HEARTBEAT, sizeof(GET_HEARTBEAT)); } | ||||
|  | ||||
| // Issuance of the underlying open parameter query command | ||||
| void MR24HPC1Component::get_radar_output_information_switch() { | ||||
|   this->send_query_(GET_RADAR_OUTPUT_INFORMATION_SWITCH, sizeof(GET_RADAR_OUTPUT_INFORMATION_SWITCH)); | ||||
| } | ||||
|  | ||||
| // Issuance of product model orders | ||||
| void MR24HPC1Component::get_product_mode() { this->send_query_(GET_PRODUCT_MODE, sizeof(GET_PRODUCT_MODE)); } | ||||
|  | ||||
| // Issuing the Get Product ID command | ||||
| void MR24HPC1Component::get_product_id() { this->send_query_(GET_PRODUCT_ID, sizeof(GET_PRODUCT_ID)); } | ||||
|  | ||||
| // Issuing hardware model commands | ||||
| void MR24HPC1Component::get_hardware_model() { this->send_query_(GET_HARDWARE_MODEL, sizeof(GET_HARDWARE_MODEL)); } | ||||
|  | ||||
| // Issuing software version commands | ||||
| void MR24HPC1Component::get_firmware_version() { | ||||
|   this->send_query_(GET_FIRMWARE_VERSION, sizeof(GET_FIRMWARE_VERSION)); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::get_human_status() { this->send_query_(GET_HUMAN_STATUS, sizeof(GET_HUMAN_STATUS)); } | ||||
|  | ||||
| void MR24HPC1Component::get_human_motion_info() { | ||||
|   this->send_query_(GET_HUMAN_MOTION_INFORMATION, sizeof(GET_HUMAN_MOTION_INFORMATION)); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::get_body_motion_params() { | ||||
|   this->send_query_(GET_BODY_MOTION_PARAMETERS, sizeof(GET_BODY_MOTION_PARAMETERS)); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::get_keep_away() { this->send_query_(GET_KEEP_AWAY, sizeof(GET_KEEP_AWAY)); } | ||||
|  | ||||
| void MR24HPC1Component::get_scene_mode() { this->send_query_(GET_SCENE_MODE, sizeof(GET_SCENE_MODE)); } | ||||
|  | ||||
| void MR24HPC1Component::get_sensitivity() { this->send_query_(GET_SENSITIVITY, sizeof(GET_SENSITIVITY)); } | ||||
|  | ||||
| void MR24HPC1Component::get_unmanned_time() { this->send_query_(GET_UNMANNED_TIME, sizeof(GET_UNMANNED_TIME)); } | ||||
|  | ||||
| void MR24HPC1Component::get_custom_mode() { this->send_query_(GET_CUSTOM_MODE, sizeof(GET_CUSTOM_MODE)); } | ||||
|  | ||||
| void MR24HPC1Component::get_existence_boundary() { | ||||
|   this->send_query_(GET_EXISTENCE_BOUNDARY, sizeof(GET_EXISTENCE_BOUNDARY)); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::get_motion_boundary() { this->send_query_(GET_MOTION_BOUNDARY, sizeof(GET_MOTION_BOUNDARY)); } | ||||
|  | ||||
| void MR24HPC1Component::get_spatial_static_value() { | ||||
|   this->send_query_(GET_SPATIAL_STATIC_VALUE, sizeof(GET_SPATIAL_STATIC_VALUE)); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::get_spatial_motion_value() { | ||||
|   this->send_query_(GET_SPATIAL_MOTION_VALUE, sizeof(GET_SPATIAL_MOTION_VALUE)); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::get_distance_of_static_object() { | ||||
|   this->send_query_(GET_DISTANCE_OF_STATIC_OBJECT, sizeof(GET_DISTANCE_OF_STATIC_OBJECT)); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::get_distance_of_moving_object() { | ||||
|   this->send_query_(GET_DISTANCE_OF_MOVING_OBJECT, sizeof(GET_DISTANCE_OF_MOVING_OBJECT)); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::get_target_movement_speed() { | ||||
|   this->send_query_(GET_TARGET_MOVEMENT_SPEED, sizeof(GET_TARGET_MOVEMENT_SPEED)); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::get_existence_threshold() { | ||||
|   this->send_query_(GET_EXISTENCE_THRESHOLD, sizeof(GET_EXISTENCE_THRESHOLD)); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::get_motion_threshold() { | ||||
|   this->send_query_(GET_MOTION_THRESHOLD, sizeof(GET_MOTION_THRESHOLD)); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::get_motion_trigger_time() { | ||||
|   this->send_query_(GET_MOTION_TRIGGER_TIME, sizeof(GET_MOTION_TRIGGER_TIME)); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::get_motion_to_rest_time() { | ||||
|   this->send_query_(GET_MOTION_TO_REST_TIME, sizeof(GET_MOTION_TO_REST_TIME)); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::get_custom_unman_time() { | ||||
|   this->send_query_(GET_CUSTOM_UNMAN_TIME, sizeof(GET_CUSTOM_UNMAN_TIME)); | ||||
| } | ||||
|  | ||||
| // Logic of setting: After setting, query whether the setting is successful or not! | ||||
|  | ||||
| void MR24HPC1Component::set_underlying_open_function(bool enable) { | ||||
|   if (enable) { | ||||
|     this->send_query_(UNDERLYING_SWITCH_ON, sizeof(UNDERLYING_SWITCH_ON)); | ||||
|   } else { | ||||
|     this->send_query_(UNDERLYING_SWITCH_OFF, sizeof(UNDERLYING_SWITCH_OFF)); | ||||
|   } | ||||
|   if (this->keep_away_text_sensor_ != nullptr) { | ||||
|     this->keep_away_text_sensor_->publish_state(""); | ||||
|   } | ||||
|   if (this->motion_status_text_sensor_ != nullptr) { | ||||
|     this->motion_status_text_sensor_->publish_state(""); | ||||
|   } | ||||
|   if (this->custom_spatial_static_value_sensor_ != nullptr) { | ||||
|     this->custom_spatial_static_value_sensor_->publish_state(NAN); | ||||
|   } | ||||
|   if (this->custom_spatial_motion_value_sensor_ != nullptr) { | ||||
|     this->custom_spatial_motion_value_sensor_->publish_state(NAN); | ||||
|   } | ||||
|   if (this->custom_motion_distance_sensor_ != nullptr) { | ||||
|     this->custom_motion_distance_sensor_->publish_state(NAN); | ||||
|   } | ||||
|   if (this->custom_presence_of_detection_sensor_ != nullptr) { | ||||
|     this->custom_presence_of_detection_sensor_->publish_state(NAN); | ||||
|   } | ||||
|   if (this->custom_motion_speed_sensor_ != nullptr) { | ||||
|     this->custom_motion_speed_sensor_->publish_state(NAN); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::set_scene_mode(uint8_t value) { | ||||
|   uint8_t send_data_len = 10; | ||||
|   uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x07, 0x00, 0x01, value, 0x00, 0x54, 0x43}; | ||||
|   send_data[7] = get_frame_crc_sum(send_data, send_data_len); | ||||
|   this->send_query_(send_data, send_data_len); | ||||
|   if (this->custom_mode_number_ != nullptr) { | ||||
|     this->custom_mode_number_->publish_state(0); | ||||
|   } | ||||
|   if (this->custom_mode_num_sensor_ != nullptr) { | ||||
|     this->custom_mode_num_sensor_->publish_state(0); | ||||
|   } | ||||
|   this->get_scene_mode(); | ||||
|   this->get_sensitivity(); | ||||
|   this->get_custom_mode(); | ||||
|   this->get_existence_boundary(); | ||||
|   this->get_motion_boundary(); | ||||
|   this->get_existence_threshold(); | ||||
|   this->get_motion_threshold(); | ||||
|   this->get_motion_trigger_time(); | ||||
|   this->get_motion_to_rest_time(); | ||||
|   this->get_custom_unman_time(); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::set_sensitivity(uint8_t value) { | ||||
|   if (value == 0x00) | ||||
|     return; | ||||
|   uint8_t send_data_len = 10; | ||||
|   uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x08, 0x00, 0x01, value, 0x00, 0x54, 0x43}; | ||||
|   send_data[7] = get_frame_crc_sum(send_data, send_data_len); | ||||
|   this->send_query_(send_data, send_data_len); | ||||
|   this->get_scene_mode(); | ||||
|   this->get_sensitivity(); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::set_restart() { | ||||
|   this->send_query_(SET_RESTART, sizeof(SET_RESTART)); | ||||
|   this->check_dev_inf_sign_ = true; | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::set_unman_time(uint8_t value) { | ||||
|   uint8_t send_data_len = 10; | ||||
|   uint8_t send_data[10] = {0x53, 0x59, 0x80, 0x0a, 0x00, 0x01, value, 0x00, 0x54, 0x43}; | ||||
|   send_data[7] = get_frame_crc_sum(send_data, send_data_len); | ||||
|   this->send_query_(send_data, send_data_len); | ||||
|   this->get_unmanned_time(); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::set_custom_mode(uint8_t mode) { | ||||
|   if (mode == 0) { | ||||
|     this->set_custom_end_mode();  // Equivalent to end setting | ||||
|     if (this->custom_mode_number_ != nullptr) { | ||||
|       this->custom_mode_number_->publish_state(0); | ||||
|     } | ||||
|     return; | ||||
|   } | ||||
|   uint8_t send_data_len = 10; | ||||
|   uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x09, 0x00, 0x01, mode, 0x00, 0x54, 0x43}; | ||||
|   send_data[7] = get_frame_crc_sum(send_data, send_data_len); | ||||
|   this->send_query_(send_data, send_data_len); | ||||
|   this->get_existence_boundary(); | ||||
|   this->get_motion_boundary(); | ||||
|   this->get_existence_threshold(); | ||||
|   this->get_motion_threshold(); | ||||
|   this->get_motion_trigger_time(); | ||||
|   this->get_motion_to_rest_time(); | ||||
|   this->get_custom_unman_time(); | ||||
|   this->get_custom_mode(); | ||||
|   this->get_scene_mode(); | ||||
|   this->get_sensitivity(); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::set_custom_end_mode() { | ||||
|   uint8_t send_data_len = 10; | ||||
|   uint8_t send_data[10] = {0x53, 0x59, 0x05, 0x0a, 0x00, 0x01, 0x0F, 0xCB, 0x54, 0x43}; | ||||
|   this->send_query_(send_data, send_data_len); | ||||
|   if (this->custom_mode_number_ != nullptr) { | ||||
|     this->custom_mode_number_->publish_state(0);  // Clear setpoints | ||||
|   } | ||||
|   this->get_existence_boundary(); | ||||
|   this->get_motion_boundary(); | ||||
|   this->get_existence_threshold(); | ||||
|   this->get_motion_threshold(); | ||||
|   this->get_motion_trigger_time(); | ||||
|   this->get_motion_to_rest_time(); | ||||
|   this->get_custom_unman_time(); | ||||
|   this->get_custom_mode(); | ||||
|   this->get_scene_mode(); | ||||
|   this->get_sensitivity(); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::set_existence_boundary(uint8_t value) { | ||||
|   if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0)) | ||||
|     return;  // You'll have to check that you're in custom mode to set it up | ||||
|   uint8_t send_data_len = 10; | ||||
|   uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x0A, 0x00, 0x01, (uint8_t) (value + 1), 0x00, 0x54, 0x43}; | ||||
|   send_data[7] = get_frame_crc_sum(send_data, send_data_len); | ||||
|   this->send_query_(send_data, send_data_len); | ||||
|   this->get_existence_boundary(); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::set_motion_boundary(uint8_t value) { | ||||
|   if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0)) | ||||
|     return;  // You'll have to check that you're in custom mode to set it up | ||||
|   uint8_t send_data_len = 10; | ||||
|   uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x0B, 0x00, 0x01, (uint8_t) (value + 1), 0x00, 0x54, 0x43}; | ||||
|   send_data[7] = get_frame_crc_sum(send_data, send_data_len); | ||||
|   this->send_query_(send_data, send_data_len); | ||||
|   this->get_motion_boundary(); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::set_existence_threshold(uint8_t value) { | ||||
|   if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0)) | ||||
|     return;  // You'll have to check that you're in custom mode to set it up | ||||
|   uint8_t send_data_len = 10; | ||||
|   uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x08, 0x00, 0x01, value, 0x00, 0x54, 0x43}; | ||||
|   send_data[7] = get_frame_crc_sum(send_data, send_data_len); | ||||
|   this->send_query_(send_data, send_data_len); | ||||
|   this->get_existence_threshold(); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::set_motion_threshold(uint8_t value) { | ||||
|   if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0)) | ||||
|     return;  // You'll have to check that you're in custom mode to set it up | ||||
|   uint8_t send_data_len = 10; | ||||
|   uint8_t send_data[10] = {0x53, 0x59, 0x08, 0x09, 0x00, 0x01, value, 0x00, 0x54, 0x43}; | ||||
|   send_data[7] = get_frame_crc_sum(send_data, send_data_len); | ||||
|   this->send_query_(send_data, send_data_len); | ||||
|   this->get_motion_threshold(); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::set_motion_trigger_time(uint8_t value) { | ||||
|   if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0)) | ||||
|     return;  // You'll have to check that you're in custom mode to set it up | ||||
|   uint8_t send_data_len = 13; | ||||
|   uint8_t send_data[13] = {0x53, 0x59, 0x08, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, value, 0x00, 0x54, 0x43}; | ||||
|   send_data[10] = get_frame_crc_sum(send_data, send_data_len); | ||||
|   this->send_query_(send_data, send_data_len); | ||||
|   this->get_motion_trigger_time(); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::set_motion_to_rest_time(uint16_t value) { | ||||
|   if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0)) | ||||
|     return;  // You'll have to check that you're in custom mode to set it up | ||||
|   uint8_t h8_num = (value >> 8) & 0xff; | ||||
|   uint8_t l8_num = value & 0xff; | ||||
|   uint8_t send_data_len = 13; | ||||
|   uint8_t send_data[13] = {0x53, 0x59, 0x08, 0x0D, 0x00, 0x04, 0x00, 0x00, h8_num, l8_num, 0x00, 0x54, 0x43}; | ||||
|   send_data[10] = get_frame_crc_sum(send_data, send_data_len); | ||||
|   this->send_query_(send_data, send_data_len); | ||||
|   this->get_motion_to_rest_time(); | ||||
| } | ||||
|  | ||||
| void MR24HPC1Component::set_custom_unman_time(uint16_t value) { | ||||
|   if ((this->custom_mode_num_sensor_ != nullptr) && (this->custom_mode_num_sensor_->state == 0)) | ||||
|     return;  // You'll have to check that you're in custom mode to set it up | ||||
|   uint32_t value_ms = value * 1000; | ||||
|   uint8_t h24_num = (value_ms >> 24) & 0xff; | ||||
|   uint8_t h16_num = (value_ms >> 16) & 0xff; | ||||
|   uint8_t h8_num = (value_ms >> 8) & 0xff; | ||||
|   uint8_t l8_num = value_ms & 0xff; | ||||
|   uint8_t send_data_len = 13; | ||||
|   uint8_t send_data[13] = {0x53, 0x59, 0x08, 0x0E, 0x00, 0x04, h24_num, h16_num, h8_num, l8_num, 0x00, 0x54, 0x43}; | ||||
|   send_data[10] = get_frame_crc_sum(send_data, send_data_len); | ||||
|   this->send_query_(send_data, send_data_len); | ||||
|   this->get_custom_unman_time(); | ||||
| } | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										217
									
								
								esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,217 @@ | ||||
| #pragma once | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/defines.h" | ||||
| #ifdef USE_BINARY_SENSOR | ||||
| #include "esphome/components/binary_sensor/binary_sensor.h" | ||||
| #endif | ||||
| #ifdef USE_SENSOR | ||||
| #include "esphome/components/sensor/sensor.h" | ||||
| #endif | ||||
| #ifdef USE_NUMBER | ||||
| #include "esphome/components/number/number.h" | ||||
| #endif | ||||
| #ifdef USE_SWITCH | ||||
| #include "esphome/components/switch/switch.h" | ||||
| #endif | ||||
| #ifdef USE_BUTTON | ||||
| #include "esphome/components/button/button.h" | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
| #include "esphome/components/select/select.h" | ||||
| #endif | ||||
| #ifdef USE_TEXT_SENSOR | ||||
| #include "esphome/components/text_sensor/text_sensor.h" | ||||
| #endif | ||||
| #include "esphome/components/uart/uart.h" | ||||
| #include "esphome/core/automation.h" | ||||
| #include "esphome/core/helpers.h" | ||||
|  | ||||
| #include "seeed_mr24hpc1_constants.h" | ||||
|  | ||||
| #include <map> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| enum FrameState { | ||||
|   FRAME_IDLE, | ||||
|   FRAME_HEADER2, | ||||
|   FRAME_CTL_WORD, | ||||
|   FRAME_CMD_WORD, | ||||
|   FRAME_DATA_LEN_H, | ||||
|   FRAME_DATA_LEN_L, | ||||
|   FRAME_DATA_BYTES, | ||||
|   FRAME_DATA_CRC, | ||||
|   FRAME_TAIL1, | ||||
|   FRAME_TAIL2, | ||||
| }; | ||||
|  | ||||
| enum PollingState { | ||||
|   STANDARD_FUNCTION_QUERY_PRODUCT_MODE = 0, | ||||
|   STANDARD_FUNCTION_QUERY_PRODUCT_ID, | ||||
|   STANDARD_FUNCTION_QUERY_FIRMWARE_VERSION, | ||||
|   STANDARD_FUNCTION_QUERY_HARDWARE_MODE,  // Above is the equipment information | ||||
|   STANDARD_FUNCTION_QUERY_SCENE_MODE, | ||||
|   STANDARD_FUNCTION_QUERY_SENSITIVITY, | ||||
|   STANDARD_FUNCTION_QUERY_UNMANNED_TIME, | ||||
|   STANDARD_FUNCTION_QUERY_HUMAN_STATUS, | ||||
|   STANDARD_FUNCTION_QUERY_HUMAN_MOTION_INF, | ||||
|   STANDARD_FUNCTION_QUERY_BODY_MOVE_PARAMETER, | ||||
|   STANDARD_FUNCTION_QUERY_KEEPAWAY_STATUS, | ||||
|   STANDARD_QUERY_CUSTOM_MODE, | ||||
|   STANDARD_FUNCTION_QUERY_HEARTBEAT_STATE,  // Above is the basic function | ||||
|  | ||||
|   CUSTOM_FUNCTION_QUERY_EXISTENCE_BOUNDARY, | ||||
|   CUSTOM_FUNCTION_QUERY_MOTION_BOUNDARY, | ||||
|   CUSTOM_FUNCTION_QUERY_EXISTENCE_THRESHOLD, | ||||
|   CUSTOM_FUNCTION_QUERY_MOTION_THRESHOLD, | ||||
|   CUSTOM_FUNCTION_QUERY_MOTION_TRIGGER_TIME, | ||||
|   CUSTOM_FUNCTION_QUERY_MOTION_TO_REST_TIME, | ||||
|   CUSTOM_FUNCTION_QUERY_TIME_OF_ENTER_UNMANNED, | ||||
|  | ||||
|   UNDERLY_FUNCTION_QUERY_HUMAN_STATUS, | ||||
|   UNDERLY_FUNCTION_QUERY_SPATIAL_STATIC_VALUE, | ||||
|   UNDERLY_FUNCTION_QUERY_SPATIAL_MOTION_VALUE, | ||||
|   UNDERLY_FUNCTION_QUERY_DISTANCE_OF_STATIC_OBJECT, | ||||
|   UNDERLY_FUNCTION_QUERY_DISTANCE_OF_MOVING_OBJECT, | ||||
|   UNDERLY_FUNCTION_QUERY_TARGET_MOVEMENT_SPEED, | ||||
| }; | ||||
|  | ||||
| enum OutputSwitch { | ||||
|   OUTPUT_SWITCH_INIT, | ||||
|   OUTPUT_SWITCH_ON, | ||||
|   OUTPUT_SWTICH_OFF, | ||||
| }; | ||||
|  | ||||
| static const char *const S_SCENE_STR[5] = {"None", "Living Room", "Bedroom", "Washroom", "Area Detection"}; | ||||
| static const bool S_SOMEONE_EXISTS_STR[2] = {false, true}; | ||||
| static const char *const S_MOTION_STATUS_STR[3] = {"None", "Motionless", "Active"}; | ||||
| static const char *const S_KEEP_AWAY_STR[3] = {"None", "Close", "Away"}; | ||||
| static const char *const S_UNMANNED_TIME_STR[9] = {"None", "10s",   "30s",   "1min", "2min", | ||||
|                                                    "5min", "10min", "30min", "60min"}; | ||||
| static const char *const S_BOUNDARY_STR[10] = {"0.5m", "1.0m", "1.5m", "2.0m", "2.5m", | ||||
|                                                "3.0m", "3.5m", "4.0m", "4.5m", "5.0m"};                // uint: m | ||||
| static const float S_PRESENCE_OF_DETECTION_RANGE_STR[7] = {0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 2.5f, 3.0f};  // uint: m | ||||
|  | ||||
| class MR24HPC1Component : public Component, | ||||
|                           public uart::UARTDevice {  // The class name must be the name defined by text_sensor.py | ||||
| #ifdef USE_TEXT_SENSOR | ||||
|   SUB_TEXT_SENSOR(heartbeat_state) | ||||
|   SUB_TEXT_SENSOR(product_model) | ||||
|   SUB_TEXT_SENSOR(product_id) | ||||
|   SUB_TEXT_SENSOR(hardware_model) | ||||
|   SUB_TEXT_SENSOR(firware_version) | ||||
|   SUB_TEXT_SENSOR(keep_away) | ||||
|   SUB_TEXT_SENSOR(motion_status) | ||||
|   SUB_TEXT_SENSOR(custom_mode_end) | ||||
| #endif | ||||
| #ifdef USE_BINARY_SENSOR | ||||
|   SUB_BINARY_SENSOR(has_target) | ||||
| #endif | ||||
| #ifdef USE_SENSOR | ||||
|   SUB_SENSOR(custom_presence_of_detection) | ||||
|   SUB_SENSOR(movement_signs) | ||||
|   SUB_SENSOR(custom_motion_distance) | ||||
|   SUB_SENSOR(custom_spatial_static_value) | ||||
|   SUB_SENSOR(custom_spatial_motion_value) | ||||
|   SUB_SENSOR(custom_motion_speed) | ||||
|   SUB_SENSOR(custom_mode_num) | ||||
| #endif | ||||
| #ifdef USE_SWITCH | ||||
|   SUB_SWITCH(underlying_open_function) | ||||
| #endif | ||||
| #ifdef USE_BUTTON | ||||
|   SUB_BUTTON(restart) | ||||
|   SUB_BUTTON(custom_set_end) | ||||
| #endif | ||||
| #ifdef USE_SELECT | ||||
|   SUB_SELECT(scene_mode) | ||||
|   SUB_SELECT(unman_time) | ||||
|   SUB_SELECT(existence_boundary) | ||||
|   SUB_SELECT(motion_boundary) | ||||
| #endif | ||||
| #ifdef USE_NUMBER | ||||
|   SUB_NUMBER(sensitivity) | ||||
|   SUB_NUMBER(custom_mode) | ||||
|   SUB_NUMBER(existence_threshold) | ||||
|   SUB_NUMBER(motion_threshold) | ||||
|   SUB_NUMBER(motion_trigger) | ||||
|   SUB_NUMBER(motion_to_rest) | ||||
|   SUB_NUMBER(custom_unman_time) | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
|   char c_product_mode_[PRODUCT_BUF_MAX_SIZE + 1]; | ||||
|   char c_product_id_[PRODUCT_BUF_MAX_SIZE + 1]; | ||||
|   char c_hardware_model_[PRODUCT_BUF_MAX_SIZE + 1]; | ||||
|   char c_firmware_version_[PRODUCT_BUF_MAX_SIZE + 1]; | ||||
|   uint8_t s_output_info_switch_flag_; | ||||
|   uint8_t sg_recv_data_state_; | ||||
|   uint8_t sg_frame_len_; | ||||
|   uint8_t sg_data_len_; | ||||
|   uint8_t sg_frame_buf_[FRAME_BUF_MAX_SIZE]; | ||||
|   uint8_t sg_frame_prase_buf_[FRAME_BUF_MAX_SIZE]; | ||||
|   int sg_start_query_data_; | ||||
|   bool check_dev_inf_sign_; | ||||
|   bool poll_time_base_func_check_; | ||||
|  | ||||
|   void update_(); | ||||
|   void r24_split_data_frame_(uint8_t value); | ||||
|   void r24_parse_data_frame_(uint8_t *data, uint8_t len); | ||||
|   void r24_frame_parse_open_underlying_information_(uint8_t *data); | ||||
|   void r24_frame_parse_work_status_(uint8_t *data); | ||||
|   void r24_frame_parse_product_information_(uint8_t *data); | ||||
|   void r24_frame_parse_human_information_(uint8_t *data); | ||||
|   void send_query_(const uint8_t *query, size_t string_length); | ||||
|  | ||||
|  public: | ||||
|   float get_setup_priority() const override { return esphome::setup_priority::LATE; } | ||||
|   void setup() override; | ||||
|   void dump_config() override; | ||||
|   void loop() override; | ||||
|  | ||||
|   void get_heartbeat_packet(); | ||||
|   void get_radar_output_information_switch(); | ||||
|   void get_product_mode(); | ||||
|   void get_product_id(); | ||||
|   void get_hardware_model(); | ||||
|   void get_firmware_version(); | ||||
|   void get_human_status(); | ||||
|   void get_human_motion_info(); | ||||
|   void get_body_motion_params(); | ||||
|   void get_keep_away(); | ||||
|   void get_scene_mode(); | ||||
|   void get_sensitivity(); | ||||
|   void get_unmanned_time(); | ||||
|   void get_custom_mode(); | ||||
|   void get_existence_boundary(); | ||||
|   void get_motion_boundary(); | ||||
|   void get_spatial_static_value(); | ||||
|   void get_spatial_motion_value(); | ||||
|   void get_distance_of_static_object(); | ||||
|   void get_distance_of_moving_object(); | ||||
|   void get_target_movement_speed(); | ||||
|   void get_existence_threshold(); | ||||
|   void get_motion_threshold(); | ||||
|   void get_motion_trigger_time(); | ||||
|   void get_motion_to_rest_time(); | ||||
|   void get_custom_unman_time(); | ||||
|  | ||||
|   void set_scene_mode(uint8_t value); | ||||
|   void set_underlying_open_function(bool enable); | ||||
|   void set_sensitivity(uint8_t value); | ||||
|   void set_restart(); | ||||
|   void set_unman_time(uint8_t value); | ||||
|   void set_custom_mode(uint8_t mode); | ||||
|   void set_custom_end_mode(); | ||||
|   void set_existence_boundary(uint8_t value); | ||||
|   void set_motion_boundary(uint8_t value); | ||||
|   void set_existence_threshold(uint8_t value); | ||||
|   void set_motion_threshold(uint8_t value); | ||||
|   void set_motion_trigger_time(uint8_t value); | ||||
|   void set_motion_to_rest_time(uint16_t value); | ||||
|   void set_custom_unman_time(uint16_t value); | ||||
| }; | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										173
									
								
								esphome/components/seeed_mr24hpc1/seeed_mr24hpc1_constants.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								esphome/components/seeed_mr24hpc1/seeed_mr24hpc1_constants.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,173 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <cstdint> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| static const uint8_t FRAME_BUF_MAX_SIZE = 128; | ||||
| static const uint8_t PRODUCT_BUF_MAX_SIZE = 32; | ||||
|  | ||||
| static const uint8_t FRAME_CONTROL_WORD_INDEX = 2; | ||||
| static const uint8_t FRAME_COMMAND_WORD_INDEX = 3; | ||||
| static const uint8_t FRAME_DATA_INDEX = 6; | ||||
|  | ||||
| static const uint8_t FRAME_HEADER1_VALUE = 0x53; | ||||
| static const uint8_t FRAME_HEADER2_VALUE = 0x59; | ||||
| static const uint8_t FRAME_TAIL1_VALUE = 0x54; | ||||
| static const uint8_t FRAME_TAIL2_VALUE = 0x43; | ||||
|  | ||||
| static const uint8_t CONTROL_MAIN = 0x01; | ||||
| static const uint8_t CONTROL_PRODUCT_INFORMATION = 0x02; | ||||
| static const uint8_t CONTROL_WORK = 0x05; | ||||
| static const uint8_t CONTROL_UNDERLYING_FUNCTION = 0x08; | ||||
| static const uint8_t CONTROL_HUMAN_INFORMATION = 0x80; | ||||
|  | ||||
| static const uint8_t COMMAND_HEARTBEAT = 0x01; | ||||
| static const uint8_t COMMAND_RESTART = 0x02; | ||||
|  | ||||
| static const uint8_t COMMAND_PRODUCT_MODE = 0xA1; | ||||
| static const uint8_t COMMAND_PRODUCT_ID = 0xA2; | ||||
| static const uint8_t COMMAND_HARDWARE_MODEL = 0xA3; | ||||
| static const uint8_t COMMAND_FIRMWARE_VERSION = 0xA4; | ||||
|  | ||||
| static const uint8_t GET_HEARTBEAT[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_MAIN, COMMAND_HEARTBEAT, 0x00, 0x01, 0x0F, 0xBE, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t SET_RESTART[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_MAIN, COMMAND_RESTART, 0x00, 0x01, 0x0F, 0xBF, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
|  | ||||
| static const uint8_t GET_PRODUCT_MODE[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_PRODUCT_INFORMATION, COMMAND_PRODUCT_MODE, 0x00, 0x01, 0x0F, 0x5F, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_PRODUCT_ID[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_PRODUCT_INFORMATION, COMMAND_PRODUCT_ID, 0x00, 0x01, 0x0F, 0x60, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_HARDWARE_MODEL[] = { | ||||
|     FRAME_HEADER1_VALUE, | ||||
|     FRAME_HEADER2_VALUE, | ||||
|     CONTROL_PRODUCT_INFORMATION, | ||||
|     COMMAND_HARDWARE_MODEL, | ||||
|     0x00, | ||||
|     0x01, | ||||
|     0x0F, | ||||
|     0x61, | ||||
|     FRAME_TAIL1_VALUE, | ||||
|     FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_FIRMWARE_VERSION[] = { | ||||
|     FRAME_HEADER1_VALUE, | ||||
|     FRAME_HEADER2_VALUE, | ||||
|     CONTROL_PRODUCT_INFORMATION, | ||||
|     COMMAND_FIRMWARE_VERSION, | ||||
|     0x00, | ||||
|     0x01, | ||||
|     0x0F, | ||||
|     0x62, | ||||
|     FRAME_TAIL1_VALUE, | ||||
|     FRAME_TAIL2_VALUE, | ||||
| }; | ||||
|  | ||||
| static const uint8_t GET_SCENE_MODE[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_WORK, 0x87, 0x00, 0x01, 0x0F, 0x48, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_SENSITIVITY[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_WORK, 0x88, 0x00, 0x01, 0x0F, 0x49, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_CUSTOM_MODE[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_WORK, 0x89, 0x00, 0x01, 0x0F, 0x4A, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
|  | ||||
| static const uint8_t UNDERLYING_SWITCH_ON[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x00, 0x00, 0x01, 0x01, 0xB6, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t UNDERLYING_SWITCH_OFF[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x00, 0x00, 0x01, 0x00, 0xB5, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
|  | ||||
| static const uint8_t GET_RADAR_OUTPUT_INFORMATION_SWITCH[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x80, 0x00, 0x01, 0x0F, 0x44, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_SPATIAL_STATIC_VALUE[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x81, 0x00, 0x01, 0x0F, 0x45, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_SPATIAL_MOTION_VALUE[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x82, 0x00, 0x01, 0x0F, 0x46, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_DISTANCE_OF_STATIC_OBJECT[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x83, 0x00, 0x01, 0x0F, 0x47, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_DISTANCE_OF_MOVING_OBJECT[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x84, 0x00, 0x01, 0x0F, 0x48, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_TARGET_MOVEMENT_SPEED[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x85, 0x00, 0x01, 0x0F, 0x49, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_EXISTENCE_THRESHOLD[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x88, 0x00, 0x01, 0x0F, 0x4C, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_MOTION_THRESHOLD[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x89, 0x00, 0x01, 0x0F, 0x4D, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_EXISTENCE_BOUNDARY[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x8A, 0x00, 0x01, 0x0F, 0x4E, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_MOTION_BOUNDARY[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x8B, 0x00, 0x01, 0x0F, 0x4F, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_MOTION_TRIGGER_TIME[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x8C, 0x00, 0x01, 0x0F, 0x50, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_MOTION_TO_REST_TIME[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x8D, 0x00, 0x01, 0x0F, 0x51, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_CUSTOM_UNMAN_TIME[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_UNDERLYING_FUNCTION, 0x8E, 0x00, 0x01, 0x0F, 0x52, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
|  | ||||
| static const uint8_t GET_HUMAN_STATUS[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_HUMAN_INFORMATION, 0x81, 0x00, 0x01, 0x0F, 0xBD, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_HUMAN_MOTION_INFORMATION[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_HUMAN_INFORMATION, 0x82, 0x00, 0x01, 0x0F, 0xBE, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_BODY_MOTION_PARAMETERS[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_HUMAN_INFORMATION, 0x83, 0x00, 0x01, 0x0F, 0xBF, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_UNMANNED_TIME[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_HUMAN_INFORMATION, 0x8A, 0x00, 0x01, 0x0F, 0xC6, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
| static const uint8_t GET_KEEP_AWAY[] = { | ||||
|     FRAME_HEADER1_VALUE, FRAME_HEADER2_VALUE, CONTROL_HUMAN_INFORMATION, 0x8B, 0x00, 0x01, 0x0F, 0xC7, | ||||
|     FRAME_TAIL1_VALUE,   FRAME_TAIL2_VALUE, | ||||
| }; | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										103
									
								
								esphome/components/seeed_mr24hpc1/select/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								esphome/components/seeed_mr24hpc1/select/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import select | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     ENTITY_CATEGORY_CONFIG, | ||||
| ) | ||||
| from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns | ||||
|  | ||||
| SceneModeSelect = mr24hpc1_ns.class_("SceneModeSelect", select.Select) | ||||
| UnmanTimeSelect = mr24hpc1_ns.class_("UnmanTimeSelect", select.Select) | ||||
| ExistenceBoundarySelect = mr24hpc1_ns.class_("ExistenceBoundarySelect", select.Select) | ||||
| MotionBoundarySelect = mr24hpc1_ns.class_("MotionBoundarySelect", select.Select) | ||||
|  | ||||
| CONF_SCENE_MODE = "scene_mode" | ||||
| CONF_UNMAN_TIME = "unman_time" | ||||
| CONF_EXISTENCE_BOUNDARY = "existence_boundary" | ||||
| CONF_MOTION_BOUNDARY = "motion_boundary" | ||||
|  | ||||
| CONFIG_SCHEMA = { | ||||
|     cv.GenerateID(CONF_MR24HPC1_ID): cv.use_id(MR24HPC1Component), | ||||
|     cv.Optional(CONF_SCENE_MODE): select.select_schema( | ||||
|         SceneModeSelect, | ||||
|         entity_category=ENTITY_CATEGORY_CONFIG, | ||||
|         icon="mdi:hoop-house", | ||||
|     ), | ||||
|     cv.Optional(CONF_UNMAN_TIME): select.select_schema( | ||||
|         UnmanTimeSelect, | ||||
|         entity_category=ENTITY_CATEGORY_CONFIG, | ||||
|         icon="mdi:timeline-clock", | ||||
|     ), | ||||
|     cv.Optional(CONF_EXISTENCE_BOUNDARY): select.select_schema( | ||||
|         ExistenceBoundarySelect, | ||||
|         entity_category=ENTITY_CATEGORY_CONFIG, | ||||
|     ), | ||||
|     cv.Optional(CONF_MOTION_BOUNDARY): select.select_schema( | ||||
|         MotionBoundarySelect, | ||||
|         entity_category=ENTITY_CATEGORY_CONFIG, | ||||
|     ), | ||||
| } | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) | ||||
|     if scenemode_config := config.get(CONF_SCENE_MODE): | ||||
|         s = await select.new_select( | ||||
|             scenemode_config, | ||||
|             options=["None", "Living Room", "Bedroom", "Washroom", "Area Detection"], | ||||
|         ) | ||||
|         await cg.register_parented(s, config[CONF_MR24HPC1_ID]) | ||||
|         cg.add(mr24hpc1_component.set_scene_mode_select(s)) | ||||
|     if unmantime_config := config.get(CONF_UNMAN_TIME): | ||||
|         s = await select.new_select( | ||||
|             unmantime_config, | ||||
|             options=[ | ||||
|                 "None", | ||||
|                 "10s", | ||||
|                 "30s", | ||||
|                 "1min", | ||||
|                 "2min", | ||||
|                 "5min", | ||||
|                 "10min", | ||||
|                 "30min", | ||||
|                 "60min", | ||||
|             ], | ||||
|         ) | ||||
|         await cg.register_parented(s, config[CONF_MR24HPC1_ID]) | ||||
|         cg.add(mr24hpc1_component.set_unman_time_select(s)) | ||||
|     if existence_boundary_config := config.get(CONF_EXISTENCE_BOUNDARY): | ||||
|         s = await select.new_select( | ||||
|             existence_boundary_config, | ||||
|             options=[ | ||||
|                 "0.5m", | ||||
|                 "1.0m", | ||||
|                 "1.5m", | ||||
|                 "2.0m", | ||||
|                 "2.5m", | ||||
|                 "3.0m", | ||||
|                 "3.5m", | ||||
|                 "4.0m", | ||||
|                 "4.5m", | ||||
|                 "5.0m", | ||||
|             ], | ||||
|         ) | ||||
|         await cg.register_parented(s, config[CONF_MR24HPC1_ID]) | ||||
|         cg.add(mr24hpc1_component.set_existence_boundary_select(s)) | ||||
|     if motion_boundary_config := config.get(CONF_MOTION_BOUNDARY): | ||||
|         s = await select.new_select( | ||||
|             motion_boundary_config, | ||||
|             options=[ | ||||
|                 "0.5m", | ||||
|                 "1.0m", | ||||
|                 "1.5m", | ||||
|                 "2.0m", | ||||
|                 "2.5m", | ||||
|                 "3.0m", | ||||
|                 "3.5m", | ||||
|                 "4.0m", | ||||
|                 "4.5m", | ||||
|                 "5.0m", | ||||
|             ], | ||||
|         ) | ||||
|         await cg.register_parented(s, config[CONF_MR24HPC1_ID]) | ||||
|         cg.add(mr24hpc1_component.set_motion_boundary_select(s)) | ||||
| @@ -0,0 +1,15 @@ | ||||
| #include "existence_boundary_select.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| void ExistenceBoundarySelect::control(const std::string &value) { | ||||
|   this->publish_state(value); | ||||
|   auto index = this->index_of(value); | ||||
|   if (index.has_value()) { | ||||
|     this->parent_->set_existence_boundary(index.value()); | ||||
|   } | ||||
| } | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/select/select.h" | ||||
| #include "../seeed_mr24hpc1.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| class ExistenceBoundarySelect : public select::Select, public Parented<MR24HPC1Component> { | ||||
|  public: | ||||
|   ExistenceBoundarySelect() = default; | ||||
|  | ||||
|  protected: | ||||
|   void control(const std::string &value) override; | ||||
| }; | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,15 @@ | ||||
| #include "motion_boundary_select.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| void MotionBoundarySelect::control(const std::string &value) { | ||||
|   this->publish_state(value); | ||||
|   auto index = this->index_of(value); | ||||
|   if (index.has_value()) { | ||||
|     this->parent_->set_motion_boundary(index.value()); | ||||
|   } | ||||
| } | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/select/select.h" | ||||
| #include "../seeed_mr24hpc1.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| class MotionBoundarySelect : public select::Select, public Parented<MR24HPC1Component> { | ||||
|  public: | ||||
|   MotionBoundarySelect() = default; | ||||
|  | ||||
|  protected: | ||||
|   void control(const std::string &value) override; | ||||
| }; | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,15 @@ | ||||
| #include "scene_mode_select.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| void SceneModeSelect::control(const std::string &value) { | ||||
|   this->publish_state(value); | ||||
|   auto index = this->index_of(value); | ||||
|   if (index.has_value()) { | ||||
|     this->parent_->set_scene_mode(index.value()); | ||||
|   } | ||||
| } | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										18
									
								
								esphome/components/seeed_mr24hpc1/select/scene_mode_select.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								esphome/components/seeed_mr24hpc1/select/scene_mode_select.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/select/select.h" | ||||
| #include "../seeed_mr24hpc1.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| class SceneModeSelect : public select::Select, public Parented<MR24HPC1Component> { | ||||
|  public: | ||||
|   SceneModeSelect() = default; | ||||
|  | ||||
|  protected: | ||||
|   void control(const std::string &value) override; | ||||
| }; | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
| @@ -0,0 +1,15 @@ | ||||
| #include "unman_time_select.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| void UnmanTimeSelect::control(const std::string &value) { | ||||
|   this->publish_state(value); | ||||
|   auto index = this->index_of(value); | ||||
|   if (index.has_value()) { | ||||
|     this->parent_->set_unman_time(index.value()); | ||||
|   } | ||||
| } | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										18
									
								
								esphome/components/seeed_mr24hpc1/select/unman_time_select.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								esphome/components/seeed_mr24hpc1/select/unman_time_select.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/select/select.h" | ||||
| #include "../seeed_mr24hpc1.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| class UnmanTimeSelect : public select::Select, public Parented<MR24HPC1Component> { | ||||
|  public: | ||||
|   UnmanTimeSelect() = default; | ||||
|  | ||||
|  protected: | ||||
|   void control(const std::string &value) override; | ||||
| }; | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										82
									
								
								esphome/components/seeed_mr24hpc1/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								esphome/components/seeed_mr24hpc1/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import sensor | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     DEVICE_CLASS_DISTANCE, | ||||
|     DEVICE_CLASS_ENERGY, | ||||
|     DEVICE_CLASS_SPEED, | ||||
|     UNIT_METER, | ||||
| ) | ||||
| from . import CONF_MR24HPC1_ID, MR24HPC1Component | ||||
|  | ||||
| CONF_CUSTOM_PRESENCE_OF_DETECTION = "custom_presence_of_detection" | ||||
| CONF_MOVEMENT_SIGNS = "movement_signs" | ||||
| CONF_CUSTOM_MOTION_DISTANCE = "custom_motion_distance" | ||||
| CONF_CUSTOM_SPATIAL_STATIC_VALUE = "custom_spatial_static_value" | ||||
| CONF_CUSTOM_SPATIAL_MOTION_VALUE = "custom_spatial_motion_value" | ||||
| CONF_CUSTOM_MOTION_SPEED = "custom_motion_speed" | ||||
| CONF_CUSTOM_MODE_NUM = "custom_mode_num" | ||||
|  | ||||
| CONFIG_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.GenerateID(CONF_MR24HPC1_ID): cv.use_id(MR24HPC1Component), | ||||
|         cv.Optional(CONF_CUSTOM_PRESENCE_OF_DETECTION): sensor.sensor_schema( | ||||
|             device_class=DEVICE_CLASS_DISTANCE, | ||||
|             unit_of_measurement=UNIT_METER, | ||||
|             accuracy_decimals=2,  # Specify the number of decimal places | ||||
|             icon="mdi:signal-distance-variant", | ||||
|         ), | ||||
|         cv.Optional(CONF_MOVEMENT_SIGNS): sensor.sensor_schema( | ||||
|             icon="mdi:human-greeting-variant", | ||||
|         ), | ||||
|         cv.Optional(CONF_CUSTOM_MOTION_DISTANCE): sensor.sensor_schema( | ||||
|             unit_of_measurement=UNIT_METER, | ||||
|             accuracy_decimals=2, | ||||
|             icon="mdi:signal-distance-variant", | ||||
|         ), | ||||
|         cv.Optional(CONF_CUSTOM_SPATIAL_STATIC_VALUE): sensor.sensor_schema( | ||||
|             device_class=DEVICE_CLASS_ENERGY, | ||||
|             icon="mdi:counter", | ||||
|         ), | ||||
|         cv.Optional(CONF_CUSTOM_SPATIAL_MOTION_VALUE): sensor.sensor_schema( | ||||
|             device_class=DEVICE_CLASS_ENERGY, | ||||
|             icon="mdi:counter", | ||||
|         ), | ||||
|         cv.Optional(CONF_CUSTOM_MOTION_SPEED): sensor.sensor_schema( | ||||
|             unit_of_measurement="m/s", | ||||
|             device_class=DEVICE_CLASS_SPEED, | ||||
|             accuracy_decimals=2, | ||||
|             icon="mdi:run-fast", | ||||
|         ), | ||||
|         cv.Optional(CONF_CUSTOM_MODE_NUM): sensor.sensor_schema( | ||||
|             icon="mdi:counter", | ||||
|         ), | ||||
|     } | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) | ||||
|     if custompresenceofdetection_config := config.get( | ||||
|         CONF_CUSTOM_PRESENCE_OF_DETECTION | ||||
|     ): | ||||
|         sens = await sensor.new_sensor(custompresenceofdetection_config) | ||||
|         cg.add(mr24hpc1_component.set_custom_presence_of_detection_sensor(sens)) | ||||
|     if movementsigns_config := config.get(CONF_MOVEMENT_SIGNS): | ||||
|         sens = await sensor.new_sensor(movementsigns_config) | ||||
|         cg.add(mr24hpc1_component.set_movement_signs_sensor(sens)) | ||||
|     if custommotiondistance_config := config.get(CONF_CUSTOM_MOTION_DISTANCE): | ||||
|         sens = await sensor.new_sensor(custommotiondistance_config) | ||||
|         cg.add(mr24hpc1_component.set_custom_motion_distance_sensor(sens)) | ||||
|     if customspatialstaticvalue_config := config.get(CONF_CUSTOM_SPATIAL_STATIC_VALUE): | ||||
|         sens = await sensor.new_sensor(customspatialstaticvalue_config) | ||||
|         cg.add(mr24hpc1_component.set_custom_spatial_static_value_sensor(sens)) | ||||
|     if customspatialmotionvalue_config := config.get(CONF_CUSTOM_SPATIAL_MOTION_VALUE): | ||||
|         sens = await sensor.new_sensor(customspatialmotionvalue_config) | ||||
|         cg.add(mr24hpc1_component.set_custom_spatial_motion_value_sensor(sens)) | ||||
|     if custommotionspeed_config := config.get(CONF_CUSTOM_MOTION_SPEED): | ||||
|         sens = await sensor.new_sensor(custommotionspeed_config) | ||||
|         cg.add(mr24hpc1_component.set_custom_motion_speed_sensor(sens)) | ||||
|     if custommodenum_config := config.get(CONF_CUSTOM_MODE_NUM): | ||||
|         sens = await sensor.new_sensor(custommodenum_config) | ||||
|         cg.add(mr24hpc1_component.set_custom_mode_num_sensor(sens)) | ||||
							
								
								
									
										32
									
								
								esphome/components/seeed_mr24hpc1/switch/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								esphome/components/seeed_mr24hpc1/switch/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import switch | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     DEVICE_CLASS_SWITCH, | ||||
|     ENTITY_CATEGORY_CONFIG, | ||||
| ) | ||||
| from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns | ||||
|  | ||||
| UnderlyingOpenFuncSwitch = mr24hpc1_ns.class_( | ||||
|     "UnderlyOpenFunctionSwitch", switch.Switch | ||||
| ) | ||||
|  | ||||
| CONF_UNDERLYING_OPEN_FUNCTION = "underlying_open_function" | ||||
|  | ||||
| CONFIG_SCHEMA = { | ||||
|     cv.GenerateID(CONF_MR24HPC1_ID): cv.use_id(MR24HPC1Component), | ||||
|     cv.Optional(CONF_UNDERLYING_OPEN_FUNCTION): switch.switch_schema( | ||||
|         UnderlyingOpenFuncSwitch, | ||||
|         device_class=DEVICE_CLASS_SWITCH, | ||||
|         entity_category=ENTITY_CATEGORY_CONFIG, | ||||
|         icon="mdi:electric-switch", | ||||
|     ), | ||||
| } | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) | ||||
|     if underlying_open_function_config := config.get(CONF_UNDERLYING_OPEN_FUNCTION): | ||||
|         s = await switch.new_switch(underlying_open_function_config) | ||||
|         await cg.register_parented(s, config[CONF_MR24HPC1_ID]) | ||||
|         cg.add(mr24hpc1_component.set_underlying_open_function_switch(s)) | ||||
| @@ -0,0 +1,12 @@ | ||||
| #include "underlyFuc_switch.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| void UnderlyOpenFunctionSwitch::write_state(bool state) { | ||||
|   this->publish_state(state); | ||||
|   this->parent_->set_underlying_open_function(state); | ||||
| } | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										18
									
								
								esphome/components/seeed_mr24hpc1/switch/underlyFuc_switch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								esphome/components/seeed_mr24hpc1/switch/underlyFuc_switch.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/switch/switch.h" | ||||
| #include "../seeed_mr24hpc1.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace seeed_mr24hpc1 { | ||||
|  | ||||
| class UnderlyOpenFunctionSwitch : public switch_::Switch, public Parented<MR24HPC1Component> { | ||||
|  public: | ||||
|   UnderlyOpenFunctionSwitch() = default; | ||||
|  | ||||
|  protected: | ||||
|   void write_state(bool state) override; | ||||
| }; | ||||
|  | ||||
| }  // namespace seeed_mr24hpc1 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										74
									
								
								esphome/components/seeed_mr24hpc1/text_sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								esphome/components/seeed_mr24hpc1/text_sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import text_sensor | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ENTITY_CATEGORY_DIAGNOSTIC | ||||
| from . import CONF_MR24HPC1_ID, MR24HPC1Component | ||||
|  | ||||
| CONF_HEART_BEAT = "heart_beat" | ||||
| CONF_PRODUCT_MODEL = "product_model" | ||||
| CONF_PRODUCT_ID = "product_id" | ||||
| CONF_HARDWARE_MODEL = "hardware_model" | ||||
| CONF_HARDWARE_VERSION = "hardware_version" | ||||
|  | ||||
| CONF_KEEP_AWAY = "keep_away" | ||||
| CONF_MOTION_STATUS = "motion_status" | ||||
|  | ||||
| CONF_CUSTOM_MODE_END = "custom_mode_end" | ||||
|  | ||||
|  | ||||
| # The entity category for read only diagnostic values, for example RSSI, uptime or MAC Address | ||||
| CONFIG_SCHEMA = { | ||||
|     cv.GenerateID(CONF_MR24HPC1_ID): cv.use_id(MR24HPC1Component), | ||||
|     cv.Optional(CONF_HEART_BEAT): text_sensor.text_sensor_schema( | ||||
|         entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:connection" | ||||
|     ), | ||||
|     cv.Optional(CONF_PRODUCT_MODEL): text_sensor.text_sensor_schema( | ||||
|         entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:information-outline" | ||||
|     ), | ||||
|     cv.Optional(CONF_PRODUCT_ID): text_sensor.text_sensor_schema( | ||||
|         entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:information-outline" | ||||
|     ), | ||||
|     cv.Optional(CONF_HARDWARE_MODEL): text_sensor.text_sensor_schema( | ||||
|         entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:information-outline" | ||||
|     ), | ||||
|     cv.Optional(CONF_HARDWARE_VERSION): text_sensor.text_sensor_schema( | ||||
|         entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:information-outline" | ||||
|     ), | ||||
|     cv.Optional(CONF_KEEP_AWAY): text_sensor.text_sensor_schema( | ||||
|         entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:walk" | ||||
|     ), | ||||
|     cv.Optional(CONF_MOTION_STATUS): text_sensor.text_sensor_schema( | ||||
|         entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:human-greeting" | ||||
|     ), | ||||
|     cv.Optional(CONF_CUSTOM_MODE_END): text_sensor.text_sensor_schema( | ||||
|         entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon="mdi:account-check" | ||||
|     ), | ||||
| } | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) | ||||
|     if heartbeat_config := config.get(CONF_HEART_BEAT): | ||||
|         sens = await text_sensor.new_text_sensor(heartbeat_config) | ||||
|         cg.add(mr24hpc1_component.set_heartbeat_state_text_sensor(sens)) | ||||
|     if productmodel_config := config.get(CONF_PRODUCT_MODEL): | ||||
|         sens = await text_sensor.new_text_sensor(productmodel_config) | ||||
|         cg.add(mr24hpc1_component.set_product_model_text_sensor(sens)) | ||||
|     if productid_config := config.get(CONF_PRODUCT_ID): | ||||
|         sens = await text_sensor.new_text_sensor(productid_config) | ||||
|         cg.add(mr24hpc1_component.set_product_id_text_sensor(sens)) | ||||
|     if hardwaremodel_config := config.get(CONF_HARDWARE_MODEL): | ||||
|         sens = await text_sensor.new_text_sensor(hardwaremodel_config) | ||||
|         cg.add(mr24hpc1_component.set_hardware_model_text_sensor(sens)) | ||||
|     if firwareversion_config := config.get(CONF_HARDWARE_VERSION): | ||||
|         sens = await text_sensor.new_text_sensor(firwareversion_config) | ||||
|         cg.add(mr24hpc1_component.set_firware_version_text_sensor(sens)) | ||||
|     if keepaway_config := config.get(CONF_KEEP_AWAY): | ||||
|         sens = await text_sensor.new_text_sensor(keepaway_config) | ||||
|         cg.add(mr24hpc1_component.set_keep_away_text_sensor(sens)) | ||||
|     if motionstatus_config := config.get(CONF_MOTION_STATUS): | ||||
|         sens = await text_sensor.new_text_sensor(motionstatus_config) | ||||
|         cg.add(mr24hpc1_component.set_motion_status_text_sensor(sens)) | ||||
|     if custommodeend_config := config.get(CONF_CUSTOM_MODE_END): | ||||
|         sens = await text_sensor.new_text_sensor(custommodeend_config) | ||||
|         cg.add(mr24hpc1_component.set_custom_mode_end_text_sensor(sens)) | ||||
							
								
								
									
										92
									
								
								tests/components/seeed_mr24hpc1/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								tests/components/seeed_mr24hpc1/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | ||||
| uart: | ||||
|   - id: seeed_mr24hpc1_uart | ||||
|     tx_pin: ${uart_tx_pin} | ||||
|     rx_pin: ${uart_rx_pin} | ||||
|     baud_rate: 115200 | ||||
|     parity: NONE | ||||
|     stop_bits: 1 | ||||
|  | ||||
| seeed_mr24hpc1: | ||||
|   id: my_seeed_mr24hpc1 | ||||
|   uart_id: seeed_mr24hpc1_uart | ||||
|  | ||||
| sensor: | ||||
|   - platform: seeed_mr24hpc1 | ||||
|     custom_presence_of_detection: | ||||
|       name: "Static Distance" | ||||
|     movement_signs: | ||||
|       name: "Body Movement Parameter" | ||||
|     custom_motion_distance: | ||||
|       name: "Motion Distance" | ||||
|     custom_spatial_static_value: | ||||
|       name: "Existence Energy" | ||||
|     custom_spatial_motion_value: | ||||
|       name: "Motion Energy" | ||||
|     custom_motion_speed: | ||||
|       name: "Motion Speed" | ||||
|     custom_mode_num: | ||||
|       name: "Current Custom Mode" | ||||
|  | ||||
| binary_sensor: | ||||
|   - platform: seeed_mr24hpc1 | ||||
|     has_target: | ||||
|       name: "Presence Information" | ||||
|  | ||||
| switch: | ||||
|   - platform: seeed_mr24hpc1 | ||||
|     underlying_open_function: | ||||
|       name: Underlying Open Function Info Output Switch | ||||
|  | ||||
| text_sensor: | ||||
|   - platform: seeed_mr24hpc1 | ||||
|     heart_beat: | ||||
|       name: "Heartbeat" | ||||
|     product_model: | ||||
|       name: "Product Model" | ||||
|     product_id: | ||||
|       name: "Product ID" | ||||
|     hardware_model: | ||||
|       name: "Hardware Model" | ||||
|     hardware_version: | ||||
|       name: "Hardware Version" | ||||
|     keep_away: | ||||
|       name: "Active Reporting Of Proximity" | ||||
|     motion_status: | ||||
|       name: "Motion Information" | ||||
|     custom_mode_end: | ||||
|       name: "Custom Mode Status" | ||||
|  | ||||
| number: | ||||
|   - platform: seeed_mr24hpc1 | ||||
|     sensitivity: | ||||
|       name: "Sensitivity" | ||||
|     custom_mode: | ||||
|       name: "Custom Mode" | ||||
|     existence_threshold: | ||||
|       name: "Existence Energy Threshold" | ||||
|     motion_threshold: | ||||
|       name: "Motion Energy Threshold" | ||||
|     motion_trigger: | ||||
|       name: "Motion Trigger Time" | ||||
|     motion_to_rest: | ||||
|       name: "Motion To Rest Time" | ||||
|     custom_unman_time: | ||||
|       name: "Time For Entering No Person State (Underlying Open Function)" | ||||
|  | ||||
| select: | ||||
|   - platform: seeed_mr24hpc1 | ||||
|     scene_mode: | ||||
|       name: "Scene" | ||||
|     unman_time: | ||||
|       name: "Time For Entering No Person State (Standard Function)" | ||||
|     existence_boundary: | ||||
|       name: "Existence Boundary" | ||||
|     motion_boundary: | ||||
|       name: "Motion Boundary" | ||||
|  | ||||
| button: | ||||
|   - platform: seeed_mr24hpc1 | ||||
|     restart: | ||||
|       name: "Module Restart" | ||||
|     custom_set_end: | ||||
|       name: "End Of Custom Mode Settings" | ||||
							
								
								
									
										5
									
								
								tests/components/seeed_mr24hpc1/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/seeed_mr24hpc1/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| substitutions: | ||||
|   uart_tx_pin: GPIO5 | ||||
|   uart_rx_pin: GPIO4 | ||||
|  | ||||
| <<: !include common.yaml | ||||
							
								
								
									
										5
									
								
								tests/components/seeed_mr24hpc1/test.esp32-c3.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/seeed_mr24hpc1/test.esp32-c3.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| substitutions: | ||||
|   uart_tx_pin: GPIO5 | ||||
|   uart_rx_pin: GPIO4 | ||||
|  | ||||
| <<: !include common.yaml | ||||
		Reference in New Issue
	
	Block a user