mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 06:33:51 +00:00 
			
		
		
		
	Add support for AT581x component (#6297)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -42,6 +42,7 @@ esphome/components/as5600/* @ammmze | ||||
| esphome/components/as5600/sensor/* @ammmze | ||||
| esphome/components/as7341/* @mrgnr | ||||
| esphome/components/async_tcp/* @OttoWinter | ||||
| esphome/components/at581x/* @X-Ryl669 | ||||
| esphome/components/atc_mithermometer/* @ahpohl | ||||
| esphome/components/atm90e26/* @danieltwagner | ||||
| esphome/components/b_parasite/* @rbaron | ||||
|   | ||||
							
								
								
									
										224
									
								
								esphome/components/at581x/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								esphome/components/at581x/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,224 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome import automation, core | ||||
| from esphome.components import i2c | ||||
| from esphome.automation import maybe_simple_id | ||||
| from esphome.const import ( | ||||
|     CONF_ID, | ||||
|     CONF_FREQUENCY, | ||||
| ) | ||||
|  | ||||
|  | ||||
| CODEOWNERS = ["@X-Ryl669"] | ||||
| DEPENDENCIES = ["i2c"] | ||||
| MULTI_CONF = True | ||||
|  | ||||
|  | ||||
| at581x_ns = cg.esphome_ns.namespace("at581x") | ||||
| AT581XComponent = at581x_ns.class_("AT581XComponent", cg.Component, i2c.I2CDevice) | ||||
|  | ||||
|  | ||||
| CONF_AT581X_ID = "at581x_id" | ||||
|  | ||||
|  | ||||
| CONF_SENSING_DISTANCE = "sensing_distance" | ||||
| CONF_SENSITIVITY = "sensitivity" | ||||
| CONF_POWERON_SELFCHECK_TIME = "poweron_selfcheck_time" | ||||
| CONF_PROTECT_TIME = "protect_time" | ||||
| CONF_TRIGGER_BASE = "trigger_base" | ||||
| CONF_TRIGGER_KEEP = "trigger_keep" | ||||
| CONF_STAGE_GAIN = "stage_gain" | ||||
| CONF_POWER_CONSUMPTION = "power_consumption" | ||||
| CONF_HW_FRONTEND_RESET = "hw_frontend_reset" | ||||
|  | ||||
| RADAR_ALLOWED_FREQ = [ | ||||
|     5696e6, | ||||
|     5715e6, | ||||
|     5730e6, | ||||
|     5748e6, | ||||
|     5765e6, | ||||
|     5784e6, | ||||
|     5800e6, | ||||
|     5819e6, | ||||
|     5836e6, | ||||
|     5851e6, | ||||
|     5869e6, | ||||
|     5888e6, | ||||
| ] | ||||
| RADAR_ALLOWED_CUR_CONSUMPTION = [ | ||||
|     48e-6, | ||||
|     56e-6, | ||||
|     63e-6, | ||||
|     70e-6, | ||||
|     77e-6, | ||||
|     91e-6, | ||||
|     105e-6, | ||||
|     115e-6, | ||||
|     40e-6, | ||||
|     44e-6, | ||||
|     47e-6, | ||||
|     51e-6, | ||||
|     54e-6, | ||||
|     61e-6, | ||||
|     68e-6, | ||||
|     78e-6, | ||||
| ] | ||||
|  | ||||
| CONFIG_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.GenerateID(): cv.declare_id(AT581XComponent), | ||||
|     } | ||||
| ) | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     CONFIG_SCHEMA.extend(i2c.i2c_device_schema(0x28)).extend(cv.COMPONENT_SCHEMA) | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await cg.register_component(var, config) | ||||
|     await i2c.register_i2c_device(var, config) | ||||
|  | ||||
|  | ||||
| # Actions | ||||
| AT581XResetAction = at581x_ns.class_("AT581XResetAction", automation.Action) | ||||
| AT581XSettingsAction = at581x_ns.class_("AT581XSettingsAction", automation.Action) | ||||
|  | ||||
|  | ||||
| @automation.register_action( | ||||
|     "at581x.reset", | ||||
|     AT581XResetAction, | ||||
|     maybe_simple_id( | ||||
|         { | ||||
|             cv.Required(CONF_ID): cv.use_id(AT581XComponent), | ||||
|         } | ||||
|     ), | ||||
| ) | ||||
| async def at581x_reset_to_code(config, action_id, template_arg, args): | ||||
|     var = cg.new_Pvariable(action_id, template_arg) | ||||
|     await cg.register_parented(var, config[CONF_ID]) | ||||
|  | ||||
|     return var | ||||
|  | ||||
|  | ||||
| RADAR_SETTINGS_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.Required(CONF_ID): cv.use_id(AT581XComponent), | ||||
|         cv.Optional(CONF_HW_FRONTEND_RESET): cv.templatable(cv.boolean), | ||||
|         cv.Optional(CONF_FREQUENCY, default="5800MHz"): cv.templatable( | ||||
|             cv.All(cv.frequency, cv.one_of(*RADAR_ALLOWED_FREQ)) | ||||
|         ), | ||||
|         cv.Optional(CONF_SENSING_DISTANCE, default=823): cv.templatable( | ||||
|             cv.int_range(min=0, max=1023) | ||||
|         ), | ||||
|         cv.Optional(CONF_POWERON_SELFCHECK_TIME, default="2000ms"): cv.templatable( | ||||
|             cv.All( | ||||
|                 cv.positive_time_period_milliseconds, | ||||
|                 cv.Range(max=core.TimePeriod(milliseconds=65535)), | ||||
|             ) | ||||
|         ), | ||||
|         cv.Optional(CONF_POWER_CONSUMPTION, default="70uA"): cv.templatable( | ||||
|             cv.All(cv.current, cv.one_of(*RADAR_ALLOWED_CUR_CONSUMPTION)) | ||||
|         ), | ||||
|         cv.Optional(CONF_PROTECT_TIME, default="1000ms"): cv.templatable( | ||||
|             cv.All( | ||||
|                 cv.positive_time_period_milliseconds, | ||||
|                 cv.Range( | ||||
|                     min=core.TimePeriod(milliseconds=1), | ||||
|                     max=core.TimePeriod(milliseconds=65535), | ||||
|                 ), | ||||
|             ) | ||||
|         ), | ||||
|         cv.Optional(CONF_TRIGGER_BASE, default="500ms"): cv.templatable( | ||||
|             cv.All( | ||||
|                 cv.positive_time_period_milliseconds, | ||||
|                 cv.Range( | ||||
|                     min=core.TimePeriod(milliseconds=1), | ||||
|                     max=core.TimePeriod(milliseconds=65535), | ||||
|                 ), | ||||
|             ) | ||||
|         ), | ||||
|         cv.Optional(CONF_TRIGGER_KEEP, default="1500ms"): cv.templatable( | ||||
|             cv.All( | ||||
|                 cv.positive_time_period_milliseconds, | ||||
|                 cv.Range( | ||||
|                     min=core.TimePeriod(milliseconds=1), | ||||
|                     max=core.TimePeriod(milliseconds=65535), | ||||
|                 ), | ||||
|             ) | ||||
|         ), | ||||
|         cv.Optional(CONF_STAGE_GAIN, default=3): cv.templatable( | ||||
|             cv.int_range(min=0, max=12) | ||||
|         ), | ||||
|     } | ||||
| ).add_extra( | ||||
|     cv.has_at_least_one_key( | ||||
|         CONF_HW_FRONTEND_RESET, | ||||
|         CONF_FREQUENCY, | ||||
|         CONF_SENSING_DISTANCE, | ||||
|     ) | ||||
| ) | ||||
|  | ||||
|  | ||||
| @automation.register_action( | ||||
|     "at581x.settings", | ||||
|     AT581XSettingsAction, | ||||
|     RADAR_SETTINGS_SCHEMA, | ||||
| ) | ||||
| async def at581x_settings_to_code(config, action_id, template_arg, args): | ||||
|     var = cg.new_Pvariable(action_id, template_arg) | ||||
|     await cg.register_parented(var, config[CONF_ID]) | ||||
|  | ||||
|     # Radar configuration | ||||
|     if frontend_reset := config.get(CONF_HW_FRONTEND_RESET): | ||||
|         template_ = await cg.templatable(frontend_reset, args, int) | ||||
|         cg.add(var.set_hw_frontend_reset(template_)) | ||||
|  | ||||
|     if freq := config.get(CONF_FREQUENCY): | ||||
|         template_ = await cg.templatable(freq, args, float) | ||||
|         template_ = int(template_ / 1000000) | ||||
|         cg.add(var.set_frequency(template_)) | ||||
|  | ||||
|     if sens_dist := config.get(CONF_SENSING_DISTANCE): | ||||
|         template_ = await cg.templatable(sens_dist, args, int) | ||||
|         cg.add(var.set_sensing_distance(template_)) | ||||
|  | ||||
|     if selfcheck := config.get(CONF_POWERON_SELFCHECK_TIME): | ||||
|         template_ = await cg.templatable(selfcheck, args, float) | ||||
|         if isinstance(template_, cv.TimePeriod): | ||||
|             template_ = template_.total_milliseconds | ||||
|         template_ = int(template_) | ||||
|         cg.add(var.set_poweron_selfcheck_time(template_)) | ||||
|  | ||||
|     if protect := config.get(CONF_PROTECT_TIME): | ||||
|         template_ = await cg.templatable(protect, args, float) | ||||
|         if isinstance(template_, cv.TimePeriod): | ||||
|             template_ = template_.total_milliseconds | ||||
|         template_ = int(template_) | ||||
|         cg.add(var.set_protect_time(template_)) | ||||
|  | ||||
|     if trig_base := config.get(CONF_TRIGGER_BASE): | ||||
|         template_ = await cg.templatable(trig_base, args, float) | ||||
|         if isinstance(template_, cv.TimePeriod): | ||||
|             template_ = template_.total_milliseconds | ||||
|         template_ = int(template_) | ||||
|         cg.add(var.set_trigger_base(template_)) | ||||
|  | ||||
|     if trig_keep := config.get(CONF_TRIGGER_KEEP): | ||||
|         template_ = await cg.templatable(trig_keep, args, float) | ||||
|         if isinstance(template_, cv.TimePeriod): | ||||
|             template_ = template_.total_milliseconds | ||||
|         template_ = int(template_) | ||||
|         cg.add(var.set_trigger_keep(template_)) | ||||
|  | ||||
|     if stage_gain := config.get(CONF_STAGE_GAIN): | ||||
|         template_ = await cg.templatable(stage_gain, args, int) | ||||
|         cg.add(var.set_stage_gain(template_)) | ||||
|  | ||||
|     if power := config.get(CONF_POWER_CONSUMPTION): | ||||
|         template_ = await cg.templatable(power, args, float) | ||||
|         template_ = int(template_ * 1000000) | ||||
|         cg.add(var.set_power_consumption(template_)) | ||||
|  | ||||
|     return var | ||||
							
								
								
									
										195
									
								
								esphome/components/at581x/at581x.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								esphome/components/at581x/at581x.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,195 @@ | ||||
| #include "at581x.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| /* Select gain for AT581X (3dB per step for level1, 6dB per step for level 2), high value = small gain. (p12) */ | ||||
| const uint8_t GAIN_ADDR_TABLE[] = {0x5c, 0x63}; | ||||
| const uint8_t GAIN5C_TABLE[] = {0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, 0xb8, 0xc8}; | ||||
| const uint8_t GAIN63_TABLE[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; | ||||
| const uint8_t GAIN61_VALUE = 0xCA;  // 0xC0 | 0x02 (freq present) | 0x08 (gain present) | ||||
|  | ||||
| /*!< Power consumption configuration table (p12). */ | ||||
| const uint8_t POWER_TABLE[] = {48, 56, 63, 70, 77, 91, 105, 115, 40, 44, 47, 51, 54, 61, 68, 78}; | ||||
| const uint8_t POWER67_TABLE[] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}; | ||||
| const uint8_t POWER68_TABLE[] = {0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, | ||||
|                                  24,  24,  24,  24,  24,  24,  24,  24};  // See Page 12, shift by 3 bits | ||||
|  | ||||
| /*!< Frequency Configuration table (p14/15 of datasheet). */ | ||||
| const uint8_t FREQ_ADDR = 0x61; | ||||
| const uint16_t FREQ_TABLE[] = {5696, 5715, 5730, 5748, 5765, 5784, 5800, 5819, 5836, 5851, 5869, 5888}; | ||||
| const uint8_t FREQ5F_TABLE[] = {0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x40, 0x41, 0x42, 0x43}; | ||||
| const uint8_t FREQ60_TABLE[] = {0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0x9e}; | ||||
|  | ||||
| /*!< Value for RF and analog modules switch (p10). */ | ||||
| const uint8_t RF_OFF_TABLE[] = {0x46, 0xaa, 0x50}; | ||||
| const uint8_t RF_ON_TABLE[] = {0x45, 0x55, 0xA0}; | ||||
| const uint8_t RF_REG_ADDR[] = {0x5d, 0x62, 0x51}; | ||||
|  | ||||
| /*!< Registers of Lighting delay time. Unit: ms, min 2s (p8) */ | ||||
| const uint8_t HIGH_LEVEL_DELAY_CONTROL_ADDR = 0x41; /*!< Time_flag_out_ctrl 0x01 */ | ||||
| const uint8_t HIGH_LEVEL_DELAY_VALUE_ADDR = 0x42;   /*!< Time_flag_out_1 Bit<7:0> */ | ||||
|  | ||||
| const uint8_t RESET_ADDR = 0x00; | ||||
|  | ||||
| /*!< Sensing distance address */ | ||||
| const uint8_t SIGNAL_DETECTION_THRESHOLD_ADDR_LO = 0x10; | ||||
| const uint8_t SIGNAL_DETECTION_THRESHOLD_ADDR_HI = 0x11; | ||||
|  | ||||
| /*!< Bit field value for power registers */ | ||||
| const uint8_t POWER_THRESHOLD_ADDR_HI = 0x68; | ||||
| const uint8_t POWER_THRESHOLD_ADDR_LO = 0x67; | ||||
| const uint8_t PWR_WORK_TIME_EN = 8;     // Reg 0x67 | ||||
| const uint8_t PWR_BURST_TIME_EN = 32;   // Reg 0x68 | ||||
| const uint8_t PWR_THRESH_EN = 64;       // Reg 0x68 | ||||
| const uint8_t PWR_THRESH_VAL_EN = 128;  // Reg 0x67 | ||||
|  | ||||
| /*!< Times */ | ||||
| const uint8_t TRIGGER_BASE_TIME_ADDR = 0x3D;  // 4 bytes, so up to 0x40 | ||||
| const uint8_t PROTECT_TIME_ADDR = 0x4E;       // 2 bytes, up to 0x4F | ||||
| const uint8_t TRIGGER_KEEP_TIME_ADDR = 0x42;  // 4 bytes, so up to 0x45 | ||||
| const uint8_t TIME41_VALUE = 1; | ||||
| const uint8_t SELF_CHECK_TIME_ADDR = 0x38;  // 2 bytes, up to 0x39 | ||||
|  | ||||
| namespace esphome { | ||||
| namespace at581x { | ||||
|  | ||||
| static const char *const TAG = "at581x"; | ||||
|  | ||||
| bool AT581XComponent::i2c_write_reg(uint8_t addr, uint8_t data) { | ||||
|   return this->write_register(addr, &data, 1) == esphome::i2c::NO_ERROR; | ||||
| } | ||||
| bool AT581XComponent::i2c_write_reg(uint8_t addr, uint32_t data) { | ||||
|   return this->i2c_write_reg(addr + 0, uint8_t(data & 0xFF)) && | ||||
|          this->i2c_write_reg(addr + 1, uint8_t((data >> 8) & 0xFF)) && | ||||
|          this->i2c_write_reg(addr + 2, uint8_t((data >> 16) & 0xFF)) && | ||||
|          this->i2c_write_reg(addr + 3, uint8_t((data >> 24) & 0xFF)); | ||||
| } | ||||
| bool AT581XComponent::i2c_write_reg(uint8_t addr, uint16_t data) { | ||||
|   return this->i2c_write_reg(addr, uint8_t(data & 0xFF)) && this->i2c_write_reg(addr + 1, uint8_t((data >> 8) & 0xFF)); | ||||
| } | ||||
|  | ||||
| bool AT581XComponent::i2c_read_reg(uint8_t addr, uint8_t &data) { | ||||
|   return this->read_register(addr, &data, 1) == esphome::i2c::NO_ERROR; | ||||
| } | ||||
|  | ||||
| void AT581XComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up AT581X..."); } | ||||
| void AT581XComponent::dump_config() { LOG_I2C_DEVICE(this); } | ||||
| #define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0])) | ||||
| bool AT581XComponent::i2c_write_config() { | ||||
|   ESP_LOGCONFIG(TAG, "Writing new config for AT581X..."); | ||||
|   ESP_LOGCONFIG(TAG, "Frequency: %dMHz", this->freq_); | ||||
|   ESP_LOGCONFIG(TAG, "Sensing distance: %d", this->delta_); | ||||
|   ESP_LOGCONFIG(TAG, "Power: %dµA", this->power_); | ||||
|   ESP_LOGCONFIG(TAG, "Gain: %d", this->gain_); | ||||
|   ESP_LOGCONFIG(TAG, "Trigger base time: %dms", this->trigger_base_time_ms_); | ||||
|   ESP_LOGCONFIG(TAG, "Trigger keep time: %dms", this->trigger_keep_time_ms_); | ||||
|   ESP_LOGCONFIG(TAG, "Protect time: %dms", this->protect_time_ms_); | ||||
|   ESP_LOGCONFIG(TAG, "Self check time: %dms", this->self_check_time_ms_); | ||||
|  | ||||
|   // Set frequency point | ||||
|   if (!this->i2c_write_reg(FREQ_ADDR, GAIN61_VALUE)) { | ||||
|     ESP_LOGE(TAG, "Failed to write AT581X Freq mode"); | ||||
|     return false; | ||||
|   } | ||||
|   // Find the current frequency from the table to know what value to write | ||||
|   for (size_t i = 0; i < ARRAY_SIZE(FREQ_TABLE) + 1; i++) { | ||||
|     if (i == ARRAY_SIZE(FREQ_TABLE)) { | ||||
|       ESP_LOGE(TAG, "Set frequency not found"); | ||||
|       return false; | ||||
|     } | ||||
|     if (FREQ_TABLE[i] == this->freq_) { | ||||
|       if (!this->i2c_write_reg(0x5F, FREQ5F_TABLE[i]) || !this->i2c_write_reg(0x60, FREQ60_TABLE[i])) { | ||||
|         ESP_LOGE(TAG, "Failed to write AT581X Freq value"); | ||||
|         return false; | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Set distance | ||||
|   if (!this->i2c_write_reg(SIGNAL_DETECTION_THRESHOLD_ADDR_LO, (uint8_t) (this->delta_ & 0xFF)) || | ||||
|       !this->i2c_write_reg(SIGNAL_DETECTION_THRESHOLD_ADDR_HI, (uint8_t) (this->delta_ >> 8))) { | ||||
|     ESP_LOGE(TAG, "Failed to write AT581X sensing distance low"); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   // Set power setting | ||||
|   uint8_t pwr67 = PWR_THRESH_VAL_EN | PWR_WORK_TIME_EN, pwr68 = PWR_BURST_TIME_EN | PWR_THRESH_EN; | ||||
|   for (size_t i = 0; i < ARRAY_SIZE(POWER_TABLE) + 1; i++) { | ||||
|     if (i == ARRAY_SIZE(POWER_TABLE)) { | ||||
|       ESP_LOGE(TAG, "Set power not found"); | ||||
|       return false; | ||||
|     } | ||||
|     if (POWER_TABLE[i] == this->power_) { | ||||
|       pwr67 |= POWER67_TABLE[i]; | ||||
|       pwr68 |= POWER68_TABLE[i];  // See Page 12 | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (!this->i2c_write_reg(POWER_THRESHOLD_ADDR_LO, pwr67) || !this->i2c_write_reg(POWER_THRESHOLD_ADDR_HI, pwr68)) { | ||||
|     ESP_LOGE(TAG, "Failed to write AT581X power registers"); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   // Set gain | ||||
|   if (!this->i2c_write_reg(GAIN_ADDR_TABLE[0], GAIN5C_TABLE[this->gain_]) || | ||||
|       !this->i2c_write_reg(GAIN_ADDR_TABLE[1], GAIN63_TABLE[this->gain_ >> 1])) { | ||||
|     ESP_LOGE(TAG, "Failed to write AT581X gain registers"); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   // Set times | ||||
|   if (!this->i2c_write_reg(TRIGGER_BASE_TIME_ADDR, (uint32_t) this->trigger_base_time_ms_)) { | ||||
|     ESP_LOGE(TAG, "Failed to write AT581X trigger base time registers"); | ||||
|     return false; | ||||
|   } | ||||
|   if (!this->i2c_write_reg(TRIGGER_KEEP_TIME_ADDR, (uint32_t) this->trigger_keep_time_ms_)) { | ||||
|     ESP_LOGE(TAG, "Failed to write AT581X trigger keep time registers"); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   if (!this->i2c_write_reg(PROTECT_TIME_ADDR, (uint16_t) this->protect_time_ms_)) { | ||||
|     ESP_LOGE(TAG, "Failed to write AT581X protect time registers"); | ||||
|     return false; | ||||
|   } | ||||
|   if (!this->i2c_write_reg(SELF_CHECK_TIME_ADDR, (uint16_t) this->self_check_time_ms_)) { | ||||
|     ESP_LOGE(TAG, "Failed to write AT581X self check time registers"); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   if (!this->i2c_write_reg(0x41, TIME41_VALUE)) { | ||||
|     ESP_LOGE(TAG, "Failed to enable AT581X time registers"); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   // Don't know why it's required in other code, it's not in datasheet | ||||
|   if (!this->i2c_write_reg(0x55, (uint8_t) 0x04)) { | ||||
|     ESP_LOGE(TAG, "Failed to enable AT581X"); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   // Ok, config is written, let's reset the chip so it's using the new config | ||||
|   return this->reset_hardware_frontend(); | ||||
| } | ||||
|  | ||||
| // float AT581XComponent::get_setup_priority() const { return 0; } | ||||
| bool AT581XComponent::reset_hardware_frontend() { | ||||
|   if (!this->i2c_write_reg(RESET_ADDR, (uint8_t) 0) || !this->i2c_write_reg(RESET_ADDR, (uint8_t) 1)) { | ||||
|     ESP_LOGE(TAG, "Failed to reset AT581X hardware frontend"); | ||||
|     return false; | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| void AT581XComponent::set_rf_mode(bool enable) { | ||||
|   const uint8_t *p = enable ? &RF_ON_TABLE[0] : &RF_OFF_TABLE[0]; | ||||
|   for (size_t i = 0; i < ARRAY_SIZE(RF_REG_ADDR); i++) { | ||||
|     if (!this->i2c_write_reg(RF_REG_ADDR[i], p[i])) { | ||||
|       ESP_LOGE(TAG, "Failed to write AT581X RF mode"); | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| }  // namespace at581x | ||||
| }  // namespace esphome | ||||
							
								
								
									
										62
									
								
								esphome/components/at581x/at581x.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								esphome/components/at581x/at581x.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <utility> | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/hal.h" | ||||
| #include "esphome/core/defines.h" | ||||
| #ifdef USE_SWITCH | ||||
| #include "esphome/components/switch/switch.h" | ||||
| #endif | ||||
| #include "esphome/components/i2c/i2c.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace at581x { | ||||
|  | ||||
| class AT581XComponent : public Component, public i2c::I2CDevice { | ||||
| #ifdef USE_SWITCH | ||||
|  protected: | ||||
|   switch_::Switch *rf_power_switch_{nullptr}; | ||||
|  | ||||
|  public: | ||||
|   void set_rf_power_switch(switch_::Switch *s) { | ||||
|     this->rf_power_switch_ = s; | ||||
|     s->turn_on(); | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   void setup() override; | ||||
|   void dump_config() override; | ||||
|   //  float get_setup_priority() const override; | ||||
|  | ||||
|   void set_sensing_distance(int distance) { this->delta_ = 1023 - distance; } | ||||
|  | ||||
|   void set_rf_mode(bool enabled); | ||||
|   void set_frequency(int frequency) { this->freq_ = frequency; } | ||||
|   void set_poweron_selfcheck_time(int value) { this->self_check_time_ms_ = value; } | ||||
|   void set_protect_time(int value) { this->protect_time_ms_ = value; } | ||||
|   void set_trigger_base(int value) { this->trigger_base_time_ms_ = value; } | ||||
|   void set_trigger_keep(int value) { this->trigger_keep_time_ms_ = value; } | ||||
|   void set_stage_gain(int value) { this->gain_ = value; } | ||||
|   void set_power_consumption(int value) { this->power_ = value; } | ||||
|  | ||||
|   bool i2c_write_config(); | ||||
|   bool reset_hardware_frontend(); | ||||
|   bool i2c_write_reg(uint8_t addr, uint8_t data); | ||||
|   bool i2c_write_reg(uint8_t addr, uint32_t data); | ||||
|   bool i2c_write_reg(uint8_t addr, uint16_t data); | ||||
|   bool i2c_read_reg(uint8_t addr, uint8_t &data); | ||||
|  | ||||
|  protected: | ||||
|   int freq_; | ||||
|   int self_check_time_ms_;   /*!< Power-on self-test time, range: 0 ~ 65536 ms */ | ||||
|   int protect_time_ms_;      /*!< Protection time, recommended 1000 ms */ | ||||
|   int trigger_base_time_ms_; /*!< Default: 500 ms */ | ||||
|   int trigger_keep_time_ms_; /*!< Total trig time = TRIGGER_BASE_TIME + DEF_TRIGGER_KEEP_TIME, minimum: 1 */ | ||||
|   int delta_;                /*!< Delta value: 0 ~ 1023, the larger the value, the shorter the distance */ | ||||
|   int gain_;                 /*!< Default: 9dB */ | ||||
|   int power_;                /*!< In µA */ | ||||
| }; | ||||
|  | ||||
| }  // namespace at581x | ||||
| }  // namespace esphome | ||||
							
								
								
									
										71
									
								
								esphome/components/at581x/automation.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								esphome/components/at581x/automation.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/automation.h" | ||||
| #include "esphome/core/helpers.h" | ||||
|  | ||||
| #include "at581x.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace at581x { | ||||
|  | ||||
| template<typename... Ts> class AT581XResetAction : public Action<Ts...>, public Parented<AT581XComponent> { | ||||
|  public: | ||||
|   void play(Ts... x) { this->parent_->reset_hardware_frontend(); } | ||||
| }; | ||||
|  | ||||
| template<typename... Ts> class AT581XSettingsAction : public Action<Ts...>, public Parented<AT581XComponent> { | ||||
|  public: | ||||
|   TEMPLATABLE_VALUE(int8_t, hw_frontend_reset) | ||||
|   TEMPLATABLE_VALUE(int, frequency) | ||||
|   TEMPLATABLE_VALUE(int, sensing_distance) | ||||
|   TEMPLATABLE_VALUE(int, poweron_selfcheck_time) | ||||
|   TEMPLATABLE_VALUE(int, power_consumption) | ||||
|   TEMPLATABLE_VALUE(int, protect_time) | ||||
|   TEMPLATABLE_VALUE(int, trigger_base) | ||||
|   TEMPLATABLE_VALUE(int, trigger_keep) | ||||
|   TEMPLATABLE_VALUE(int, stage_gain) | ||||
|  | ||||
|   void play(Ts... x) { | ||||
|     if (this->frequency_.has_value()) { | ||||
|       int v = this->frequency_.value(x...); | ||||
|       this->parent_->set_frequency(v); | ||||
|     } | ||||
|     if (this->sensing_distance_.has_value()) { | ||||
|       int v = this->sensing_distance_.value(x...); | ||||
|       this->parent_->set_sensing_distance(v); | ||||
|     } | ||||
|     if (this->poweron_selfcheck_time_.has_value()) { | ||||
|       int v = this->poweron_selfcheck_time_.value(x...); | ||||
|       this->parent_->set_poweron_selfcheck_time(v); | ||||
|     } | ||||
|     if (this->power_consumption_.has_value()) { | ||||
|       int v = this->power_consumption_.value(x...); | ||||
|       this->parent_->set_power_consumption(v); | ||||
|     } | ||||
|     if (this->protect_time_.has_value()) { | ||||
|       int v = this->protect_time_.value(x...); | ||||
|       this->parent_->set_protect_time(v); | ||||
|     } | ||||
|     if (this->trigger_base_.has_value()) { | ||||
|       int v = this->trigger_base_.value(x...); | ||||
|       this->parent_->set_trigger_base(v); | ||||
|     } | ||||
|     if (this->trigger_keep_.has_value()) { | ||||
|       int v = this->trigger_keep_.value(x...); | ||||
|       this->parent_->set_trigger_keep(v); | ||||
|     } | ||||
|     if (this->stage_gain_.has_value()) { | ||||
|       int v = this->stage_gain_.value(x...); | ||||
|       this->parent_->set_stage_gain(v); | ||||
|     } | ||||
|  | ||||
|     // This actually perform all the modification on the system | ||||
|     this->parent_->i2c_write_config(); | ||||
|  | ||||
|     if (this->hw_frontend_reset_.has_value() && this->hw_frontend_reset_.value(x...) == true) { | ||||
|       this->parent_->reset_hardware_frontend(); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| }  // namespace at581x | ||||
| }  // namespace esphome | ||||
							
								
								
									
										31
									
								
								esphome/components/at581x/switch/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								esphome/components/at581x/switch/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import switch | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     DEVICE_CLASS_SWITCH, | ||||
|     ICON_WIFI, | ||||
| ) | ||||
| from .. import CONF_AT581X_ID, AT581XComponent, at581x_ns | ||||
|  | ||||
| DEPENDENCIES = ["at581x"] | ||||
|  | ||||
| RFSwitch = at581x_ns.class_("RFSwitch", switch.Switch) | ||||
|  | ||||
| CONFIG_SCHEMA = switch.switch_schema( | ||||
|     RFSwitch, | ||||
|     device_class=DEVICE_CLASS_SWITCH, | ||||
|     icon=ICON_WIFI, | ||||
| ).extend( | ||||
|     cv.Schema( | ||||
|         { | ||||
|             cv.GenerateID(CONF_AT581X_ID): cv.use_id(AT581XComponent), | ||||
|         } | ||||
|     ) | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     at581x_component = await cg.get_variable(config[CONF_AT581X_ID]) | ||||
|     s = await switch.new_switch(config) | ||||
|     await cg.register_parented(s, config[CONF_AT581X_ID]) | ||||
|     cg.add(at581x_component.set_rf_power_switch(s)) | ||||
							
								
								
									
										12
									
								
								esphome/components/at581x/switch/rf_switch.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								esphome/components/at581x/switch/rf_switch.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| #include "rf_switch.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace at581x { | ||||
|  | ||||
| void RFSwitch::write_state(bool state) { | ||||
|   this->publish_state(state); | ||||
|   this->parent_->set_rf_mode(state); | ||||
| } | ||||
|  | ||||
| }  // namespace at581x | ||||
| }  // namespace esphome | ||||
							
								
								
									
										15
									
								
								esphome/components/at581x/switch/rf_switch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								esphome/components/at581x/switch/rf_switch.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/switch/switch.h" | ||||
| #include "../at581x.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace at581x { | ||||
|  | ||||
| class RFSwitch : public switch_::Switch, public Parented<AT581XComponent> { | ||||
|  protected: | ||||
|   void write_state(bool state) override; | ||||
| }; | ||||
|  | ||||
| }  // namespace at581x | ||||
| }  // namespace esphome | ||||
							
								
								
									
										38
									
								
								tests/components/at581x/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								tests/components/at581x/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| esphome: | ||||
|   on_boot: | ||||
|     then: | ||||
|       - at581x.settings: | ||||
|           id: "Waveradar" | ||||
|           hw_frontend_reset: false | ||||
|           frequency: 5800MHz | ||||
|           sensing_distance: 200 | ||||
|           poweron_selfcheck_time: 2s | ||||
|           protect_time: 1s | ||||
|           trigger_base: 500ms | ||||
|           trigger_keep: 10s | ||||
|           stage_gain: 3 | ||||
|           power_consumption: 70uA | ||||
|       - at581x.reset: | ||||
|           id: "Waveradar" | ||||
|  | ||||
| at581x: | ||||
|   id: "Waveradar" | ||||
|   i2c_id: i2c_bus | ||||
|  | ||||
| i2c: | ||||
|   sda: 8 | ||||
|   scl: 9 | ||||
|   scan: true | ||||
|   frequency: 100kHz | ||||
|   setup_priority: -100 | ||||
|   id: i2c_bus | ||||
|  | ||||
| binary_sensor: | ||||
|   - platform: gpio | ||||
|     pin: GPIO21 | ||||
|     name: "Radar motion" | ||||
|  | ||||
| switch: | ||||
|   - platform: at581x | ||||
|     at581x_id: "Waveradar" | ||||
|     name: "Enable Radar" | ||||
							
								
								
									
										38
									
								
								tests/components/at581x/test.esp32-c3.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								tests/components/at581x/test.esp32-c3.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| esphome: | ||||
|   on_boot: | ||||
|     then: | ||||
|       - at581x.settings: | ||||
|           id: "Waveradar" | ||||
|           hw_frontend_reset: false | ||||
|           frequency: 5800MHz | ||||
|           sensing_distance: 200 | ||||
|           poweron_selfcheck_time: 2s | ||||
|           protect_time: 1s | ||||
|           trigger_base: 500ms | ||||
|           trigger_keep: 10s | ||||
|           stage_gain: 3 | ||||
|           power_consumption: 70uA | ||||
|       - at581x.reset: | ||||
|           id: "Waveradar" | ||||
|  | ||||
| at581x: | ||||
|   id: "Waveradar" | ||||
|   i2c_id: i2c_bus | ||||
|  | ||||
| i2c: | ||||
|   sda: 8 | ||||
|   scl: 9 | ||||
|   scan: true | ||||
|   frequency: 100kHz | ||||
|   setup_priority: -100 | ||||
|   id: i2c_bus | ||||
|  | ||||
| binary_sensor: | ||||
|   - platform: gpio | ||||
|     pin: GPIO21 | ||||
|     name: "Radar motion" | ||||
|  | ||||
| switch: | ||||
|   - platform: at581x | ||||
|     at581x_id: "Waveradar" | ||||
|     name: "Enable Radar" | ||||
							
								
								
									
										38
									
								
								tests/components/at581x/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								tests/components/at581x/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| esphome: | ||||
|   on_boot: | ||||
|     then: | ||||
|       - at581x.settings: | ||||
|           id: "Waveradar" | ||||
|           hw_frontend_reset: false | ||||
|           frequency: 5800MHz | ||||
|           sensing_distance: 200 | ||||
|           poweron_selfcheck_time: 2s | ||||
|           protect_time: 1s | ||||
|           trigger_base: 500ms | ||||
|           trigger_keep: 10s | ||||
|           stage_gain: 3 | ||||
|           power_consumption: 70uA | ||||
|       - at581x.reset: | ||||
|           id: "Waveradar" | ||||
|  | ||||
| at581x: | ||||
|   id: "Waveradar" | ||||
|   i2c_id: i2c_bus | ||||
|  | ||||
| i2c: | ||||
|   sda: 14 | ||||
|   scl: 15 | ||||
|   scan: true | ||||
|   frequency: 100kHz | ||||
|   setup_priority: -100 | ||||
|   id: i2c_bus | ||||
|  | ||||
| binary_sensor: | ||||
|   - platform: gpio | ||||
|     pin: GPIO21 | ||||
|     name: "Radar motion" | ||||
|  | ||||
| switch: | ||||
|   - platform: at581x | ||||
|     at581x_id: "Waveradar" | ||||
|     name: "Enable Radar" | ||||
							
								
								
									
										38
									
								
								tests/components/at581x/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								tests/components/at581x/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| esphome: | ||||
|   on_boot: | ||||
|     then: | ||||
|       - at581x.settings: | ||||
|           id: "Waveradar" | ||||
|           hw_frontend_reset: false | ||||
|           frequency: 5800MHz | ||||
|           sensing_distance: 200 | ||||
|           poweron_selfcheck_time: 2s | ||||
|           protect_time: 1s | ||||
|           trigger_base: 500ms | ||||
|           trigger_keep: 10s | ||||
|           stage_gain: 3 | ||||
|           power_consumption: 70uA | ||||
|       - at581x.reset: | ||||
|           id: "Waveradar" | ||||
|  | ||||
| at581x: | ||||
|   id: "Waveradar" | ||||
|   i2c_id: i2c_bus | ||||
|  | ||||
| i2c: | ||||
|   sda: 14 | ||||
|   scl: 15 | ||||
|   scan: true | ||||
|   frequency: 100kHz | ||||
|   setup_priority: -100 | ||||
|   id: i2c_bus | ||||
|  | ||||
| binary_sensor: | ||||
|   - platform: gpio | ||||
|     pin: GPIO21 | ||||
|     name: "Radar motion" | ||||
|  | ||||
| switch: | ||||
|   - platform: at581x | ||||
|     at581x_id: "Waveradar" | ||||
|     name: "Enable Radar" | ||||
							
								
								
									
										38
									
								
								tests/components/at581x/test.esp8266.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								tests/components/at581x/test.esp8266.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| esphome: | ||||
|   on_boot: | ||||
|     then: | ||||
|       - at581x.settings: | ||||
|           id: "Waveradar" | ||||
|           hw_frontend_reset: false | ||||
|           frequency: 5800MHz | ||||
|           sensing_distance: 200 | ||||
|           poweron_selfcheck_time: 2s | ||||
|           protect_time: 1s | ||||
|           trigger_base: 500ms | ||||
|           trigger_keep: 10s | ||||
|           stage_gain: 3 | ||||
|           power_consumption: 70uA | ||||
|       - at581x.reset: | ||||
|           id: "Waveradar" | ||||
|  | ||||
| at581x: | ||||
|   id: "Waveradar" | ||||
|   i2c_id: i2c_bus | ||||
|  | ||||
| i2c: | ||||
|   sda: 14 | ||||
|   scl: 15 | ||||
|   scan: true | ||||
|   frequency: 100kHz | ||||
|   setup_priority: -100 | ||||
|   id: i2c_bus | ||||
|  | ||||
| binary_sensor: | ||||
|   - platform: gpio | ||||
|     pin: GPIO4 | ||||
|     name: "Radar motion" | ||||
|  | ||||
| switch: | ||||
|   - platform: at581x | ||||
|     at581x_id: "Waveradar" | ||||
|     name: "Enable Radar" | ||||
							
								
								
									
										38
									
								
								tests/components/at581x/test.rp2040.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								tests/components/at581x/test.rp2040.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| esphome: | ||||
|   on_boot: | ||||
|     then: | ||||
|       - at581x.settings: | ||||
|           id: "Waveradar" | ||||
|           hw_frontend_reset: false | ||||
|           frequency: 5800MHz | ||||
|           sensing_distance: 200 | ||||
|           poweron_selfcheck_time: 2s | ||||
|           protect_time: 1s | ||||
|           trigger_base: 500ms | ||||
|           trigger_keep: 10s | ||||
|           stage_gain: 3 | ||||
|           power_consumption: 70uA | ||||
|       - at581x.reset: | ||||
|           id: "Waveradar" | ||||
|  | ||||
| at581x: | ||||
|   id: "Waveradar" | ||||
|   i2c_id: i2c_bus | ||||
|  | ||||
| i2c: | ||||
|   sda: 8 | ||||
|   scl: 9 | ||||
|   scan: true | ||||
|   frequency: 100kHz | ||||
|   setup_priority: -100 | ||||
|   id: i2c_bus | ||||
|  | ||||
| binary_sensor: | ||||
|   - platform: gpio | ||||
|     pin: GPIO21 | ||||
|     name: "Radar motion" | ||||
|  | ||||
| switch: | ||||
|   - platform: at581x | ||||
|     at581x_id: "Waveradar" | ||||
|     name: "Enable Radar" | ||||
		Reference in New Issue
	
	Block a user