From f275ad60f05ad4ce7a63b484901e327aab923243 Mon Sep 17 00:00:00 2001 From: maxime Date: Fri, 3 Apr 2026 18:35:33 +0200 Subject: [PATCH] =?UTF-8?q?f=C3=A9licitations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composants/byPanda/alarme.py | 168 ++++++++++------------------- composants/byPanda/board1main.py | 3 - composants/byPanda/bouton.py | 60 +++++------ composants/byPanda/bouton_servo.py | 62 +++++++++-- fastapi/main.py | 11 +- flask/main.py | 14 ++- 6 files changed, 154 insertions(+), 164 deletions(-) diff --git a/composants/byPanda/alarme.py b/composants/byPanda/alarme.py index c7a8321..634aae5 100644 --- a/composants/byPanda/alarme.py +++ b/composants/byPanda/alarme.py @@ -2,20 +2,17 @@ import RPi.GPIO as GPIO import time import threading -# ── Numérotation BCM ──────────────────────────────────────────────────────── GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) -# ── Broches ───────────────────────────────────────────────────────────────── PIN_LED_R = 17 -PIN_LED_G = 27 -PIN_LED_B = 22 -PIN_PIR = 15 +PIN_LED_G = 22 +PIN_LED_B = 3 +PIN_PIR = 23 PIN_BUZZER = 18 -# Keypad 4x4 — 4 lignes (sorties) + 4 colonnes (entrées pull-up) -ROWS = [5, 6, 13, 19] # R1 R2 R3 R4 -COLS = [26, 12, 16, 20] # C1 C2 C3 C4 +ROWS = [5, 6, 13, 19] +COLS = [26, 12, 16, 20] KEYPAD_MAP = [ ['1', '2', '3', 'A'], @@ -24,59 +21,41 @@ KEYPAD_MAP = [ ['*', '0', '#', 'D'], ] -# ── Code secret (modifiable ici) ───────────────────────────────────────────── CODE_SECRET = "1234" -# ── Configuration GPIO ─────────────────────────────────────────────────────── + 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) +GPIO.setup(PIN_PIR, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 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) -# ── État global ────────────────────────────────────────────────────────────── -etat = "desarmee" +etat = "Désarmée" etat_lock = threading.Lock() _stop_buzzer = threading.Event() _thread_buzzer = None -# ════════════════════════════════════════════════════════════════════════════ -# LED RGB -# ════════════════════════════════════════════════════════════════════════════ 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() - - -# ════════════════════════════════════════════════════════════════════════════ -# Buzzer -# ════════════════════════════════════════════════════════════════════════════ - 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.""" +def _buzzer_continu(stop_event): while not stop_event.is_set(): GPIO.output(PIN_BUZZER, GPIO.HIGH) time.sleep(0.5) @@ -84,39 +63,31 @@ def _buzzer_continu(stop_event: threading.Event): time.sleep(0.5) GPIO.output(PIN_BUZZER, GPIO.LOW) +def etat_alarme(): + with etat_lock: + return etat -# ════════════════════════════════════════════════════════════════════════════ -# Keypad 4x4 -# ════════════════════════════════════════════════════════════════════════════ 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) # anti-rebond + time.sleep(0.05) while GPIO.input(col) == GPIO.LOW: - pass # attente relâchement + pass GPIO.output(row, GPIO.HIGH) return KEYPAD_MAP[i][j] GPIO.output(row, GPIO.HIGH) return None def lire_code(nb_chiffres=4, timeout=30): - """ - Attend nb_chiffres touches numériques sur le keypad. - Retourne la chaîne saisie ou '' si timeout. - """ saisi = "" debut = time.time() print(" Code : ", end="", flush=True) while len(saisi) < nb_chiffres: if time.time() - debut > timeout: - print("\n [Timeout — saisie annulée]") + print("\n [Timeout]") return "" touche = lire_touche() if touche and touche.isdigit(): @@ -127,114 +98,89 @@ def lire_code(nb_chiffres=4, timeout=30): return saisi -# ════════════════════════════════════════════════════════════════════════════ -# Transitions d'état -# ════════════════════════════════════════════════════════════════════════════ - 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") + etat = "Désarmée" + led(b=True) # Bleu + print("[ÉTAT] ● DÉSARMÉE") def passer_en_armee(): global etat + print("[ÉTAT] ● ARMEMENT... Stabilisation capteur (10s)") + led(r=True, g=True) + time.sleep(10) + with etat_lock: - etat = "armee" - led_vert() - bip(nb=2) # 2 petits bips = armée avec succès - print("[ÉTAT] ● ARMÉE — LED verte — PIR actif") + etat = "Armée" + led(g=True) + bip(nb=2) + print("[ÉTAT] ● ARMÉE — Surveillance active !") def passer_en_declenchee(): global etat, _thread_buzzer with etat_lock: - etat = "declenchee" - led_rouge() - print("[ÉTAT] ● DÉCLENCHÉE — LED rouge — buzzer actif") + etat = "Déclenchée" + led(r=True) # Rouge + print("[ÉTAT] ● DÉCLENCHÉE !") _stop_buzzer.clear() - _thread_buzzer = threading.Thread( - target=_buzzer_continu, args=(_stop_buzzer,), daemon=True - ) + _thread_buzzer = threading.Thread(target=_buzzer_continu, args=(_stop_buzzer,), daemon=True) _thread_buzzer.start() - -# ════════════════════════════════════════════════════════════════════════════ -# Thread : surveillance PIR -# ════════════════════════════════════════════════════════════════════════════ - -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") +def _surveiller_pir(stop_evt): + print("[PIR] Thread de surveillance prêt") 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() + + if etat_local == "Armée": + if GPIO.input(PIN_PIR) == GPIO.HIGH: + time.sleep(0.3) + if GPIO.input(PIN_PIR) == GPIO.HIGH: + passer_en_declenchee() + time.sleep(0.1) -# ════════════════════════════════════════════════════════════════════════════ -# Boucle principale -# ════════════════════════════════════════════════════════════════════════════ - def boucle_principale(): - global etat - - # Démarrage : LED bleue (désarmée) passer_en_desarmee() - # Thread PIR en arrière-plan stop_pir = threading.Event() - thread_pir = threading.Thread( - target=_surveiller_pir, args=(stop_pir,), daemon=True - ) + 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") + print("\n=== Système prêt (Code: " + CODE_SECRET + ") ===") try: while True: - with etat_lock: - etat_local = etat + etat_actuel = etat_alarme() - # ── DÉSARMÉE : attente d'un code pour armer ────────────────────── - if etat_local == "desarmee": - print(" → Saisir le code pour ARMER :") - code = lire_code(nb_chiffres=len(CODE_SECRET)) - if code == CODE_SECRET: - print(" ✔ Code correct → armement") + if etat_actuel == "Désarmée": + print("→ Saisir code pour ARMER :") + if lire_code() == CODE_SECRET: passer_en_armee() - elif code != "": - print(" ✘ Code incorrect") - bip(nb=1, duree=0.4) # 1 bip long = erreur - # ── ARMÉE : le thread PIR gère le déclenchement ────────────────── - elif etat_local == "armee": - time.sleep(0.1) - - # ── DÉCLENCHÉE : attente du code pour désarmer ─────────────────── - elif etat_local == "declenchee": - print(" → Saisir le code pour DÉSARMER :") - code = lire_code(nb_chiffres=len(CODE_SECRET)) - if code == CODE_SECRET: - print(" ✔ Code correct → désarmement") + elif etat_actuel == "Armée": + print("→ Système ARMÉ (Code pour DÉSARMER) :") + if lire_code() == CODE_SECRET: passer_en_desarmee() - elif code != "": - print(" ✘ Code incorrect — alarme maintenue") + + elif etat_actuel == "Déclenchée": + print("→ Saisir code pour DÉSARMER :") + if lire_code() == CODE_SECRET: + passer_en_desarmee() + + time.sleep(0.2) except KeyboardInterrupt: - print("\n[INFO] Arrêt demandé (Ctrl+C)") - + print("\n[INFO] Arrêt demandé par l'utilisateur") finally: stop_pir.set() _stop_buzzer.set() - led_off() + led(False, False, False) GPIO.cleanup() print("[INFO] GPIO libérés. Fin du programme.") diff --git a/composants/byPanda/board1main.py b/composants/byPanda/board1main.py index a111ce3..6cfb7a7 100644 --- a/composants/byPanda/board1main.py +++ b/composants/byPanda/board1main.py @@ -7,14 +7,12 @@ import RPi.GPIO as GPIO porte = SystemePorteRFID() def call_board1(): - # 1. On lance l'alarme dans son propre thread pour qu'elle ne bloque pas le reste thread_alarme = threading.Thread(target=alarme.boucle_principale, daemon=True) thread_alarme.start() print("[BOARD 1] Système d'alarme lancé en arrière-plan.") try: - # 2. La boucle principale ne gère plus que le RFID while True: porte.mettreAJour() time.sleep(0.3) @@ -22,6 +20,5 @@ def call_board1(): except KeyboardInterrupt: print("\nArrêt manuel du programme.") finally: - # On utilise GPIO.cleanup() directement car alarme.cleanup n'existe pas porte.cleanup() GPIO.cleanup() \ No newline at end of file diff --git a/composants/byPanda/bouton.py b/composants/byPanda/bouton.py index a893f36..f38f413 100644 --- a/composants/byPanda/bouton.py +++ b/composants/byPanda/bouton.py @@ -3,48 +3,44 @@ import time as t from septsegments import afficher_temperature from DHT11 import lire_temperature -GPIO.setmode(GPIO.BCM) -GPIO.setwarnings(False) - +# --- Configuration des Pins --- bouton_up = 23 bouton_down = 24 -GPIO.setup(bouton_up, GPIO.IN, pull_up_down=GPIO.PUD_UP) -GPIO.setup(bouton_down, GPIO.IN, pull_up_down=GPIO.PUD_UP) + +# --- Variables Globales Partagées --- +temperature_cible = 18 + +def setup_boutons(): + """Initialisation des GPIO (à appeler au début)""" + GPIO.setmode(GPIO.BCM) + GPIO.setup(bouton_up, GPIO.IN, pull_up_down=GPIO.PUD_UP) + GPIO.setup(bouton_down, GPIO.IN, pull_up_down=GPIO.PUD_UP) def test_boutons(): + + global temperature_cible + setup_boutons() + temperature_DHT = lire_temperature() - temperature_cible = 18 - - etatPrecedent_up = GPIO.input(bouton_up) - etatPrecedent_down = GPIO.input(bouton_down) + etatPrecedent_up = GPIO.input(bouton_up) + etatPrecedent_down = GPIO.input(bouton_down) - print("Thermostat lancé ! Appuie sur UP (23) ou DOWN (24).") + print(f"Thermostat lancé ! Cible actuelle : {temperature_cible}°C") - afficher_temperature(temperature_DHT, temperature_cible) - while True: etat_up = GPIO.input(bouton_up) etat_down = GPIO.input(bouton_down) - if etat_up != etatPrecedent_up: - if etat_up == 0: - print("Bouton UP Appuyé ⬆️") - temperature_cible += 1 - if temperature_cible >= 40: - temperature_cible = 40 - - afficher_temperature(temperature_DHT, temperature_cible) - etatPrecedent_up = etat_up + if etat_up == 0 and etatPrecedent_up == 1: + temperature_cible = min(40, temperature_cible + 1) + print(f"Bouton UP -> Nouvelle cible : {temperature_cible}") + afficher_temperature(lire_temperature(), temperature_cible) - if etat_down != etatPrecedent_down: - if etat_down == 0: - print("Bouton DOWN Appuyé ⬇️") - temperature_cible -= 1 - if temperature_cible <= 0: - temperature_cible = 0 - - afficher_temperature(temperature_DHT, temperature_cible) - etatPrecedent_down = etat_down - - t.sleep(0.05) + if etat_down == 0 and etatPrecedent_down == 1: + temperature_cible = max(0, temperature_cible - 1) + print(f"Bouton DOWN -> Nouvelle cible : {temperature_cible}") + afficher_temperature(lire_temperature(), temperature_cible) + etatPrecedent_up = etat_up + etatPrecedent_down = etat_down + t.sleep(0.05) \ No newline at end of file diff --git a/composants/byPanda/bouton_servo.py b/composants/byPanda/bouton_servo.py index 2e04c02..698accf 100644 --- a/composants/byPanda/bouton_servo.py +++ b/composants/byPanda/bouton_servo.py @@ -1,12 +1,60 @@ import RPi.GPIO as GPIO +import time as t -LDR_PIN = 20 -def setup_ldr(): +servo_pin = 18 +bouton_up = 27 +bouton_down = 16 +etat_porte = "Fermé" + +def get_etat(etat): + global etat_porte + etat_porte = etat + print(f"État mis à jour : {etat_porte}") + +def test_boutons(): + global etat_porte + GPIO.setmode(GPIO.BCM) - GPIO.setup(LDR_PIN, GPIO.IN) + GPIO.setwarnings(False) + + GPIO.setup(servo_pin, GPIO.OUT) + GPIO.setup(bouton_up, GPIO.IN, pull_up_down=GPIO.PUD_UP) + GPIO.setup(bouton_down, GPIO.IN, pull_up_down=GPIO.PUD_UP) -def lire_etat(): - if GPIO.input(LDR_PIN) == GPIO.HIGH: - return "Nuit" - return "Jour" \ No newline at end of file + pwm = GPIO.PWM(servo_pin, 50) + pwm.start(0) + + etatPrecedent_up = GPIO.input(bouton_up) + etatPrecedent_down = GPIO.input(bouton_down) + + print("Thread Servo : Démarré et prêt.") + + try: + while True: + etat_up = GPIO.input(bouton_up) + etat_down = GPIO.input(bouton_down) + + if etat_up != etatPrecedent_up: + if etat_up == GPIO.LOW: + get_etat('Ouvert') + pwm.ChangeDutyCycle(2.5) + t.sleep(0.5) + pwm.ChangeDutyCycle(0) + etatPrecedent_up = etat_up + + if etat_down != etatPrecedent_down: + if etat_down == GPIO.LOW: + get_etat('Fermé') + pwm.ChangeDutyCycle(7.5) + t.sleep(0.5) + pwm.ChangeDutyCycle(0) + etatPrecedent_down = etat_down + + t.sleep(0.05) + except Exception as e: + print(f"Erreur dans le thread servo : {e}") + finally: + pwm.stop() + +#test_boutons() diff --git a/fastapi/main.py b/fastapi/main.py index 8ef6707..42542b4 100644 --- a/fastapi/main.py +++ b/fastapi/main.py @@ -62,21 +62,20 @@ async def eteindre_led(): etatSysteme.signalerProbleme() return {"success": False, "message": str(e)} + @app.get("/temperature") async def read_temp(): try: temp = controleur_thermostat.lireTemperature() if temp is None: - etatSysteme.signalerProbleme() - return {"success": False, "message": "Impossible de lire le capteur DHT11"} + # On renvoie une valeur par défaut ou 0 pour éviter le undefined + return {"success": False, "temperature": "--", "message": "Erreur DHT11"} - etatSysteme.signalerOk() - afficher_temperature(temp, 18) + afficher_temperature(temp, bouton.temperature_cible) return {"success": True, "temperature": temp} except Exception as e: - etatSysteme.signalerProbleme() - return {"success": False, "message": str(e)} + return {"success": False, "temperature": "Erreur", "message": str(e)} @app.get("/volet_status") async def volet_status(): diff --git a/flask/main.py b/flask/main.py index 8e8fa6c..aefdf08 100644 --- a/flask/main.py +++ b/flask/main.py @@ -121,13 +121,17 @@ def get_users(): return jsonify({"success": True, "users": users}) @app.route("/alarme_status") -def get_alarme_status_info(): # Nom différent de l'import 'alarme' +def get_alarme_status_info(): try: - # On accède à la variable du fichier - statut = alarme.etat_alarme - return jsonify({"success": True, "status": statut}) + # On appelle la fonction corrigée dans alarme.py + statut = alarme.etat_alarme() + + return jsonify({ + "success": True, + "status": statut # Retournera "Désarmée", "Armée" ou "Déclenchée" + }) except Exception as e: - return jsonify({"success": False, "message": str(e)}), 500 + return jsonify({"success": False, "message": str(e)}), 500 @app.route("/api/", methods=["GET"]) def relais_pi2(action):