Skip to content
Snippets Groups Projects
Commit e8d1b6c2 authored by Marie Bureau's avatar Marie Bureau
Browse files

move to folder myGates and add wdt for BLE

parent 4d894d92
No related branches found
No related tags found
1 merge request!4My gates ble
GATE 4 : 34:94:54:5A:2B:94
// Wifi and OTA credentials
const char *ssid = "Gate";
const char *password = "neOCampus";
// 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
/*******************************/
/*********** 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);
}
#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);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment