v1.0.0 — 2025–2026

Documentation
SmartLib

Guide technique complet du système de gestion d'emprunts de livres SmartLib — Raspberry Pi 4, RFID-RC522, Python/Tkinter, SQLite, et services réseau.

Ce projet est le TFE de Bako Abdelwadoud pour l'obtention du certificat de qualification Technicien(ne) en informatique — INRACI Forest, année 2025–2026.

SmartLib est une solution autonome et économique pour remplacer la gestion manuelle des bibliothèques scolaires. Le système tourne entièrement sur un Raspberry Pi 4, sans serveur externe requis.

ComposantTechnologieRôle
AuthentificationRFID-RC522 + MIFARE 1kIdentifier les élèves par badge
InterfacePython 3 + TkinterGUI client et administration
StockageSQLite (smartlib.db)Livres, emprunts, utilisateurs
DocumentsReportLab (PDF) + SMTPReçus automatiques par e-mail
Réseau localSamba + mDNS (Avahi)Partage des reçus PDF
CloudAlwaysData + Paramiko (SFTP)Backup distant de la base
LogsLogging + SysLogHandlerTraçabilité de tous les événements
PlanificationCronBackup et nettoyage automatiques

00

Prérequis

Avant de déployer SmartLib, assurez-vous de disposer des éléments suivants.

💡
Testé sur Raspberry Pi OS (Debian Bookworm) 64-bit. VMware Workstation recommandé pour le prototypage avant déploiement physique.

Installation des dépendances Python

bash
terminal
# Mise à jour du système
sudo apt update && sudo apt upgrade -y

# Dépendances système
sudo apt install -y python3 python3-pip python3-tk samba avahi-daemon

# Modules Python
pip install reportlab paramiko mfrc522 RPi.GPIO --break-system-packages

# Activer SPI
sudo raspi-config  # → Interface Options → SPI → Enable

01

Câblage RFID-RC522

Le module RFID-RC522 se connecte au Raspberry Pi 4 via 7 câbles GPIO (Dupont mâle-femelle) en utilisant l'interface SPI.

Pin RC522Pin GPIO Raspberry PiNuméro physiqueDescription
SDAGPIO 8 (CE0)24Chip Select
SCKGPIO 11 (SCLK)23Clock SPI
MOSIGPIO 10 (MOSI)19Master Out Slave In
MISOGPIO 9 (MISO)21Master In Slave Out
IRQNon utilisé
GNDGND6Masse
RSTGPIO 2522Reset
3.3V3.3V1Alimentation
Ne jamais alimenter le RC522 en 5V — il fonctionne exclusivement en 3.3V. Un voltage incorrect endommage définitivement le module.

02

Configuration SPI

Le protocole SPI (Serial Peripheral Interface) est utilisé pour la communication entre le Raspberry Pi et le RFID-RC522. Il doit être activé manuellement.

Vérification du module SPI

bash
terminal
# Vérifier que SPI est activé
lsmod | grep spi

# Doit afficher : spidev  spi_bcm2835

# Test rapide de lecture RFID
python3 -c "from mfrc522 import SimpleMFRC522; r=SimpleMFRC522(); print(r.read())"

03

Schéma de la base de données

Le fichier smartlib.db contient 4 tables. Il est stocké à /home/abdel/tfe/smartlib.db.

📚 books
idINTEGERPK
titleTEXT
authorTEXT
genreTEXT
quantityINTEGER
👤 users
idINTEGERPK
uidTEXT UNIQUE
nameTEXT
emailTEXT
📋 loans
idINTEGERPK
user_idINTEGERFK
book_idINTEGERFK
borrow_dateDATETIME
due_dateDATETIME
return_dateDATETIME
statusTEXT
⚙ sqlite_sequence
nameTEXT
seqINTEGER

04

Initialisation de la base de données

python
smartlib_tkinter.py
# Configuration
USER_HOME = "/home/abdel"
DB_PATH   = "/home/abdel/tfe/smartlib.db"

#Base de donnée
def init_db():
    conn = sqlite3.connect(DB_PATH)
    c    = conn.cursor()
    c.execute("""CREATE TABLE IF NOT EXISTS books (
        id       INTEGER PRIMARY KEY AUTOINCREMENT,
        title    TEXT NOT NULL,
        author   TEXT,
        genre    TEXT DEFAULT 'Général',
        quantity INTEGER DEFAULT 1
    )""")
    c.execute("""CREATE TABLE IF NOT EXISTS users (
        id   INTEGER PRIMARY KEY AUTOINCREMENT,
        uid  TEXT UNIQUE NOT NULL,
        name TEXT NOT NULL,
        email TEXT DEFAULT ''
    )""")
    c.execute("""CREATE TABLE IF NOT EXISTS loans (
        id          INTEGER PRIMARY KEY AUTOINCREMENT,
        user_id     INTEGER REFERENCES users(id),
        book_id     INTEGER REFERENCES books(id),
        borrow_date DATETIME,
        due_date    DATETIME,
        return_date DATETIME,
        status      TEXT DEFAULT 'En cours'
    )""")
    conn.commit()
    conn.close()

05

Module RFID

Deux fonctions principales gèrent le RFID : read_rfid() pour lire un badge et register_student_rfid() pour enregistrer un nouvel élève.

python
smartlib_tkinter.py — #RFID
#RFID
def read_rfid():
    try:
        from mfrc522 import SimpleMFRC522
        r   = SimpleMFRC522()
        uid, _ = r.read()
        logger.info(f"🔖 RFID détecté - UID: {uid}")
        return str(uid)
    except Exception as e:
        logger.error(f"✗ Erreur lecture RFID: {e}")
        return None
    finally:
        GPIO.cleanup()
💡
La librairie SimpleMFRC522 est issue du projet miguelbalboa/rfid. Le GPIO.cleanup() en finally libère les broches même en cas d'erreur.

Enregistrement d'un badge

1

Ouvrir la fenêtre d'enregistrement

Cliquer sur le bouton □ Enregistrer dans l'interface admin. Une fenêtre Tkinter s'ouvre avec un champ pour le nom de l'élève.

2

Approcher le badge

Appuyer sur □ Lire & Enregistrer. La fonction read_rfid() est appelée — elle attend un badge sur le lecteur.

3

Enregistrement en base

L'UID lu est inséré dans la table users avec le nom de l'élève via INSERT INTO users VALUES (?,?,?). Un log est créé.


06

Module E-mail (SMTPLib)

Chaque emprunt déclenche un envoi automatique d'e-mail avec le reçu PDF en pièce jointe. L'envoi est asynchrone via threading pour ne pas bloquer l'interface.

python
smartlib_tkinter.py — #EMAIL
# Configuration SMTP
SMTP_EMAIL    = "abdelwadoud.bako@gmail.com"
SMTP_PASSWORD = "uhcamcmeuuonrlvt"   # App password Gmail
DESTINATAIRE  = "abdelwadoud.bako@inraci.be"

def send_email_with_pdf(pdf_path, book_title):
    if not SMTP_EMAIL or not SMTP_PASSWORD: return

    # Attendre que le PDF soit généré (max 2,5s)
    wait = 0
    while not os.path.exists(pdf_path) and wait < 5:
        time.sleep(0.5); wait += 0.5

    try:
        msg = MIMEMultipart()
        msg['From'], msg['To'] = SMTP_EMAIL, DESTINATAIRE
        msg['Subject'] = f"□ SmartLib : {book_title}"
        msg.attach(MIMEText(f"Livre emprunté : {book_title}", 'plain'))

        # Attacher le PDF
        with open(pdf_path, "rb") as f:
            part = MIMEBase('application', 'octet-stream')
            part.set_payload(f.read())
        encoders.encode_base64(part)
        msg.attach(part)

        # Envoi via Gmail SMTP port 587
        s = smtplib.SMTP('smtp.gmail.com', 587)
        s.starttls()
        s.login(SMTP_EMAIL, SMTP_PASSWORD)
        s.sendmail(SMTP_EMAIL, DESTINATAIRE, msg.as_string())
        s.quit()
    except Exception as e:
        logger.error(f"✗ Erreur Email: {e}")
Utiliser un mot de passe d'application Gmail (Google → Compte → Sécurité → Mots de passe des applis), pas le mot de passe principal. L'authentification à 2 facteurs doit être activée.

07

Génération de reçus PDF

La fonction generate_receipt() crée un reçu PDF au format A4 à chaque emprunt. Le fichier est sauvegardé localement ET copié dans le dossier Samba partagé.

python
smartlib_tkinter.py — #PDF GÉNÉRATION
def generate_receipt(book_id, borrow_date, due_date, username):
    conn = sqlite3.connect(DB_PATH); c = conn.cursor()
    c.execute("SELECT title, author, genre FROM books WHERE id=?", (book_id,))
    b = c.fetchone(); conn.close()
    if not b: return None

    title, author, genre = b
    fname = f"recu_emprunt_{book_id}_{datetime.now().strftime('%Y%m%d_%H%M')}.pdf"
    local = os.path.join(USER_HOME, fname)
    samba = os.path.join(SAMBAPATH, fname)
    os.makedirs(SAMBAPATH, exist_ok=True)

    # Création du PDF A4
    pdf = canvas.Canvas(local, pagesize=A4)
    w, h = A4
    pdf.setFont("Helvetica-Bold", 16)
    pdf.drawString(50, h-50,  "■ SmartLib - Reçu")
    pdf.setFont("Helvetica", 12)
    pdf.drawString(50, h-70,  f"Date : {datetime.now().strftime('%d/%m/%Y %H:%M')}")
    pdf.drawString(50, h-90,  f"Utilisateur : {username}")
    pdf.drawString(70, h-140, f"Titre  : {title}")
    pdf.drawString(70, h-160, f"Auteur : {author}")
    pdf.drawString(70, h-180, f"Genre  : {genre}")
    pdf.drawString(70, h-200, f"Emprunté le : {borrow_date}")
    pdf.drawString(70, h-220, f"À rendre    : {due_date}")
    pdf.save()

    try: shutil.copy2(local, samba)
    except Exception as e: print(f"Erreur Samba: {e}")
    return local, title

08

Samba + mDNS (Avahi)

Samba permet aux administrateurs d'accéder aux reçus PDF depuis n'importe quel PC du réseau local. mDNS (Avahi) donne un nom de domaine simple au Raspberry Pi.

Configuration /etc/samba/smb.conf

ini
/etc/samba/smb.conf
[global]
netbios name = smartlib

[SmartLib_Receipts]
path          = /home/abdel/smartlib_receipts
browseable    = yes
writable      = yes
guest ok      = yes
read only     = no
valid users   = abdel

Accès depuis Windows

powershell
Explorateur Windows
# Dans la barre d'adresse de l'explorateur :
\\smartlib.local\SmartLib_Receipts

# Ou par IP directe :
\\192.168.0.195\SmartLib_Receipts
Le nom smartlib.local est résolu grâce au démon Avahi (mDNS) qui diffuse le nom du Raspberry Pi sur le réseau local. Assurez-vous qu'Avahi est actif : sudo systemctl enable avahi-daemon

09

Logging / SysLogHandler

Tous les événements importants sont journalisés dans le syslog système via logging.handlers.SysLogHandler.

python
smartlib_tkinter.py — #Configuration Syslog
def setup_logging():
    logger = logging.getLogger("SmartLib")
    logger.setLevel(logging.INFO)
    try:
        handler   = logging.handlers.SysLogHandler(address='/dev/log')
        formatter = logging.Formatter(
            '%(asctime)s SmartLib: %(levelname)s - %(message)s')
        handler.setFormatter(formatter)
        logger.addHandler(handler)
    except Exception as e:
        console = logging.StreamHandler()
        logger.addHandler(console)
    return logger

logger = setup_logging()

Consulter les logs

bash
terminal
sudo journalctl -f | grep SmartLib
# Ou :
sudo journalctl -u smartlib -f
Événement journaliséNiveau
Démarrage en mode KiosqueINFO
Badge RFID détecté (UID)INFO
Emprunt validé (utilisateur + livre)INFO
Nouveau badge enregistréINFO
E-mail envoyé avec PDFINFO
Export CSV effectuéINFO
Sauvegarde cloud terminéeINFO
Connexion admin réussieINFO
Erreur lecture RFIDERROR
PDF supprimé (nettoyage auto)INFO

10

Cron — Tâches planifiées

Deux tâches Cron s'exécutent automatiquement chaque nuit à 2h du matin.

crontab
crontab -e
# m  h  dom mon dow  commande

# Sauvegarde quotidienne de la base à 2h02
0 2 * * * cp /home/abdel/smartlib.db /home/abdel/smartlib/backups/smartlib_$(date +\%Y\%m\%d).db

# Suppression des backups vieux de +7 jours
0 2 * * * find /home/abdel/smartlib/backups -name 'smartlib_backup_*.db' -mtime +7 -delete

Le nettoyage des PDF expirés (vieux de plus de 30 jours) est géré dans le code Python via la fonction cleanup_old_pdfs(days=30), appelée au démarrage.


11

Sauvegarde (Local + Cloud)

Deux types de sauvegarde sont disponibles depuis l'interface admin : locale (sur le Raspberry Pi) et cloud (vers AlwaysData via SFTP/Paramiko).

Admin clique "Backup Cloud"
Paramiko SFTP connect
ssh-abdel.alwaysdata.net:22
smartlib.db → smartlib_cloud_YYYYMMDD_HHMMSS.db
/home/abdel/backups/ sur AlwaysData
🔒
Les identifiants AlwaysData (REMOTE_USER, REMOTE_PASSWORD) sont écrits en clair dans le code source. En production, utiliser des variables d'environnement ou un fichier de configuration protégé.

12

Interface client (Tkinter)

L'interface principale s'ouvre en mode kiosque (plein écran) et contient 3 onglets.

OngletContenuActions disponibles
EmprunterListe complète des livres avec disponibilité, recherche et filtre par genreSélectionner un livre → Emprunter (scan badge)
RetournerEmprunts en cours de l'utilisateur avec dates de retour prévuesSélectionner → Retourner (scan badge)
Mon historiqueTous les emprunts passés avec statut (En cours / Rendu)Consultation uniquement

13

Interface administrateur

L'interface admin est accessible via le bouton □ Admin depuis l'écran principal. Elle contient 2 onglets et 8 boutons d'action.

BoutonAction
+ LivreOuvre une fenêtre pour ajouter un livre (titre, auteur, genre, quantité)
Suppr.Supprime le livre sélectionné de la base
+ ExAjoute un exemplaire au livre sélectionné
− ExRetire un exemplaire du livre sélectionné
□ EnregistrerScan RFID + saisie nom → enregistre un badge en base
Suppr. BadgeSupprime un badge RFID (liste déroulante)
□ Backup LocalCopie de smartlib.db dans /backups/ horodatée
▲ Backup CloudUpload SFTP de smartlib.db vers AlwaysData
CSVExport de l'historique complet en fichier .csv

14

AlwaysData — Sauvegarde cloud

AlwaysData est un hébergeur gratuit utilisé pour stocker les copies distantes de la base de données. L'accès se fait en SSH/SFTP.

python
smartlib_tkinter.py — #ALWAYSDATA
REMOTE_HOST = "ssh-abdel.alwaysdata.net"
REMOTE_PORT = 22
REMOTE_USER = "abdel"
REMOTE_PATH = "/home/abdel/backups/"

Se connecter en SSH (vérification)

bash
terminal
ssh abdel@ssh-abdel.alwaysdata.net
# Lister les backups :
ls -lh /home/abdel/backups/
AlwaysData propose un hébergement gratuit avec 100 MB de stockage, SSH, SFTP et une interface web d'administration. Suffisant pour stocker plusieurs dizaines de backups de smartlib.db (≈ 36 KB chacun).

15

📄 Rapport TFE complet

Le rapport complet du Travail de Fin d'Études de Bako Abdelwadoud — INRACI Forest, année scolaire 2025–2026. Consultez ou téléchargez le PDF directement ci-dessous.

📘
Document officiel soumis pour l'obtention du certificat de qualification Technicien(ne) en informatique — 39 pages, incluant introduction, matériel, logiciels, architecture, code source, et annexes.
Auteur
Bako Abdelwadoud
Pages
39 pages
Année
2025–2026
📄 Abdelwadoud_Bako_TFE_6I.pdf
39 pages · SmartLib ↓ Télécharger
Table des matières
1. Introductionp.5
2. Matérielsp.6
3. Prixp.17
4. Schémasp.18
5. Travail réalisép.20
6. Conclusionp.33
7. Sitographiep.34
8. Annexesp.35
INRACI Forest — Avenue Jupiter, 188 — 1190 Forest
Année scolaire 2025–2026
💡
Si l'aperçu ne s'affiche pas, placez le fichier Abdelwadoud_Bako_TFE_6I.pdf dans le même dossier que ce fichier HTML, ou utilisez le bouton Télécharger.