2021-03-22 14:11:42 +01:00
|
|
|
#include "BleFingerprint.h"
|
|
|
|
|
|
|
|
static const uint16_t beaconUUID = 0xFEAA;
|
|
|
|
static const uint16_t tileUUID = 0xFEED;
|
|
|
|
static const uint16_t exposureUUID = 0xFD6F;
|
2021-03-29 14:53:51 +02:00
|
|
|
|
2021-03-22 14:11:42 +01:00
|
|
|
#ifdef TX_DEFAULT
|
|
|
|
static const int defaultTxPower = TX_DEFAULT;
|
|
|
|
#else
|
|
|
|
static const int defaultTxPower = -59;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00) >> 8) + (((x)&0xFF) << 8))
|
2021-03-29 14:53:51 +02:00
|
|
|
#define Sprintf(f, ...) ({ char* s; asprintf(&s, f, __VA_ARGS__); String r = s; free(s); r; })
|
2021-03-29 20:50:23 +02:00
|
|
|
#define SDateTimef(f) ({ struct tm firstSeenTm; gmtime_r(&f, &firstSeenTm); Sprintf("%d/%d/%d %d:%.2d:%.2d", firstSeenTm.tm_mon, firstSeenTm.tm_mday, 1900 + firstSeenTm.tm_year, firstSeenTm.tm_hour, firstSeenTm.tm_min, firstSeenTm.tm_sec); })
|
|
|
|
#define SMacf(f) ({ auto nativeAddress = f.getNative(); Sprintf("%02x%02x%02x%02x%02x%02x", nativeAddress[5], nativeAddress[4], nativeAddress[3], nativeAddress[2], nativeAddress[1], nativeAddress[0]); })
|
2021-03-22 14:11:42 +01:00
|
|
|
|
|
|
|
static String getProximityUUIDString(BLEBeacon beacon)
|
|
|
|
{
|
|
|
|
std::string serviceData = beacon.getProximityUUID().toString().c_str();
|
|
|
|
int serviceDataLength = serviceData.length();
|
|
|
|
String returnedString = "";
|
|
|
|
int i = serviceDataLength;
|
|
|
|
while (i > 0)
|
|
|
|
{
|
|
|
|
if (serviceData[i - 1] == '-')
|
|
|
|
{
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
char a = serviceData[i - 1];
|
|
|
|
char b = serviceData[i - 2];
|
|
|
|
returnedString += b;
|
|
|
|
returnedString += a;
|
|
|
|
|
|
|
|
i -= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return returnedString;
|
|
|
|
}
|
|
|
|
|
2021-03-30 00:12:59 +02:00
|
|
|
BleFingerprint::~BleFingerprint()
|
|
|
|
{
|
|
|
|
Serial.printf("Del | MAC: %s, ID: %s\n", SMacf(address).c_str(), id.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
BleFingerprint::BleFingerprint(BLEAdvertisedDevice *advertisedDevice)
|
2021-03-22 14:11:42 +01:00
|
|
|
{
|
2021-03-29 20:50:23 +02:00
|
|
|
firstSeen = time(nullptr);
|
2021-03-28 20:35:54 +02:00
|
|
|
address = advertisedDevice->getAddress();
|
|
|
|
|
2021-03-30 00:12:59 +02:00
|
|
|
String mac_address = SMacf(address);
|
2021-03-22 14:11:42 +01:00
|
|
|
|
2021-03-30 00:12:59 +02:00
|
|
|
Serial.printf("New | MAC: %s", mac_address.c_str());
|
2021-03-22 14:11:42 +01:00
|
|
|
|
|
|
|
if (advertisedDevice->haveName())
|
2021-03-24 18:16:49 +01:00
|
|
|
name = String(advertisedDevice->getName().c_str());
|
2021-03-22 14:11:42 +01:00
|
|
|
|
|
|
|
std::string strServiceData = advertisedDevice->getServiceData();
|
|
|
|
uint8_t cServiceData[100];
|
|
|
|
strServiceData.copy((char *)cServiceData, strServiceData.length(), 0);
|
|
|
|
|
|
|
|
if (advertisedDevice->haveServiceUUID() && advertisedDevice->getServiceDataUUID().equals(BLEUUID(tileUUID)) == true)
|
|
|
|
{
|
2021-03-23 02:42:25 +01:00
|
|
|
id = "tile:" + mac_address;
|
2021-03-24 18:16:49 +01:00
|
|
|
Serial.printf(", ID: %s", id.c_str());
|
2021-03-30 00:12:59 +02:00
|
|
|
calRssi = advertisedDevice->haveTXPower() ? (-advertisedDevice->getTXPower()) - 41 : 0;
|
2021-03-22 14:11:42 +01:00
|
|
|
}
|
|
|
|
else if (advertisedDevice->haveServiceUUID() && advertisedDevice->getServiceDataUUID().equals(BLEUUID(exposureUUID)) == true)
|
|
|
|
{ // found covid exposure tracker
|
|
|
|
id = "exp:" + String(strServiceData.length());
|
2021-03-24 18:16:49 +01:00
|
|
|
Serial.printf(", ID: %s", id.c_str());
|
2021-03-30 00:12:59 +02:00
|
|
|
calRssi = advertisedDevice->haveTXPower() ? (-advertisedDevice->getTXPower()) - 41 : 0;
|
2021-03-24 19:06:40 +01:00
|
|
|
|
2021-03-27 04:07:25 +01:00
|
|
|
//char *sdHex = NimBLEUtils::buildHexData(nullptr, (uint8_t *)strServiceData.data(), strServiceData.length());
|
|
|
|
//doc["tek"] = String(sdHex).substring(4, 20);
|
|
|
|
//free(sdHex);
|
2021-03-22 14:11:42 +01:00
|
|
|
}
|
|
|
|
else if (advertisedDevice->haveServiceUUID() && advertisedDevice->getServiceDataUUID().equals(BLEUUID(beaconUUID)) == true)
|
|
|
|
{ // found Eddystone UUID
|
|
|
|
Serial.print(", Eddystone");
|
|
|
|
if (cServiceData[0] == 0x10)
|
|
|
|
{
|
|
|
|
BLEEddystoneURL oBeacon = BLEEddystoneURL();
|
|
|
|
oBeacon.setData(strServiceData);
|
|
|
|
// Serial.printf("Eddystone Frame Type (Eddystone-URL) ");
|
2021-03-30 00:12:59 +02:00
|
|
|
url = String(oBeacon.getDecodedURL().c_str());
|
2021-03-22 14:11:42 +01:00
|
|
|
Serial.print(" URL: ");
|
2021-03-30 00:12:59 +02:00
|
|
|
Serial.print(url.c_str());
|
|
|
|
calRssi = oBeacon.getPower();
|
2021-03-22 14:11:42 +01:00
|
|
|
}
|
|
|
|
else if (cServiceData[0] == 0x20)
|
|
|
|
{
|
|
|
|
BLEEddystoneTLM oBeacon = BLEEddystoneTLM();
|
|
|
|
oBeacon.setData(strServiceData);
|
|
|
|
Serial.printf(" TLM: ");
|
|
|
|
Serial.printf(oBeacon.toString().c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-03-24 18:16:49 +01:00
|
|
|
if (advertisedDevice->haveServiceUUID())
|
|
|
|
{
|
|
|
|
for (int i = 0; i < advertisedDevice->getServiceUUIDCount(); i++)
|
|
|
|
{
|
|
|
|
std::string sid = advertisedDevice->getServiceUUID(i).toString();
|
|
|
|
Serial.printf(", sID: %s", sid.c_str());
|
|
|
|
}
|
|
|
|
}
|
2021-03-22 14:11:42 +01:00
|
|
|
if (advertisedDevice->haveManufacturerData() == true)
|
|
|
|
{
|
|
|
|
std::string strManufacturerData = advertisedDevice->getManufacturerData();
|
|
|
|
|
|
|
|
uint8_t cManufacturerData[100];
|
|
|
|
strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
|
|
|
|
char *mdHex = NimBLEUtils::buildHexData(nullptr, (uint8_t *)strManufacturerData.data(), strManufacturerData.length());
|
|
|
|
|
|
|
|
if (strManufacturerData.length() > 2 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00) // Apple
|
|
|
|
{
|
|
|
|
if (strManufacturerData.length() == 25 && cManufacturerData[2] == 0x02 && cManufacturerData[3] == 0x15)
|
|
|
|
{
|
|
|
|
BLEBeacon oBeacon = BLEBeacon();
|
|
|
|
oBeacon.setData(strManufacturerData);
|
|
|
|
|
|
|
|
String proximityUUID = getProximityUUIDString(oBeacon);
|
|
|
|
|
|
|
|
int major = ENDIAN_CHANGE_U16(oBeacon.getMajor());
|
|
|
|
int minor = ENDIAN_CHANGE_U16(oBeacon.getMinor());
|
|
|
|
|
2021-03-24 18:16:49 +01:00
|
|
|
id = "iBeacon:" + proximityUUID + "-" + String(major) + "-" + String(minor);
|
|
|
|
Serial.printf(", ID: %s", id.c_str());
|
2021-03-30 00:12:59 +02:00
|
|
|
calRssi = oBeacon.getSignalPower();
|
2021-03-22 14:11:42 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
String fingerprint = "apple:" + String(mdHex).substring(4, 8) + ":" + String(strManufacturerData.length());
|
|
|
|
if (advertisedDevice->haveTXPower())
|
|
|
|
fingerprint = fingerprint + String(-advertisedDevice->getTXPower());
|
|
|
|
|
|
|
|
id = fingerprint;
|
2021-03-24 18:16:49 +01:00
|
|
|
Serial.printf(", ID: %s", id.c_str());
|
2021-03-22 14:11:42 +01:00
|
|
|
|
2021-03-30 00:12:59 +02:00
|
|
|
calRssi = advertisedDevice->haveTXPower() ? (-advertisedDevice->getTXPower()) - 41 : 0;
|
2021-03-22 14:11:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-03-24 18:16:49 +01:00
|
|
|
if (strManufacturerData.length() > 2)
|
|
|
|
{
|
|
|
|
String fingerprint = "md:" + String(mdHex).substring(2, 4) + String(mdHex).substring(0, 2) + ":" + String(strManufacturerData.length());
|
|
|
|
if (advertisedDevice->haveTXPower())
|
|
|
|
fingerprint = fingerprint + String(-advertisedDevice->getTXPower());
|
|
|
|
id = fingerprint;
|
|
|
|
Serial.printf(", ID: %s", id.c_str());
|
|
|
|
}
|
2021-03-22 14:11:42 +01:00
|
|
|
|
2021-03-30 00:12:59 +02:00
|
|
|
calRssi = advertisedDevice->haveTXPower() ? (-advertisedDevice->getTXPower()) - 41 : 0;
|
2021-03-22 14:11:42 +01:00
|
|
|
}
|
|
|
|
free(mdHex);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-03-30 00:12:59 +02:00
|
|
|
calRssi = (advertisedDevice->haveTXPower() ? (-advertisedDevice->getTXPower()) - 41 : 0);
|
2021-03-22 14:11:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Serial.println();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BleFingerprint::seen(BLEAdvertisedDevice *advertisedDevice)
|
|
|
|
{
|
2021-03-29 20:50:23 +02:00
|
|
|
lastSeen = time(nullptr);
|
|
|
|
|
2021-03-22 14:11:42 +01:00
|
|
|
rssi = advertisedDevice->getRSSI();
|
|
|
|
if (!calRssi)
|
|
|
|
calRssi = defaultTxPower;
|
|
|
|
|
2021-03-22 23:56:29 +01:00
|
|
|
float ratio = (calRssi - rssi) / 35.0f;
|
2021-03-30 00:12:59 +02:00
|
|
|
raw = pow(10, ratio);
|
|
|
|
setDistance(raw);
|
|
|
|
}
|
2021-03-22 23:56:29 +01:00
|
|
|
|
2021-03-30 00:12:59 +02:00
|
|
|
void BleFingerprint::setDistance(float distFl)
|
|
|
|
{
|
2021-03-24 14:10:33 +01:00
|
|
|
Reading<float> inter1, inter2;
|
|
|
|
|
|
|
|
if (tsFilter.push(&distFl, &inter1))
|
2021-03-22 23:56:29 +01:00
|
|
|
{
|
2021-03-24 14:10:33 +01:00
|
|
|
inter2.timestamp = inter1.timestamp;
|
|
|
|
inter2.value = oneEuro(inter1.value);
|
|
|
|
if (diffFilter.push(&inter2, &output))
|
2021-03-29 20:50:23 +02:00
|
|
|
hasValue = true;
|
2021-03-22 23:56:29 +01:00
|
|
|
}
|
2021-03-29 20:50:23 +02:00
|
|
|
}
|
|
|
|
|
2021-03-30 00:12:59 +02:00
|
|
|
float BleFingerprint::getDistance()
|
|
|
|
{
|
|
|
|
return output.value.position;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BleFingerprint::report(JsonDocument *doc)
|
2021-03-29 20:50:23 +02:00
|
|
|
{
|
|
|
|
if (id == nullptr && name == nullptr)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!hasValue)
|
|
|
|
return false;
|
2021-03-24 14:10:33 +01:00
|
|
|
|
2021-03-30 00:12:59 +02:00
|
|
|
String mac = SMacf(address);
|
2021-03-29 21:51:18 +02:00
|
|
|
if (output.value.position < 0.5)
|
|
|
|
{
|
|
|
|
if (!enroll)
|
|
|
|
{
|
2021-03-30 00:12:59 +02:00
|
|
|
Serial.printf("Enter | MAC: %s, ID: %-50s %lu %5.1f %5.1f %5.1f\n", mac.c_str(), id.c_str(), output.timestamp, output.value.position, output.value.speed * 1e6, output.value.acceleration * 1e12);
|
2021-03-29 21:51:18 +02:00
|
|
|
enroll = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (enroll && output.value.position > 1.5)
|
|
|
|
{
|
2021-03-30 00:12:59 +02:00
|
|
|
Serial.printf("Left | MAC: %s, ID: %-50s %lu %5.1f %5.1f %5.1f\n", mac.c_str(), id.c_str(), output.timestamp, output.value.position, output.value.speed * 1e6, output.value.acceleration * 1e12);
|
2021-03-29 21:51:18 +02:00
|
|
|
enroll = false;
|
|
|
|
}
|
2021-03-22 14:11:42 +01:00
|
|
|
|
2021-03-24 18:16:49 +01:00
|
|
|
if (id != nullptr)
|
2021-03-30 00:12:59 +02:00
|
|
|
(*doc)[F("id")] = id;
|
2021-03-24 18:16:49 +01:00
|
|
|
if (name != nullptr)
|
2021-03-30 00:12:59 +02:00
|
|
|
(*doc)[F("name")] = name;
|
|
|
|
|
|
|
|
(*doc)[F("rssi@1m")] = calRssi;
|
|
|
|
(*doc)[F("rssi")] = rssi;
|
2021-03-29 20:50:23 +02:00
|
|
|
|
2021-03-30 00:12:59 +02:00
|
|
|
(*doc)[F("mac")] = mac;
|
|
|
|
(*doc)[F("raw")] = round(raw * 100.0f) / 100.0f;
|
|
|
|
(*doc)[F("distance")] = round(output.value.position * 100.0f) / 100.0f;
|
|
|
|
(*doc)[F("speed")] = round(output.value.speed * 1e7f) / 10.0f;
|
2021-03-29 20:50:23 +02:00
|
|
|
|
2021-03-30 00:12:59 +02:00
|
|
|
(*doc)[F("first")] = SDateTimef(firstSeen);
|
|
|
|
(*doc)[F("last")] = SDateTimef(lastSeen);
|
2021-03-29 20:50:23 +02:00
|
|
|
|
2021-03-30 00:12:59 +02:00
|
|
|
return true;
|
2021-03-22 14:11:42 +01:00
|
|
|
}
|