From 15a3f8c5296e860d34d7b069af73ccba28939dfb Mon Sep 17 00:00:00 2001 From: flush <93215916+0Flush0@users.noreply.github.com> Date: Tue, 22 Aug 2023 12:44:43 +0200 Subject: [PATCH] Added support for the Xioami Flower Care sensor (#779) * Remove room assistant support since irks are far superior * Bunch of refactors and reorgs --------- Co-authored-by: Yashar Zenker Co-authored-by: DTTerastar --- lib/BleFingerprint/BleFingerprint.cpp | 99 +++++-------- lib/BleFingerprint/BleFingerprint.h | 19 ++- .../BleFingerprintCollection.cpp | 2 +- lib/BleFingerprint/BleFingerprintCollection.h | 2 +- lib/BleFingerprint/QueryReport.h | 17 +++ lib/BleFingerprint/rssi.h | 22 +-- lib/BleFingerprint/string_utils.h | 2 +- lib/handlers/MiFloraHandler.cpp | 137 ++++++++++++++++++ lib/handlers/MiFloraHandler.h | 18 +++ lib/handlers/NameModelHandler.cpp | 24 +++ lib/handlers/NameModelHandler.h | 14 ++ platformio.ini | 10 +- src/GUI.cpp | 2 +- src/HttpWebServer.cpp | 8 +- src/I2C.cpp | 2 +- src/LEDs.cpp | 2 +- src/Switch.cpp | 6 +- src/Updater.cpp | 4 +- src/main.cpp | 52 +++++-- 19 files changed, 324 insertions(+), 118 deletions(-) create mode 100644 lib/BleFingerprint/QueryReport.h create mode 100644 lib/handlers/MiFloraHandler.cpp create mode 100644 lib/handlers/MiFloraHandler.h create mode 100644 lib/handlers/NameModelHandler.cpp create mode 100644 lib/handlers/NameModelHandler.h diff --git a/lib/BleFingerprint/BleFingerprint.cpp b/lib/BleFingerprint/BleFingerprint.cpp index c9a56b6..cefbb9e 100644 --- a/lib/BleFingerprint/BleFingerprint.cpp +++ b/lib/BleFingerprint/BleFingerprint.cpp @@ -1,5 +1,7 @@ #include "BleFingerprint.h" +#include "../handlers/MiFloraHandler.h" +#include "../handlers/NameModelHandler.h" #include "BleFingerprintCollection.h" #include "mbedtls/aes.h" #include "rssi.h" @@ -76,13 +78,13 @@ BleFingerprint::BleFingerprint(BLEAdvertisedDevice *advertisedDevice, float fcmi addressType = advertisedDevice->getAddressType(); newest = recent = oldest = rssi = advertisedDevice->getRSSI(); seenCount = 1; - + queryReport = nullptr; fingerprintAddress(); } void BleFingerprint::fingerprint(NimBLEAdvertisedDevice *advertisedDevice) { if (advertisedDevice->haveName()) { - std::string name = advertisedDevice->getName(); + const std::string name = advertisedDevice->getName(); if (!name.empty()) setId(String("name:") + kebabify(name).c_str(), ID_TYPE_NAME, String(name.c_str())); } @@ -100,20 +102,20 @@ void BleFingerprint::fingerprint(NimBLEAdvertisedDevice *advertisedDevice) { } int bt_encrypt_be(const uint8_t *key, const uint8_t *plaintext, uint8_t *enc_data) { - mbedtls_aes_context s = {0}; - mbedtls_aes_init(&s); + mbedtls_aes_context ctx; + mbedtls_aes_init(&ctx); - if (mbedtls_aes_setkey_enc(&s, key, 128) != 0) { - mbedtls_aes_free(&s); + if (mbedtls_aes_setkey_enc(&ctx, key, 128) != 0) { + mbedtls_aes_free(&ctx); return BLE_HS_EUNKNOWN; } - if (mbedtls_aes_crypt_ecb(&s, MBEDTLS_AES_ENCRYPT, plaintext, enc_data) != 0) { - mbedtls_aes_free(&s); + if (mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, plaintext, enc_data) != 0) { + mbedtls_aes_free(&ctx); return BLE_HS_EUNKNOWN; } - mbedtls_aes_free(&s); + mbedtls_aes_free(&ctx); return 0; } @@ -144,7 +146,7 @@ bool ble_ll_resolv_rpa(const uint8_t *rpa, const uint8_t *irk) { ecb.plain_text[14] = rpa[4]; ecb.plain_text[13] = rpa[5]; - auto err = bt_encrypt_be(ecb.key, ecb.plain_text, ecb.cipher_text); + bt_encrypt_be(ecb.key, ecb.plain_text, ecb.cipher_text); if (ecb.cipher_text[15] != rpa[0] || ecb.cipher_text[14] != rpa[1] || ecb.cipher_text[13] != rpa[2]) return false; @@ -165,7 +167,7 @@ void BleFingerprint::fingerprintAddress() { break; case BLE_ADDR_RANDOM: case BLE_ADDR_RANDOM_ID: { - auto naddress = address.getNative(); + const auto *naddress = address.getNative(); if ((naddress[5] & 0xc0) == 0xc0) setId(mac, ID_TYPE_RAND_STATIC_MAC); else { @@ -193,18 +195,7 @@ void BleFingerprint::fingerprintServiceAdvertisements(NimBLEAdvertisedDevice *ad #ifdef VERBOSE Serial.printf("Verbose | %s | %-58s%ddBm AD: %s\r\n", getMac().c_str(), getId().c_str(), rssi, advertisedDevice->getServiceUUID(i).toString().c_str()); #endif - if (uuid == roomAssistantService) { - asRssi = BleFingerprintCollection::rxRefRssi + RM_ASST_TX; - if (!rmAsst) { - rmAsst = true; - if (didQuery) { - qryDelayMillis = 0; - qryAttempts = 0; - didQuery = false; - } - } - return; - } else if (uuid == tileUUID) { + if (uuid == tileUUID) { asRssi = BleFingerprintCollection::rxRefRssi + TILE_TX; setId("tile:" + getMac(), ID_TYPE_TILE); return; @@ -428,7 +419,6 @@ bool BleFingerprint::seen(BLEAdvertisedDevice *advertisedDevice) { auto the_min = min(min(oldest, recent), newest); auto the_max = max(max(oldest, recent), newest); auto the_median = the_max ^ the_min ^ oldest ^ recent ^ newest; - auto range = the_max - the_min; rssi = the_median; @@ -504,14 +494,14 @@ bool BleFingerprint::report(JsonObject *doc) { } bool BleFingerprint::query() { - if (!(allowQuery || rmAsst) || didQuery) return false; - if (rssi < -90) return false; + if (!allowQuery || isQuerying) return false; + if (rssi < -90) return false; // Too far away + auto now = millis(); + if (now - lastSeenMillis > 5) return false; // Haven't seen lately + if (now - lastQryMillis < qryDelayMillis) return false; // Too soon - if (now - lastSeenMillis > 5) return false; - - if (now - lastQryMillis < qryDelayMillis) return false; - didQuery = true; + isQuerying = true; lastQryMillis = now; bool success = false; @@ -526,48 +516,25 @@ bool BleFingerprint::query() { pClient->setConnectTimeout(5); NimBLEDevice::getScan()->stop(); if (pClient->connect(address)) { - bool iphone = true; if (allowQuery) { - std::string sMdl = pClient->getValue(deviceInformationService, modelChar); - std::string sName = pClient->getValue(genericAccessService, nameChar); - iphone = sMdl.find("iPhone") == 0; - 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%u Name | %s | %-58s%ddBm %s\u001b[0m\r\n", xPortGetCoreID(), getMac().c_str(), id.c_str(), rssi, 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%u Model | %s | %-58s%ddBm %s\u001b[0m\r\n", xPortGetCoreID(), getMac().c_str(), id.c_str(), rssi, sMdl.c_str()); - } - success = true; - } - } - - if (rmAsst || iphone) // For some reason we often don't get room assistant's service advertisement - { - std::string sRmAst = pClient->getValue(roomAssistantService, rootAssistantCharacteristic); - if (!sRmAst.empty()) { - if (setId(String("roomAssistant:") + kebabify(sRmAst).c_str(), ID_TYPE_RM_ASST)) { - Serial.printf("\u001b[38;5;129m%u RmAst | %s | %-58s%ddBm %s\u001b[0m\r\n", xPortGetCoreID(), getMac().c_str(), id.c_str(), rssi, sRmAst.c_str()); - } - success = true; - } + if (id.startsWith("flora:")) + success = MiFloraHandler::requestData(pClient, this); + else + success = NameModelHandler::requestData(pClient, this); } } NimBLEDevice::deleteClient(pClient); - if (success) return true; - - qryAttempts++; - qryDelayMillis = min(int(pow(10, qryAttempts)), 60000); - Serial.printf("%u QryErr | %s | %-58s%ddBm Try %d, retry after %dms\r\n", xPortGetCoreID(), getMac().c_str(), id.c_str(), rssi, qryAttempts, qryDelayMillis); - - didQuery = false; - + if (success) { + qryAttempts = 0; + qryDelayMillis = BleFingerprintCollection::requeryMs; + } else { + qryAttempts++; + qryDelayMillis = min(int(pow(10, qryAttempts)), 60000); + Serial.printf("%u QryErr | %s | %-58s%ddBm Try %d, retry after %dms\r\n", xPortGetCoreID(), getMac().c_str(), id.c_str(), rssi, qryAttempts, qryDelayMillis); + } + isQuerying = false; return true; } diff --git a/lib/BleFingerprint/BleFingerprint.h b/lib/BleFingerprint/BleFingerprint.h index bbb0cba..fcf1e89 100644 --- a/lib/BleFingerprint/BleFingerprint.h +++ b/lib/BleFingerprint/BleFingerprint.h @@ -1,8 +1,5 @@ #ifndef _BLEFINGERPRINT_ #define _BLEFINGERPRINT_ - -#include "rssi.h" -#include "string_utils.h" #include #include #include @@ -11,7 +8,13 @@ #include #include -#define NO_RSSI (-128) +#include + +#include "QueryReport.h" +#include "rssi.h" +#include "string_utils.h" + +#define NO_RSSI int8_t(-128) #define ID_TYPE_TX_POW short(1) @@ -111,7 +114,10 @@ public: bool getAllowQuery() const { return allowQuery; }; - bool getRmAsst() const { return rmAsst; }; + const bool hasReport() { return queryReport != nullptr; }; + const QueryReport getReport() { return *queryReport; }; + void setReport(const QueryReport &report) { queryReport = std::unique_ptr(new QueryReport {report}); }; + void clearReport() { queryReport.reset(); }; unsigned int getSeenCount() { @@ -129,7 +135,7 @@ private: static bool shouldHide(const String &s); - 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; + bool hasValue = false, added = false, close = false, reported = false, ignore = false, allowQuery = false, isQuerying = false, hidden = false, connectable = false, countable = false, counting = false; NimBLEAddress address; String id, name, disc; short int idType = NO_ID_TYPE; @@ -147,6 +153,7 @@ private: OneEuroFilter oneEuro; DifferentialFilter diffFilter; + std::unique_ptr queryReport = nullptr; bool filter(); void fingerprint(NimBLEAdvertisedDevice *advertisedDevice); diff --git a/lib/BleFingerprint/BleFingerprintCollection.cpp b/lib/BleFingerprint/BleFingerprintCollection.cpp index 5f45e4d..9deaa1b 100644 --- a/lib/BleFingerprint/BleFingerprintCollection.cpp +++ b/lib/BleFingerprint/BleFingerprintCollection.cpp @@ -8,7 +8,7 @@ namespace BleFingerprintCollection { String include{}, exclude{}, query{}, knownMacs{}, knownIrks{}, countIds{}; float skipDistance = 0.0f, maxDistance = 0.0f, absorption = 3.5f, countEnter = 2, countExit = 4; int8_t rxRefRssi = -65, rxAdjRssi = 0, txRefRssi = -59; -int forgetMs = 0, skipMs = 0, countMs = 10000; +int forgetMs = 0, skipMs = 0, countMs = 10000, requeryMs = 300000; std::vector deviceConfigs; std::vector irks; std::vector fingerprints; diff --git a/lib/BleFingerprint/BleFingerprintCollection.h b/lib/BleFingerprint/BleFingerprintCollection.h index a74c314..d169594 100644 --- a/lib/BleFingerprint/BleFingerprintCollection.h +++ b/lib/BleFingerprint/BleFingerprintCollection.h @@ -47,7 +47,7 @@ extern TCallbackFingerprint onCountDel; extern String include, exclude, query, knownMacs, knownIrks, countIds; extern float skipDistance, maxDistance, absorption, countEnter, countExit; extern int8_t rxRefRssi, rxAdjRssi, txRefRssi; -extern int forgetMs, skipMs, countMs; +extern int forgetMs, skipMs, countMs, requeryMs; extern std::vector deviceConfigs; extern std::vector irks; extern std::vector fingerprints; diff --git a/lib/BleFingerprint/QueryReport.h b/lib/BleFingerprint/QueryReport.h new file mode 100644 index 0000000..0a93b68 --- /dev/null +++ b/lib/BleFingerprint/QueryReport.h @@ -0,0 +1,17 @@ +#pragma once +#include + +class QueryReport { +public: + QueryReport(const String& id, const String& payload) : id(id), payload(payload) {} + + String getId() const { return id; } + String getPayload() const { return payload; } + + void setId(const String& id) { this->id = id; } + void setPayload(const String& payload) { this->payload = payload; } + +private: + String id; + String payload; +}; diff --git a/lib/BleFingerprint/rssi.h b/lib/BleFingerprint/rssi.h index 9752643..e42d07f 100644 --- a/lib/BleFingerprint/rssi.h +++ b/lib/BleFingerprint/rssi.h @@ -1,19 +1,19 @@ #ifndef _RSSI_ #define _RSSI_ -#define CLOSE_RSSI (-40) -#define LEFT_RSSI (-50) +#define CLOSE_RSSI int8_t(-40) +#define LEFT_RSSI int8_t(-50) -#define DEFAULT_TX (-6) +#define DEFAULT_TX int8_t(-6) -#define APPLE_TX 0 -#define RM_ASST_TX 0 -#define TILE_TX (-4) -#define EXPOSURE_TX (-12) -#define ITAG_TX (-10) +#define APPLE_TX int8_t(0) +#define RM_ASST_TX int8_t(0) +#define TILE_TX int8_t(-4) +#define EXPOSURE_TX int8_t(-12) +#define ITAG_TX int8_t(-10) -#define NUT_TX (-12) -#define FLORA_TX (-10) +#define NUT_TX int8_t(-12) +#define FLORA_TX int8_t(-10) -#define EDDYSTONE_ADD_1M (-41) +#define EDDYSTONE_ADD_1M int8_t(-41) #endif diff --git a/lib/BleFingerprint/string_utils.h b/lib/BleFingerprint/string_utils.h index ba87102..e5513fc 100644 --- a/lib/BleFingerprint/string_utils.h +++ b/lib/BleFingerprint/string_utils.h @@ -10,7 +10,7 @@ #define Stdprintf(f, ...) ({ char* s; asprintf(&s, f, __VA_ARGS__); const std::string r = s; free(s); r; }) #define SMacf(f) ( \ { \ - auto nativeAddress = (f).getNative(); \ + const auto nativeAddress = (f).getNative(); \ Sprintf("%02x%02x%02x%02x%02x%02x", nativeAddress[5], nativeAddress[4], nativeAddress[3], nativeAddress[2], nativeAddress[1], nativeAddress[0]); \ }) diff --git a/lib/handlers/MiFloraHandler.cpp b/lib/handlers/MiFloraHandler.cpp new file mode 100644 index 0000000..35036b5 --- /dev/null +++ b/lib/handlers/MiFloraHandler.cpp @@ -0,0 +1,137 @@ +#include "MiFloraHandler.h" + +namespace MiFloraHandler { + +std::vector addresses; +bool readSensorData(BLERemoteService* floraService, DynamicJsonDocument* doc) { + BLERemoteCharacteristic* floraCharacteristic = nullptr; + + // get the main device data characteristic + floraCharacteristic = floraService->getCharacteristic(uuid_sensor_data); + + if (floraCharacteristic == nullptr) { + Serial.println("-- Can't read characteristics"); + return false; + } + + // read characteristic value + NimBLEAttValue value; + + value = floraCharacteristic->readValue(); + + if (value.size() == 0) { + Serial.println("Reading Value failed"); + return false; + } + + const char* val = value.c_str(); + + float temperature = (val[0] + val[1] * 256) / ((float)10.0); + uint8_t moisture = val[7]; + uint32_t brightness = val[3] + val[4] * 256; + float conductivity = val[8] + val[9] * 256; + + (*doc)[F("temperature")] = temperature; + (*doc)[F("moisture")] = moisture; + (*doc)[F("light")] = brightness; + (*doc)[F("conductivity")] = conductivity; + + floraService->deleteCharacteristics(); + + return true; +} + +bool readBatteryData(BLERemoteService* floraService, DynamicJsonDocument* doc) { + BLERemoteCharacteristic* floraCharacteristic = nullptr; + + floraCharacteristic = floraService->getCharacteristic(uuid_version_battery); + + if (floraCharacteristic == nullptr) { + Serial.println("-- Can't read characteristics"); + return false; + } + NimBLEAttValue val; + + val = floraCharacteristic->readValue(); + + if (val.size() == 0) { + Serial.println("Reading Value failed"); + return false; + } + + int8_t battery = val.c_str()[0]; + (*doc)[F("battery")] = battery; + + floraService->deleteCharacteristics(); + return true; +} + +bool forceFloraServiceDataMode(BLERemoteService* floraService) { // Setting the mi flora to data reading mode + BLERemoteCharacteristic* floraCharacteristic; + + // get device mode characteristic, needs to be changed to read data + // Serial.println("- Force device in data mode"); + floraCharacteristic = nullptr; + floraCharacteristic = floraService->getCharacteristic(uuid_write_mode); + + if (floraCharacteristic == nullptr) { + // Serial.println("-- Failed, skipping device"); + return false; + } + + uint8_t buf[2] = {0xA0, 0x1F}; + floraCharacteristic->writeValue(buf, 2, true); + + delay(500); + floraService->deleteCharacteristics(); + + return true; +} + +void fillDeviceData(DynamicJsonDocument* doc, BleFingerprint* f) { + (*doc)[F("id")] = f->getId(); + (*doc)[F("mac")] = f->getMac(); + (*doc)[F("rssi")] = f->getRssi(); +} + +bool getFloraData(DynamicJsonDocument* doc, BLERemoteService* floraService, BleFingerprint* f) { + // Force miFlora to data mode + + fillDeviceData(doc, f); + + if (!MiFloraHandler::readBatteryData(floraService, doc)) + Serial.println("Failed reading battery data"); + + if (MiFloraHandler::forceFloraServiceDataMode(floraService)) { + } else { + Serial.println("Failed to force data reading mode"); + } + + if (!MiFloraHandler::readSensorData(floraService, doc)) + Serial.println("Failed reading sensor data"); + + return true; +} + +static DynamicJsonDocument document(1024); +bool requestData(NimBLEClient* pClient, BleFingerprint* fingerprint) // Getting mi flora data +{ + NimBLERemoteService* floraService = pClient->getService(serviceUUID); + + if (floraService == nullptr) { + Serial.println("Getting MiFlora service failed"); + return false; + } + + document.clear(); + // Retriving the actual data + if (!getFloraData(&document, floraService, fingerprint)) // Getting flora data + return false; + String buf = String(); + serializeJson(document, buf); + // Sending buffer over mqtt + fingerprint->setReport(QueryReport{"miflora", buf}); + return true; +} + +} // namespace MiFloraHandler diff --git a/lib/handlers/MiFloraHandler.h b/lib/handlers/MiFloraHandler.h new file mode 100644 index 0000000..bd09fa4 --- /dev/null +++ b/lib/handlers/MiFloraHandler.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +namespace MiFloraHandler +{ + static BLEUUID serviceUUID(0x00001204, 0x0000, 0x1000, 0x800000805f9b34fb); + static BLEUUID uuid_version_battery(0x00001a02, 0x0000, 0x1000, 0x800000805f9b34fb); + static BLEUUID uuid_sensor_data(0x00001a01, 0x0000, 0x1000, 0x800000805f9b34fb); + static BLEUUID uuid_write_mode(0x00001a00, 0x0000, 0x1000, 0x800000805f9b34fb); + + bool requestData(NimBLEClient* pClient, BleFingerprint* fingerprint); +} // namespace MiFloraHandler diff --git a/lib/handlers/NameModelHandler.cpp b/lib/handlers/NameModelHandler.cpp new file mode 100644 index 0000000..7971325 --- /dev/null +++ b/lib/handlers/NameModelHandler.cpp @@ -0,0 +1,24 @@ +#include "NameModelHandler.h" +#include "util.h" + +namespace NameModelHandler { +bool requestData(NimBLEClient* pClient, BleFingerprint* f) { + std::string sMdl = pClient->getValue(deviceInformationService, modelChar); + std::string sName = pClient->getValue(genericAccessService, nameChar); + if (!sName.empty() && sMdl.find(sName) == std::string::npos && sName != "Apple Watch") { + if (f->setId(String("name:") + kebabify(sName).c_str(), ID_TYPE_QUERY_NAME, String(sName.c_str()))) { + Serial.printf("\u001b[38;5;104m%u Name | %s | %-58s%ddBm %s\u001b[0m\r\n", xPortGetCoreID(), f->getMac().c_str(), f->getId().c_str(), f->getRssi(), sName.c_str()); + } + return true; + } + + if (!sMdl.empty()) { + if (f->setId(String("apple:") + kebabify(sMdl).c_str(), ID_TYPE_QUERY_MODEL, String(sMdl.c_str()))) { + Serial.printf("\u001b[38;5;136m%u Model | %s | %-58s%ddBm %s\u001b[0m\r\n", xPortGetCoreID(), f->getMac().c_str(), f->getId().c_str(), f->getRssi(), sMdl.c_str()); + } + return true; + } + + return false; +} +} // namespace NameModelHandler diff --git a/lib/handlers/NameModelHandler.h b/lib/handlers/NameModelHandler.h new file mode 100644 index 0000000..7045650 --- /dev/null +++ b/lib/handlers/NameModelHandler.h @@ -0,0 +1,14 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +namespace NameModelHandler { + +bool requestData(NimBLEClient* pClient, BleFingerprint* fingerprint); +} diff --git a/platformio.ini b/platformio.ini index 2d074a6..4f64b22 100644 --- a/platformio.ini +++ b/platformio.ini @@ -27,8 +27,8 @@ build_flags = -Wformat-truncation -D ARDUINOJSON_ENABLE_NAN=0 -D CONFIG_BT_NIMBLE_TASK_STACK_SIZE=4096 - -D SCAN_TASK_STACK_SIZE=2096 - -D ARDUINO_LOOP_STACK_SIZE=6144 + -D SCAN_TASK_STACK_SIZE=2562 + -D ARDUINO_LOOP_STACK_SIZE=3584 -D MQTT_MIN_FREE_MEMORY=12192 -D CONFIG_ASYNC_TCP_USE_WDT=0 -D CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT=20 @@ -38,13 +38,13 @@ build_flags = ; -D CONFIG_NIMBLE_CPP_LOG_LEVEL=4 ; -D CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT=1 ; -D CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT=1 -; -D CHECK_FOR_UPDATES_INTERVAL=1 +; -D CHECK_FOR_UPDATES_INTERVAL=1 build_unflags = framework = arduino lib_deps = AsyncTCP = https://github.com/pbolduc/AsyncTCP.git@^1.2.0 https://github.com/ESPresense/ESPAsyncWebServer.git - https://github.com/ESPresense/AsyncWiFiSettings.git#1.0.6 + https://github.com/ESPresense/AsyncWiFiSettings.git@^1.0.7 https://github.com/ESPresense/SoftFilters.git https://github.com/ESPresense/NimBLE-Arduino.git marvinroger/AsyncMqttClient@^0.9.0 @@ -120,8 +120,6 @@ lib_deps = paulstoffregen/OneWire@^2.3.7 milesburton/DallasTemperature@^3.11.0 - - [env:esp32] extends = esp32 lib_deps = diff --git a/src/GUI.cpp b/src/GUI.cpp index efafc42..a0bfaf2 100644 --- a/src/GUI.cpp +++ b/src/GUI.cpp @@ -53,7 +53,7 @@ void Loop() { void Added(BleFingerprint *f) { if (f->getIgnore()) return; - Serial.printf("%u New %s | %s | %-58s%ddBm %s\r\n", xPortGetCoreID(), f->getRmAsst() ? "R" : (f->getAllowQuery() ? "Q" : " "), f->getMac().c_str(), f->getId().c_str(), f->getRssi(), f->getDiscriminator().c_str()); + Serial.printf("%u New %s | %s | %-58s%ddBm %s\r\n", xPortGetCoreID(), f->getAllowQuery() ? "Q" : " ", f->getMac().c_str(), f->getId().c_str(), f->getRssi(), f->getDiscriminator().c_str()); } void Removed(BleFingerprint *f) { diff --git a/src/HttpWebServer.cpp b/src/HttpWebServer.cpp index 51e61ad..a890265 100644 --- a/src/HttpWebServer.cpp +++ b/src/HttpWebServer.cpp @@ -27,11 +27,11 @@ void serializeState(JsonObject &root) { } void serializeConfigs(JsonObject &root) { - JsonArray devices = root.createNestedArray("configs"); + JsonArray configs = root.createNestedArray("configs"); - auto f = BleFingerprintCollection::deviceConfigs; - for (auto it = f.begin(); it != f.end(); ++it) { - JsonObject node = devices.createNestedObject(); + auto deviceConfigs = BleFingerprintCollection::deviceConfigs; + for (auto it = deviceConfigs.begin(); it != deviceConfigs.end(); ++it) { + const JsonObject& node = configs.createNestedObject(); node["id"] = it->id; node["alias"] = it->alias; node["name"] = it->name; diff --git a/src/I2C.cpp b/src/I2C.cpp index 1abb3ea..8ba6ece 100644 --- a/src/I2C.cpp +++ b/src/I2C.cpp @@ -18,7 +18,7 @@ int I2C_Bus_2_SDA = 0; int I2C_Bus_2_SCL = 0; void ConnectToWifi() { - AsyncWiFiSettings.heading("I2C Settings ℹ️", false); + AsyncWiFiSettings.heading("I2C Settings", false); AsyncWiFiSettings.html("h4", "Bus 1:"); diff --git a/src/LEDs.cpp b/src/LEDs.cpp index 3aa5230..24aa3e9 100644 --- a/src/LEDs.cpp +++ b/src/LEDs.cpp @@ -34,7 +34,7 @@ void ConnectToWifi() { std::vector ledTypes = {"PWM", "PWM Inverted", "Addressable GRB", "Addressable GRBW", "Addressable RGB", "Addressable RGBW"}; std::vector ledControlTypes = {"MQTT", "Status", "Motion", "Count"}; - AsyncWiFiSettings.heading("LEDs ℹ️", false); + AsyncWiFiSettings.heading("LEDs", false); AsyncWiFiSettings.html("h4", "LED 1:"); diff --git a/src/Switch.cpp b/src/Switch.cpp index c8c801c..d5be5cd 100644 --- a/src/Switch.cpp +++ b/src/Switch.cpp @@ -45,9 +45,9 @@ void ConnectToWifi() { } void SerialReport() { - Serial.print("Switch One Sensor: "); + Serial.print("Switch One: "); Serial.println(switch_1Pin >= 0 ? "enabled" : "disabled"); - Serial.print("Switch Two Sensor: "); + Serial.print("Switch Two: "); Serial.println(switch_2Pin >= 0 ? "enabled" : "disabled"); } @@ -118,4 +118,4 @@ bool SendOnline() { online = true; return true; } -} // namespace Switch \ No newline at end of file +} // namespace Switch diff --git a/src/Updater.cpp b/src/Updater.cpp index fb712e4..a939978 100644 --- a/src/Updater.cpp +++ b/src/Updater.cpp @@ -102,10 +102,12 @@ void firmwareUpdate() { case HTTP_UPDATE_FAILED: Serial.printf("Http Update Failed (Error=%d): %s\r\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); break; - case HTTP_UPDATE_NO_UPDATES: Serial.printf("No Update!\r\n"); break; + case HTTP_UPDATE_OK: + Serial.printf("Update OK!\r\n"); + break; } } } diff --git a/src/main.cpp b/src/main.cpp index 1d9d43b..5c2978e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,13 @@ #define VAR_DECLS #include "main.h" +#include "esp_heap_caps.h" + +void heapCapsAllocFailedHook(size_t requestedSize, uint32_t caps, const char *functionName) +{ + printf("%s was called but failed to allocate %d bytes with 0x%X capabilities. \n",functionName, requestedSize, caps); +} + bool sendTelemetry(unsigned int totalSeen, unsigned int totalFpSeen, int unsigned totalFpQueried, int unsigned totalFpReported, unsigned int count) { if (!online) { if ( @@ -107,9 +114,9 @@ bool sendTelemetry(unsigned int totalSeen, unsigned int totalFpSeen, int unsigne auto maxHeap = ESP.getMaxAllocHeap(); auto freeHeap = ESP.getFreeHeap(); doc["freeHeap"] = freeHeap; - doc["maxAllocHeap"] = maxHeap; - doc["memFrag"] = 100 - (maxHeap * 100.0 / freeHeap); - doc["scanHighWater"] = uxTaskGetStackHighWaterMark(scanTaskHandle); + doc["maxHeap"] = maxHeap; + doc["scanStack"] = uxTaskGetStackHighWaterMark(scanTaskHandle); + doc["loopStack"] = uxTaskGetStackHighWaterMark(nullptr); serializeJson(doc, buffer); if (pub(teleTopic.c_str(), 0, false, buffer)) return true; @@ -133,7 +140,7 @@ void setupNetwork() { std::vector ethernetTypes = {"None", "WT32-ETH01", "ESP32-POE", "WESP32", "QuinLED-ESP32", "TwilightLord-ESP32", "ESP32Deux", "KIT-VE", "LilyGO-T-ETH-POE", "GL-inet GL-S10 v2.1 Ethernet"}; ethernetType = AsyncWiFiSettings.dropdown("eth", ethernetTypes, 0, "Ethernet Type"); - AsyncWiFiSettings.heading("MQTT ℹ️", false); + AsyncWiFiSettings.heading("MQTT", false); mqttHost = AsyncWiFiSettings.string("mqtt_host", DEFAULT_MQTT_HOST, "Server"); mqttPort = AsyncWiFiSettings.integer("mqtt_port", DEFAULT_MQTT_PORT, "Port"); mqttUser = AsyncWiFiSettings.pstring("mqtt_user", DEFAULT_MQTT_USER, "Username"); @@ -144,28 +151,31 @@ void setupNetwork() { publishRooms = AsyncWiFiSettings.checkbox("pub_rooms", true, "Send to rooms topic"); publishDevices = AsyncWiFiSettings.checkbox("pub_devices", true, "Send to devices topic"); - AsyncWiFiSettings.heading("Updating ℹ️", false); + AsyncWiFiSettings.heading("Updating", false); Updater::ConnectToWifi(); - AsyncWiFiSettings.heading("Scanning ℹ️", false); + AsyncWiFiSettings.heading("Scanning", false); BleFingerprintCollection::knownMacs = AsyncWiFiSettings.string("known_macs", "", "Known BLE mac addresses (no colons, space seperated)"); BleFingerprintCollection::knownIrks = AsyncWiFiSettings.string("known_irks", "", "Known BLE identity resolving keys, should be 32 hex chars space seperated"); - BleFingerprintCollection::query = AsyncWiFiSettings.string("query", DEFAULT_QUERY, "Query device ids for characteristics (eg. apple:1005:9-26)"); - AsyncWiFiSettings.heading("Counting ℹ️", false); + AsyncWiFiSettings.heading("Querying", false); + BleFingerprintCollection::query = AsyncWiFiSettings.string("query", DEFAULT_QUERY, "Query device ids for characteristics (eg. flora:)"); + BleFingerprintCollection::requeryMs = AsyncWiFiSettings.integer("requery_ms", 30, 3600, 300, "Requery interval in seconds") * 1000; + + AsyncWiFiSettings.heading("Counting", false); BleFingerprintCollection::countIds = AsyncWiFiSettings.string("count_ids", "", "Include id prefixes (space seperated)"); BleFingerprintCollection::countEnter = AsyncWiFiSettings.floating("count_enter", 0, 100, 2, "Start counting devices less than distance (in meters)"); BleFingerprintCollection::countExit = AsyncWiFiSettings.floating("count_exit", 0, 100, 4, "Stop counting devices greater than distance (in meters)"); BleFingerprintCollection::countMs = AsyncWiFiSettings.integer("count_ms", 0, 3000000, 30000, "Include devices with age less than (in ms)"); - AsyncWiFiSettings.heading("Filtering ℹ️", false); + AsyncWiFiSettings.heading("Filtering", false); BleFingerprintCollection::include = AsyncWiFiSettings.string("include", DEFAULT_INCLUDE, "Include only sending these ids to mqtt (eg. apple:iphone10-6 apple:iphone13-2)"); BleFingerprintCollection::exclude = AsyncWiFiSettings.string("exclude", DEFAULT_EXCLUDE, "Exclude sending these ids to mqtt (eg. exp:20 apple:iphone10-6)"); BleFingerprintCollection::maxDistance = AsyncWiFiSettings.floating("max_dist", 0, 100, DEFAULT_MAX_DISTANCE, "Maximum distance to report (in meters)"); BleFingerprintCollection::skipDistance = AsyncWiFiSettings.floating("skip_dist", 0, 10, DEFAULT_SKIP_DISTANCE, "Report early if beacon has moved more than this distance (in meters)"); BleFingerprintCollection::skipMs = AsyncWiFiSettings.integer("skip_ms", 0, 3000000, DEFAULT_SKIP_MS, "Skip reporting if message age is less that this (in milliseconds)"); - AsyncWiFiSettings.heading("Calibration ℹ️", false); + AsyncWiFiSettings.heading("Calibration", false); BleFingerprintCollection::rxRefRssi = AsyncWiFiSettings.integer("ref_rssi", -100, 100, DEFAULT_RX_REF_RSSI, "Rssi expected from a 0dBm transmitter at 1 meter (NOT used for iBeacons or Eddystone)"); BleFingerprintCollection::rxAdjRssi = AsyncWiFiSettings.integer("rx_adj_rssi", -100, 100, 0, "Rssi adjustment for receiver (use only if you know this device has a weak antenna)"); BleFingerprintCollection::absorption = AsyncWiFiSettings.floating("absorption", -100, 100, DEFAULT_ABSORPTION, "Factor used to account for absorption, reflection, or diffraction"); @@ -174,7 +184,7 @@ void setupNetwork() { GUI::ConnectToWifi(); - AsyncWiFiSettings.heading("GPIO Sensors ℹ️", false); + AsyncWiFiSettings.heading("GPIO Sensors", false); BleFingerprintCollection::ConnectToWifi(); Motion::ConnectToWifi(); @@ -185,7 +195,7 @@ void setupNetwork() { DHT::ConnectToWifi(); I2C::ConnectToWifi(); - AsyncWiFiSettings.heading("I2C Sensors ℹ️", false); + AsyncWiFiSettings.heading("I2C Sensors", false); AHTX0::ConnectToWifi(); BH1750::ConnectToWifi(); @@ -393,6 +403,13 @@ void connectToMqtt() { mqttClient.connect(); } +bool reportBuffer(BleFingerprint *f) { + if (!mqttClient.connected()) return false; + auto report = f->getReport(); + String topic = Sprintf(CHANNEL "/devices/%s/%s/%s", f->getId().c_str(), id.c_str(), report.getId().c_str()); + return mqttClient.publish(topic.c_str(), 0, false, report.getPayload().c_str()); +} + bool reportDevice(BleFingerprint *f) { doc.clear(); JsonObject obj = doc.to(); @@ -404,9 +421,7 @@ bool reportDevice(BleFingerprint *f) { bool p1 = false, p2 = false; for (int i = 0; i < 10; i++) { - if (!mqttClient.connected()) - return false; - + if (!mqttClient.connected()) return false; if (!p1 && (!publishRooms || mqttClient.publish(roomsTopic.c_str(), 0, false, buffer))) p1 = true; @@ -417,6 +432,7 @@ bool reportDevice(BleFingerprint *f) { return true; delay(20); } + teleFails++; return false; } @@ -456,6 +472,11 @@ void reportLoop() { totalSeen += seen; totalFpSeen++; } + + if (f->hasReport()) { + if (reportBuffer(f)) + f->clearReport(); + } if (reportDevice(f)) { totalFpReported++; reported++; @@ -515,6 +536,7 @@ void setup() { esp_log_level_set("*", ESP_LOG_ERROR); #endif Serial.printf("Pre-Setup Free Mem: %d\r\n", ESP.getFreeHeap()); + heap_caps_register_failed_alloc_callback(heapCapsAllocFailedHook); #if M5STICK AXP192::Setup();