202 lines
5.6 KiB
Python
202 lines
5.6 KiB
Python
"""
|
|
QR Code Shopping Scanner
|
|
Author: Leart Ramushi
|
|
Version: 1.0
|
|
Bsc Artificial Intelligence in Software Engineering CDS-205
|
|
|
|
Hinweis:
|
|
- Kommentare dieses Projekts wurden mit Unterstützung von ChatGPT erstellt.
|
|
- Die Funktion `scan_qr_codes` wurde gemeinsam mit ChatGPT entwickelt.
|
|
- Auch Error- bzw. Fehlermeldungen im Code stammen von ChatGPT.
|
|
|
|
Coding Guidelines:
|
|
- Klare, modulare Struktur (-> Funktionsorientiert)
|
|
- Lesbare einfache Namen für Variablen und Funktionen
|
|
- Namenskonvention: snake_case für Funktionen und Variablen
|
|
- Konsistente Einrückung und Stil
|
|
"""
|
|
|
|
import cv2
|
|
import os
|
|
import re
|
|
import smtplib
|
|
from email.mime.text import MIMEText
|
|
from dotenv import load_dotenv
|
|
from pyzbar.pyzbar import decode
|
|
|
|
|
|
def load_email_settings():
|
|
"""
|
|
Lädt die E-Mail-Zugangsdaten aus Umgebungsvariablen.
|
|
|
|
Rückgabe:
|
|
- Absender-E-Mail
|
|
- Passwort
|
|
- Dictionary mit auswählbaren Empfängern
|
|
"""
|
|
load_dotenv()
|
|
sender = os.getenv("EMAIL_ADDRESS")
|
|
password = os.getenv("APP_PASSWORD")
|
|
|
|
recipients = {
|
|
"0": ("Myself", sender),
|
|
"1": ("Sister", os.getenv("EMAIL_SISTER")),
|
|
"2": ("Mother", os.getenv("EMAIL_MOTHER")),
|
|
"3": ("Father", os.getenv("EMAIL_FATHER")),
|
|
}
|
|
return sender, password, recipients
|
|
|
|
|
|
def is_valid_qr_data(data):
|
|
"""
|
|
Prüft, ob der QR-Code-Inhalt dem erwarteten Format entspricht.
|
|
|
|
Erlaubt sind:
|
|
- alphabetische Begriffe
|
|
- durch Kommas getrennte Einträge
|
|
"""
|
|
pattern = r"^[a-zA-ZäöüÄÖÜ]+(,\s*[a-zA-ZäöüÄÖÜ]+)*$"
|
|
return re.fullmatch(pattern, data.strip()) is not None
|
|
|
|
|
|
def send_email(sender, password, receiver, items):
|
|
"""
|
|
Sendet die gesammelten Artikel per E-Mail.
|
|
"""
|
|
body = "Shopping list scanned in this session:\n\n"
|
|
body += "\n".join(items)
|
|
|
|
msg = MIMEText(body)
|
|
msg["From"] = sender
|
|
msg["To"] = receiver
|
|
msg["Subject"] = "Shopping List"
|
|
|
|
try:
|
|
with smtplib.SMTP_SSL("smtp.mail.me.com", 465) as server:
|
|
server.login(sender, password)
|
|
server.send_message(msg)
|
|
except Exception as e:
|
|
print("\nFailed to send email:", e)
|
|
|
|
|
|
def scan_qr_codes():
|
|
"""
|
|
Scannt QR-Codes in Echtzeit über die Webcam.
|
|
|
|
Funktionale Beschreibung:
|
|
- Zugriff auf die Standard-Webcam
|
|
- Kontinuierliches Einlesen von Videoframes
|
|
- Erkennung und Dekodierung von QR-Codes
|
|
- Visuelle Markierung erkannter QR-Codes im Kamerabild
|
|
- Validierung und Speicherung neuer, eindeutiger Einträge
|
|
|
|
Benutzerinteraktion:
|
|
- Live-Videostream mit Markierung erkannter QR-Codes
|
|
- Beenden des Scan-Vorgangs durch Drücken der Taste 'q'
|
|
|
|
Hinweis zur Erstellung:
|
|
Diese Funktion wurde gemeinsam mit ChatGPT entwickelt, um
|
|
OpenCV- und pyzbar-Integration korrekt umzusetzen und die
|
|
Funktionsstruktur zu erstellen
|
|
|
|
Rückgabewert:
|
|
- scanned_items: Menge aller gültig gescannten QR-Code-Inhalte
|
|
"""
|
|
scanned_items = set()
|
|
cap = cv2.VideoCapture(0)
|
|
|
|
if not cap.isOpened():
|
|
print("Cannot open cam")
|
|
return scanned_items
|
|
|
|
print("Scan is running. Press 'Q' to finish current process\n")
|
|
|
|
while True:
|
|
ret, frame = cap.read()
|
|
if not ret:
|
|
break
|
|
|
|
qrcodes = decode(frame)
|
|
|
|
for qr in qrcodes:
|
|
data = qr.data.decode("utf-8").strip()
|
|
points = qr.polygon
|
|
|
|
if len(points) > 3:
|
|
for i in range(len(points)):
|
|
pt1 = (points[i].x, points[i].y)
|
|
pt2 = (points[(i + 1) % len(points)].x, points[(i + 1) % len(points)].y)
|
|
cv2.line(frame, pt1, pt2, (255, 0, 255), 2)
|
|
|
|
cv2.putText(
|
|
frame,
|
|
data,
|
|
(points[0].x, points[0].y - 10),
|
|
cv2.FONT_HERSHEY_SIMPLEX,
|
|
0.5,
|
|
(0, 255, 0),
|
|
2
|
|
)
|
|
|
|
if is_valid_qr_data(data) and data not in scanned_items:
|
|
scanned_items.add(data)
|
|
print("New item scanned:", data)
|
|
print("Current items:")
|
|
for item in scanned_items:
|
|
print("-", item)
|
|
print()
|
|
|
|
cv2.imshow("QR Scanner", frame)
|
|
|
|
if cv2.waitKey(1) & 0xFF == ord("q"):
|
|
break
|
|
|
|
cap.release()
|
|
cv2.destroyAllWindows()
|
|
return scanned_items
|
|
|
|
|
|
def choose_recipient(recipients):
|
|
"""
|
|
Ermöglicht die Auswahl eines Empfängers über die Konsole.
|
|
"""
|
|
print("Choose recipient:")
|
|
for key, (name, _) in recipients.items():
|
|
print(f"{key}: {name}")
|
|
|
|
choice = input("\nEnter number: ").strip()
|
|
return recipients.get(choice)
|
|
|
|
|
|
def main():
|
|
"""
|
|
Hauptfunktion zur Steuerung des Programmablaufs.
|
|
"""
|
|
sender, password, recipients = load_email_settings()
|
|
items = scan_qr_codes()
|
|
|
|
if not items:
|
|
print("No valid QR codes scanned")
|
|
return
|
|
|
|
print("Items ready to send:")
|
|
for item in items:
|
|
print("-", item)
|
|
|
|
selected = choose_recipient(recipients)
|
|
if not selected:
|
|
print("Invalid choice")
|
|
return
|
|
|
|
name, email = selected
|
|
confirm = input(f"\nSend email to {name}? say 'yes' or 'no': ").strip().lower()
|
|
|
|
if confirm == "yes":
|
|
send_email(sender, password, email, items)
|
|
print("\nEmail sent successfully")
|
|
elif confirm == "no":
|
|
print("\nEmail was not sent")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |