Skip to content
Snippets Groups Projects
Commit 986c7c74 authored by Manon MALIQUE's avatar Manon MALIQUE
Browse files

Merge branch 'feature-calibration' of...

Merge branch 'feature-calibration' of gitlab.irit.fr:gis-neocampus/neosensor/neOCampus-arduino into feature-calibration
parents 58d50f87 a0e59a06
Branches
No related tags found
No related merge requests found
#
# neOCampus operation
# Note: 'UNPUBLISHED' means the release may have been installed on some
# devices BUT not set as globally available for firmware upgrades
# devices BUT not set as globally available for firmware upgrades
# (c) neOCampus / F.Thiebolt Université Toulouse3, Laboratoire IRIT
=== Upcoming release / feature-calibration
The main goal is to maje use of a BLE enabled ambiant sensor and to get at latest
two different measures points to compute the y= Ax + B parameters to achieve
correction of non calibrated sensors.
Bumps to esp32 2.0.14
The main goal is to make use of a BLE enabled ambiant sensor to provide our
our neOSensors two different measures points to compute the y= Ax + B
parameters to achieve correction of uncalibrated sensors.
Kept esp32 2.0.14
Kept esp8266 3.1.2
- added status mode with additional functionnalities set @boot time:
press CLR 5s --> format SPIFFS (standard behaviour)
press CLR,SW+ for 5s --> format SPIFFS and CLEAR NVS namespaces
press SW+,SW- for 5s --> enter calibration mode
- to be continued
press CLR for 5s --> format SPIFFS (standard behaviour)
press CLR,SW+ for 5s --> format SPIFFS and CLEAR NVS namespaces
press SW+,SW- for 5s --> enter calibration mode
press SW- for 5s --> enter validation mode (no WiFi nor BLE nor ...)
Note 'validation mode': ensure to already have the whole neOSensor configuration (especially for analog sensors)
Roughly seaking, 'validation' mode is just about displaying the 'sharedRoot' json on serial link
The 'sharedRoot' structure holds all of the sensors values our neOSensor features.
=== Release 231216 for esp32 only (Arduino Core ESP32 2.0.14) /
feature-calibration
......@@ -41,7 +44,7 @@ Bumps to esp8266 3.1.2
- switch WiFi to both 802.11b AND 802.11g (DSI cut down 802.11b !!)
- esp8266 now features a configTzTime() that unifies NTP setup for both ESPs
- NVS WiFinamespace to save WiFi credentials (in order to avoid SPIFFS
partitionning issues)
partitionning issues)
- NVS SENSOnamespace to sensOCampus credentials (MQTT creds)
- recompiled lwip for NTP server support from DHCP answer (IDF 4.4.4)
......@@ -57,7 +60,7 @@ Bumps to esp32 2.0.6
Bumps to esp8266 3.1.0
- force 802.11b for both ESP8266 and ESP32 --> solved our DHCP issues :D
- WARNING: breaks SPIFFS format@ESP32 ==> reformat @ reboot ==> per device setup :'(
(hopefully) no SPIFFS format change @ ESP8266
(hopefully) no SPIFFS format change @ ESP8266
- WiFiManager 2.0.15-rc1 no debug --> revert to 2.0.14-beta
- newer WiFiManager introduces ASYNC SCAN ==> very slow (almost unanswered)
[esp32]
......@@ -91,21 +94,21 @@ to connect to WiFi gateway
===
=== Changes prior to 2022
* F.Thiebolt nov.21 corrected timezone definition for esp32
* added support for various serial sensors like PMSx003, SDS011 and IKEA Vindriktning :D
* added support for digital inputs (PIR & switches)
* introduced the cooldown approach and data integration
* ... means that we'll only send data when they differ from the previously sent
* added support for various serial sensors like PMSx003, SDS011 and IKEA Vindriktning :D
* added support for digital inputs (PIR & switches)
* introduced the cooldown approach and data integration
* ... means that we'll only send data when they differ from the previously sent
* F.Thiebolt sep.21 added display module support (e.g oled or 7segment displays)
* F.Thiebolt aug.21 started digital inputs support (e.g PIR sensor)
* added support for shared JSON document for data exchange
* between modules
* F.Thiebolt apr.21 added support for 3 NTP servers + NTP from DHCP to lwip
* Have a look to `arduinoIDE_esp32_boards/README.md`
* F.Thiebolt apr.21 added support for 3 NTP servers + NTP from DHCP to lwip
* Have a look to `arduinoIDE_esp32_boards/README.md`
* F.Thiebolt aug.20 initial port from neOSensor based on ESP8266
* added esp32 adc calibration support
* setupNTP called AFTER network setup
* new definition board for neOSensor-AirQuality board
* added definition board for (future) neOSensor esp32 based board\
* added suppport for boards configuration via sensOCampus JSON config\
* added Arduino IDE support for our various neOSensor boards
* new definition board for neOSensor-AirQuality board
* added definition board for (future) neOSensor esp32 based board\
* added suppport for boards configuration via sensOCampus JSON config\
* added Arduino IDE support for our various neOSensor boards
......@@ -25,7 +25,7 @@ First of all, you ought to install esp32, esp8266 or CubeCell support in your Ar
| Device | Release | Arduino Board Manager json file |
|----------|-----------|------------------------------------------------------------------------------------------------------------|
| esp8266 | 3.1.2 | https://arduino.esp8266.com/stable/package_esp8266com_index.json |
| esp32 | 2.0.11 | https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json |
| esp32 | 2.0.14 | https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json |
| CubeCell | *latest* | https://github.com/HelTecAutomation/CubeCell-Arduino/releases/download/V1.3.0/package_CubeCell_index.json |
| stm32 | *latest* | https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json |
......
......@@ -8,6 +8,9 @@ neOSensor.bootloader.tool=esptool_py
neOSensor.bootloader.tool.default=esptool_py
neOSensor.upload.tool=esptool_py
neOSensor.upload.tool.default=esptool_py
neOSensor.upload.tool.network=esp_ota
neOSensor.upload.maximum_size=1310720
neOSensor.upload.maximum_data_size=327680
neOSensor.upload.wait_for_upload_port=true
......@@ -83,6 +86,9 @@ neOSensor-airquality.bootloader.tool=esptool_py
neOSensor-airquality.bootloader.tool.default=esptool_py
neOSensor-airquality.upload.tool=esptool_py
neOSensor-airquality.upload.tool.default=esptool_py
neOSensor-airquality.upload.tool.network=esp_ota
neOSensor-airquality.upload.maximum_size=1310720
neOSensor-airquality.upload.maximum_data_size=327680
neOSensor-airquality.upload.wait_for_upload_port=true
......
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);
}
/*
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);
}
/*
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);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment