mirror of
https://github.com/esphome/esphome.git
synced 2024-12-22 13:34:54 +01:00
[Fingerprint_grow] Implements Sleep Mode feature (#6116)
This commit is contained in:
parent
247baa414a
commit
8850b959e9
5 changed files with 185 additions and 25 deletions
|
@ -118,7 +118,7 @@ esphome/components/ezo_pmp/* @carlos-sarmiento
|
|||
esphome/components/factory_reset/* @anatoly-savchenkov
|
||||
esphome/components/fastled_base/* @OttoWinter
|
||||
esphome/components/feedback/* @ianchi
|
||||
esphome/components/fingerprint_grow/* @OnFreund @loongyh
|
||||
esphome/components/fingerprint_grow/* @OnFreund @alexborro @loongyh
|
||||
esphome/components/fs3000/* @kahrendt
|
||||
esphome/components/ft5x06/* @clydebarrow
|
||||
esphome/components/ft63x6/* @gpambrozio
|
||||
|
|
|
@ -25,12 +25,14 @@ from esphome.const import (
|
|||
CONF_TRIGGER_ID,
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@OnFreund", "@loongyh"]
|
||||
CODEOWNERS = ["@OnFreund", "@loongyh", "@alexborro"]
|
||||
DEPENDENCIES = ["uart"]
|
||||
AUTO_LOAD = ["binary_sensor", "sensor"]
|
||||
MULTI_CONF = True
|
||||
|
||||
CONF_FINGERPRINT_GROW_ID = "fingerprint_grow_id"
|
||||
CONF_SENSOR_POWER_PIN = "sensor_power_pin"
|
||||
CONF_IDLE_PERIOD_TO_SLEEP = "idle_period_to_sleep"
|
||||
|
||||
fingerprint_grow_ns = cg.esphome_ns.namespace("fingerprint_grow")
|
||||
FingerprintGrowComponent = fingerprint_grow_ns.class_(
|
||||
|
@ -102,11 +104,26 @@ AURA_LED_COLORS = {
|
|||
}
|
||||
validate_aura_led_colors = cv.enum(AURA_LED_COLORS, upper=True)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
|
||||
def validate(config):
|
||||
if CONF_SENSOR_POWER_PIN in config and CONF_SENSING_PIN not in config:
|
||||
raise cv.Invalid("You cannot use the Sensor Power Pin without a Sensing Pin")
|
||||
if CONF_IDLE_PERIOD_TO_SLEEP in config and CONF_SENSOR_POWER_PIN not in config:
|
||||
raise cv.Invalid(
|
||||
"You cannot have an Idle Period to Sleep without a Sensor Power Pin"
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(FingerprintGrowComponent),
|
||||
cv.Optional(CONF_SENSING_PIN): pins.gpio_input_pin_schema,
|
||||
cv.Optional(CONF_SENSOR_POWER_PIN): pins.gpio_output_pin_schema,
|
||||
cv.Optional(
|
||||
CONF_IDLE_PERIOD_TO_SLEEP
|
||||
): cv.positive_time_period_milliseconds,
|
||||
cv.Optional(CONF_PASSWORD): cv.uint32_t,
|
||||
cv.Optional(CONF_NEW_PASSWORD): cv.uint32_t,
|
||||
cv.Optional(CONF_ON_FINGER_SCAN_START): automation.validate_automation(
|
||||
|
@ -168,7 +185,8 @@ CONFIG_SCHEMA = (
|
|||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("500ms"))
|
||||
.extend(uart.UART_DEVICE_SCHEMA)
|
||||
.extend(uart.UART_DEVICE_SCHEMA),
|
||||
validate,
|
||||
)
|
||||
|
||||
|
||||
|
@ -188,6 +206,14 @@ async def to_code(config):
|
|||
sensing_pin = await cg.gpio_pin_expression(config[CONF_SENSING_PIN])
|
||||
cg.add(var.set_sensing_pin(sensing_pin))
|
||||
|
||||
if CONF_SENSOR_POWER_PIN in config:
|
||||
sensor_power_pin = await cg.gpio_pin_expression(config[CONF_SENSOR_POWER_PIN])
|
||||
cg.add(var.set_sensor_power_pin(sensor_power_pin))
|
||||
|
||||
if CONF_IDLE_PERIOD_TO_SLEEP in config:
|
||||
idle_period_to_sleep_ms = config[CONF_IDLE_PERIOD_TO_SLEEP]
|
||||
cg.add(var.set_idle_period_to_sleep_ms(idle_period_to_sleep_ms))
|
||||
|
||||
for conf in config.get(CONF_ON_FINGER_SCAN_START, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
|
|
@ -16,9 +16,14 @@ void FingerprintGrowComponent::update() {
|
|||
}
|
||||
|
||||
if (this->has_sensing_pin_) {
|
||||
// A finger touch results in a low level (digital_read() == false)
|
||||
if (this->sensing_pin_->digital_read()) {
|
||||
ESP_LOGV(TAG, "No touch sensing");
|
||||
this->waiting_removal_ = false;
|
||||
if ((this->enrollment_image_ == 0) && // Not in enrolment process
|
||||
(millis() - this->last_transfer_ms_ > this->idle_period_to_sleep_ms_) && (this->is_sensor_awake_)) {
|
||||
this->sensor_sleep_();
|
||||
}
|
||||
return;
|
||||
} else if (!this->waiting_removal_) {
|
||||
this->finger_scan_start_callback_.call();
|
||||
|
@ -53,7 +58,29 @@ void FingerprintGrowComponent::update() {
|
|||
|
||||
void FingerprintGrowComponent::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up Grow Fingerprint Reader...");
|
||||
|
||||
this->has_sensing_pin_ = (this->sensing_pin_ != nullptr);
|
||||
this->has_power_pin_ = (this->sensor_power_pin_ != nullptr);
|
||||
|
||||
// Call pins setup, so we effectively apply the config generated from the yaml file.
|
||||
if (this->has_sensing_pin_) {
|
||||
this->sensing_pin_->setup();
|
||||
}
|
||||
if (this->has_power_pin_) {
|
||||
// Starts with output low (disabling power) to avoid glitches in the sensor
|
||||
this->sensor_power_pin_->digital_write(false);
|
||||
this->sensor_power_pin_->setup();
|
||||
|
||||
// If the user didn't specify an idle period to sleep, applies the default.
|
||||
if (this->idle_period_to_sleep_ms_ == UINT32_MAX) {
|
||||
this->idle_period_to_sleep_ms_ = DEFAULT_IDLE_PERIOD_TO_SLEEP_MS;
|
||||
}
|
||||
}
|
||||
|
||||
// Place the sensor in a known (sleep/off) state and sync internal var state.
|
||||
this->sensor_sleep_();
|
||||
delay(20); // This delay guarantees the sensor will in fact be powered power.
|
||||
|
||||
if (this->check_password_()) {
|
||||
if (this->new_password_ != -1) {
|
||||
if (this->set_password_())
|
||||
|
@ -335,7 +362,7 @@ void FingerprintGrowComponent::aura_led_control(uint8_t state, uint8_t speed, ui
|
|||
}
|
||||
}
|
||||
|
||||
uint8_t FingerprintGrowComponent::send_command_() {
|
||||
uint8_t FingerprintGrowComponent::transfer_(std::vector<uint8_t> *p_data_buffer) {
|
||||
while (this->available())
|
||||
this->read();
|
||||
this->write((uint8_t) (START_CODE >> 8));
|
||||
|
@ -346,12 +373,12 @@ uint8_t FingerprintGrowComponent::send_command_() {
|
|||
this->write(this->address_[3]);
|
||||
this->write(COMMAND);
|
||||
|
||||
uint16_t wire_length = this->data_.size() + 2;
|
||||
uint16_t wire_length = p_data_buffer->size() + 2;
|
||||
this->write((uint8_t) (wire_length >> 8));
|
||||
this->write((uint8_t) (wire_length & 0xFF));
|
||||
|
||||
uint16_t sum = ((wire_length) >> 8) + ((wire_length) &0xFF) + COMMAND;
|
||||
for (auto data : this->data_) {
|
||||
for (auto data : *p_data_buffer) {
|
||||
this->write(data);
|
||||
sum += data;
|
||||
}
|
||||
|
@ -359,7 +386,7 @@ uint8_t FingerprintGrowComponent::send_command_() {
|
|||
this->write((uint8_t) (sum >> 8));
|
||||
this->write((uint8_t) (sum & 0xFF));
|
||||
|
||||
this->data_.clear();
|
||||
p_data_buffer->clear();
|
||||
|
||||
uint8_t byte;
|
||||
uint16_t idx = 0, length = 0;
|
||||
|
@ -369,7 +396,9 @@ uint8_t FingerprintGrowComponent::send_command_() {
|
|||
delay(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
byte = this->read();
|
||||
|
||||
switch (idx) {
|
||||
case 0:
|
||||
if (byte != (uint8_t) (START_CODE >> 8))
|
||||
|
@ -403,9 +432,9 @@ uint8_t FingerprintGrowComponent::send_command_() {
|
|||
length |= byte;
|
||||
break;
|
||||
default:
|
||||
this->data_.push_back(byte);
|
||||
p_data_buffer->push_back(byte);
|
||||
if ((idx - 8) == length) {
|
||||
switch (this->data_[0]) {
|
||||
switch ((*p_data_buffer)[0]) {
|
||||
case OK:
|
||||
case NO_FINGER:
|
||||
case IMAGE_FAIL:
|
||||
|
@ -425,38 +454,122 @@ uint8_t FingerprintGrowComponent::send_command_() {
|
|||
ESP_LOGE(TAG, "Reader failed to process request");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unknown response received from reader: %d", this->data_[0]);
|
||||
ESP_LOGE(TAG, "Unknown response received from reader: 0x%.2X", (*p_data_buffer)[0]);
|
||||
break;
|
||||
}
|
||||
return this->data_[0];
|
||||
this->last_transfer_ms_ = millis();
|
||||
return (*p_data_buffer)[0];
|
||||
}
|
||||
break;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
ESP_LOGE(TAG, "No response received from reader");
|
||||
this->data_[0] = TIMEOUT;
|
||||
(*p_data_buffer)[0] = TIMEOUT;
|
||||
this->last_transfer_ms_ = millis();
|
||||
return TIMEOUT;
|
||||
}
|
||||
|
||||
uint8_t FingerprintGrowComponent::send_command_() {
|
||||
this->sensor_wakeup_();
|
||||
return this->transfer_(&this->data_);
|
||||
}
|
||||
|
||||
void FingerprintGrowComponent::sensor_wakeup_() {
|
||||
// Immediately return if there is no power pin or the sensor is already on
|
||||
if ((!this->has_power_pin_) || (this->is_sensor_awake_))
|
||||
return;
|
||||
|
||||
this->sensor_power_pin_->digital_write(true);
|
||||
this->is_sensor_awake_ = true;
|
||||
|
||||
uint8_t byte = TIMEOUT;
|
||||
|
||||
// Wait for the byte HANDSHAKE_SIGN from the sensor meaning it is operational.
|
||||
for (uint16_t timer = 0; timer < WAIT_FOR_WAKE_UP_MS; timer++) {
|
||||
if (this->available() > 0) {
|
||||
byte = this->read();
|
||||
|
||||
/* If the received byte is zero, the UART probably misinterpreted a raising edge on
|
||||
* the RX pin due the power up as byte "zero" - I verified this behaviour using
|
||||
* the esp32-arduino lib. So here we just ignore this fake byte.
|
||||
*/
|
||||
if (byte != 0)
|
||||
break;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
|
||||
/* Lets check if the received by is a HANDSHAKE_SIGN, otherwise log an error
|
||||
* message and try to continue on the best effort.
|
||||
*/
|
||||
if (byte == HANDSHAKE_SIGN) {
|
||||
ESP_LOGD(TAG, "Sensor has woken up!");
|
||||
} else if (byte == TIMEOUT) {
|
||||
ESP_LOGE(TAG, "Timed out waiting for sensor wake-up");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Received wrong byte from the sensor during wake-up: 0x%.2X", byte);
|
||||
}
|
||||
|
||||
/* Next step, we must authenticate with the password. We cannot call check_password_ here
|
||||
* neither use data_ to store the command because it might be already in use by the caller
|
||||
* of send_command_()
|
||||
*/
|
||||
std::vector<uint8_t> buffer = {VERIFY_PASSWORD, (uint8_t) (this->password_ >> 24), (uint8_t) (this->password_ >> 16),
|
||||
(uint8_t) (this->password_ >> 8), (uint8_t) (this->password_ & 0xFF)};
|
||||
|
||||
if (this->transfer_(&buffer) != OK) {
|
||||
ESP_LOGE(TAG, "Wrong password");
|
||||
}
|
||||
}
|
||||
|
||||
void FingerprintGrowComponent::sensor_sleep_() {
|
||||
// Immediately return if the power pin feature is not implemented
|
||||
if (!this->has_power_pin_)
|
||||
return;
|
||||
|
||||
this->sensor_power_pin_->digital_write(false);
|
||||
this->is_sensor_awake_ = false;
|
||||
ESP_LOGD(TAG, "Fingerprint sensor is now in sleep mode.");
|
||||
}
|
||||
|
||||
void FingerprintGrowComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "GROW_FINGERPRINT_READER:");
|
||||
ESP_LOGCONFIG(TAG, " System Identifier Code: 0x%.4X", this->system_identifier_code_);
|
||||
ESP_LOGCONFIG(TAG, " Touch Sensing Pin: %s",
|
||||
this->has_sensing_pin_ ? this->sensing_pin_->dump_summary().c_str() : "None");
|
||||
ESP_LOGCONFIG(TAG, " Sensor Power Pin: %s",
|
||||
this->has_power_pin_ ? this->sensor_power_pin_->dump_summary().c_str() : "None");
|
||||
if (this->idle_period_to_sleep_ms_ < UINT32_MAX) {
|
||||
ESP_LOGCONFIG(TAG, " Idle Period to Sleep: %u ms", this->idle_period_to_sleep_ms_);
|
||||
} else {
|
||||
ESP_LOGCONFIG(TAG, " Idle Period to Sleep: Never");
|
||||
}
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
LOG_SENSOR(" ", "Fingerprint Count", this->fingerprint_count_sensor_);
|
||||
ESP_LOGCONFIG(TAG, " Current Value: %d", (uint16_t) this->fingerprint_count_sensor_->get_state());
|
||||
LOG_SENSOR(" ", "Status", this->status_sensor_);
|
||||
ESP_LOGCONFIG(TAG, " Current Value: %d", (uint8_t) this->status_sensor_->get_state());
|
||||
LOG_SENSOR(" ", "Capacity", this->capacity_sensor_);
|
||||
ESP_LOGCONFIG(TAG, " Current Value: %d", (uint16_t) this->capacity_sensor_->get_state());
|
||||
LOG_SENSOR(" ", "Security Level", this->security_level_sensor_);
|
||||
ESP_LOGCONFIG(TAG, " Current Value: %d", (uint8_t) this->security_level_sensor_->get_state());
|
||||
LOG_SENSOR(" ", "Last Finger ID", this->last_finger_id_sensor_);
|
||||
ESP_LOGCONFIG(TAG, " Current Value: %d", (uint32_t) this->last_finger_id_sensor_->get_state());
|
||||
LOG_SENSOR(" ", "Last Confidence", this->last_confidence_sensor_);
|
||||
ESP_LOGCONFIG(TAG, " Current Value: %d", (uint32_t) this->last_confidence_sensor_->get_state());
|
||||
if (this->fingerprint_count_sensor_) {
|
||||
LOG_SENSOR(" ", "Fingerprint Count", this->fingerprint_count_sensor_);
|
||||
ESP_LOGCONFIG(TAG, " Current Value: %d", (uint16_t) this->fingerprint_count_sensor_->get_state());
|
||||
}
|
||||
if (this->status_sensor_) {
|
||||
LOG_SENSOR(" ", "Status", this->status_sensor_);
|
||||
ESP_LOGCONFIG(TAG, " Current Value: %d", (uint8_t) this->status_sensor_->get_state());
|
||||
}
|
||||
if (this->capacity_sensor_) {
|
||||
LOG_SENSOR(" ", "Capacity", this->capacity_sensor_);
|
||||
ESP_LOGCONFIG(TAG, " Current Value: %d", (uint16_t) this->capacity_sensor_->get_state());
|
||||
}
|
||||
if (this->security_level_sensor_) {
|
||||
LOG_SENSOR(" ", "Security Level", this->security_level_sensor_);
|
||||
ESP_LOGCONFIG(TAG, " Current Value: %d", (uint8_t) this->security_level_sensor_->get_state());
|
||||
}
|
||||
if (this->last_finger_id_sensor_) {
|
||||
LOG_SENSOR(" ", "Last Finger ID", this->last_finger_id_sensor_);
|
||||
ESP_LOGCONFIG(TAG, " Current Value: %d", (uint32_t) this->last_finger_id_sensor_->get_state());
|
||||
}
|
||||
if (this->last_confidence_sensor_) {
|
||||
LOG_SENSOR(" ", "Last Confidence", this->last_confidence_sensor_);
|
||||
ESP_LOGCONFIG(TAG, " Current Value: %d", (uint32_t) this->last_confidence_sensor_->get_state());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fingerprint_grow
|
||||
|
|
|
@ -15,6 +15,11 @@ static const uint16_t START_CODE = 0xEF01;
|
|||
|
||||
static const uint16_t ENROLLMENT_SLOT_UNUSED = 0xFFFF;
|
||||
|
||||
// The datasheet says a max wake up time of of 200ms.
|
||||
static const uint8_t WAIT_FOR_WAKE_UP_MS = 200;
|
||||
|
||||
static const uint32_t DEFAULT_IDLE_PERIOD_TO_SLEEP_MS = 5000;
|
||||
|
||||
enum GrowPacketType {
|
||||
COMMAND = 0x01,
|
||||
DATA = 0x02,
|
||||
|
@ -63,6 +68,7 @@ enum GrowResponse {
|
|||
INVALID_IMAGE = 0x15,
|
||||
FLASH_ERR = 0x18,
|
||||
INVALID_REG = 0x1A,
|
||||
HANDSHAKE_SIGN = 0x55,
|
||||
BAD_PACKET = 0xFE,
|
||||
TIMEOUT = 0xFF,
|
||||
};
|
||||
|
@ -99,8 +105,10 @@ class FingerprintGrowComponent : public PollingComponent, public uart::UARTDevic
|
|||
this->address_[3] = (uint8_t) (address & 0xFF);
|
||||
}
|
||||
void set_sensing_pin(GPIOPin *sensing_pin) { this->sensing_pin_ = sensing_pin; }
|
||||
void set_sensor_power_pin(GPIOPin *sensor_power_pin) { this->sensor_power_pin_ = sensor_power_pin; }
|
||||
void set_password(uint32_t password) { this->password_ = password; }
|
||||
void set_new_password(uint32_t new_password) { this->new_password_ = new_password; }
|
||||
void set_idle_period_to_sleep_ms(uint32_t period_ms) { this->idle_period_to_sleep_ms_ = period_ms; }
|
||||
void set_fingerprint_count_sensor(sensor::Sensor *fingerprint_count_sensor) {
|
||||
this->fingerprint_count_sensor_ = fingerprint_count_sensor;
|
||||
}
|
||||
|
@ -160,7 +168,10 @@ class FingerprintGrowComponent : public PollingComponent, public uart::UARTDevic
|
|||
bool set_password_();
|
||||
bool get_parameters_();
|
||||
void get_fingerprint_count_();
|
||||
uint8_t transfer_(std::vector<uint8_t> *p_data_buffer);
|
||||
uint8_t send_command_();
|
||||
void sensor_wakeup_();
|
||||
void sensor_sleep_();
|
||||
|
||||
std::vector<uint8_t> data_ = {};
|
||||
uint8_t address_[4] = {0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
@ -168,14 +179,19 @@ class FingerprintGrowComponent : public PollingComponent, public uart::UARTDevic
|
|||
uint32_t password_ = 0x0;
|
||||
uint32_t new_password_ = -1;
|
||||
GPIOPin *sensing_pin_{nullptr};
|
||||
GPIOPin *sensor_power_pin_{nullptr};
|
||||
uint8_t enrollment_image_ = 0;
|
||||
uint16_t enrollment_slot_ = ENROLLMENT_SLOT_UNUSED;
|
||||
uint8_t enrollment_buffers_ = 5;
|
||||
bool waiting_removal_ = false;
|
||||
bool has_sensing_pin_ = false;
|
||||
bool has_power_pin_ = false;
|
||||
bool is_sensor_awake_ = false;
|
||||
uint32_t last_transfer_ms_ = 0;
|
||||
uint32_t last_aura_led_control_ = 0;
|
||||
uint16_t last_aura_led_duration_ = 0;
|
||||
uint16_t system_identifier_code_ = 0;
|
||||
uint32_t idle_period_to_sleep_ms_ = UINT32_MAX;
|
||||
sensor::Sensor *fingerprint_count_sensor_{nullptr};
|
||||
sensor::Sensor *status_sensor_{nullptr};
|
||||
sensor::Sensor *capacity_sensor_{nullptr};
|
||||
|
|
|
@ -1299,6 +1299,11 @@ fingerprint_grow:
|
|||
sensing_pin:
|
||||
allow_other_uses: true
|
||||
number: 4
|
||||
sensor_power_pin:
|
||||
allow_other_uses: true
|
||||
number: 5
|
||||
inverted: true
|
||||
idle_period_to_sleep: 5s
|
||||
password: 0x12FE37DC
|
||||
new_password: 0xA65B9840
|
||||
on_finger_scan_start:
|
||||
|
|
Loading…
Reference in a new issue