mirror of
https://github.com/esphome/esphome.git
synced 2024-12-21 16:27:44 +01:00
Add Grow Fingerprint Reader (#1356)
This commit is contained in:
parent
cc6d1e85cc
commit
4d7c1ae143
@ -36,6 +36,7 @@ esphome/components/ds1307/* @badbadc0ffee
|
||||
esphome/components/exposure_notifications/* @OttoWinter
|
||||
esphome/components/ezo/* @ssieb
|
||||
esphome/components/fastled_base/* @OttoWinter
|
||||
esphome/components/fingerprint_grow/* @OnFreund @loongyh
|
||||
esphome/components/globals/* @esphome/core
|
||||
esphome/components/gpio/* @esphome/core
|
||||
esphome/components/gps/* @coogle
|
||||
|
293
esphome/components/fingerprint_grow/__init__.py
Normal file
293
esphome/components/fingerprint_grow/__init__.py
Normal file
@ -0,0 +1,293 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import automation
|
||||
from esphome import pins
|
||||
from esphome.components import uart
|
||||
from esphome.const import (
|
||||
CONF_COLOR,
|
||||
CONF_COUNT,
|
||||
CONF_FINGER_ID,
|
||||
CONF_ID,
|
||||
CONF_NEW_PASSWORD,
|
||||
CONF_NUM_SCANS,
|
||||
CONF_ON_ENROLLMENT_DONE,
|
||||
CONF_ON_ENROLLMENT_FAILED,
|
||||
CONF_ON_ENROLLMENT_SCAN,
|
||||
CONF_ON_FINGER_SCAN_MATCHED,
|
||||
CONF_ON_FINGER_SCAN_UNMATCHED,
|
||||
CONF_PASSWORD,
|
||||
CONF_SENSING_PIN,
|
||||
CONF_SPEED,
|
||||
CONF_STATE,
|
||||
CONF_TRIGGER_ID,
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@OnFreund", "@loongyh"]
|
||||
DEPENDENCIES = ["uart"]
|
||||
AUTO_LOAD = ["binary_sensor", "sensor"]
|
||||
MULTI_CONF = True
|
||||
|
||||
CONF_FINGERPRINT_GROW_ID = "fingerprint_grow_id"
|
||||
|
||||
fingerprint_grow_ns = cg.esphome_ns.namespace("fingerprint_grow")
|
||||
FingerprintGrowComponent = fingerprint_grow_ns.class_(
|
||||
"FingerprintGrowComponent", cg.PollingComponent, uart.UARTDevice
|
||||
)
|
||||
|
||||
FingerScanMatchedTrigger = fingerprint_grow_ns.class_(
|
||||
"FingerScanMatchedTrigger", automation.Trigger.template(cg.uint16, cg.uint16)
|
||||
)
|
||||
|
||||
FingerScanUnmatchedTrigger = fingerprint_grow_ns.class_(
|
||||
"FingerScanUnmatchedTrigger", automation.Trigger.template()
|
||||
)
|
||||
|
||||
EnrollmentScanTrigger = fingerprint_grow_ns.class_(
|
||||
"EnrollmentScanTrigger", automation.Trigger.template(cg.uint8, cg.uint16)
|
||||
)
|
||||
|
||||
EnrollmentDoneTrigger = fingerprint_grow_ns.class_(
|
||||
"EnrollmentDoneTrigger", automation.Trigger.template(cg.uint16)
|
||||
)
|
||||
|
||||
EnrollmentFailedTrigger = fingerprint_grow_ns.class_(
|
||||
"EnrollmentFailedTrigger", automation.Trigger.template(cg.uint16)
|
||||
)
|
||||
|
||||
EnrollmentAction = fingerprint_grow_ns.class_("EnrollmentAction", automation.Action)
|
||||
CancelEnrollmentAction = fingerprint_grow_ns.class_(
|
||||
"CancelEnrollmentAction", automation.Action
|
||||
)
|
||||
DeleteAction = fingerprint_grow_ns.class_("DeleteAction", automation.Action)
|
||||
DeleteAllAction = fingerprint_grow_ns.class_("DeleteAllAction", automation.Action)
|
||||
LEDControlAction = fingerprint_grow_ns.class_("LEDControlAction", automation.Action)
|
||||
AuraLEDControlAction = fingerprint_grow_ns.class_(
|
||||
"AuraLEDControlAction", automation.Action
|
||||
)
|
||||
|
||||
AuraLEDState = fingerprint_grow_ns.enum("GrowAuraLEDState", True)
|
||||
AURA_LED_STATES = {
|
||||
"BREATHING": AuraLEDState.BREATHING,
|
||||
"FLASHING": AuraLEDState.FLASHING,
|
||||
"ALWAYS_ON": AuraLEDState.ALWAYS_ON,
|
||||
"ALWAYS_OFF": AuraLEDState.ALWAYS_OFF,
|
||||
"GRADUAL_ON": AuraLEDState.GRADUAL_ON,
|
||||
"GRADUAL_OFF": AuraLEDState.GRADUAL_OFF,
|
||||
}
|
||||
validate_aura_led_states = cv.enum(AURA_LED_STATES, upper=True)
|
||||
AuraLEDColor = fingerprint_grow_ns.enum("GrowAuraLEDColor", True)
|
||||
AURA_LED_COLORS = {
|
||||
"RED": AuraLEDColor.RED,
|
||||
"BLUE": AuraLEDColor.BLUE,
|
||||
"PURPLE": AuraLEDColor.PURPLE,
|
||||
}
|
||||
validate_aura_led_colors = cv.enum(AURA_LED_COLORS, upper=True)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(FingerprintGrowComponent),
|
||||
cv.Optional(CONF_SENSING_PIN): pins.gpio_input_pin_schema,
|
||||
cv.Optional(CONF_PASSWORD): cv.uint32_t,
|
||||
cv.Optional(CONF_NEW_PASSWORD): cv.uint32_t,
|
||||
cv.Optional(CONF_ON_FINGER_SCAN_MATCHED): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||
FingerScanMatchedTrigger
|
||||
),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_FINGER_SCAN_UNMATCHED): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||
FingerScanUnmatchedTrigger
|
||||
),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_ENROLLMENT_SCAN): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||
EnrollmentScanTrigger
|
||||
),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_ENROLLMENT_DONE): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||
EnrollmentDoneTrigger
|
||||
),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_ENROLLMENT_FAILED): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||
EnrollmentFailedTrigger
|
||||
),
|
||||
}
|
||||
),
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("500ms"))
|
||||
.extend(uart.UART_DEVICE_SCHEMA)
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
if CONF_PASSWORD in config:
|
||||
password = config[CONF_PASSWORD]
|
||||
cg.add(var.set_password(password))
|
||||
yield uart.register_uart_device(var, config)
|
||||
|
||||
if CONF_NEW_PASSWORD in config:
|
||||
new_password = config[CONF_NEW_PASSWORD]
|
||||
cg.add(var.set_new_password(new_password))
|
||||
|
||||
if CONF_SENSING_PIN in config:
|
||||
sensing_pin = yield cg.gpio_pin_expression(config[CONF_SENSING_PIN])
|
||||
cg.add(var.set_sensing_pin(sensing_pin))
|
||||
|
||||
for conf in config.get(CONF_ON_FINGER_SCAN_MATCHED, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
yield automation.build_automation(
|
||||
trigger, [(cg.uint16, "finger_id"), (cg.uint16, "confidence")], conf
|
||||
)
|
||||
|
||||
for conf in config.get(CONF_ON_FINGER_SCAN_UNMATCHED, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
yield automation.build_automation(trigger, [], conf)
|
||||
|
||||
for conf in config.get(CONF_ON_ENROLLMENT_SCAN, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
yield automation.build_automation(
|
||||
trigger, [(cg.uint8, "scan_num"), (cg.uint16, "finger_id")], conf
|
||||
)
|
||||
|
||||
for conf in config.get(CONF_ON_ENROLLMENT_DONE, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
yield automation.build_automation(trigger, [(cg.uint16, "finger_id")], conf)
|
||||
|
||||
for conf in config.get(CONF_ON_ENROLLMENT_FAILED, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
yield automation.build_automation(trigger, [(cg.uint16, "finger_id")], conf)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"fingerprint_grow.enroll",
|
||||
EnrollmentAction,
|
||||
cv.maybe_simple_value(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(FingerprintGrowComponent),
|
||||
cv.Required(CONF_FINGER_ID): cv.templatable(cv.uint16_t),
|
||||
cv.Optional(CONF_NUM_SCANS): cv.templatable(cv.uint8_t),
|
||||
},
|
||||
key=CONF_FINGER_ID,
|
||||
),
|
||||
)
|
||||
def fingerprint_grow_enroll_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
|
||||
template_ = yield cg.templatable(config[CONF_FINGER_ID], args, cg.uint16)
|
||||
cg.add(var.set_finger_id(template_))
|
||||
if CONF_NUM_SCANS in config:
|
||||
template_ = yield cg.templatable(config[CONF_NUM_SCANS], args, cg.uint8)
|
||||
cg.add(var.set_num_scans(template_))
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"fingerprint_grow.cancel_enroll",
|
||||
CancelEnrollmentAction,
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(FingerprintGrowComponent),
|
||||
}
|
||||
),
|
||||
)
|
||||
def fingerprint_grow_cancel_enroll_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"fingerprint_grow.delete",
|
||||
DeleteAction,
|
||||
cv.maybe_simple_value(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(FingerprintGrowComponent),
|
||||
cv.Required(CONF_FINGER_ID): cv.templatable(cv.uint16_t),
|
||||
},
|
||||
key=CONF_FINGER_ID,
|
||||
),
|
||||
)
|
||||
def fingerprint_grow_delete_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
|
||||
template_ = yield cg.templatable(config[CONF_FINGER_ID], args, cg.uint16)
|
||||
cg.add(var.set_finger_id(template_))
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"fingerprint_grow.delete_all",
|
||||
DeleteAllAction,
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(FingerprintGrowComponent),
|
||||
}
|
||||
),
|
||||
)
|
||||
def fingerprint_grow_delete_all_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
yield var
|
||||
|
||||
|
||||
FINGERPRINT_GROW_LED_CONTROL_ACTION_SCHEMA = cv.maybe_simple_value(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(FingerprintGrowComponent),
|
||||
cv.Required(CONF_STATE): cv.templatable(cv.boolean),
|
||||
},
|
||||
key=CONF_STATE,
|
||||
)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"fingerprint_grow.led_control",
|
||||
LEDControlAction,
|
||||
FINGERPRINT_GROW_LED_CONTROL_ACTION_SCHEMA,
|
||||
)
|
||||
def fingerprint_grow_led_control_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
|
||||
template_ = yield cg.templatable(config[CONF_STATE], args, cg.bool_)
|
||||
cg.add(var.set_state(template_))
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"fingerprint_grow.aura_led_control",
|
||||
AuraLEDControlAction,
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(FingerprintGrowComponent),
|
||||
cv.Required(CONF_STATE): cv.templatable(validate_aura_led_states),
|
||||
cv.Required(CONF_SPEED): cv.templatable(cv.uint8_t),
|
||||
cv.Required(CONF_COLOR): cv.templatable(validate_aura_led_colors),
|
||||
cv.Required(CONF_COUNT): cv.templatable(cv.uint8_t),
|
||||
}
|
||||
),
|
||||
)
|
||||
def fingerprint_grow_aura_led_control_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
|
||||
for key in [CONF_STATE, CONF_SPEED, CONF_COLOR, CONF_COUNT]:
|
||||
template_ = yield cg.templatable(config[key], args, cg.uint8)
|
||||
cg.add(getattr(var, f"set_{key}")(template_))
|
||||
yield var
|
20
esphome/components/fingerprint_grow/binary_sensor.py
Normal file
20
esphome/components/fingerprint_grow/binary_sensor.py
Normal file
@ -0,0 +1,20 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import binary_sensor
|
||||
from esphome.const import CONF_ICON, ICON_KEY_PLUS
|
||||
from . import CONF_FINGERPRINT_GROW_ID, FingerprintGrowComponent
|
||||
|
||||
DEPENDENCIES = ["fingerprint_grow"]
|
||||
|
||||
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(CONF_FINGERPRINT_GROW_ID): cv.use_id(FingerprintGrowComponent),
|
||||
cv.Optional(CONF_ICON, default=ICON_KEY_PLUS): cv.icon,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
hub = yield cg.get_variable(config[CONF_FINGERPRINT_GROW_ID])
|
||||
var = yield binary_sensor.new_binary_sensor(config)
|
||||
cg.add(hub.set_enrolling_binary_sensor(var))
|
434
esphome/components/fingerprint_grow/fingerprint_grow.cpp
Normal file
434
esphome/components/fingerprint_grow/fingerprint_grow.cpp
Normal file
@ -0,0 +1,434 @@
|
||||
#include "fingerprint_grow.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace fingerprint_grow {
|
||||
|
||||
static const char* TAG = "fingerprint_grow";
|
||||
|
||||
// Based on Adafruit's library: https://github.com/adafruit/Adafruit-Fingerprint-Sensor-Library
|
||||
|
||||
void FingerprintGrowComponent::update() {
|
||||
if (this->enrollment_image_ > this->enrollment_buffers_) {
|
||||
this->finish_enrollment(this->save_fingerprint_());
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->sensing_pin_ != nullptr) {
|
||||
if (this->sensing_pin_->digital_read() == HIGH) {
|
||||
ESP_LOGV(TAG, "No touch sensing");
|
||||
this->waiting_removal_ = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->waiting_removal_) {
|
||||
if (this->scan_image_(1) == NO_FINGER) {
|
||||
ESP_LOGD(TAG, "Finger removed");
|
||||
this->waiting_removal_ = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->enrollment_image_ == 0) {
|
||||
this->scan_and_match_();
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t result = this->scan_image_(this->enrollment_image_);
|
||||
if (result == NO_FINGER) {
|
||||
return;
|
||||
}
|
||||
this->waiting_removal_ = true;
|
||||
if (result != OK) {
|
||||
this->finish_enrollment(result);
|
||||
return;
|
||||
}
|
||||
this->enrollment_scan_callback_.call(this->enrollment_image_, this->enrollment_slot_);
|
||||
++this->enrollment_image_;
|
||||
}
|
||||
|
||||
void FingerprintGrowComponent::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up Grow Fingerprint Reader...");
|
||||
if (this->check_password_()) {
|
||||
if (this->new_password_ != nullptr) {
|
||||
if (this->set_password_())
|
||||
return;
|
||||
} else {
|
||||
if (this->get_parameters_())
|
||||
return;
|
||||
}
|
||||
}
|
||||
this->mark_failed();
|
||||
}
|
||||
|
||||
void FingerprintGrowComponent::enroll_fingerprint(uint16_t finger_id, uint8_t num_buffers) {
|
||||
ESP_LOGI(TAG, "Starting enrollment in slot %d", finger_id);
|
||||
if (this->enrolling_binary_sensor_ != nullptr) {
|
||||
this->enrolling_binary_sensor_->publish_state(true);
|
||||
}
|
||||
this->enrollment_slot_ = finger_id;
|
||||
this->enrollment_buffers_ = num_buffers;
|
||||
this->enrollment_image_ = 1;
|
||||
}
|
||||
|
||||
void FingerprintGrowComponent::finish_enrollment(uint8_t result) {
|
||||
if (result == OK) {
|
||||
this->enrollment_done_callback_.call(this->enrollment_slot_);
|
||||
} else {
|
||||
this->enrollment_failed_callback_.call(this->enrollment_slot_);
|
||||
}
|
||||
this->enrollment_image_ = 0;
|
||||
this->enrollment_slot_ = 0;
|
||||
if (this->enrolling_binary_sensor_ != nullptr) {
|
||||
this->enrolling_binary_sensor_->publish_state(false);
|
||||
}
|
||||
ESP_LOGI(TAG, "Finished enrollment");
|
||||
}
|
||||
|
||||
void FingerprintGrowComponent::scan_and_match_() {
|
||||
if (this->sensing_pin_ != nullptr) {
|
||||
ESP_LOGD(TAG, "Scan and match");
|
||||
} else {
|
||||
ESP_LOGV(TAG, "Scan and match");
|
||||
}
|
||||
if (this->scan_image_(1) == OK) {
|
||||
this->waiting_removal_ = true;
|
||||
this->data_ = {SEARCH, 0x01, 0x00, 0x00, (uint8_t)(this->capacity_ >> 8), (uint8_t)(this->capacity_ & 0xFF)};
|
||||
switch (this->send_command_()) {
|
||||
case OK: {
|
||||
ESP_LOGD(TAG, "Fingerprint matched");
|
||||
uint16_t finger_id = ((uint16_t) this->data_[1] << 8) | this->data_[2];
|
||||
uint16_t confidence = ((uint16_t) this->data_[3] << 8) | this->data_[4];
|
||||
if (this->last_finger_id_sensor_ != nullptr) {
|
||||
this->last_finger_id_sensor_->publish_state(finger_id);
|
||||
}
|
||||
if (this->last_confidence_sensor_ != nullptr) {
|
||||
this->last_confidence_sensor_->publish_state(confidence);
|
||||
}
|
||||
this->finger_scan_matched_callback_.call(finger_id, confidence);
|
||||
break;
|
||||
}
|
||||
case NOT_FOUND:
|
||||
ESP_LOGD(TAG, "Fingerprint not matched to any saved slots");
|
||||
this->finger_scan_unmatched_callback_.call();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t FingerprintGrowComponent::scan_image_(uint8_t buffer) {
|
||||
if (this->sensing_pin_ != nullptr) {
|
||||
ESP_LOGD(TAG, "Getting image %d", buffer);
|
||||
} else {
|
||||
ESP_LOGV(TAG, "Getting image %d", buffer);
|
||||
}
|
||||
this->data_ = {GET_IMAGE};
|
||||
switch (this->send_command_()) {
|
||||
case OK:
|
||||
break;
|
||||
case NO_FINGER:
|
||||
if (this->sensing_pin_ != nullptr) {
|
||||
ESP_LOGD(TAG, "No finger");
|
||||
} else {
|
||||
ESP_LOGV(TAG, "No finger");
|
||||
}
|
||||
return this->data_[0];
|
||||
case IMAGE_FAIL:
|
||||
ESP_LOGE(TAG, "Imaging error");
|
||||
default:
|
||||
return this->data_[0];
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Processing image %d", buffer);
|
||||
this->data_ = {IMAGE_2_TZ, buffer};
|
||||
switch (this->send_command_()) {
|
||||
case OK:
|
||||
ESP_LOGI(TAG, "Processed image %d", buffer);
|
||||
break;
|
||||
case IMAGE_MESS:
|
||||
ESP_LOGE(TAG, "Image too messy");
|
||||
break;
|
||||
case FEATURE_FAIL:
|
||||
case INVALID_IMAGE:
|
||||
ESP_LOGE(TAG, "Could not find fingerprint features");
|
||||
break;
|
||||
}
|
||||
return this->data_[0];
|
||||
}
|
||||
|
||||
uint8_t FingerprintGrowComponent::save_fingerprint_() {
|
||||
ESP_LOGI(TAG, "Creating model");
|
||||
this->data_ = {REG_MODEL};
|
||||
switch (this->send_command_()) {
|
||||
case OK:
|
||||
break;
|
||||
case ENROLL_MISMATCH:
|
||||
ESP_LOGE(TAG, "Scans do not match");
|
||||
default:
|
||||
return this->data_[0];
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Storing model");
|
||||
this->data_ = {STORE, 0x01, (uint8_t)(this->enrollment_slot_ >> 8), (uint8_t)(this->enrollment_slot_ & 0xFF)};
|
||||
switch (this->send_command_()) {
|
||||
case OK:
|
||||
ESP_LOGI(TAG, "Stored model");
|
||||
break;
|
||||
case BAD_LOCATION:
|
||||
ESP_LOGE(TAG, "Invalid slot");
|
||||
break;
|
||||
case FLASH_ERR:
|
||||
ESP_LOGE(TAG, "Error writing to flash");
|
||||
break;
|
||||
}
|
||||
return this->data_[0];
|
||||
}
|
||||
|
||||
bool FingerprintGrowComponent::check_password_() {
|
||||
ESP_LOGD(TAG, "Checking password");
|
||||
this->data_ = {VERIFY_PASSWORD, (uint8_t)(this->password_ >> 24), (uint8_t)(this->password_ >> 16),
|
||||
(uint8_t)(this->password_ >> 8), (uint8_t)(this->password_ & 0xFF)};
|
||||
switch (this->send_command_()) {
|
||||
case OK:
|
||||
ESP_LOGD(TAG, "Password verified");
|
||||
return true;
|
||||
case PASSWORD_FAIL:
|
||||
ESP_LOGE(TAG, "Wrong password");
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FingerprintGrowComponent::set_password_() {
|
||||
ESP_LOGI(TAG, "Setting new password: %d", *this->new_password_);
|
||||
this->data_ = {SET_PASSWORD, (uint8_t)(*this->new_password_ >> 24), (uint8_t)(*this->new_password_ >> 16),
|
||||
(uint8_t)(*this->new_password_ >> 8), (uint8_t)(*this->new_password_ & 0xFF)};
|
||||
if (this->send_command_() == OK) {
|
||||
ESP_LOGI(TAG, "New password successfully set");
|
||||
ESP_LOGI(TAG, "Define the new password in your configuration and reflash now");
|
||||
ESP_LOGW(TAG, "!!!Forgetting the password will render your device unusable!!!");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FingerprintGrowComponent::get_parameters_() {
|
||||
ESP_LOGD(TAG, "Getting parameters");
|
||||
this->data_ = {READ_SYS_PARAM};
|
||||
if (this->send_command_() == OK) {
|
||||
ESP_LOGD(TAG, "Got parameters");
|
||||
if (this->status_sensor_ != nullptr) {
|
||||
this->status_sensor_->publish_state(((uint16_t) this->data_[1] << 8) | this->data_[2]);
|
||||
}
|
||||
this->capacity_ = ((uint16_t) this->data_[5] << 8) | this->data_[6];
|
||||
if (this->capacity_sensor_ != nullptr) {
|
||||
this->capacity_sensor_->publish_state(this->capacity_);
|
||||
}
|
||||
if (this->security_level_sensor_ != nullptr) {
|
||||
this->security_level_sensor_->publish_state(((uint16_t) this->data_[7] << 8) | this->data_[8]);
|
||||
}
|
||||
if (this->enrolling_binary_sensor_ != nullptr) {
|
||||
this->enrolling_binary_sensor_->publish_state(false);
|
||||
}
|
||||
this->get_fingerprint_count_();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FingerprintGrowComponent::get_fingerprint_count_() {
|
||||
ESP_LOGD(TAG, "Getting fingerprint count");
|
||||
this->data_ = {TEMPLATE_COUNT};
|
||||
if (this->send_command_() == OK) {
|
||||
ESP_LOGD(TAG, "Got fingerprint count");
|
||||
if (this->fingerprint_count_sensor_ != nullptr)
|
||||
this->fingerprint_count_sensor_->publish_state(((uint16_t) this->data_[1] << 8) | this->data_[2]);
|
||||
}
|
||||
}
|
||||
|
||||
void FingerprintGrowComponent::delete_fingerprint(uint16_t finger_id) {
|
||||
ESP_LOGI(TAG, "Deleting fingerprint in slot %d", finger_id);
|
||||
this->data_ = {DELETE, (uint8_t)(finger_id >> 8), (uint8_t)(finger_id & 0xFF), 0x00, 0x01};
|
||||
switch (this->send_command_()) {
|
||||
case OK:
|
||||
ESP_LOGI(TAG, "Deleted fingerprint");
|
||||
this->get_fingerprint_count_();
|
||||
break;
|
||||
case DELETE_FAIL:
|
||||
ESP_LOGE(TAG, "Reader failed to delete fingerprint");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FingerprintGrowComponent::delete_all_fingerprints() {
|
||||
ESP_LOGI(TAG, "Deleting all stored fingerprints");
|
||||
this->data_ = {EMPTY};
|
||||
switch (this->send_command_()) {
|
||||
case OK:
|
||||
ESP_LOGI(TAG, "Deleted all fingerprints");
|
||||
this->get_fingerprint_count_();
|
||||
break;
|
||||
case DB_CLEAR_FAIL:
|
||||
ESP_LOGE(TAG, "Reader failed to clear fingerprint library");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FingerprintGrowComponent::led_control(bool state) {
|
||||
ESP_LOGD(TAG, "Setting LED");
|
||||
if (state)
|
||||
this->data_ = {LED_ON};
|
||||
else
|
||||
this->data_ = {LED_OFF};
|
||||
switch (this->send_command_()) {
|
||||
case OK:
|
||||
ESP_LOGD(TAG, "LED set");
|
||||
break;
|
||||
case PACKET_RCV_ERR:
|
||||
case TIMEOUT:
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Try aura_led_control instead");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FingerprintGrowComponent::aura_led_control(uint8_t state, uint8_t speed, uint8_t color, uint8_t count) {
|
||||
const uint32_t now = millis();
|
||||
const uint32_t elapsed = now - this->last_aura_led_control_;
|
||||
if (elapsed < this->last_aura_led_duration_) {
|
||||
delay(this->last_aura_led_duration_ - elapsed);
|
||||
}
|
||||
ESP_LOGD(TAG, "Setting Aura LED");
|
||||
this->data_ = {AURA_CONFIG, state, speed, color, count};
|
||||
switch (this->send_command_()) {
|
||||
case OK:
|
||||
ESP_LOGD(TAG, "Aura LED set");
|
||||
this->last_aura_led_control_ = millis();
|
||||
this->last_aura_led_duration_ = 10 * speed * count;
|
||||
break;
|
||||
case PACKET_RCV_ERR:
|
||||
case TIMEOUT:
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Try led_control instead");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t FingerprintGrowComponent::send_command_() {
|
||||
this->write((uint8_t)(START_CODE >> 8));
|
||||
this->write((uint8_t)(START_CODE & 0xFF));
|
||||
this->write(this->address_[0]);
|
||||
this->write(this->address_[1]);
|
||||
this->write(this->address_[2]);
|
||||
this->write(this->address_[3]);
|
||||
this->write(COMMAND);
|
||||
|
||||
uint16_t wire_length = this->data_.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_) {
|
||||
this->write(data);
|
||||
sum += data;
|
||||
}
|
||||
|
||||
this->write((uint8_t)(sum >> 8));
|
||||
this->write((uint8_t)(sum & 0xFF));
|
||||
|
||||
this->data_.clear();
|
||||
|
||||
uint8_t byte;
|
||||
uint16_t idx = 0, length = 0;
|
||||
|
||||
for (uint16_t timer = 0; timer < 1000; timer++) {
|
||||
if (this->available() == 0) {
|
||||
delay(1);
|
||||
continue;
|
||||
}
|
||||
byte = this->read();
|
||||
switch (idx) {
|
||||
case 0:
|
||||
if (byte != (uint8_t)(START_CODE >> 8))
|
||||
continue;
|
||||
break;
|
||||
case 1:
|
||||
if (byte != (uint8_t)(START_CODE & 0xFF)) {
|
||||
idx = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
if (byte != this->address_[idx - 2]) {
|
||||
idx = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (byte != ACK) {
|
||||
idx = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
length = (uint16_t) byte << 8;
|
||||
break;
|
||||
case 8:
|
||||
length |= byte;
|
||||
break;
|
||||
default:
|
||||
this->data_.push_back(byte);
|
||||
if ((idx - 8) == length) {
|
||||
switch (this->data_[0]) {
|
||||
case OK:
|
||||
case NO_FINGER:
|
||||
case IMAGE_FAIL:
|
||||
case IMAGE_MESS:
|
||||
case FEATURE_FAIL:
|
||||
case NO_MATCH:
|
||||
case NOT_FOUND:
|
||||
case ENROLL_MISMATCH:
|
||||
case BAD_LOCATION:
|
||||
case DELETE_FAIL:
|
||||
case DB_CLEAR_FAIL:
|
||||
case PASSWORD_FAIL:
|
||||
case INVALID_IMAGE:
|
||||
case FLASH_ERR:
|
||||
break;
|
||||
case PACKET_RCV_ERR:
|
||||
ESP_LOGE(TAG, "Reader failed to process request");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unknown response received from reader: %d", this->data_[0]);
|
||||
break;
|
||||
}
|
||||
return this->data_[0];
|
||||
}
|
||||
break;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
ESP_LOGE(TAG, "No response received from reader");
|
||||
this->data_[0] = TIMEOUT;
|
||||
return TIMEOUT;
|
||||
}
|
||||
|
||||
void FingerprintGrowComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "GROW_FINGERPRINT_READER:");
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
LOG_SENSOR(" ", "Fingerprint Count", this->fingerprint_count_sensor_);
|
||||
LOG_SENSOR(" ", "Status", this->status_sensor_);
|
||||
LOG_SENSOR(" ", "Capacity", this->capacity_sensor_);
|
||||
LOG_SENSOR(" ", "Security Level", this->security_level_sensor_);
|
||||
LOG_SENSOR(" ", "Last Finger ID", this->last_finger_id_sensor_);
|
||||
LOG_SENSOR(" ", "Last Confidence", this->last_confidence_sensor_);
|
||||
}
|
||||
|
||||
} // namespace fingerprint_grow
|
||||
} // namespace esphome
|
276
esphome/components/fingerprint_grow/fingerprint_grow.h
Normal file
276
esphome/components/fingerprint_grow/fingerprint_grow.h
Normal file
@ -0,0 +1,276 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace fingerprint_grow {
|
||||
|
||||
static const uint16_t START_CODE = 0xEF01;
|
||||
|
||||
enum GrowPacketType {
|
||||
COMMAND = 0x01,
|
||||
DATA = 0x02,
|
||||
ACK = 0x07,
|
||||
END_DATA = 0x08,
|
||||
};
|
||||
|
||||
enum GrowCommand {
|
||||
GET_IMAGE = 0x01,
|
||||
IMAGE_2_TZ = 0x02,
|
||||
SEARCH = 0x04,
|
||||
REG_MODEL = 0x05,
|
||||
STORE = 0x06,
|
||||
LOAD = 0x07,
|
||||
UPLOAD = 0x08,
|
||||
DELETE = 0x0C,
|
||||
EMPTY = 0x0D,
|
||||
READ_SYS_PARAM = 0x0F,
|
||||
SET_PASSWORD = 0x12,
|
||||
VERIFY_PASSWORD = 0x13,
|
||||
HI_SPEED_SEARCH = 0x1B,
|
||||
TEMPLATE_COUNT = 0x1D,
|
||||
AURA_CONFIG = 0x35,
|
||||
LED_ON = 0x50,
|
||||
LED_OFF = 0x51,
|
||||
};
|
||||
|
||||
enum GrowResponse {
|
||||
OK = 0x00,
|
||||
PACKET_RCV_ERR = 0x01,
|
||||
NO_FINGER = 0x02,
|
||||
IMAGE_FAIL = 0x03,
|
||||
IMAGE_MESS = 0x06,
|
||||
FEATURE_FAIL = 0x07,
|
||||
NO_MATCH = 0x08,
|
||||
NOT_FOUND = 0x09,
|
||||
ENROLL_MISMATCH = 0x0A,
|
||||
BAD_LOCATION = 0x0B,
|
||||
DB_RANGE_FAIL = 0x0C,
|
||||
UPLOAD_FEATURE_FAIL = 0x0D,
|
||||
PACKET_RESPONSE_FAIL = 0x0E,
|
||||
UPLOAD_FAIL = 0x0F,
|
||||
DELETE_FAIL = 0x10,
|
||||
DB_CLEAR_FAIL = 0x11,
|
||||
PASSWORD_FAIL = 0x13,
|
||||
INVALID_IMAGE = 0x15,
|
||||
FLASH_ERR = 0x18,
|
||||
INVALID_REG = 0x1A,
|
||||
BAD_PACKET = 0xFE,
|
||||
TIMEOUT = 0xFF,
|
||||
};
|
||||
|
||||
enum GrowAuraLEDState {
|
||||
BREATHING = 0x01,
|
||||
FLASHING = 0x02,
|
||||
ALWAYS_ON = 0x03,
|
||||
ALWAYS_OFF = 0x04,
|
||||
GRADUAL_ON = 0x05,
|
||||
GRADUAL_OFF = 0x06,
|
||||
};
|
||||
|
||||
enum GrowAuraLEDColor {
|
||||
RED = 0x01,
|
||||
BLUE = 0x02,
|
||||
PURPLE = 0x03,
|
||||
};
|
||||
|
||||
class FingerprintGrowComponent : public PollingComponent, public uart::UARTDevice {
|
||||
public:
|
||||
void update() override;
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
|
||||
void set_address(uint32_t address) {
|
||||
this->address_[0] = (uint8_t)(address >> 24);
|
||||
this->address_[1] = (uint8_t)(address >> 16);
|
||||
this->address_[2] = (uint8_t)(address >> 8);
|
||||
this->address_[3] = (uint8_t)(address & 0xFF);
|
||||
}
|
||||
void set_sensing_pin(GPIOPin *sensing_pin) { this->sensing_pin_ = sensing_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_fingerprint_count_sensor(sensor::Sensor *fingerprint_count_sensor) {
|
||||
this->fingerprint_count_sensor_ = fingerprint_count_sensor;
|
||||
}
|
||||
void set_status_sensor(sensor::Sensor *status_sensor) { this->status_sensor_ = status_sensor; }
|
||||
void set_capacity_sensor(sensor::Sensor *capacity_sensor) { this->capacity_sensor_ = capacity_sensor; }
|
||||
void set_security_level_sensor(sensor::Sensor *security_level_sensor) {
|
||||
this->security_level_sensor_ = security_level_sensor;
|
||||
}
|
||||
void set_last_finger_id_sensor(sensor::Sensor *last_finger_id_sensor) {
|
||||
this->last_finger_id_sensor_ = last_finger_id_sensor;
|
||||
}
|
||||
void set_last_confidence_sensor(sensor::Sensor *last_confidence_sensor) {
|
||||
this->last_confidence_sensor_ = last_confidence_sensor;
|
||||
}
|
||||
void set_enrolling_binary_sensor(binary_sensor::BinarySensor *enrolling_binary_sensor) {
|
||||
this->enrolling_binary_sensor_ = enrolling_binary_sensor;
|
||||
}
|
||||
void add_on_finger_scan_matched_callback(std::function<void(uint16_t, uint16_t)> callback) {
|
||||
this->finger_scan_matched_callback_.add(std::move(callback));
|
||||
}
|
||||
void add_on_finger_scan_unmatched_callback(std::function<void()> callback) {
|
||||
this->finger_scan_unmatched_callback_.add(std::move(callback));
|
||||
}
|
||||
void add_on_enrollment_scan_callback(std::function<void(uint8_t, uint16_t)> callback) {
|
||||
this->enrollment_scan_callback_.add(std::move(callback));
|
||||
}
|
||||
void add_on_enrollment_done_callback(std::function<void(uint16_t)> callback) {
|
||||
this->enrollment_done_callback_.add(std::move(callback));
|
||||
}
|
||||
|
||||
void add_on_enrollment_failed_callback(std::function<void(uint16_t)> callback) {
|
||||
this->enrollment_failed_callback_.add(std::move(callback));
|
||||
}
|
||||
|
||||
void enroll_fingerprint(uint16_t finger_id, uint8_t num_buffers);
|
||||
void finish_enrollment(uint8_t result);
|
||||
void delete_fingerprint(uint16_t finger_id);
|
||||
void delete_all_fingerprints();
|
||||
|
||||
void led_control(bool state);
|
||||
void aura_led_control(uint8_t state, uint8_t speed, uint8_t color, uint8_t count);
|
||||
|
||||
protected:
|
||||
void scan_and_match_();
|
||||
uint8_t scan_image_(uint8_t buffer);
|
||||
uint8_t save_fingerprint_();
|
||||
bool check_password_();
|
||||
bool set_password_();
|
||||
bool get_parameters_();
|
||||
void get_fingerprint_count_();
|
||||
uint8_t send_command_();
|
||||
|
||||
std::vector<uint8_t> data_ = {};
|
||||
uint8_t address_[4] = {0xFF, 0xFF, 0xFF, 0xFF};
|
||||
uint16_t capacity_ = 64;
|
||||
uint32_t password_ = 0x0;
|
||||
uint32_t *new_password_{nullptr};
|
||||
GPIOPin *sensing_pin_{nullptr};
|
||||
uint8_t enrollment_image_ = 0;
|
||||
uint16_t enrollment_slot_ = 0;
|
||||
uint8_t enrollment_buffers_ = 5;
|
||||
bool waiting_removal_ = false;
|
||||
uint32_t last_aura_led_control_ = 0;
|
||||
uint16_t last_aura_led_duration_ = 0;
|
||||
sensor::Sensor *fingerprint_count_sensor_{nullptr};
|
||||
sensor::Sensor *status_sensor_{nullptr};
|
||||
sensor::Sensor *capacity_sensor_{nullptr};
|
||||
sensor::Sensor *security_level_sensor_{nullptr};
|
||||
sensor::Sensor *last_finger_id_sensor_{nullptr};
|
||||
sensor::Sensor *last_confidence_sensor_{nullptr};
|
||||
binary_sensor::BinarySensor *enrolling_binary_sensor_{nullptr};
|
||||
CallbackManager<void(uint16_t, uint16_t)> finger_scan_matched_callback_;
|
||||
CallbackManager<void()> finger_scan_unmatched_callback_;
|
||||
CallbackManager<void(uint8_t, uint16_t)> enrollment_scan_callback_;
|
||||
CallbackManager<void(uint16_t)> enrollment_done_callback_;
|
||||
CallbackManager<void(uint16_t)> enrollment_failed_callback_;
|
||||
};
|
||||
|
||||
class FingerScanMatchedTrigger : public Trigger<uint16_t, uint16_t> {
|
||||
public:
|
||||
explicit FingerScanMatchedTrigger(FingerprintGrowComponent *parent) {
|
||||
parent->add_on_finger_scan_matched_callback(
|
||||
[this](uint16_t finger_id, uint16_t confidence) { this->trigger(finger_id, confidence); });
|
||||
}
|
||||
};
|
||||
|
||||
class FingerScanUnmatchedTrigger : public Trigger<> {
|
||||
public:
|
||||
explicit FingerScanUnmatchedTrigger(FingerprintGrowComponent *parent) {
|
||||
parent->add_on_finger_scan_unmatched_callback([this]() { this->trigger(); });
|
||||
}
|
||||
};
|
||||
|
||||
class EnrollmentScanTrigger : public Trigger<uint8_t, uint16_t> {
|
||||
public:
|
||||
explicit EnrollmentScanTrigger(FingerprintGrowComponent *parent) {
|
||||
parent->add_on_enrollment_scan_callback(
|
||||
[this](uint8_t scan_num, uint16_t finger_id) { this->trigger(scan_num, finger_id); });
|
||||
}
|
||||
};
|
||||
|
||||
class EnrollmentDoneTrigger : public Trigger<uint16_t> {
|
||||
public:
|
||||
explicit EnrollmentDoneTrigger(FingerprintGrowComponent *parent) {
|
||||
parent->add_on_enrollment_done_callback([this](uint16_t finger_id) { this->trigger(finger_id); });
|
||||
}
|
||||
};
|
||||
|
||||
class EnrollmentFailedTrigger : public Trigger<uint16_t> {
|
||||
public:
|
||||
explicit EnrollmentFailedTrigger(FingerprintGrowComponent *parent) {
|
||||
parent->add_on_enrollment_failed_callback([this](uint16_t finger_id) { this->trigger(finger_id); });
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Ts> class EnrollmentAction : public Action<Ts...>, public Parented<FingerprintGrowComponent> {
|
||||
public:
|
||||
TEMPLATABLE_VALUE(uint16_t, finger_id)
|
||||
TEMPLATABLE_VALUE(uint8_t, num_scans)
|
||||
|
||||
void play(Ts... x) override {
|
||||
auto finger_id = this->finger_id_.value(x...);
|
||||
auto num_scans = this->num_scans_.value(x...);
|
||||
if (num_scans) {
|
||||
this->parent_->enroll_fingerprint(finger_id, num_scans);
|
||||
} else {
|
||||
this->parent_->enroll_fingerprint(finger_id, 2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Ts>
|
||||
class CancelEnrollmentAction : public Action<Ts...>, public Parented<FingerprintGrowComponent> {
|
||||
public:
|
||||
void play(Ts... x) override { this->parent_->finish_enrollment(1); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class DeleteAction : public Action<Ts...>, public Parented<FingerprintGrowComponent> {
|
||||
public:
|
||||
TEMPLATABLE_VALUE(uint16_t, finger_id)
|
||||
|
||||
void play(Ts... x) override {
|
||||
auto finger_id = this->finger_id_.value(x...);
|
||||
this->parent_->delete_fingerprint(finger_id);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Ts> class DeleteAllAction : public Action<Ts...>, public Parented<FingerprintGrowComponent> {
|
||||
public:
|
||||
void play(Ts... x) override { this->parent_->delete_all_fingerprints(); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class LEDControlAction : public Action<Ts...>, public Parented<FingerprintGrowComponent> {
|
||||
public:
|
||||
TEMPLATABLE_VALUE(bool, state)
|
||||
|
||||
void play(Ts... x) override {
|
||||
auto state = this->state_.value(x...);
|
||||
this->parent_->led_control(state);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Ts> class AuraLEDControlAction : public Action<Ts...>, public Parented<FingerprintGrowComponent> {
|
||||
public:
|
||||
TEMPLATABLE_VALUE(uint8_t, state)
|
||||
TEMPLATABLE_VALUE(uint8_t, speed)
|
||||
TEMPLATABLE_VALUE(uint8_t, color)
|
||||
TEMPLATABLE_VALUE(uint8_t, count)
|
||||
|
||||
void play(Ts... x) override {
|
||||
auto state = this->state_.value(x...);
|
||||
auto speed = this->speed_.value(x...);
|
||||
auto color = this->color_.value(x...);
|
||||
auto count = this->count_.value(x...);
|
||||
|
||||
this->parent_->aura_led_control(state, speed, color, count);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fingerprint_grow
|
||||
} // namespace esphome
|
64
esphome/components/fingerprint_grow/sensor.py
Normal file
64
esphome/components/fingerprint_grow/sensor.py
Normal file
@ -0,0 +1,64 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor
|
||||
from esphome.const import (
|
||||
CONF_CAPACITY,
|
||||
CONF_FINGERPRINT_COUNT,
|
||||
CONF_LAST_CONFIDENCE,
|
||||
CONF_LAST_FINGER_ID,
|
||||
CONF_SECURITY_LEVEL,
|
||||
CONF_STATUS,
|
||||
DEVICE_CLASS_EMPTY,
|
||||
ICON_ACCOUNT,
|
||||
ICON_ACCOUNT_CHECK,
|
||||
ICON_DATABASE,
|
||||
ICON_EMPTY,
|
||||
ICON_FINGERPRINT,
|
||||
ICON_SECURITY,
|
||||
UNIT_EMPTY,
|
||||
)
|
||||
from . import CONF_FINGERPRINT_GROW_ID, FingerprintGrowComponent
|
||||
|
||||
DEPENDENCIES = ["fingerprint_grow"]
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_FINGERPRINT_GROW_ID): cv.use_id(FingerprintGrowComponent),
|
||||
cv.Optional(CONF_FINGERPRINT_COUNT): sensor.sensor_schema(
|
||||
UNIT_EMPTY, ICON_FINGERPRINT, 0, DEVICE_CLASS_EMPTY
|
||||
),
|
||||
cv.Optional(CONF_STATUS): sensor.sensor_schema(
|
||||
UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY
|
||||
),
|
||||
cv.Optional(CONF_CAPACITY): sensor.sensor_schema(
|
||||
UNIT_EMPTY, ICON_DATABASE, 0, DEVICE_CLASS_EMPTY
|
||||
),
|
||||
cv.Optional(CONF_SECURITY_LEVEL): sensor.sensor_schema(
|
||||
UNIT_EMPTY, ICON_SECURITY, 0, DEVICE_CLASS_EMPTY
|
||||
),
|
||||
cv.Optional(CONF_LAST_FINGER_ID): sensor.sensor_schema(
|
||||
UNIT_EMPTY, ICON_ACCOUNT, 0, DEVICE_CLASS_EMPTY
|
||||
),
|
||||
cv.Optional(CONF_LAST_CONFIDENCE): sensor.sensor_schema(
|
||||
UNIT_EMPTY, ICON_ACCOUNT_CHECK, 0, DEVICE_CLASS_EMPTY
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
hub = yield cg.get_variable(config[CONF_FINGERPRINT_GROW_ID])
|
||||
|
||||
for key in [
|
||||
CONF_FINGERPRINT_COUNT,
|
||||
CONF_STATUS,
|
||||
CONF_CAPACITY,
|
||||
CONF_SECURITY_LEVEL,
|
||||
CONF_LAST_FINGER_ID,
|
||||
CONF_LAST_CONFIDENCE,
|
||||
]:
|
||||
if key not in config:
|
||||
continue
|
||||
conf = config[key]
|
||||
sens = yield sensor.new_sensor(conf)
|
||||
cg.add(getattr(hub, f"set_{key}_sensor")(sens))
|
@ -97,6 +97,7 @@ CONF_BUSY_PIN = "busy_pin"
|
||||
CONF_CALIBRATE_LINEAR = "calibrate_linear"
|
||||
CONF_CALIBRATION = "calibration"
|
||||
CONF_CAPACITANCE = "capacitance"
|
||||
CONF_CAPACITY = "capacity"
|
||||
CONF_CARRIER_DUTY_PERCENT = "carrier_duty_percent"
|
||||
CONF_CARRIER_FREQUENCY = "carrier_frequency"
|
||||
CONF_CERTIFICATE = "certificate"
|
||||
@ -115,6 +116,7 @@ CONF_CO2 = "co2"
|
||||
CONF_CODE = "code"
|
||||
CONF_COLD_WHITE = "cold_white"
|
||||
CONF_COLD_WHITE_COLOR_TEMPERATURE = "cold_white_color_temperature"
|
||||
CONF_COLOR = "color"
|
||||
CONF_COLOR_CORRECT = "color_correct"
|
||||
CONF_COLOR_TEMPERATURE = "color_temperature"
|
||||
CONF_COLORS = "colors"
|
||||
@ -130,6 +132,7 @@ CONF_CONDUCTIVITY = "conductivity"
|
||||
CONF_CONTRAST = "contrast"
|
||||
CONF_COOL_ACTION = "cool_action"
|
||||
CONF_COOL_MODE = "cool_mode"
|
||||
CONF_COUNT = "count"
|
||||
CONF_COUNT_MODE = "count_mode"
|
||||
CONF_COURSE = "course"
|
||||
CONF_CRON = "cron"
|
||||
@ -208,6 +211,8 @@ CONF_FILE = "file"
|
||||
CONF_FILTER = "filter"
|
||||
CONF_FILTER_OUT = "filter_out"
|
||||
CONF_FILTERS = "filters"
|
||||
CONF_FINGER_ID = "finger_id"
|
||||
CONF_FINGERPRINT_COUNT = "fingerprint_count"
|
||||
CONF_FLASH_LENGTH = "flash_length"
|
||||
CONF_FOR = "for"
|
||||
CONF_FORCE_UPDATE = "force_update"
|
||||
@ -275,6 +280,8 @@ CONF_KEEP_ON_TIME = "keep_on_time"
|
||||
CONF_KEEPALIVE = "keepalive"
|
||||
CONF_KEY = "key"
|
||||
CONF_LAMBDA = "lambda"
|
||||
CONF_LAST_CONFIDENCE = "last_confidence"
|
||||
CONF_LAST_FINGER_ID = "last_finger_id"
|
||||
CONF_LATITUDE = "latitude"
|
||||
CONF_LENGTH = "length"
|
||||
CONF_LEVEL = "level"
|
||||
@ -335,11 +342,13 @@ CONF_NAME = "name"
|
||||
CONF_NBITS = "nbits"
|
||||
CONF_NEC = "nec"
|
||||
CONF_NETWORKS = "networks"
|
||||
CONF_NEW_PASSWORD = "new_password"
|
||||
CONF_NOISE_LEVEL = "noise_level"
|
||||
CONF_NUM_ATTEMPTS = "num_attempts"
|
||||
CONF_NUM_CHANNELS = "num_channels"
|
||||
CONF_NUM_CHIPS = "num_chips"
|
||||
CONF_NUM_LEDS = "num_leds"
|
||||
CONF_NUM_SCANS = "num_scans"
|
||||
CONF_NUMBER = "number"
|
||||
CONF_OFF_MODE = "off_mode"
|
||||
CONF_OFFSET = "offset"
|
||||
@ -350,6 +359,11 @@ CONF_ON_BLE_SERVICE_DATA_ADVERTISE = "on_ble_service_data_advertise"
|
||||
CONF_ON_BOOT = "on_boot"
|
||||
CONF_ON_CLICK = "on_click"
|
||||
CONF_ON_DOUBLE_CLICK = "on_double_click"
|
||||
CONF_ON_ENROLLMENT_DONE = "on_enrollment_done"
|
||||
CONF_ON_ENROLLMENT_FAILED = "on_enrollment_failed"
|
||||
CONF_ON_ENROLLMENT_SCAN = "on_enrollment_scan"
|
||||
CONF_ON_FINGER_SCAN_MATCHED = "on_finger_scan_matched"
|
||||
CONF_ON_FINGER_SCAN_UNMATCHED = "on_finger_scan_unmatched"
|
||||
CONF_ON_JSON_MESSAGE = "on_json_message"
|
||||
CONF_ON_LOOP = "on_loop"
|
||||
CONF_ON_MESSAGE = "on_message"
|
||||
@ -472,10 +486,12 @@ CONF_SDA = "sda"
|
||||
CONF_SDO_PIN = "sdo_pin"
|
||||
CONF_SECOND = "second"
|
||||
CONF_SECONDS = "seconds"
|
||||
CONF_SECURITY_LEVEL = "security_level"
|
||||
CONF_SEGMENTS = "segments"
|
||||
CONF_SEL_PIN = "sel_pin"
|
||||
CONF_SEND_EVERY = "send_every"
|
||||
CONF_SEND_FIRST_AT = "send_first_at"
|
||||
CONF_SENSING_PIN = "sensing_pin"
|
||||
CONF_SENSOR = "sensor"
|
||||
CONF_SENSOR_ID = "sensor_id"
|
||||
CONF_SENSORS = "sensors"
|
||||
@ -505,6 +521,7 @@ CONF_SSL_FINGERPRINTS = "ssl_fingerprints"
|
||||
CONF_STATE = "state"
|
||||
CONF_STATE_TOPIC = "state_topic"
|
||||
CONF_STATIC_IP = "static_ip"
|
||||
CONF_STATUS = "status"
|
||||
CONF_STEP_MODE = "step_mode"
|
||||
CONF_STEP_PIN = "step_pin"
|
||||
CONF_STOP = "stop"
|
||||
@ -599,6 +616,8 @@ ICON_ACCELERATION = "mdi:axis-arrow"
|
||||
ICON_ACCELERATION_X = "mdi:axis-x-arrow"
|
||||
ICON_ACCELERATION_Y = "mdi:axis-y-arrow"
|
||||
ICON_ACCELERATION_Z = "mdi:axis-z-arrow"
|
||||
ICON_ACCOUNT = "mdi:account"
|
||||
ICON_ACCOUNT_CHECK = "mdi:account-check"
|
||||
ICON_ARROW_EXPAND_VERTICAL = "mdi:arrow-expand-vertical"
|
||||
ICON_BATTERY = "mdi:battery"
|
||||
ICON_BRIEFCASE_DOWNLOAD = "mdi:briefcase-download"
|
||||
@ -608,7 +627,9 @@ ICON_CHECK_CIRCLE_OUTLINE = "mdi:check-circle-outline"
|
||||
ICON_CHEMICAL_WEAPON = "mdi:chemical-weapon"
|
||||
ICON_COUNTER = "mdi:counter"
|
||||
ICON_CURRENT_AC = "mdi:current-ac"
|
||||
ICON_DATABASE = "mdi:database"
|
||||
ICON_EMPTY = ""
|
||||
ICON_FINGERPRINT = "mdi:fingerprint"
|
||||
ICON_FLASH = "mdi:flash"
|
||||
ICON_FLASK = "mdi:flask"
|
||||
ICON_FLASK_OUTLINE = "mdi:flask-outline"
|
||||
@ -616,6 +637,7 @@ ICON_FLOWER = "mdi:flower"
|
||||
ICON_GAS_CYLINDER = "mdi:gas-cylinder"
|
||||
ICON_GAUGE = "mdi:gauge"
|
||||
ICON_GRAIN = "mdi:grain"
|
||||
ICON_KEY_PLUS = "mdi:key-plus"
|
||||
ICON_LIGHTBULB = "mdi:lightbulb"
|
||||
ICON_MAGNET = "mdi:magnet"
|
||||
ICON_MOLECULE_CO2 = "mdi:molecule-co2"
|
||||
@ -632,6 +654,7 @@ ICON_RULER = "mdi:ruler"
|
||||
ICON_SCALE = "mdi:scale"
|
||||
ICON_SCALE_BATHROOM = "mdi:scale-bathroom"
|
||||
ICON_SCREEN_ROTATION = "mdi:screen-rotation"
|
||||
ICON_SECURITY = "mdi:security"
|
||||
ICON_SIGN_DIRECTION = "mdi:sign-direction"
|
||||
ICON_SIGNAL = "mdi:signal-distance-variant"
|
||||
ICON_SIGNAL_DISTANCE_VARIANT = "mdi:signal"
|
||||
|
@ -177,6 +177,26 @@ api:
|
||||
kp: 1.0
|
||||
kd: 1.0
|
||||
ki: 1.0
|
||||
- service: fingerprint_grow_enroll
|
||||
variables:
|
||||
finger_id: int
|
||||
num_scans: int
|
||||
then:
|
||||
- fingerprint_grow.enroll:
|
||||
finger_id: !lambda 'return finger_id;'
|
||||
num_scans: !lambda 'return num_scans;'
|
||||
- service: fingerprint_grow_cancel_enroll
|
||||
then:
|
||||
- fingerprint_grow.cancel_enroll:
|
||||
- service: fingerprint_grow_delete
|
||||
variables:
|
||||
finger_id: int
|
||||
then:
|
||||
- fingerprint_grow.delete:
|
||||
finger_id: !lambda 'return finger_id;'
|
||||
- service: fingerprint_grow_delete_all
|
||||
then:
|
||||
- fingerprint_grow.delete_all:
|
||||
|
||||
wifi:
|
||||
ssid: 'MySSID'
|
||||
@ -424,6 +444,19 @@ sensor:
|
||||
id: ph_ezo
|
||||
address: 99
|
||||
unit_of_measurement: 'pH'
|
||||
- platform: fingerprint_grow
|
||||
fingerprint_count:
|
||||
name: "Fingerprint Count"
|
||||
status:
|
||||
name: "Fingerprint Status"
|
||||
capacity:
|
||||
name: "Fingerprint Capacity"
|
||||
security_level:
|
||||
name: "Fingerprint Security Level"
|
||||
last_finger_id:
|
||||
name: "Fingerprint Last Finger ID"
|
||||
last_confidence:
|
||||
name: "Fingerprint Last Confidence"
|
||||
|
||||
time:
|
||||
- platform: homeassistant
|
||||
@ -486,6 +519,8 @@ binary_sensor:
|
||||
- platform: ttp229_bsf
|
||||
channel: 1
|
||||
name: TTP229 BSF Test
|
||||
- platform: fingerprint_grow
|
||||
name: "Fingerprint Enrolling"
|
||||
- platform: custom
|
||||
lambda: |-
|
||||
auto s = new CustomBinarySensor();
|
||||
@ -919,3 +954,33 @@ display:
|
||||
http_request:
|
||||
useragent: esphome/device
|
||||
timeout: 10s
|
||||
|
||||
fingerprint_grow:
|
||||
sensing_pin: 4
|
||||
password: 0x12FE37DC
|
||||
new_password: 0xA65B9840
|
||||
on_finger_scan_matched:
|
||||
- homeassistant.event:
|
||||
event: esphome.${devicename}_fingerprint_grow_finger_scan_matched
|
||||
data:
|
||||
finger_id: !lambda 'return finger_id;'
|
||||
confidence: !lambda 'return confidence;'
|
||||
on_finger_scan_unmatched:
|
||||
- homeassistant.event:
|
||||
event: esphome.${devicename}_fingerprint_grow_finger_scan_unmatched
|
||||
on_enrollment_scan:
|
||||
- homeassistant.event:
|
||||
event: esphome.${devicename}_fingerprint_grow_enrollment_scan
|
||||
data:
|
||||
finger_id: !lambda 'return finger_id;'
|
||||
scan_num: !lambda 'return scan_num;'
|
||||
on_enrollment_done:
|
||||
- homeassistant.event:
|
||||
event: esphome.${devicename}_fingerprint_grow_node_enrollment_done
|
||||
data:
|
||||
finger_id: !lambda 'return finger_id;'
|
||||
on_enrollment_failed:
|
||||
- homeassistant.event:
|
||||
event: esphome.${devicename}_fingerprint_grow_enrollment_failed
|
||||
data:
|
||||
finger_id: !lambda 'return finger_id;'
|
||||
|
Loading…
Reference in New Issue
Block a user