From 96461d98abfc28e5548abb58ac8902f9d5c2c767 Mon Sep 17 00:00:00 2001 From: Jim McKeown Date: Tue, 18 Apr 2023 04:32:21 +0700 Subject: [PATCH 01/35] Example with image rendering functionality Example from modified fingerprint_simpletest.py adding image viewing and saving functionality using matplotlib and numpy. This has been tested on a Linux PC but should work under Windows or MacOS. --- examples/fingerprint_picturetest.py | 247 ++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 examples/fingerprint_picturetest.py diff --git a/examples/fingerprint_picturetest.py b/examples/fingerprint_picturetest.py new file mode 100644 index 0000000..3c0bbd3 --- /dev/null +++ b/examples/fingerprint_picturetest.py @@ -0,0 +1,247 @@ +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT + +import time +import board +import busio +from digitalio import DigitalInOut, Direction +import adafruit_fingerprint +import numpy as np +from matplotlib import pyplot as plt + + +#led = DigitalInOut(board.D13) +#led.direction = Direction.OUTPUT + +# This has not been tested: +#uart = busio.UART(board.TX, board.RX, baudrate=57600) + +# If using with a computer such as Linux/RaspberryPi, Mac, Windows with USB/serial converter: +import serial +uart = serial.Serial("/dev/ttyACM0", baudrate=57600, timeout=1) + +# If using with Linux/Raspberry Pi and hardware UART: +# import serial +# uart = serial.Serial("/dev/ttyS0", baudrate=57600, timeout=1) + +finger = adafruit_fingerprint.Adafruit_Fingerprint(uart) + +################################################## + + +def get_fingerprint(): + """Get a finger print image, template it, and see if it matches!""" + print("Waiting for image...") + while finger.get_image() != adafruit_fingerprint.OK: + pass + print("Templating...") + if finger.image_2_tz(1) != adafruit_fingerprint.OK: + return False + print("Searching...") + if finger.finger_search() != adafruit_fingerprint.OK: + return False + return True + + +# pylint: disable=too-many-branches +def get_fingerprint_detail(): + """Get a finger print image, template it, and see if it matches! + This time, print out each error instead of just returning on failure""" + print("Getting image...", end="") + i = finger.get_image() + if i == adafruit_fingerprint.OK: + print("Image taken") + else: + if i == adafruit_fingerprint.NOFINGER: + print("No finger detected") + elif i == adafruit_fingerprint.IMAGEFAIL: + print("Imaging error") + else: + print("Other error") + return False + + print("Templating...", end="") + i = finger.image_2_tz(1) + if i == adafruit_fingerprint.OK: + print("Templated") + else: + if i == adafruit_fingerprint.IMAGEMESS: + print("Image too messy") + elif i == adafruit_fingerprint.FEATUREFAIL: + print("Could not identify features") + elif i == adafruit_fingerprint.INVALIDIMAGE: + print("Image invalid") + else: + print("Other error") + return False + + print("Searching...", end="") + i = finger.finger_fast_search() + # pylint: disable=no-else-return + # This block needs to be refactored when it can be tested. + if i == adafruit_fingerprint.OK: + print("Found fingerprint!") + return True + else: + if i == adafruit_fingerprint.NOTFOUND: + print("No match found") + else: + print("Other error") + return False + +def get_fingerprint_photo(): + """Get and show fingerprint image""" + print("Waiting for image...") + while finger.get_image() != adafruit_fingerprint.OK: + pass + print("Got image...Transferring image data...") + imgList = finger.get_fpdata('image', 2) + imgArray = np.zeros(73728,np.uint8) + for i, val in enumerate(imgList): + imgArray[(i * 2)] = (val & 240) + imgArray[(i * 2) + 1] = (val & 15) * 16 + imgArray = np.reshape(imgArray, (288, 256)) + plt.title("Fingerprint Image") + plt.imshow(imgArray) + plt.show() + +def get_fingerprint_preview(): + """Get a finger print image, show it, template it, and see if it matches!""" + print("Waiting for image...") + while finger.get_image() != adafruit_fingerprint.OK: + pass + print("Got image...Transferring image data...") + imgList = finger.get_fpdata('image', 2) + imgArray = np.zeros(73728,np.uint8) + for i, val in enumerate(imgList): + imgArray[(i * 2)] = (val & 240) + imgArray[(i * 2) + 1] = (val & 15) * 16 + imgArray = np.reshape(imgArray, (288, 256)) + plt.title("Fingerprint Image") + plt.imshow(imgArray) + plt.show() + print("Templating...") + if finger.image_2_tz(1) != adafruit_fingerprint.OK: + return False + print("Searching...") + if finger.finger_search() != adafruit_fingerprint.OK: + return False + return True + +# pylint: disable=too-many-statements +def enroll_finger(location): + """Take a 2 finger images and template it, then store in 'location'""" + for fingerimg in range(1, 3): + if fingerimg == 1: + print("Place finger on sensor...", end="") + else: + print("Place same finger again...", end="") + + while True: + i = finger.get_image() + if i == adafruit_fingerprint.OK: + print("Image taken") + break + if i == adafruit_fingerprint.NOFINGER: + print(".", end="") + elif i == adafruit_fingerprint.IMAGEFAIL: + print("Imaging error") + return False + else: + print("Other error") + return False + + print("Templating...", end="") + i = finger.image_2_tz(fingerimg) + if i == adafruit_fingerprint.OK: + print("Templated") + else: + if i == adafruit_fingerprint.IMAGEMESS: + print("Image too messy") + elif i == adafruit_fingerprint.FEATUREFAIL: + print("Could not identify features") + elif i == adafruit_fingerprint.INVALIDIMAGE: + print("Image invalid") + else: + print("Other error") + return False + + if fingerimg == 1: + print("Remove finger") + time.sleep(1) + while i != adafruit_fingerprint.NOFINGER: + i = finger.get_image() + + print("Creating model...", end="") + i = finger.create_model() + if i == adafruit_fingerprint.OK: + print("Created") + else: + if i == adafruit_fingerprint.ENROLLMISMATCH: + print("Prints did not match") + else: + print("Other error") + return False + + print("Storing model #%d..." % location, end="") + i = finger.store_model(location) + if i == adafruit_fingerprint.OK: + print("Stored") + else: + if i == adafruit_fingerprint.BADLOCATION: + print("Bad storage location") + elif i == adafruit_fingerprint.FLASHERR: + print("Flash storage error") + else: + print("Other error") + return False + + return True + + +################################################## + + +def get_num(): + """Use input() to get a valid number from 1 to 127. Retry till success!""" + i = 0 + while (i > 127) or (i < 1): + try: + i = int(input("Enter ID # from 1-127: ")) + except ValueError: + pass + return i + + +while True: + print("----------------") + if finger.read_templates() != adafruit_fingerprint.OK: + raise RuntimeError("Failed to read templates") + print("Fingerprint templates:", finger.templates) + print("e) enroll print") + print("f) find print") + print("d) delete print") + print("v) view print") + print("p) preview and find print") + print("----------------") + c = input("> ") + + if c == "e": + enroll_finger(get_num()) + if c == "f": + if get_fingerprint(): + print("Detected #", finger.finger_id, "with confidence", finger.confidence) + else: + print("Finger not found") + if c == "d": + if finger.delete_model(get_num()) == adafruit_fingerprint.OK: + print("Deleted!") + else: + print("Failed to delete") + if c == "v": + get_fingerprint_photo() + if c == "p": + if get_fingerprint_preview(): + print("Detected #", finger.finger_id, "with confidence", finger.confidence) + else: + print("Finger not found") From 859b5ac5a957571d788790c9955a7431cd31d84b Mon Sep 17 00:00:00 2001 From: Jim McKeown Date: Fri, 28 Apr 2023 12:24:20 +0700 Subject: [PATCH 02/35] Update fingerprint_picturetest.py --- examples/fingerprint_picturetest.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/examples/fingerprint_picturetest.py b/examples/fingerprint_picturetest.py index 3c0bbd3..c2ebe1f 100644 --- a/examples/fingerprint_picturetest.py +++ b/examples/fingerprint_picturetest.py @@ -1,14 +1,16 @@ # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT +# Added 'View Print' and 'Preview and Find Print' functions to +# example code fingerprint_simpletest.py + import time -import board -import busio -from digitalio import DigitalInOut, Direction -import adafruit_fingerprint +# import board +# import busio +# from digitalio import DigitalInOut, Direction import numpy as np from matplotlib import pyplot as plt - +import adafruit_fingerprint #led = DigitalInOut(board.D13) #led.direction = Direction.OUTPUT @@ -17,6 +19,7 @@ #uart = busio.UART(board.TX, board.RX, baudrate=57600) # If using with a computer such as Linux/RaspberryPi, Mac, Windows with USB/serial converter: +# Edit ttyACM0 to your USB/serial port import serial uart = serial.Serial("/dev/ttyACM0", baudrate=57600, timeout=1) @@ -103,7 +106,7 @@ def get_fingerprint_photo(): imgArray = np.reshape(imgArray, (288, 256)) plt.title("Fingerprint Image") plt.imshow(imgArray) - plt.show() + plt.show(block = False) def get_fingerprint_preview(): """Get a finger print image, show it, template it, and see if it matches!""" @@ -119,7 +122,7 @@ def get_fingerprint_preview(): imgArray = np.reshape(imgArray, (288, 256)) plt.title("Fingerprint Image") plt.imshow(imgArray) - plt.show() + plt.show(block = False) print("Templating...") if finger.image_2_tz(1) != adafruit_fingerprint.OK: return False From 55dd65e835a47cd0cad7ca13a3cf6b17c1bf3b1c Mon Sep 17 00:00:00 2001 From: Jim McKeown Date: Fri, 28 Apr 2023 12:41:47 +0700 Subject: [PATCH 03/35] fixed import order error Fixed import order error. pyplot changed to non-blocking to run properly from the command line. --- examples/fingerprint_picturetest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fingerprint_picturetest.py b/examples/fingerprint_picturetest.py index c2ebe1f..d10151e 100644 --- a/examples/fingerprint_picturetest.py +++ b/examples/fingerprint_picturetest.py @@ -10,6 +10,7 @@ # from digitalio import DigitalInOut, Direction import numpy as np from matplotlib import pyplot as plt +import serial import adafruit_fingerprint #led = DigitalInOut(board.D13) @@ -20,7 +21,6 @@ # If using with a computer such as Linux/RaspberryPi, Mac, Windows with USB/serial converter: # Edit ttyACM0 to your USB/serial port -import serial uart = serial.Serial("/dev/ttyACM0", baudrate=57600, timeout=1) # If using with Linux/Raspberry Pi and hardware UART: From 48fc1fc6483e14467a087e0bcd0a15a3e38346c5 Mon Sep 17 00:00:00 2001 From: Jim McKeown Date: Fri, 28 Apr 2023 13:06:23 +0700 Subject: [PATCH 04/35] black reformatted --- examples/fingerprint_picturetest.py | 34 ++++++++++++++++------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/examples/fingerprint_picturetest.py b/examples/fingerprint_picturetest.py index d10151e..abb6dd9 100644 --- a/examples/fingerprint_picturetest.py +++ b/examples/fingerprint_picturetest.py @@ -1,10 +1,11 @@ # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT -# Added 'View Print' and 'Preview and Find Print' functions to +# Added 'View Print' and 'Preview and Find Print' functions to # example code fingerprint_simpletest.py import time + # import board # import busio # from digitalio import DigitalInOut, Direction @@ -13,11 +14,11 @@ import serial import adafruit_fingerprint -#led = DigitalInOut(board.D13) -#led.direction = Direction.OUTPUT +# led = DigitalInOut(board.D13) +# led.direction = Direction.OUTPUT # This has not been tested: -#uart = busio.UART(board.TX, board.RX, baudrate=57600) +# uart = busio.UART(board.TX, board.RX, baudrate=57600) # If using with a computer such as Linux/RaspberryPi, Mac, Windows with USB/serial converter: # Edit ttyACM0 to your USB/serial port @@ -92,44 +93,47 @@ def get_fingerprint_detail(): print("Other error") return False + def get_fingerprint_photo(): """Get and show fingerprint image""" print("Waiting for image...") while finger.get_image() != adafruit_fingerprint.OK: pass print("Got image...Transferring image data...") - imgList = finger.get_fpdata('image', 2) - imgArray = np.zeros(73728,np.uint8) + imgList = finger.get_fpdata("image", 2) + imgArray = np.zeros(73728, np.uint8) for i, val in enumerate(imgList): - imgArray[(i * 2)] = (val & 240) + imgArray[(i * 2)] = val & 240 imgArray[(i * 2) + 1] = (val & 15) * 16 imgArray = np.reshape(imgArray, (288, 256)) plt.title("Fingerprint Image") plt.imshow(imgArray) - plt.show(block = False) - + plt.show(block=False) + + def get_fingerprint_preview(): """Get a finger print image, show it, template it, and see if it matches!""" print("Waiting for image...") while finger.get_image() != adafruit_fingerprint.OK: pass print("Got image...Transferring image data...") - imgList = finger.get_fpdata('image', 2) - imgArray = np.zeros(73728,np.uint8) + imgList = finger.get_fpdata("image", 2) + imgArray = np.zeros(73728, np.uint8) for i, val in enumerate(imgList): - imgArray[(i * 2)] = (val & 240) + imgArray[(i * 2)] = val & 240 imgArray[(i * 2) + 1] = (val & 15) * 16 imgArray = np.reshape(imgArray, (288, 256)) plt.title("Fingerprint Image") plt.imshow(imgArray) - plt.show(block = False) + plt.show(block=False) print("Templating...") if finger.image_2_tz(1) != adafruit_fingerprint.OK: return False print("Searching...") if finger.finger_search() != adafruit_fingerprint.OK: return False - return True + return True + # pylint: disable=too-many-statements def enroll_finger(location): @@ -247,4 +251,4 @@ def get_num(): if get_fingerprint_preview(): print("Detected #", finger.finger_id, "with confidence", finger.confidence) else: - print("Finger not found") + print("Finger not found") From bdb112828d018efb21d28317c4630e579601755f Mon Sep 17 00:00:00 2001 From: Jim McKeown Date: Sat, 29 Apr 2023 07:23:27 +0700 Subject: [PATCH 05/35] Update fingerprint_picturetest.py --- examples/fingerprint_picturetest.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/fingerprint_picturetest.py b/examples/fingerprint_picturetest.py index abb6dd9..96f8d64 100644 --- a/examples/fingerprint_picturetest.py +++ b/examples/fingerprint_picturetest.py @@ -1,8 +1,7 @@ -# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-FileCopyrightText: 2023 Jim McKeown # SPDX-License-Identifier: MIT -# Added 'View Print' and 'Preview and Find Print' functions to -# example code fingerprint_simpletest.py +"""Added 'View Print' and 'Preview and Find Print' to fingerprint_simpletest.py""" import time From c6996ed8e933bb3255cbba5ed50cbb221ff420ba Mon Sep 17 00:00:00 2001 From: Jim McKeown Date: Sat, 29 Apr 2023 08:15:19 +0700 Subject: [PATCH 06/35] Update optional_requirements.txt --- optional_requirements.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/optional_requirements.txt b/optional_requirements.txt index d4e27c4..78fd9ca 100644 --- a/optional_requirements.txt +++ b/optional_requirements.txt @@ -1,3 +1,7 @@ # SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries # # SPDX-License-Identifier: Unlicense + +numpy +pyplot from matplotlib +serial From b76f8d6c05235527b9a5a7b84eee5e3af60ac094 Mon Sep 17 00:00:00 2001 From: Jim McKeown Date: Sat, 29 Apr 2023 08:19:56 +0700 Subject: [PATCH 07/35] Update optional_requirements.txt --- optional_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/optional_requirements.txt b/optional_requirements.txt index 78fd9ca..a8b48bb 100644 --- a/optional_requirements.txt +++ b/optional_requirements.txt @@ -3,5 +3,5 @@ # SPDX-License-Identifier: Unlicense numpy -pyplot from matplotlib +matplotlib serial From 6d0d17bae7bd56813f9ba248c0b3dc74171c3112 Mon Sep 17 00:00:00 2001 From: Jim McKeown Date: Sat, 29 Apr 2023 08:41:50 +0700 Subject: [PATCH 08/35] Update fingerprint_picturetest.py --- examples/fingerprint_picturetest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fingerprint_picturetest.py b/examples/fingerprint_picturetest.py index 96f8d64..6639618 100644 --- a/examples/fingerprint_picturetest.py +++ b/examples/fingerprint_picturetest.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT """Added 'View Print' and 'Preview and Find Print' to fingerprint_simpletest.py""" - +"""This example only works on single board computers with the use of Blinka""" import time # import board From a13159e0a848b416d879e016064d7108ef63b353 Mon Sep 17 00:00:00 2001 From: Jim McKeown Date: Sat, 29 Apr 2023 08:47:17 +0700 Subject: [PATCH 09/35] Update fingerprint_picturetest.py --- examples/fingerprint_picturetest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/fingerprint_picturetest.py b/examples/fingerprint_picturetest.py index 6639618..de02609 100644 --- a/examples/fingerprint_picturetest.py +++ b/examples/fingerprint_picturetest.py @@ -1,10 +1,7 @@ # SPDX-FileCopyrightText: 2023 Jim McKeown # SPDX-License-Identifier: MIT -"""Added 'View Print' and 'Preview and Find Print' to fingerprint_simpletest.py""" -"""This example only works on single board computers with the use of Blinka""" import time - # import board # import busio # from digitalio import DigitalInOut, Direction @@ -13,6 +10,9 @@ import serial import adafruit_fingerprint +"""Added 'View Print' and 'Preview and Find Print' to fingerprint_simpletest.py""" +"""This example only works on single board computers with the use of Blinka""" + # led = DigitalInOut(board.D13) # led.direction = Direction.OUTPUT From 11c5754502a5c98f7dbe8ef81e250c126b79abb6 Mon Sep 17 00:00:00 2001 From: Jim McKeown Date: Sat, 29 Apr 2023 09:06:01 +0700 Subject: [PATCH 10/35] Update fingerprint_picturetest.py --- examples/fingerprint_picturetest.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/fingerprint_picturetest.py b/examples/fingerprint_picturetest.py index de02609..fb17b2d 100644 --- a/examples/fingerprint_picturetest.py +++ b/examples/fingerprint_picturetest.py @@ -2,9 +2,6 @@ # SPDX-License-Identifier: MIT import time -# import board -# import busio -# from digitalio import DigitalInOut, Direction import numpy as np from matplotlib import pyplot as plt import serial From 601fd8a8b6c111e6c67c6babbd5defb9294a7445 Mon Sep 17 00:00:00 2001 From: Jim McKeown Date: Thu, 4 May 2023 16:18:01 +0700 Subject: [PATCH 11/35] Update optional_requirements.txt --- optional_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/optional_requirements.txt b/optional_requirements.txt index a8b48bb..7efc06e 100644 --- a/optional_requirements.txt +++ b/optional_requirements.txt @@ -4,4 +4,4 @@ numpy matplotlib -serial +pyserial From b881b1338c471df68f0959f6aaf22200461fcfaa Mon Sep 17 00:00:00 2001 From: Jim McKeown Date: Thu, 4 May 2023 16:45:25 +0700 Subject: [PATCH 12/35] Update fingerprint_picturetest.py --- examples/fingerprint_picturetest.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/examples/fingerprint_picturetest.py b/examples/fingerprint_picturetest.py index fb17b2d..c733c79 100644 --- a/examples/fingerprint_picturetest.py +++ b/examples/fingerprint_picturetest.py @@ -1,15 +1,28 @@ # SPDX-FileCopyrightText: 2023 Jim McKeown # SPDX-License-Identifier: MIT +""" +This example shows the basic functionality to: +Show the devices fingerprint slots that have fingerprints enrolled. +Enroll a fingerprint in an existing or new fingerprint slot. +Try to find a fingerprint in the existing list of enrolled fingerprints. +Delete an enrolled fingerprint. +View the image of a fingerprint. +Preview the image of a fingerprint and then try to find the fingerprint +in the existing list of enrolled fingerprints. + +Please note that this example only works on single board computers +with the use of Blinka. + +This example is based on fingerprint_simpletest.py +""" + import time import numpy as np from matplotlib import pyplot as plt import serial import adafruit_fingerprint -"""Added 'View Print' and 'Preview and Find Print' to fingerprint_simpletest.py""" -"""This example only works on single board computers with the use of Blinka""" - # led = DigitalInOut(board.D13) # led.direction = Direction.OUTPUT From 78adf78ecc3df0a20f9994e93fd5213f316bfb58 Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Tue, 23 May 2023 23:01:29 -0400 Subject: [PATCH 13/35] Update .pylintrc, fix jQuery for docs --- .pylintrc | 2 +- docs/conf.py | 1 + docs/requirements.txt | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.pylintrc b/.pylintrc index 40208c3..f945e92 100644 --- a/.pylintrc +++ b/.pylintrc @@ -396,4 +396,4 @@ min-public-methods=1 # Exceptions that will emit a warning when being caught. Defaults to # "Exception" -overgeneral-exceptions=Exception +overgeneral-exceptions=builtins.Exception diff --git a/docs/conf.py b/docs/conf.py index 1159b2b..b71fa8d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,6 +17,7 @@ # ones. extensions = [ "sphinx.ext.autodoc", + "sphinxcontrib.jquery", "sphinx.ext.intersphinx", "sphinx.ext.viewcode", ] diff --git a/docs/requirements.txt b/docs/requirements.txt index 88e6733..797aa04 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -3,3 +3,4 @@ # SPDX-License-Identifier: Unlicense sphinx>=4.0.0 +sphinxcontrib-jquery From c11eded825135f74a190098d4c7a181581e19e7c Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 18 Sep 2023 16:24:05 -0500 Subject: [PATCH 14/35] "fix rtd theme " --- docs/conf.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index b71fa8d..46ca9c6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -97,19 +97,10 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -on_rtd = os.environ.get("READTHEDOCS", None) == "True" - -if not on_rtd: # only import and set the theme if we're building docs locally - try: - import sphinx_rtd_theme - - html_theme = "sphinx_rtd_theme" - html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] - except: - html_theme = "default" - html_theme_path = ["."] -else: - html_theme_path = ["."] +import sphinx_rtd_theme + +html_theme = "sphinx_rtd_theme" +html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, From c57990eb4f9ae8d7103201a9e0c870c14cd9d96e Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 16 Oct 2023 14:30:31 -0500 Subject: [PATCH 15/35] unpin sphinx and add sphinx-rtd-theme to docs reqs Signed-off-by: foamyguy --- docs/requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 797aa04..979f568 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,5 +2,6 @@ # # SPDX-License-Identifier: Unlicense -sphinx>=4.0.0 +sphinx sphinxcontrib-jquery +sphinx-rtd-theme From cbe965d781cd6eef4599bb7655be15b2f9490835 Mon Sep 17 00:00:00 2001 From: itsFDavid Date: Wed, 2 Oct 2024 19:02:31 -0600 Subject: [PATCH 16/35] add program to compare template with fingerprint folfer --- ...nt_template_folder_compare_with_file.py.py | 312 ++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 examples/fingerprint_template_folder_compare_with_file.py.py diff --git a/examples/fingerprint_template_folder_compare_with_file.py.py b/examples/fingerprint_template_folder_compare_with_file.py.py new file mode 100644 index 0000000..31e0ba6 --- /dev/null +++ b/examples/fingerprint_template_folder_compare_with_file.py.py @@ -0,0 +1,312 @@ +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +`fingerprint_template_folder_compare_with_file.py` +==================================================== + +This is an example program to demo storing fingerprint templates in a folder. It also allows +comparing a newly obtained print with one stored in the folder in previous step. This is helpful +when fingerprint templates are stored centrally (not on sensor's flash memory) and shared +between multiple sensors. + +* Author(s): itsFDavid + +Implementation Notes +-------------------- +This program was used on others sensor of fingerprint generics and everything turned out to be as expected, +so this program was tested with Raspsberry Pi Zero 2" + +""" +import time +from PIL import Image +import os + +##################### Settings of serial port + +import serial +import adafruit_fingerprint + +#import board +#import busio + +# import board (if you are using a micropython board) +# uart = busio.UART(board.TX, board.RX, baudrate=57600) + +# If using with a computer such as Linux/RaspberryPi, Mac, Windows with USB/serial converter: +# uart = serial.Serial("COM6", baudrate=57600, timeout=1) + +# If using with Linux/Raspberry Pi and hardware UART: +uart = serial.Serial("/dev/ttyUSB0", baudrate=57600, timeout=1) + +# If using with Linux/Raspberry Pi 3 with pi3-disable-bte +# uart = serial.Serial("/dev/ttyAMA0", baudrate=57600, timeout=1) + +finger = adafruit_fingerprint.Adafruit_Fingerprint(uart) + +################################################## + + +# Carpeta donde se almacenan las plantillas de huellas +FINGERPRINT_FOLDER = "fingerprint/" + +################################################## +# Enrrols and verification functions +################################################## + +def get_fingerprint(): + """get image to fingerprint sensor for search, process for a match""" + print("Wait finger..") + while finger.get_image() != adafruit_fingerprint.OK: + pass + print("Process image...") + if finger.image_2_tz(1) != adafruit_fingerprint.OK: + return False + print("Searching coincidences...") + if finger.finger_search() != adafruit_fingerprint.OK: + return False + return True + +def get_fingerprint_detail(): + """Get image to fingerprint for process and return errors.""" + print("Wait finger..", end="") + i = finger.get_image() + if i == adafruit_fingerprint.OK: + print("Image captured") + else: + print("Error capturing image") + return False + + print("Process image...", end="") + i = finger.image_2_tz(1) + if i == adafruit_fingerprint.OK: + print("Image processed") + else: + print("Error processing image") + return False + + print("Searching coincidences...", end="") + i = finger.finger_fast_search() + if i == adafruit_fingerprint.OK: + print("¡Fingerprint found!") + return True + else: + print("Fingerprint not found") + return False + +def enroll_finger(location): + """Enroll a finger with the fingerprint sensor and store it in the given location specific.""" + for fingerimg in range(1, 3): + if fingerimg == 1: + print("Please put your finger on sensor...", end="") + else: + print("Put same finger...", end="") + + while True: + i = finger.get_image() + if i == adafruit_fingerprint.OK: + print("Image captured") + break + if i == adafruit_fingerprint.NOFINGER: + print(".", end="") + else: + print("Error capturing image") + return False + + print("Process image...", end="") + i = finger.image_2_tz(fingerimg) + if i == adafruit_fingerprint.OK: + print("Imagen procesed") + else: + print("Error processing image") + return False + + if fingerimg == 1: + print("Remove finger") + time.sleep(1) + while i != adafruit_fingerprint.NOFINGER: + i = finger.get_image() + + print("Creating model..", end="") + i = finger.create_model() + if i == adafruit_fingerprint.OK: + print("Model created") + else: + print("Error creating model") + return False + + print("Storing in that location #%d..." % location, end="") + i = finger.store_model(location) + if i == adafruit_fingerprint.OK: + print("Model stored") + else: + print("Error storing model") + return False + + return True + +################################################## +# Save and Compare from File Functions +################################################## + +def save_fingerprint_image(filename): + """Scan your fingerprint and save the image to a file.""" + while finger.get_image(): + pass + + img = Image.new("L", (256, 288), "white") + pixeldata = img.load() + mask = 0b00001111 + result = finger.get_fpdata(sensorbuffer="image") + + x, y = 0, 0 + for i in range(len(result)): + pixeldata[x, y] = (int(result[i]) >> 4) * 17 + x += 1 + pixeldata[x, y] = (int(result[i]) & mask) * 17 + if x == 255: + x = 0 + y += 1 + else: + x += 1 + + if not img.save(filename): + return True + return False + +def enroll_save_to_file(): + """Scan your fingerprint and save the image to a file""" + for fingerimg in range(1, 3): + if fingerimg == 1: + print("Please put your finger on sensor...", end="") + else: + print("Put same finger..", end="") + + while True: + i = finger.get_image() + if i == adafruit_fingerprint.OK: + print("Image captured") + break + if i == adafruit_fingerprint.NOFINGER: + print(".", end="") + else: + print("Error capturing image") + return False + + print("Process image...", end="") + i = finger.image_2_tz(fingerimg) + if i == adafruit_fingerprint.OK: + print("Image processed") + else: + print("Error processing image") + return False + + if fingerimg == 1: + print("Remove finger") + while i != adafruit_fingerprint.NOFINGER: + i = finger.get_image() + + print("Creating model...", end="") + i = finger.create_model() + if i == adafruit_fingerprint.OK: + print("Model create") + else: + print("Error creating model") + return False + + print("Storing template...") + data = finger.get_fpdata("char", 1) + # Guardar la plantilla con un nombre único basado en la hora actual + filename = os.path.join(FINGERPRINT_FOLDER, f"template_{int(time.time())}.dat") + with open(filename, "wb") as file: + file.write(bytearray(data)) + print(f"Template saved on {filename}") + + return True + +def fingerprint_check_folder(): + """Compare fingerprint with all files in the fingerprint folder.""" + print("Wait for fingerprint...") + while finger.get_image() != adafruit_fingerprint.OK: + pass + print("Process image...") + if finger.image_2_tz(1) != adafruit_fingerprint.OK: + return False + + print("Searching coincidences on the template's folder...", end="") + found_match = False + matched_filename = None + + for filename in os.listdir(FINGERPRINT_FOLDER): + if filename.endswith(".dat"): + file_path = os.path.join(FINGERPRINT_FOLDER, filename) + with open(file_path, "rb") as file: + data = file.read() + finger.send_fpdata(list(data), "char", 2) + i = finger.compare_templates() + if i == adafruit_fingerprint.OK: + matched_filename = filename + found_match = True + break # Detener la búsqueda después de encontrar una coincidencia + + if found_match: + print(f"¡Fingerprint match the template in the file {matched_filename}!") + else: + print("Not match found") + + return found_match + +################################################## +# Main cycle of the program +################################################## + +while True: + print("----------------") + if finger.read_templates() != adafruit_fingerprint.OK: + raise RuntimeError("Could not be read the templates") + print("Templates of fingerprints: ", finger.templates) + if finger.count_templates() != adafruit_fingerprint.OK: + raise RuntimeError("Could not be counted the templates") + print("Number of templates found: ", finger.template_count) + if finger.read_sysparam() != adafruit_fingerprint.OK: + raise RuntimeError("Could not be obtained params of system.") + print("Size of template library ", finger.library_size) + print("e) Enrrol fingerprint") + print("f) Search fingerprint") + print("d) Delete fingerprint") + print("s) Store image of fingerprint") + print("cf) Compare template with file") + print("esf) Enrrol and save in file") + print("r) Reset library") + print("q) Exit") + print("----------------") + c = input("> ") + + if c == "e": + enroll_finger(get_num(finger.library_size)) + if c == "f": + if get_fingerprint(): + print("Fingerprint detected with ID #", finger.finger_id, "and confidence", finger.confidence) + else: + print("Fingerprint not found") + if c == "d": + if finger.delete_model(get_num(finger.library_size)) == adafruit_fingerprint.OK: + print("¡Deleted!") + else: + print("Error deleting") + if c == "s": + if save_fingerprint_image("fingerprint.png"): + print("Image of fingerpriint") + else: + print("Error storing an image") + if c == "cf": + fingerprint_check_folder() + if c == "esf": + enroll_save_to_file() + if c == "r": + if finger.empty_library() == adafruit_fingerprint.OK: + print("¡Empty Library!") + else: + print("Error emptying library") + if c == "q": + print("Leavinf of fingerprint program") + raise SystemExit \ No newline at end of file From 19438ee586d4783e2a7812772c31ec6026dcdb8b Mon Sep 17 00:00:00 2001 From: itsFDavid Date: Wed, 2 Oct 2024 19:14:49 -0600 Subject: [PATCH 17/35] update this program for to pass tests --- ...ingerprint_template_folder_compare_with_file.py.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/fingerprint_template_folder_compare_with_file.py.py b/examples/fingerprint_template_folder_compare_with_file.py.py index 31e0ba6..4c535cd 100644 --- a/examples/fingerprint_template_folder_compare_with_file.py.py +++ b/examples/fingerprint_template_folder_compare_with_file.py.py @@ -13,13 +13,15 @@ Implementation Notes -------------------- -This program was used on others sensor of fingerprint generics and everything turned out to be as expected, +This program was used on others sensor of fingerprint, +generics and everything turned out to be as expected, so this program was tested with Raspsberry Pi Zero 2" """ +import os import time from PIL import Image -import os + ##################### Settings of serial port @@ -89,9 +91,7 @@ def get_fingerprint_detail(): if i == adafruit_fingerprint.OK: print("¡Fingerprint found!") return True - else: - print("Fingerprint not found") - return False + return False def enroll_finger(location): """Enroll a finger with the fingerprint sensor and store it in the given location specific.""" @@ -289,6 +289,7 @@ def fingerprint_check_folder(): else: print("Fingerprint not found") if c == "d": + """"get_num is a function that returns a number from 0 to 127""" if finger.delete_model(get_num(finger.library_size)) == adafruit_fingerprint.OK: print("¡Deleted!") else: From 00ac1b99a096f90e0705f9ee75b6d788c5b9c9e0 Mon Sep 17 00:00:00 2001 From: itsFDavid Date: Fri, 4 Oct 2024 22:25:34 -0600 Subject: [PATCH 18/35] Refactor code for improved performance --- ...nt_template_folder_compare_with_file.py.py | 151 +++++++++--------- 1 file changed, 77 insertions(+), 74 deletions(-) diff --git a/examples/fingerprint_template_folder_compare_with_file.py.py b/examples/fingerprint_template_folder_compare_with_file.py.py index 4c535cd..9d33f15 100644 --- a/examples/fingerprint_template_folder_compare_with_file.py.py +++ b/examples/fingerprint_template_folder_compare_with_file.py.py @@ -5,7 +5,7 @@ ==================================================== This is an example program to demo storing fingerprint templates in a folder. It also allows -comparing a newly obtained print with one stored in the folder in previous step. This is helpful +comparing a newly obtained print with one stored in the folder in the previous step. This is helpful when fingerprint templates are stored centrally (not on sensor's flash memory) and shared between multiple sensors. @@ -13,64 +13,68 @@ Implementation Notes -------------------- -This program was used on others sensor of fingerprint, -generics and everything turned out to be as expected, -so this program was tested with Raspsberry Pi Zero 2" - +This program was used on other fingerprint sensors, +and everything worked as expected, including testing with Raspberry Pi Zero 2. """ + import os import time from PIL import Image - -##################### Settings of serial port +##################### Settings for the serial port import serial import adafruit_fingerprint -#import board -#import busio - -# import board (if you are using a micropython board) -# uart = busio.UART(board.TX, board.RX, baudrate=57600) - # If using with a computer such as Linux/RaspberryPi, Mac, Windows with USB/serial converter: # uart = serial.Serial("COM6", baudrate=57600, timeout=1) # If using with Linux/Raspberry Pi and hardware UART: uart = serial.Serial("/dev/ttyUSB0", baudrate=57600, timeout=1) -# If using with Linux/Raspberry Pi 3 with pi3-disable-bte -# uart = serial.Serial("/dev/ttyAMA0", baudrate=57600, timeout=1) - finger = adafruit_fingerprint.Adafruit_Fingerprint(uart) ################################################## - -# Carpeta donde se almacenan las plantillas de huellas +# Folder where fingerprint templates are stored FINGERPRINT_FOLDER = "fingerprint/" ################################################## -# Enrrols and verification functions +# Enroll and verification functions ################################################## +def get_num(max_num): + """ + Prompts the user to enter a valid template number. + Ensures that the number is within the available template range. + """ + while True: + try: + num = int(input(f"Enter a template number (0-{max_num}): ")) + if 0 <= num <= max_num: + return num + else: + print(f"Please enter a number between 0 and {max_num}.") + except ValueError: + print("Invalid input. Please enter a valid number.") + + def get_fingerprint(): - """get image to fingerprint sensor for search, process for a match""" - print("Wait finger..") + """Get an image from the fingerprint sensor for search, process for a match.""" + print("Waiting for finger...") while finger.get_image() != adafruit_fingerprint.OK: pass - print("Process image...") + print("Processing image...") if finger.image_2_tz(1) != adafruit_fingerprint.OK: return False - print("Searching coincidences...") + print("Searching for matches...") if finger.finger_search() != adafruit_fingerprint.OK: return False return True def get_fingerprint_detail(): - """Get image to fingerprint for process and return errors.""" - print("Wait finger..", end="") + """Get an image from the fingerprint sensor and return details/errors.""" + print("Waiting for finger...", end="") i = finger.get_image() if i == adafruit_fingerprint.OK: print("Image captured") @@ -78,7 +82,7 @@ def get_fingerprint_detail(): print("Error capturing image") return False - print("Process image...", end="") + print("Processing image...", end="") i = finger.image_2_tz(1) if i == adafruit_fingerprint.OK: print("Image processed") @@ -86,20 +90,20 @@ def get_fingerprint_detail(): print("Error processing image") return False - print("Searching coincidences...", end="") + print("Searching for matches...", end="") i = finger.finger_fast_search() if i == adafruit_fingerprint.OK: - print("¡Fingerprint found!") + print("Fingerprint found!") return True return False def enroll_finger(location): - """Enroll a finger with the fingerprint sensor and store it in the given location specific.""" + """Enroll a fingerprint and store it in the specified location.""" for fingerimg in range(1, 3): if fingerimg == 1: - print("Please put your finger on sensor...", end="") + print("Please place your finger on the sensor...", end="") else: - print("Put same finger...", end="") + print("Place the same finger again...", end="") while True: i = finger.get_image() @@ -112,10 +116,10 @@ def enroll_finger(location): print("Error capturing image") return False - print("Process image...", end="") + print("Processing image...", end="") i = finger.image_2_tz(fingerimg) if i == adafruit_fingerprint.OK: - print("Imagen procesed") + print("Image processed") else: print("Error processing image") return False @@ -126,7 +130,7 @@ def enroll_finger(location): while i != adafruit_fingerprint.NOFINGER: i = finger.get_image() - print("Creating model..", end="") + print("Creating model...", end="") i = finger.create_model() if i == adafruit_fingerprint.OK: print("Model created") @@ -134,7 +138,7 @@ def enroll_finger(location): print("Error creating model") return False - print("Storing in that location #%d..." % location, end="") + print(f"Storing model in location #{location}...", end="") i = finger.store_model(location) if i == adafruit_fingerprint.OK: print("Model stored") @@ -149,7 +153,7 @@ def enroll_finger(location): ################################################## def save_fingerprint_image(filename): - """Scan your fingerprint and save the image to a file.""" + """Capture a fingerprint and save the image to a file.""" while finger.get_image(): pass @@ -159,27 +163,27 @@ def save_fingerprint_image(filename): result = finger.get_fpdata(sensorbuffer="image") x, y = 0, 0 - for i in range(len(result)): - pixeldata[x, y] = (int(result[i]) >> 4) * 17 + for i, value in enumerate(result): + pixeldata[x, y] = (int(value) >> 4) * 17 x += 1 - pixeldata[x, y] = (int(result[i]) & mask) * 17 + pixeldata[x, y] = (int(value) & mask) * 17 if x == 255: x = 0 y += 1 else: x += 1 - if not img.save(filename): - return True - return False + img.save(filename) + return True + def enroll_save_to_file(): - """Scan your fingerprint and save the image to a file""" + """Capture a fingerprint, create a model, and save it to a file.""" for fingerimg in range(1, 3): if fingerimg == 1: - print("Please put your finger on sensor...", end="") + print("Please place your finger on the sensor...", end="") else: - print("Put same finger..", end="") + print("Place the same finger again...", end="") while True: i = finger.get_image() @@ -192,7 +196,7 @@ def enroll_save_to_file(): print("Error capturing image") return False - print("Process image...", end="") + print("Processing image...", end="") i = finger.image_2_tz(fingerimg) if i == adafruit_fingerprint.OK: print("Image processed") @@ -208,31 +212,31 @@ def enroll_save_to_file(): print("Creating model...", end="") i = finger.create_model() if i == adafruit_fingerprint.OK: - print("Model create") + print("Model created") else: print("Error creating model") return False print("Storing template...") data = finger.get_fpdata("char", 1) - # Guardar la plantilla con un nombre único basado en la hora actual + # Save the template with a unique filename based on the current time filename = os.path.join(FINGERPRINT_FOLDER, f"template_{int(time.time())}.dat") with open(filename, "wb") as file: file.write(bytearray(data)) - print(f"Template saved on {filename}") + print(f"Template saved to {filename}") return True def fingerprint_check_folder(): - """Compare fingerprint with all files in the fingerprint folder.""" - print("Wait for fingerprint...") + """Compare a fingerprint with all files in the fingerprint folder.""" + print("Waiting for fingerprint...") while finger.get_image() != adafruit_fingerprint.OK: pass - print("Process image...") + print("Processing image...") if finger.image_2_tz(1) != adafruit_fingerprint.OK: return False - print("Searching coincidences on the template's folder...", end="") + print("Searching for matches in the template folder...", end="") found_match = False matched_filename = None @@ -246,36 +250,36 @@ def fingerprint_check_folder(): if i == adafruit_fingerprint.OK: matched_filename = filename found_match = True - break # Detener la búsqueda después de encontrar una coincidencia + break # Stop searching after finding a match if found_match: - print(f"¡Fingerprint match the template in the file {matched_filename}!") + print(f"Fingerprint matches the template in the file {matched_filename}!") else: - print("Not match found") + print("No match found") return found_match ################################################## -# Main cycle of the program +# Main program loop ################################################## while True: print("----------------") if finger.read_templates() != adafruit_fingerprint.OK: - raise RuntimeError("Could not be read the templates") - print("Templates of fingerprints: ", finger.templates) + raise RuntimeError("Could not read templates") + print("Stored fingerprint templates: ", finger.templates) if finger.count_templates() != adafruit_fingerprint.OK: - raise RuntimeError("Could not be counted the templates") + raise RuntimeError("Could not count templates") print("Number of templates found: ", finger.template_count) if finger.read_sysparam() != adafruit_fingerprint.OK: - raise RuntimeError("Could not be obtained params of system.") - print("Size of template library ", finger.library_size) - print("e) Enrrol fingerprint") + raise RuntimeError("Could not retrieve system parameters.") + print("Template library size: ", finger.library_size) + print("e) Enroll fingerprint") print("f) Search fingerprint") print("d) Delete fingerprint") - print("s) Store image of fingerprint") + print("s) Save fingerprint image") print("cf) Compare template with file") - print("esf) Enrrol and save in file") + print("esf) Enroll and save to file") print("r) Reset library") print("q) Exit") print("----------------") @@ -285,29 +289,28 @@ def fingerprint_check_folder(): enroll_finger(get_num(finger.library_size)) if c == "f": if get_fingerprint(): - print("Fingerprint detected with ID #", finger.finger_id, "and confidence", finger.confidence) + print("Fingerprint detected with ID#",finger.finger_id,"& confidence",finger.confidence) else: print("Fingerprint not found") if c == "d": - """"get_num is a function that returns a number from 0 to 127""" if finger.delete_model(get_num(finger.library_size)) == adafruit_fingerprint.OK: - print("¡Deleted!") + print("Deleted successfully!") else: print("Error deleting") if c == "s": if save_fingerprint_image("fingerprint.png"): - print("Image of fingerpriint") + print("Fingerprint image saved") else: - print("Error storing an image") + print("Error saving image") if c == "cf": fingerprint_check_folder() if c == "esf": enroll_save_to_file() if c == "r": if finger.empty_library() == adafruit_fingerprint.OK: - print("¡Empty Library!") + print("Library cleared") else: - print("Error emptying library") + print("Failed to clear library") if c == "q": - print("Leavinf of fingerprint program") - raise SystemExit \ No newline at end of file + print("Exiting program") + break \ No newline at end of file From 3ea128c49aca27a944ce476419b80527b749da41 Mon Sep 17 00:00:00 2001 From: itsFDavid Date: Fri, 4 Oct 2024 22:39:34 -0600 Subject: [PATCH 19/35] Refactor code for improved performance and add program to compare template with fingerprint folder --- ...nt_template_folder_compare_with_file.py.py | 140 +++++------------- 1 file changed, 39 insertions(+), 101 deletions(-) diff --git a/examples/fingerprint_template_folder_compare_with_file.py.py b/examples/fingerprint_template_folder_compare_with_file.py.py index 9d33f15..cd60533 100644 --- a/examples/fingerprint_template_folder_compare_with_file.py.py +++ b/examples/fingerprint_template_folder_compare_with_file.py.py @@ -20,9 +20,6 @@ import os import time from PIL import Image - -##################### Settings for the serial port - import serial import adafruit_fingerprint @@ -34,15 +31,10 @@ finger = adafruit_fingerprint.Adafruit_Fingerprint(uart) -################################################## - # Folder where fingerprint templates are stored FINGERPRINT_FOLDER = "fingerprint/" -################################################## # Enroll and verification functions -################################################## - def get_num(max_num): """ Prompts the user to enter a valid template number. @@ -53,8 +45,7 @@ def get_num(max_num): num = int(input(f"Enter a template number (0-{max_num}): ")) if 0 <= num <= max_num: return num - else: - print(f"Please enter a number between 0 and {max_num}.") + print(f"Please enter a number between 0 and {max_num}.") except ValueError: print("Invalid input. Please enter a valid number.") @@ -64,97 +55,55 @@ def get_fingerprint(): print("Waiting for finger...") while finger.get_image() != adafruit_fingerprint.OK: pass + print("Processing image...") if finger.image_2_tz(1) != adafruit_fingerprint.OK: return False - print("Searching for matches...") - if finger.finger_search() != adafruit_fingerprint.OK: - return False - return True - -def get_fingerprint_detail(): - """Get an image from the fingerprint sensor and return details/errors.""" - print("Waiting for finger...", end="") - i = finger.get_image() - if i == adafruit_fingerprint.OK: - print("Image captured") - else: - print("Error capturing image") - return False - print("Processing image...", end="") - i = finger.image_2_tz(1) - if i == adafruit_fingerprint.OK: - print("Image processed") - else: - print("Error processing image") - return False + print("Searching for matches...") + return finger.finger_search() == adafruit_fingerprint.OK - print("Searching for matches...", end="") - i = finger.finger_fast_search() - if i == adafruit_fingerprint.OK: - print("Fingerprint found!") - return True - return False def enroll_finger(location): """Enroll a fingerprint and store it in the specified location.""" for fingerimg in range(1, 3): - if fingerimg == 1: - print("Please place your finger on the sensor...", end="") - else: - print("Place the same finger again...", end="") + action = "Place finger on sensor" if fingerimg == 1 else "Same finger again" + print(action, end="") while True: - i = finger.get_image() - if i == adafruit_fingerprint.OK: + if finger.get_image() == adafruit_fingerprint.OK: print("Image captured") break - if i == adafruit_fingerprint.NOFINGER: - print(".", end="") - else: - print("Error capturing image") - return False + print(".", end="") print("Processing image...", end="") - i = finger.image_2_tz(fingerimg) - if i == adafruit_fingerprint.OK: - print("Image processed") - else: + if finger.image_2_tz(fingerimg) != adafruit_fingerprint.OK: print("Error processing image") return False if fingerimg == 1: print("Remove finger") time.sleep(1) - while i != adafruit_fingerprint.NOFINGER: - i = finger.get_image() + while finger.get_image() != adafruit_fingerprint.NOFINGER: + pass print("Creating model...", end="") - i = finger.create_model() - if i == adafruit_fingerprint.OK: - print("Model created") - else: + if finger.create_model() != adafruit_fingerprint.OK: print("Error creating model") return False print(f"Storing model in location #{location}...", end="") - i = finger.store_model(location) - if i == adafruit_fingerprint.OK: - print("Model stored") - else: + if finger.store_model(location) != adafruit_fingerprint.OK: print("Error storing model") return False + print("Model stored") return True -################################################## -# Save and Compare from File Functions -################################################## def save_fingerprint_image(filename): """Capture a fingerprint and save the image to a file.""" - while finger.get_image(): + while finger.get_image() != adafruit_fingerprint.OK: pass img = Image.new("L", (256, 288), "white") @@ -180,46 +129,32 @@ def save_fingerprint_image(filename): def enroll_save_to_file(): """Capture a fingerprint, create a model, and save it to a file.""" for fingerimg in range(1, 3): - if fingerimg == 1: - print("Please place your finger on the sensor...", end="") - else: - print("Place the same finger again...", end="") + action = "Place finger on sensor" if fingerimg == 1 else "Same finger again" + print(action, end="") while True: - i = finger.get_image() - if i == adafruit_fingerprint.OK: + if finger.get_image() == adafruit_fingerprint.OK: print("Image captured") break - if i == adafruit_fingerprint.NOFINGER: - print(".", end="") - else: - print("Error capturing image") - return False + print(".", end="") print("Processing image...", end="") - i = finger.image_2_tz(fingerimg) - if i == adafruit_fingerprint.OK: - print("Image processed") - else: + if finger.image_2_tz(fingerimg) != adafruit_fingerprint.OK: print("Error processing image") return False if fingerimg == 1: print("Remove finger") - while i != adafruit_fingerprint.NOFINGER: - i = finger.get_image() + while finger.get_image() != adafruit_fingerprint.NOFINGER: + pass print("Creating model...", end="") - i = finger.create_model() - if i == adafruit_fingerprint.OK: - print("Model created") - else: + if finger.create_model() != adafruit_fingerprint.OK: print("Error creating model") return False print("Storing template...") data = finger.get_fpdata("char", 1) - # Save the template with a unique filename based on the current time filename = os.path.join(FINGERPRINT_FOLDER, f"template_{int(time.time())}.dat") with open(filename, "wb") as file: file.write(bytearray(data)) @@ -227,11 +162,13 @@ def enroll_save_to_file(): return True + def fingerprint_check_folder(): """Compare a fingerprint with all files in the fingerprint folder.""" print("Waiting for fingerprint...") while finger.get_image() != adafruit_fingerprint.OK: pass + print("Processing image...") if finger.image_2_tz(1) != adafruit_fingerprint.OK: return False @@ -246,8 +183,7 @@ def fingerprint_check_folder(): with open(file_path, "rb") as file: data = file.read() finger.send_fpdata(list(data), "char", 2) - i = finger.compare_templates() - if i == adafruit_fingerprint.OK: + if finger.compare_templates() == adafruit_fingerprint.OK: matched_filename = filename found_match = True break # Stop searching after finding a match @@ -259,21 +195,22 @@ def fingerprint_check_folder(): return found_match -################################################## -# Main program loop -################################################## +# Main program loop while True: print("----------------") if finger.read_templates() != adafruit_fingerprint.OK: raise RuntimeError("Could not read templates") print("Stored fingerprint templates: ", finger.templates) + if finger.count_templates() != adafruit_fingerprint.OK: raise RuntimeError("Could not count templates") print("Number of templates found: ", finger.template_count) + if finger.read_sysparam() != adafruit_fingerprint.OK: raise RuntimeError("Could not retrieve system parameters.") print("Template library size: ", finger.library_size) + print("e) Enroll fingerprint") print("f) Search fingerprint") print("d) Delete fingerprint") @@ -283,34 +220,35 @@ def fingerprint_check_folder(): print("r) Reset library") print("q) Exit") print("----------------") + c = input("> ") if c == "e": enroll_finger(get_num(finger.library_size)) - if c == "f": + elif c == "f": if get_fingerprint(): print("Fingerprint detected with ID#",finger.finger_id,"& confidence",finger.confidence) else: print("Fingerprint not found") - if c == "d": + elif c == "d": if finger.delete_model(get_num(finger.library_size)) == adafruit_fingerprint.OK: print("Deleted successfully!") else: print("Error deleting") - if c == "s": + elif c == "s": if save_fingerprint_image("fingerprint.png"): print("Fingerprint image saved") else: print("Error saving image") - if c == "cf": + elif c == "cf": fingerprint_check_folder() - if c == "esf": + elif c == "esf": enroll_save_to_file() - if c == "r": + elif c == "r": if finger.empty_library() == adafruit_fingerprint.OK: print("Library cleared") else: print("Failed to clear library") - if c == "q": + elif c == "q": print("Exiting program") - break \ No newline at end of file + break From 890db1db92535618263a91df11fcab4b637b16f9 Mon Sep 17 00:00:00 2001 From: itsFDavid Date: Fri, 4 Oct 2024 23:30:17 -0600 Subject: [PATCH 20/35] Refactor code for improved performance and add program to compare template with fingerprint folder --- ...rint_template_folder_compare_with_file.py} | 182 +++++++++++------- 1 file changed, 110 insertions(+), 72 deletions(-) rename examples/{fingerprint_template_folder_compare_with_file.py.py => fingerprint_template_folder_compare_with_file.py} (60%) diff --git a/examples/fingerprint_template_folder_compare_with_file.py.py b/examples/fingerprint_template_folder_compare_with_file.py similarity index 60% rename from examples/fingerprint_template_folder_compare_with_file.py.py rename to examples/fingerprint_template_folder_compare_with_file.py index cd60533..affcf53 100644 --- a/examples/fingerprint_template_folder_compare_with_file.py.py +++ b/examples/fingerprint_template_folder_compare_with_file.py @@ -14,12 +14,19 @@ Implementation Notes -------------------- This program was used on other fingerprint sensors, -and everything worked as expected, including testing with Raspberry Pi Zero 2. +and everything worked as expected, including testing with Raspberry Pi Zero 2W. + +To run the program: +1. Connect the fingerprint sensor to your Raspberry Pi. +2. Install required libraries. +3. Execute the script using Python. """ import os +import sys import time from PIL import Image + import serial import adafruit_fingerprint @@ -36,10 +43,7 @@ # Enroll and verification functions def get_num(max_num): - """ - Prompts the user to enter a valid template number. - Ensures that the number is within the available template range. - """ + """Prompts the user to enter a valid template number within the available range.""" while True: try: num = int(input(f"Enter a template number (0-{max_num}): ")) @@ -49,7 +53,6 @@ def get_num(max_num): except ValueError: print("Invalid input. Please enter a valid number.") - def get_fingerprint(): """Get an image from the fingerprint sensor for search, process for a match.""" print("Waiting for finger...") @@ -58,12 +61,12 @@ def get_fingerprint(): print("Processing image...") if finger.image_2_tz(1) != adafruit_fingerprint.OK: + print("Error processing image.") return False print("Searching for matches...") return finger.finger_search() == adafruit_fingerprint.OK - def enroll_finger(location): """Enroll a fingerprint and store it in the specified location.""" for fingerimg in range(1, 3): @@ -78,7 +81,7 @@ def enroll_finger(location): print("Processing image...", end="") if finger.image_2_tz(fingerimg) != adafruit_fingerprint.OK: - print("Error processing image") + print("Error processing image.") return False if fingerimg == 1: @@ -89,20 +92,20 @@ def enroll_finger(location): print("Creating model...", end="") if finger.create_model() != adafruit_fingerprint.OK: - print("Error creating model") + print("Error creating model.") return False print(f"Storing model in location #{location}...", end="") if finger.store_model(location) != adafruit_fingerprint.OK: - print("Error storing model") + print("Error storing model.") return False - print("Model stored") + print("Model stored.") return True - def save_fingerprint_image(filename): """Capture a fingerprint and save the image to a file.""" + print("Waiting for finger...") while finger.get_image() != adafruit_fingerprint.OK: pass @@ -113,6 +116,8 @@ def save_fingerprint_image(filename): x, y = 0, 0 for i, value in enumerate(result): + if i % 100 == 0: + print("", end="") pixeldata[x, y] = (int(value) >> 4) * 17 x += 1 pixeldata[x, y] = (int(value) & mask) * 17 @@ -123,6 +128,7 @@ def save_fingerprint_image(filename): x += 1 img.save(filename) + print(f"\nImage saved to {filename}") return True @@ -140,7 +146,7 @@ def enroll_save_to_file(): print("Processing image...", end="") if finger.image_2_tz(fingerimg) != adafruit_fingerprint.OK: - print("Error processing image") + print("Error processing image.") return False if fingerimg == 1: @@ -150,7 +156,7 @@ def enroll_save_to_file(): print("Creating model...", end="") if finger.create_model() != adafruit_fingerprint.OK: - print("Error creating model") + print("Error creating model.") return False print("Storing template...") @@ -162,7 +168,6 @@ def enroll_save_to_file(): return True - def fingerprint_check_folder(): """Compare a fingerprint with all files in the fingerprint folder.""" print("Waiting for fingerprint...") @@ -171,6 +176,7 @@ def fingerprint_check_folder(): print("Processing image...") if finger.image_2_tz(1) != adafruit_fingerprint.OK: + print("Error processing image.") return False print("Searching for matches in the template folder...", end="") @@ -186,69 +192,101 @@ def fingerprint_check_folder(): if finger.compare_templates() == adafruit_fingerprint.OK: matched_filename = filename found_match = True - break # Stop searching after finding a match + break if found_match: print(f"Fingerprint matches the template in the file {matched_filename}!") else: - print("No match found") + print("No match found.") return found_match +def main(): + """Main function to run the fingerprint enrollment and verification program. -# Main program loop -while True: - print("----------------") - if finger.read_templates() != adafruit_fingerprint.OK: - raise RuntimeError("Could not read templates") - print("Stored fingerprint templates: ", finger.templates) - - if finger.count_templates() != adafruit_fingerprint.OK: - raise RuntimeError("Could not count templates") - print("Number of templates found: ", finger.template_count) - - if finger.read_sysparam() != adafruit_fingerprint.OK: - raise RuntimeError("Could not retrieve system parameters.") - print("Template library size: ", finger.library_size) - - print("e) Enroll fingerprint") - print("f) Search fingerprint") - print("d) Delete fingerprint") - print("s) Save fingerprint image") - print("cf) Compare template with file") - print("esf) Enroll and save to file") - print("r) Reset library") - print("q) Exit") - print("----------------") - - c = input("> ") - - if c == "e": - enroll_finger(get_num(finger.library_size)) - elif c == "f": - if get_fingerprint(): - print("Fingerprint detected with ID#",finger.finger_id,"& confidence",finger.confidence) - else: - print("Fingerprint not found") - elif c == "d": - if finger.delete_model(get_num(finger.library_size)) == adafruit_fingerprint.OK: - print("Deleted successfully!") - else: - print("Error deleting") - elif c == "s": - if save_fingerprint_image("fingerprint.png"): - print("Fingerprint image saved") - else: - print("Error saving image") - elif c == "cf": - fingerprint_check_folder() - elif c == "esf": - enroll_save_to_file() - elif c == "r": - if finger.empty_library() == adafruit_fingerprint.OK: - print("Library cleared") + This function provides a menu for the user to enroll fingerprints, search for + fingerprints, delete templates, save fingerprint images, and reset the fingerprint library. + It interacts with the user via the console and performs the necessary actions based on + user input. + """ + actions = { + "e": lambda: enroll_finger(get_num(finger.library_size)), + "f": lambda: print_fingerprint(), + "d": lambda: delete_fingerprint(), + "s": lambda: save_fingerprint_image(f"fingerprint_{int(time.time())}.png"), + "cf": lambda: fingerprint_check_folder(), + "esf": lambda: enroll_save_to_file(), + "r": lambda: reset_library(), + "q": lambda: exit_program() + } + + while True: + print("----------------") + if finger.read_templates() != adafruit_fingerprint.OK: + raise RuntimeError("Could not read templates.") + print("Stored fingerprint templates: ", finger.templates) + + if finger.count_templates() != adafruit_fingerprint.OK: + raise RuntimeError("Could not count templates.") + print("Number of templates found: ", finger.template_count) + + if finger.read_sysparam() != adafruit_fingerprint.OK: + raise RuntimeError("Could not retrieve system parameters.") + print("Template library size: ", finger.library_size) + + print("Options:") + for option in actions.keys(): + print(f"{option}) {option_description(option)}") + print("----------------") + + c = input("> ") + + if c in actions: + actions[c]() else: - print("Failed to clear library") - elif c == "q": - print("Exiting program") - break + print("Invalid option.") + +def print_fingerprint(): + """Prints the fingerprint detection result.""" + if get_fingerprint(): + output_finger_detected=f"Fingerprint detected with ID #{finger.finger_id}" + output_finger_confidence=f"Confidence: {finger.confidence}" + print(output_finger_detected) + print(output_finger_confidence) + else: + print("Fingerprint not found.") + +def delete_fingerprint(): + """Deletes a fingerprint model based on user input.""" + if finger.delete_model(get_num(finger.library_size)) == adafruit_fingerprint.OK: + print("Deleted successfully!") + else: + print("Failed to delete.") +def reset_library(): + """Resets the fingerprint library.""" + if finger.empty_library() == adafruit_fingerprint.OK: + print("Library reset.") + else: + print("Failed to reset library.") + +def exit_program(): + """Exits the program.""" + print("Exiting...") + sys.exit(0) + +def option_description(option): + """Returns a description for each menu option.""" + descriptions = { + "e": "Enroll fingerprint", + "f": "Search fingerprint", + "d": "Delete fingerprint", + "s": "Save fingerprint image", + "cf": "Compare template with file", + "esf": "Enroll and save to file", + "r": "Reset library", + "q": "Exit" + } + return descriptions.get(option, "No description available.") + +if __name__ == "__main__": + main() From a6bf0aff53df45671012ca856e5c774aaec59420 Mon Sep 17 00:00:00 2001 From: itsFDavid Date: Sat, 5 Oct 2024 21:44:34 -0600 Subject: [PATCH 21/35] Refactor code for improved performance and update menu options --- ...print_template_folder_compare_with_file.py | 59 +++++++++---------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/examples/fingerprint_template_folder_compare_with_file.py b/examples/fingerprint_template_folder_compare_with_file.py index affcf53..f7a4e32 100644 --- a/examples/fingerprint_template_folder_compare_with_file.py +++ b/examples/fingerprint_template_folder_compare_with_file.py @@ -209,17 +209,6 @@ def main(): It interacts with the user via the console and performs the necessary actions based on user input. """ - actions = { - "e": lambda: enroll_finger(get_num(finger.library_size)), - "f": lambda: print_fingerprint(), - "d": lambda: delete_fingerprint(), - "s": lambda: save_fingerprint_image(f"fingerprint_{int(time.time())}.png"), - "cf": lambda: fingerprint_check_folder(), - "esf": lambda: enroll_save_to_file(), - "r": lambda: reset_library(), - "q": lambda: exit_program() - } - while True: print("----------------") if finger.read_templates() != adafruit_fingerprint.OK: @@ -235,16 +224,38 @@ def main(): print("Template library size: ", finger.library_size) print("Options:") - for option in actions.keys(): - print(f"{option}) {option_description(option)}") + print("e) Enroll fingerprint") + print("f) Search fingerprint") + print("d) Delete fingerprint") + print("s) Save fingerprint image") + print("cf) Compare template with file") + print("esf) Enroll and save to file") + print("r) Reset library") + print("q) Exit") print("----------------") c = input("> ") - if c in actions: - actions[c]() - else: - print("Invalid option.") + match c: + case "e": + enroll_finger(get_num(finger.library_size)) + case "f": + print_fingerprint() + case "d": + delete_fingerprint() + case "s": + save_fingerprint_image(f"fingerprint_{int(time.time())}.png") + case "cf": + fingerprint_check_folder() + case "esf": + enroll_save_to_file() + case "r": + reset_library() + case "q": + exit_program() + case _: + print("Invalid option.") + def print_fingerprint(): """Prints the fingerprint detection result.""" @@ -268,25 +279,11 @@ def reset_library(): print("Library reset.") else: print("Failed to reset library.") - def exit_program(): """Exits the program.""" print("Exiting...") sys.exit(0) -def option_description(option): - """Returns a description for each menu option.""" - descriptions = { - "e": "Enroll fingerprint", - "f": "Search fingerprint", - "d": "Delete fingerprint", - "s": "Save fingerprint image", - "cf": "Compare template with file", - "esf": "Enroll and save to file", - "r": "Reset library", - "q": "Exit" - } - return descriptions.get(option, "No description available.") if __name__ == "__main__": main() From e741c79392775bc6a54a39b8f938a6dc0d4b7232 Mon Sep 17 00:00:00 2001 From: itsFDavid Date: Sat, 5 Oct 2024 21:56:52 -0600 Subject: [PATCH 22/35] Refactor code for improved performance for black format --- ...erprint_template_folder_compare_with_file.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/examples/fingerprint_template_folder_compare_with_file.py b/examples/fingerprint_template_folder_compare_with_file.py index f7a4e32..4dc185a 100644 --- a/examples/fingerprint_template_folder_compare_with_file.py +++ b/examples/fingerprint_template_folder_compare_with_file.py @@ -53,6 +53,7 @@ def get_num(max_num): except ValueError: print("Invalid input. Please enter a valid number.") + def get_fingerprint(): """Get an image from the fingerprint sensor for search, process for a match.""" print("Waiting for finger...") @@ -67,6 +68,7 @@ def get_fingerprint(): print("Searching for matches...") return finger.finger_search() == adafruit_fingerprint.OK + def enroll_finger(location): """Enroll a fingerprint and store it in the specified location.""" for fingerimg in range(1, 3): @@ -103,6 +105,7 @@ def enroll_finger(location): print("Model stored.") return True + def save_fingerprint_image(filename): """Capture a fingerprint and save the image to a file.""" print("Waiting for finger...") @@ -161,13 +164,17 @@ def enroll_save_to_file(): print("Storing template...") data = finger.get_fpdata("char", 1) - filename = os.path.join(FINGERPRINT_FOLDER, f"template_{int(time.time())}.dat") + filename = os.path.join( + FINGERPRINT_FOLDER, + f"template_{int(time.time())}.dat" + ) with open(filename, "wb") as file: file.write(bytearray(data)) print(f"Template saved to {filename}") return True + def fingerprint_check_folder(): """Compare a fingerprint with all files in the fingerprint folder.""" print("Waiting for fingerprint...") @@ -201,6 +208,7 @@ def fingerprint_check_folder(): return found_match + def main(): """Main function to run the fingerprint enrollment and verification program. @@ -233,9 +241,7 @@ def main(): print("r) Reset library") print("q) Exit") print("----------------") - c = input("> ") - match c: case "e": enroll_finger(get_num(finger.library_size)) @@ -267,18 +273,23 @@ def print_fingerprint(): else: print("Fingerprint not found.") + def delete_fingerprint(): """Deletes a fingerprint model based on user input.""" if finger.delete_model(get_num(finger.library_size)) == adafruit_fingerprint.OK: print("Deleted successfully!") else: print("Failed to delete.") + + def reset_library(): """Resets the fingerprint library.""" if finger.empty_library() == adafruit_fingerprint.OK: print("Library reset.") else: print("Failed to reset library.") + + def exit_program(): """Exits the program.""" print("Exiting...") From 21dc7f119d431851bb1c2e1e91f9dd4d2097d00a Mon Sep 17 00:00:00 2001 From: itsFDavid Date: Sat, 5 Oct 2024 22:02:36 -0600 Subject: [PATCH 23/35] format code with isort --- examples/fingerprint_template_folder_compare_with_file.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/fingerprint_template_folder_compare_with_file.py b/examples/fingerprint_template_folder_compare_with_file.py index 4dc185a..a7ada2f 100644 --- a/examples/fingerprint_template_folder_compare_with_file.py +++ b/examples/fingerprint_template_folder_compare_with_file.py @@ -25,10 +25,10 @@ import os import sys import time -from PIL import Image -import serial import adafruit_fingerprint +import serial +from PIL import Image # If using with a computer such as Linux/RaspberryPi, Mac, Windows with USB/serial converter: # uart = serial.Serial("COM6", baudrate=57600, timeout=1) From ef16bfdfd038aa1fe3ece2563a4577b9904d0bb6 Mon Sep 17 00:00:00 2001 From: itsFDavid Date: Sat, 5 Oct 2024 22:03:42 -0600 Subject: [PATCH 24/35] format code with black --- .../fingerprint_template_folder_compare_with_file.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/examples/fingerprint_template_folder_compare_with_file.py b/examples/fingerprint_template_folder_compare_with_file.py index a7ada2f..87eae21 100644 --- a/examples/fingerprint_template_folder_compare_with_file.py +++ b/examples/fingerprint_template_folder_compare_with_file.py @@ -41,6 +41,7 @@ # Folder where fingerprint templates are stored FINGERPRINT_FOLDER = "fingerprint/" + # Enroll and verification functions def get_num(max_num): """Prompts the user to enter a valid template number within the available range.""" @@ -164,10 +165,7 @@ def enroll_save_to_file(): print("Storing template...") data = finger.get_fpdata("char", 1) - filename = os.path.join( - FINGERPRINT_FOLDER, - f"template_{int(time.time())}.dat" - ) + filename = os.path.join(FINGERPRINT_FOLDER, f"template_{int(time.time())}.dat") with open(filename, "wb") as file: file.write(bytearray(data)) print(f"Template saved to {filename}") @@ -266,8 +264,8 @@ def main(): def print_fingerprint(): """Prints the fingerprint detection result.""" if get_fingerprint(): - output_finger_detected=f"Fingerprint detected with ID #{finger.finger_id}" - output_finger_confidence=f"Confidence: {finger.confidence}" + output_finger_detected = f"Fingerprint detected with ID #{finger.finger_id}" + output_finger_confidence = f"Confidence: {finger.confidence}" print(output_finger_detected) print(output_finger_confidence) else: From 386ce6b75ba4a593d5c4e4e3a0c53fbd007a7d21 Mon Sep 17 00:00:00 2001 From: itsFDavid Date: Sat, 5 Oct 2024 22:21:23 -0600 Subject: [PATCH 25/35] Refactor code for improved performance --- ...print_template_folder_compare_with_file.py | 26 +------------------ 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/examples/fingerprint_template_folder_compare_with_file.py b/examples/fingerprint_template_folder_compare_with_file.py index 87eae21..69bd3f9 100644 --- a/examples/fingerprint_template_folder_compare_with_file.py +++ b/examples/fingerprint_template_folder_compare_with_file.py @@ -60,12 +60,10 @@ def get_fingerprint(): print("Waiting for finger...") while finger.get_image() != adafruit_fingerprint.OK: pass - print("Processing image...") if finger.image_2_tz(1) != adafruit_fingerprint.OK: print("Error processing image.") return False - print("Searching for matches...") return finger.finger_search() == adafruit_fingerprint.OK @@ -75,34 +73,28 @@ def enroll_finger(location): for fingerimg in range(1, 3): action = "Place finger on sensor" if fingerimg == 1 else "Same finger again" print(action, end="") - while True: if finger.get_image() == adafruit_fingerprint.OK: print("Image captured") break print(".", end="") - print("Processing image...", end="") if finger.image_2_tz(fingerimg) != adafruit_fingerprint.OK: print("Error processing image.") return False - if fingerimg == 1: print("Remove finger") time.sleep(1) while finger.get_image() != adafruit_fingerprint.NOFINGER: pass - print("Creating model...", end="") if finger.create_model() != adafruit_fingerprint.OK: print("Error creating model.") return False - print(f"Storing model in location #{location}...", end="") if finger.store_model(location) != adafruit_fingerprint.OK: print("Error storing model.") return False - print("Model stored.") return True @@ -112,12 +104,10 @@ def save_fingerprint_image(filename): print("Waiting for finger...") while finger.get_image() != adafruit_fingerprint.OK: pass - img = Image.new("L", (256, 288), "white") pixeldata = img.load() mask = 0b00001111 result = finger.get_fpdata(sensorbuffer="image") - x, y = 0, 0 for i, value in enumerate(result): if i % 100 == 0: @@ -130,7 +120,6 @@ def save_fingerprint_image(filename): y += 1 else: x += 1 - img.save(filename) print(f"\nImage saved to {filename}") return True @@ -141,35 +130,29 @@ def enroll_save_to_file(): for fingerimg in range(1, 3): action = "Place finger on sensor" if fingerimg == 1 else "Same finger again" print(action, end="") - while True: if finger.get_image() == adafruit_fingerprint.OK: print("Image captured") break print(".", end="") - print("Processing image...", end="") if finger.image_2_tz(fingerimg) != adafruit_fingerprint.OK: print("Error processing image.") return False - if fingerimg == 1: print("Remove finger") while finger.get_image() != adafruit_fingerprint.NOFINGER: pass - print("Creating model...", end="") if finger.create_model() != adafruit_fingerprint.OK: print("Error creating model.") return False - print("Storing template...") data = finger.get_fpdata("char", 1) filename = os.path.join(FINGERPRINT_FOLDER, f"template_{int(time.time())}.dat") with open(filename, "wb") as file: file.write(bytearray(data)) print(f"Template saved to {filename}") - return True @@ -178,16 +161,13 @@ def fingerprint_check_folder(): print("Waiting for fingerprint...") while finger.get_image() != adafruit_fingerprint.OK: pass - print("Processing image...") if finger.image_2_tz(1) != adafruit_fingerprint.OK: print("Error processing image.") return False - print("Searching for matches in the template folder...", end="") found_match = False matched_filename = None - for filename in os.listdir(FINGERPRINT_FOLDER): if filename.endswith(".dat"): file_path = os.path.join(FINGERPRINT_FOLDER, filename) @@ -198,18 +178,15 @@ def fingerprint_check_folder(): matched_filename = filename found_match = True break - if found_match: print(f"Fingerprint matches the template in the file {matched_filename}!") else: print("No match found.") - return found_match def main(): """Main function to run the fingerprint enrollment and verification program. - This function provides a menu for the user to enroll fingerprints, search for fingerprints, delete templates, save fingerprint images, and reset the fingerprint library. It interacts with the user via the console and performs the necessary actions based on @@ -228,7 +205,6 @@ def main(): if finger.read_sysparam() != adafruit_fingerprint.OK: raise RuntimeError("Could not retrieve system parameters.") print("Template library size: ", finger.library_size) - print("Options:") print("e) Enroll fingerprint") print("f) Search fingerprint") @@ -291,7 +267,7 @@ def reset_library(): def exit_program(): """Exits the program.""" print("Exiting...") - sys.exit(0) + raise SystemExit if __name__ == "__main__": From 954dac2f4d3f242a499c3d8417fea55b01fbbf5d Mon Sep 17 00:00:00 2001 From: itsFDavid Date: Sat, 5 Oct 2024 22:29:18 -0600 Subject: [PATCH 26/35] Refactor code for improved performance --- examples/fingerprint_template_folder_compare_with_file.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/fingerprint_template_folder_compare_with_file.py b/examples/fingerprint_template_folder_compare_with_file.py index 69bd3f9..3dd55e4 100644 --- a/examples/fingerprint_template_folder_compare_with_file.py +++ b/examples/fingerprint_template_folder_compare_with_file.py @@ -23,12 +23,11 @@ """ import os -import sys import time -import adafruit_fingerprint import serial from PIL import Image +import adafruit_fingerprint # If using with a computer such as Linux/RaspberryPi, Mac, Windows with USB/serial converter: # uart = serial.Serial("COM6", baudrate=57600, timeout=1) From 0f98a8cf944eaffb1472272d87a42dada47aba4e Mon Sep 17 00:00:00 2001 From: itsFDavid Date: Sat, 5 Oct 2024 22:29:38 -0600 Subject: [PATCH 27/35] Refactor code for pass pylint --- ...print_template_folder_compare_with_file.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/fingerprint_template_folder_compare_with_file.py b/examples/fingerprint_template_folder_compare_with_file.py index 3dd55e4..f5ce68b 100644 --- a/examples/fingerprint_template_folder_compare_with_file.py +++ b/examples/fingerprint_template_folder_compare_with_file.py @@ -107,18 +107,18 @@ def save_fingerprint_image(filename): pixeldata = img.load() mask = 0b00001111 result = finger.get_fpdata(sensorbuffer="image") - x, y = 0, 0 + coor_x, coor_y = 0, 0 for i, value in enumerate(result): if i % 100 == 0: print("", end="") - pixeldata[x, y] = (int(value) >> 4) * 17 - x += 1 - pixeldata[x, y] = (int(value) & mask) * 17 - if x == 255: - x = 0 - y += 1 + pixeldata[coor_x, coor_y] = (int(value) >> 4) * 17 + coor_x += 1 + pixeldata[coor_x, coor_y] = (int(value) & mask) * 17 + if coor_x == 255: + coor_x = 0 + coor_y += 1 else: - x += 1 + coor_x += 1 img.save(filename) print(f"\nImage saved to {filename}") return True @@ -214,8 +214,8 @@ def main(): print("r) Reset library") print("q) Exit") print("----------------") - c = input("> ") - match c: + user_choice = input("> ") + match user_choice.lower(): case "e": enroll_finger(get_num(finger.library_size)) case "f": From 2c7d33099ad669a52af431241b0ac47a4f08000a Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 7 Oct 2024 09:24:05 -0500 Subject: [PATCH 28/35] remove deprecated get_html_theme_path() call Signed-off-by: foamyguy --- docs/conf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 46ca9c6..d8044a5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -100,7 +100,6 @@ import sphinx_rtd_theme html_theme = "sphinx_rtd_theme" -html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, From 35408d6eb6a9174861ae5c3405d0e3d788588d74 Mon Sep 17 00:00:00 2001 From: itsFDavid Date: Mon, 7 Oct 2024 22:07:05 -0600 Subject: [PATCH 29/35] Refactor code for renaming fingerprint template file for Raspberry Pi --- ....py => fingerprint_template_folder_compare_with_file_rpi.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename examples/{fingerprint_template_folder_compare_with_file.py => fingerprint_template_folder_compare_with_file_rpi.py} (99%) diff --git a/examples/fingerprint_template_folder_compare_with_file.py b/examples/fingerprint_template_folder_compare_with_file_rpi.py similarity index 99% rename from examples/fingerprint_template_folder_compare_with_file.py rename to examples/fingerprint_template_folder_compare_with_file_rpi.py index f5ce68b..b68ef5b 100644 --- a/examples/fingerprint_template_folder_compare_with_file.py +++ b/examples/fingerprint_template_folder_compare_with_file_rpi.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-FileCopyrightText: 2024 itsFDavid # SPDX-License-Identifier: MIT """ `fingerprint_template_folder_compare_with_file.py` From 6d2e0735bd675ffeb964c0074d3a9f12a62a0231 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 19 Nov 2024 16:28:28 -0600 Subject: [PATCH 30/35] wait after set_sysparam --- adafruit_fingerprint.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/adafruit_fingerprint.py b/adafruit_fingerprint.py index 0b1e75a..7236ff0 100644 --- a/adafruit_fingerprint.py +++ b/adafruit_fingerprint.py @@ -30,6 +30,7 @@ pass import struct +import time from micropython import const from busio import UART @@ -171,6 +172,7 @@ def set_sysparam(self, param_num: int, param_val: int) -> int: self.security_level = param_val elif param_num == 6: self.data_packet_size = param_val + time.sleep(0.25) return r[0] def get_image(self) -> int: From dc4edf25b55bfd4d48d609e7f7fcd8bf06ac30ae Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 14 Jan 2025 11:32:34 -0600 Subject: [PATCH 31/35] add sphinx configuration to rtd.yaml Signed-off-by: foamyguy --- .readthedocs.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 33c2a61..88bca9f 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -8,6 +8,9 @@ # Required version: 2 +sphinx: + configuration: docs/conf.py + build: os: ubuntu-20.04 tools: From 75553e709828709863ce7b2802290d5c653af297 Mon Sep 17 00:00:00 2001 From: Asadullah Shaikh Date: Sun, 6 Apr 2025 13:29:36 +0530 Subject: [PATCH 32/35] add `serial.Serial` as a valid type for `uart` parameter of `Adafruit_Fingerprint.__init__` --- adafruit_fingerprint.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/adafruit_fingerprint.py b/adafruit_fingerprint.py index 7236ff0..8951327 100644 --- a/adafruit_fingerprint.py +++ b/adafruit_fingerprint.py @@ -26,6 +26,7 @@ """ try: from typing import Tuple, List, Union + from serial import Serial except ImportError: pass @@ -115,7 +116,11 @@ class Adafruit_Fingerprint: system_id = None status_register = None - def __init__(self, uart: UART, passwd: Tuple[int, int, int, int] = (0, 0, 0, 0)): + def __init__( + self, + uart: Union[UART, "Serial"], + passwd: Tuple[int, int, int, int] = (0, 0, 0, 0), + ): # Create object with UART for interface, and default 32-bit password self.password = passwd self._uart = uart From 3e167da3c95367993ef4d2062c441f3ff63b45b8 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 14 May 2025 15:28:26 +0000 Subject: [PATCH 33/35] change to ruff --- .gitattributes | 11 + .pre-commit-config.yaml | 43 +- .pylintrc | 399 ------------------ README.rst | 6 +- adafruit_fingerprint.py | 31 +- docs/api.rst | 3 + docs/conf.py | 8 +- examples/fingerprint_picturetest.py | 4 +- examples/fingerprint_r503.py | 2 + examples/fingerprint_r503_rpi.py | 5 +- examples/fingerprint_simpletest.py | 2 + examples/fingerprint_simpletest_rpi.py | 6 +- examples/fingerprint_template_file_compare.py | 5 +- ...t_template_folder_compare_with_file_rpi.py | 1 + ruff.toml | 105 +++++ 15 files changed, 162 insertions(+), 469 deletions(-) create mode 100644 .gitattributes delete mode 100644 .pylintrc create mode 100644 ruff.toml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..21c125c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense + +.py text eol=lf +.rst text eol=lf +.txt text eol=lf +.yaml text eol=lf +.toml text eol=lf +.license text eol=lf +.md text eol=lf diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 70ade69..ff19dde 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,42 +1,21 @@ -# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò +# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries # # SPDX-License-Identifier: Unlicense repos: - - repo: https://github.com/python/black - rev: 23.3.0 - hooks: - - id: black - - repo: https://github.com/fsfe/reuse-tool - rev: v1.1.2 - hooks: - - id: reuse - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace - - repo: https://github.com/pycqa/pylint - rev: v2.17.4 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.3.4 hooks: - - id: pylint - name: pylint (library code) - types: [python] - args: - - --disable=consider-using-f-string - exclude: "^(docs/|examples/|tests/|setup.py$)" - - id: pylint - name: pylint (example code) - description: Run pylint rules on "examples/*.py" files - types: [python] - files: "^examples/" - args: - - --disable=missing-docstring,invalid-name,consider-using-f-string,duplicate-code - - id: pylint - name: pylint (test code) - description: Run pylint rules on "tests/*.py" files - types: [python] - files: "^tests/" - args: - - --disable=missing-docstring,consider-using-f-string,duplicate-code + - id: ruff-format + - id: ruff + args: ["--fix"] + - repo: https://github.com/fsfe/reuse-tool + rev: v3.0.1 + hooks: + - id: reuse diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index f945e92..0000000 --- a/.pylintrc +++ /dev/null @@ -1,399 +0,0 @@ -# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries -# -# SPDX-License-Identifier: Unlicense - -[MASTER] - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code -extension-pkg-whitelist= - -# Add files or directories to the ignore-list. They should be base names, not -# paths. -ignore=CVS - -# Add files or directories matching the regex patterns to the ignore-list. The -# regex matches against base names, not paths. -ignore-patterns= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Use multiple processes to speed up Pylint. -jobs=1 - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins=pylint.extensions.no_self_use - -# Pickle collected data for later comparisons. -persistent=yes - -# Specify a configuration file. -#rcfile= - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -# disable=import-error,raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,deprecated-str-translate-call -disable=raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,import-error,pointless-string-statement,unspecified-encoding - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -enable= - - -[REPORTS] - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details -#msg-template= - -# Set the output format. Available formats are text, parseable, colorized, json -# and msvs (visual studio).You can also give a reporter class, eg -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Tells whether to display a full report or only the messages -reports=no - -# Activate the evaluation score. -score=yes - - -[REFACTORING] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging - - -[SPELLING] - -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -spelling-dict= - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to indicated private dictionary in -# --spelling-private-dict-file option instead of raising a message. -spelling-store-unknown-words=no - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -# notes=FIXME,XXX,TODO -notes=FIXME,XXX - - -[TYPECHECK] - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members= - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# This flag controls whether pylint should warn about no-member and similar -# checks whenever an opaque object is returned when inferring. The inference -# can return multiple potential results while evaluating a Python object, but -# some branches might not be evaluated, which results in partial inference. In -# that case, it might be useful to still emit no-member and other checks for -# the rest of the inferred objects. -ignore-on-opaque-inference=yes - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=optparse.Values,thread._local,_thread._local - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis. It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules=board - -# Show a hint with possible names when a member name was not found. The aspect -# of finding the hint is based on edit distance. -missing-member-hint=yes - -# The minimum edit distance a name should have in order to be considered a -# similar match for a missing member name. -missing-member-hint-distance=1 - -# The total number of similar names that should be taken in consideration when -# showing a hint for a missing member. -missing-member-max-choices=1 - - -[VARIABLES] - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - -# Tells whether unused global variables should be treated as a violation. -allow-global-unused-variables=yes - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_,_cb - -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.*|^ignored_|^unused_ - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six.moves,future.builtins - - -[FORMAT] - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -# expected-line-ending-format= -expected-line-ending-format=LF - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Maximum number of characters on a single line. -max-line-length=100 - -# Maximum number of lines in a module -max-module-lines=1000 - -# Allow the body of a class to be on the same line as the declaration if body -# contains single statement. -single-line-class-stmt=no - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - - -[SIMILARITIES] - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=yes - -# Minimum lines number of a similarity. -min-similarity-lines=12 - - -[BASIC] - -# Regular expression matching correct argument names -argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct attribute names -attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata - -# Regular expression matching correct class attribute names -class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Regular expression matching correct class names -# class-rgx=[A-Z_][a-zA-Z0-9]+$ -class-rgx=[A-Z_][a-zA-Z0-9_]+$ - -# Regular expression matching correct constant names -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - -# Regular expression matching correct function names -function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Good variable names which should always be accepted, separated by a comma -# good-names=i,j,k,ex,Run,_ -good-names=r,g,b,w,i,j,k,n,x,y,z,ex,ok,Run,_ - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# Regular expression matching correct inline iteration names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Regular expression matching correct method names -method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=^_ - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -property-classes=abc.abstractproperty - -# Regular expression matching correct variable names -variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - - -[IMPORTS] - -# Allow wildcard imports from modules that define __all__. -allow-wildcard-with-all=no - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=optparse,tkinter.tix - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - - -[CLASSES] - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict,_fields,_replace,_source,_make - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - - -[DESIGN] - -# Maximum number of arguments for function / method -max-args=5 - -# Maximum number of attributes for a class (see R0902). -# max-attributes=7 -max-attributes=11 - -# Maximum number of boolean expressions in a if statement -max-bool-expr=5 - -# Maximum number of branch for function / method body -max-branches=12 - -# Maximum number of locals for function / method body -max-locals=15 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of return / yield for function / method body -max-returns=6 - -# Maximum number of statements in function / method body -max-statements=50 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=1 - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=builtins.Exception diff --git a/README.rst b/README.rst index 4b348ee..956e4b1 100644 --- a/README.rst +++ b/README.rst @@ -14,9 +14,9 @@ Introduction :target: https://github.com/adafruit/Adafruit_CircuitPython_Fingerprint/actions/ :alt: Build Status -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - :alt: Code Style: Black +.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json + :target: https://github.com/astral-sh/ruff + :alt: Code Style: Ruff This library will let you use an Adafruit Fingerprint sensor on any UART to get, store, retreive and query fingerprints! Great for adding bio-sensing security to your next build. diff --git a/adafruit_fingerprint.py b/adafruit_fingerprint.py index 7236ff0..daacf3e 100644 --- a/adafruit_fingerprint.py +++ b/adafruit_fingerprint.py @@ -24,16 +24,17 @@ * Adafruit CircuitPython firmware (2.2.0+) for the ESP8622 and M0-based boards: https://github.com/adafruit/circuitpython/releases """ + try: - from typing import Tuple, List, Union + from typing import List, Tuple, Union except ImportError: pass import struct import time -from micropython import const from busio import UART +from micropython import const __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Fingerprint.git" @@ -93,8 +94,6 @@ MODULEOK = const(0x55) -# pylint: disable=too-many-instance-attributes -# pylint: disable=too-many-public-methods class Adafruit_Fingerprint: """UART based fingerprint sensor.""" @@ -214,7 +213,7 @@ def load_model(self, location: int, slot: int = 1) -> int: def get_fpdata(self, sensorbuffer: str = "char", slot: int = 1) -> List[int]: """Requests the sensor to transfer the fingerprint image or template. Returns the data payload only.""" - if slot not in (1, 2): + if slot not in {1, 2}: # raise error or use default value? slot = 2 if sensorbuffer == "image": @@ -229,12 +228,10 @@ def get_fpdata(self, sensorbuffer: str = "char", slot: int = 1) -> List[int]: self._print_debug("get_fdata res:", res, data_type="hex") return res - def send_fpdata( - self, data: List[int], sensorbuffer: str = "char", slot: int = 1 - ) -> bool: + def send_fpdata(self, data: List[int], sensorbuffer: str = "char", slot: int = 1) -> bool: """Requests the sensor to receive data, either a fingerprint image or a character/template data. Data is the payload only.""" - if slot not in (1, 2): + if slot not in {1, 2}: # raise error or use default value? slot = 2 if sensorbuffer == "image": @@ -259,7 +256,7 @@ def read_templates(self) -> int: """Requests the sensor to list of all template locations in use and stores them in self.templates. Returns the packet error code or OK success""" - from math import ceil # pylint: disable=import-outside-toplevel + from math import ceil # noqa: PLC0415 self.templates = [] self.read_sysparam() @@ -291,9 +288,7 @@ def finger_fast_search(self) -> int: # or base the page on module's capacity self.read_sysparam() capacity = self.library_size - self._send_packet( - [_HISPEEDSEARCH, 0x01, 0x00, 0x00, capacity >> 8, capacity & 0xFF] - ) + self._send_packet([_HISPEEDSEARCH, 0x01, 0x00, 0x00, capacity >> 8, capacity & 0xFF]) r = self._get_packet(16) self.finger_id, self.confidence = struct.unpack(">HH", bytes(r[1:5])) self._print_debug("finger_fast_search packet:", r, data_type="hex") @@ -309,9 +304,7 @@ def finger_search(self) -> int: and self.confidence. Returns the packet error code or OK success""" self.read_sysparam() capacity = self.library_size - self._send_packet( - [_FINGERPRINTSEARCH, 0x01, 0x00, 0x00, capacity >> 8, capacity & 0xFF] - ) + self._send_packet([_FINGERPRINTSEARCH, 0x01, 0x00, 0x00, capacity >> 8, capacity & 0xFF]) r = self._get_packet(16) self.finger_id, self.confidence = struct.unpack(">HH", bytes(r[1:5])) self._print_debug("finger_search packet:", r, data_type="hex") @@ -327,9 +320,7 @@ def compare_templates(self) -> int: self._print_debug("compare_templates confidence:", self.confidence) return r[0] - def set_led( - self, color: int = 1, mode: int = 3, speed: int = 0x80, cycles: int = 0 - ) -> int: + def set_led(self, color: int = 1, mode: int = 3, speed: int = 0x80, cycles: int = 0) -> int: """LED function -- only for R503 Sensor. Parameters: See User Manual for full details color: 1=red, 2=blue, 3=purple @@ -508,6 +499,6 @@ def _print_debug(self, info: str, data: Union[int, str], data_type: str = "str") return if data_type == "hex": - print("*** DEBUG ==>", info, ["{:02x}".format(i) for i in data]) + print("*** DEBUG ==>", info, [f"{i:02x}" for i in data]) elif data_type == "str": print("*** DEBUG ==>", info, data) diff --git a/docs/api.rst b/docs/api.rst index 4538610..e274cc9 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1,5 +1,8 @@ .. If you created a package, create one automodule per module in the package. +API Reference +############# + .. automodule:: adafruit_fingerprint :members: diff --git a/docs/conf.py b/docs/conf.py index d8044a5..a8e316f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,12 +1,10 @@ -# -*- coding: utf-8 -*- - # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # # SPDX-License-Identifier: MIT +import datetime import os import sys -import datetime sys.path.insert(0, os.path.abspath("..")) @@ -45,9 +43,7 @@ creation_year = "2017" current_year = str(datetime.datetime.now().year) year_duration = ( - current_year - if current_year == creation_year - else creation_year + " - " + current_year + current_year if current_year == creation_year else creation_year + " - " + current_year ) copyright = year_duration + " ladyada" author = "ladyada" diff --git a/examples/fingerprint_picturetest.py b/examples/fingerprint_picturetest.py index c733c79..bb79b58 100644 --- a/examples/fingerprint_picturetest.py +++ b/examples/fingerprint_picturetest.py @@ -18,9 +18,11 @@ """ import time + import numpy as np -from matplotlib import pyplot as plt import serial +from matplotlib import pyplot as plt + import adafruit_fingerprint # led = DigitalInOut(board.D13) diff --git a/examples/fingerprint_r503.py b/examples/fingerprint_r503.py index 9c9590b..28ba818 100644 --- a/examples/fingerprint_r503.py +++ b/examples/fingerprint_r503.py @@ -2,8 +2,10 @@ # SPDX-License-Identifier: MIT import time + import board import busio + import adafruit_fingerprint uart = busio.UART(board.TX, board.RX, baudrate=57600) diff --git a/examples/fingerprint_r503_rpi.py b/examples/fingerprint_r503_rpi.py index 3ffb7a2..17f3dd3 100644 --- a/examples/fingerprint_r503_rpi.py +++ b/examples/fingerprint_r503_rpi.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: MIT import time + import serial import adafruit_fingerprint @@ -173,7 +174,7 @@ def save_fingerprint_image(filename): return False # let PIL take care of the image headers and file structure - from PIL import Image # pylint: disable=import-outside-toplevel + from PIL import Image # noqa: PLC0415 img = Image.new("L", (192, 192), "white") pixeldata = img.load() @@ -213,7 +214,7 @@ def get_num(max_number): i = -1 while (i > max_number - 1) or (i < 0): try: - i = int(input("Enter ID # from 0-{}: ".format(max_number - 1))) + i = int(input(f"Enter ID # from 0-{max_number - 1}: ")) except ValueError: pass return i diff --git a/examples/fingerprint_simpletest.py b/examples/fingerprint_simpletest.py index 9e916fc..6180ebb 100644 --- a/examples/fingerprint_simpletest.py +++ b/examples/fingerprint_simpletest.py @@ -2,9 +2,11 @@ # SPDX-License-Identifier: MIT import time + import board import busio from digitalio import DigitalInOut, Direction + import adafruit_fingerprint led = DigitalInOut(board.D13) diff --git a/examples/fingerprint_simpletest_rpi.py b/examples/fingerprint_simpletest_rpi.py index cf10d27..48d1413 100644 --- a/examples/fingerprint_simpletest_rpi.py +++ b/examples/fingerprint_simpletest_rpi.py @@ -2,11 +2,11 @@ # SPDX-License-Identifier: MIT import time + import serial import adafruit_fingerprint - # import board # uart = busio.UART(board.TX, board.RX, baudrate=57600) @@ -162,7 +162,7 @@ def save_fingerprint_image(filename): pass # let PIL take care of the image headers and file structure - from PIL import Image # pylint: disable=import-outside-toplevel + from PIL import Image # noqa: PLC0415 img = Image.new("L", (256, 288), "white") pixeldata = img.load() @@ -202,7 +202,7 @@ def get_num(max_number): i = -1 while (i > max_number - 1) or (i < 0): try: - i = int(input("Enter ID # from 0-{}: ".format(max_number - 1))) + i = int(input(f"Enter ID # from 0-{max_number - 1}: ")) except ValueError: pass return i diff --git a/examples/fingerprint_template_file_compare.py b/examples/fingerprint_template_file_compare.py index 4d58297..2a3c49b 100644 --- a/examples/fingerprint_template_file_compare.py +++ b/examples/fingerprint_template_file_compare.py @@ -21,10 +21,9 @@ * `Panel Mount Fingerprint sensor `_ (Product ID: 4651) """ - import serial -import adafruit_fingerprint +import adafruit_fingerprint # import board (if you are using a micropython board) # uart = busio.UART(board.TX, board.RX, baudrate=57600) @@ -187,7 +186,7 @@ def set_led_local(color=1, mode=3, speed=0x80, cycles=0): print("----------------") c = input("> ") - if c in ("x", "q"): + if c in {"x", "q"}: print("Exiting fingerprint example program") # turn off LED set_led_local(mode=4) diff --git a/examples/fingerprint_template_folder_compare_with_file_rpi.py b/examples/fingerprint_template_folder_compare_with_file_rpi.py index b68ef5b..579a2ee 100644 --- a/examples/fingerprint_template_folder_compare_with_file_rpi.py +++ b/examples/fingerprint_template_folder_compare_with_file_rpi.py @@ -27,6 +27,7 @@ import serial from PIL import Image + import adafruit_fingerprint # If using with a computer such as Linux/RaspberryPi, Mac, Windows with USB/serial converter: diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..36332ff --- /dev/null +++ b/ruff.toml @@ -0,0 +1,105 @@ +# SPDX-FileCopyrightText: 2024 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +target-version = "py38" +line-length = 100 + +[lint] +preview = true +select = ["I", "PL", "UP"] + +extend-select = [ + "D419", # empty-docstring + "E501", # line-too-long + "W291", # trailing-whitespace + "PLC0414", # useless-import-alias + "PLC2401", # non-ascii-name + "PLC2801", # unnecessary-dunder-call + "PLC3002", # unnecessary-direct-lambda-call + "E999", # syntax-error + "PLE0101", # return-in-init + "F706", # return-outside-function + "F704", # yield-outside-function + "PLE0116", # continue-in-finally + "PLE0117", # nonlocal-without-binding + "PLE0241", # duplicate-bases + "PLE0302", # unexpected-special-method-signature + "PLE0604", # invalid-all-object + "PLE0605", # invalid-all-format + "PLE0643", # potential-index-error + "PLE0704", # misplaced-bare-raise + "PLE1141", # dict-iter-missing-items + "PLE1142", # await-outside-async + "PLE1205", # logging-too-many-args + "PLE1206", # logging-too-few-args + "PLE1307", # bad-string-format-type + "PLE1310", # bad-str-strip-call + "PLE1507", # invalid-envvar-value + "PLE2502", # bidirectional-unicode + "PLE2510", # invalid-character-backspace + "PLE2512", # invalid-character-sub + "PLE2513", # invalid-character-esc + "PLE2514", # invalid-character-nul + "PLE2515", # invalid-character-zero-width-space + "PLR0124", # comparison-with-itself + "PLR0202", # no-classmethod-decorator + "PLR0203", # no-staticmethod-decorator + "UP004", # useless-object-inheritance + "PLR0206", # property-with-parameters + "PLR0904", # too-many-public-methods + "PLR0911", # too-many-return-statements + "PLR0912", # too-many-branches + "PLR0913", # too-many-arguments + "PLR0914", # too-many-locals + "PLR0915", # too-many-statements + "PLR0916", # too-many-boolean-expressions + "PLR1702", # too-many-nested-blocks + "PLR1704", # redefined-argument-from-local + "PLR1711", # useless-return + "C416", # unnecessary-comprehension + "PLR1733", # unnecessary-dict-index-lookup + "PLR1736", # unnecessary-list-index-lookup + + # ruff reports this rule is unstable + #"PLR6301", # no-self-use + + "PLW0108", # unnecessary-lambda + "PLW0120", # useless-else-on-loop + "PLW0127", # self-assigning-variable + "PLW0129", # assert-on-string-literal + "B033", # duplicate-value + "PLW0131", # named-expr-without-context + "PLW0245", # super-without-brackets + "PLW0406", # import-self + "PLW0602", # global-variable-not-assigned + "PLW0603", # global-statement + "PLW0604", # global-at-module-level + + # fails on the try: import typing used by libraries + #"F401", # unused-import + + "F841", # unused-variable + "E722", # bare-except + "PLW0711", # binary-op-exception + "PLW1501", # bad-open-mode + "PLW1508", # invalid-envvar-default + "PLW1509", # subprocess-popen-preexec-fn + "PLW2101", # useless-with-lock + "PLW3301", # nested-min-max +] + +ignore = [ + "PLR2004", # magic-value-comparison + "UP030", # format literals + "PLW1514", # unspecified-encoding + "PLR0913", # too-many-arguments + "PLR0915", # too-many-statements + "PLR0917", # too-many-positional-arguments + "PLR0904", # too-many-public-methods + "PLR0912", # too-many-branches + "PLR0916", # too-many-boolean-expressions +] + +[format] +line-ending = "lf" From 27e7e240329bdcccfc19b673edeb4878e15bbdfe Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 14 May 2025 10:33:20 -0500 Subject: [PATCH 34/35] remove pylint disables --- examples/fingerprint_picturetest.py | 3 --- examples/fingerprint_r503.py | 3 --- examples/fingerprint_r503_rpi.py | 6 ------ examples/fingerprint_simpletest.py | 3 --- examples/fingerprint_simpletest_rpi.py | 6 ------ examples/fingerprint_template_file_compare.py | 3 --- 6 files changed, 24 deletions(-) diff --git a/examples/fingerprint_picturetest.py b/examples/fingerprint_picturetest.py index bb79b58..95abd80 100644 --- a/examples/fingerprint_picturetest.py +++ b/examples/fingerprint_picturetest.py @@ -58,7 +58,6 @@ def get_fingerprint(): return True -# pylint: disable=too-many-branches def get_fingerprint_detail(): """Get a finger print image, template it, and see if it matches! This time, print out each error instead of just returning on failure""" @@ -92,7 +91,6 @@ def get_fingerprint_detail(): print("Searching...", end="") i = finger.finger_fast_search() - # pylint: disable=no-else-return # This block needs to be refactored when it can be tested. if i == adafruit_fingerprint.OK: print("Found fingerprint!") @@ -146,7 +144,6 @@ def get_fingerprint_preview(): return True -# pylint: disable=too-many-statements def enroll_finger(location): """Take a 2 finger images and template it, then store in 'location'""" for fingerimg in range(1, 3): diff --git a/examples/fingerprint_r503.py b/examples/fingerprint_r503.py index 28ba818..8bc5ef1 100644 --- a/examples/fingerprint_r503.py +++ b/examples/fingerprint_r503.py @@ -37,7 +37,6 @@ def get_fingerprint(): return True -# pylint: disable=too-many-branches def get_fingerprint_detail(): """Get a finger print image, template it, and see if it matches! This time, print out each error instead of just returning on failure""" @@ -71,7 +70,6 @@ def get_fingerprint_detail(): print("Searching...", end="") i = finger.finger_fast_search() - # pylint: disable=no-else-return # This block needs to be refactored when it can be tested. if i == adafruit_fingerprint.OK: print("Found fingerprint!") @@ -84,7 +82,6 @@ def get_fingerprint_detail(): return False -# pylint: disable=too-many-statements def enroll_finger(location): """Take a 2 finger images and template it, then store in 'location'""" for fingerimg in range(1, 3): diff --git a/examples/fingerprint_r503_rpi.py b/examples/fingerprint_r503_rpi.py index 17f3dd3..ad6161d 100644 --- a/examples/fingerprint_r503_rpi.py +++ b/examples/fingerprint_r503_rpi.py @@ -38,7 +38,6 @@ def get_fingerprint(): return True -# pylint: disable=too-many-branches def get_fingerprint_detail(): """Get a finger print image, template it, and see if it matches! This time, print out each error instead of just returning on failure""" @@ -72,7 +71,6 @@ def get_fingerprint_detail(): print("Searching...", end="") i = finger.finger_fast_search() - # pylint: disable=no-else-return # This block needs to be refactored when it can be tested. if i == adafruit_fingerprint.OK: print("Found fingerprint!") @@ -85,7 +83,6 @@ def get_fingerprint_detail(): return False -# pylint: disable=too-many-statements def enroll_finger(location): """Take a 2 finger images and template it, then store in 'location'""" for fingerimg in range(1, 3): @@ -185,11 +182,8 @@ def save_fingerprint_image(filename): # module then copies the image data to the image placeholder "img" # pixel by pixel. please refer to section 4.2.1 of the manual for # more details. thanks to Bastian Raschke and Danylo Esterman. - # pylint: disable=invalid-name x = 0 - # pylint: disable=invalid-name y = 0 - # pylint: disable=consider-using-enumerate for i in range(len(result)): pixeldata[x, y] = (int(result[i]) >> 4) * 17 x += 1 diff --git a/examples/fingerprint_simpletest.py b/examples/fingerprint_simpletest.py index 6180ebb..39bbd37 100644 --- a/examples/fingerprint_simpletest.py +++ b/examples/fingerprint_simpletest.py @@ -41,7 +41,6 @@ def get_fingerprint(): return True -# pylint: disable=too-many-branches def get_fingerprint_detail(): """Get a finger print image, template it, and see if it matches! This time, print out each error instead of just returning on failure""" @@ -75,7 +74,6 @@ def get_fingerprint_detail(): print("Searching...", end="") i = finger.finger_fast_search() - # pylint: disable=no-else-return # This block needs to be refactored when it can be tested. if i == adafruit_fingerprint.OK: print("Found fingerprint!") @@ -88,7 +86,6 @@ def get_fingerprint_detail(): return False -# pylint: disable=too-many-statements def enroll_finger(location): """Take a 2 finger images and template it, then store in 'location'""" for fingerimg in range(1, 3): diff --git a/examples/fingerprint_simpletest_rpi.py b/examples/fingerprint_simpletest_rpi.py index 48d1413..019faf5 100644 --- a/examples/fingerprint_simpletest_rpi.py +++ b/examples/fingerprint_simpletest_rpi.py @@ -38,7 +38,6 @@ def get_fingerprint(): return True -# pylint: disable=too-many-branches def get_fingerprint_detail(): """Get a finger print image, template it, and see if it matches! This time, print out each error instead of just returning on failure""" @@ -72,7 +71,6 @@ def get_fingerprint_detail(): print("Searching...", end="") i = finger.finger_fast_search() - # pylint: disable=no-else-return # This block needs to be refactored when it can be tested. if i == adafruit_fingerprint.OK: print("Found fingerprint!") @@ -85,7 +83,6 @@ def get_fingerprint_detail(): return False -# pylint: disable=too-many-statements def enroll_finger(location): """Take a 2 finger images and template it, then store in 'location'""" for fingerimg in range(1, 3): @@ -173,11 +170,8 @@ def save_fingerprint_image(filename): # module then copies the image data to the image placeholder "img" # pixel by pixel. please refer to section 4.2.1 of the manual for # more details. thanks to Bastian Raschke and Danylo Esterman. - # pylint: disable=invalid-name x = 0 - # pylint: disable=invalid-name y = 0 - # pylint: disable=consider-using-enumerate for i in range(len(result)): pixeldata[x, y] = (int(result[i]) >> 4) * 17 x += 1 diff --git a/examples/fingerprint_template_file_compare.py b/examples/fingerprint_template_file_compare.py index 2a3c49b..efe1edb 100644 --- a/examples/fingerprint_template_file_compare.py +++ b/examples/fingerprint_template_file_compare.py @@ -50,7 +50,6 @@ def sensor_reset(): print("Sensor is reset.") -# pylint: disable=too-many-branches def fingerprint_check_file(): """Compares a new fingerprint template to an existing template stored in a file This is useful when templates are stored centrally (i.e. in a database)""" @@ -80,7 +79,6 @@ def fingerprint_check_file(): return False -# pylint: disable=too-many-statements def enroll_save_to_file(): """Take a 2 finger images and template it, then store it in a file""" set_led_local(color=3, mode=1) @@ -153,7 +151,6 @@ def enroll_save_to_file(): return True -# pylint: disable=broad-except def set_led_local(color=1, mode=3, speed=0x80, cycles=0): """this is to make sure LED doesn't interfer with example running on models without LED support - needs testing""" From 5fa0d6e1096f25996b76c648b07e2a8ee7698a95 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 28 May 2025 15:16:48 -0500 Subject: [PATCH 35/35] merge main, format code --- adafruit_fingerprint.py | 1 + 1 file changed, 1 insertion(+) diff --git a/adafruit_fingerprint.py b/adafruit_fingerprint.py index 940570d..0057498 100644 --- a/adafruit_fingerprint.py +++ b/adafruit_fingerprint.py @@ -27,6 +27,7 @@ try: from typing import List, Tuple, Union + from serial import Serial except ImportError: pass