import network, socket, time, os
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
# ===== OLED Setup =====
i2c = I2C(0, scl=Pin(1), sda=Pin(0)) # SDA=GPIO0, SCL=GPIO1
oled = SSD1306_I2C(128, 64, i2c)
# ===== Lock Setup =====
LOCK_PIN = 15
lock = Pin(LOCK_PIN, Pin.OUT)
lock.value(0) # locked
# ===== Password Storage =====
def load_password():
try:
with open("password.txt", "r") as f:
return f.read().strip()
except:
with open("password.txt", "w") as f:
f.write("1234")
return "1234"
def save_password(new_pass):
with open("password.txt", "w") as f:
f.write(new_pass.strip())
current_password = load_password()
# ===== Keypad Setup (4x4) =====
rows = [Pin(x, Pin.OUT) for x in (2,3,4,5)] # row pins
cols = [Pin(x, Pin.IN, Pin.PULL_UP) for x in (6,7,8,9)] # col pins
keys = [
["1","2","3","A"],
["4","5","6","B"],
["7","8","9","C"],
["*","0","#","D"]
]
def get_key():
"""Scan keypad and return key or None."""
for r in range(4):
rows[r].low()
for c in range(4):
if cols[c].value() == 0:
while cols[c].value() == 0:
time.sleep(0.02) # debounce
rows[r].high()
return keys[r][c]
rows[r].high()
return None
# ===== Manual Unlock Logic =====
typed = ""
def manual_unlock():
global typed, current_password
key = get_key()
if key:
if key == "#": # Enter key
if typed == current_password:
oled.fill(0)
oled.text("Unlocked!", 20, 30)
oled.show()
lock.value(1)
time.sleep(3)
lock.value(0)
typed = ""
else:
oled.fill(0)
oled.text("Wrong PIN!", 20, 30)
oled.show()
time.sleep(2)
typed = ""
elif key == "*": # Clear
typed = ""
else:
typed += key
show_input()
def show_input():
oled.fill(0)
oled.text("Enter PIN:", 10, 10)
oled.text("*" * len(typed), 40, 30)
oled.show()
# ===== Web Page =====
def web_page(message=""):
return f"""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Wi-Fi Door Lock</title>
<style>
body {{
font-family: Arial;
text-align: center;
background: linear-gradient(to right, #4facfe, #00f2fe);
padding-top: 40px;
color: white;
}}
input {{
padding: 10px;
width: 220px;
border-radius: 5px;
border: none;
margin-bottom: 10px;
}}
button {{
padding: 10px 20px;
background-color: #005fcc;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}}
.box {{
background-color: rgba(0, 0, 0, 0.2);
padding: 20px;
border-radius: 10px;
width: 300px;
margin: auto;
}}
.message {{
margin-top: 15px;
font-size: 18px;
color: yellow;
}}
</style>
</head>
<body>
<h1>Smart Wi-Fi Door Lock</h1>
<div class="box">
<h3>Unlock Door</h3>
<form action="/unlock" method="POST">
<input type="password" name="pass" placeholder="Enter Password"><br>
<button type="submit">Unlock</button>
</form>
</div>
<br>
<div class="box">
<h3>Change Password</h3>
<form action="/update" method="POST">
<input type="password" name="old" placeholder="Current Password"><br>
<input type="password" name="new" placeholder="New Password"><br>
<button type="submit">Update</button>
</form>
</div>
<div class="message">{message}</div>
</body>
</html>"""
# ===== Wi-Fi Access Point =====
ap = network.WLAN(network.AP_IF)
ap.config(essid='PicoDoorLock', password='raspberry')
ap.active(True)
while not ap.active():
pass
print("AP started:", ap.ifconfig())
# ===== HTTP Server =====
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(1)
print("Web server running at http://192.168.4.1")
# ===== Status Message =====
last_status_message = "🔒 Door is Locked"
# ===== Main Loop =====
show_input()
while True:
# --- Manual Unlock ---
manual_unlock()
# --- Web Server Handling ---
try:
s.settimeout(0.1) # non-blocking for keypad responsiveness
cl, addr = s.accept()
except OSError:
continue # no client → continue keypad scanning
request = cl.recv(1024).decode()
method = request.split(" ")[0]
path = request.split(" ")[1]
try:
if method == "POST":
headers_end = request.find("\r\n\r\n") + 4
body = request[headers_end:]
form_data = {}
for pair in body.split("&"):
if "=" in pair:
k, v = pair.split("=")
form_data[k] = v
if path == "/unlock":
user_pass = form_data.get("pass", "")
if user_pass == current_password:
lock.value(1)
last_status_message = "✅ Door Unlocked!"
time.sleep(3)
lock.value(0)
last_status_message = "🔒 Door Locked"
else:
last_status_message = "❌ Incorrect Password!"
elif path == "/update":
old = form_data.get("old", "")
new = form_data.get("new", "")
if old == current_password and len(new) >= 3:
save_password(new)
current_password = new
last_status_message = "✅ Password Updated!"
elif old != current_password:
last_status_message = "❌ Current Password Wrong!"
else:
last_status_message = "⚠️ New Password Too Short!"
cl.send("HTTP/1.1 303 See Other\r\nLocation: /\r\n\r\n")
else:
response = web_page(message=last_status_message)
cl.send("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n")
cl.send(response)
except Exception as e:
print("Error:", e)
cl.send("HTTP/1.1 500 Internal Server Error\r\n\r\nError")
cl.close()