From 41312b0f753c8454bc00993a2c3c46f4de95ec84 Mon Sep 17 00:00:00 2001 From: maxime Date: Wed, 1 Apr 2026 18:39:00 +0200 Subject: [PATCH] maj de 18h38 --- composants/byPanda/porterfid.py | 2 +- composants/byPanda/septsegments.py | 13 +- composants/test/ALARM_V2.py | 205 ++++++++++++++++++++++++++ fastapi/main.py | 30 +++- flask/index.html | 222 +++++++++++++++++++++++++++++ flask/main.py | 51 ++++++- flask/run_flask.sh | 4 +- flask/templates/dashboard.html | 32 ++--- flask/templates/index.html | 2 +- 9 files changed, 522 insertions(+), 39 deletions(-) create mode 100644 composants/test/ALARM_V2.py create mode 100644 flask/index.html diff --git a/composants/byPanda/porterfid.py b/composants/byPanda/porterfid.py index 8f9814f..96e3404 100644 --- a/composants/byPanda/porterfid.py +++ b/composants/byPanda/porterfid.py @@ -19,7 +19,7 @@ class SystemePorteRFID: Gère le lecteur RFID et la LED de la porte. L'authentification est maintenant gérée par le serveur Flask et MariaDB. """ - self.pinLed = 21 + self.pinLed = 4 GPIO.setup(self.pinLed, GPIO.OUT, initial=GPIO.LOW) self.lecteur = SimpleMFRC522() diff --git a/composants/byPanda/septsegments.py b/composants/byPanda/septsegments.py index df660e5..99f8442 100644 --- a/composants/byPanda/septsegments.py +++ b/composants/byPanda/septsegments.py @@ -1,8 +1,13 @@ import tm1637 import time as t +_display = None -display = tm1637.TM1637(clk=4, dio=17) -display.brightness(2) +def get_display(): + global _display + if _display is None: + _display = tm1637.TM1637(clk=4, dio=17) + _display.brightness(2) + return _display def afficher_temperature(temperature, temperature_moyenne): print(f"Test affichage: Cible {temperature} | Moyenne {temperature_moyenne}") @@ -10,8 +15,8 @@ def afficher_temperature(temperature, temperature_moyenne): temp1 = int(temperature) temp2 = int(temperature_moyenne) texte_ecran = f"{temp1:02d}{temp2:02d}" - - display.show(texte_ecran) + disp = get_display() + disp.show(texte_ecran) except Exception as e: print(f"Erreur d'affichage : {e}") \ No newline at end of file diff --git a/composants/test/ALARM_V2.py b/composants/test/ALARM_V2.py new file mode 100644 index 0000000..8c53e22 --- /dev/null +++ b/composants/test/ALARM_V2.py @@ -0,0 +1,205 @@ +import RPi.GPIO as GPIO +import time +import threading + +GPIO.setmode(GPIO.BCM) +GPIO.setwarnings(False) + +PIN_LED_R = 17 +PIN_LED_G = 22 +PIN_LED_B = 27 +PIN_PIR = 15 +PIN_BUZZER = 18 + +ROWS = [5, 6, 13, 19] +COLS = [26, 12, 16, 20] + +KEYPAD_MAP = [ + ['1', '2', '3', 'A'], + ['4', '5', '6', 'B'], + ['7', '8', '9', 'C'], + ['*', '0', '#', 'D'], +] + +CODE_SECRET = "1234" + +GPIO.setup(PIN_LED_R, GPIO.OUT, initial=GPIO.LOW) +GPIO.setup(PIN_LED_G, GPIO.OUT, initial=GPIO.LOW) +GPIO.setup(PIN_LED_B, GPIO.OUT, initial=GPIO.LOW) +GPIO.setup(PIN_BUZZER, GPIO.OUT, initial=GPIO.LOW) +GPIO.setup(PIN_PIR, GPIO.IN) + +for row in ROWS: + GPIO.setup(row, GPIO.OUT, initial=GPIO.HIGH) +for col in COLS: + GPIO.setup(col, GPIO.IN, pull_up_down=GPIO.PUD_UP) + +etat = "desarmee" +etat_lock = threading.Lock() + +_stop_buzzer = threading.Event() +_thread_buzzer = None + +def led(r=False, g=False, b=False): + """Allume la LED RGB avec la couleur voulue.""" + GPIO.output(PIN_LED_R, GPIO.HIGH if r else GPIO.LOW) + GPIO.output(PIN_LED_G, GPIO.HIGH if g else GPIO.LOW) + GPIO.output(PIN_LED_B, GPIO.HIGH if b else GPIO.LOW) + +def led_bleu(): led(b=True) +def led_vert(): led(g=True) +def led_rouge(): led(r=True) +def led_off(): led() + +def bip(nb=1, duree=0.08, pause=0.12): + """Émet nb bip(s) courts.""" + for _ in range(nb): + GPIO.output(PIN_BUZZER, GPIO.HIGH) + time.sleep(duree) + GPIO.output(PIN_BUZZER, GPIO.LOW) + time.sleep(pause) + +def _buzzer_continu(stop_event: threading.Event): + """Boucle interne : buzzer ON/OFF jusqu'à stop_event.""" + while not stop_event.is_set(): + GPIO.output(PIN_BUZZER, GPIO.HIGH) + time.sleep(0.5) + GPIO.output(PIN_BUZZER, GPIO.LOW) + time.sleep(0.5) + GPIO.output(PIN_BUZZER, GPIO.LOW) + +def lire_touche(): + """ + Scan matriciel : met chaque ligne à LOW tour à tour + et lit les colonnes. Retourne la touche ou None. + """ + for i, row in enumerate(ROWS): + GPIO.output(row, GPIO.LOW) + for j, col in enumerate(COLS): + if GPIO.input(col) == GPIO.LOW: + time.sleep(0.05) + while GPIO.input(col) == GPIO.LOW: + pass + GPIO.output(row, GPIO.HIGH) + return KEYPAD_MAP[i][j] + GPIO.output(row, GPIO.HIGH) + return None + +def lire_code(timeout=30): + saisi = "" + debut = time.time() + print(" Code (# pour valider, * pour effacer) : ", end="", flush=True) + while True: + if time.time() - debut > timeout: + print("\n [Timeout — saisie annulée]") + return "" + touche = lire_touche() + if touche is None: + time.sleep(0.05) + continue + if touche == '#': + print() + return saisi + elif touche == '*': + if saisi: + saisi = saisi[:-1] + print("\b \b", end="", flush=True) + elif touche.isdigit(): + saisi += touche + print("*", end="", flush=True) + time.sleep(0.05) + +def passer_en_desarmee(): + global etat, _thread_buzzer + _stop_buzzer.set() + if _thread_buzzer and _thread_buzzer.is_alive(): + _thread_buzzer.join() + with etat_lock: + etat = "desarmee" + led_bleu() + print("[ÉTAT] ● DÉSARMÉE — LED bleue") + +def passer_en_armee(): + global etat + with etat_lock: + etat = "armee" + led_vert() + bip(nb=2) + print("[ÉTAT] ● ARMÉE — LED verte — PIR actif") + +def passer_en_declenchee(): + global etat, _thread_buzzer + with etat_lock: + etat = "declenchee" + led_rouge() + print("[ÉTAT] ● DÉCLENCHÉE — LED rouge — buzzer actif") + _stop_buzzer.clear() + _thread_buzzer = threading.Thread( + target=_buzzer_continu, args=(_stop_buzzer,), daemon=True + ) + _thread_buzzer.start() + +def _surveiller_pir(stop_evt: threading.Event): + """Lit le PIR toutes les 100 ms. Déclenche si mouvement et armée.""" + print("[PIR] Surveillance démarrée") + while not stop_evt.is_set(): + with etat_lock: + etat_local = etat + if etat_local == "armee" and GPIO.input(PIN_PIR) == GPIO.HIGH: + print("[PIR] ⚠ Mouvement détecté !") + passer_en_declenchee() + time.sleep(0.1) + +def boucle_principale(): + global etat + + passer_en_desarmee() + + stop_pir = threading.Event() + thread_pir = threading.Thread( + target=_surveiller_pir, args=(stop_pir,), daemon=True + ) + thread_pir.start() + + print("\n=== Système d'alarme démarré ===") + print(" Tapez le code sur le keypad pour armer / désarmer.\n") + + try: + while True: + with etat_lock: + etat_local = etat + + if etat_local == "desarmee": + print(" → Saisir le code pour ARMER :") + code = lire_code() # CORRECTION ICI + if code == CODE_SECRET: + print(" ✔ Code correct → armement") + passer_en_armee() + elif code != "": + print(" ✘ Code incorrect") + bip(nb=1, duree=0.4) + + elif etat_local == "armee": + time.sleep(0.1) + + elif etat_local == "declenchee": + print(" → Saisir le code pour DÉSARMER :") + code = lire_code() # CORRECTION ICI + if code == CODE_SECRET: + print(" ✔ Code correct → désarmement") + passer_en_desarmee() # AJOUT : pour que l'alarme s'arrête vraiment + elif code != "": + print(" ✘ Code incorrect — alarme maintenue") + + except KeyboardInterrupt: + print("\n[INFO] Arrêt demandé (Ctrl+C)") + + finally: + stop_pir.set() + _stop_buzzer.set() + led_off() + GPIO.cleanup() + print("[INFO] GPIO libérés. Fin du programme.") + +if __name__ == "__main__": + boucle_principale() \ No newline at end of file diff --git a/fastapi/main.py b/fastapi/main.py index 2620f94..982340a 100644 --- a/fastapi/main.py +++ b/fastapi/main.py @@ -1,7 +1,9 @@ import os import sys from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware import RPi.GPIO as GPIO +import uvicorn GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) @@ -13,7 +15,7 @@ sys.path.insert(0, composants) from lumieres import SystemeLumieres from thermostat import SystemeThermostat #from volets import SystemeVolets -from etatsystemes import EtatSysteme +from etatsysteme import EtatSysteme from septsegments import afficher_temperature app = FastAPI(title="L'API des loustiques") @@ -56,13 +58,33 @@ async def read_temp(): return {"success": False, "message": "Impossible de lire le capteur DHT11"} etatSysteme.signalerOk() - afficher_temperature(temp) + afficher_temperature(temp, 18) return {"success": True, "temperature": temp} except Exception as e: etatSysteme.signalerProbleme() return {"success": False, "message": str(e)} + + +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], # Autorise tous les sites web (le fameux "*") + allow_credentials=False, # (Doit être False quand on met "*") + allow_methods=["*"], # Autorise toutes les méthodes (GET, POST, etc.) + allow_headers=["*"], # Autorise tous les en-têtes +) if __name__ == "__main__": - import uvicorn - uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) + # On prépare les chemins proprement pour éviter les erreurs de parenthèses + # (Vérifie bien que le dossier 'web_secu' est bien dans le dossier racine de ton Pi 2) + chemin_cle = os.path.join(BASE_DIR, 'web_secu', 'ssl', 'key.pem') + chemin_cert = os.path.join(BASE_DIR, 'web_secu', 'ssl', 'cert.pem') + + # On lance Uvicorn avec la bonne syntaxe + uvicorn.run( + "main:app", + host="0.0.0.0", + port=8000, + ssl_keyfile=chemin_cle, + ssl_certfile=chemin_cert + ) \ No newline at end of file diff --git a/flask/index.html b/flask/index.html new file mode 100644 index 0000000..cdc66cc --- /dev/null +++ b/flask/index.html @@ -0,0 +1,222 @@ + + + + + + Loustiques Home - Connexion + + + + +
+

Loustiques Home

+

Connectez-vous via mot de passe ou avec votre bagde pour accéder à votre espace.

+ +
+ + +
+ +
+ + +
+ + + +
+ + +
+ + + + diff --git a/flask/main.py b/flask/main.py index ef60569..5c3531a 100644 --- a/flask/main.py +++ b/flask/main.py @@ -10,14 +10,14 @@ import re app = Flask(__name__) Talisman(app, force_https=True, -content_security_policy=False ) +content_security_policy=False) current_user = None BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) composants = os.path.join(BASE_DIR, "composants", "byPanda") sys.path.insert(0, composants) from alarme import SystemeAlarme -from lumiere import SystemeLumieres +from lumieres import SystemeLumieres from board1main import * @app.route("/") @@ -48,21 +48,45 @@ def call_led(): else: SystemeLumieres.eteindreLumieres() return jsonify({"success": True}) +# Variable temporaire pour stocker le dernier badge scanné +dernier_badge_scanne = None + @app.route("/rfid-scan", methods=["POST"]) def rfid_scan(): global dernier_badge_scanne data = request.get_json() - badge_id = str(data.get("badge_id")) + badge_id = data.get("badge_id") + + # On va créer cette fonction dans ton fichier auth.py juste après username = auth.get_user_by_rfid(badge_id) if username: - + # Le badge est dans la base de données ! On autorise. dernier_badge_scanne = username return jsonify({"success": True, "username": username}) else: - # Badge inconnu dans la BDD + # Badge inconnu return jsonify({"success": False}) +@app.route("/check-rfid-login", methods=["GET"]) +def check_rfid_login(): + global dernier_badge_scanne + global current_user + + # Si le Raspberry Pi a signalé un badge validé récemment + if dernier_badge_scanne: + user = dernier_badge_scanne + + # On valide la connexion côté serveur + current_user = user + + # On vide la variable pour ne pas le reconnecter en boucle à l'infini + dernier_badge_scanne = None + + return jsonify({"success": True, "username": user}) + + return jsonify({"success": False}) + @app.route("/alarme",methods=["POST"]) @@ -107,6 +131,23 @@ def get_users(): users = auth.get_users() return jsonify({"success": True, "users": users}) +@app.route("/api/relais-pi2/", methods=["GET"]) +def relais_pi2(action): + """ + Flask sert de relais. Le navigateur demande à Flask, et Flask demande au Pi 2. + """ + try: + # L'adresse de ton Pi 2 + url_pi2 = f"https://pi32.local:8000/{action}" + + # Le Pi 1 fait la requête ! verify=False permet d'ignorer le faux certificat + reponse = requests.get(url_pi2, timeout=5, verify=False) + + return jsonify(reponse.json()) + + except Exception as e: + return jsonify({"success": False, "message": str(e)}) + if __name__ == "__main__": print("[*] Démarrage du lecteur RFID et de l'alarme en arrière-plan...") diff --git a/flask/run_flask.sh b/flask/run_flask.sh index 62b9290..fd5386b 100755 --- a/flask/run_flask.sh +++ b/flask/run_flask.sh @@ -46,14 +46,14 @@ Vérification des certificats SSL ================================== EOF -bash web_secu/ssl.sh +bash ../web_secu/ssl.sh cat << 'EOF' ============================= Vérification du daemon Avahi ============================ EOF -bash web_secu/avahi.sh +bash ../web_secu/avahi.sh cat << 'EOF' diff --git a/flask/templates/dashboard.html b/flask/templates/dashboard.html index 4dccdc9..0f74813 100644 --- a/flask/templates/dashboard.html +++ b/flask/templates/dashboard.html @@ -268,14 +268,14 @@
Actions rapides
-