mirror of https://github.com/arendst/Tasmota.git
Initial support for iBeacons (Sensor52) on ESP32 using internal BLE module.
Differs from MI32 (Sensor62): - Dynamically detects beacons, no preset MACs needed - Reports detected beacon immediately, not on tele period.
This commit is contained in:
parent
bdbe1f9ec2
commit
18fb79d954
|
@ -19,44 +19,13 @@
|
|||
|
||||
#ifdef USE_IBEACON
|
||||
|
||||
|
||||
|
||||
#define XSNS_52 52
|
||||
|
||||
#include <TasmotaSerial.h>
|
||||
|
||||
#define TMSBSIZ52 512
|
||||
|
||||
#define HM17_BAUDRATE 9600
|
||||
|
||||
#define IBEACON_DEBUG
|
||||
|
||||
// use this for Version 110
|
||||
#define HM17_V110
|
||||
|
||||
|
||||
// keyfob expires after N seconds
|
||||
#define IB_TIMEOUT_INTERVAL 30
|
||||
// does a passive scan every N seconds
|
||||
#define IB_UPDATE_TIME_INTERVAL 10
|
||||
|
||||
TasmotaSerial *IBEACON_Serial = nullptr;
|
||||
|
||||
|
||||
uint8_t hm17_found,hm17_cmd,hm17_flag;
|
||||
|
||||
#ifdef IBEACON_DEBUG
|
||||
uint8_t hm17_debug=0;
|
||||
#endif
|
||||
|
||||
|
||||
// 78 is max serial response
|
||||
#define HM17_BSIZ 128
|
||||
char hm17_sbuffer[HM17_BSIZ];
|
||||
uint8_t hm17_sindex,hm17_result,hm17_scanning,hm17_connecting;
|
||||
uint32_t hm17_lastms;
|
||||
char ib_mac[14];
|
||||
|
||||
// should be in Settings
|
||||
#if 1
|
||||
uint8_t ib_upd_interval,ib_tout_interval;
|
||||
|
@ -69,9 +38,71 @@ uint8_t ib_upd_interval,ib_tout_interval;
|
|||
#define IB_TIMEOUT_TIME Settings.ib_tout_interval
|
||||
#endif
|
||||
|
||||
char ib_mac[14];
|
||||
|
||||
#ifdef USE_IBEACON_ESP32
|
||||
|
||||
struct {
|
||||
union {
|
||||
struct {
|
||||
uint32_t init:1;
|
||||
uint32_t autoScan:1;
|
||||
uint32_t canScan:1;
|
||||
uint32_t runningScan:1;
|
||||
uint32_t shallClearResults:1; // BLE scan results
|
||||
uint32_t firstAutodiscoveryDone:1;
|
||||
uint32_t activeBeacon;
|
||||
};
|
||||
uint32_t all = 0;
|
||||
} mode;
|
||||
struct {
|
||||
uint8_t sensor; // points to to the number 0...255
|
||||
uint8_t beaconScanCounter; // countdown timer in seconds
|
||||
} state;
|
||||
} ESP32BLE;
|
||||
|
||||
#include <NimBLEDevice.h>
|
||||
#include <NimBLEAdvertisedDevice.h>
|
||||
#include "NimBLEEddystoneURL.h"
|
||||
#include "NimBLEEddystoneTLM.h"
|
||||
#include "NimBLEBeacon.h"
|
||||
|
||||
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00) >> 8) + (((x)&0xFF) << 8))
|
||||
|
||||
BLEScan *ESP32BLEScan;
|
||||
|
||||
#else
|
||||
|
||||
#include <TasmotaSerial.h>
|
||||
|
||||
#define TMSBSIZ52 512
|
||||
|
||||
#define HM17_BAUDRATE 9600
|
||||
|
||||
#define IBEACON_DEBUG
|
||||
|
||||
// use this for Version 110
|
||||
#define HM17_V110
|
||||
|
||||
TasmotaSerial *IBEACON_Serial = nullptr;
|
||||
|
||||
uint8_t hm17_found,hm17_cmd,hm17_flag;
|
||||
|
||||
#ifdef IBEACON_DEBUG
|
||||
uint8_t hm17_debug=0;
|
||||
#endif
|
||||
|
||||
// 78 is max serial response
|
||||
#define HM17_BSIZ 128
|
||||
char hm17_sbuffer[HM17_BSIZ];
|
||||
uint8_t hm17_sindex,hm17_result,hm17_scanning,hm17_connecting;
|
||||
uint32_t hm17_lastms;
|
||||
|
||||
enum {HM17_TEST,HM17_ROLE,HM17_IMME,HM17_DISI,HM17_IBEA,HM17_SCAN,HM17_DISC,HM17_RESET,HM17_RENEW,HM17_CON};
|
||||
#define HM17_SUCESS 99
|
||||
|
||||
#endif
|
||||
|
||||
struct IBEACON {
|
||||
char FACID[8];
|
||||
char UID[32];
|
||||
|
@ -82,7 +113,11 @@ struct IBEACON {
|
|||
char RSSI[4];
|
||||
};
|
||||
|
||||
#define MAX_IBEACONS 16
|
||||
#ifdef USE_IBEACON_ESP32
|
||||
#define MAX_IBEACONS 32
|
||||
#else
|
||||
#define MAX_IBEACONS 16
|
||||
#endif
|
||||
|
||||
struct IBEACON_UID {
|
||||
char MAC[12];
|
||||
|
@ -94,9 +129,154 @@ struct IBEACON_UID {
|
|||
uint8_t TIME;
|
||||
} ibeacons[MAX_IBEACONS];
|
||||
|
||||
#ifdef USE_IBEACON_ESP32
|
||||
|
||||
uint32_t ibeacon_add(struct IBEACON *ib);
|
||||
|
||||
void ESP32BLE_ReverseStr(uint8_t _mac[], uint8_t len=6){
|
||||
uint8_t _reversedMAC[len];
|
||||
for (uint8_t i=0; i<len; i++){
|
||||
_reversedMAC[len-1-i] = _mac[i];
|
||||
}
|
||||
memcpy(_mac,_reversedMAC, sizeof(_reversedMAC));
|
||||
}
|
||||
|
||||
void DumpHex(const unsigned char * in, size_t insz, char * out)
|
||||
{
|
||||
static const char * hex = "0123456789ABCDEF";
|
||||
const unsigned char * pin = in;
|
||||
char * pout = out;
|
||||
for (; pin < in+insz; pout+=2, pin++) {
|
||||
pout[0] = hex[(pgm_read_byte(pin)>>4) & 0xF];
|
||||
pout[1] = hex[ pgm_read_byte(pin) & 0xF];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ESP32BLEScanCallback : public BLEAdvertisedDeviceCallbacks
|
||||
{
|
||||
void onResult(BLEAdvertisedDevice *advertisedDevice)
|
||||
{
|
||||
struct IBEACON ib;
|
||||
ESP32BLEScan->erase(advertisedDevice->getAddress());
|
||||
if (advertisedDevice->haveManufacturerData() == true) {
|
||||
std::string strManufacturerData = advertisedDevice->getManufacturerData();
|
||||
|
||||
uint8_t cManufacturerData[100];
|
||||
strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
|
||||
|
||||
int16_t RSSI = advertisedDevice->getRSSI();
|
||||
char sRSSI[6];
|
||||
itoa(RSSI,sRSSI,10);
|
||||
|
||||
DumpHex(cManufacturerData,2,ib.FACID);
|
||||
|
||||
uint8_t MAC[6];
|
||||
memcpy(MAC,advertisedDevice->getAddress().getNative(),6);
|
||||
ESP32BLE_ReverseStr(MAC,6);
|
||||
|
||||
if (strManufacturerData.length() == 25 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00)
|
||||
{
|
||||
BLEBeacon oBeacon = BLEBeacon();
|
||||
oBeacon.setData(strManufacturerData);
|
||||
|
||||
uint8_t UUID[16];
|
||||
memcpy(UUID,oBeacon.getProximityUUID().getNative()->u128.value,16);
|
||||
ESP32BLE_ReverseStr(UUID,16);
|
||||
|
||||
uint16_t Major = ENDIAN_CHANGE_U16(oBeacon.getMajor());
|
||||
uint16_t Minor = ENDIAN_CHANGE_U16(oBeacon.getMinor());
|
||||
|
||||
uint8_t PWR = oBeacon.getSignalPower();
|
||||
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("MAC: %s Major: %d Minor: %d UUID: %s Power: %d RSSI: %d"),
|
||||
advertisedDevice->getAddress().toString().c_str(),
|
||||
Major, Minor,
|
||||
oBeacon.getProximityUUID().toString().c_str(),
|
||||
PWR, RSSI);
|
||||
|
||||
DumpHex((const unsigned char*)&UUID,16,ib.UID);
|
||||
DumpHex((const unsigned char*)&Major,2,ib.MAJOR);
|
||||
DumpHex((const unsigned char*)&Minor,2,ib.MINOR);
|
||||
DumpHex((const unsigned char*)&PWR,1,ib.PWR);
|
||||
DumpHex((const unsigned char*)&MAC,6,ib.MAC);
|
||||
memcpy(ib.RSSI,sRSSI,4);
|
||||
|
||||
if (ibeacon_add(&ib)) {
|
||||
ibeacon_mqtt(ib.MAC,ib.RSSI,ib.UID,ib.MAJOR,ib.MINOR);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
memset(ib.UID,'0',32);
|
||||
memset(ib.MAJOR,'0',4);
|
||||
memset(ib.MINOR,'0',4);
|
||||
memset(ib.PWR,'0',2);
|
||||
DumpHex((const unsigned char*)&MAC,6,ib.MAC);
|
||||
memcpy(ib.RSSI,sRSSI,4);
|
||||
|
||||
if (ibeacon_add(&ib)) {
|
||||
ibeacon_mqtt(ib.MAC,ib.RSSI,ib.UID,ib.MAJOR,ib.MINOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void ESP32StartScanTask(){
|
||||
ESP32BLE.mode.runningScan = 1;
|
||||
xTaskCreatePinnedToCore(
|
||||
ESP32ScanTask, /* Function to implement the task */
|
||||
"ESP32ScanTask", /* Name of the task */
|
||||
2048, /* Stack size in words */
|
||||
NULL, /* Task input parameter */
|
||||
0, /* Priority of the task */
|
||||
NULL, /* Task handle. */
|
||||
0); /* Core where the task should run */
|
||||
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("%s: Start scanning"),"IBEACON_ESP32");
|
||||
}
|
||||
|
||||
void ESP32scanEndedCB(NimBLEScanResults results);
|
||||
|
||||
void ESP32ScanTask(void *pvParameters){
|
||||
if (ESP32BLEScan == nullptr) ESP32BLEScan = NimBLEDevice::getScan();
|
||||
ESP32BLEScan->setInterval(70);
|
||||
ESP32BLEScan->setWindow(50);
|
||||
ESP32BLEScan->setAdvertisedDeviceCallbacks(new ESP32BLEScanCallback());
|
||||
ESP32BLEScan->setActiveScan(false);
|
||||
ESP32BLEScan->setDuplicateFilter(false);
|
||||
|
||||
for (;;) {
|
||||
ESP32BLEScan->start(0, ESP32scanEndedCB, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ESP32scanEndedCB(NimBLEScanResults results) {
|
||||
ESP32BLE.mode.runningScan = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void IBEACON_Init() {
|
||||
|
||||
#ifdef USE_IBEACON_ESP32
|
||||
|
||||
ESP32BLE.mode.init = false;
|
||||
if (!ESP32BLE.mode.init) {
|
||||
NimBLEDevice::init("");
|
||||
|
||||
ESP32BLE.mode.canScan = 1;
|
||||
ESP32BLE.mode.init = 1;
|
||||
|
||||
ESP32StartScanTask(); // Let's get started !!
|
||||
|
||||
IB_UPDATE_TIME=IB_UPDATE_TIME_INTERVAL;
|
||||
IB_TIMEOUT_TIME=IB_TIMEOUT_INTERVAL;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
hm17_found=0;
|
||||
|
||||
// actually doesnt work reliably with software serial
|
||||
|
@ -113,8 +293,27 @@ void IBEACON_Init() {
|
|||
IB_TIMEOUT_TIME=IB_TIMEOUT_INTERVAL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_IBEACON_ESP32
|
||||
|
||||
void esp32_every_second(void) {
|
||||
for (uint32_t cnt=0;cnt<MAX_IBEACONS;cnt++) {
|
||||
if (ibeacons[cnt].FLAGS) {
|
||||
ibeacons[cnt].TIME++;
|
||||
if (ibeacons[cnt].TIME>IB_TIMEOUT_TIME) {
|
||||
ibeacons[cnt].FLAGS=0;
|
||||
ibeacon_mqtt(ibeacons[cnt].MAC,"0000",ibeacons[cnt].UID,ibeacons[cnt].MAJOR,ibeacons[cnt].MINOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void hm17_every_second(void) {
|
||||
if (!IBEACON_Serial) return;
|
||||
|
||||
|
@ -196,6 +395,8 @@ void hm17_sendcmd(uint8_t cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
uint32_t ibeacon_add(struct IBEACON *ib) {
|
||||
/* if (!strncmp(ib->MAJOR,"4B1C",4)) {
|
||||
return 0;
|
||||
|
@ -242,6 +443,8 @@ uint32_t ibeacon_add(struct IBEACON *ib) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifndef USE_IBEACON_ESP32
|
||||
|
||||
void hm17_decode(void) {
|
||||
struct IBEACON ib;
|
||||
switch (hm17_cmd) {
|
||||
|
@ -438,8 +641,16 @@ hm17_v110:
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void IBEACON_loop() {
|
||||
|
||||
#ifdef USE_IBEACON_ESP32
|
||||
|
||||
return;
|
||||
|
||||
#else
|
||||
|
||||
if (!IBEACON_Serial) return;
|
||||
|
||||
uint32_t difftime=millis()-hm17_lastms;
|
||||
|
@ -464,6 +675,8 @@ uint32_t difftime=millis()-hm17_lastms;
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
|
@ -523,7 +736,20 @@ bool xsns52_cmd(void) {
|
|||
uint16_t len=XdrvMailbox.data_len;
|
||||
if (len > 0) {
|
||||
char *cp=XdrvMailbox.data;
|
||||
if (*cp>='0' && *cp<='8') {
|
||||
if (*cp=='u') {
|
||||
cp++;
|
||||
if (*cp) IB_UPDATE_TIME=atoi(cp);
|
||||
Response_P(S_JSON_IBEACON, XSNS_52,"uintv",IB_UPDATE_TIME);
|
||||
} else if (*cp=='t') {
|
||||
cp++;
|
||||
if (*cp) IB_TIMEOUT_TIME=atoi(cp);
|
||||
Response_P(S_JSON_IBEACON, XSNS_52,"lintv",IB_TIMEOUT_TIME);
|
||||
} else if (*cp=='c') {
|
||||
for (uint32_t cnt=0;cnt<MAX_IBEACONS;cnt++) ibeacons[cnt].FLAGS=0;
|
||||
Response_P(S_JSON_IBEACON1, XSNS_52,"clr list","");
|
||||
}
|
||||
#ifndef USE_IBEACON_ESP32
|
||||
else if (*cp>='0' && *cp<='8') {
|
||||
hm17_sendcmd(*cp&7);
|
||||
Response_P(S_JSON_IBEACON, XSNS_52,"hm17cmd",*cp&7);
|
||||
} else if (*cp=='s') {
|
||||
|
@ -536,18 +762,8 @@ bool xsns52_cmd(void) {
|
|||
IBEACON_Serial->write((uint8_t*)cp,len);
|
||||
hm17_cmd=99;
|
||||
Response_P(S_JSON_IBEACON1, XSNS_52,"hm17cmd",cp);
|
||||
} else if (*cp=='u') {
|
||||
cp++;
|
||||
if (*cp) IB_UPDATE_TIME=atoi(cp);
|
||||
Response_P(S_JSON_IBEACON, XSNS_52,"uintv",IB_UPDATE_TIME);
|
||||
} else if (*cp=='t') {
|
||||
cp++;
|
||||
if (*cp) IB_TIMEOUT_TIME=atoi(cp);
|
||||
Response_P(S_JSON_IBEACON, XSNS_52,"lintv",IB_TIMEOUT_TIME);
|
||||
} else if (*cp=='c') {
|
||||
for (uint32_t cnt=0;cnt<MAX_IBEACONS;cnt++) ibeacons[cnt].FLAGS=0;
|
||||
Response_P(S_JSON_IBEACON1, XSNS_52,"clr list","");
|
||||
}
|
||||
#endif
|
||||
#ifdef IBEACON_DEBUG
|
||||
else if (*cp=='d') {
|
||||
cp++;
|
||||
|
@ -562,6 +778,8 @@ bool xsns52_cmd(void) {
|
|||
}
|
||||
|
||||
#define D_CMND_IBEACON "IBEACON"
|
||||
|
||||
#ifndef USE_IBEACON_ESP32
|
||||
//"IBEACON_FFFF3D1B1E9D_RSSI", Data "99" causes TAG to beep
|
||||
bool ibeacon_cmd(void) {
|
||||
ib_mac[0]=0;
|
||||
|
@ -592,6 +810,8 @@ void ib_sendbeep(void) {
|
|||
hm17_sendcmd(HM17_CON);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void ibeacon_mqtt(const char *mac,const char *rssi,const char *uid,const char *major,const char *minor) {
|
||||
char s_mac[14];
|
||||
char s_uid[34];
|
||||
|
@ -636,19 +856,29 @@ bool Xsns52(byte function)
|
|||
IBEACON_loop();
|
||||
break;
|
||||
case FUNC_EVERY_SECOND:
|
||||
#ifdef USE_IBEACON_ESP32
|
||||
esp32_every_second();
|
||||
#else
|
||||
hm17_every_second();
|
||||
#endif
|
||||
break;
|
||||
case FUNC_COMMAND_SENSOR:
|
||||
if (XSNS_52 == XdrvMailbox.index) {
|
||||
result = xsns52_cmd();
|
||||
}
|
||||
break;
|
||||
#ifndef USE_IBEACON_ESP32
|
||||
case FUNC_COMMAND:
|
||||
result=ibeacon_cmd();
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_WEBSERVER
|
||||
case FUNC_WEB_SENSOR:
|
||||
#ifndef USE_IBEACON_ESP32
|
||||
if (hm17_found) IBEACON_Show();
|
||||
#else
|
||||
IBEACON_Show();
|
||||
#endif
|
||||
break;
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue