/* Système d'alarme V2.0
*********************************************************************************
*	Série de cours d'initiation à la programmation Arduino pour débutants. 		*
*	Offert gratuitement, sans inscription										*
*	Copier ce lien :															*
*	https://www.youtube.com/playlist?list=PLoffRtP427acSg1FbpFuH_g5ptz-aovFN	*
*********************************************************************************
*/
//Inclure la bibliothèque LiquidCrystal_I2C.
//#include <LiquidCrystal.h>
#include <LiquidCrystal_I2C.h>
// Créer l'objet lcd de la classe LiquidCrystal_I2C.
//LiquidCrystal_I2C lcd(0X20,16,2);
LiquidCrystal_I2C lcd(0X27, 16, 2);
//Inclure la bibliothèque Keypad
#include <Keypad.h>

// Relie le + du buzzer à la broche 8
#define piezo 8
// Relie la pin déclencheur à la broche 9
#define trigPin 9
// Relie la pin écho à la broche 10
#define echoPin 10

//Relie la Led tricolor aux broches 11,12,13.
const int LedRouge = 11, LedBleu = 12, LedVert = 13;

// Les variables changeront:
int ledState = LOW;  // ledState utilisé pour définir l'état de la LED
/*_____________________________________________________________________________ 
 *  Généralement, vous devez utiliser "unsigned long" pour les variables 
 *  qui contiennent du temps. La valeur deviendra rapidement trop grande pour 
 *  qu'un int puisse la stocker
 * _________________________________________________________________________ */
unsigned long previousMillis = 0;  // will store last time LED was updated.

// les constantes ne changeront pas:
const long interval = 1000;  // intervalle de clignotement (millisecondes)

long duration; // La durée de la note

// Créer les variables pour le capteur de distance par ultrasons.
int distance, initialDistance, currentDistance, posCurseur;

int screenOffMsg = 0;
String NIP = "1234";   // Chaine de caractères initialisée
String NIP_Temporaire; // Chaine de caractères non initialisée

// État de l'alarme
boolean active = false;
boolean activerAlarme = false;
boolean alarmeActive = false;

//État du mot de passe saisi pour arrêter l'alarme
boolean ModeChangerNIP = false;
boolean NIPChanged = false;

// Definit les paramètres du pavé matriciel 4x4.
const byte ROWS = 4; //4 lignes
const byte COLS = 4; //4 colonnes
char keypressed;     // Touche pressée.

//définit les symboles sur les boutons des claviers
char keyMap[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}};

byte rowPins[ROWS] = {7, 6, 5, 4}; // Brochage des lignes du clavier
byte colPins[COLS] = {3, 2, 1, 0}; // Brochage des colonnes du clavier

// Créer et initialise l'objet clavier de la classe Keypad.
Keypad clavier = Keypad( makeKeymap(keyMap), rowPins, colPins, ROWS, COLS); 

/*==========  Fin de l'entête déclarative ===============================*/

void setup() { 
  lcd.init(); lcd.backlight(); // initialise l'écran lcd...
  pinMode(piezo, OUTPUT);   // Définir buzzer comme sortie
  pinMode(trigPin, OUTPUT); // Définir trigPin comme sortie
  pinMode(echoPin, INPUT);  // Définir echoPin comme entrée
 
  lcd.print(" INITIALISATION ");
  
  //Définir le mode OUTPUT pour les broches 11, 12, 13.
  // et teste la led tricolor.
  for(int pin=11;pin<=13;pin++){
    pinMode(pin,OUTPUT); 
    digitalWrite(pin,HIGH); delay(1000);  
    digitalWrite(pin,LOW);  delay(100);
    CommandLed(LedVert,1);} //Quitte la boucle for()   
  
}// Quitte la fonction setup().

void loop() {
  
  if (activerAlarme){
    lcd.clear();
    lcd.setCursor(0,0); lcd.print("Alarme sera");
    lcd.setCursor(0,1); lcd.print("active dans");       
    
    int countdown = 9; // Compte à rebours de 9 secondes avant d'activer l'alarme
    
    while (countdown != 0) { // Tant que countdown n'égale pas 0...
      lcd.setCursor(13,1); lcd.print(countdown);  // Affiche le décompte
      countdown--; // Opérateur de décrémentation soustrait 1 à countdown
      tone(piezo, 700, 100); // Beep
      
      if (ledState == HIGH){ledState = LOW;}
      else {ledState = HIGH;}
      // définit l'état de la LED avec ledState de la variable :
      digitalWrite(LedRouge, ledState);      
      delay(1000);			 // Vitesse du décompte par pas de 1 seconde
    } // Sortie de while.
    
    lcd.clear(); // Efface l'écran.
    lcd.setCursor(0,0); lcd.print("Alarme Active !"); // Affiche l'état de l'alarme
    initialDistance = getDistance(); 
    activerAlarme = false;
    alarmeActive = true; CommandLed(LedVert,1);
    }
  
  if (alarmeActive == true){
    CommandLed(LedRouge,1);
      currentDistance = getDistance() + 10;
      if ( currentDistance < initialDistance) {
        tone(piezo, 1000); // Envoie un signal sonore de 1 KHz
        lcd.clear();
        EntrezNip();
      }
    }

  if (!alarmeActive) {
    CommandLed(LedVert,1);
    if (screenOffMsg == 0 ){
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("A - Activation");
      lcd.setCursor(0,1);
      lcd.print("B - Changer NIP");
      screenOffMsg = 1;
    }
    keypressed = clavier.getKey();
     if (keypressed =='A'){        //If A is pressed, activate the alarm
      tone(piezo, 1000, 200);
      activerAlarme = true;            
    }
    else if (keypressed =='B') {
      CommandLed(LedBleu,1);
      lcd.clear();
      int i=1;
      tone(piezo, 2000, 20);
      NIP_Temporaire = "";
      lcd.setCursor(0,0);
      lcd.print("NIP Actuel");
      lcd.setCursor(0,1);
      lcd.print(">");
      ModeChangerNIP = true;
      NIPChanged = true;
      
      while(NIPChanged) {      
      keypressed = clavier.getKey();
      if (keypressed != NO_KEY){
        if (keypressed == '0' || keypressed == '1' || keypressed == '2' || keypressed == '3' ||
            keypressed == '4' || keypressed == '5' || keypressed == '6' || keypressed == '7' ||
            keypressed == '8' || keypressed == '9' ) {
         NIP_Temporaire += keypressed;
         lcd.setCursor(posCurseur,1);
         lcd.print("*");
         posCurseur++;
         tone(piezo, 2000, 100);
        }
      }
      if (posCurseur > 5 || keypressed == '#') {
        NIP_Temporaire = "";
        posCurseur=1;
        lcd.clear();
        lcd.setCursor(0,0); lcd.print("Nip Actuel?");
        lcd.setCursor(0,1); lcd.print(">"); 
      }
      if ( keypressed == '*') {
        posCurseur=1;
        tone(piezo, 2000, 100);
        if (NIP == NIP_Temporaire) {
          NIP_Temporaire="";
          lcd.clear();
          lcd.setCursor(0,0); lcd.print("Nouveau NIP");
          lcd.setCursor(0,1); lcd.print(">");
          while(ModeChangerNIP){
            keypressed = clavier.getKey();
            if (keypressed != NO_KEY){
              if (keypressed == '0' || keypressed == '1' || keypressed == '2' || keypressed == '3' ||
                  keypressed == '4' || keypressed == '5' || keypressed == '6' || keypressed == '7' ||
                  keypressed == '8' || keypressed == '9' ) {
                NIP_Temporaire += keypressed;
                lcd.setCursor(posCurseur,1); 
                lcd.print("*");
                posCurseur++;
                tone(piezo, 2000, 100);
              }
            }
            if (posCurseur > 5 || keypressed == '#') {
              NIP_Temporaire = "";
              posCurseur=1;
              tone(piezo, 2000, 100);
              lcd.clear();
              lcd.setCursor(0,0);
              lcd.print("Nouveau NIP");
              lcd.setCursor(0,1);
              lcd.print(">");
            }
            if ( keypressed == '*') {
              posCurseur=1;
              tone(piezo, 2000, 100);
              NIP = NIP_Temporaire;
              ModeChangerNIP = false;
              NIPChanged = false;
              screenOffMsg = 0;
              CommandLed(LedVert,1);
            }            
          }
        }
      }
    }
   }
 }
}

void EntrezNip() {
  int k=5;
  NIP_Temporaire = "";
  active = true;
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(" *** ALARME *** ");
  lcd.setCursor(0,1);
  lcd.print("NIP>");
      while(active) {
      keypressed = clavier.getKey();
      if (keypressed != NO_KEY){
        if (keypressed == '0' || keypressed == '1' || keypressed == '2' || keypressed == '3' ||
            keypressed == '4' || keypressed == '5' || keypressed == '6' || keypressed == '7' ||
            keypressed == '8' || keypressed == '9' ) {
          NIP_Temporaire += keypressed;
          lcd.setCursor(k,1);
          lcd.print("*");
          k++;
        }
      }
      if (k > 9 || keypressed == '#') {
        NIP_Temporaire = "";
        k=5;
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print(" *** ALARME *** ");
        lcd.setCursor(0,1);
        lcd.print("NIP>");
      }
      if ( keypressed == '*') {
        if ( NIP_Temporaire == NIP ) {
          active = false;
          alarmeActive = false;
          noTone(piezo);
          screenOffMsg = 0; 
        }
        else if (NIP_Temporaire != NIP) {
          lcd.setCursor(0,1);
          lcd.print("  Recommencez ! ");
          delay(2000);
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print(" *** ALARME *** ");
          lcd.setCursor(0,1);
          lcd.print("NIP>");
        }
      }    
    }
}
// Fonction personnalisée pour le capteur à ultrasons
long getDistance(){
  // Efface le trigPin
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);

  // Définit le trigPin sur l'état HIGH pendant 10 microsecondes
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  // Lit l'echoPin, renvoie le temps de parcours de l'onde sonore en microsecondes
  duration = pulseIn(echoPin, HIGH);

  // Calcul de la distance
  distance = duration*0.034/2;
   return distance;
}

void CommandLed(int ledPin, bool State){
  switch(ledPin){
    case LedRouge: digitalWrite(ledPin, State);
    digitalWrite(LedBleu, LOW);
    digitalWrite(LedVert, LOW);    
    break;
    
    case LedBleu: digitalWrite(ledPin, State);
    digitalWrite(LedRouge, LOW);
    digitalWrite(LedVert, LOW);    
    break;
    
    case LedVert: digitalWrite(ledPin, State);
    digitalWrite(LedRouge, LOW);
    digitalWrite(LedBleu, LOW);    
    break;
    }
}