diff --git a/composants/byPanda/ALARM_V1.py b/composants/byPanda/ALARM_V1.py deleted file mode 100644 index 8939f36..0000000 --- a/composants/byPanda/ALARM_V1.py +++ /dev/null @@ -1,207 +0,0 @@ - -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 - -# 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 - -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) # anti-rebond - while GPIO.input(col) == GPIO.LOW: - pass # attente relâchement - 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]") - return "" - touche = lire_touche() - if touche and touche.isdigit(): - saisi += touche - print("*", end="", flush=True) - time.sleep(0.05) - print() - return saisi - - -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) # 2 petits bips = armée avec succès - 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 - - # 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.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(nb_chiffres=len(CODE_SECRET)) - if code == CODE_SECRET: - print(" ✔ Code correct → armement") - passer_en_armee() - elif code != "": - print(" ✘ Code incorrect") - bip(nb=1, duree=0.4) # 1 bip long = erreur - - elif etat_local == "armee": - time.sleep(0.1) - - 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") - passer_en_desarmee() - 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.") diff --git a/composants/byPanda/DHT11.py b/composants/byPanda/DHT11.py index b521098..52fcd06 100644 --- a/composants/byPanda/DHT11.py +++ b/composants/byPanda/DHT11.py @@ -1,14 +1,10 @@ import Adafruit_DHT as dht - -# On définit juste le capteur et la broche (Rappel : 25 en BCM = broche physique 22) capteur = dht.DHT11 pin = 25 def lire_temperature(): humidite, temperature = dht.read_retry(capteur, pin) - - # On renvoie la température au script principal ! if temperature is not None: return temperature else: - return 0 # Sécurité si le capteur bugge, pour ne pas faire planter l'affichage \ No newline at end of file + return 0 \ No newline at end of file diff --git a/composants/byPanda/LDR.py b/composants/byPanda/LDR.py new file mode 100644 index 0000000..d359a62 --- /dev/null +++ b/composants/byPanda/LDR.py @@ -0,0 +1,12 @@ +import RPi.GPIO as GPIO + +LDR_PIN = 20 + + +GPIO.setmode(GPIO.BCM) +GPIO.setup(LDR_PIN, GPIO.IN) + +def lire_etat(): + if GPIO.input(LDR_PIN) == GPIO.HIGH: + return "Nuit" + return "Jour" \ No newline at end of file diff --git a/composants/byPanda/alarme.py b/composants/byPanda/alarme.py index 2ff2448..210c61b 100644 --- a/composants/byPanda/alarme.py +++ b/composants/byPanda/alarme.py @@ -1,246 +1,194 @@ -import time import RPi.GPIO as GPIO +import time +import threading -GPIO.setmode(GPIO.BCM) +# Configuration initiale +GPIO.setmode(GPIO.BOARD) # Utilisation des numéros physiques des pins GPIO.setwarnings(False) +# --- CONFIGURATION PINS (BOARD) --- +PIN_LED_R = 11 +PIN_LED_G = 15 +PIN_LED_B = 13 +PIN_PIR = 10 +PIN_BUZZER = 12 -class SystemeAlarme: - def __init__(self): - """ - Initialise les composants liés à l'alarme. +# Pins Keypad (Vérifie bien tes branchements physiques sur ces numéros) +ROWS = [29, 31, 33, 35] +COLS = [37, 32, 36, 38] - Cette classe gère uniquement la logique locale de sécurité : - - le capteur PIR - - le buzzer - - la LED RGB de statut - - le clavier 4x4 +KEYPAD_MAP = [ + ['1', '2', '3', 'A'], + ['4', '5', '6', 'B'], + ['7', '8', '9', 'C'], + ['*', '0', '#', 'D'], +] - Elle ne dépend d'aucune autre partie du projet. - """ +CODE_SECRET = "1234" - # ----------------------------- - # Définition des pins physiques - # ----------------------------- - self.pinPir = 15 - self.pinBuzzer = 18 +# --- INITIALISATION 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) - self.pinLedRouge = 17 - self.pinLedVerte = 27 - self.pinLedBleue = 22 +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) - # Clavier 4x4 - # 4 lignes + 4 colonnes - self.lignes = [5, 6, 13, 19] - self.colonnes = [26, 12, 16, 20] +etat_alarme = "Désarmée" +etat_lock = threading.Lock() - # Disposition classique d'un clavier 4x4 - self.touches = [ - ["1", "2", "3", "A"], - ["4", "5", "6", "B"], - ["7", "8", "9", "C"], - ["*", "0", "#", "D"] - ] +_stop_buzzer = threading.Event() +_thread_buzzer = None - # ----------------------------- - # Variables de fonctionnement - # ----------------------------- - self.codeSecret = "1234" - self.codeSaisi = "" - # Etats possibles : - # - desarme - # - arme - # - alarme - self.etat = "desarme" - # Anti-rebond clavier - self.derniereLecture = 0 - self.delaiLecture = 0.25 +def led(r=False, g=False, b=False): + 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) - self.initialiserGPIO() - self.mettreAJourEtat() +def led_bleu(): led(b=True) +def led_vert(): led(g=True) +def led_rouge(): led(r=True) +def led_off(): led() - def initialiserGPIO(self): - """Configure les broches du Raspberry Pi pour l'alarme.""" - GPIO.setup(self.pinPir, GPIO.IN) - GPIO.setup(self.pinBuzzer, GPIO.OUT, initial=GPIO.LOW) +def bip(nb=1, duree=0.08, pause=0.12): + for _ in range(nb): + GPIO.output(PIN_BUZZER, GPIO.HIGH) + time.sleep(duree) + GPIO.output(PIN_BUZZER, GPIO.LOW) + time.sleep(pause) - GPIO.setup(self.pinLedRouge, GPIO.OUT, initial=GPIO.LOW) - GPIO.setup(self.pinLedVerte, GPIO.OUT, initial=GPIO.LOW) - GPIO.setup(self.pinLedBleue, GPIO.OUT, initial=GPIO.LOW) +def _buzzer_continu(stop_event: threading.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) - for pin in self.lignes: - GPIO.setup(pin, GPIO.OUT, initial=GPIO.LOW) - for pin in self.colonnes: - GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) +def lire_touche(): - def definirCouleur(self, rouge, vert, bleu): - """ - Allume la LED RGB selon la couleur voulue. + for i, row in enumerate(ROWS): + GPIO.output(row, GPIO.LOW) + time.sleep(0.01) # Stabilisation électrique + for j, col in enumerate(COLS): + if GPIO.input(col) == GPIO.LOW: + time.sleep(0.05) # Anti-rebond + while GPIO.input(col) == GPIO.LOW: + time.sleep(0.01) + GPIO.output(row, GPIO.HIGH) + return KEYPAD_MAP[i][j] + GPIO.output(row, GPIO.HIGH) + return None - Paramètres : - - rouge : True / False - - vert : True / False - - bleu : True / False - """ - GPIO.output(self.pinLedRouge, GPIO.HIGH if rouge else GPIO.LOW) - GPIO.output(self.pinLedVerte, GPIO.HIGH if vert else GPIO.LOW) - GPIO.output(self.pinLedBleue, GPIO.HIGH if bleu else GPIO.LOW) +def lire_code(nb_chiffres=4, timeout=20): + saisi = "" + debut = time.time() + print(" Entrez le code : ", end="", flush=True) + while len(saisi) < nb_chiffres: + if time.time() - debut > timeout: + print("\n [Timeout]") + return "" + touche = lire_touche() + if touche and touche.isdigit(): + saisi += touche + bip(1, 0.05) # Petit bip de confirmation touche + print("*", end="", flush=True) + time.sleep(0.05) + print() + return saisi - def mettreAJourEtat(self): - """ - Met à jour les sorties selon l'état actuel du système. +# --- GESTION DES ÉTATS --- - - desarme : LED verte, buzzer éteint - - arme : LED bleue, buzzer éteint - - alarme : LED rouge, buzzer allumé - """ - if self.etat == "desarme": - self.definirCouleur(False, True, False) - GPIO.output(self.pinBuzzer, GPIO.LOW) +def passer_en_desarmee(): + global etat_alarme, _thread_buzzer + _stop_buzzer.set() + if _thread_buzzer and _thread_buzzer.is_alive(): + _thread_buzzer.join() + with etat_lock: + etat_alarme = "Désarmée" + led_bleu() + print("[ÉTAT] ● DÉSARMÉE") - elif self.etat == "arme": - self.definirCouleur(False, False, True) - GPIO.output(self.pinBuzzer, GPIO.LOW) +def passer_en_armee(): + global etat_alarme + with etat_lock: + etat_alarme = "Armée" + led_vert() + bip(nb=2) + print("[ÉTAT] ● ARMÉE") - elif self.etat == "alarme": - self.definirCouleur(True, False, False) - GPIO.output(self.pinBuzzer, GPIO.HIGH) +def passer_en_declenchee(): + global etat_alarme, _thread_buzzer + with etat_lock: + # On ne déclenche que si on était armé + if etat_alarme == "Armée": + etat_alarme = "Déclenchée" + led_rouge() + print("[ÉTAT] ● DÉCLENCHÉE !") + _stop_buzzer.clear() + _thread_buzzer = threading.Thread(target=_buzzer_continu, args=(_stop_buzzer,), daemon=True) + _thread_buzzer.start() - def armer(self): - """Passe le système en mode armé.""" - self.etat = "arme" - self.codeSaisi = "" - self.mettreAJourEtat() - print("Alarme activée.") +# --- SURVEILLANCE --- - def desarmer(self): - """Passe le système en mode désarmé.""" - self.etat = "desarme" - self.codeSaisi = "" - self.mettreAJourEtat() - print("Alarme désactivée.") +def _surveiller_pir(stop_evt: threading.Event): + while not stop_evt.is_set(): + with etat_lock: + local_etat = etat_alarme + if local_etat == "Armée" and GPIO.input(PIN_PIR) == GPIO.HIGH: + passer_en_declenchee() + time.sleep(0.2) - def declencherAlarme(self): - """ - Déclenche l'alarme si un mouvement est détecté alors - que le système est armé. - """ - if self.etat != "alarme": - self.etat = "alarme" - self.codeSaisi = "" - self.mettreAJourEtat() - print("Intrusion détectée : alarme déclenchée.") +def boucle_principale(): + """Lancée par board1main dans un thread.""" + passer_en_desarmee() + + stop_pir = threading.Event() + thread_pir = threading.Thread(target=_surveiller_pir, args=(stop_pir,), daemon=True) + thread_pir.start() - def lireClavier(self): - """ - Scanne le clavier 4x4. + print("\n=== Système d'alarme démarré ===") - Retour : - - la touche détectée - - None si aucune touche n'est pressée - """ - maintenant = time.time() + try: + while True: + with etat_lock: + current = etat_alarme - if maintenant - self.derniereLecture < self.delaiLecture: - return None + # CAS 1 : L'alarme est éteinte, on attend le code pour l'allumer + if current == "Désarmée": + print(" [DÉSARMÉE] Entrez code pour ARMER...") + code = lire_code(len(CODE_SECRET)) + if code == CODE_SECRET: + passer_en_armee() + elif code != "": + bip(1, 0.5) - for indexLigne, ligne in enumerate(self.lignes): - GPIO.output(ligne, GPIO.HIGH) + # CAS 2 : L'alarme est allumée, on attend le code pour l'éteindre + elif current == "Armée": + # On réutilise lire_code ici pour permettre le désarmement manuel + print(" [ARMÉE] Entrez code pour DÉSARMER...") + code = lire_code(len(CODE_SECRET)) + if code == CODE_SECRET: + passer_en_desarmee() + elif code != "": + bip(1, 0.5) - for indexColonne, colonne in enumerate(self.colonnes): - if GPIO.input(colonne) == GPIO.HIGH: - GPIO.output(ligne, GPIO.LOW) - self.derniereLecture = maintenant - - # Petite attente pour éviter la lecture multiple - time.sleep(0.05) - - return self.touches[indexLigne][indexColonne] - - GPIO.output(ligne, GPIO.LOW) - - return None - - def validerCode(self): - """ - Vérifie le code saisi. - - Si le code est correct : - - alarme désarmée -> armée - - alarme armée -> désarmée - - alarme déclenchée -> désarmée - - Si le code est faux : - - on efface la saisie - """ - if self.codeSaisi == self.codeSecret: - if self.etat == "desarme": - self.armer() - else: - self.desarmer() - else: - print("Code incorrect.") - self.codeSaisi = "" - - def traiterClavier(self, touche): - """ - Gère la logique du clavier : - - chiffres : ajout au code saisi - - * : efface la saisie - - # : valide le code - """ - if touche is None: - return - - print("Touche appuyée :", touche) - - if touche == "*": - self.codeSaisi = "" - print("Saisie effacée.") - return - - if touche == "#": - self.validerCode() - return - - if touche.isdigit(): - if len(self.codeSaisi) < 8: - self.codeSaisi += touche - print("Code en cours :", "*" * len(self.codeSaisi)) - - def surveillerPIR(self): - """ - Vérifie le capteur de mouvement. - - Si un mouvement est détecté alors que l'alarme est armée, - on passe en état d'alarme. - """ - mouvement = GPIO.input(self.pinPir) == GPIO.HIGH - - if self.etat == "arme" and mouvement: - self.declencherAlarme() - - def mettreAJour(self): - """ - Fonction appelée en boucle dans le programme principal. - - Elle : - - lit le clavier - - traite la touche appuyée - - surveille le PIR - - synchronise LED et buzzer avec l'état courant - """ - touche = self.lireClavier() - self.traiterClavier(touche) - self.surveillerPIR() - self.mettreAJourEtat() - - def cleanup(self): - """ - Remet les sorties dans un état propre à la fermeture. - """ - GPIO.output(self.pinBuzzer, GPIO.LOW) - self.definirCouleur(False, False, False) \ No newline at end of file + # CAS 3 : L'alarme sonne, on attend le code pour stopper le buzzer + elif current == "Déclenchée": + print(" [ALERTE] Entrez code pour STOPPER...") + code = lire_code(len(CODE_SECRET)) + if code == CODE_SECRET: + passer_en_desarmee() + + time.sleep(0.1) + finally: + stop_pir.set() + _stop_buzzer.set() + led_off() \ No newline at end of file diff --git a/composants/byPanda/alarme_test.py b/composants/byPanda/alarme_test.py new file mode 100644 index 0000000..2ff2448 --- /dev/null +++ b/composants/byPanda/alarme_test.py @@ -0,0 +1,246 @@ +import time +import RPi.GPIO as GPIO + +GPIO.setmode(GPIO.BCM) +GPIO.setwarnings(False) + + +class SystemeAlarme: + def __init__(self): + """ + Initialise les composants liés à l'alarme. + + Cette classe gère uniquement la logique locale de sécurité : + - le capteur PIR + - le buzzer + - la LED RGB de statut + - le clavier 4x4 + + Elle ne dépend d'aucune autre partie du projet. + """ + + # ----------------------------- + # Définition des pins physiques + # ----------------------------- + self.pinPir = 15 + self.pinBuzzer = 18 + + self.pinLedRouge = 17 + self.pinLedVerte = 27 + self.pinLedBleue = 22 + + # Clavier 4x4 + # 4 lignes + 4 colonnes + self.lignes = [5, 6, 13, 19] + self.colonnes = [26, 12, 16, 20] + + # Disposition classique d'un clavier 4x4 + self.touches = [ + ["1", "2", "3", "A"], + ["4", "5", "6", "B"], + ["7", "8", "9", "C"], + ["*", "0", "#", "D"] + ] + + # ----------------------------- + # Variables de fonctionnement + # ----------------------------- + self.codeSecret = "1234" + self.codeSaisi = "" + + # Etats possibles : + # - desarme + # - arme + # - alarme + self.etat = "desarme" + + # Anti-rebond clavier + self.derniereLecture = 0 + self.delaiLecture = 0.25 + + self.initialiserGPIO() + self.mettreAJourEtat() + + def initialiserGPIO(self): + """Configure les broches du Raspberry Pi pour l'alarme.""" + GPIO.setup(self.pinPir, GPIO.IN) + GPIO.setup(self.pinBuzzer, GPIO.OUT, initial=GPIO.LOW) + + GPIO.setup(self.pinLedRouge, GPIO.OUT, initial=GPIO.LOW) + GPIO.setup(self.pinLedVerte, GPIO.OUT, initial=GPIO.LOW) + GPIO.setup(self.pinLedBleue, GPIO.OUT, initial=GPIO.LOW) + + for pin in self.lignes: + GPIO.setup(pin, GPIO.OUT, initial=GPIO.LOW) + + for pin in self.colonnes: + GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) + + def definirCouleur(self, rouge, vert, bleu): + """ + Allume la LED RGB selon la couleur voulue. + + Paramètres : + - rouge : True / False + - vert : True / False + - bleu : True / False + """ + GPIO.output(self.pinLedRouge, GPIO.HIGH if rouge else GPIO.LOW) + GPIO.output(self.pinLedVerte, GPIO.HIGH if vert else GPIO.LOW) + GPIO.output(self.pinLedBleue, GPIO.HIGH if bleu else GPIO.LOW) + + def mettreAJourEtat(self): + """ + Met à jour les sorties selon l'état actuel du système. + + - desarme : LED verte, buzzer éteint + - arme : LED bleue, buzzer éteint + - alarme : LED rouge, buzzer allumé + """ + if self.etat == "desarme": + self.definirCouleur(False, True, False) + GPIO.output(self.pinBuzzer, GPIO.LOW) + + elif self.etat == "arme": + self.definirCouleur(False, False, True) + GPIO.output(self.pinBuzzer, GPIO.LOW) + + elif self.etat == "alarme": + self.definirCouleur(True, False, False) + GPIO.output(self.pinBuzzer, GPIO.HIGH) + + def armer(self): + """Passe le système en mode armé.""" + self.etat = "arme" + self.codeSaisi = "" + self.mettreAJourEtat() + print("Alarme activée.") + + def desarmer(self): + """Passe le système en mode désarmé.""" + self.etat = "desarme" + self.codeSaisi = "" + self.mettreAJourEtat() + print("Alarme désactivée.") + + def declencherAlarme(self): + """ + Déclenche l'alarme si un mouvement est détecté alors + que le système est armé. + """ + if self.etat != "alarme": + self.etat = "alarme" + self.codeSaisi = "" + self.mettreAJourEtat() + print("Intrusion détectée : alarme déclenchée.") + + def lireClavier(self): + """ + Scanne le clavier 4x4. + + Retour : + - la touche détectée + - None si aucune touche n'est pressée + """ + maintenant = time.time() + + if maintenant - self.derniereLecture < self.delaiLecture: + return None + + for indexLigne, ligne in enumerate(self.lignes): + GPIO.output(ligne, GPIO.HIGH) + + for indexColonne, colonne in enumerate(self.colonnes): + if GPIO.input(colonne) == GPIO.HIGH: + GPIO.output(ligne, GPIO.LOW) + self.derniereLecture = maintenant + + # Petite attente pour éviter la lecture multiple + time.sleep(0.05) + + return self.touches[indexLigne][indexColonne] + + GPIO.output(ligne, GPIO.LOW) + + return None + + def validerCode(self): + """ + Vérifie le code saisi. + + Si le code est correct : + - alarme désarmée -> armée + - alarme armée -> désarmée + - alarme déclenchée -> désarmée + + Si le code est faux : + - on efface la saisie + """ + if self.codeSaisi == self.codeSecret: + if self.etat == "desarme": + self.armer() + else: + self.desarmer() + else: + print("Code incorrect.") + self.codeSaisi = "" + + def traiterClavier(self, touche): + """ + Gère la logique du clavier : + - chiffres : ajout au code saisi + - * : efface la saisie + - # : valide le code + """ + if touche is None: + return + + print("Touche appuyée :", touche) + + if touche == "*": + self.codeSaisi = "" + print("Saisie effacée.") + return + + if touche == "#": + self.validerCode() + return + + if touche.isdigit(): + if len(self.codeSaisi) < 8: + self.codeSaisi += touche + print("Code en cours :", "*" * len(self.codeSaisi)) + + def surveillerPIR(self): + """ + Vérifie le capteur de mouvement. + + Si un mouvement est détecté alors que l'alarme est armée, + on passe en état d'alarme. + """ + mouvement = GPIO.input(self.pinPir) == GPIO.HIGH + + if self.etat == "arme" and mouvement: + self.declencherAlarme() + + def mettreAJour(self): + """ + Fonction appelée en boucle dans le programme principal. + + Elle : + - lit le clavier + - traite la touche appuyée + - surveille le PIR + - synchronise LED et buzzer avec l'état courant + """ + touche = self.lireClavier() + self.traiterClavier(touche) + self.surveillerPIR() + self.mettreAJourEtat() + + def cleanup(self): + """ + Remet les sorties dans un état propre à la fermeture. + """ + GPIO.output(self.pinBuzzer, GPIO.LOW) + self.definirCouleur(False, False, False) \ No newline at end of file diff --git a/composants/byPanda/board1main.py b/composants/byPanda/board1main.py index b9f3492..a111ce3 100644 --- a/composants/byPanda/board1main.py +++ b/composants/byPanda/board1main.py @@ -1,36 +1,27 @@ import time -from ALARM_V1 import * +import threading +import alarme from porterfid import SystemePorteRFID +import RPi.GPIO as GPIO -# ------------------------------------------------------------ -# board1main.py -# ------------------------------------------------------------ -# Ce fichier lance uniquement la logique locale de la board 1. -# Il ne dépend pas du site web, de la base de données ni de Flask. -# Son rôle est simplement de faire tourner : -# - le système d'alarme -# - le système de porte RFID -# ------------------------------------------------------------ - -alarme = SystemeAlarme() 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: - # Mise à jour des deux modules locaux - ALARM_V1.boucle_principale() porte.mettreAJour() - time.sleep(0.05) + time.sleep(0.3) except KeyboardInterrupt: - porte.cleanup() - alarme.cleanup() print("\nArrêt manuel du programme.") - finally: - # On remet les sorties dans un état propre avant de quitter - alarme.cleanup() + # 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 b3ec8cf..a893f36 100644 --- a/composants/byPanda/bouton.py +++ b/composants/byPanda/bouton.py @@ -35,7 +35,7 @@ def test_boutons(): afficher_temperature(temperature_DHT, temperature_cible) etatPrecedent_up = etat_up - - + if etat_down != etatPrecedent_down: if etat_down == 0: print("Bouton DOWN Appuyé ⬇️") @@ -48,9 +48,3 @@ def test_boutons(): t.sleep(0.05) -if __name__ == "__main__": - try: - test_boutons() - except KeyboardInterrupt: - print("\nFin du test") - GPIO.cleanup() \ No newline at end of file diff --git a/composants/byPanda/bouton_servo.py b/composants/byPanda/bouton_servo.py index f077464..2e04c02 100644 --- a/composants/byPanda/bouton_servo.py +++ b/composants/byPanda/bouton_servo.py @@ -1,43 +1,12 @@ import RPi.GPIO as GPIO -import time as t -GPIO.setmode(GPIO.BOARD) -GPIO.setwarnings(False) -servo = 12 -GPIO.setup(servo, GPIO.OUT) +LDR_PIN = 20 -pwm = GPIO.PWM(servo, 50) -pwm.start(0) -bouton_up = 13 -bouton_down = 36 -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 setup_ldr(): + GPIO.setmode(GPIO.BCM) + GPIO.setup(LDR_PIN, GPIO.IN) -def test_boutons(): - etatPrecedent_up = GPIO.input(bouton_up) - etatPrecedent_down = GPIO.input(bouton_down) - - print("Test lancé ! Appuie sur UP (23) pour monter, DOWN (24) pour descendre.") - - 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é ⬆️") - print("Volet ouvert") - pwm.ChangeDutyCycle(2) - etatPrecedent_up = etat_up - if etat_down != etatPrecedent_down: - if etat_down == 0: - print("Bouton DOWN Appuyé ⬇️") - print("Volet fermé") - pwm.ChangeDutyCycle(7) - etatPrecedent_down = etat_down - t.sleep(0.05) - -if name == "main": - try: - test_boutons() - except KeyboardInterrupt: - print("\nFin du test") \ No newline at end of file +def lire_etat(): + if GPIO.input(LDR_PIN) == GPIO.HIGH: + return "Nuit" + return "Jour" \ No newline at end of file diff --git a/composants/byPanda/ledRGB.py b/composants/byPanda/ledRGB.py new file mode 100644 index 0000000..779dc12 --- /dev/null +++ b/composants/byPanda/ledRGB.py @@ -0,0 +1,15 @@ +import RPi.GPIO as GPIO +import time as t + +GPIO.setmode(GPIO.BOARD) + +r, g, b = 11, 13, 15 + +GPIO.setup(r, GPIO.OUT) +GPIO.setup(g, GPIO.OUT) +GPIO.setup(b, GPIO.OUT) + +while True: + GPIO.output(r, 1); t.sleep(1); GPIO.output(r, 0) + GPIO.output(g, 1); t.sleep(1); GPIO.output(g, 0) + GPIO.output(b, 1); t.sleep(1); GPIO.output(b, 0) \ No newline at end of file diff --git a/composants/test/LDR.py b/composants/test/LDR.py deleted file mode 100644 index 6114c2b..0000000 --- a/composants/test/LDR.py +++ /dev/null @@ -1,26 +0,0 @@ -import RPi.GPIO as GPIO -import time - -# Configuration -LDR_PIN = 20# Broche GPIO connectée au circuit LDR -SEUIL = 500 # Valeur de seuil à ajuster (0-1024) - -GPIO.setmode(GPIO.BCM) -GPIO.setup(LDR_PIN, GPIO.IN) - - -def lire_ldr(): - # Simulation de lecture analogique (nécessite MCP3008 ou circuit RC) - # Pour cet exemple, on simplifie par une lecture numérique - return GPIO.input(LDR_PIN) - -try: - while True: - luminosite = lire_ldr() - if luminosite < SEUIL: - print("Nuit : Allumage lumière") - else: - print("Jour : Extinction lumière") - time.sleep(1) -except KeyboardInterrupt: - GPIO.cleanup() diff --git a/flask/main.py b/flask/main.py index 9b91a50..8e8fa6c 100644 --- a/flask/main.py +++ b/flask/main.py @@ -18,9 +18,14 @@ 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 lumieres import SystemeLumieres -from board1main import * +from board1main import call_board1 +import alarme + + + + @app.route("/") def index(): @@ -76,10 +81,13 @@ def check_rfid_login(): return jsonify({"success": True, "username": user}) return jsonify({"success": False}) +""" @app.route("/alarme",methods=["POST"]) def armer_alarme(): SystemeAlarme.armer() return jsonify({"success": True}) + +""" @app.route("/admin") def admin_page(): return render_template("admin.html") @@ -87,8 +95,6 @@ def admin_page(): @app.route("/admin/logs") def logs_page(): return render_template("log.html") - - @app.route("/admin/logs/data") def get_logs(): try: @@ -114,32 +120,29 @@ def get_users(): users = auth.get_users() return jsonify({"success": True, "users": users}) +@app.route("/alarme_status") +def get_alarme_status_info(): # Nom différent de l'import 'alarme' + try: + # On accède à la variable du fichier + statut = alarme.etat_alarme + return jsonify({"success": True, "status": statut}) + except Exception as e: + return jsonify({"success": False, "message": str(e)}), 500 + @app.route("/api/", methods=["GET"]) def relais_pi2(action): url_pi2 = f"https://pi32.local:8000/{action}" - print(f"\n[RELAIS] 1. Tentative de contact avec le Pi 2 : {url_pi2}") - try: reponse = requests.get(url_pi2, timeout=5, verify=False) - print(f"[RELAIS] 2. Code HTTP reçu du Pi 2 : {reponse.status_code}") - print(f"[RELAIS] 3. Texte brut reçu du Pi 2 : {reponse.text}") if not reponse.ok: - return jsonify({ - "success": False, - "message": f"Le Pi 2 a refusé la requête (Code {reponse.status_code})" - }), reponse.status_code - - # Si tout va bien, on tente d'extraire le JSON - try: - data = reponse.json() - return jsonify(data) - except ValueError: - print("[RELAIS] 4. ERREUR : Le Pi 2 n'a pas renvoyé de JSON valide.") - return jsonify({"success": False, "message": "Réponse invalide du Pi 2"}), 502 + return jsonify({"success": False, "message": "Erreur Pi 2"}), reponse.status_code + + return jsonify(reponse.json()) except Exception as e: - print(f"[RELAIS] ERREUR CRITIQUE : Impossible de joindre le Pi 2. Raison : {e}") - return jsonify({"success": False, "message": f"Erreur de connexion : {str(e)}"}), 500 + # On ne garde que l'erreur si vraiment ça plante + print(f"[RELAIS] ERREUR : {e}") + return jsonify({"success": False, "message": str(e)}), 500 if __name__ == "__main__": diff --git a/flask/templates/dashboard.html b/flask/templates/dashboard.html index cb44086..6283c62 100644 --- a/flask/templates/dashboard.html +++ b/flask/templates/dashboard.html @@ -5,204 +5,38 @@ Loustiques Home — Dashboard @@ -224,66 +58,74 @@
-
- -
Statut
-
En ligne
-
Serveur opérationnel
-
Heure locale
--:--
-
--
- -
-
Température
-
-- °C
- - -
-
Porte
--
+
- -
Raspberry Pi 1 (actuelle)
-
Actif
-
Flask 3.1
+ +
Température
+
-- °C
+
Capteur DHT11 (Pi 2)
- -
Raspberry Pi 2 distant
-
Actif
-
FastAPi
-
+ + + +
Luminosité
+
--
+
Capteur LDR (Pi 2)
+
+
- -
Session
-
Authentifiée
-
Accès autorisé
+ +
Porte / Volet
+
--
+
État du moteur (Pi 2)
+
+ +
+ +
Alarme
+
--
+
Sécurité (Pi 1)
+
+ +
+ +
Raspberry Pi 1
+
Vérification...
+
Serveur Flask
+
+ +
+ +
Raspberry Pi 2
+
Vérification...
+
Serveur FastAPI
Actions rapides
-
- - + Éteindre la LED (Pi 2) + + +
@@ -297,78 +139,89 @@