diff --git a/myGates/MACAddr.txt b/myGates/MACAddr.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f856d08d3270c55fbae6f3fc1a9dc883087c7993
--- /dev/null
+++ b/myGates/MACAddr.txt
@@ -0,0 +1 @@
+ GATE 4 : 34:94:54:5A:2B:94
diff --git a/myGates/myGates_Barrier/credentials.h b/myGates/myGates_Barrier/credentials.h
new file mode 100644
index 0000000000000000000000000000000000000000..32038a95eb372b202d9dcc605c7915f9fcdd8478
--- /dev/null
+++ b/myGates/myGates_Barrier/credentials.h
@@ -0,0 +1,3 @@
+// Wifi and OTA credentials
+const char *ssid = "Gate";
+const char *password = "neOCampus";
diff --git a/myGates/myGates_Barrier/gateParameters.h b/myGates/myGates_Barrier/gateParameters.h
new file mode 100644
index 0000000000000000000000000000000000000000..130a5ada981fad5793a95e568b311982d9293a03
--- /dev/null
+++ b/myGates/myGates_Barrier/gateParameters.h
@@ -0,0 +1,15 @@
+// MY GATES PARAMETERS
+
+#define NAVETTE_UUID "DEADDEAD-F88F-0042-F88F-010203040506"   // same UUID for all vehicles
+#define FORCEGATEOPEN 0b0100                                  // minor high bits = 0b01 => force gate to open
+#define CLEARGATECALIBRATION 0b1000                           // minor high bits = 0b10 => disable BLE scan and upload software
+#define OTASWUPDATE 0b1100                                    // minor high bits = 0b11 => clear gate calibration
+
+#define OTA_EXIT_AFTER 60*5             // after X sec if the software is not updating, getting out of the mode STATE_OTA
+#define SCAN_TIME 1                   // scan period in second
+#define GO_TO_SCAN_STATE_DELAY 4      // if no frame was received during X sec, go to STATE_SCAN
+#define DELAY_REJECT_FRAME 3           // if the last frame was received more than X seconds ago, the average RSSI is not computed and returns an average RSSI of -100
+#define PULSE_DURATION 500            // pulse to open gate. duration in ms
+#define DELAY_BETWEEN_PULSE 5         // to keep the gate open emit a pulse every X seconds
+#define RSSI_THRESHOLD_OPEN_GATE -95  // if the average RSSI is above this threshold the gate can be open
+#define SERIAL_BAUDRATE 115200
diff --git a/myGates/myGates_Barrier/myGates_Barrier.ino b/myGates/myGates_Barrier/myGates_Barrier.ino
new file mode 100644
index 0000000000000000000000000000000000000000..fea8c60fd07777f214ac6d31632205369069ed27
--- /dev/null
+++ b/myGates/myGates_Barrier/myGates_Barrier.ino
@@ -0,0 +1,410 @@
+/*******************************/
+/*********** INCLUDES***********/
+/*******************************/
+
+#include <Arduino.h>
+#include <ArduinoOTA.h>
+#include <WiFi.h>
+#include <BLEDevice.h>
+#include <BLEUtils.h>
+#include <BLEScan.h>
+#include <BLEAdvertisedDevice.h>
+#include <BLEBeacon.h>
+#include "sdkconfig.h"
+#include "esp_task_wdt.h"
+
+#include "gateParameters.h"
+#include "credentials.h"
+
+/*******************************/
+/********* DEFINITIONS *********/
+/*******************************/
+
+#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00) >> 8) + (((x)&0xFF) << 8))
+#define HIGH4BITS_U16(x) (((x)&0b1111000000000000) >> 12)
+#define RELAY1 32
+
+// State enumeration
+typedef enum {
+  STATE_SCAN = 0, /*STATE_SCAN : scanning iBeacon frame with UUID = NAVETTE_UUID. Opening door when the RSSI is high enough. Go to STATE_OPEN_GATE after opening the door.*/
+  STATE_OPEN_GATE, /*TATE_OPEN_GATE : door is open. Keep the door open while receiving frame. Go to STATE_SCAN when not receiving frame after GO_TO_SCAN_STATE_DELAY*/
+  STATE_OTA /*STATE_OTA : disable BLE and start uploading software with Wifi*/
+} MACHINE_STATE;
+
+MACHINE_STATE STATE;     /*state of the system : can be either STATE_SCAN or STATE_OPEN_GATE or STATE_OTA*/
+
+// Time related definition
+time_t t;           /*time is seconds*/
+time_t timerOTA;    /*time OTA software update started*/
+time_t tPulseGate = 0;  /*time last Pulse to open gate*/
+
+struct InfoBeacon {  /*structure contening received beacon RSSI and time*/
+  int rssi = -100;
+  time_t time = 0;
+} tabRecBeacon[3]; /*info of the last 3 received frames. Used to compute the average RSSI.*/
+
+bool BLEScanActivated = false;
+
+/*****************************/
+/********* FONCTIONS *********/
+/*****************************/
+
+// set up Serial Port
+void setupSerial() {
+#ifdef SERIAL_BAUDRATE
+  delay(3000);                    /*time for USB serial link to come up anew*/
+  Serial.begin(SERIAL_BAUDRATE);  /*start serial for output*/
+  Serial.setDebugOutput(true);
+#endif
+}
+
+// compute WiFi AP name
+const char *getAPname( void ) {
+  uint8_t macAddr[6];
+  static char _apName[16] = "";
+  if( !strlen(_apName) ) {
+    WiFi.macAddress(macAddr); /*get MAC address*/
+    snprintf(_apName,sizeof(_apName),"GATE_%02X%02X",macAddr[4],macAddr[5]);
+  }
+  return (const char*)_apName;
+}
+
+// set up WiFi AP
+void setUpWifiAP() {
+  WiFi.mode(WIFI_AP);
+  WiFi.softAP(getAPname(), password);
+}
+
+// set up Wdtifor BLE scan_evt timeout error
+void setupWdtBLE(){
+  esp_task_wdt_init(10, true); /*enable panic so ESP32 restarts, interrupt when task executed for more than 10 seconds*/
+  esp_task_wdt_add(NULL); /*add current thread to WDT watch*/
+}
+
+// set up On The Air software upload
+void setupOTA() {
+  // Port defaults to 3232
+  ArduinoOTA.setPort(3232);
+  // Hostname
+  ArduinoOTA.setHostname(ssid);
+  // Authentication
+  ArduinoOTA.setPassword(password);
+
+  ArduinoOTA.onStart([]() {
+    String type;
+    if (ArduinoOTA.getCommand() == U_FLASH)
+      type = "sketch";
+    else  /*U_SPIFFS*/
+      type = "filesystem";
+
+    /*NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()*/
+    Serial.println("Start updating " + type);
+  });
+  ArduinoOTA.onEnd([]() {
+    Serial.println("\nEnd");
+    STATE = STATE_SCAN;
+  });
+  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
+    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
+  });
+  ArduinoOTA.onError([](ota_error_t error) {
+    Serial.printf("Error[%u]: ", error);
+    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
+    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
+    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
+    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
+    else if (error == OTA_END_ERROR) Serial.println("End Failed");
+  });
+}
+
+// open gate
+void openGate() {
+  Serial.printf("OPENING GATE\n"); /*DEBUG*/
+  digitalWrite(RELAY1, HIGH); /*activate relay1 for 0.5 sec*/
+  delay(PULSE_DURATION);
+  digitalWrite(RELAY1, LOW);
+  time(&tPulseGate); /*save time of the last pulse*/
+}
+
+// update Beacon RSSI table
+void updateBeaconTab(InfoBeacon newBeacon) { /*save RSSI and time in the table tabRecBeacon*/
+  tabRecBeacon[2] = tabRecBeacon[1];
+  tabRecBeacon[1] = tabRecBeacon[0];
+  tabRecBeacon[0] = newBeacon;
+}
+
+// compute average RSSI
+int averageRSSI() {
+  time(&t); // get time
+  if (difftime(t,tabRecBeacon[2].time) > DELAY_REJECT_FRAME) {  /*if last frames were received more than x sec ago, return an average RSSI of -100*/
+    return -100;
+  } else {
+    int avRSSI = (tabRecBeacon[2].rssi + tabRecBeacon[1].rssi + tabRecBeacon[0].rssi) / 3;  /*compute the average RSSI using the last 3 RSSI values*/
+    return avRSSI;
+  }
+}
+
+class IBeaconAdvertised : public BLEAdvertisedDeviceCallbacks {
+  public:
+
+    // BLE on result
+    void onResult(BLEAdvertisedDevice device) {
+      /*check if iBeacon frame*/
+      if (!isIBeacon(device)) {
+        return;
+      }
+
+      /*check for NAVETTE_UUID*/
+      if (!isNavetteUUID(device)) {
+        return;
+      }
+
+      /*received a frame FORCE GATE OPEN*/
+      if (HIGH4BITS_U16(getMinor(device)) == FORCEGATEOPEN) {
+        Serial.printf("FORCE OPEN FRAME "); /*DEBUG*/
+        openGate();
+        return;
+      }
+
+      /*received a FRAME OTA Software Update*/
+      if (HIGH4BITS_U16(getMinor(device)) == OTASWUPDATE) {
+        time(&timerOTA); /*save OTA start time */
+        Serial.printf("OTA SOFTWARE UPDATING MODE \n"); /*DEBUG*/
+        STATE = STATE_OTA;
+        return;
+      }
+
+      InfoBeacon newBeacon = saveBeaconInfo(device); /*get received Beacon info*/
+      updateBeaconTab(newBeacon); /*save received frame RSSI in the table*/
+      printIBeacon(device); /*DEBUG*/
+    }
+
+  private:
+
+    // is frame iBeacon ?
+    bool isIBeacon(BLEAdvertisedDevice device) {
+      if (device.getManufacturerData().length() < 25) {
+        return false;
+      }
+      if (getCompanyId(device) != 0x004C) {
+        return false;
+      }
+      if (getIBeaconHeader(device) != 0x1502) {
+        return false;
+      }
+      return true;
+    }
+
+    // is UUID_NAVETTE ?
+    bool isNavetteUUID(BLEAdvertisedDevice device) { /*check if iBeacon frame UUID = NAVETTE_UUID*/
+      if (getProxyUuid(device).equals(BLEUUID(NAVETTE_UUID))) {
+        return true;
+      } else {
+        return false;
+      }
+    }
+
+    // save RSSI info
+    InfoBeacon saveBeaconInfo(BLEAdvertisedDevice device) { /*get signal RSSI and reception time*/
+      InfoBeacon newBeacon;
+      time(&t);
+      newBeacon.rssi = device.getRSSI();
+      newBeacon.time = t;
+      return newBeacon;
+    }
+
+    // get companyId
+    unsigned short getCompanyId(BLEAdvertisedDevice device) {
+      const unsigned short *pCompanyId = (const unsigned short *)&device
+                                         .getManufacturerData()
+                                         .c_str()[0];
+      return *pCompanyId;
+    }
+
+    // get iBeacon Header
+    unsigned short getIBeaconHeader(BLEAdvertisedDevice device) {
+      const unsigned short *pHeader = (const unsigned short *)&device
+                                      .getManufacturerData()
+                                      .c_str()[2];
+      return *pHeader;
+    }
+
+    // get iBEACON UUID
+    BLEUUID getProxyUuid(BLEAdvertisedDevice device) {
+      BLEUUID uuid;
+      std::string strManufacturerData = device.getManufacturerData();
+      uint8_t cManufacturerData[100];
+      strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
+      BLEBeacon oBeacon = BLEBeacon();
+      oBeacon.setData(strManufacturerData);
+      uuid = oBeacon.getProximityUUID();
+      return uuid;
+    }
+
+    // BEACON Major 
+    uint16_t getMajor(BLEAdvertisedDevice device) {
+      std::string strManufacturerData = device.getManufacturerData();
+      uint8_t cManufacturerData[100];
+      strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
+      BLEBeacon oBeacon = BLEBeacon();
+      oBeacon.setData(strManufacturerData);
+      return ENDIAN_CHANGE_U16(oBeacon.getMajor());
+    }
+
+    // iBEACON Minor
+    uint16_t getMinor(BLEAdvertisedDevice device) {
+      std::string strManufacturerData = device.getManufacturerData();
+      uint8_t cManufacturerData[100];
+      strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
+      BLEBeacon oBeacon = BLEBeacon();
+      oBeacon.setData(strManufacturerData);
+      return ENDIAN_CHANGE_U16(oBeacon.getMinor());
+    }
+
+    // iBEACON TxPower
+    int8_t getTxPower(BLEAdvertisedDevice device) {
+      std::string strManufacturerData = device.getManufacturerData();
+      uint8_t cManufacturerData[100];
+      strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
+      BLEBeacon oBeacon = BLEBeacon();
+      oBeacon.setData(strManufacturerData);
+      return oBeacon.getSignalPower();
+    }
+
+    // print iBeacon device info
+    void printIBeacon(BLEAdvertisedDevice device) {
+      time(&t);
+      Serial.printf("name:%s uuid:%s major:%d minor:%d rssi:%d, avRSSI:%d \r\n",
+                    device.getName().c_str(),
+                    getProxyUuid(device).toString().c_str(),
+                    getMajor(device),
+                    getMinor(device),
+                    device.getRSSI(),
+                    averageRSSI());
+    }
+};
+
+// manage gate opening 
+void manageGateOpening() {
+  switch (STATE) { /*check gate state*/
+
+    case STATE_OPEN_GATE:
+      if (difftime(t,tPulseGate) > DELAY_BETWEEN_PULSE) { /*end a pulse to keep the gate open every X=DELAY_BETWEEN_PULSE sec*/
+        openGate();
+      }
+      break;
+
+    case STATE_OTA :
+    case STATE_SCAN:
+    default:
+      /*do not open gate*/
+      break; /*end case STATE_SCAN*/
+  }
+}
+
+// manage gate state
+void manageState()
+{
+  time(&t); /*get time*/
+
+  switch (STATE) { /*check gate state*/
+
+    case STATE_OTA :
+      if (difftime(t,timerOTA) > OTA_EXIT_AFTER) {
+        STATE = STATE_SCAN; /*go to STATE_SCAN*/
+        setupWdtBLE(); /*setup Wdt for BLE*/
+        Serial.printf("GO TO STATE_SCAN\n"); /*DEBUG*/
+      }
+      break;/*end case STATE_OTA*/
+
+    case STATE_OPEN_GATE:
+      if (difftime(t,tabRecBeacon[0].time) > GO_TO_SCAN_STATE_DELAY) {  /*f last frame was received more than x seconds ago (GO_TO_SCAN_STATE_DELAY)*/
+        STATE = STATE_SCAN; /*go to STATE_SCAN*/
+        Serial.printf("GO TO STATE_SCAN\n"); /*DEBUG*/
+      }
+      break; /*end case STATE_OPEN_GATE*/
+
+    case STATE_SCAN:
+      int avRSSI = averageRSSI(); /*compute average RSSI (with 3 last values)*/
+      if (avRSSI > RSSI_THRESHOLD_OPEN_GATE) {  /*if the received signal power is above the threshold RSSI_THRESHOLD_OPEN_GATE*/
+        STATE = STATE_OPEN_GATE;  /*change state and go to state STATE_OPEN_GATE*/
+        Serial.printf("GO TO STATE_OPEN_GATE\n"); /*DEBUG*/
+      } else {
+        /*RSSI is too low*/
+      }
+      break; /*end case STATE_SCAN*/
+  }
+}
+
+// start BLE scan
+void startScanBLE() {
+  BLEScan* pBLEScan = BLEDevice::getScan(); // start scanning
+  pBLEScan->setAdvertisedDeviceCallbacks(new IBeaconAdvertised(), true);
+  pBLEScan->setActiveScan(true);
+  pBLEScan->start(SCAN_TIME, scanCompleteCB);
+  BLEScanActivated = true;
+}
+
+// scan complete Call Back 
+/* Callback invoked when scanning has completed */
+static void scanCompleteCB(BLEScanResults scanResults) { 
+  BLEScanActivated = false;
+}
+
+// manage BLE scan
+void manageBLEscan() {
+  switch (STATE) { /*check gate state*/
+
+    case STATE_OTA :
+      /*do not restart BLE scan*/
+      esp_task_wdt_delete(NULL); /*disable watchdog timer for BLE*/
+      break;
+
+    case STATE_OPEN_GATE:
+    case STATE_SCAN:
+    default:
+      if (!BLEScanActivated)
+        startScanBLE(); /*start scanning*/
+        esp_task_wdt_reset(); /*reset the watchdog timer*/
+      break;
+  }
+}
+
+// setup
+void setup() {
+  /*init serial port*/
+  setupSerial();
+
+  /*init relay module*/
+  pinMode(RELAY1, OUTPUT);
+  
+  /*setup WiFi as Access Point*/
+  setUpWifiAP();
+
+  /*setup OTA*/
+  setupOTA();
+  ArduinoOTA.begin();
+  
+  /*init BLE*/
+  BLEDevice::init("");
+
+  /*init state*/
+  STATE = STATE_SCAN;
+
+  /*setup Wdt for BLE*/
+  setupWdtBLE(); 
+  
+  /*print ready*/
+  Serial.println();
+  Serial.println("Ready");
+  Serial.println();
+}
+
+// loop
+void loop() {
+  ArduinoOTA.handle();
+  manageState();
+  manageGateOpening();
+  manageBLEscan();
+  delay(100);
+}
diff --git a/myGates/myGates_Vehicle/myGates_Vehicle.ino b/myGates/myGates_Vehicle/myGates_Vehicle.ino
new file mode 100644
index 0000000000000000000000000000000000000000..41fc56873c92f594d2c141109de16d4041baf277
--- /dev/null
+++ b/myGates/myGates_Vehicle/myGates_Vehicle.ino
@@ -0,0 +1,125 @@
+#include <M5StickCPlus.h>
+#include "BLEDevice.h"
+#include "BLEUtils.h"
+#include "BLEBeacon.h"
+
+#define ADVERTISMENT_INTERVAL     500  //(ms) advertise every 0.5 second
+#define ADVERTISMENT_DURATION     100  //(ms)
+#define BEACON_UUID               "DEADDEAD-F88F-0042-F88F-010203040506" //same UUID for all vehicles
+#define UT3_AUTONOMOUS_VEHICLE    0x0042
+#define EASYMILE_EZ10             0x0000
+#define FORCE_GATE_OPEN           0b0100000000000000
+#define OTA_SW_UPDATE             0b1100000000000000
+#define CLEAR_GATE_CALIBRATION    0b1000000000000000
+#define TX_POWER                  ESP_PWR_LVL_N14
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+BLEAdvertising *pAdvertising; // BLE Advertisement type
+
+bool send_force_gate_frame = false;
+bool send_OTA_update_frame = false;
+uint16_t MAJOR;
+uint16_t MINOR;
+
+void setBeacon() {
+  //configure ibeacon data
+  MAJOR = UT3_AUTONOMOUS_VEHICLE;
+  MINOR = EASYMILE_EZ10;
+  
+  if(send_force_gate_frame){ // if button A was pressed, send FORCE_GATE_OPEN trame
+    MINOR = (MINOR | FORCE_GATE_OPEN);
+    send_force_gate_frame = false;
+    Serial.println("forcing gate to open");
+  }
+  if(send_OTA_update_frame){ // if button B was pressed, send FORCE_GATE_OPEN trame
+   MINOR = (MINOR | OTA_SW_UPDATE);
+   send_OTA_update_frame = false;
+   Serial.println("starting On The Air software update");
+  }
+
+  
+  BLEBeacon oBeacon = BLEBeacon();
+  oBeacon.setManufacturerId(0x4C00); // fake Apple 0x004C LSB (ENDIAN_CHANGE_U16!)
+  oBeacon.setProximityUUID(BLEUUID(BEACON_UUID));
+  oBeacon.setMajor(MAJOR);
+  oBeacon.setMinor(MINOR);
+  oBeacon.setSignalPower(TX_POWER);
+  BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
+  BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
+
+  oAdvertisementData.setFlags(0x04);
+
+  std::string strServiceData = "";
+
+  strServiceData += (char)26;     // Len
+  strServiceData += (char)0xFF;   // Type
+  strServiceData += oBeacon.getData(); 
+  oAdvertisementData.addData(strServiceData);
+
+  pAdvertising->setAdvertisementData(oAdvertisementData);
+  pAdvertising->setScanResponseData(oScanResponseData);
+
+}
+#define LED 10
+
+void setup() {
+  pinMode(LED, OUTPUT);
+  pinMode(M5_BUTTON_HOME, INPUT_PULLUP);
+  digitalWrite(LED, HIGH);
+  M5.begin();
+  M5.Lcd.setRotation(1);
+  M5.Lcd.fillScreen(BLACK);
+
+  M5.Lcd.setCursor(2, 0, 2);
+  M5.Lcd.printf("UUID: %s",BEACON_UUID);
+ /* M5.Lcd.setCursor(2, 40, 2);
+  M5.Lcd.printf("Major %d Minor %d",MAJOR ,MINOR);  */
+
+  Serial.begin(115200);
+
+  // Create the BLE Device
+  BLEDevice::init("navette neOCampus");
+  pAdvertising = BLEDevice::getAdvertising();
+
+  // Increase TX POWER
+  //BLEDevice::setPower(TX_POWER);
+  esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, TX_POWER);
+  esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, TX_POWER);
+
+    // Create the BLE Server
+  BLEServer *pServer = BLEDevice::createServer();
+  pAdvertising = BLEDevice::getAdvertising();
+  BLEDevice::startAdvertising();
+  
+  setBeacon();
+}
+
+void loop() {
+  M5.update();  // Read the press state of the key
+  if (M5.BtnA.wasReleased()) {  // If the button A is pressed
+    send_force_gate_frame = true;
+    Serial.println("button A was pressed");
+  }
+    if (M5.BtnB.wasReleasefor(5000)) {  // If the button B is pressed for 5sec
+    send_OTA_update_frame = true;
+    Serial.println("button B was pressed for 5 sec");
+  }
+  setBeacon();
+  pAdvertising->start();
+  digitalWrite(LED, LOW);  
+  Serial.printf("Advertizing started...\n");
+  delay(ADVERTISMENT_DURATION);
+  Serial.println("Advertizing stop...");
+  pAdvertising->stop();
+  digitalWrite(LED, HIGH);  
+  delay(ADVERTISMENT_INTERVAL - ADVERTISMENT_DURATION);
+}
diff --git a/tests/myGates_BLE_Beacon_Advertiser/myGates_BLE_Beacon_Advertiser.ino b/tests/myGates_BLE_Beacon_Advertiser/myGates_BLE_Beacon_Advertiser.ino
index f39fdf446662f0032cd494f52a4f47db750cccc6..41fc56873c92f594d2c141109de16d4041baf277 100644
--- a/tests/myGates_BLE_Beacon_Advertiser/myGates_BLE_Beacon_Advertiser.ino
+++ b/tests/myGates_BLE_Beacon_Advertiser/myGates_BLE_Beacon_Advertiser.ino
@@ -1,116 +1,125 @@
-/*
-   Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
-   Ported to Arduino ESP32 by pcbreflux
-
-   Create a BLE server that will send periodic iBeacon frames.
-   The design of creating the BLE server is:
-   1. Create a BLE Server
-   2. Create advertising data
-   3. Start advertising.
-   4. wait
-   5. Stop advertising.
-   6. deep sleep
-
-  TBC: Tx power changed ... check it works !
-   
-*/
-#include "sys/time.h"
-
+#include <M5StickCPlus.h>
 #include "BLEDevice.h"
 #include "BLEUtils.h"
 #include "BLEBeacon.h"
-#include "esp_sleep.h"
 
-#define GPIO_DEEP_SLEEP_DURATION     10  // sleep x seconds and then wake up
-RTC_DATA_ATTR static time_t last;        // remember last boot in RTC Memory
-RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory
+#define ADVERTISMENT_INTERVAL     500  //(ms) advertise every 0.5 second
+#define ADVERTISMENT_DURATION     100  //(ms)
+#define BEACON_UUID               "DEADDEAD-F88F-0042-F88F-010203040506" //same UUID for all vehicles
+#define UT3_AUTONOMOUS_VEHICLE    0x0042
+#define EASYMILE_EZ10             0x0000
+#define FORCE_GATE_OPEN           0b0100000000000000
+#define OTA_SW_UPDATE             0b1100000000000000
+#define CLEAR_GATE_CALIBRATION    0b1000000000000000
+#define TX_POWER                  ESP_PWR_LVL_N14
+
+
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-uint8_t temprature_sens_read();
-//uint8_t g_phyFuns;
-
 #ifdef __cplusplus
 }
 #endif
 
-// See the following for generating UUIDs:
-// https://www.uuidgenerator.net/
-BLEAdvertising *pAdvertising;
-struct timeval now;
+BLEAdvertising *pAdvertising; // BLE Advertisement type
 
-#define BEACON_UUID           "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/)
+bool send_force_gate_frame = false;
+bool send_OTA_update_frame = false;
+uint16_t MAJOR;
+uint16_t MINOR;
 
 void setBeacon() {
+  //configure ibeacon data
+  MAJOR = UT3_AUTONOMOUS_VEHICLE;
+  MINOR = EASYMILE_EZ10;
+  
+  if(send_force_gate_frame){ // if button A was pressed, send FORCE_GATE_OPEN trame
+    MINOR = (MINOR | FORCE_GATE_OPEN);
+    send_force_gate_frame = false;
+    Serial.println("forcing gate to open");
+  }
+  if(send_OTA_update_frame){ // if button B was pressed, send FORCE_GATE_OPEN trame
+   MINOR = (MINOR | OTA_SW_UPDATE);
+   send_OTA_update_frame = false;
+   Serial.println("starting On The Air software update");
+  }
 
+  
   BLEBeacon oBeacon = BLEBeacon();
   oBeacon.setManufacturerId(0x4C00); // fake Apple 0x004C LSB (ENDIAN_CHANGE_U16!)
   oBeacon.setProximityUUID(BLEUUID(BEACON_UUID));
-  oBeacon.setMajor((bootcount & 0xFFFF0000) >> 16);
-  oBeacon.setMinor(bootcount&0xFFFF);
-  // ### TODO: add oBeacon.Txpower ??
+  oBeacon.setMajor(MAJOR);
+  oBeacon.setMinor(MINOR);
+  oBeacon.setSignalPower(TX_POWER);
   BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
   BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
-  
-  oAdvertisementData.setFlags(0x04); // BR_EDR_NOT_SUPPORTED 0x04
-  
+
+  oAdvertisementData.setFlags(0x04);
+
   std::string strServiceData = "";
-  
+
   strServiceData += (char)26;     // Len
   strServiceData += (char)0xFF;   // Type
   strServiceData += oBeacon.getData(); 
   oAdvertisementData.addData(strServiceData);
-  
+
   pAdvertising->setAdvertisementData(oAdvertisementData);
   pAdvertising->setScanResponseData(oScanResponseData);
-  pAdvertising->setAdvertisementType(ADV_TYPE_NONCONN_IND);
 
 }
+#define LED 10
 
 void setup() {
-  delay(3000);  // time for USB serial link to come up anew
+  pinMode(LED, OUTPUT);
+  pinMode(M5_BUTTON_HOME, INPUT_PULLUP);
+  digitalWrite(LED, HIGH);
+  M5.begin();
+  M5.Lcd.setRotation(1);
+  M5.Lcd.fillScreen(BLACK);
+
+  M5.Lcd.setCursor(2, 0, 2);
+  M5.Lcd.printf("UUID: %s",BEACON_UUID);
+ /* M5.Lcd.setCursor(2, 40, 2);
+  M5.Lcd.printf("Major %d Minor %d",MAJOR ,MINOR);  */
 
   Serial.begin(115200);
-  gettimeofday(&now, NULL);
 
-  // Arduino libs v2.4.1, to enable printf and debug messages output
-  Serial.setDebugOutput( true );
-
-  Serial.printf("start ESP32 %d\n",bootcount++);
-
-  Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n",now.tv_sec,now.tv_sec-last);
-
-  last = now.tv_sec;
-  
   // Create the BLE Device
-  BLEDevice::init("");
-
-  // [sep.22] Increase TX POWER ?
-  BLEDevice::setPower(ESP_PWR_LVL_P9);
-  // or ...
-  esp_err_t errRc=esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT,ESP_PWR_LVL_P9);
-  esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, ESP_PWR_LVL_P9);
-  esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_SCAN ,ESP_PWR_LVL_P9);
-
-
+  BLEDevice::init("navette neOCampus");
+  pAdvertising = BLEDevice::getAdvertising();
 
-  // Create the BLE Server
-  // BLEServer *pServer = BLEDevice::createServer(); // <-- no longer required to instantiate BLEServer, less flash and ram usage
+  // Increase TX POWER
+  //BLEDevice::setPower(TX_POWER);
+  esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, TX_POWER);
+  esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, TX_POWER);
 
+    // Create the BLE Server
+  BLEServer *pServer = BLEDevice::createServer();
   pAdvertising = BLEDevice::getAdvertising();
+  BLEDevice::startAdvertising();
   
   setBeacon();
-   // Start advertising
-  pAdvertising->start();
-  Serial.println("Advertizing started...");
-  delay(100);
-  pAdvertising->stop();
-  Serial.printf("enter deep sleep\n");
-  esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
-  Serial.printf("in deep sleep\n");
 }
 
 void loop() {
+  M5.update();  // Read the press state of the key
+  if (M5.BtnA.wasReleased()) {  // If the button A is pressed
+    send_force_gate_frame = true;
+    Serial.println("button A was pressed");
+  }
+    if (M5.BtnB.wasReleasefor(5000)) {  // If the button B is pressed for 5sec
+    send_OTA_update_frame = true;
+    Serial.println("button B was pressed for 5 sec");
+  }
+  setBeacon();
+  pAdvertising->start();
+  digitalWrite(LED, LOW);  
+  Serial.printf("Advertizing started...\n");
+  delay(ADVERTISMENT_DURATION);
+  Serial.println("Advertizing stop...");
+  pAdvertising->stop();
+  digitalWrite(LED, HIGH);  
+  delay(ADVERTISMENT_INTERVAL - ADVERTISMENT_DURATION);
 }
diff --git a/tests/myGates_BLE_Beacon_Scanner/myGates_BLE_Beacon_Scanner.ino b/tests/myGates_BLE_Beacon_Scanner/myGates_BLE_Beacon_Scanner.ino
index 84cb47e1a14fd729042aa9cdcced53597063411c..41d81f99be1cb04e124880b1a0f86e2e0379e16a 100644
--- a/tests/myGates_BLE_Beacon_Scanner/myGates_BLE_Beacon_Scanner.ino
+++ b/tests/myGates_BLE_Beacon_Scanner/myGates_BLE_Beacon_Scanner.ino
@@ -1,170 +1,402 @@
-/*
-   Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
-   Ported to Arduino ESP32 by Evandro Copercini
-   Changed to a beacon scanner to report iBeacon, EddystoneURL and EddystoneTLM beacons by beegee-tokyo
-
-  TBC: Tx power changed ... check it works !
-
-*/
+/*******************************/
+/*********** INCLUDES***********/
+/*******************************/
 
 #include <Arduino.h>
-
+#include <ArduinoOTA.h>
+#include <WiFi.h>
 #include <BLEDevice.h>
 #include <BLEUtils.h>
 #include <BLEScan.h>
 #include <BLEAdvertisedDevice.h>
-#include <BLEEddystoneURL.h>
-#include <BLEEddystoneTLM.h>
 #include <BLEBeacon.h>
+#include <time.h>
+#include "sdkconfig.h"
+
+/*******************************/
+/********* DEFINITIONS *********/
+/*******************************/
 
 #define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00) >> 8) + (((x)&0xFF) << 8))
+#define HIGH4BITS_U16(x) (((x)&0b1111000000000000) >> 12)
 
-int scanTime = 5; //In seconds
-BLEScan *pBLEScan;
+#define RELAY1 32
 
-class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
-{
-    void onResult(BLEAdvertisedDevice advertisedDevice)
-    {
-      if (advertisedDevice.haveName())
-      {
-        Serial.print("Device name: ");
-        Serial.println(advertisedDevice.getName().c_str());
-        Serial.println("");
+#define NAVETTE_UUID "DEADDEAD-F88F-0042-F88F-010203040506"   // same UUID for all vehicles
+#define FORCEGATEOPEN 0b0100                                  // minor high bits = 0b01 => force gate to open
+#define CLEARGATECALIBRATION 0b1000                           // minor high bits = 0b10 => disable BLE scan and upload software
+#define OTASWUPDATE 0b1100                                    // minor high bits = 0b11 => clear gate calibration
+
+#define OTA_EXIT_AFTER 60*5             // after X sec if the software is not updating, getting out of the mode STATE_OTA
+#define SCAN_TIME 1                   // scan period in second
+#define GO_TO_SCAN_STATE_DELAY 4      // if no frame was received during X sec, go to STATE_SCAN
+#define DELAY_REJECT_FRAME 3           // if the last frame was received more than X seconds ago, the average RSSI is not computed and returns an average RSSI of -100
+#define PULSE_DURATION 500            // pulse to open gate. duration in ms
+#define DELAY_BETWEEN_PULSE 5         // to keep the gate open emit a pulse every X seconds
+#define RSSI_THRESHOLD_OPEN_GATE -95  // if the average RSSI is above this threshold the gate can be open
+#define SERIAL_BAUDRATE 115200
+
+// Wifi credentials
+const char *ssid = "Gate";
+const char *password = "neOCampus";
+
+//State enumeration
+typedef enum {
+  STATE_SCAN = 0, // STATE_SCAN : scanning iBeacon frame with UUID = NAVETTE_UUID. Opening door when the RSSI is high enough. Go to STATE_OPEN_GATE after opening the door.
+  STATE_OPEN_GATE, // STATE_OPEN_GATE : door is open. Keep the door open while receiving frame. Go to STATE_SCAN when not receiving frame after GO_TO_SCAN_STATE_DELAY
+  STATE_OTA // STATE_OTA : disable BLE and start uploading software with Wifi
+} MACHINE_STATE;
+
+MACHINE_STATE STATE;     // state of the system : can be either STATE_SCAN or STATE_OPEN_GATE or STATE_OTA
+
+//Time related definition
+time_t t;           // time is seconds
+time_t timerOTA;    // time OTA software update started
+time_t tPulseGate = 0;  // time last Pulse to open gate
+
+struct InfoBeacon {  // structure contening received beacon RSSI and time
+  int rssi = -100;
+  time_t time = 0;
+} tabRecBeacon[3]; // info of the last 3 received frames. Used to compute the average RSSI.
+
+bool BLEScanActivated = false;
+
+/*****************************/
+/********* FONCTIONS *********/
+/*****************************/
+
+// ***** set up Serial Port *****
+void setupSerial() {
+#ifdef SERIAL_BAUDRATE
+  delay(3000);                    // time for USB serial link to come up anew
+  Serial.begin(SERIAL_BAUDRATE);  // Start serial for output
+  Serial.setDebugOutput(true);
+#endif
+}
+
+// ***** set up WiFi AP*****
+void setUpWifiAP() {
+  WiFi.mode(WIFI_AP);
+  WiFi.softAP(ssid, password);
+}
+
+// ***** set up On The Air software upload *****
+void setupOTA() {
+  // Port defaults to 3232
+  ArduinoOTA.setPort(3232);
+  // Hostname
+  ArduinoOTA.setHostname(ssid);
+  // Authentication
+  ArduinoOTA.setPassword(password);
+
+  ArduinoOTA.onStart([]() {
+    String type;
+    if (ArduinoOTA.getCommand() == U_FLASH)
+      type = "sketch";
+    else  // U_SPIFFS
+      type = "filesystem";
+
+    // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
+    Serial.println("Start updating " + type);
+  });
+  ArduinoOTA.onEnd([]() {
+    Serial.println("\nEnd");
+    STATE = STATE_SCAN;
+  });
+  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
+    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
+  });
+  ArduinoOTA.onError([](ota_error_t error) {
+    Serial.printf("Error[%u]: ", error);
+    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
+    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
+    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
+    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
+    else if (error == OTA_END_ERROR) Serial.println("End Failed");
+  });
+}
+
+// ***** open gate *****
+void openGate() {
+  Serial.printf("OPENING GATE\n"); //DEBUG
+  digitalWrite(RELAY1, HIGH);       //activate relay1 for 0.5 sec
+  delay(PULSE_DURATION);
+  digitalWrite(RELAY1, LOW);
+  time(&tPulseGate);  // save time of the last pulse
+}
+
+// ***** update Beacon RSSI table *****
+void updateBeaconTab(InfoBeacon newBeacon) {  // save RSSI and time in the table tabRecBeacon
+  tabRecBeacon[2] = tabRecBeacon[1];
+  tabRecBeacon[1] = tabRecBeacon[0];
+  tabRecBeacon[0] = newBeacon;
+}
+
+// ***** compute average RSSI *****
+int averageRSSI() {
+  time(&t); // get time
+  if (difftime(t,tabRecBeacon[2].time) > DELAY_REJECT_FRAME) {  // if last frames were received more than x sec ago, return an average RSSI of -100
+    return -100;
+  } else {
+    int avRSSI = (tabRecBeacon[2].rssi + tabRecBeacon[1].rssi + tabRecBeacon[0].rssi) / 3;  // compute the average RSSI using the last 3 RSSI values
+    return avRSSI;
+  }
+}
+
+class IBeaconAdvertised : public BLEAdvertisedDeviceCallbacks {
+  public:
+
+    // BLE
+    void onResult(BLEAdvertisedDevice device) {
+      // check if iBeacon frame
+      if (!isIBeacon(device)) {
+        return;
       }
 
-      if (advertisedDevice.haveServiceUUID())
-      {
-        BLEUUID devUUID = advertisedDevice.getServiceUUID();
-        Serial.print("Found ServiceUUID: ");
-        Serial.println(devUUID.toString().c_str());
-        Serial.println("");
+      // check for NAVETTE_UUID
+      if (!isNavetteUUID(device)) {
+        return;
       }
-      else
-      {
-        if (advertisedDevice.haveManufacturerData() == true)
-        {
-          std::string strManufacturerData = advertisedDevice.getManufacturerData();
-
-          uint8_t cManufacturerData[100];
-          strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
-
-          if (strManufacturerData.length() == 25 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00)
-          {
-            Serial.println("Found an iBeacon!");
-            BLEBeacon oBeacon = BLEBeacon();
-            oBeacon.setData(strManufacturerData);
-            Serial.printf("iBeacon Frame\n");
-            Serial.printf("ID: %04X Major: %d Minor: %d UUID: %s Power: %d\n", oBeacon.getManufacturerId(), ENDIAN_CHANGE_U16(oBeacon.getMajor()), ENDIAN_CHANGE_U16(oBeacon.getMinor()), oBeacon.getProximityUUID().toString().c_str(), oBeacon.getSignalPower());
-          }
-          else
-          {
-            Serial.println("Found another manufacturers beacon!");
-            Serial.printf("strManufacturerData: %d ", strManufacturerData.length());
-            for (int i = 0; i < strManufacturerData.length(); i++)
-            {
-              Serial.printf("[%X]", cManufacturerData[i]);
-            }
-            Serial.printf("\n");
-          }
-        }
+
+      // received a frame FORCE GATE OPEN
+      if (HIGH4BITS_U16(getMinor(device)) == FORCEGATEOPEN) {
+        Serial.printf("FORCE OPEN FRAME ");   // DEBUG
+        openGate();
         return;
       }
 
-      uint8_t *payLoad = advertisedDevice.getPayload();
-
-      BLEUUID checkUrlUUID = (uint16_t)0xfeaa;
-
-      if (advertisedDevice.getServiceUUID().equals(checkUrlUUID))
-      {
-        if (payLoad[11] == 0x10)
-        {
-          Serial.println("Found an EddystoneURL beacon!");
-          BLEEddystoneURL foundEddyURL = BLEEddystoneURL();
-          std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
-
-          foundEddyURL.setData(eddyContent);
-          std::string bareURL = foundEddyURL.getURL();
-          if (bareURL[0] == 0x00)
-          {
-            size_t payLoadLen = advertisedDevice.getPayloadLength();
-            Serial.println("DATA-->");
-            for (int idx = 0; idx < payLoadLen; idx++)
-            {
-              Serial.printf("0x%08X ", payLoad[idx]);
-            }
-            Serial.println("\nInvalid Data");
-            return;
-          }
-
-          Serial.printf("Found URL: %s\n", foundEddyURL.getURL().c_str());
-          Serial.printf("Decoded URL: %s\n", foundEddyURL.getDecodedURL().c_str());
-          Serial.printf("TX power %d\n", foundEddyURL.getPower());
-          Serial.println("\n");
-        }
-        else if (payLoad[11] == 0x20)
-        {
-          Serial.println("Found an EddystoneTLM beacon!");
-          BLEEddystoneTLM foundEddyURL = BLEEddystoneTLM();
-          std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
-
-          eddyContent = "01234567890123";
-
-          for (int idx = 0; idx < 14; idx++)
-          {
-            eddyContent[idx] = payLoad[idx + 11];
-          }
-
-          foundEddyURL.setData(eddyContent);
-          Serial.printf("Reported battery voltage: %dmV\n", foundEddyURL.getVolt());
-          Serial.printf("Reported temperature from TLM class: %.2fC\n", (double)foundEddyURL.getTemp());
-          int temp = (int)payLoad[16] + (int)(payLoad[15] << 8);
-          float calcTemp = temp / 256.0f;
-          Serial.printf("Reported temperature from data: %.2fC\n", calcTemp);
-          Serial.printf("Reported advertise count: %d\n", foundEddyURL.getCount());
-          Serial.printf("Reported time since last reboot: %ds\n", foundEddyURL.getTime());
-          Serial.println("\n");
-          Serial.print(foundEddyURL.toString().c_str());
-          Serial.println("\n");
-        }
+      // received a FRAME OTA Software Update
+      if (HIGH4BITS_U16(getMinor(device)) == OTASWUPDATE) {
+        time(&timerOTA); // save OTA start time 
+        Serial.printf("OTA SOFTWARE UPDATING MODE \n");   // DEBUG
+        STATE = STATE_OTA;
+        return;
+      }
+
+      InfoBeacon newBeacon = saveBeaconInfo(device);   // get received Beacon info
+      updateBeaconTab(newBeacon);   // save received frame RSSI in the table
+      printIBeacon(device);    // DEBUG
+    }
+
+  private:
+
+    // ***** is frame iBeacon ? *****
+    bool isIBeacon(BLEAdvertisedDevice device) {
+      if (device.getManufacturerData().length() < 25) {
+        return false;
+      }
+      if (getCompanyId(device) != 0x004C) {
+        return false;
+      }
+      if (getIBeaconHeader(device) != 0x1502) {
+        return false;
       }
+      return true;
+    }
+
+    // ***** is UUID_NAVETTE ? *****
+    bool isNavetteUUID(BLEAdvertisedDevice device) {  // check if iBeacon frame UUID = NAVETTE_UUID
+      if (getProxyUuid(device).equals(BLEUUID(NAVETTE_UUID))) {
+        return true;
+      } else {
+        return false;
+      }
+    }
+
+    // ***** save RSSI info *****
+    InfoBeacon saveBeaconInfo(BLEAdvertisedDevice device) {  // get signal RSSI and reception time
+      InfoBeacon newBeacon;
+      time(&t);
+      newBeacon.rssi = device.getRSSI();
+      newBeacon.time = t;
+      return newBeacon;
+    }
+
+    // ***** get companyId *****
+    unsigned short getCompanyId(BLEAdvertisedDevice device) {
+      const unsigned short *pCompanyId = (const unsigned short *)&device
+                                         .getManufacturerData()
+                                         .c_str()[0];
+      return *pCompanyId;
+    }
+
+    // ***** get iBeacon Header *****
+    unsigned short getIBeaconHeader(BLEAdvertisedDevice device) {
+      const unsigned short *pHeader = (const unsigned short *)&device
+                                      .getManufacturerData()
+                                      .c_str()[2];
+      return *pHeader;
+    }
+
+    // ***** get iBEACON UUID *****
+    BLEUUID getProxyUuid(BLEAdvertisedDevice device) {
+      BLEUUID uuid;
+      std::string strManufacturerData = device.getManufacturerData();
+      uint8_t cManufacturerData[100];
+      strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
+      BLEBeacon oBeacon = BLEBeacon();
+      oBeacon.setData(strManufacturerData);
+      uuid = oBeacon.getProximityUUID();
+      return uuid;
+    }
+
+    // ***** iBEACON Major *****
+    uint16_t getMajor(BLEAdvertisedDevice device) {
+      std::string strManufacturerData = device.getManufacturerData();
+      uint8_t cManufacturerData[100];
+      strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
+      BLEBeacon oBeacon = BLEBeacon();
+      oBeacon.setData(strManufacturerData);
+      return ENDIAN_CHANGE_U16(oBeacon.getMajor());
+    }
+
+    // ***** iBEACON Minor *****
+    uint16_t getMinor(BLEAdvertisedDevice device) {
+      std::string strManufacturerData = device.getManufacturerData();
+      uint8_t cManufacturerData[100];
+      strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
+      BLEBeacon oBeacon = BLEBeacon();
+      oBeacon.setData(strManufacturerData);
+      return ENDIAN_CHANGE_U16(oBeacon.getMinor());
+    }
+
+    // ***** iBEACON TxPower *****
+    int8_t getTxPower(BLEAdvertisedDevice device) {
+      std::string strManufacturerData = device.getManufacturerData();
+      uint8_t cManufacturerData[100];
+      strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
+      BLEBeacon oBeacon = BLEBeacon();
+      oBeacon.setData(strManufacturerData);
+      return oBeacon.getSignalPower();
+    }
+
+    // ***** print iBeacon device info *****
+    void printIBeacon(BLEAdvertisedDevice device) {
+      // char buf[512];
+      // memset(buf,0, sizeof (buf));
+      // strncpy(buf, msg, (sizeof msg)-1);
+      time(&t);
+      Serial.printf("name:%s uuid:%s major:%d minor:%d rssi:%d, avRSSI:%d \r\n",
+                    device.getName().c_str(),
+                    getProxyUuid(device).toString().c_str(),
+                    getMajor(device),
+                    getMinor(device),
+                    device.getRSSI(),
+                    averageRSSI());
     }
 };
 
-void setup()
+// ***** manage gate Opening  *****
+void manageGateOpening() {
+  switch (STATE) { //check gate state
+
+    case STATE_OPEN_GATE:
+      if (difftime(t,tPulseGate) > DELAY_BETWEEN_PULSE) {  // send a pulse to keep the gate open every X=DELAY_BETWEEN_PULSE sec
+        openGate();
+      }
+      break;
+
+    case STATE_OTA :
+    case STATE_SCAN:
+    default:
+      // do not open gate
+      break; //end case STATE_SCAN
+  }
+}
+
+// ***** manage gate state  *****
+void manageState()
 {
-  delay(3000);  // time for USB serial link to come up anew
+  time(&t); // get time
+
+  switch (STATE) { //check gate state
+
+    case STATE_OTA :
+      if (difftime(t,timerOTA) > OTA_EXIT_AFTER) {
+        STATE = STATE_SCAN; // go to STATE_SCAN
+        Serial.printf("GO TO STATE_SCAN\n"); // DEBUG
+      }
+      break;//end case STATE_OTA
+
+    case STATE_OPEN_GATE:
+      if (difftime(t,tabRecBeacon[0].time) > GO_TO_SCAN_STATE_DELAY) {  // if last frame was received more than x seconds ago (GO_TO_SCAN_STATE_DELAY)
+        STATE = STATE_SCAN; // go to STATE_SCAN
+        Serial.printf("GO TO STATE_SCAN\n"); // DEBUG
+      }
+      break; //end case STATE_OPEN_GATE
+
+    case STATE_SCAN:
+      int avRSSI = averageRSSI(); // compute average RSSI (with 3 last values)
+      if (avRSSI > RSSI_THRESHOLD_OPEN_GATE) {  // if the received signal power is above the threshold RSSI_THRESHOLD_OPEN_GATE
+        STATE = STATE_OPEN_GATE;  // change state and go to state STATE_OPEN_GATE
+        Serial.printf("GO TO STATE_OPEN_GATE\n"); // DEBUG
+      } else {
+        // RSSI is too low
+      }
+      break; //end case STATE_SCAN
+  }
+}
+
+// ***** start BLE scan  *****
+void startScanBLE() {
+  BLEScan* pBLEScan = BLEDevice::getScan(); // start scanning
+  pBLEScan->setAdvertisedDeviceCallbacks(new IBeaconAdvertised(), true);
+  pBLEScan->setActiveScan(true);
+  pBLEScan->start(SCAN_TIME, scanCompleteCB);
+  BLEScanActivated = true;
+}
+
+// ***** scan Complete Call Back  *****
+static void scanCompleteCB(BLEScanResults scanResults) { // Callback invoked when scanning has completed
+  BLEScanActivated = false;
+}
+
+// ***** manage BLE scan  *****
+void manageBLEscan() {
+  switch (STATE) { //check gate state
+
+    case STATE_OTA :
+      // do not restart BLE scan
+      break;//end case STATE_OTA
 
-  Serial.begin(115200);
+    case STATE_OPEN_GATE:
+    case STATE_SCAN:
+    default:
+      if (!BLEScanActivated)
+        startScanBLE(); // start scanning
+      break; //end case STATE_SCAN
+  }
+}
+
+void setup() {
+  //init serial port
+  setupSerial();
+
+  //init relay module
+  pinMode(RELAY1, OUTPUT);
 
-  // Arduino libs v2.4.1, to enable printf and debug messages output
-  Serial.setDebugOutput( true );
+  //setup WiFi as Access Point
+  setUpWifiAP();
 
-  Serial.println("Scanning...");
+  //setup OTA
+  setupOTA();
+  ArduinoOTA.begin();
 
+  //init BLE
   BLEDevice::init("");
 
-  // [sep.22] Increase TX POWER ?
-  BLEDevice::setPower(ESP_PWR_LVL_P9);
-  // or ...
-  esp_err_t errRc=esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT,ESP_PWR_LVL_P9);
-  esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, ESP_PWR_LVL_P9);
-  esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_SCAN ,ESP_PWR_LVL_P9);
-
-  pBLEScan = BLEDevice::getScan(); //create new scan
-  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
-  pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
-  pBLEScan->setInterval(100);
-  pBLEScan->setWindow(99); // less or equal setInterval value
+  //init state
+  STATE = STATE_SCAN;
+
+  Serial.println();
+  Serial.println("Ready");
+  Serial.println();
 }
 
-void loop()
-{
-  // put your main code here, to run repeatedly:
-  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
-  Serial.print("Devices found: ");
-  Serial.println(foundDevices.getCount());
-  Serial.println("Scan done!");
-  pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
-  delay(2000);
+void loop() {
+  ArduinoOTA.handle();
+  manageState();
+  manageGateOpening();
+  manageBLEscan();
+  delay(100);
 }