TFE — Danny Hurst — 2026

IT-WORLD

Système de caisse automatique NFC sur Raspberry Pi

Un projet de fin d'études ambitieux qui reproduit fidèlement le fonctionnement d'une caisse automatique moderne — gestion de produits, clients, paiements sécurisés, sauvegardes automatiques et déploiement physique sur Raspberry Pi 4.

10+
Technologies
5
Phases de dev
3
Tags NFC NTAG213
100%
Fonctionnel
Explorer

Présentation du Projet

IT-WORLD est un projet de TFE (Travail de Fin d'Études) réalisé dans le cadre de la formation en informatique. Il simule de façon très complète une caisse automatique réelle.

🎯

Objectif

Concevoir, développer et déployer une caisse automatique fonctionnelle, capable de gérer des produits, des clients, des paiements et des tickets — le tout sur un Raspberry Pi 4 avec un écran tactile.

💡

Contexte

Inspiré des systèmes utilisés dans les grandes surfaces (Carrefour, Delhaize…), IT-WORLD en reproduit la logique métier, l'interface utilisateur et la gestion des données, en version compacte et autonome.

🏆

Résultat

Une borne de caisse entièrement opérationnelle, avec interface graphique plein écran, base de données locale, simulation de paiement Stripe, module NFC et génération de ticket à chaque transaction.

En détail — Ce qui a été réalisé

CONTEXTE

Pourquoi ce projet ?

Les caisses automatiques sont omniprésentes dans notre quotidien, mais leur fonctionnement interne reste peu documenté de manière accessible. IT-WORLD est né de la volonté de comprendre et de reproduire ces systèmes complexes, en partant de zéro.

L'ambition était claire : ne pas se contenter d'une simulation à l'écran, mais réaliser un vrai déploiement physique sur matériel embarqué, avec toutes les contraintes que cela implique.

L'ensemble du projet a été conçu, codé, testé et documenté par une seule personne, dans un délai encadré par les exigences scolaires.
📋

Contraintes techniques

Interface fonctionnelle sur écran tactile, base de données locale sans serveur distant, compatibilité Raspberry Pi OS, et performance suffisante sur un hardware limité (4 Go RAM, CPU ARM).

🔧

Choix technologiques

Python pour la logique, Tkinter pour l'interface (léger et natif), SQLite pour la persistance des données, Stripe API pour les paiements, et Git/GitHub pour le versioning.

UTILISATEURS

Deux types d'utilisateurs

Le client utilise la borne en mode fullscreen pour scanner ses articles, choisir son mode de paiement et recevoir son ticket.

L'administrateur accède à un panneau dédié pour gérer le catalogue de produits, consulter les statistiques de vente, exporter les données et configurer le système.

  • Identification par code PIN ou carte NFC
  • Gestion des rôles et des permissions
  • Tableau de bord des ventes en temps réel
  • Export CSV des transactions
Le panneau administrateur est protégé par mot de passe et accessible uniquement via un raccourci discret dans l'interface, invisible pour les clients.
Les rôles sont gérés directement en base de données SQLite, avec hachage des mots de passe via hashlib.sha256.
NFC

Intégration NFC

L'un des aspects les plus innovants du projet est l'intégration d'un lecteur NFC (RC522) connecté au Raspberry Pi via le bus SPI. Chaque client peut être associé à un badge ou une carte NFC.

Au passage de la carte, le système identifie automatiquement le client, charge son panier habituel si activé, et pré-remplit ses informations de profil.

  • Lecture de l'UID de la carte NFC
  • Association UID ↔ compte client en base de données
  • Identification instantanée < 500ms
  • Fallback manuel si carte non reconnue
Python — nfc_reader.py
# Lecture d'un badge NFC via RC522
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522

reader = SimpleMFRC522()

def lire_badge():
    try:
        uid, texte = reader.read_no_block()
        if uid:
            return str(uid).strip()
        return None
    finally:
        GPIO.cleanup()

Fonctionnalités Clés

Chaque fonctionnalité a été pensée pour reproduire fidèlement les systèmes professionnels, avec les contraintes d'un matériel embarqué.

INTERFACE

Interface Tkinter Fullscreen

Tout le code de l'interface est centralisé dans interface.py. La fenêtre principale (root) est créée avec Tkinter, forcée en plein écran dès le démarrage, et cachée (root.withdraw()) pendant que la popup de sélection du type de client s'affiche.

Dès que le client fait son choix (client existant, création de compte, mode professionnel ou invité), la fenêtre principale est révélée via root.deiconify(). L'interface affiche ensuite en temps réel le panier via un Treeview ttk, le sous-total, la TVA 21% et le total — ou le montant HTVA pour les clients professionnels.

  • Fenêtre principale en fullscreen, fond #101010, thème personnalisé ttk.Style
  • Popup client au démarrage : 4 modes (existant, création, professionnel TVA, invité)
  • Champ de scan UID invisible positionné hors-écran, relié à la touche <Return>
  • Horloge mise à jour toutes les secondes via root.after(1000, ...)
  • Accès admin caché via le raccourci Ctrl+Shift+A
  • Son de scan (bip Windows) via winsound.Beep si disponible
Python — interface.py (extrait réel)
# Fenêtre principale — masquée au démarrage
root = tk.Tk()
root.withdraw()
root.attributes("-fullscreen", True)
root.configure(bg="#101010")
root.bind("<Escape>", lambda e: root.destroy())
root.bind("<Control-Shift-A>",
      lambda e: open_admin_login())

# Champ de scan invisible (capte le lecteur NFC)
entry_uid = tk.Entry(root)
entry_uid.place(x=-100, y=-100)
entry_uid.bind("<Return>", scan_product)

# Révéler l'interface après choix du client
def show_main_interface():
    root.deiconify()

# Horloge en temps réel
def update_clock():
    now = datetime.now().strftime(
        "%d/%m/%Y - %H:%M:%S")
    clock_label.config(text=now)
    root.after(1000, update_clock)
Le champ entry_uid est positionné à x=-100, y=-100 pour rester invisible tout en conservant le focus clavier — technique classique pour capturer les lectures NFC qui simulent une saisie clavier.
BASE DE DONNÉES

SQLite — Gestion des données

Toutes les données du projet sont stockées dans une base SQLite locale appelée shop.db, sans aucun serveur externe. La connexion est établie dès le démarrage de main.py et reste ouverte pendant toute la durée de fonctionnement de la caisse.

Trois tables sont créées automatiquement au premier lancement avec CREATE TABLE IF NOT EXISTS, ce qui garantit qu'elles n'existent qu'une seule fois même si le programme est relancé. Chaque ajout au panier déclenmente directement le stock en base via un UPDATE atomique suivi d'un commit().

  • Table products : uid (clé NFC), name, price, stock, image
  • Table tickets : id autoincrement, total, date de la transaction
  • Table clients : phone unique, client_number généré aléatoirement, tva_number
  • Décrémentation du stock en temps réel à chaque scan produit
  • Historique des 10 derniers tickets récupéré avec ORDER BY id DESC LIMIT 10
Python — main.py (extrait réel)
import sqlite3

conn = sqlite3.connect("shop.db")
cursor = conn.cursor()

# Création automatique des 3 tables au démarrage
cursor.execute("""
CREATE TABLE IF NOT EXISTS products (
    uid   TEXT PRIMARY KEY,
    name  TEXT,
    price REAL,
    stock INTEGER,
    image TEXT
)""")
cursor.execute("""
CREATE TABLE IF NOT EXISTS tickets (
    id    INTEGER PRIMARY KEY AUTOINCREMENT,
    total REAL,
    date  TEXT
)""")
cursor.execute("""
CREATE TABLE IF NOT EXISTS clients (
    id            INTEGER PRIMARY KEY AUTOINCREMENT,
    phone         TEXT UNIQUE,
    client_number TEXT UNIQUE,
    tva_number    TEXT
)""")
conn.commit()

# Scan : décrémente le stock et retourne les infos
def add_product(uid):
    cursor.execute(
        "SELECT name,price,stock,image FROM products WHERE uid=?",
        (uid,))
    product = cursor.fetchone()
    if product and product[2] > 0:
        cursor.execute(
            "UPDATE products SET stock=stock-1 WHERE uid=?",
            (uid,))
        conn.commit()
        return True, {"name": product[0],
                        "price": product[1],
                        "image": product[3]}
    return False, {"error": "rupture"}
L'UID NFC du produit sert de clé primaire dans la table products — chaque badge NFC est donc directement lié à un produit en base, sans couche intermédiaire.
PAIEMENT

Simulation Stripe

L'intégration Stripe est gérée directement dans interface.py. Quand le client clique sur "PAYER", la fonction open_payment() calcule le total via main.get_total_with_tva(), puis crée une Checkout Session Stripe avec le montant exact converti en centimes.

Stripe retourne une URL de paiement sécurisée qui s'ouvre automatiquement dans le navigateur via webbrowser.open(). Une fois le paiement effectué, le ticket est enregistré en base via main.add_ticket(total) et le panier est vidé. Tout est encapsulé dans un try/except pour afficher un message d'erreur propre en cas de problème Stripe.

  • Création d'une stripe.checkout.Session avec montant en centimes
  • Ouverture de l'URL de paiement Stripe dans le navigateur
  • Mode paiement carte uniquement (payment_method_types=["card"])
  • Enregistrement du ticket en base après confirmation
  • Gestion d'erreur via except Exception avec messagebox
  • Clé API en mode test (sk_test_...) — aucun vrai débit
Python — interface.py (extrait réel)
import stripe
import webbrowser

stripe.api_key = "sk_test_51Sydzo..."

def open_payment():
    total = main.get_total_with_tva()
    if total == 0:
        messagebox.showwarning("Paiement",
                                  "Panier vide")
        return
    try:
        session = stripe.checkout.Session.create(
            payment_method_types=["card"],
            line_items=[{
                "price_data": {
                    "currency": "eur",
                    "product_data": {
                        "name": "Paiement IT WORLD"
                    },
                    "unit_amount": int(total * 100),
                },
                "quantity": 1,
            }],
            mode="payment",
            success_url="https://example.com/success",
            cancel_url="https://example.com/cancel",
        )
        webbrowser.open(session.url)
        main.add_ticket(total)
        reset_cart()
    except Exception as e:
        messagebox.showerror("Erreur Stripe", str(e))
Le montant est multiplié par 100 avant envoi à Stripe car l'API travaille en centimes : 12,50 € devient 1250. Pour les clients professionnels, get_total_with_tva() retourne le montant HTVA directement.
SÉCURITÉ

Sauvegardes automatiques

La fonction create_backup() est définie dans main.py et appelée automatiquement à chaque démarrage du programme. Elle crée une copie horodatée du fichier shop.db dans le dossier backups/, qui est créé s'il n'existe pas encore.

Le nom du fichier de backup inclut la date et l'heure précises au format backup_YYYY-MM-DD_HH-MM-SS.db, ce qui permet de retrouver facilement une version précise en cas de problème. La copie est réalisée avec shutil.copy(), fonction standard Python qui garantit une copie binaire fidèle du fichier SQLite.

  • Sauvegarde déclenchée automatiquement à chaque lancement
  • Dossier backups/ créé automatiquement si absent
  • Nom horodaté : backup_2026-05-29_14-32-10.db
  • Copie via shutil.copy() — rapide et fiable
  • Vérification de l'existence de shop.db avant copie
Python — main.py (extrait réel)
import shutil
import os
from datetime import datetime

def create_backup():

    backup_folder = "backups"

    # Crée le dossier s'il n'existe pas
    if not os.path.exists(backup_folder):
        os.makedirs(backup_folder)

    # Nom horodaté : backup_2026-05-29_14-32-10.db
    now = datetime.now().strftime(
        "%Y-%m-%d_%H-%M-%S")

    backup_name = f"backup_{now}.db"

    backup_path = os.path.join(
        backup_folder,
        backup_name
    )

    # Copie uniquement si la BDD existe
    if os.path.exists("shop.db"):
        shutil.copy("shop.db", backup_path)

# Appelé automatiquement au démarrage
create_backup()
Chaque redémarrage de la caisse génère un nouveau fichier de backup. Le dossier backups/ accumule ainsi un historique complet des états de la base, consultable directement avec DB Browser for SQLite (.sqbpro).

Journal de Développement

Retour détaillé sur chaque phase du projet, des premières lignes de code jusqu'au déploiement physique final sur Raspberry Pi 4.

1
Phase 1

Interface & Base de données

Développement de l'interface Tkinter fullscreen et mise en place de la base de données SQLite. Création du popup client (4 modes), du panier avec Treeview, du calcul TVA automatique et du système de backup au démarrage.

  • Fenêtre fullscreen root.withdraw() + popup client
  • 3 tables SQLite : products, clients, tickets
  • Calcul TVA 21% / HTVA selon profil client
  • Backup automatique horodaté au démarrage
  • Bouton accueil, panel admin protégé Ctrl+Shift+A
main.py gère toute la logique métier — interface.py gère uniquement l'affichage et les événements.
2
Phase 2 — Difficulté majeure

NFC : PN532 → RC522

Le module PN532 prévu initialement ne répondait pas malgré de nombreux essais de câblage et de configuration. Cette difficulté a causé une perte de temps importante avant de décider de le remplacer par le RC522.

  • ❌ Module PN532 non fonctionnel — raison inconnue
  • ✅ Remplacement par RC522 via protocole SPI
  • Thread NFC en arrière-plan (daemon thread)
  • Appel thread-safe via root.after(0, lambda u=uid: scan_product(u))
  • Anti-doublon : même tag ignoré < 2 secondes
  • 3 tags NTAG213 associés aux produits en base
Le RC522 lit l'UID du tag, qui est comparé à la table products pour retrouver le produit correspondant.
3
Phase 3

Stripe & Impression ticket

Intégration du paiement Stripe en mode Checkout Session et génération automatique d'un ticket PDF via ReportLab après chaque paiement.

  • Session Stripe Checkout avec line_items par produit
  • Ouverture automatique dans le navigateur du Pi
  • Ticket PDF généré avec ReportLab (logo + articles + total)
  • Impression automatique via lp -d CanonTS3351
  • Message de finalisation affiché sur le ticket
4
Phase 4

Panel Admin complet

Refonte complète du panel administrateur avec 3 onglets distincts utilisant ttk.Notebook.

  • 🛒 Onglet Panier : supprimer article, modifier quantité, vider le panier
  • 📦 Onglet Produits : modifier prix, modifier stock, reset tous les stocks
  • 🧾 Onglet Historique : 10 derniers tickets avec date et montant
  • Raccourci Ctrl+Shift+A accessible depuis tous les écrans (popup inclus)
  • Touche Échap pour fermer le panel
5
Phase 5

Déploiement sur Raspberry Pi

Configuration complète du déploiement sur le Pi avec autostart, impression réseau et gestion des permissions Linux.

  • Autostart via /home/danny/.config/autostart/itworld.desktop
  • Imprimante Canon TS3351 configurée via CUPS (port 631, WiFi)
  • IP imprimante trouvée avec nmap 192.168.129.44
  • Correction permissions : sudo chown -R danny:danny /home/pi/IT_WORLD
  • UIDs réels des tags synchronisés dans SQLite via update_uids.py
  • Correction popup plein écran : double attributes(-fullscreen) + lift()
Le projet tourne entièrement sur le Pi : scan NFC → panier → Stripe → ticket PDF → impression Canon automatique.

Avancement par module

Interface Tkinter100%
Base de données SQLite100%
Intégration Stripe100%
Module NFC RC522100%
Impression ticket Canon100%
Panel Admin (3 onglets)100%
Backups automatiques100%
Déploiement Raspberry Pi100%

Architecture du Système

Vue d'ensemble de la stack technique et du flux de données, du client jusqu'à la génération du ticket.

Flux principal

👤
Client
Interaction tactile ou badge NFC
🖥️
Interface Tkinter
Fullscreen, navigation par Frames
⚙️
Python Backend
Logique métier, Session, contrôleurs
🗄️
SQLite Database
Produits, tickets, clients, logs
💳
Stripe API
PaymentIntent, confirmation, erreurs
🧾
Ticket généré
PDF + affichage écran + log BDD

Composants hardware

🍓

Raspberry Pi 4 (4 Go RAM)

Cœur du système. Fait tourner Python, SQLite, les services système et le gestionnaire de fenêtres Xorg pour Tkinter.

🖥️

Écran

N'importe quel écran compatible peut être utilisé. L'interface Tkinter s'adapte à la résolution disponible et passe automatiquement en mode plein écran au lancement.

📡

Lecteur NFC PN532

Module de lecture NFC connecté au Raspberry Pi. Permet la détection instantanée de badges ou cartes sans contact pour l'identification des clients.

💾

MicroSD 32 Go (Classe 10)

Système d'exploitation + base de données + sauvegardes. Vitesse d'écriture suffisante pour SQLite en charge normale.

Schéma des modules Python

Structure du projet
itworld/
├── __pycache__/           # Cache bytecode Python (généré auto)
├── backups/               # Sauvegardes automatiques de la BDD
├── images/                # Images produits, logo, assets
├── interface.py           # Interface Tkinter complète (popup client, scan, panier, admin)
├── main.py                # Logique métier : BDD, panier, Stripe, clients
├── shop.sqbpro            # Fichier projet DB Browser (SQLite)
└── shop                   # Base de données SQLite principale

Technologies Utilisées

Chaque technologie a été sélectionnée avec soin pour répondre aux contraintes du projet : légèreté, compatibilité ARM, fonctionnement hors-ligne.

🐍
Python 3.11
Logique métier, backend, threads, intégrations
CORE
🖼️
Tkinter
Interface graphique fullscreen, navigation Frames
UI
🗄️
SQLite
Base de données locale, sans serveur, ACID
DATA
💳
Stripe API
Simulation de paiements sécurisés par carte
PAIEMENT
🍓
Raspberry Pi 4
Cœur hardware, GPIO, déploiement embarqué
HARDWARE
📡
NFC RC522
Lecture tags NTAG213, thread SPI, root.after()
HARDWARE
🐧
Linux
Raspberry Pi OS 64-bit, Xorg, cron, systemd
OS
🐙
GitHub
Versioning, branches, documentation
DEV
📄
ReportLab
Génération de tickets PDF formatés
UTIL
🖨️
CUPS + Canon TS3351
Impression WiFi, port 631, commande lp
RÉSEAU

Rapport de TFE

Travail de Fin d'Études réalisé par Danny Hurst — 6TQ Informatique — INRACI — Année scolaire 2025-2026

📋

Titre officiel

Système de caisse automatique NFC — Pour l'obtention du certificat de qualification Technicien(ne) en informatique.

👨‍🏫

Encadrement

Encadré par Monsieur Janah et Monsieur Ben Sellam — Institut National de Radioélectricité et de Cinématographie (INRACI), Forest.

📅

Année scolaire

2025 — 2026. Développé sur 3 mois environ, de février à juin 2026. Déploiement final sur Raspberry Pi 4 avec imprimante Canon TS3351.

Table des matières

CHAPITRES
1Analyse du besoin
2Technologies utilisées
3Conception du système
4Développement de l'application
5Difficultés rencontrées
6Résultats obtenus et tests
Conclusion générale
ANNEXES & EXTRAS
📎Session checkout Stripe
📎Backup automatique
📎Création client
📎Login client
📎Client Business (TVA)
📎Calcul TVA
📚Bibliographie complète

Points clés du rapport

CHAPITRE 1 & 2

Analyse & Technologies

Le rapport définit la problématique principale : "Comment développer une caisse automatique moderne, fonctionnelle et intuitive en utilisant des technologies accessibles ?"

Les technologies retenues sont justifiées par leur légèreté, compatibilité ARM et gratuité : Python, Tkinter, SQLite, Stripe, Raspberry Pi.

  • Public cible : petits commerces, associations, contexte pédagogique
  • Contraintes : budget limité, compatibilité Pi, sécurité des données
  • Architecture choisie : 2 fichiers Python + SQLite local
La problématique est résolue par IT-WORLD, qui prouve qu'une caisse NFC fonctionnelle peut être construite avec du matériel grand public (< 100€) et du code Python open-source.
Le rapport détaille 9 technologies, leurs avantages et leur rôle précis dans le projet, avec des exemples de code pour chacune.
CHAPITRE 5

Difficultés rencontrées

Le rapport documente honnêtement les obstacles rencontrés, notamment la difficulté majeure du module PN532 qui n'a pas pu être intégré dans les délais.

  • ❌ PN532 non fonctionnel → remplacé par RC522
  • 🔧 Thread NFC + Tkinter → résolu avec root.after()
  • 🖨️ Imprimante sans RJ45 → CUPS WiFi port 631
  • 🐧 Permissions Linux → chown danny
  • 📺 Popup hors plein écran → double attributes + lift()
Chaque difficulté a été documentée avec le problème exact, la solution trouvée et les apprentissages tirés. Ces obstacles font partie intégrante du projet.
📄

Rapport complet disponible

Le rapport TFE complet (39 pages) inclut l'analyse des besoins, la conception, le développement, les schémas, les résultats et la bibliographie complète.

📥 Télécharger le rapport TFE (PDF)

Hurst Danny — INRACI — 6TQ Informatique — 2025-2026