Add include exclude query filtering (#255)
Co-authored-by: Stefan Knaak <stefan@knaak.org> * Add Feature: Blacklist/Whitelist * MQTT room=* all rooms will set, added restart * Fixes: #58 #229 #152
This commit is contained in:
parent
3960110290
commit
4780e362ae
|
@ -4,25 +4,29 @@ about: Create a report to help us improve
|
|||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Hardware Details**
|
||||
If the bug is related to tracking a specific piece of hardware (e.g. iBeacon, phone, etc), please enter any relevant details about the hardware (such as firmware version, MAC address, etc).
|
||||
A clear and concise description of what the bug is. If it relates to fingerprinting or presense please include the id you expect/monitor.
|
||||
|
||||
**Config**
|
||||
|
||||
- [ ] Active Scan enabled
|
||||
- [ ] Query enabled
|
||||
- Version:
|
||||
- Active scan enabled:
|
||||
- Include filter:
|
||||
- Exclude filter:
|
||||
- Query filter:
|
||||
|
||||
**Hardware**
|
||||
|
||||
- Firmware flavor:
|
||||
- Device (be specific):
|
||||
|
||||
**Logs**
|
||||
|
||||
If possible, copy and paste any logs from the serial monitor from the time that you see the bug.
|
||||
|
||||
**Screenshots**
|
||||
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
|
|
@ -19,6 +19,61 @@
|
|||
Sprintf("%02x%02x%02x%02x%02x%02x", nativeAddress[5], nativeAddress[4], nativeAddress[3], nativeAddress[2], nativeAddress[1], nativeAddress[0]); \
|
||||
})
|
||||
|
||||
bool prefixExists(String prefixes, String id)
|
||||
{
|
||||
unsigned int start = 0;
|
||||
unsigned int space = 0;
|
||||
|
||||
while ((space = prefixes.indexOf(" ", start)) != -1)
|
||||
{
|
||||
if (space > start)
|
||||
{
|
||||
auto sub = prefixes.substring(start, space);
|
||||
#ifdef VERBOSE
|
||||
Serial.printf("Verbose | %-58sSUB\n", sub.c_str());
|
||||
#endif
|
||||
if (sub == "*" || id.indexOf(sub) != -1) return true;
|
||||
}
|
||||
start = space + 1;
|
||||
}
|
||||
auto sub = prefixes.substring(start);
|
||||
return (sub == "*" || id.indexOf(sub) != -1);
|
||||
}
|
||||
|
||||
bool BleFingerprint::shouldHide(String id)
|
||||
{
|
||||
auto include = _parent->getInclude();
|
||||
if (include.length() > 0 && !prefixExists(include, id)) return true;
|
||||
|
||||
auto exclude = _parent->getExclude();
|
||||
return (exclude.length() > 0 && prefixExists(exclude, id));
|
||||
}
|
||||
|
||||
void BleFingerprint::setId(String newId, short int newIdType)
|
||||
{
|
||||
if (newIdType < idType) return;
|
||||
|
||||
hidden = shouldHide(newId);
|
||||
|
||||
if (!allowQuery)
|
||||
{
|
||||
auto query = _parent->getQuery();
|
||||
if (prefixExists(query, newId))
|
||||
{
|
||||
allowQuery = true;
|
||||
qryAttempts = 0;
|
||||
if (rssi < -60)
|
||||
{
|
||||
qryDelayMillis = 5000;
|
||||
lastQryMillis = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
id = newId;
|
||||
idType = newIdType;
|
||||
}
|
||||
|
||||
String BleFingerprint::getMac() { return SMacf(address); }
|
||||
|
||||
int BleFingerprint::get1mRssi()
|
||||
|
@ -44,6 +99,9 @@ void BleFingerprint::fingerprint(BLEAdvertisedDevice *advertisedDevice)
|
|||
if (advertisedDevice->haveName())
|
||||
name = String(advertisedDevice->getName().c_str());
|
||||
|
||||
if (advertisedDevice->getAdvType() > 0)
|
||||
connectable = true;
|
||||
|
||||
if (advertisedDevice->haveServiceUUID())
|
||||
{
|
||||
|
||||
|
@ -83,10 +141,12 @@ void BleFingerprint::fingerprint(BLEAdvertisedDevice *advertisedDevice)
|
|||
if (!rmAsst)
|
||||
{
|
||||
rmAsst = true;
|
||||
didQuery = false;
|
||||
shouldQuery = true;
|
||||
qryAttempts = 0;
|
||||
qryDelayMillis = 3;
|
||||
if (didQuery)
|
||||
{
|
||||
qryDelayMillis = 0;
|
||||
qryAttempts = 0;
|
||||
didQuery = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -210,7 +270,6 @@ void BleFingerprint::fingerprint(BLEAdvertisedDevice *advertisedDevice)
|
|||
}
|
||||
else if (strManufacturerData.length() >= 4 && strManufacturerData[2] == 0x10)
|
||||
{
|
||||
shouldQuery = true;
|
||||
ignore = false;
|
||||
{
|
||||
String pid;
|
||||
|
@ -338,7 +397,7 @@ void BleFingerprint::setInitial(int initalRssi, float initalDistance)
|
|||
|
||||
bool BleFingerprint::report(JsonDocument *doc)
|
||||
{
|
||||
if (ignore || (idType == 0 && !macPublic))
|
||||
if (ignore || (idType == 0 && !macPublic) || hidden)
|
||||
return false;
|
||||
|
||||
if (reported || !hasValue)
|
||||
|
@ -380,7 +439,7 @@ bool BleFingerprint::report(JsonDocument *doc)
|
|||
|
||||
bool BleFingerprint::query()
|
||||
{
|
||||
if (!shouldQuery || didQuery) return false;
|
||||
if (!(allowQuery || rmAsst) || !connectable || didQuery) return false;
|
||||
if (rssi < -90) return false;
|
||||
|
||||
auto now = millis();
|
||||
|
@ -390,58 +449,56 @@ 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);
|
||||
|
||||
NimBLEClient *pClient = NimBLEDevice::getClientListSize() ? NimBLEDevice::getClientByPeerAddress(address) : nullptr;
|
||||
if (!pClient) pClient = NimBLEDevice::getDisconnectedClient();
|
||||
if (!pClient) pClient = NimBLEDevice::createClient();
|
||||
pClient->setConnectTimeout(5);
|
||||
pClient->setConnectTimeout(1);
|
||||
if (pClient->connect(address))
|
||||
{
|
||||
auto sRmAst = pClient->getValue(roomAssistantService, rootAssistantCharacteristic);
|
||||
if (!sRmAst.empty())
|
||||
if (rmAsst)
|
||||
{
|
||||
setId(String("roomAssistant:") + kebabify(sRmAst).c_str(), ID_TYPE_RM_ASST);
|
||||
Serial.printf("%d RmAst | MAC: %s, ID: %-60s %s\n", xPortGetCoreID(), getMac().c_str(), getId().c_str(), sRmAst.c_str());
|
||||
success = true;
|
||||
auto sRmAst = pClient->getValue(roomAssistantService, rootAssistantCharacteristic);
|
||||
if (!sRmAst.empty())
|
||||
{
|
||||
setId(String("roomAssistant:") + kebabify(sRmAst).c_str(), ID_TYPE_RM_ASST);
|
||||
Serial.printf("%d RmAst | MAC: %s, ID: %-60s %s\n", xPortGetCoreID(), getMac().c_str(), getId().c_str(), sRmAst.c_str());
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (allowQuery)
|
||||
{
|
||||
auto sMdl = pClient->getValue(deviceInformationService, modelChar);
|
||||
auto sName = pClient->getValue(genericAccessService, nameChar);
|
||||
if (!sName.empty() && !sMdl.empty() && sMdl.find(sName) == std::string::npos && sName.compare("Apple Watch") != 0)
|
||||
{
|
||||
setId(String("name:") + kebabify(sName).c_str(), ID_TYPE_APPLE_NAME);
|
||||
Serial.printf("%d Name | MAC: %s, ID: %-60s %s\n", xPortGetCoreID(), getMac().c_str(), getId().c_str(), sName.c_str());
|
||||
success = !rmAsst; // Success only if we don't expect to get rootAssistantCharacteristic
|
||||
setId(String("name:") + kebabify(sName).c_str(), ID_TYPE_APPLE_NAME);
|
||||
success = true;
|
||||
}
|
||||
else if (!sMdl.empty())
|
||||
{
|
||||
setId(String("apple:") + kebabify(sMdl).c_str(), ID_TYPE_APPLE_MODEL);
|
||||
if (name.isEmpty()) name = sMdl.c_str();
|
||||
Serial.printf("%d Model | MAC: %s, ID: %-60s %s\n", xPortGetCoreID(), getMac().c_str(), getId().c_str(), sMdl.c_str());
|
||||
success = !rmAsst; // Success only if we don't expect to get rootAssistantCharacteristic
|
||||
setId(String("apple:") + kebabify(sMdl).c_str(), ID_TYPE_APPLE_MODEL);
|
||||
success = true;
|
||||
}
|
||||
else if (!sName.empty())
|
||||
{
|
||||
if (name.isEmpty()) name = sName.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
// auto sFwRevChar = pClient->getValue(deviceInformationService, fwRevChar);
|
||||
// Serial.printf("%d FwRev | MAC: %s, ID: %-50s%s\n", xPortGetCoreID(), getMac().c_str(), getId().c_str(), sFwRevChar.c_str());
|
||||
|
||||
// auto sHwRevChar = pClient->getValue(deviceInformationService, hwRevChar);
|
||||
// Serial.printf("%d HwRev | MAC: %s, ID: %-50s%s\n", xPortGetCoreID(), getMac().c_str(), getId().c_str(), sHwRevChar.c_str());
|
||||
|
||||
pClient->disconnect();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
qryAttempts++;
|
||||
if (qryDelayMillis < 30000)
|
||||
qryDelayMillis *= qryAttempts;
|
||||
qryDelayMillis += (1000 * qryAttempts * qryAttempts);
|
||||
else
|
||||
qryDelayMillis = 30000;
|
||||
didQuery = false;
|
||||
|
|
|
@ -56,12 +56,7 @@ public:
|
|||
return getMac();
|
||||
}
|
||||
|
||||
void setId(String newId, short int newIdType)
|
||||
{
|
||||
if (newIdType < idType) return;
|
||||
id = newId;
|
||||
idType = newIdType;
|
||||
}
|
||||
void setId(String newId, short int newIdType);
|
||||
|
||||
String getMac();
|
||||
int get1mRssi();
|
||||
|
@ -85,13 +80,14 @@ public:
|
|||
|
||||
private:
|
||||
void fingerprint(BLEAdvertisedDevice *advertisedDevice);
|
||||
bool shouldHide(String newId);
|
||||
|
||||
BleFingerprintCollection *_parent;
|
||||
bool hasValue = false, close = false, reported = false, macPublic = false, ignore = false, shouldQuery = false, didQuery = false, rmAsst = false;
|
||||
bool hasValue = false, close = false, reported = false, macPublic = false, ignore = false, allowQuery = false, didQuery = false, rmAsst = false, hidden = false, connectable = false;
|
||||
NimBLEAddress address;
|
||||
String id, name, disc;
|
||||
short int idType = 0, 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 = 3;
|
||||
int qryAttempts = 0, seenCount = 1, qryDelayMillis = 0;
|
||||
float raw = 0, lastReported = 0, temp = 0, humidity = 0;
|
||||
unsigned long firstSeenMillis, lastSeenMillis = 0, lastReportedMillis = 0, lastQryMillis = 0;
|
||||
uint16_t mv = 0;
|
||||
|
|
|
@ -20,18 +20,24 @@ public:
|
|||
void cleanupOldFingerprints();
|
||||
std::list<BleFingerprint *> getCopy();
|
||||
void setDisable(bool disable) { _disable = disable; }
|
||||
void setParams(int rssiRef, int forgetMs, float skipDistance, int skipMs, float maxDistance)
|
||||
void setParams(int rssiRef, int forgetMs, float skipDistance, int skipMs, float maxDistance, String include, String exclude, String query)
|
||||
{
|
||||
_refRssi = rssiRef;
|
||||
_forgetMs = forgetMs;
|
||||
_skipDistance = skipDistance;
|
||||
_skipMs = skipMs;
|
||||
_maxDistance = maxDistance;
|
||||
_include = include;
|
||||
_exclude = exclude;
|
||||
_query = query;
|
||||
}
|
||||
int getSkipMs() { return _skipMs; }
|
||||
float getSkipDistance() { return _skipDistance; }
|
||||
int getRefRssi() { return _refRssi; }
|
||||
float getMaxDistance() { return _maxDistance; }
|
||||
String getInclude() { return _include; }
|
||||
String getExclude() { return _exclude; }
|
||||
String getQuery() { return _query; }
|
||||
|
||||
private:
|
||||
bool _disable = false;
|
||||
|
@ -39,6 +45,7 @@ private:
|
|||
float _maxDistance, _skipDistance;
|
||||
int _refRssi, _forgetMs, _skipMs;
|
||||
unsigned long lastCleanup = 0;
|
||||
String _include, _exclude, _query;
|
||||
|
||||
SemaphoreHandle_t fingerprintSemaphore;
|
||||
std::list<BleFingerprint *> fingerprints;
|
||||
|
|
|
@ -21,13 +21,13 @@ static BLEUUID meaterService(0xa75cc7fc, 0xc956, 0x488f, 0xac2a2dbc08b63a04);
|
|||
static BLEUUID meaterCharacteristic(0x7edda774, 0x045e, 0x4bbf, 0x909b45d1991a2876);
|
||||
|
||||
static BLEUUID genericAccessService(uint16_t(0x1800));
|
||||
static BLEUUID deviceInformationService(uint16_t(0x180A));
|
||||
|
||||
static BLEUUID nameChar(uint16_t(0x2A00));
|
||||
static BLEUUID manufChar(uint16_t(0x2A29));
|
||||
|
||||
static BLEUUID deviceInformationService(uint16_t(0x180A));
|
||||
static BLEUUID modelChar(uint16_t(0x2A24));
|
||||
static BLEUUID hwRevChar(uint16_t(0x2A27));
|
||||
static BLEUUID fwRevChar(uint16_t(0x2A26));
|
||||
static BLEUUID hwRevChar(uint16_t(0x2A27));
|
||||
static BLEUUID manufChar(uint16_t(0x2A29));
|
||||
|
||||
static int median_of_3(int a, int b, int c)
|
||||
{
|
||||
|
|
|
@ -14,7 +14,7 @@ default_envs = esp32
|
|||
[common_env_data]
|
||||
platform = espressif32@3.5
|
||||
framework = arduino
|
||||
lib_deps_external =
|
||||
lib_deps_external =
|
||||
haimoz/SoftFilters@^0.1.0
|
||||
marvinroger/AsyncMqttClient@^0.9.0
|
||||
bblanchon/ArduinoJson@^6.17.3
|
||||
|
@ -37,25 +37,23 @@ lib_deps_external =
|
|||
platform = ${common_env_data.platform}
|
||||
framework = ${common_env_data.framework}
|
||||
board = esp32dev
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
lib_deps = ${common_env_data.lib_deps_external}
|
||||
board_build.partitions = partitions_singleapp.csv
|
||||
monitor_speed = 115200
|
||||
upload_speed = 1500000
|
||||
monitor_filters = esp32_exception_decoder
|
||||
build_flags =
|
||||
build_flags =
|
||||
-D FIRMWARE='"esp32"'
|
||||
|
||||
[env:adafruit-huzzah32]
|
||||
platform = ${common_env_data.platform}
|
||||
framework = ${common_env_data.framework}
|
||||
board = esp32dev
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
lib_deps = ${common_env_data.lib_deps_external}
|
||||
board_build.partitions = partitions_singleapp.csv
|
||||
monitor_speed = 115200
|
||||
monitor_filters = esp32_exception_decoder
|
||||
build_flags =
|
||||
build_flags =
|
||||
-D FIRMWARE='"adafruit-huzzah32"'
|
||||
-D HUZZAH32
|
||||
|
||||
|
@ -63,13 +61,12 @@ build_flags =
|
|||
platform = ${common_env_data.platform}
|
||||
framework = ${common_env_data.framework}
|
||||
board = esp32dev
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
lib_deps = ${common_env_data.lib_deps_external}
|
||||
board_build.partitions = partitions_singleapp.csv
|
||||
monitor_speed = 115200
|
||||
upload_speed = 1500000
|
||||
monitor_filters = esp32_exception_decoder
|
||||
build_flags =
|
||||
build_flags =
|
||||
-D CORE_DEBUG_LEVEL=2
|
||||
-D FIRMWARE='"esp32-verbose"'
|
||||
-D VERBOSE
|
||||
|
@ -78,13 +75,13 @@ build_flags =
|
|||
platform = ${common_env_data.platform}
|
||||
framework = ${common_env_data.framework}
|
||||
board = m5stick-c
|
||||
lib_deps =
|
||||
lib_deps =
|
||||
m5stack/M5StickC@^0.2.0
|
||||
${common_env_data.lib_deps_external}
|
||||
board_build.partitions = partitions_singleapp.csv
|
||||
monitor_speed = 115200
|
||||
monitor_filters = esp32_exception_decoder
|
||||
build_flags =
|
||||
build_flags =
|
||||
-D M5STICK
|
||||
-D FIRMWARE='"m5stickc"'
|
||||
|
||||
|
@ -92,13 +89,13 @@ build_flags =
|
|||
platform = ${common_env_data.platform}
|
||||
framework = ${common_env_data.framework}
|
||||
board = m5stick-c
|
||||
lib_deps =
|
||||
lib_deps =
|
||||
m5stack/M5StickCPlus@^0.0.2
|
||||
${common_env_data.lib_deps_external}
|
||||
board_build.partitions = partitions_singleapp.csv
|
||||
monitor_speed = 115200
|
||||
monitor_filters = esp32_exception_decoder
|
||||
build_flags =
|
||||
build_flags =
|
||||
-D M5STICK
|
||||
-D PLUS
|
||||
-D FIRMWARE='"m5stickc-plus"'
|
||||
|
@ -107,14 +104,14 @@ build_flags =
|
|||
platform = ${common_env_data.platform}
|
||||
framework = ${common_env_data.framework}
|
||||
board = m5stack-atom
|
||||
lib_deps =
|
||||
lib_deps =
|
||||
fastled/FastLED@^3.4.0
|
||||
m5stack/m5atom@^0.0.5
|
||||
${common_env_data.lib_deps_external}
|
||||
board_build.partitions = partitions_singleapp.csv
|
||||
monitor_speed = 115200
|
||||
monitor_filters = esp32_exception_decoder
|
||||
build_flags =
|
||||
build_flags =
|
||||
-D M5ATOM
|
||||
-D MATRIX
|
||||
-D FIRMWARE='"m5atom-matrix"'
|
||||
|
@ -123,11 +120,10 @@ build_flags =
|
|||
platform = ${common_env_data.platform}
|
||||
framework = ${common_env_data.framework}
|
||||
board = esp32dev
|
||||
lib_deps =
|
||||
${common_env_data.lib_deps_external}
|
||||
lib_deps = ${common_env_data.lib_deps_external}
|
||||
board_build.partitions = partitions_singleapp.csv
|
||||
monitor_speed = 115200
|
||||
build_flags =
|
||||
build_flags =
|
||||
-D MACCHINA_A0
|
||||
-D FIRMWARE='"macchina-a0"'
|
||||
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
//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 WiFi. 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 WiFi. Do not modify unless you are confident you know what you're doing
|
||||
|
||||
|
|
75
src/main.cpp
75
src/main.cpp
|
@ -17,7 +17,7 @@ bool sendTelemetry(int totalSeen, int totalFpSeen, int totalFpQueried, int total
|
|||
|
||||
if (discovery && !sentDiscovery)
|
||||
{
|
||||
if (sendDiscoveryConnectivity() && sendDiscoveryUptime() && sendDiscoveryFreeMem() && sendSwitchDiscovery("Status LED", "config") && sendNumberDiscovery("Max Distance", "config") && sendSwitchDiscovery("Active Scan", "config") && sendSwitchDiscovery("Query", "config") && sendDiscoveryMotion()
|
||||
if (sendDiscoveryConnectivity() && sendDiscoveryUptime() && sendDiscoveryFreeMem() && sendButtonDiscovery("Restart", "diagnostic") && sendSwitchDiscovery("Status LED", "config") && sendNumberDiscovery("Max Distance", "config") && sendSwitchDiscovery("Active Scan", "config") && sendDeleteDiscovery("switch", "Query") && sendDiscoveryMotion()
|
||||
#ifdef SENSORS
|
||||
&& sendDiscoveryHumidity() && sendDiscoveryTemperature() && sendDiscoveryLux() && sendDiscoveryBME280Temperature() && sendDiscoveryBME280Humidity() && sendDiscoveryBME280Pressure() && sendDiscoveryTSL2561Lux()
|
||||
#endif
|
||||
|
@ -115,28 +115,29 @@ void connectToWifi()
|
|||
room = WiFiSettings.string("room", ESPMAC, "Room");
|
||||
|
||||
WiFiSettings.heading("MQTT Connection");
|
||||
|
||||
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");
|
||||
|
||||
statusLed = WiFiSettings.checkbox("status_led", true, "Status LED");
|
||||
Display.setStatusLed(statusLed);
|
||||
|
||||
autoUpdate = WiFiSettings.checkbox("auto_update", DEFAULT_AUTO_UPDATE, "Automatically 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)");
|
||||
allowQuery = WiFiSettings.checkbox("query", false, "Query devices for characteristics (helps apple fingerprints uniqueness)");
|
||||
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("Calibration");
|
||||
WiFiSettings.heading("Filtering");
|
||||
query = WiFiSettings.string("query", DEFAULT_QUERY, "Query device ids for characteristics (eg. apple:1005:9-26)");
|
||||
if (query == "1") query = "apple:10"; // This is to keep query=true doing the same thing as older firmwares
|
||||
include = WiFiSettings.string("include", DEFAULT_INCLUDE, "If set will only send matching to mqtt (eg. apple:iphone10-6 apple:iphone13-2)");
|
||||
exclude = WiFiSettings.string("exclude", DEFAULT_EXCLUDE, "Exclude sensing these ids to mqtt (eg. exp:20 apple:iphone10-6)");
|
||||
|
||||
WiFiSettings.heading("Calibration");
|
||||
maxDistance = WiFiSettings.floating("max_dist", 0, 100, DEFAULT_MAX_DISTANCE, "Maximum distance to report (in meters)");
|
||||
forgetMs = WiFiSettings.integer("forget_ms", 0, 3000000, DEFAULT_FORGET_MS, "Forget beacon if not seen for (in miliiseconds)");
|
||||
skipDistance = WiFiSettings.floating("skip_dist", 0, 10, DEFAULT_SKIP_DISTANCE, "Update mqtt if beacon has moved more than this distance since last report (in meters)");
|
||||
|
@ -144,7 +145,6 @@ void connectToWifi()
|
|||
refRssi = WiFiSettings.integer("ref_rssi", -100, 100, DEFAULT_REF_RSSI, "Rssi expected from a 0dBm transmitter at 1 meter");
|
||||
|
||||
WiFiSettings.heading("Additional Sensors");
|
||||
|
||||
pirPin = WiFiSettings.integer("pir_pin", 0, "PIR motion pin (0 for disable)");
|
||||
radarPin = WiFiSettings.integer("radar_pin", 0, "Radar motion pin (0 for disable)");
|
||||
#ifdef SENSORS
|
||||
|
@ -222,19 +222,26 @@ void connectToWifi()
|
|||
Serial.println(TSL2561_I2c + " on bus " + TSL2561_I2c_Bus);
|
||||
Serial.println(BH1750_I2c);
|
||||
#endif
|
||||
|
||||
Serial.print("Query: ");
|
||||
Serial.println(query);
|
||||
Serial.print("Include: ");
|
||||
Serial.println(include);
|
||||
Serial.print("Exclude: ");
|
||||
Serial.println(exclude);
|
||||
|
||||
localIp = WiFi.localIP().toString();
|
||||
id = slugify(room);
|
||||
roomsTopic = CHANNEL + "/rooms/" + id;
|
||||
statusTopic = roomsTopic + "/status";
|
||||
teleTopic = roomsTopic + "/telemetry";
|
||||
subTopic = roomsTopic + "/+/set";
|
||||
setTopic = roomsTopic + "/+/set";
|
||||
}
|
||||
|
||||
void onMqttConnect(bool sessionPresent)
|
||||
{
|
||||
xTimerStop(reconnectTimer, 0);
|
||||
mqttClient.subscribe(subTopic.c_str(), 2);
|
||||
mqttClient.subscribe("espresense/rooms/*/+/set", 1);
|
||||
mqttClient.subscribe(setTopic.c_str(), 1);
|
||||
Display.connected(true, true);
|
||||
}
|
||||
|
||||
|
@ -255,33 +262,56 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties
|
|||
|
||||
String top = String(topic);
|
||||
String pay = String(new_payload);
|
||||
if (top == roomsTopic + "/max_distance/set")
|
||||
|
||||
auto setPos = top.lastIndexOf("/set");
|
||||
if (setPos <= 1) return;
|
||||
auto commandPos = top.lastIndexOf("/", setPos - 1);
|
||||
if (commandPos < 0) return;
|
||||
auto command = top.substring(commandPos + 1, setPos);
|
||||
|
||||
if (command == "max_distance")
|
||||
{
|
||||
maxDistance = pay.toFloat();
|
||||
spurt("/max_dist", pay);
|
||||
online = false;
|
||||
}
|
||||
else if (top == roomsTopic + "/active_scan/set")
|
||||
else if (command == "active_scan")
|
||||
{
|
||||
activeScan = pay == "ON";
|
||||
spurt("/active_scan", String(activeScan));
|
||||
online = false;
|
||||
}
|
||||
else if (top == roomsTopic + "/query/set")
|
||||
else if (command == "query")
|
||||
{
|
||||
allowQuery = pay == "ON";
|
||||
spurt("/query", String(allowQuery));
|
||||
query = pay;
|
||||
spurt("/query", String(query));
|
||||
online = false;
|
||||
}
|
||||
else if (top == roomsTopic + "/status_led/set")
|
||||
else if (command == "include")
|
||||
{
|
||||
include = pay;
|
||||
spurt("/include", String(include));
|
||||
online = false;
|
||||
}
|
||||
else if (command == "exclude")
|
||||
{
|
||||
exclude = pay;
|
||||
spurt("/exclude", String(exclude));
|
||||
online = false;
|
||||
}
|
||||
else if (command == "status_led")
|
||||
{
|
||||
statusLed = pay == "ON";
|
||||
spurt("/status_led", String(statusLed));
|
||||
Display.setStatusLed(statusLed);
|
||||
online = false;
|
||||
}
|
||||
else if (command == "restart")
|
||||
{
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
fingerprints.setParams(refRssi, forgetMs, skipDistance, skipMs, maxDistance);
|
||||
fingerprints.setParams(refRssi, forgetMs, skipDistance, skipMs, maxDistance, include, exclude, query);
|
||||
}
|
||||
|
||||
void reconnect(TimerHandle_t xTimer)
|
||||
|
@ -352,7 +382,7 @@ bool reportDevice(BleFingerprint *f)
|
|||
|
||||
void scanForDevices(void *parameter)
|
||||
{
|
||||
fingerprints.setParams(refRssi, forgetMs, skipDistance, skipMs, maxDistance);
|
||||
fingerprints.setParams(refRssi, forgetMs, skipDistance, skipMs, maxDistance, include, exclude, query);
|
||||
BLEDevice::init(Stdprintf("ESPresense-%06" PRIx64, ESP.getEfuseMac() >> 24));
|
||||
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);
|
||||
|
@ -380,18 +410,25 @@ void scanForDevices(void *parameter)
|
|||
|
||||
sendTelemetry(totalSeen, totalFpSeen, totalFpQueried, totalFpReported);
|
||||
|
||||
if (allowQuery)
|
||||
if (millis() - lastQueryMillis > 3000)
|
||||
{
|
||||
auto started = millis();
|
||||
for (auto it = seen.begin(); it != seen.end(); ++it)
|
||||
{
|
||||
auto f = (*it);
|
||||
if (f->query())
|
||||
totalFpQueried++;
|
||||
|
||||
if (millis() - started > 3000) break;
|
||||
}
|
||||
|
||||
if (!pBLEScan->isScanning())
|
||||
{
|
||||
if (!pBLEScan->start(0, nullptr, false))
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = seen.begin(); it != seen.end(); ++it)
|
||||
|
|
37
src/main.h
37
src/main.h
|
@ -67,7 +67,7 @@ TaskHandle_t scannerTask;
|
|||
|
||||
bool updateInProgress = false;
|
||||
String localIp;
|
||||
unsigned long lastTeleMillis;
|
||||
unsigned long lastTeleMillis, lastQueryMillis;
|
||||
int reconnectTries = 0;
|
||||
int teleFails = 0;
|
||||
bool online = false; // Have we successfully sent status=online
|
||||
|
@ -82,10 +82,13 @@ String id;
|
|||
String statusTopic;
|
||||
String teleTopic;
|
||||
String roomsTopic;
|
||||
String subTopic;
|
||||
String setTopic;
|
||||
String query;
|
||||
String include;
|
||||
String exclude;
|
||||
bool autoUpdate, otaUpdate;
|
||||
bool discovery, statusLed;
|
||||
bool activeScan, allowQuery;
|
||||
bool activeScan;
|
||||
bool publishTele;
|
||||
bool publishRooms;
|
||||
bool publishDevices;
|
||||
|
@ -335,7 +338,7 @@ bool pub(const char *topic, uint8_t qos, bool retain, const char *payload, size_
|
|||
|
||||
bool sendOnline()
|
||||
{
|
||||
return mqttClient.publish(statusTopic.c_str(), 0, 1, "online") && mqttClient.publish((roomsTopic + "/max_distance").c_str(), 0, 1, String(maxDistance).c_str()) && mqttClient.publish((roomsTopic + "/query").c_str(), 0, 1, String(allowQuery ? "ON" : "OFF").c_str()) && mqttClient.publish((roomsTopic + "/status_led").c_str(), 0, 1, String(statusLed ? "ON" : "OFF").c_str()) && mqttClient.publish((roomsTopic + "/active_scan").c_str(), 0, 1, String(activeScan ? "ON" : "OFF").c_str());
|
||||
return mqttClient.publish(statusTopic.c_str(), 0, 1, "online") && mqttClient.publish((roomsTopic + "/max_distance").c_str(), 0, 1, String(maxDistance).c_str()) && mqttClient.publish((roomsTopic + "/query").c_str(), 0, 1, query.c_str()) && mqttClient.publish((roomsTopic + "/include").c_str(), 0, 1, include.c_str()) && mqttClient.publish((roomsTopic + "/exclude").c_str(), 0, 1, exclude.c_str()) && mqttClient.publish((roomsTopic + "/status_led").c_str(), 0, 1, String(statusLed ? "ON" : "OFF").c_str()) && mqttClient.publish((roomsTopic + "/active_scan").c_str(), 0, 1, String(activeScan ? "ON" : "OFF").c_str());
|
||||
}
|
||||
|
||||
void commonDiscovery(JsonDocument *doc)
|
||||
|
@ -613,6 +616,25 @@ bool sendDiscoveryTSL2561Lux()
|
|||
}
|
||||
#endif
|
||||
|
||||
bool sendButtonDiscovery(String name, String entityCategory)
|
||||
{
|
||||
auto slug = slugify(name);
|
||||
|
||||
DynamicJsonDocument doc(1200);
|
||||
commonDiscovery(&doc);
|
||||
doc["~"] = roomsTopic;
|
||||
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"] = "~/" + slug;
|
||||
doc["cmd_t"] = "~/" + slug + "/set";
|
||||
doc["entity_category"] = entityCategory;
|
||||
|
||||
char buffer[1200];
|
||||
serializeJson(doc, buffer);
|
||||
String discoveryTopic = "homeassistant/button/espresense_" + ESPMAC + "/" + slug + "/config";
|
||||
return pub(discoveryTopic.c_str(), 0, true, buffer);
|
||||
}
|
||||
|
||||
bool sendSwitchDiscovery(String name, String entityCategory)
|
||||
{
|
||||
|
@ -634,6 +656,13 @@ bool sendSwitchDiscovery(String name, String entityCategory)
|
|||
return pub(discoveryTopic.c_str(), 0, true, buffer);
|
||||
}
|
||||
|
||||
bool sendDeleteDiscovery(String domain, String name)
|
||||
{
|
||||
auto slug = slugify(name);
|
||||
String discoveryTopic = "homeassistant/" + domain + "/espresense_" + ESPMAC + "/" + slug + "/config";
|
||||
return pub(discoveryTopic.c_str(), 0, false, "");
|
||||
}
|
||||
|
||||
bool sendNumberDiscovery(String name, String entityCategory)
|
||||
{
|
||||
auto slug = slugify(name);
|
||||
|
|
Loading…
Reference in New Issue