Loads of improvements (#372)

* Disable unused ble functions to free up some memory
* Added Count of devices present in room
* Added known macs
* Reorg settings
* Improvements to ignoring (trailing spaces matched everything)
* Add battery percent to ATC sensors
* Remove sprite usage to clean up memory usage
* Initial support for samsung smart tag (may not actually work) (#351)
* DHT Sensor temp related changes (#385)
* Add interval, fix rounding
* Add batt for MACCHINA_A0
* Add running to macchina
* Add Garmin watch (Fenix 6) id
* Updgrade ArduinoJson

Co-authored-by: tr-v-r <83373608+tr-v-r@users.noreply.github.com>
This commit is contained in:
Darrell 2022-03-13 21:54:50 -04:00 committed by GitHub
parent e8699f0279
commit 54721b03be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 512 additions and 357 deletions

View File

@ -4,10 +4,9 @@ import time
#this list contains array of esp32 clients,
# and each client contains mDNS name and the path to .bin file
#I only have 1 ESP so I duplicate mDNS entry for testing
esps = [
#mDNS name of ESP #path to ".bin" file
['192.168.128.114', 'macchina-a0'],
['192.168.128.112', 'macchina-a0'],
['192.168.128.124', 'm5stickc'],
['192.168.128.64', 'm5atom-matrix'],
['192.168.128.84', 'm5atom-matrix']

View File

@ -4,23 +4,15 @@
#include "strings.h"
#include "util.h"
bool prefixExists(const String& prefixes, const String& id)
class ClientCallbacks : public BLEClientCallbacks
{
unsigned int start = 0;
unsigned int space = 0;
while ((space = prefixes.indexOf(" ", start)) != -1)
bool onConnParamsUpdateRequest(NimBLEClient *pClient, const ble_gap_upd_params *params)
{
if (space > start)
{
auto sub = prefixes.substring(start, space);
if (sub == "*" || id.indexOf(sub) != -1) return true;
}
start = space + 1;
}
auto sub = prefixes.substring(start);
return (sub == "*" || id.indexOf(sub) != -1);
}
return true;
};
};
static ClientCallbacks clientCB;
bool BleFingerprint::shouldHide(const String& s)
{
@ -30,13 +22,14 @@ bool BleFingerprint::shouldHide(const String& s)
bool BleFingerprint::setId(const String& newId, short newIdType, const String& newName)
{
if (newIdType < idType) return false;
if (newIdType < idType && idType > 0) return false;
hidden = shouldHide(newId);
ignore = newIdType < 0;
if (!allowQuery)
if (!allowQuery && !ignore)
{
if (BleFingerprintCollection::query.length() > 0 && prefixExists(BleFingerprintCollection::query, newId))
if (!BleFingerprintCollection::query.isEmpty() && prefixExists(BleFingerprintCollection::query, newId))
{
allowQuery = true;
qryAttempts = 0;
@ -48,6 +41,7 @@ bool BleFingerprint::setId(const String& newId, short newIdType, const String& n
}
}
countable = !ignore && !BleFingerprintCollection::countIds.isEmpty() && prefixExists(BleFingerprintCollection::countIds, newId);
id = newId;
idType = newIdType;
if (!newName.isEmpty()) name = newName;
@ -66,9 +60,25 @@ BleFingerprint::BleFingerprint(const BleFingerprintCollection *parent, BLEAdvert
{
firstSeenMillis = millis();
address = NimBLEAddress(advertisedDevice->getAddress());
macPublic = advertisedDevice->getAddressType() == BLE_ADDR_PUBLIC;
newest = recent = oldest = rssi = advertisedDevice->getRSSI();
seenCount = 1;
auto mac = getMac();
if (!BleFingerprintCollection::knownMacs.isEmpty() && prefixExists(BleFingerprintCollection::knownMacs, mac))
setId("known:" + mac, ID_TYPE_KNOWN_MAC);
else
{
switch (advertisedDevice->getAddressType())
{
case BLE_ADDR_PUBLIC:
case BLE_ADDR_PUBLIC_ID:
setId(mac, ID_TYPE_PUBLIC_MAC);
break;
default:
setId(mac, ID_TYPE_MAC);
break;
}
}
}
void BleFingerprint::fingerprint(NimBLEAdvertisedDevice *advertisedDevice)
@ -81,13 +91,15 @@ void BleFingerprint::fingerprint(NimBLEAdvertisedDevice *advertisedDevice)
size_t serviceAdvCount = advertisedDevice->getServiceUUIDCount();
size_t serviceDataCount = advertisedDevice->getServiceDataCount();
bool haveTxPower = advertisedDevice->haveTXPower();
int8_t txPower = advertisedDevice->getTXPower();
if (serviceAdvCount > 0) fingerprintServiceAdvertisements(advertisedDevice, serviceAdvCount);
if (serviceDataCount > 0) fingerprintServiceData(advertisedDevice, serviceDataCount);
if (advertisedDevice->haveManufacturerData()) fingerprintManufactureData(advertisedDevice);
if (serviceAdvCount > 0) fingerprintServiceAdvertisements(advertisedDevice, serviceAdvCount, haveTxPower, txPower);
if (serviceDataCount > 0) fingerprintServiceData(advertisedDevice, serviceDataCount, haveTxPower, txPower);
if (advertisedDevice->haveManufacturerData()) fingerprintManufactureData(advertisedDevice, haveTxPower, txPower);
}
void BleFingerprint::fingerprintServiceAdvertisements(NimBLEAdvertisedDevice *advertisedDevice, size_t serviceAdvCount)
void BleFingerprint::fingerprintServiceAdvertisements(NimBLEAdvertisedDevice *advertisedDevice, size_t serviceAdvCount, bool haveTxPower, int8_t txPower)
{
for (size_t i = 0; i < serviceAdvCount; i++)
{
@ -118,135 +130,142 @@ void BleFingerprint::fingerprintServiceAdvertisements(NimBLEAdvertisedDevice *ad
}
else if (uuid == sonosUUID)
{
asRssi = advertisedDevice->haveTXPower() ? BleFingerprintCollection::refRssi + advertisedDevice->getTXPower() : NO_RSSI;
asRssi = haveTxPower ? BleFingerprintCollection::refRssi + txPower : NO_RSSI;
setId("sonos:" + getMac(), ID_TYPE_SONOS);
return;
}
else if (uuid == itagUUID)
{
asRssi = BleFingerprintCollection::refRssi + (advertisedDevice->haveTXPower() ? advertisedDevice->getTXPower() : ITAG_TX);
asRssi = BleFingerprintCollection::refRssi + (haveTxPower ? txPower : ITAG_TX);
setId("itag:" + getMac(), ID_TYPE_ITAG);
return;
}
else if (uuid == trackrUUID)
{
asRssi = advertisedDevice->haveTXPower() ? BleFingerprintCollection::refRssi + advertisedDevice->getTXPower() : NO_RSSI;
asRssi = haveTxPower ? BleFingerprintCollection::refRssi + txPower : NO_RSSI;
setId("trackr:" + getMac(), ID_TYPE_TRACKR);
return;
}
else if (uuid == vanmoofUUID)
{
asRssi = advertisedDevice->haveTXPower() ? BleFingerprintCollection::refRssi + advertisedDevice->getTXPower() : NO_RSSI;
asRssi = haveTxPower ? BleFingerprintCollection::refRssi + txPower : NO_RSSI;
setId("vanmoof:" + getMac(), ID_TYPE_VANMOOF);
return;
}
else if (uuid == (meaterService))
{
asRssi = advertisedDevice->haveTXPower() ? BleFingerprintCollection::refRssi + advertisedDevice->getTXPower() : NO_RSSI;
asRssi = haveTxPower ? BleFingerprintCollection::refRssi + txPower : NO_RSSI;
setId("meater:" + getMac(), ID_TYPE_MEATER);
return;
}
}
String fingerprint = "ad:";
asRssi = advertisedDevice->haveTXPower() ? BleFingerprintCollection::refRssi + advertisedDevice->getTXPower() : NO_RSSI;
asRssi = haveTxPower ? BleFingerprintCollection::refRssi + txPower : NO_RSSI;
for (int i = 0; i < serviceAdvCount; i++)
{
std::string sid = advertisedDevice->getServiceUUID(i).toString();
fingerprint = fingerprint + sid.c_str();
}
if (advertisedDevice->haveTXPower()) fingerprint = fingerprint + String(-advertisedDevice->getTXPower());
if (haveTxPower) fingerprint = fingerprint + String(-txPower);
setId(fingerprint, ID_TYPE_AD);
}
void BleFingerprint::fingerprintServiceData(NimBLEAdvertisedDevice *advertisedDevice, size_t serviceDataCount)
void BleFingerprint::fingerprintServiceData(NimBLEAdvertisedDevice *advertisedDevice, size_t serviceDataCount, bool haveTxPower, int8_t txPower)
{
asRssi = haveTxPower ? BleFingerprintCollection::refRssi + txPower : NO_RSSI;
String fingerprint = "sd:";
for (int i = 0; i < serviceDataCount; i++)
{
asRssi = advertisedDevice->haveTXPower() ? BleFingerprintCollection::refRssi + advertisedDevice->getTXPower() : NO_RSSI;
String fingerprint = "sd:";
for (int i = 0; i < serviceDataCount; i++)
{
BLEUUID uuid = advertisedDevice->getServiceDataUUID(i);
std::string strServiceData = advertisedDevice->getServiceData(i);
BLEUUID uuid = advertisedDevice->getServiceDataUUID(i);
std::string strServiceData = advertisedDevice->getServiceData(i);
#ifdef VERBOSE
Serial.printf("Verbose | %-58sSD: %s/%s\n", getId().c_str(), uuid.toString().c_str(), hexStr(strServiceData).c_str());
Serial.printf("Verbose | %-58sSD: %s/%s\n", getId().c_str(), uuid.toString().c_str(), hexStr(strServiceData).c_str());
#endif
if (uuid == exposureUUID)
{ // found COVID-19 exposure tracker
calRssi = BleFingerprintCollection::refRssi + EXPOSURE_TX;
setId("exp:" + String(strServiceData.length()), ID_TYPE_EXPOSURE);
disc = hexStr(strServiceData).c_str();
}
else if (uuid == miThermUUID)
{
asRssi = advertisedDevice->haveTXPower() ? BleFingerprintCollection::refRssi + advertisedDevice->getTXPower() : NO_RSSI;
if (strServiceData.length() == 15)
{ // custom format
auto serviceData = strServiceData.c_str();
temp = float(*(int16_t *)(serviceData + 6)) / 100.0f;
humidity = float(*(uint16_t *)(serviceData + 8)) / 100.0f;
mv = *(uint16_t *)(serviceData + 10);
#ifdef VERBOSE
Serial.printf("Temp: %.2f°, Humidity: %.2f%%, Vbatt: %d, Battery: %d%%, flg: 0x%02x, cout: %d\n", temp, humidity, mv, serviceData[12], serviceData[14], serviceData[13]);
#endif
setId("miTherm:" + getMac(), ID_TYPE_MITHERM);
}
else if (strServiceData.length() == 13)
{ // format atc1441
auto serviceData = strServiceData.c_str();
int16_t x = (serviceData[6] << 8) | serviceData[7];
temp = float(x) / 10.0f;
mv = x = (serviceData[10] << 8) | serviceData[11];
#ifdef VERBOSE
Serial.printf("Temp: %.1f°, Humidity: %d%%, Vbatt: %d, Battery: %d%%, cout: %d\n", temp, serviceData[8], mv, serviceData[9], serviceData[12]);
#endif
setId("miTherm:" + getMac(), ID_TYPE_MITHERM);
}
}
else if (uuid == eddystoneUUID && strServiceData.length() > 0)
{
if (strServiceData[0] == EDDYSTONE_URL_FRAME_TYPE && strServiceData.length() <= 18)
{
BLEEddystoneURL oBeacon = BLEEddystoneURL();
oBeacon.setData(strServiceData);
calRssi = EDDYSTONE_ADD_1M + oBeacon.getPower();
}
else if (strServiceData[0] == EDDYSTONE_TLM_FRAME_TYPE)
{
BLEEddystoneTLM oBeacon = BLEEddystoneTLM();
oBeacon.setData(strServiceData);
temp = oBeacon.getTemp();
mv = oBeacon.getVolt();
#ifdef VERBOSE
Serial.println(oBeacon.toString().c_str());
#endif
}
else if (strServiceData[0] == 0x00)
{
auto serviceData = strServiceData.c_str();
int8_t rss0m = *(int8_t *)(serviceData + 1);
calRssi = EDDYSTONE_ADD_1M + rss0m;
setId(Sprintf("eddy:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x-%02x%02x%02x%02x%02x%02x",
strServiceData[2], strServiceData[3], strServiceData[4], strServiceData[5], strServiceData[6],
strServiceData[6], strServiceData[7], strServiceData[8], strServiceData[9], strServiceData[10],
strServiceData[11], strServiceData[12], strServiceData[13], strServiceData[14], strServiceData[15],
strServiceData[16], strServiceData[17]),
ID_TYPE_EBEACON);
}
}
else
{
fingerprint = fingerprint + uuid.toString().c_str();
}
}
if (advertisedDevice->haveTXPower())
fingerprint = fingerprint + String(-advertisedDevice->getTXPower());
setId(fingerprint, ID_TYPE_SD);
if (uuid == exposureUUID)
{ // found COVID-19 exposure tracker
calRssi = BleFingerprintCollection::refRssi + EXPOSURE_TX;
setId("exp:" + String(strServiceData.length()), ID_TYPE_EXPOSURE);
disc = hexStr(strServiceData).c_str();
}
else if (uuid == smartTagUUID)
{ // found Samsung smart tag
asRssi = haveTxPower ? BleFingerprintCollection::refRssi + txPower : NO_RSSI;
setId(String("smarttag:") + hexStr(strServiceData).c_str(), ID_TYPE_SMARTTAG);
}
else if (uuid == miThermUUID)
{
asRssi = haveTxPower ? BleFingerprintCollection::refRssi + txPower : NO_RSSI;
if (strServiceData.length() == 15)
{ // custom format
auto serviceData = strServiceData.c_str();
temp = float(*(int16_t *)(serviceData + 6)) / 100.0f;
humidity = float(*(uint16_t *)(serviceData + 8)) / 100.0f;
mv = *(uint16_t *)(serviceData + 10);
battery = serviceData[12];
#ifdef VERBOSE
Serial.printf("Temp: %.1f°, Humidity: %.1f%%, mV: %hu, Battery: %hhu%%, flg: 0x%02hhx, cout: %hhu\n", temp, humidity, mv, battery, serviceData[14], serviceData[13]);
#endif
setId("miTherm:" + getMac(), ID_TYPE_MITHERM);
}
else if (strServiceData.length() == 13)
{ // format atc1441
auto serviceData = strServiceData.c_str();
int16_t x = (serviceData[6] << 8) | serviceData[7];
temp = float(x) / 10.0f;
humidity = serviceData[8];
mv = x = (serviceData[10] << 8) | serviceData[11];
battery = serviceData[9];
#ifdef VERBOSE
Serial.printf("Temp: %.1f°, Humidity: %.1f%%, mV: %hu, Battery: %hhu%%, cout: %hhu\n", temp, humidity, mv, battery, serviceData[12]);
#endif
setId("miTherm:" + getMac(), ID_TYPE_MITHERM);
}
}
else if (uuid == eddystoneUUID && strServiceData.length() > 0)
{
if (strServiceData[0] == EDDYSTONE_URL_FRAME_TYPE && strServiceData.length() <= 18)
{
BLEEddystoneURL oBeacon = BLEEddystoneURL();
oBeacon.setData(strServiceData);
calRssi = EDDYSTONE_ADD_1M + oBeacon.getPower();
}
else if (strServiceData[0] == EDDYSTONE_TLM_FRAME_TYPE)
{
BLEEddystoneTLM oBeacon = BLEEddystoneTLM();
oBeacon.setData(strServiceData);
temp = oBeacon.getTemp();
mv = oBeacon.getVolt();
#ifdef VERBOSE
Serial.println(oBeacon.toString().c_str());
#endif
}
else if (strServiceData[0] == 0x00)
{
auto serviceData = strServiceData.c_str();
int8_t rss0m = *(int8_t *)(serviceData + 1);
calRssi = EDDYSTONE_ADD_1M + rss0m;
setId(Sprintf("eddy:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x-%02x%02x%02x%02x%02x%02x",
strServiceData[2], strServiceData[3], strServiceData[4], strServiceData[5], strServiceData[6],
strServiceData[6], strServiceData[7], strServiceData[8], strServiceData[9], strServiceData[10],
strServiceData[11], strServiceData[12], strServiceData[13], strServiceData[14], strServiceData[15],
strServiceData[16], strServiceData[17]),
ID_TYPE_EBEACON);
}
}
else
{
fingerprint = fingerprint + uuid.toString().c_str();
}
}
if (haveTxPower)
fingerprint = fingerprint + String(-txPower);
setId(fingerprint, ID_TYPE_SD);
}
void BleFingerprint::fingerprintManufactureData(NimBLEAdvertisedDevice *advertisedDevice)
void BleFingerprint::fingerprintManufactureData(NimBLEAdvertisedDevice *advertisedDevice, bool haveTxPower, int8_t txPower)
{
std::string strManufacturerData = advertisedDevice->getManufacturerData();
#ifdef VERBOSE
@ -262,46 +281,43 @@ void BleFingerprint::fingerprintManufactureData(NimBLEAdvertisedDevice *advertis
{
BLEBeacon oBeacon = BLEBeacon();
oBeacon.setData(strManufacturerData);
setId(Sprintf("iBeacon:%s-%d-%d", std::string(oBeacon.getProximityUUID()).c_str(), ENDIAN_CHANGE_U16(oBeacon.getMajor()), ENDIAN_CHANGE_U16(oBeacon.getMinor())), ID_TYPE_IBEACON);
setId(Sprintf("iBeacon:%s-%u-%u", std::string(oBeacon.getProximityUUID()).c_str(), ENDIAN_CHANGE_U16(oBeacon.getMajor()), ENDIAN_CHANGE_U16(oBeacon.getMinor())), ID_TYPE_IBEACON);
calRssi = oBeacon.getSignalPower();
}
else if (strManufacturerData.length() >= 4 && strManufacturerData[2] == 0x10)
{
ignore = false;
{
String pid;
if (advertisedDevice->haveTXPower())
pid = Sprintf("apple:%02x%02x:%d%d", strManufacturerData[2], strManufacturerData[3], strManufacturerData.length(), -advertisedDevice->getTXPower());
else
pid = Sprintf("apple:%02x%02x:%d", strManufacturerData[2], strManufacturerData[3], strManufacturerData.length());
setId(pid, ID_TYPE_APPLE_NEARBY);
}
String pid = Sprintf("apple:%02x%02x:%zu", strManufacturerData[2], strManufacturerData[3], strManufacturerData.length());
if (haveTxPower) pid += -txPower;
setId(pid, ID_TYPE_APPLE_NEARBY);
disc = hexStr(strManufacturerData.substr(4)).c_str();
mdRssi = BleFingerprintCollection::refRssi + APPLE_TX;
}
else
else if (strManufacturerData.length() >= 4)
{
if (advertisedDevice->haveTXPower())
setId(Sprintf("apple:%02x%02x:%d%d", strManufacturerData[2], strManufacturerData[3], strManufacturerData.length(), -advertisedDevice->getTXPower()), ID_TYPE_MISC_APPLE + ID_TYPE_TX_POW);
else
setId(Sprintf("apple:%02x%02x:%d", strManufacturerData[2], strManufacturerData[3], strManufacturerData.length()), ID_TYPE_MISC_APPLE);
String pid = Sprintf("apple:%02x%02x:%zu", strManufacturerData[2], strManufacturerData[3], strManufacturerData.length());
if (haveTxPower) pid += -txPower;
setId(pid, ID_TYPE_MISC_APPLE);
mdRssi = BleFingerprintCollection::refRssi + APPLE_TX;
ignore = true;
}
}
else if (manuf == "05a7") // Sonos
{
mdRssi = advertisedDevice->haveTXPower() ? BleFingerprintCollection::refRssi + advertisedDevice->getTXPower() : NO_RSSI;
mdRssi = haveTxPower ? BleFingerprintCollection::refRssi + txPower : NO_RSSI;
setId("sonos:" + getMac(), ID_TYPE_SONOS);
}
else if (manuf == "0087") // Garmin
{
mdRssi = haveTxPower ? BleFingerprintCollection::refRssi + txPower : NO_RSSI;
setId("garmin:" + getMac(), ID_TYPE_GARMIN);
}
else if (manuf == "0157") // Mi-fit
{
mdRssi = advertisedDevice->haveTXPower() ? BleFingerprintCollection::refRssi + advertisedDevice->getTXPower() : NO_RSSI;
mdRssi = haveTxPower ? BleFingerprintCollection::refRssi + txPower : NO_RSSI;
setId("mifit:" + getMac(), ID_TYPE_MIFIT);
}
else if (manuf == "0006" && strManufacturerData.length() == 29) // microsoft
{
mdRssi = advertisedDevice->haveTXPower() ? BleFingerprintCollection::refRssi + advertisedDevice->getTXPower() : NO_RSSI;
mdRssi = haveTxPower ? BleFingerprintCollection::refRssi + txPower : NO_RSSI;
setId(Sprintf("msft:cdp:%02x%02x", strManufacturerData[3], strManufacturerData[5]), ID_TYPE_MSFT);
disc = Sprintf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
strManufacturerData[6], strManufacturerData[7], strManufacturerData[8], strManufacturerData[9], strManufacturerData[10],
@ -311,22 +327,21 @@ void BleFingerprint::fingerprintManufactureData(NimBLEAdvertisedDevice *advertis
}
else if (manuf == "0075") // samsung
{
mdRssi = advertisedDevice->haveTXPower() ? BleFingerprintCollection::refRssi + advertisedDevice->getTXPower() : NO_RSSI;
mdRssi = haveTxPower ? BleFingerprintCollection::refRssi + txPower : NO_RSSI;
setId("samsung:" + getMac(), ID_TYPE_MISC);
}
else if (strManufacturerData.length() == 26 && strManufacturerData[2] == 0xBE && strManufacturerData[3] == 0xAC)
else if (manuf == "beac" && strManufacturerData.length() == 26)
{
BLEBeacon oBeacon = BLEBeacon();
oBeacon.setData(strManufacturerData.substr(0, 25));
setId(Sprintf("altBeacon:%s-%d-%d", std::string(oBeacon.getProximityUUID()).c_str(), ENDIAN_CHANGE_U16(oBeacon.getMajor()), ENDIAN_CHANGE_U16(oBeacon.getMinor())), ID_TYPE_ABEACON);
setId(Sprintf("altBeacon:%s-%u-%u", std::string(oBeacon.getProximityUUID()).c_str(), ENDIAN_CHANGE_U16(oBeacon.getMajor()), ENDIAN_CHANGE_U16(oBeacon.getMinor())), ID_TYPE_ABEACON);
calRssi = oBeacon.getSignalPower();
}
else if (manuf != "0000")
{
mdRssi = advertisedDevice->haveTXPower() ? BleFingerprintCollection::refRssi + advertisedDevice->getTXPower() : NO_RSSI;
String fingerprint = Sprintf("md:%s:%d", manuf.c_str(), strManufacturerData.length());
if (advertisedDevice->haveTXPower())
fingerprint = fingerprint + String(-advertisedDevice->getTXPower());
mdRssi = haveTxPower ? BleFingerprintCollection::refRssi + txPower : NO_RSSI;
String fingerprint = Sprintf("md:%s:%zu", manuf.c_str(), strManufacturerData.length());
if (haveTxPower) fingerprint = fingerprint + String(-txPower);
setId(fingerprint, ID_TYPE_MD);
}
}
@ -392,7 +407,7 @@ void BleFingerprint::setInitial(int initalRssi, float initalDistance)
bool BleFingerprint::report(JsonDocument *doc)
{
if (ignore || (idType == 0 && !macPublic) || hidden)
if (ignore || idType == 0 || hidden)
return false;
if (reported || !hasValue)
@ -410,7 +425,7 @@ bool BleFingerprint::report(JsonDocument *doc)
lastReported = output.value.position;
reported = true;
(*doc)[F("id")] = getId();
(*doc)[F("id")] = id;
if (!name.isEmpty()) (*doc)[F("name")] = name;
if (!disc.isEmpty()) (*doc)[F("disc")] = disc;
if (idType) (*doc)[F("idType")] = idType;
@ -423,9 +438,12 @@ bool BleFingerprint::report(JsonDocument *doc)
(*doc)[F("speed")] = round(output.value.speed * 1e5f) / 100.0f;
(*doc)[F("mac")] = SMacf(address);
(*doc)[F("interval")] = (now - firstSeenMillis) / seenCount;
if (mv) (*doc)[F("mV")] = mv;
if (temp) (*doc)[F("temp")] = temp;
if (humidity) (*doc)[F("rh")] = humidity;
if (battery != 0xFF) (*doc)[F("batt")] = battery;
if (temp) (*doc)[F("temp")] = round(temp*10)/10;
if (humidity) (*doc)[F("rh")] = round(humidity*10)/10;
return true;
}
@ -436,7 +454,7 @@ bool BleFingerprint::query()
if (rssi < -90) return false;
auto now = millis();
if (now - lastSeenMillis > 5) return false;
if (now - lastSeenMillis > 10) return false;
if (now - lastQryMillis < qryDelayMillis) return false;
didQuery = true;
@ -444,14 +462,18 @@ bool BleFingerprint::query()
bool success = false;
Serial.printf("%d Query | MAC: %s, ID: %-60s rssi %d\n", xPortGetCoreID(), getMac().c_str(), getId().c_str(), rssi);
Serial.printf("%u Query | MAC: %s, ID: %-60s %lums\n", xPortGetCoreID(), getMac().c_str(), id.c_str(), now - lastSeenMillis);
NimBLEClient *pClient = NimBLEDevice::getClientListSize() ? NimBLEDevice::getClientByPeerAddress(address) : nullptr;
if (!pClient) pClient = NimBLEDevice::getDisconnectedClient();
if (!pClient) pClient = NimBLEDevice::createClient();
pClient->setClientCallbacks(&clientCB, false);
pClient->setConnectionParams(12, 12, 0, 200);
pClient->setConnectTimeout(5);
NimBLEDevice::getScan()->stop();
if (pClient->connect(address))
{
delay(100);
bool iphone = true;
if (allowQuery)
{
@ -461,14 +483,18 @@ bool BleFingerprint::query()
if (!sName.empty() && sMdl.find(sName) == std::string::npos && sName != "Apple Watch")
{
if (setId(String("name:") + kebabify(sName).c_str(), ID_TYPE_QUERY_NAME, String(sName.c_str())))
Serial.printf("\u001b[38;5;104m%d Name | MAC: %s, ID: %-60s %s\u001b[0m\n", xPortGetCoreID(), getMac().c_str(), getId().c_str(), sName.c_str());
{
Serial.printf("\u001b[38;5;104m%u Name | MAC: %s, ID: %-60s %s\u001b[0m\n", xPortGetCoreID(), getMac().c_str(), id.c_str(), sName.c_str());
}
success = true;
}
if (!sMdl.empty())
{
if (setId(String("apple:") + kebabify(sMdl).c_str(), ID_TYPE_QUERY_MODEL, String(sMdl.c_str())))
Serial.printf("\u001b[38;5;136m%d Model | MAC: %s, ID: %-60s %s\u001b[0m\n", xPortGetCoreID(), getMac().c_str(), getId().c_str(), sMdl.c_str());
{
Serial.printf("\u001b[38;5;136m%u Model | MAC: %s, ID: %-60s %s\u001b[0m\n", xPortGetCoreID(), getMac().c_str(), id.c_str(), sMdl.c_str());
}
success = true;
}
}
@ -479,7 +505,9 @@ bool BleFingerprint::query()
if (!sRmAst.empty())
{
if (setId(String("roomAssistant:") + kebabify(sRmAst).c_str(), ID_TYPE_RM_ASST))
Serial.printf("\u001b[38;5;129m%d RmAst | MAC: %s, ID: %-60s %s\u001b[0m\n", xPortGetCoreID(), getMac().c_str(), getId().c_str(), sRmAst.c_str());
{
Serial.printf("\u001b[38;5;129m%u RmAst | MAC: %s, ID: %-60s %s\u001b[0m\n", xPortGetCoreID(), getMac().c_str(), id.c_str(), sRmAst.c_str());
}
success = true;
}
}
@ -490,7 +518,7 @@ bool BleFingerprint::query()
if (success) return true;
qryAttempts++;
Serial.printf("%d QryErr| MAC: %s, ID: %-60s rssi %d, try %d, retry after %dms\n", xPortGetCoreID(), getMac().c_str(), getId().c_str(), rssi, qryAttempts, qryDelayMillis);
Serial.printf("%u QryErr| MAC: %s, ID: %-60s rssi %d, try %d, retry after %dms\n", xPortGetCoreID(), getMac().c_str(), id.c_str(), rssi, qryAttempts, qryDelayMillis);
if (qryDelayMillis < 30000)
qryDelayMillis += (1000 * qryAttempts * qryAttempts);
@ -500,3 +528,23 @@ bool BleFingerprint::query()
return true;
}
bool BleFingerprint::shouldCount()
{
bool prevCounting = counting;
if (ignore || !countable)
counting = false;
else if (getMsSinceFirstSeen() <= BleFingerprintCollection::countMs || getMsSinceLastSeen() > BleFingerprintCollection::countMs)
counting = false;
else if (counting && output.value.position > BleFingerprintCollection::countExit)
counting = false;
else if (!counting && output.value.position <= BleFingerprintCollection::countEnter)
counting = true;
if (prevCounting != counting)
{
counting ? GUI::plusOne(this) : GUI::minusOne(this);
}
return counting;
}

View File

@ -15,17 +15,18 @@
#define NO_RSSI (-32768)
#define ID_TYPE_TX_POW short(1)
#define ID_TYPE_MISC_APPLE short(-5)
#define ID_TYPE_MAC short(0)
#define ID_TYPE_AD short(10)
#define ID_TYPE_SD short(15)
#define ID_TYPE_MD short(20)
#define ID_TYPE_MISC_APPLE short(25)
#define ID_TYPE_MISC short(30)
#define ID_TYPE_NAME short(35)
#define ID_TYPE_PUBLIC_MAC short(50)
#define ID_TYPE_MSFT short(100)
#define ID_TYPE_SONOS short(105)
#define ID_TYPE_GARMIN short(107)
#define ID_TYPE_MITHERM short(110)
#define ID_TYPE_MIFIT short(115)
#define ID_TYPE_EXPOSURE short(120)
@ -34,6 +35,7 @@
#define ID_TYPE_TILE short( 135)
#define ID_TYPE_MEATER short(140)
#define ID_TYPE_VANMOOF short(145)
#define ID_TYPE_SMARTTAG short(146)
#define ID_TYPE_APPLE_NEARBY short(150)
#define ID_TYPE_QUERY_MODEL short(155)
#define ID_TYPE_QUERY_NAME short(160)
@ -41,6 +43,7 @@
#define ID_TYPE_ABEACON short(170)
#define ID_TYPE_IBEACON short(175)
#define ID_TYPE_RM_ASST short(180)
#define ID_TYPE_KNOWN_MAC short(185)
class BleFingerprintCollection;
@ -56,13 +59,7 @@ public:
bool query();
String getId()
{
if (!id.isEmpty() && idType > 10) return id;
if (macPublic) return getMac();
if (!id.isEmpty()) return id;
return getMac();
}
String getId() { return id; }
bool setId(const String &newId, short int newIdType, const String &newName = "");
@ -82,7 +79,9 @@ public:
NimBLEAddress const getAddress() { return address; }
long getAge() const { return millis() - lastSeenMillis; };
unsigned long getMsSinceLastSeen() const { return millis() - lastSeenMillis; };
unsigned long getMsSinceFirstSeen() const { return millis() - firstSeenMillis; };
bool getAdded() const { return added; };
@ -92,26 +91,30 @@ public:
bool getRmAsst() const { return rmAsst; };
int getSeenCount()
unsigned int getSeenCount()
{
auto sc = seenCount;
seenCount = 0;
auto sc = seenCount - lastSeenCount;
lastSeenCount = seenCount;
return sc;
}
bool shouldCount();
private:
static bool shouldHide(const String &s);
bool hasValue = false, added = false, close = false, reported = false, macPublic = false, ignore = false, allowQuery = false, didQuery = false, rmAsst = false, hidden = false, connectable = false;
bool hasValue = false, added = false, close = false, reported = false, ignore = false, allowQuery = false, didQuery = false, rmAsst = false, hidden = false, connectable = false, countable = false, counting = false;
NimBLEAddress address;
String id, name, disc;
short int idType = 0;
int rssi = -100, calRssi = NO_RSSI, mdRssi = NO_RSSI, asRssi = NO_RSSI, newest = NO_RSSI, recent = NO_RSSI, oldest = NO_RSSI;
int qryAttempts = 0, seenCount = 1, qryDelayMillis = 0;
unsigned int qryAttempts = 0, qryDelayMillis = 0;
float raw = 0, lastReported = 0, temp = 0, humidity = 0;
unsigned long firstSeenMillis, lastSeenMillis = 0, lastReportedMillis = 0, lastQryMillis = 0;
unsigned long seenCount = 1, lastSeenCount = 0;
uint16_t mv = 0;
uint8_t battery = 0xFF;
Reading<Differential<float>> output;
@ -122,11 +125,11 @@ private:
void fingerprint(NimBLEAdvertisedDevice *advertisedDevice);
void fingerprintServiceAdvertisements(NimBLEAdvertisedDevice *advertisedDevice, size_t serviceAdvCount);
void fingerprintServiceAdvertisements(NimBLEAdvertisedDevice *advertisedDevice, size_t serviceAdvCount, bool haveTxPower, int8_t txPower);
void fingerprintServiceData(NimBLEAdvertisedDevice *advertisedDevice, size_t serviceDataCount);
void fingerprintServiceData(NimBLEAdvertisedDevice *advertisedDevice, size_t serviceDataCount, bool haveTxPower, int8_t txPower);
void fingerprintManufactureData(NimBLEAdvertisedDevice *advertisedDevice);
void fingerprintManufactureData(NimBLEAdvertisedDevice *advertisedDevice, bool haveTxPower, int8_t txPower);
};
#endif

View File

@ -8,7 +8,7 @@ void BleFingerprintCollection::cleanupOldFingerprints()
auto it = fingerprints.begin();
while (it != fingerprints.end())
{
long age = (*it)->getAge();
auto age = (*it)->getMsSinceLastSeen();
if (age > forgetMs)
{
GUI::removed((*it));
@ -54,7 +54,7 @@ BleFingerprint *BleFingerprintCollection::getFingerprint(BLEAdvertisedDevice *ad
return f;
}
std::list<BleFingerprint *> BleFingerprintCollection::getCopy()
const std::list<BleFingerprint *> BleFingerprintCollection::getCopy()
{
if (xSemaphoreTake(fingerprintSemaphore, 1000) != pdTRUE)
log_e("Couldn't take semaphore!");
@ -62,8 +62,13 @@ std::list<BleFingerprint *> BleFingerprintCollection::getCopy()
std::list<BleFingerprint *> copy(fingerprints);
if (xSemaphoreGive(fingerprintSemaphore) != pdTRUE)
log_e("Couldn't give semaphore!");
return copy;
return std::move(copy);
}
String BleFingerprintCollection::include{}, BleFingerprintCollection::exclude{}, BleFingerprintCollection::query{}, BleFingerprintCollection::knownMacs{}, BleFingerprintCollection::countIds{};
float BleFingerprintCollection::skipDistance = 0.0f, BleFingerprintCollection::maxDistance = 0.0f, BleFingerprintCollection::absorption = 3.5f, BleFingerprintCollection::countEnter = 2, BleFingerprintCollection::countExit = 4;
int BleFingerprintCollection::refRssi = 0, BleFingerprintCollection::forgetMs = 0, BleFingerprintCollection::skipMs = 0, BleFingerprintCollection::countMs = 10000;
const std::list<BleFingerprint *>* const BleFingerprintCollection::getNative()
{
return &fingerprints;
}
String BleFingerprintCollection::include{}, BleFingerprintCollection::exclude{}, BleFingerprintCollection::query{};
float BleFingerprintCollection::skipDistance = 0.0f, BleFingerprintCollection::maxDistance = 0.0f, BleFingerprintCollection::absorption = 3.5f;
int BleFingerprintCollection::refRssi = 0, BleFingerprintCollection::forgetMs = 0, BleFingerprintCollection::skipMs = 0;

View File

@ -18,12 +18,15 @@ public:
}
BleFingerprint *getFingerprint(BLEAdvertisedDevice *advertisedDevice);
void cleanupOldFingerprints();
std::list<BleFingerprint *> getCopy();
const std::list<BleFingerprint *>* const getNative();
const std::list<BleFingerprint *> getCopy();
void setDisable(bool disable) { _disable = disable; }
static String include, exclude, query;
static String knownMacs, include, exclude, query;
static float skipDistance, maxDistance, absorption;
static int refRssi, forgetMs, skipMs;
static String countIds;
static float countEnter, countExit;
static int countMs;
private:
bool _disable = false;

View File

@ -1,4 +1,7 @@
#include "GUI.h"
#ifdef M5STICK
#include "tb_display.h"
#endif
#if defined M5STICK
@ -57,8 +60,6 @@ void GUI::erased()
void GUI::connecting()
{
status("Connecting...");
connected(false, false);
#ifdef LED_BUILTIN
if (GUI::statusLed) digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
#endif
@ -85,26 +86,36 @@ void GUI::connected(bool wifi = false, bool mqtt = false)
void GUI::added(BleFingerprint *f)
{
if (f->getIgnore()) return;
Serial.printf("%d New %s | MAC: %s, ID: %-60s %s\n", xPortGetCoreID(), f->getRmAsst() ? "R" : (f->getAllowQuery() ? "Q" : " "), f->getMac().c_str(), f->getId().c_str(), f->getDiscriminator().c_str());
Serial.printf("%u New %s | MAC: %s, ID: %-60s %s\n", xPortGetCoreID(), f->getRmAsst() ? "R" : (f->getAllowQuery() ? "Q" : " "), f->getMac().c_str(), f->getId().c_str(), f->getDiscriminator().c_str());
}
void GUI::removed(BleFingerprint *f)
{
if (f->getIgnore() || !f->getAdded()) return;
Serial.printf("\u001b[38;5;236m%d Del | MAC: %s, ID: %-60s %s\u001b[0m\n", xPortGetCoreID(), f->getMac().c_str(), f->getId().c_str(), f->getDiscriminator().c_str());
Serial.printf("\u001b[38;5;236m%u Del | MAC: %s, ID: %-60s %s\u001b[0m\n", xPortGetCoreID(), f->getMac().c_str(), f->getId().c_str(), f->getDiscriminator().c_str());
}
void GUI::plusOne(BleFingerprint *f)
{
Serial.printf("\u001b[36m%u C# +1 | MAC: %s, ID: %-60s (%.2fm) %lums\u001b[0m\n", xPortGetCoreID(), f->getMac().c_str(), f->getId().c_str(), f->getDistance(), f->getMsSinceLastSeen());
}
void GUI::minusOne(BleFingerprint *f)
{
Serial.printf("\u001b[35m%u C# -1 | MAC: %s, ID: %-60s (%.2fm) %lums\u001b[0m\n", xPortGetCoreID(), f->getMac().c_str(), f->getId().c_str(), f->getDistance(), f->getMsSinceLastSeen());
}
void GUI::close(BleFingerprint *f)
{
if (f->getIgnore()) return;
Serial.printf("\u001b[32m%d Close | MAC: %s, ID: %-60s (%.2fm) %ddBm\u001b[0m\n", xPortGetCoreID(), f->getMac().c_str(), f->getId().c_str(), f->getDistance(), f->getNewestRssi());
Serial.printf("\u001b[32m%u Close | MAC: %s, ID: %-60s (%.2fm) %ddBm\u001b[0m\n", xPortGetCoreID(), f->getMac().c_str(), f->getId().c_str(), f->getDistance(), f->getNewestRssi());
status("C: %s", f->getId().c_str());
}
void GUI::left(BleFingerprint *f)
{
if (f->getIgnore()) return;
Serial.printf("\u001b[33m%d Left | MAC: %s, ID: %-60s (%.2fm) %ddBm\u001b[0m\n", xPortGetCoreID(), f->getMac().c_str(), f->getId().c_str(), f->getDistance(), f->getNewestRssi());
Serial.printf("\u001b[33m%u Left | MAC: %s, ID: %-60s (%.2fm) %ddBm\u001b[0m\n", xPortGetCoreID(), f->getMac().c_str(), f->getId().c_str(), f->getDistance(), f->getNewestRssi());
status("L: %s", f->getId().c_str());
}
@ -112,18 +123,18 @@ void GUI::added(BleFingerprint *f)
{
begin();
#ifdef M5STICK
sprite.fillSprite(TFT_BLACK);
sprite.setTextDatum(MC_DATUM);
char *message;
va_list args;
va_start(args, format);
vasprintf(&message, format, args);
va_end(args);
tb_display_print_String(message);
tb_display_print_String("\n");
#ifdef PLUS
sprite.drawString(message, sprite.width() / 2, sprite.height() / 2, 4);
//drawString(message, sprite.width() / 2, sprite.height() / 2, 4);
#else
sprite.drawString(message, sprite.width() / 2, sprite.height() / 2, 1);
//sprite.drawString(message, sprite.width() / 2, sprite.height() / 2, 1);
#endif
free(message);
dirty = true;
@ -143,29 +154,15 @@ void GUI::added(BleFingerprint *f)
{
#ifdef M5STICK
M5.begin(true, true, false);
M5.Lcd.setRotation(3);
sprite.createSprite(M5.Lcd.width(), M5.Lcd.height());
sprite.setSwapBytes(true);
M5.Axp.ScreenBreath(12);
tb_display_init(3);
#elif defined M5ATOM
M5.begin(false, false, true);
M5.dis.drawpix(0, CRGB(64, 0, 0));
#endif
GUI::init = true;
}
}
void GUI::blit()
{
begin();
#ifdef M5STICK
if (dirty)
{
sprite.pushSprite(0, 0);
M5.Axp.ScreenBreath(12);
dirty = false;
}
#endif
}
void GUI::updateStart()
{
@ -193,5 +190,4 @@ bool GUI::statusLed=false;
#ifdef M5STICK
bool GUI::dirty = false;
TFT_eSprite GUI::sprite(&M5.Lcd);
#endif

View File

@ -40,10 +40,12 @@ public:
static void connected(bool wifi, bool mqtt);
static void status(const char *message, ...);
static void blit();
static bool statusLed;
static void plusOne(BleFingerprint *f);
static void minusOne(BleFingerprint *f);
private:
static void begin();

View File

@ -74,3 +74,49 @@ std::string hexStr(const std::string& s)
{
return hexStr(s.c_str(), s.length());
}
std::string hexStr(const uint8_t *&s, unsigned int len)
{
return hexStr(reinterpret_cast<const char *>(s), len);
}
std::string hexStrRev(const char *data, unsigned int len)
{
constexpr char hexmap[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
std::string s(len * 2, ' ');
for (int i = 0; i < len; ++i)
{
s[len - (2 * i + 1)] = hexmap[(data[i] & 0xF0) >> 4];
s[len - (2 * i + 2)] = hexmap[data[i] & 0x0F];
}
return s;
}
std::string hexStrRev(const uint8_t *&s, unsigned int len)
{
return hexStrRev(reinterpret_cast<const char *>(s), len);
}
std::string hexStrRev(const std::string &s)
{
return hexStrRev(s.c_str(), s.length());
}
bool prefixExists(const String& prefixes, const String& s)
{
unsigned int start = 0;
unsigned int space;
while ((space = prefixes.indexOf(" ", start)) != -1)
{
if (space > start)
{
auto sub = prefixes.substring(start, space);
if (s.indexOf(sub) != -1) return true;
}
start = space + 1;
}
auto sub = prefixes.substring(start);
return !sub.isEmpty() && s.indexOf(sub) != -1;
}

View File

@ -16,6 +16,11 @@ std::string slugify(const std::string& text);
String slugify(const String& text);
std::string kebabify(const std::string& text);
String kebabify(const String& text);
std::string hexStr(const uint8_t *data, int len);
std::string hexStr(const char *data, int len);
std::string hexStr(const std::string& s);
std::string hexStrRev(const uint8_t *data, int len);
std::string hexStrRev(const char *data, int len);
std::string hexStrRev(const std::string &s);
bool prefixExists(const String& prefixes, const String& s);
#endif

View File

@ -7,6 +7,7 @@
static BLEUUID eddystoneUUID((uint16_t)0xFEAA);
static BLEUUID tileUUID((uint16_t)0xFEED);
static BLEUUID exposureUUID((uint16_t)0xFD6F);
static BLEUUID smartTagUUID((uint16_t)0xFD5A);
static BLEUUID sonosUUID((uint16_t)0xFE07);
static BLEUUID itagUUID((uint16_t)0xffe0);
static BLEUUID miThermUUID(uint16_t(0x181A));

View File

@ -14,19 +14,23 @@ default_envs = esp32
[common]
debug_build_flags = -O0 -ggdb3 -g3 -DDEBUG_TLS_MEM
build_flags =
-D MQTT_MAX_PACKET_SIZE=1024
-D MQTT_MIN_FREE_MEMORY=8128
-D SECURE_CLIENT=SECURE_CLIENT_BEARSSL
-D BEARSSL_SSL_BASIC
-D CONFIG_BT_NIMBLE_PINNED_TO_CORE=1
-D CONFIG_BT_NIMBLE_MAX_BONDS=0
-D CONFIG_BT_NIMBLE_MAX_CCCDS=0
-D CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED
-D CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED
-D CONFIG_ASYNC_TCP_USE_WDT=0
platform = espressif32@3.2
framework = arduino
lib_deps =
haimoz/SoftFilters@^0.1.0
marvinroger/AsyncMqttClient@^0.9.0
bblanchon/ArduinoJson@^6.17.3
bblanchon/ArduinoJson@^6.19.3
https://github.com/ESPresense/ESP-WiFiSettings.git
https://github.com/h2zero/NimBLE-Arduino.git#1.3.3
https://github.com/ESPresense/NimBLE-Arduino.git
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
bbx10/DNSServer@^1.1.0
@ -50,7 +54,7 @@ lib_deps = ${common.lib_deps}
board_build.partitions = partitions_singleapp.csv
monitor_port = /dev/cu.usbserial-*1
monitor_speed = 115200
monitor_filters = esp32_exception_decoder
monitor_filters = esp32_exception_decoder, time
debug_build_flags = ${common.debug_build_flags}
build_flags = ${common.build_flags}
@ -101,6 +105,7 @@ framework = ${common.framework}
board = m5stick-c
lib_deps =
m5stack/M5StickC@^0.2.0
https://github.com/ESPresense/M5StickC-TB_Display.git
${common.lib_deps}
board_build.partitions = partitions_singleapp.csv
monitor_speed = 115200
@ -116,6 +121,7 @@ framework = ${common.framework}
board = m5stick-c
lib_deps =
m5stack/M5StickCPlus@^0.0.2
https://github.com/ESPresense/M5StickC-TB_Display.git
${common.lib_deps}
board_build.partitions = partitions_singleapp.csv
monitor_speed = 115200
@ -211,6 +217,7 @@ framework = ${common.framework}
board = m5stick-c
lib_deps =
m5stack/M5StickC@^0.2.0
https://github.com/ESPresense/M5StickC-TB_Display.git
${common.lib_deps}
${common_sensors.lib_deps}
board_build.partitions = partitions_singleapp.csv
@ -228,6 +235,7 @@ framework = ${common.framework}
board = m5stick-c
lib_deps =
m5stack/M5StickCPlus@^0.0.2
https://github.com/ESPresense/M5StickC-TB_Display.git
${common.lib_deps}
${common_sensors.lib_deps}
board_build.partitions = partitions_singleapp.csv

View File

@ -1,31 +1,27 @@
#ifdef VERBOSE
#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
#endif
//Replace with your MQTT Broker address
// Replace with your MQTT Broker address
#define DEFAULT_MQTT_HOST "mqtt.z13.org"
//Replace with your MQTT Broker port
// Replace with your MQTT Broker port
#define DEFAULT_MQTT_PORT 1883
//Replace with your MQTT Broker user
// Replace with your MQTT Broker user
#define DEFAULT_MQTT_USER ""
//Replace with your MQTT Broker password
// Replace with your MQTT Broker password
#define DEFAULT_MQTT_PASSWORD ""
// Maximum distance (in meters) to report. Devices that are calculated to be further than this distance in meters will not be reported
#define DEFAULT_MAX_DISTANCE 16
//Define the base topic for room detection. Usually "espresense"
// Define the base topic for room detection. Usually "espresense"
#define CHANNEL String("espresense")
#define DEFAULT_QUERY ""
#define DEFAULT_INCLUDE ""
#define DEFAULT_EXCLUDE ""
#define BLE_SCAN_INTERVAL 40 // Used to determine antenna sharing between Bluetooth and Wi-Fi. Do not modify unless you are confident you know what you're doing
#define BLE_SCAN_WINDOW 30 // Used to determine antenna sharing between Bluetooth and Wi-Fi. Do not modify unless you are confident you know what you're doing
#define BLE_SCAN_INTERVAL 0x80
#define BLE_SCAN_WINDOW 0x80
#define DEFAULT_REF_RSSI (-65)
#define DEFAULT_ABSORPTION (3.5)
@ -48,8 +44,8 @@
#ifdef VERSION
#define DEFAULT_AUTO_UPDATE true
#define DEFAULT_OTA_UPDATE false
#define DEFAULT_ARDUINO_OTA false
#else
#define DEFAULT_AUTO_UPDATE false
#define DEFAULT_OTA_UPDATE true
#define DEFAULT_ARDUINO_OTA true
#endif

View File

@ -2,7 +2,7 @@
#include "MotionSensors.h"
bool sendTelemetry(int totalSeen, int totalFpSeen, int totalFpQueried, int totalFpReported)
bool sendTelemetry(int totalSeen, int totalFpSeen, int totalFpQueried, int totalFpReported, int count)
{
if (!online)
{
@ -19,7 +19,11 @@ bool sendTelemetry(int totalSeen, int totalFpSeen, int totalFpQueried, int total
if (discovery && !sentDiscovery)
{
if (sendDiscoveryConnectivity() && sendDiscoveryUptime() && sendDiscoveryFreeMem() && sendButtonDiscovery("Restart", "diagnostic") && sendSwitchDiscovery("Status LED", "config") && sendNumberDiscovery("Max Distance", "config") && sendNumberDiscovery("Absorption", "config") && sendSwitchDiscovery("Active Scan", "config") && sendSwitchDiscovery("Auto Update", "config") && sendSwitchDiscovery("OTA Update", "config") && sendSwitchDiscovery("Prerelease", "config") && sendDeleteDiscovery("switch", "Query") && Motion::SendDiscovery(doc)
if (sendDiscoveryConnectivity() && sendTeleSensorDiscovery("Uptime", EC_DIAGNOSTIC, "{{ value_json.uptime }}", "s") && sendTeleSensorDiscovery("Free Mem", EC_DIAGNOSTIC, "{{ value_json.freeHeap }}", "bytes") && (BleFingerprintCollection::countIds.isEmpty() ? sendDeleteDiscovery("sensor", "Count") : sendTeleSensorDiscovery("Count", "", "{{ value_json.count }}", "")) && sendButtonDiscovery("Restart", EC_DIAGNOSTIC) && sendSwitchDiscovery("Status LED", EC_CONFIG) && sendNumberDiscovery("Max Distance", EC_CONFIG) && sendNumberDiscovery("Absorption", EC_CONFIG) && sendSwitchDiscovery("Active Scan", EC_CONFIG) && sendSwitchDiscovery("Auto Update", EC_CONFIG) && sendSwitchDiscovery("Arduino OTA", EC_CONFIG) && sendSwitchDiscovery("Prerelease", EC_CONFIG) && sendDeleteDiscovery("switch", "OTA Update") && Motion::SendDiscovery(doc)
#ifdef MACCHINA_A0
&& sendTeleSensorDiscovery("Battery", "", "{{ value_json.batt }}", "%")
&& sendTeleBinarySensorDiscovery("Running", "", "{{ value_json.run }}", "running")
#endif
#ifdef SENSORS
&& sendDiscoveryHumidity() && sendDiscoveryTemperature() && sendDiscoveryLux() && sendDiscoveryBME280Temperature() && sendDiscoveryBME280Humidity() && sendDiscoveryBME280Pressure() && sendDiscoveryTSL2561Lux()
#endif
@ -48,11 +52,19 @@ bool sendTelemetry(int totalSeen, int totalFpSeen, int totalFpQueried, int total
#endif
doc["rssi"] = WiFi.RSSI();
#ifdef MACCHINA_A0
doc["batt"] = a0_read_batt_mv() / 1000.0f;
auto mv = a0_read_batt_mv();
doc["mV"] = mv;
bool run = (mv > 13200);
unsigned int soc = round(-13275.04 + 2.049731 * mv - (0.00007847975 * mv) * mv);
doc["batt"] = run ? (unsigned int)100 : max((unsigned int)0, min((unsigned int)100, soc));
doc["run"] = run ? "ON" : "OFF";
#endif
#ifdef VERSION
doc["ver"] = String(VERSION);
#endif
if (!BleFingerprintCollection::countIds.isEmpty())
doc["count"] = count;
if (totalSeen > 0)
doc["adverts"] = totalSeen;
if (totalFpSeen > 0)
@ -90,12 +102,7 @@ bool sendTelemetry(int totalSeen, int totalFpSeen, int totalFpQueried, int total
void connectToWifi()
{
Serial.printf("Connecting to WiFi (%s)...\n", WiFi.macAddress().c_str());
GUI::blit();
WiFiSettings.onConnect = []()
{
GUI::connected(false, false);
};
GUI::connected(false, false);
WiFiSettings.onFailure = []()
{
@ -118,46 +125,54 @@ void connectToWifi()
#endif
room = WiFiSettings.string("room", ESPMAC, "Room");
WiFiSettings.heading("MQTT Connection");
WiFiSettings.heading("MQTT <a href='https://espresense.com/settings#mqtt' target='_blank'></a>", false);
mqttHost = WiFiSettings.string("mqtt_host", DEFAULT_MQTT_HOST, "Server");
mqttPort = WiFiSettings.integer("mqtt_port", DEFAULT_MQTT_PORT, "Port");
mqttUser = WiFiSettings.string("mqtt_user", DEFAULT_MQTT_USER, "Username");
mqttPass = WiFiSettings.string("mqtt_pass", DEFAULT_MQTT_PASSWORD, "Password");
WiFiSettings.heading("Preferences");
GUI::statusLed = WiFiSettings.checkbox("status_led", true, "Status LED");
autoUpdate = WiFiSettings.checkbox("auto_update", DEFAULT_AUTO_UPDATE, "Automatically update");
prerelease = WiFiSettings.checkbox("prerelease", false, "Include pre-released versions in auto-update");
otaUpdate = WiFiSettings.checkbox("ota_update", DEFAULT_OTA_UPDATE, "Arduino OTA Update");
discovery = WiFiSettings.checkbox("discovery", true, "Home Assistant Discovery");
activeScan = WiFiSettings.checkbox("active_scan", false, "Active scanning (uses more battery but more results)");
discovery = WiFiSettings.checkbox("discovery", true, "Send to discovery topic");
publishTele = WiFiSettings.checkbox("pub_tele", true, "Send to telemetry topic");
publishRooms = WiFiSettings.checkbox("pub_rooms", true, "Send to rooms topic");
publishDevices = WiFiSettings.checkbox("pub_devices", true, "Send to devices topic");
WiFiSettings.heading("Filtering");
WiFiSettings.heading("Room Count <a href='https://espresense.com/settings#room-count' target='_blank'></a>", false);
BleFingerprintCollection::countIds = WiFiSettings.string("count_ids", "", "Include device ids (space seperated ids)");
BleFingerprintCollection::countEnter = WiFiSettings.floating("count_enter", 0, 100, 2, "Start counting devices less than distance (in meters)");
BleFingerprintCollection::countExit = WiFiSettings.floating("count_exit", 0, 100, 4, "Stop counting devices greater than distance (in meters)");
BleFingerprintCollection::countMs = WiFiSettings.integer("count_ms", 0, 3000000, 30000, "Include devices with age less than (in ms)");
WiFiSettings.heading("Updating <a href='https://espresense.com/settings#updating' target='_blank'></a>", false);
autoUpdate = WiFiSettings.checkbox("auto_update", DEFAULT_AUTO_UPDATE, "Automatically update");
prerelease = WiFiSettings.checkbox("prerelease", false, "Include pre-released versions in auto-update");
arduinoOta = WiFiSettings.checkbox("arduino_ota", DEFAULT_ARDUINO_OTA, "Arduino OTA Update");
WiFiSettings.heading("Scanning <a href='https://espresense.com/settings#scanning' target='_blank'></a>", false);
activeScan = WiFiSettings.checkbox("active_scan", false, "Request scan results (usually not needed)");
BleFingerprintCollection::knownMacs = WiFiSettings.string("known_macs", "", "Known BLE mac addresses (no colons, space seperated)");
BleFingerprintCollection::query = WiFiSettings.string("query", DEFAULT_QUERY, "Query device ids for characteristics (eg. apple:1005:9-26)");
WiFiSettings.heading("Filtering <a href='https://espresense.com/settings#filtering' target='_blank'></a>", false);
if (BleFingerprintCollection::query == "1") BleFingerprintCollection::query = "apple:10"; // This is to keep query=true doing the same thing as older firmwares
BleFingerprintCollection::include = WiFiSettings.string("include", DEFAULT_INCLUDE, "If set will only send matching to mqtt (eg. apple:iphone10-6 apple:iphone13-2)");
BleFingerprintCollection::include = WiFiSettings.string("include", DEFAULT_INCLUDE, "Include only sending these ids to mqtt (eg. apple:iphone10-6 apple:iphone13-2)");
BleFingerprintCollection::exclude = WiFiSettings.string("exclude", DEFAULT_EXCLUDE, "Exclude sending these ids to mqtt (eg. exp:20 apple:iphone10-6)");
BleFingerprintCollection::maxDistance = WiFiSettings.floating("max_dist", 0, 100, DEFAULT_MAX_DISTANCE, "Maximum distance to report (in meters)");
BleFingerprintCollection::skipDistance = WiFiSettings.floating("skip_dist", 0, 10, DEFAULT_SKIP_DISTANCE, "Report early if beacon has moved more than this distance (in meters)");
BleFingerprintCollection::skipMs = WiFiSettings.integer("skip_ms", 0, 3000000, DEFAULT_SKIP_MS, "Skip reporting if message age is less that this (in milliseconds)");
WiFiSettings.heading("Calibration");
WiFiSettings.heading("Calibration <a href='https://espresense.com/settings#calibration' target='_blank'></a>", false);
BleFingerprintCollection::refRssi = WiFiSettings.integer("ref_rssi", -100, 100, DEFAULT_REF_RSSI, "Rssi expected from a 0dBm transmitter at 1 meter");
BleFingerprintCollection::absorption = WiFiSettings.floating("absorption", -100, 100, DEFAULT_ABSORPTION, "Factor used to account for absorption, reflection, or diffraction");
BleFingerprintCollection::forgetMs = WiFiSettings.integer("forget_ms", 0, 3000000, DEFAULT_FORGET_MS, "Forget beacon if not seen for (in milliseconds)");
WiFiSettings.heading("Additional Sensors");
WiFiSettings.heading("Misc <a href='https://espresense.com/settings#misc' target='_blank'></a>", false);
GUI::statusLed = WiFiSettings.checkbox("status_led", true, "Status LED");
Motion::ConnectToWifi();
#ifdef SENSORS
dht11Pin = WiFiSettings.integer("dht11_pin", 0, "DHT11 sensor pin (0 for disable)");
dht22Pin = WiFiSettings.integer("dht22_pin", 0, "DHT22 sensor pin (0 for disable)");
dhtTempOffset = WiFiSettings.floating("dhtTemp_offset", -40, 125, 0.0, "DHT temperature offset");
WiFiSettings.heading("I2C Settings");
WiFiSettings.heading("I2C Settings <a href='https://espresense.com/settings#i2c-settings' target='_blank'></a>", false);
I2CDebug = WiFiSettings.checkbox("I2CDebug", false, "Debug I2C addreses. Look at the serial log to get the correct address");
@ -170,7 +185,7 @@ void connectToWifi()
I2C_Bus_2_SDA = WiFiSettings.integer("I2C_Bus_2_SDA", 0, "SDA pin (0 to disable)");
I2C_Bus_2_SCL = WiFiSettings.integer("I2C_Bus_2_SCL", 0, "SCL pin (0 to disable)");
WiFiSettings.heading("I2C Sensors");
WiFiSettings.heading("I2C Sensors <a href='https://espresense.com/settings#i2c-sensors' target='_blank'></a>", false);
WiFiSettings.html("h4", "BH1750 - Ambient Light Sensor:");
BH1750_I2c_Bus = WiFiSettings.integer("BH1750_I2c_Bus", 1, 2, DEFAULT_I2C_BUS, "I2C Bus");
@ -190,9 +205,11 @@ void connectToWifi()
if (!WiFiSettings.connect(true, 60))
ESP.restart();
#ifdef FIRMWARE
Serial.println("Firmware: " + String(FIRMWARE));
#endif
#ifdef VERSION
Serial.println("Version: " + String(VERSION));
Serial.println("Version: " + String(VERSION));
#endif
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
@ -204,20 +221,14 @@ void connectToWifi()
Serial.println(room);
Serial.printf("MQTT server: %s:%d\n", mqttHost.c_str(), mqttPort);
Serial.printf("Max Distance: %.2f\n", BleFingerprintCollection::maxDistance);
Serial.print("Telemetry: ");
Serial.println(publishTele ? "enabled" : "disabled");
Serial.print("Rooms: ");
Serial.println(publishRooms ? "enabled" : "disabled");
Serial.print("Devices: ");
Serial.println(publishDevices ? "enabled" : "disabled");
Serial.print("Discovery: ");
Serial.println(discovery ? "enabled" : "disabled");
Motion::SerialReport();
#ifdef SENSORS
Serial.print("DHT11 Sensor: ");
Serial.println(dht11Pin ? "enabled" : "disabled");
Serial.print("DHT22 Sensor: ");
Serial.println(dht22Pin ? "enabled" : "disabled");
Serial.print("DHT Temp Offset: ");
Serial.println(dhtTempOffset ? "enabled" : "disabled");
Serial.print("BH1750_I2c Sensor: ");
Serial.println(BH1750_I2c + " on bus " + BH1750_I2c_Bus);
Serial.print("BME280_I2c Sensor: ");
@ -232,6 +243,10 @@ void connectToWifi()
Serial.println(BleFingerprintCollection::include);
Serial.print("Exclude: ");
Serial.println(BleFingerprintCollection::exclude);
Serial.print("Known Macs: ");
Serial.println(BleFingerprintCollection::knownMacs);
Serial.print("Count Ids: ");
Serial.println(BleFingerprintCollection::countIds);
localIp = WiFi.localIP().toString();
id = slugify(room);
@ -309,16 +324,28 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties
spurt("/exclude", pay);
online = false;
}
else if (command == "known_macs")
{
BleFingerprintCollection::knownMacs = pay;
spurt("/known_macs", pay);
online = false;
}
else if (command == "count_ids")
{
BleFingerprintCollection::countIds = pay;
spurt("/count_ids", pay);
online = false;
}
else if (command == "status_led")
{
GUI::statusLed = pay == "ON";
spurt("/status_led", String(GUI::statusLed));
online = false;
}
else if (command == "ota_update")
else if (command == "arduino_ota")
{
otaUpdate = pay == "ON";
spurt("/ota_update", String(otaUpdate));
arduinoOta = pay == "ON";
spurt("/arduino_ota", String(arduinoOta));
online = false;
}
else if (command == "auto_update")
@ -345,7 +372,7 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties
void reconnect(TimerHandle_t xTimer)
{
Serial.printf("%d Reconnect timer\n", xPortGetCoreID());
Serial.printf("%u Reconnect timer\n", xPortGetCoreID());
if (updateInProgress) return;
if (WiFi.isConnected() && mqttClient.connected()) return;
@ -357,12 +384,12 @@ void reconnect(TimerHandle_t xTimer)
if (!WiFi.isConnected())
{
Serial.printf("%d Reconnecting to WiFi...\n", xPortGetCoreID());
Serial.printf("%u Reconnecting to WiFi...\n", xPortGetCoreID());
if (!WiFiSettings.connect(true, 60))
ESP.restart();
}
Serial.printf("%d Reconnecting to MQTT...\n", xPortGetCoreID());
Serial.printf("%u Reconnecting to MQTT...\n", xPortGetCoreID());
mqttClient.connect();
}
@ -407,29 +434,14 @@ bool reportDevice(BleFingerprint *f)
return false;
}
void scanForDevices(void *parameter)
int totalFpReported = 0;
int totalSeen = 0;
int totalFpSeen = 0;
int totalFpQueried = 0;
void reportTask(void *parameter)
{
connectToMqtt();
BLEDevice::init("");
for (esp_ble_power_type_t i = ESP_BLE_PWR_TYPE_CONN_HDL0; i <= ESP_BLE_PWR_TYPE_CONN_HDL8; i = esp_ble_power_type_t((int)i + 1))
NimBLEDevice::setPower(ESP_PWR_LVL_P9, i);
NimBLEDevice::setSecurityAuth(false, false, false);
auto pBLEScan = BLEDevice::getScan();
pBLEScan->setInterval(BLE_SCAN_INTERVAL);
pBLEScan->setWindow(BLE_SCAN_WINDOW);
pBLEScan->setAdvertisedDeviceCallbacks(&fingerprints, true);
if (activeScan) pBLEScan->setActiveScan(true);
pBLEScan->setDuplicateFilter(false);
pBLEScan->setMaxResults(0);
// pBLEScan->setFilterPolicy(BLE_HCI_SCAN_FILT_NO_WL_INITA);
if (!pBLEScan->start(0, nullptr, false))
log_e("Error starting continuous ble scan");
int totalSeen = 0;
int totalFpSeen = 0;
int totalFpQueried = 0;
int totalFpReported = 0;
while (true)
{
@ -439,28 +451,14 @@ void scanForDevices(void *parameter)
yield();
auto copy = fingerprints.getCopy();
sendTelemetry(totalSeen, totalFpSeen, totalFpQueried, totalFpReported);
int count = 0;
for (auto i: copy)
if (i->shouldCount())
count++;
yield();
sendTelemetry(totalSeen, totalFpSeen, totalFpQueried, totalFpReported, count);
yield();
if (millis() - lastQueryMillis > 3000)
{
auto started = millis();
for (auto f : copy)
{
if (f->query())
totalFpQueried++;
if (millis() - started > 3000) break;
}
if (!pBLEScan->isScanning())
{
if (!pBLEScan->start(0, nullptr, true))
log_e("Error re-starting continuous ble scan");
lastQueryMillis = millis(); // If we stopped scanning, don't query for 3 seconds in order for us to catch any missed broadcasts
}
}
auto reported = 0;
for (auto f : copy)
@ -476,6 +474,45 @@ void scanForDevices(void *parameter)
totalFpReported++;
reported++;
}
yield();
}
}
}
void scanTask(void *parameter)
{
NimBLEDevice::init("");
for (esp_ble_power_type_t i = ESP_BLE_PWR_TYPE_CONN_HDL0; i <= ESP_BLE_PWR_TYPE_CONN_HDL8; i = esp_ble_power_type_t((int)i + 1))
NimBLEDevice::setPower(ESP_PWR_LVL_P9, i);
NimBLEDevice::setSecurityAuth(true, true, true);
NimBLEDevice::setSecurityRespKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
NimBLEDevice::setMTU(255);
auto pBLEScan = NimBLEDevice::getScan();
pBLEScan->setInterval(BLE_SCAN_INTERVAL);
pBLEScan->setWindow(BLE_SCAN_WINDOW);
pBLEScan->setAdvertisedDeviceCallbacks(&fingerprints, true);
pBLEScan->setActiveScan(activeScan);
pBLEScan->setDuplicateFilter(false);
pBLEScan->setMaxResults(0);
if (!pBLEScan->start(0, nullptr, false))
log_e("Error starting continuous ble scan");
while (true)
{
for (auto f : *fingerprints.getNative())
if (f->query())
totalFpQueried++;
if (!pBLEScan->isScanning())
{
if (!pBLEScan->start(0, nullptr, true))
log_e("Error re-starting continuous ble scan");
delay(3000); // If we stopped scanning, don't query for 3 seconds in order for us to catch any missed broadcasts
}
else
{
delay(100);
}
}
}
@ -540,7 +577,9 @@ void setup()
setClock();
#endif
Motion::Setup();
#if MACCHINA_A0
pinMode(GPIO_NUM_35, INPUT);
#endif
#ifdef SENSORS
if (dht11Pin) dhtSensor.setup(dht11Pin, DHTesp::DHT11);
if (dht22Pin) dhtSensor.setup(dht22Pin, DHTesp::DHT22); //(AM2302)
@ -596,7 +635,7 @@ void setup()
{
// Init BH1750 (witch default l2c adres)
int rc; // Returncode
long m; // milli for calibration
unsigned long m; // milli for calibration
bool state = false;
// if (! BH1750.begin(BH1750_TO_GROUND))
@ -646,7 +685,8 @@ void setup()
}
}
#endif
xTaskCreatePinnedToCore(scanForDevices, "scanForDevices", 6000, nullptr, 1, &scannerTask, 1);
xTaskCreatePinnedToCore(scanTask, "scanTask", 7168, nullptr, 2, &scanTaskHandle, CONFIG_BT_NIMBLE_PINNED_TO_CORE);
xTaskCreatePinnedToCore(reportTask, "reportTask", 7168, nullptr, 1, &reportTaskHandle, 1);
configureOTA();
}
@ -658,11 +698,11 @@ void dhtLoop()
if (gotNewTemperature)
{
float humidity = dhtSensorData.humidity;
float temperature = dhtSensorData.temperature;
Serial.println("Temp: " + String(temperature, 2) + "'C Humidity: " + String(humidity, 1) + "%");
float temperature = dhtSensorData.temperature + dhtTempOffset;
Serial.println("Temp: " + String(temperature, 1) + "'C Humidity: " + String(humidity, 1) + "%");
mqttClient.publish((roomsTopic + "/humidity").c_str(), 0, 1, String(humidity).c_str());
mqttClient.publish((roomsTopic + "/temperature").c_str(), 0, 1, String(temperature).c_str());
mqttClient.publish((roomsTopic + "/humidity").c_str(), 0, 1, String(humidity, 1).c_str());
mqttClient.publish((roomsTopic + "/temperature").c_str(), 0, 1, String(temperature, 1).c_str());
gotNewTemperature = false;
}
@ -897,12 +937,11 @@ void l2cScanner()
void loop()
{
int freeHeap = ESP.getFreeHeap();
if (otaUpdate && freeHeap > 4096)
uint32_t freeHeap = ESP.getFreeHeap();
if (arduinoOta && freeHeap > 4096)
ArduinoOTA.handle();
if (freeHeap < 10000) Serial.printf("Low memory: %d bytes free", freeHeap);
if (freeHeap < 10000) Serial.printf("Low memory: %u bytes free", freeHeap);
firmwareUpdate();
GUI::blit();
Motion::Loop(mqttClient);
#ifdef SENSORS
dhtLoop();

View File

@ -41,7 +41,7 @@ unsigned long sensorInterval = 60000;
//GY-302 lux sensor
#include <hp_BH1750.h>
hp_BH1750 BH1750;
long ms_BH1750;
unsigned long ms_BH1750;
float lux_BH1750;
int lux_BH1750_MQTT;
String BH1750_I2c;
@ -63,41 +63,37 @@ String TSL2561_I2c_Gain;
unsigned long tsl2561PreviousMillis = 0;
#endif
static const char *const EC_DIAGNOSTIC = "diagnostic";
static const char *const EC_CONFIG = "config";
AsyncMqttClient mqttClient;
TimerHandle_t reconnectTimer;
TaskHandle_t scannerTask;
TaskHandle_t scanTaskHandle, reportTaskHandle;
DynamicJsonDocument doc(2048);
char buffer[2048];
bool updateInProgress = false;
String localIp;
unsigned long lastTeleMillis, lastQueryMillis;
unsigned long lastTeleMillis;
int reconnectTries = 0;
int teleFails = 0;
bool online = false; // Have we successfully sent status=online
bool sentDiscovery = false; // Have we successfully sent discovery
String offline = "offline";
String mqttHost;
int mqttPort;
String mqttUser;
String mqttPass;
String room;
String id;
String statusTopic;
String teleTopic;
String roomsTopic;
String setTopic;
bool autoUpdate, otaUpdate, prerelease;
bool discovery;
bool activeScan;
bool publishTele;
bool publishRooms;
bool publishDevices;
String mqttHost, mqttUser, mqttPass;
uint16_t mqttPort;
String room, id, statusTopic, teleTopic, roomsTopic, setTopic;
bool autoUpdate, arduinoOta, prerelease;
bool discovery, activeScan, publishTele, publishRooms, publishDevices;
#ifdef SENSORS
int dht11Pin;
int dht22Pin;
uint8_t dht11Pin;
uint8_t dht22Pin;
float dhtTempOffset;
/** Initialize DHT sensor 1 */
DHTesp dhtSensor;
@ -185,7 +181,7 @@ void setClock()
void configureOTA()
{
if (!otaUpdate) return;
if (!arduinoOta) return;
ArduinoOTA
.onStart([]()
{
@ -296,7 +292,7 @@ void spiffsInit()
int flashes = 0;
unsigned long debounceDelay = 250;
long lastDebounceTime = millis();
unsigned long lastDebounceTime = millis();
while (digitalRead(BUTTON) == BUTTON_PRESSED)
{
if ((millis() - lastDebounceTime) > debounceDelay)
@ -336,7 +332,7 @@ bool pub(const char *topic, uint8_t qos, bool retain, const char *payload, size_
bool sendOnline()
{
return pub(statusTopic.c_str(), 0, true, "online") && pub((roomsTopic + "/max_distance").c_str(), 0, true, String(BleFingerprintCollection::maxDistance).c_str()) && pub((roomsTopic + "/absorption").c_str(), 0, true, String(BleFingerprintCollection::absorption).c_str()) && pub((roomsTopic + "/query").c_str(), 0, true, BleFingerprintCollection::query.c_str()) && pub((roomsTopic + "/include").c_str(), 0, true, BleFingerprintCollection::include.c_str()) && pub((roomsTopic + "/exclude").c_str(), 0, true, BleFingerprintCollection::exclude.c_str()) && pub((roomsTopic + "/status_led").c_str(), 0, true, String(GUI::statusLed ? "ON" : "OFF").c_str()) && pub((roomsTopic + "/ota_update").c_str(), 0, true, String(otaUpdate ? "ON" : "OFF").c_str()) && pub((roomsTopic + "/auto_update").c_str(), 0, true, String(autoUpdate ? "ON" : "OFF").c_str()) && pub((roomsTopic + "/prerelease").c_str(), 0, true, String(prerelease ? "ON" : "OFF").c_str()) && pub((roomsTopic + "/active_scan").c_str(), 0, true, String(activeScan ? "ON" : "OFF").c_str());
return pub(statusTopic.c_str(), 0, true, "online") && pub((roomsTopic + "/max_distance").c_str(), 0, true, String(BleFingerprintCollection::maxDistance).c_str()) && pub((roomsTopic + "/absorption").c_str(), 0, true, String(BleFingerprintCollection::absorption).c_str()) && pub((roomsTopic + "/query").c_str(), 0, true, BleFingerprintCollection::query.c_str()) && pub((roomsTopic + "/include").c_str(), 0, true, BleFingerprintCollection::include.c_str()) && pub((roomsTopic + "/exclude").c_str(), 0, true, BleFingerprintCollection::exclude.c_str()) && pub((roomsTopic + "/known_macs").c_str(), 0, true, BleFingerprintCollection::knownMacs.c_str()) && pub((roomsTopic + "/count_ids").c_str(), 0, true, BleFingerprintCollection::countIds.c_str()) && pub((roomsTopic + "/status_led").c_str(), 0, true, String(GUI::statusLed ? "ON" : "OFF").c_str()) && pub((roomsTopic + "/arduino_ota").c_str(), 0, true, String(arduinoOta ? "ON" : "OFF").c_str()) && pub((roomsTopic + "/auto_update").c_str(), 0, true, String(autoUpdate ? "ON" : "OFF").c_str()) && pub((roomsTopic + "/prerelease").c_str(), 0, true, String(prerelease ? "ON" : "OFF").c_str()) && pub((roomsTopic + "/active_scan").c_str(), 0, true, String(activeScan ? "ON" : "OFF").c_str());
}
void commonDiscovery()
@ -378,38 +374,40 @@ bool sendDiscoveryConnectivity()
return pub(discoveryTopic.c_str(), 0, true, buffer);
}
bool sendDiscoveryUptime()
bool sendTeleBinarySensorDiscovery(const String &name, const String &entityCategory, const String &temp, const String &devClass)
{
auto slug = slugify(name);
commonDiscovery();
doc["~"] = roomsTopic;
doc["name"] = "ESPresense " + room + " Uptime";
doc["uniq_id"] = Sprintf("espresense_%06" PRIx64 "_uptime", ESP.getEfuseMac() >> 24);
doc["name"] = Sprintf("ESPresense %s %s", room.c_str(), name.c_str());
doc["uniq_id"] = Sprintf("espresense_%06" PRIx64 "_%s", ESP.getEfuseMac() >> 24, slug.c_str());
doc["avty_t"] = "~/status";
doc["stat_t"] = "~/telemetry";
doc["entity_category"] = "diagnostic";
doc["value_template"] = "{{ value_json.uptime }}";
doc["unit_of_measurement"] = "s";
if (!entityCategory.isEmpty()) doc["entity_category"] = entityCategory;
doc["value_template"] = temp;
doc["dev_cla"] = devClass;
serializeJson(doc, buffer);
String discoveryTopic = "homeassistant/sensor/espresense_" + ESPMAC + "/uptime/config";
String discoveryTopic = "homeassistant/binary_sensor/espresense_" + ESPMAC + "/" + slug + "/config";
return pub(discoveryTopic.c_str(), 0, true, buffer);
}
bool sendDiscoveryFreeMem()
bool sendTeleSensorDiscovery(const String &name, const String &entityCategory, const String &temp, const String &units)
{
auto slug = slugify(name);
commonDiscovery();
doc["~"] = roomsTopic;
doc["name"] = "ESPresense " + room + " Free Memory";
doc["uniq_id"] = Sprintf("espresense_%06" PRIx64 "_free_mem", ESP.getEfuseMac() >> 24);
doc["name"] = Sprintf("ESPresense %s %s", room.c_str(), name.c_str());
doc["uniq_id"] = Sprintf("espresense_%06" PRIx64 "_%s", ESP.getEfuseMac() >> 24, slug.c_str());
doc["avty_t"] = "~/status";
doc["stat_t"] = "~/telemetry";
doc["entity_category"] = "diagnostic";
doc["value_template"] = "{{ value_json.maxAllocHeap }}";
doc["unit_of_measurement"] = "bytes";
if (!entityCategory.isEmpty()) doc["entity_category"] = entityCategory;
doc["value_template"] = temp;
if (!units.isEmpty()) doc["unit_of_measurement"] = units;
serializeJson(doc, buffer);
String discoveryTopic = "homeassistant/sensor/espresense_" + ESPMAC + "/free_mem/config";
String discoveryTopic = "homeassistant/sensor/espresense_" + ESPMAC + "/" + slug + "/config";
return pub(discoveryTopic.c_str(), 0, true, buffer);
}
@ -654,9 +652,15 @@ bool spurt(const String &fn, const String &content)
}
#ifdef MACCHINA_A0
int smoothMilliVolts;
int a0_read_batt_mv()
{
float vout = ((float)analogRead(GPIO_NUM_35) + 35) / 215.0;
return vout * 1100; // V to mV with +10% correction
int mv = round(((float)analogRead(GPIO_NUM_35) + 35) / 0.215);
if (smoothMilliVolts)
smoothMilliVolts = round(0.1 * (mv - smoothMilliVolts) + smoothMilliVolts);
else
smoothMilliVolts = mv;
return smoothMilliVolts;
}
#endif