mirror of
https://github.com/esphome/esphome.git
synced 2024-11-22 06:58:11 +01:00
Add support for AT581x component (#6297)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
2345e7606a
commit
952ccf554b
14 changed files with 839 additions and 0 deletions
|
@ -42,6 +42,7 @@ esphome/components/as5600/* @ammmze
|
||||||
esphome/components/as5600/sensor/* @ammmze
|
esphome/components/as5600/sensor/* @ammmze
|
||||||
esphome/components/as7341/* @mrgnr
|
esphome/components/as7341/* @mrgnr
|
||||||
esphome/components/async_tcp/* @OttoWinter
|
esphome/components/async_tcp/* @OttoWinter
|
||||||
|
esphome/components/at581x/* @X-Ryl669
|
||||||
esphome/components/atc_mithermometer/* @ahpohl
|
esphome/components/atc_mithermometer/* @ahpohl
|
||||||
esphome/components/atm90e26/* @danieltwagner
|
esphome/components/atm90e26/* @danieltwagner
|
||||||
esphome/components/b_parasite/* @rbaron
|
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"
|
Loading…
Reference in a new issue