commit 5aec6bf292aa9f7ad32202e95bab4a1be762c02d Author: Leart Ramushi Date: Thu Dec 18 20:37:53 2025 +0100 Dateien nach "/" hochladen diff --git a/qr_code_shopping_scanner.py b/qr_code_shopping_scanner.py new file mode 100644 index 0000000..8860432 --- /dev/null +++ b/qr_code_shopping_scanner.py @@ -0,0 +1,202 @@ +""" +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() \ No newline at end of file