ESPHome  2022.12.8
fingerprint_grow.cpp
Go to the documentation of this file.
1 #include "fingerprint_grow.h"
2 #include "esphome/core/log.h"
3 
4 namespace esphome {
5 namespace fingerprint_grow {
6 
7 static const char *const TAG = "fingerprint_grow";
8 
9 // Based on Adafruit's library: https://github.com/adafruit/Adafruit-Fingerprint-Sensor-Library
10 
12  if (this->enrollment_image_ > this->enrollment_buffers_) {
13  this->finish_enrollment(this->save_fingerprint_());
14  return;
15  }
16 
17  if (this->sensing_pin_ != nullptr) {
18  if (this->sensing_pin_->digital_read()) {
19  ESP_LOGV(TAG, "No touch sensing");
20  this->waiting_removal_ = false;
21  return;
22  }
23  }
24 
25  if (this->waiting_removal_) {
26  if (this->scan_image_(1) == NO_FINGER) {
27  ESP_LOGD(TAG, "Finger removed");
28  this->waiting_removal_ = false;
29  }
30  return;
31  }
32 
33  if (this->enrollment_image_ == 0) {
34  this->scan_and_match_();
35  return;
36  }
37 
38  uint8_t result = this->scan_image_(this->enrollment_image_);
39  if (result == NO_FINGER) {
40  return;
41  }
42  this->waiting_removal_ = true;
43  if (result != OK) {
44  this->finish_enrollment(result);
45  return;
46  }
48  ++this->enrollment_image_;
49 }
50 
52  ESP_LOGCONFIG(TAG, "Setting up Grow Fingerprint Reader...");
53  if (this->check_password_()) {
54  if (this->new_password_ != -1) {
55  if (this->set_password_())
56  return;
57  } else {
58  if (this->get_parameters_())
59  return;
60  }
61  }
62  this->mark_failed();
63 }
64 
65 void FingerprintGrowComponent::enroll_fingerprint(uint16_t finger_id, uint8_t num_buffers) {
66  ESP_LOGI(TAG, "Starting enrollment in slot %d", finger_id);
67  if (this->enrolling_binary_sensor_ != nullptr) {
69  }
70  this->enrollment_slot_ = finger_id;
71  this->enrollment_buffers_ = num_buffers;
72  this->enrollment_image_ = 1;
73 }
74 
76  if (result == OK) {
78  this->get_fingerprint_count_();
79  } else {
81  }
82  this->enrollment_image_ = 0;
83  this->enrollment_slot_ = 0;
84  if (this->enrolling_binary_sensor_ != nullptr) {
86  }
87  ESP_LOGI(TAG, "Finished enrollment");
88 }
89 
91  if (this->sensing_pin_ != nullptr) {
92  ESP_LOGD(TAG, "Scan and match");
93  } else {
94  ESP_LOGV(TAG, "Scan and match");
95  }
96  if (this->scan_image_(1) == OK) {
97  this->waiting_removal_ = true;
98  this->data_ = {SEARCH, 0x01, 0x00, 0x00, (uint8_t)(this->capacity_ >> 8), (uint8_t)(this->capacity_ & 0xFF)};
99  switch (this->send_command_()) {
100  case OK: {
101  ESP_LOGD(TAG, "Fingerprint matched");
102  uint16_t finger_id = ((uint16_t) this->data_[1] << 8) | this->data_[2];
103  uint16_t confidence = ((uint16_t) this->data_[3] << 8) | this->data_[4];
104  if (this->last_finger_id_sensor_ != nullptr) {
105  this->last_finger_id_sensor_->publish_state(finger_id);
106  }
107  if (this->last_confidence_sensor_ != nullptr) {
108  this->last_confidence_sensor_->publish_state(confidence);
109  }
110  this->finger_scan_matched_callback_.call(finger_id, confidence);
111  break;
112  }
113  case NOT_FOUND:
114  ESP_LOGD(TAG, "Fingerprint not matched to any saved slots");
115  this->finger_scan_unmatched_callback_.call();
116  break;
117  }
118  }
119 }
120 
121 uint8_t FingerprintGrowComponent::scan_image_(uint8_t buffer) {
122  if (this->sensing_pin_ != nullptr) {
123  ESP_LOGD(TAG, "Getting image %d", buffer);
124  } else {
125  ESP_LOGV(TAG, "Getting image %d", buffer);
126  }
127  this->data_ = {GET_IMAGE};
128  switch (this->send_command_()) {
129  case OK:
130  break;
131  case NO_FINGER:
132  if (this->sensing_pin_ != nullptr) {
133  ESP_LOGD(TAG, "No finger");
134  } else {
135  ESP_LOGV(TAG, "No finger");
136  }
137  return this->data_[0];
138  case IMAGE_FAIL:
139  ESP_LOGE(TAG, "Imaging error");
140  default:
141  return this->data_[0];
142  }
143 
144  ESP_LOGD(TAG, "Processing image %d", buffer);
145  this->data_ = {IMAGE_2_TZ, buffer};
146  switch (this->send_command_()) {
147  case OK:
148  ESP_LOGI(TAG, "Processed image %d", buffer);
149  break;
150  case IMAGE_MESS:
151  ESP_LOGE(TAG, "Image too messy");
152  break;
153  case FEATURE_FAIL:
154  case INVALID_IMAGE:
155  ESP_LOGE(TAG, "Could not find fingerprint features");
156  break;
157  }
158  return this->data_[0];
159 }
160 
162  ESP_LOGI(TAG, "Creating model");
163  this->data_ = {REG_MODEL};
164  switch (this->send_command_()) {
165  case OK:
166  break;
167  case ENROLL_MISMATCH:
168  ESP_LOGE(TAG, "Scans do not match");
169  default:
170  return this->data_[0];
171  }
172 
173  ESP_LOGI(TAG, "Storing model");
174  this->data_ = {STORE, 0x01, (uint8_t)(this->enrollment_slot_ >> 8), (uint8_t)(this->enrollment_slot_ & 0xFF)};
175  switch (this->send_command_()) {
176  case OK:
177  ESP_LOGI(TAG, "Stored model");
178  break;
179  case BAD_LOCATION:
180  ESP_LOGE(TAG, "Invalid slot");
181  break;
182  case FLASH_ERR:
183  ESP_LOGE(TAG, "Error writing to flash");
184  break;
185  }
186  return this->data_[0];
187 }
188 
190  ESP_LOGD(TAG, "Checking password");
191  this->data_ = {VERIFY_PASSWORD, (uint8_t)(this->password_ >> 24), (uint8_t)(this->password_ >> 16),
192  (uint8_t)(this->password_ >> 8), (uint8_t)(this->password_ & 0xFF)};
193  switch (this->send_command_()) {
194  case OK:
195  ESP_LOGD(TAG, "Password verified");
196  return true;
197  case PASSWORD_FAIL:
198  ESP_LOGE(TAG, "Wrong password");
199  break;
200  }
201  return false;
202 }
203 
205  ESP_LOGI(TAG, "Setting new password: %d", this->new_password_);
206  this->data_ = {SET_PASSWORD, (uint8_t)(this->new_password_ >> 24), (uint8_t)(this->new_password_ >> 16),
207  (uint8_t)(this->new_password_ >> 8), (uint8_t)(this->new_password_ & 0xFF)};
208  if (this->send_command_() == OK) {
209  ESP_LOGI(TAG, "New password successfully set");
210  ESP_LOGI(TAG, "Define the new password in your configuration and reflash now");
211  ESP_LOGW(TAG, "!!!Forgetting the password will render your device unusable!!!");
212  return true;
213  }
214  return false;
215 }
216 
218  ESP_LOGD(TAG, "Getting parameters");
219  this->data_ = {READ_SYS_PARAM};
220  if (this->send_command_() == OK) {
221  ESP_LOGD(TAG, "Got parameters");
222  if (this->status_sensor_ != nullptr) {
223  this->status_sensor_->publish_state(((uint16_t) this->data_[1] << 8) | this->data_[2]);
224  }
225  this->capacity_ = ((uint16_t) this->data_[5] << 8) | this->data_[6];
226  if (this->capacity_sensor_ != nullptr) {
228  }
229  if (this->security_level_sensor_ != nullptr) {
230  this->security_level_sensor_->publish_state(((uint16_t) this->data_[7] << 8) | this->data_[8]);
231  }
232  if (this->enrolling_binary_sensor_ != nullptr) {
234  }
235  this->get_fingerprint_count_();
236  return true;
237  }
238  return false;
239 }
240 
242  ESP_LOGD(TAG, "Getting fingerprint count");
243  this->data_ = {TEMPLATE_COUNT};
244  if (this->send_command_() == OK) {
245  ESP_LOGD(TAG, "Got fingerprint count");
246  if (this->fingerprint_count_sensor_ != nullptr)
247  this->fingerprint_count_sensor_->publish_state(((uint16_t) this->data_[1] << 8) | this->data_[2]);
248  }
249 }
250 
252  ESP_LOGI(TAG, "Deleting fingerprint in slot %d", finger_id);
253  this->data_ = {DELETE, (uint8_t)(finger_id >> 8), (uint8_t)(finger_id & 0xFF), 0x00, 0x01};
254  switch (this->send_command_()) {
255  case OK:
256  ESP_LOGI(TAG, "Deleted fingerprint");
257  this->get_fingerprint_count_();
258  break;
259  case DELETE_FAIL:
260  ESP_LOGE(TAG, "Reader failed to delete fingerprint");
261  break;
262  }
263 }
264 
266  ESP_LOGI(TAG, "Deleting all stored fingerprints");
267  this->data_ = {EMPTY};
268  switch (this->send_command_()) {
269  case OK:
270  ESP_LOGI(TAG, "Deleted all fingerprints");
271  this->get_fingerprint_count_();
272  break;
273  case DB_CLEAR_FAIL:
274  ESP_LOGE(TAG, "Reader failed to clear fingerprint library");
275  break;
276  }
277 }
278 
280  ESP_LOGD(TAG, "Setting LED");
281  if (state) {
282  this->data_ = {LED_ON};
283  } else {
284  this->data_ = {LED_OFF};
285  }
286  switch (this->send_command_()) {
287  case OK:
288  ESP_LOGD(TAG, "LED set");
289  break;
290  case PACKET_RCV_ERR:
291  case TIMEOUT:
292  break;
293  default:
294  ESP_LOGE(TAG, "Try aura_led_control instead");
295  break;
296  }
297 }
298 
299 void FingerprintGrowComponent::aura_led_control(uint8_t state, uint8_t speed, uint8_t color, uint8_t count) {
300  const uint32_t now = millis();
301  const uint32_t elapsed = now - this->last_aura_led_control_;
302  if (elapsed < this->last_aura_led_duration_) {
303  delay(this->last_aura_led_duration_ - elapsed);
304  }
305  ESP_LOGD(TAG, "Setting Aura LED");
306  this->data_ = {AURA_CONFIG, state, speed, color, count};
307  switch (this->send_command_()) {
308  case OK:
309  ESP_LOGD(TAG, "Aura LED set");
310  this->last_aura_led_control_ = millis();
311  this->last_aura_led_duration_ = 10 * speed * count;
312  break;
313  case PACKET_RCV_ERR:
314  case TIMEOUT:
315  break;
316  default:
317  ESP_LOGE(TAG, "Try led_control instead");
318  break;
319  }
320 }
321 
323  this->write((uint8_t)(START_CODE >> 8));
324  this->write((uint8_t)(START_CODE & 0xFF));
325  this->write(this->address_[0]);
326  this->write(this->address_[1]);
327  this->write(this->address_[2]);
328  this->write(this->address_[3]);
329  this->write(COMMAND);
330 
331  uint16_t wire_length = this->data_.size() + 2;
332  this->write((uint8_t)(wire_length >> 8));
333  this->write((uint8_t)(wire_length & 0xFF));
334 
335  uint16_t sum = ((wire_length) >> 8) + ((wire_length) &0xFF) + COMMAND;
336  for (auto data : this->data_) {
337  this->write(data);
338  sum += data;
339  }
340 
341  this->write((uint8_t)(sum >> 8));
342  this->write((uint8_t)(sum & 0xFF));
343 
344  this->data_.clear();
345 
346  uint8_t byte;
347  uint16_t idx = 0, length = 0;
348 
349  for (uint16_t timer = 0; timer < 1000; timer++) {
350  if (this->available() == 0) {
351  delay(1);
352  continue;
353  }
354  byte = this->read();
355  switch (idx) {
356  case 0:
357  if (byte != (uint8_t)(START_CODE >> 8))
358  continue;
359  break;
360  case 1:
361  if (byte != (uint8_t)(START_CODE & 0xFF)) {
362  idx = 0;
363  continue;
364  }
365  break;
366  case 2:
367  case 3:
368  case 4:
369  case 5:
370  if (byte != this->address_[idx - 2]) {
371  idx = 0;
372  continue;
373  }
374  break;
375  case 6:
376  if (byte != ACK) {
377  idx = 0;
378  continue;
379  }
380  break;
381  case 7:
382  length = (uint16_t) byte << 8;
383  break;
384  case 8:
385  length |= byte;
386  break;
387  default:
388  this->data_.push_back(byte);
389  if ((idx - 8) == length) {
390  switch (this->data_[0]) {
391  case OK:
392  case NO_FINGER:
393  case IMAGE_FAIL:
394  case IMAGE_MESS:
395  case FEATURE_FAIL:
396  case NO_MATCH:
397  case NOT_FOUND:
398  case ENROLL_MISMATCH:
399  case BAD_LOCATION:
400  case DELETE_FAIL:
401  case DB_CLEAR_FAIL:
402  case PASSWORD_FAIL:
403  case INVALID_IMAGE:
404  case FLASH_ERR:
405  break;
406  case PACKET_RCV_ERR:
407  ESP_LOGE(TAG, "Reader failed to process request");
408  break;
409  default:
410  ESP_LOGE(TAG, "Unknown response received from reader: %d", this->data_[0]);
411  break;
412  }
413  return this->data_[0];
414  }
415  break;
416  }
417  idx++;
418  }
419  ESP_LOGE(TAG, "No response received from reader");
420  this->data_[0] = TIMEOUT;
421  return TIMEOUT;
422 }
423 
425  ESP_LOGCONFIG(TAG, "GROW_FINGERPRINT_READER:");
426  LOG_UPDATE_INTERVAL(this);
427  LOG_SENSOR(" ", "Fingerprint Count", this->fingerprint_count_sensor_);
428  LOG_SENSOR(" ", "Status", this->status_sensor_);
429  LOG_SENSOR(" ", "Capacity", this->capacity_sensor_);
430  LOG_SENSOR(" ", "Security Level", this->security_level_sensor_);
431  LOG_SENSOR(" ", "Last Finger ID", this->last_finger_id_sensor_);
432  LOG_SENSOR(" ", "Last Confidence", this->last_confidence_sensor_);
433 }
434 
435 } // namespace fingerprint_grow
436 } // namespace esphome
CallbackManager< void(uint16_t, uint16_t)> finger_scan_matched_callback_
CallbackManager< void(uint8_t, uint16_t)> enrollment_scan_callback_
int speed
Definition: fan.h:35
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:26
void publish_state(float state)
Publish a new state to the front-end.
Definition: sensor.cpp:72
void publish_state(bool state)
Publish a new state to the front-end.
void enroll_fingerprint(uint16_t finger_id, uint8_t num_buffers)
CallbackManager< void(uint16_t)> enrollment_failed_callback_
virtual bool digital_read()=0
binary_sensor::BinarySensor * enrolling_binary_sensor_
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:112
CallbackManager< void(uint16_t)> enrollment_done_callback_
Definition: a4988.cpp:4
void aura_led_control(uint8_t state, uint8_t speed, uint8_t color, uint8_t count)
size_t write(uint8_t data)
Definition: uart.h:52
bool state
Definition: fan.h:34
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:27