Home Upgrade Search Memberlist Extras Hacker Tools Award Goals Help Wiki Contact

Raspberry Pi 

Magnetic Door Lock

I’ve developed a basic prototype of an electromagnetic door lock using a Raspberry Pi. The lock works well, but I’ve noticed that the electromagnetic component can become warm to the touch after a few days of continuous power. To prevent overheating, I’m considering adding a secondary locking mechanism for long-term use. I’m still evaluating the pros and cons of different options to determine the best solution. Implementing FaceID will take more time due to challenges related to varying lighting conditions and overall complexity. I’ll share updates on that as progress is made.

PARTS LIST

[Image: 1.png?ex=66e2e253&is=66e190d3&hm=7b37bc8...746ee175d&]

Code
import I2C_LCD_driver
import RPi.GPIO as GPIO
from time import sleep

# Pin configuration
COLUMNS = [5, 6, 13, 19]
ROWS = [12, 16, 20, 21]
BUZZER = 17
RELAY = 27
SECRET_CODE = "1234"

# Initialize variables
relay_state = True
keypad_pressed = -1
input_code = ""

# Setup GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUZZER, GPIO.OUT)
GPIO.setup(RELAY, GPIO.OUT)
GPIO.output(RELAY, GPIO.HIGH)

for pin in COLUMNS:
    GPIO.setup(pin, GPIO.OUT)
for pin in ROWS:
    GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

# Initialize LCD
lcd = I2C_LCD_driver.lcd()
lcd.lcd_display_string("System loading", 1, 1)
for a in range(16):
    lcd.lcd_display_string(".", 2, a)
    sleep(0.1)
lcd.lcd_clear()

# Callback for keypad press
def keypad_callback(channel):
    global keypad_pressed
    if keypad_pressed == -1:
        keypad_pressed = channel

# Register event detection for rows
for row in ROWS:
    GPIO.add_event_detect(row, GPIO.RISING, callback=keypad_callback)

# Set all columns to a specific state
def set_all_columns(state):
    for col in COLUMNS:
        GPIO.output(col, state)

# Handle commands for checking or clearing PIN
def handle_commands():
    global relay_state, input_code
    pressed = False
    GPIO.output(COLUMNS[0], GPIO.HIGH)
   
    if GPIO.input(ROWS[0]) == 1:
        lcd.lcd_clear()
        lcd.lcd_display_string("Clear", 1, 5)
        sleep(1)
        pressed = True
    elif GPIO.input(ROWS[1]) == 1:
        if input_code == SECRET_CODE:
            lcd.lcd_clear()
            lcd.lcd_display_string("Successful", 1, 3)
            relay_state = not relay_state
            GPIO.output(RELAY, GPIO.LOW if relay_state else GPIO.HIGH)
            GPIO.output(BUZZER, GPIO.HIGH)
            sleep(0.3)
            GPIO.output(BUZZER, GPIO.LOW)
            sleep(1)
        else:
            lcd.lcd_clear()
            lcd.lcd_display_string("Wrong PIN!", 1, 3)
            for _ in range(3):
                GPIO.output(BUZZER, GPIO.HIGH)
                sleep(0.3)
                GPIO.output(BUZZER, GPIO.LOW)
                sleep(0.3)
        pressed = True
   
    GPIO.output(COLUMNS[0], GPIO.LOW)
    if pressed:
        input_code = ""
    return pressed

# Read input from keypad
def read_input(column, characters):
    global input_code
    GPIO.output(column, GPIO.HIGH)
    for i, row in enumerate(ROWS):
        if GPIO.input(row) == 1:
            input_code += characters[i]
            lcd.lcd_display_string(input_code, 2, 0)
    GPIO.output(column, GPIO.LOW)

# Main loop
try:
    while True:
        lcd.lcd_display_string("Enter your PIN:", 1, 0)
        if keypad_pressed != -1:
            set_all_columns(GPIO.HIGH)
            if GPIO.input(keypad_pressed) == 0:
                keypad_pressed = -1
            else:
                sleep(0.1)
        else:
            if not handle_commands():
                read_input(COLUMNS[0], ["D", "C", "B", "A"])
                read_input(COLUMNS[1], ["#", "9", "6", "3"])
                read_input(COLUMNS[2], ["0", "8", "5", "2"])
                read_input(COLUMNS[3], ["*", "7", "4", "1"])
                sleep(0.1)
            else:
                sleep(0.1)
except KeyboardInterrupt:
    print("Stopped!")
                PYTHON | C# | LUA

[Image: forum.png]
I like the idea of creating your own device but for about $40 you can buy one and put it on a basic 12/24v power supply depending on what you purchase and use a wireless relay device that can fit on a keychain, Won't have any issues with overheating
[Image: 0HDwfE0.png]
Crafty stuff. Like the idea.
(Sep 11, 2024 06:56 AM)Spookz Wrote:  I’ve developed a basic prototype of an electromagnetic door lock using a Raspberry Pi. The lock works well, but I’ve noticed that the electromagnetic component can become warm to the touch after a few days of continuous power. To prevent overheating, I’m considering adding a secondary locking mechanism for long-term use. I’m still evaluating the pros and cons of different options to determine the best solution. Implementing FaceID will take more time due to challenges related to varying lighting conditions and overall complexity. I’ll share updates on that as progress is made.

PARTS LIST

[Image: 1.png?ex=66e2e253&is=66e190d3&hm=7b37bc8...746ee175d&]

Code
import I2C_LCD_driver
import RPi.GPIO as GPIO
from time import sleep

# Pin configuration
COLUMNS = [5, 6, 13, 19]
ROWS = [12, 16, 20, 21]
BUZZER = 17
RELAY = 27
SECRET_CODE = "1234"

# Initialize variables
relay_state = True
keypad_pressed = -1
input_code = ""

# Setup GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUZZER, GPIO.OUT)
GPIO.setup(RELAY, GPIO.OUT)
GPIO.output(RELAY, GPIO.HIGH)

for pin in COLUMNS:
    GPIO.setup(pin, GPIO.OUT)
for pin in ROWS:
    GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

# Initialize LCD
lcd = I2C_LCD_driver.lcd()
lcd.lcd_display_string("System loading", 1, 1)
for a in range(16):
    lcd.lcd_display_string(".", 2, a)
    sleep(0.1)
lcd.lcd_clear()

# Callback for keypad press
def keypad_callback(channel):
    global keypad_pressed
    if keypad_pressed == -1:
        keypad_pressed = channel

# Register event detection for rows
for row in ROWS:
    GPIO.add_event_detect(row, GPIO.RISING, callback=keypad_callback)

# Set all columns to a specific state
def set_all_columns(state):
    for col in COLUMNS:
        GPIO.output(col, state)

# Handle commands for checking or clearing PIN
def handle_commands():
    global relay_state, input_code
    pressed = False
    GPIO.output(COLUMNS[0], GPIO.HIGH)
   
    if GPIO.input(ROWS[0]) == 1:
        lcd.lcd_clear()
        lcd.lcd_display_string("Clear", 1, 5)
        sleep(1)
        pressed = True
    elif GPIO.input(ROWS[1]) == 1:
        if input_code == SECRET_CODE:
            lcd.lcd_clear()
            lcd.lcd_display_string("Successful", 1, 3)
            relay_state = not relay_state
            GPIO.output(RELAY, GPIO.LOW if relay_state else GPIO.HIGH)
            GPIO.output(BUZZER, GPIO.HIGH)
            sleep(0.3)
            GPIO.output(BUZZER, GPIO.LOW)
            sleep(1)
        else:
            lcd.lcd_clear()
            lcd.lcd_display_string("Wrong PIN!", 1, 3)
            for _ in range(3):
                GPIO.output(BUZZER, GPIO.HIGH)
                sleep(0.3)
                GPIO.output(BUZZER, GPIO.LOW)
                sleep(0.3)
        pressed = True
   
    GPIO.output(COLUMNS[0], GPIO.LOW)
    if pressed:
        input_code = ""
    return pressed

# Read input from keypad
def read_input(column, characters):
    global input_code
    GPIO.output(column, GPIO.HIGH)
    for i, row in enumerate(ROWS):
        if GPIO.input(row) == 1:
            input_code += characters[i]
            lcd.lcd_display_string(input_code, 2, 0)
    GPIO.output(column, GPIO.LOW)

# Main loop
try:
    while True:
        lcd.lcd_display_string("Enter your PIN:", 1, 0)
        if keypad_pressed != -1:
            set_all_columns(GPIO.HIGH)
            if GPIO.input(keypad_pressed) == 0:
                keypad_pressed = -1
            else:
                sleep(0.1)
        else:
            if not handle_commands():
                read_input(COLUMNS[0], ["D", "C", "B", "A"])
                read_input(COLUMNS[1], ["#", "9", "6", "3"])
                read_input(COLUMNS[2], ["0", "8", "5", "2"])
                read_input(COLUMNS[3], ["*", "7", "4", "1"])
                sleep(0.1)
            else:
                sleep(0.1)
except KeyboardInterrupt:
    print("Stopped!")

Also I forgot to mention instead of using a maglock you can use a door strike lock, They have them fail safe and fail secure depending on your usage and they're made for any door style
[Image: 0HDwfE0.png]
if anyone cares, i thought i would just mention that theres probably a timing vulnerability in your implementation. the way you compare the input code string using the == operator uses a memcmp underneath (check the cpython source code) which compares the string byte by byte (probably musl implementation on your pi). the problem with this is that if it fails on a specific byte, the function will return early and you can measure the time it takes when this happens. this is a side channel timing attack that can be brute forced.

proper string comparison checking should be constant time like this:

Code
def secure_strcmp(s1: str, s2: str, length: int):
    result = True

    for i in range(length):
        result &= s1[i] == s2[i]

    return result
(Sep 11, 2024 06:56 AM)Spookz Wrote:  I’ve developed a basic prototype of an electromagnetic door lock using a Raspberry Pi. The lock works well, but I’ve noticed that the electromagnetic component can become warm to the touch after a few days of continuous power. To prevent overheating, I’m considering adding a secondary locking mechanism for long-term use. I’m still evaluating the pros and cons of different options to determine the best solution. Implementing FaceID will take more time due to challenges related to varying lighting conditions and overall complexity. I’ll share updates on that as progress is made.

PARTS LIST

[Image: 1.png?ex=66e2e253&is=66e190d3&hm=7b37bc8...746ee175d&]

Code
import I2C_LCD_driver
import RPi.GPIO as GPIO
from time import sleep

# Pin configuration
COLUMNS = [5, 6, 13, 19]
ROWS = [12, 16, 20, 21]
BUZZER = 17
RELAY = 27
SECRET_CODE = "1234"

# Initialize variables
relay_state = True
keypad_pressed = -1
input_code = ""

# Setup GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUZZER, GPIO.OUT)
GPIO.setup(RELAY, GPIO.OUT)
GPIO.output(RELAY, GPIO.HIGH)

for pin in COLUMNS:
    GPIO.setup(pin, GPIO.OUT)
for pin in ROWS:
    GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

# Initialize LCD
lcd = I2C_LCD_driver.lcd()
lcd.lcd_display_string("System loading", 1, 1)
for a in range(16):
    lcd.lcd_display_string(".", 2, a)
    sleep(0.1)
lcd.lcd_clear()

# Callback for keypad press
def keypad_callback(channel):
    global keypad_pressed
    if keypad_pressed == -1:
        keypad_pressed = channel

# Register event detection for rows
for row in ROWS:
    GPIO.add_event_detect(row, GPIO.RISING, callback=keypad_callback)

# Set all columns to a specific state
def set_all_columns(state):
    for col in COLUMNS:
        GPIO.output(col, state)

# Handle commands for checking or clearing PIN
def handle_commands():
    global relay_state, input_code
    pressed = False
    GPIO.output(COLUMNS[0], GPIO.HIGH)
   
    if GPIO.input(ROWS[0]) == 1:
        lcd.lcd_clear()
        lcd.lcd_display_string("Clear", 1, 5)
        sleep(1)
        pressed = True
    elif GPIO.input(ROWS[1]) == 1:
        if input_code == SECRET_CODE:
            lcd.lcd_clear()
            lcd.lcd_display_string("Successful", 1, 3)
            relay_state = not relay_state
            GPIO.output(RELAY, GPIO.LOW if relay_state else GPIO.HIGH)
            GPIO.output(BUZZER, GPIO.HIGH)
            sleep(0.3)
            GPIO.output(BUZZER, GPIO.LOW)
            sleep(1)
        else:
            lcd.lcd_clear()
            lcd.lcd_display_string("Wrong PIN!", 1, 3)
            for _ in range(3):
                GPIO.output(BUZZER, GPIO.HIGH)
                sleep(0.3)
                GPIO.output(BUZZER, GPIO.LOW)
                sleep(0.3)
        pressed = True
   
    GPIO.output(COLUMNS[0], GPIO.LOW)
    if pressed:
        input_code = ""
    return pressed

# Read input from keypad
def read_input(column, characters):
    global input_code
    GPIO.output(column, GPIO.HIGH)
    for i, row in enumerate(ROWS):
        if GPIO.input(row) == 1:
            input_code += characters[i]
            lcd.lcd_display_string(input_code, 2, 0)
    GPIO.output(column, GPIO.LOW)

# Main loop
try:
    while True:
        lcd.lcd_display_string("Enter your PIN:", 1, 0)
        if keypad_pressed != -1:
            set_all_columns(GPIO.HIGH)
            if GPIO.input(keypad_pressed) == 0:
                keypad_pressed = -1
            else:
                sleep(0.1)
        else:
            if not handle_commands():
                read_input(COLUMNS[0], ["D", "C", "B", "A"])
                read_input(COLUMNS[1], ["#", "9", "6", "3"])
                read_input(COLUMNS[2], ["0", "8", "5", "2"])
                read_input(COLUMNS[3], ["*", "7", "4", "1"])
                sleep(0.1)
            else:
                sleep(0.1)
except KeyboardInterrupt:
    print("Stopped!")

great job bro :) ✌👍


Possibly Related Threads...
Thread / Author Replies Views Last Post
by SIM-5234130Aug 18, 2024 07:25 AM 13 552 Aug 18, 2024 07:25 AM
Last Post: SIM-5234130
[R-Pi] by SpookzMay 19, 2023 07:14 PM 4 332 May 19, 2023 07:14 PM
Last Post: Spookz
[R-Pi] by SpookzMay 18, 2023 04:14 PM 6 294 May 18, 2023 04:14 PM
Last Post: Zexo