[BLE] Add moving beacon detection (#1636)

This commit is contained in:
Florian authored and GitHub committed 2023-05-11 07:42:52 -05:00
1 parent 28f9fbff60
commit b1667190d5
6 files changed
+63 -11

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

+2
View File
@@ -25,6 +25,8 @@ Added to that it retrieves the measures from the devices below. By default the d
| BLE watches with fixed MAC||rssi for presence detection| | BLE watches with fixed MAC||rssi for presence detection|
| BLE beacons keychains||rssi for presence detection| | BLE beacons keychains||rssi for presence detection|
| BlueCharm|BC08|acceleration x/y/z-axis/voltage/temperature| | BlueCharm|BC08|acceleration x/y/z-axis/voltage/temperature|
| BlueCharm|BC04P|acceleration x/y/z-axis/voltage/temperature|
| BlueCharm|BC021|acceleration x/y/z-axis/voltage/temperature|
| BlueMaestro|TempoDisc 1 in 1|temperature/battery| | BlueMaestro|TempoDisc 1 in 1|temperature/battery|
| BlueMaestro|TempoDisc 3 in 1|temperature/humidity/dew point/battery| | BlueMaestro|TempoDisc 3 in 1|temperature/humidity/dew point/battery|
| BlueMaestro|TempoDisc 4 in 1|temperature/humidity/pressure/battery| | BlueMaestro|TempoDisc 4 in 1|temperature/humidity/pressure/battery|
+17
View File
@@ -52,6 +52,23 @@ Note that you can find apps to simulate beacons and do some tests like [Beacon s
iOS version >=10 devices advertise without an extra app MAC address, nevertheless this address [changes randomly](https://github.com/1technophile/OpenMQTTGateway/issues/71) and cannot be used for presence detection. You must install an app to advertise a fixed MAC address. iOS version >=10 devices advertise without an extra app MAC address, nevertheless this address [changes randomly](https://github.com/1technophile/OpenMQTTGateway/issues/71) and cannot be used for presence detection. You must install an app to advertise a fixed MAC address.
## Receiving signals from BLE devices with accelerometers for movement detection
The gateway is designed to detect BLE trackers from BlueCharm and automatically create a binary sensor entity in accordance with the Home Assistant discovery convention, provided that auto discovery is enabled.
The binary sensor entity's state will be set to on or off based on whether the BLE beacon's x-axis acceleration value is detected during the time period defined by the movingtimer parameter.
By default, the movingtimer parameter is set to 60 seconds (60,000 ms). To modify this value, use the following command:
`mosquitto_pub -t home/OpenMQTTGateway/commands/MQTTtoBT/config -m '{"movingtimer":66000}'`
To ensure proper functionality, configure the beacon using the KBeacon or KBeaconPro app (depending on your specific sensor) with the following settings:
* In the General tab, set the Trigger Command to "motion".
* In the Slot tab, enable advertisement with the Beacon Type set to "KSensor", the Trigger Only Advertisement option set to "YES", and the Sensor Axis set to "ON".
![](../img/KBeacon-app-configuration-moving.jpg)
![](../img/KBeacon-app-configuration-moving2.jpg)
## Setting a white or black list ## Setting a white or black list
A black list is a list of MAC addresses that will never be published by OMG A black list is a list of MAC addresses that will never be published by OMG
to set black list to set black list
+39 -10
View File
@@ -104,6 +104,7 @@ void BTConfig_init() {
BTConfig.pubBeaconUuidForTopic = useBeaconUuidForTopic; BTConfig.pubBeaconUuidForTopic = useBeaconUuidForTopic;
BTConfig.ignoreWBlist = false; BTConfig.ignoreWBlist = false;
BTConfig.presenceAwayTimer = PresenceAwayTimer; BTConfig.presenceAwayTimer = PresenceAwayTimer;
BTConfig.movingTimer = MovingTimer;
} }
// Watchdog, if there was no change of BLE scanCount, restart BT // Watchdog, if there was no change of BLE scanCount, restart BT
@@ -149,6 +150,7 @@ String stateBTMeasures(bool start) {
jo["pubBeaconUuidForTopic"] = BTConfig.pubBeaconUuidForTopic; jo["pubBeaconUuidForTopic"] = BTConfig.pubBeaconUuidForTopic;
jo["ignoreWBlist"] = BTConfig.ignoreWBlist; jo["ignoreWBlist"] = BTConfig.ignoreWBlist;
jo["presenceawaytimer"] = BTConfig.presenceAwayTimer; jo["presenceawaytimer"] = BTConfig.presenceAwayTimer;
jo["movingtimer"] = BTConfig.movingTimer;
jo["btqblck"] = btQueueBlocked; jo["btqblck"] = btQueueBlocked;
jo["btqsum"] = btQueueLengthSum; jo["btqsum"] = btQueueLengthSum;
jo["btqsnd"] = btQueueLengthCount; jo["btqsnd"] = btQueueLengthCount;
@@ -227,6 +229,8 @@ void BTConfig_fromJson(JsonObject& BTdata, bool startup = false) {
Config_update(BTdata, "presenceUseBeaconUuid", BTConfig.presenceUseBeaconUuid); Config_update(BTdata, "presenceUseBeaconUuid", BTConfig.presenceUseBeaconUuid);
// Timer to trigger a device state as offline if not seen // Timer to trigger a device state as offline if not seen
Config_update(BTdata, "presenceawaytimer", BTConfig.presenceAwayTimer); Config_update(BTdata, "presenceawaytimer", BTConfig.presenceAwayTimer);
// Timer to trigger a device state as offline if not seen
Config_update(BTdata, "movingtimer", BTConfig.movingTimer);
// MinRSSI set // MinRSSI set
Config_update(BTdata, "minrssi", BTConfig.minRssi); Config_update(BTdata, "minrssi", BTConfig.minRssi);
// Send undecoded device data // Send undecoded device data
@@ -277,6 +281,7 @@ void BTConfig_fromJson(JsonObject& BTdata, bool startup = false) {
jo["pubBeaconUuidForTopic"] = BTConfig.pubBeaconUuidForTopic; jo["pubBeaconUuidForTopic"] = BTConfig.pubBeaconUuidForTopic;
jo["ignoreWBlist"] = BTConfig.ignoreWBlist; jo["ignoreWBlist"] = BTConfig.ignoreWBlist;
jo["presenceawaytimer"] = BTConfig.presenceAwayTimer; jo["presenceawaytimer"] = BTConfig.presenceAwayTimer;
jo["movingtimer"] = BTConfig.movingTimer;
// Save config into NVS (non-volatile storage) // Save config into NVS (non-volatile storage)
String conf = ""; String conf = "";
serializeJson(jsonBuffer, conf); serializeJson(jsonBuffer, conf);
@@ -490,14 +495,15 @@ void updateDevicesStatus() {
for (vector<BLEdevice*>::iterator it = devices.begin(); it != devices.end(); ++it) { for (vector<BLEdevice*>::iterator it = devices.begin(); it != devices.end(); ++it) {
BLEdevice* p = *it; BLEdevice* p = *it;
unsigned long now = millis(); unsigned long now = millis();
if (p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::NUT || // Device tracker devices
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::MIBAND || if (BTConfig.presenceEnable && (p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::NUT ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::TAGIT || p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::MIBAND ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::TILE || p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::TAGIT ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::TILEN || p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::TILE ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::ITAG || p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::TILEN ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::RUUVITAG_RAWV1 || p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::ITAG ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::RUUVITAG_RAWV2) { // We apply the offline status only for tracking device, can be extended further to all the devices p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::RUUVITAG_RAWV1 ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::RUUVITAG_RAWV2)) { // We apply the offline status only for tracking device, can be extended further to all the devices
if ((p->lastUpdate != 0) && (p->lastUpdate < (now - BTConfig.presenceAwayTimer) && (now > BTConfig.presenceAwayTimer)) && if ((p->lastUpdate != 0) && (p->lastUpdate < (now - BTConfig.presenceAwayTimer) && (now > BTConfig.presenceAwayTimer)) &&
(BTConfig.ignoreWBlist || ((!oneWhite || isWhite(p)) && !isBlack(p)))) { // Only if WBlist is disabled OR ((no white MAC OR this MAC is white) AND not a black listed MAC)) { (BTConfig.ignoreWBlist || ((!oneWhite || isWhite(p)) && !isBlack(p)))) { // Only if WBlist is disabled OR ((no white MAC OR this MAC is white) AND not a black listed MAC)) {
JsonObject BLEdata = getBTJsonObject(); JsonObject BLEdata = getBTJsonObject();
@@ -508,6 +514,18 @@ void updateDevicesStatus() {
p->lastUpdate = 0; p->lastUpdate = 0;
} }
} }
// Moving detection devices (devices with an accelerometer)
if (p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::BC08) {
if ((p->lastUpdate != 0) && (p->lastUpdate < (now - BTConfig.movingTimer) && (now > BTConfig.movingTimer)) &&
(BTConfig.ignoreWBlist || ((!oneWhite || isWhite(p)) && !isBlack(p)))) { // Only if WBlist is disabled OR ((no white MAC OR this MAC is white) AND not a black listed MAC)) {
JsonObject BLEdata = getBTJsonObject();
BLEdata["id"] = p->macAdr;
BLEdata["state"] = "offline";
pubBT(BLEdata);
// We set the lastUpdate to 0 to avoid replublishing the offline state
p->lastUpdate = 0;
}
}
} }
} }
@@ -722,8 +740,7 @@ void procBLETask(void* pvParameters) {
} else { } else {
Log.trace(F("Filtered MAC device" CR)); Log.trace(F("Filtered MAC device" CR));
} }
if (BTConfig.presenceEnable) updateDevicesStatus();
updateDevicesStatus();
} }
delete (advertisedDevice); delete (advertisedDevice);
} }
@@ -977,6 +994,7 @@ void setupBT() {
Log.notice(F("minrssi: %d" CR), -abs(BTConfig.minRssi)); Log.notice(F("minrssi: %d" CR), -abs(BTConfig.minRssi));
Log.notice(F("Low Power Mode: %d" CR), lowpowermode); Log.notice(F("Low Power Mode: %d" CR), lowpowermode);
Log.notice(F("Presence Away Timer: %d" CR), BTConfig.presenceAwayTimer); Log.notice(F("Presence Away Timer: %d" CR), BTConfig.presenceAwayTimer);
Log.notice(F("Moving Timer: %d" CR), BTConfig.movingTimer);
atomic_init(&forceBTScan, 0); // in theory, we don't need this atomic_init(&forceBTScan, 0); // in theory, we don't need this
atomic_init(&jsonBTBufferQueueNext, 0); // in theory, we don't need this atomic_init(&jsonBTBufferQueueNext, 0); // in theory, we don't need this
@@ -1057,6 +1075,17 @@ void launchBTDiscovery(bool overrideDiscovery) {
model.c_str(), brand.c_str(), model_id.c_str(), macWOdots.c_str(), false, model.c_str(), brand.c_str(), model_id.c_str(), macWOdots.c_str(), false,
stateClassNone); stateClassNone);
} }
if (p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::BC08) {
String sensor_name = String(model_id.c_str()) + "-moving";
String sensor_id = macWOdots + "-moving";
createDiscovery("binary_sensor",
discovery_topic.c_str(), sensor_name.c_str(), sensor_id.c_str(),
will_Topic, "moving", "{% if value_json.get('accx') -%}on{%- else -%}off{%- endif %}",
"on", "off", "",
0, "", "", false, "",
model.c_str(), brand.c_str(), model_id.c_str(), macWOdots.c_str(), false,
stateClassNone);
}
if (!properties.empty()) { if (!properties.empty()) {
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer; StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
deserializeJson(jsonBuffer, properties); deserializeJson(jsonBuffer, properties);
+5 -1
View File
@@ -94,7 +94,10 @@ extern int btQueueLengthCount;
# define TimeBtwConnect 3600000 //define default time between BLE connection attempt (not used for immediate actions); in milliseconds # define TimeBtwConnect 3600000 //define default time between BLE connection attempt (not used for immediate actions); in milliseconds
#endif #endif
#ifndef PresenceAwayTimer #ifndef PresenceAwayTimer
# define PresenceAwayTimer 120000 //define the time between Offline Status update for the sensors # define PresenceAwayTimer 120000 //define the time between Offline Status update for the tracker sensors
#endif
#ifndef MovingTimer
# define MovingTimer 60000 //define the time between Offline Status update for the moving sensors with an accelerometer
#endif #endif
#ifndef BLEScanDuplicateCacheSize #ifndef BLEScanDuplicateCacheSize
@@ -168,6 +171,7 @@ struct BTConfig_s {
bool pubBeaconUuidForTopic; // Use iBeacon UUID as topic, instead of sender (random) MAC address bool pubBeaconUuidForTopic; // Use iBeacon UUID as topic, instead of sender (random) MAC address
bool ignoreWBlist; // Disable Whitelist & Blacklist bool ignoreWBlist; // Disable Whitelist & Blacklist
unsigned long presenceAwayTimer; //Timer that trigger a tracker state as offline if not seen unsigned long presenceAwayTimer; //Timer that trigger a tracker state as offline if not seen
unsigned long movingTimer; //Timer that trigger a moving sensor state as offline if not seen
}; };
// Global struct to store live BT configuration data // Global struct to store live BT configuration data