Skip to content

Commit

Permalink
[BLE] Add moving beacon detection (#1636)
Browse files Browse the repository at this point in the history
  • Loading branch information
1technophile authored May 11, 2023
1 parent 28f9fbf commit b166719
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 11 deletions.
Binary file added docs/img/KBeacon-app-configuration-moving.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/KBeacon-app-configuration-moving2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions docs/prerequisites/devices.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 beacons keychains||rssi for presence detection|
| 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 3 in 1|temperature/humidity/dew point/battery|
| BlueMaestro|TempoDisc 4 in 1|temperature/humidity/pressure/battery|
Expand Down
17 changes: 17 additions & 0 deletions docs/use/ble.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

## 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
A black list is a list of MAC addresses that will never be published by OMG
to set black list
Expand Down
49 changes: 39 additions & 10 deletions main/ZgatewayBT.ino
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ void BTConfig_init() {
BTConfig.pubBeaconUuidForTopic = useBeaconUuidForTopic;
BTConfig.ignoreWBlist = false;
BTConfig.presenceAwayTimer = PresenceAwayTimer;
BTConfig.movingTimer = MovingTimer;
}

// Watchdog, if there was no change of BLE scanCount, restart BT
Expand Down Expand Up @@ -149,6 +150,7 @@ String stateBTMeasures(bool start) {
jo["pubBeaconUuidForTopic"] = BTConfig.pubBeaconUuidForTopic;
jo["ignoreWBlist"] = BTConfig.ignoreWBlist;
jo["presenceawaytimer"] = BTConfig.presenceAwayTimer;
jo["movingtimer"] = BTConfig.movingTimer;
jo["btqblck"] = btQueueBlocked;
jo["btqsum"] = btQueueLengthSum;
jo["btqsnd"] = btQueueLengthCount;
Expand Down Expand Up @@ -227,6 +229,8 @@ void BTConfig_fromJson(JsonObject& BTdata, bool startup = false) {
Config_update(BTdata, "presenceUseBeaconUuid", BTConfig.presenceUseBeaconUuid);
// Timer to trigger a device state as offline if not seen
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
Config_update(BTdata, "minrssi", BTConfig.minRssi);
// Send undecoded device data
Expand Down Expand Up @@ -277,6 +281,7 @@ void BTConfig_fromJson(JsonObject& BTdata, bool startup = false) {
jo["pubBeaconUuidForTopic"] = BTConfig.pubBeaconUuidForTopic;
jo["ignoreWBlist"] = BTConfig.ignoreWBlist;
jo["presenceawaytimer"] = BTConfig.presenceAwayTimer;
jo["movingtimer"] = BTConfig.movingTimer;
// Save config into NVS (non-volatile storage)
String conf = "";
serializeJson(jsonBuffer, conf);
Expand Down Expand Up @@ -490,14 +495,15 @@ void updateDevicesStatus() {
for (vector<BLEdevice*>::iterator it = devices.begin(); it != devices.end(); ++it) {
BLEdevice* p = *it;
unsigned long now = millis();
if (p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::NUT ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::MIBAND ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::TAGIT ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::TILE ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::TILEN ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::ITAG ||
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
// Device tracker devices
if (BTConfig.presenceEnable && (p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::NUT ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::MIBAND ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::TAGIT ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::TILE ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::TILEN ||
p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::ITAG ||
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)) &&
(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();
Expand All @@ -508,6 +514,18 @@ void updateDevicesStatus() {
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;
}
}
}
}

Expand Down Expand Up @@ -722,8 +740,7 @@ void procBLETask(void* pvParameters) {
} else {
Log.trace(F("Filtered MAC device" CR));
}
if (BTConfig.presenceEnable)
updateDevicesStatus();
updateDevicesStatus();
}
delete (advertisedDevice);
}
Expand Down Expand Up @@ -977,6 +994,7 @@ void setupBT() {
Log.notice(F("minrssi: %d" CR), -abs(BTConfig.minRssi));
Log.notice(F("Low Power Mode: %d" CR), lowpowermode);
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(&jsonBTBufferQueueNext, 0); // in theory, we don't need this
Expand Down Expand Up @@ -1057,6 +1075,17 @@ void launchBTDiscovery(bool overrideDiscovery) {
model.c_str(), brand.c_str(), model_id.c_str(), macWOdots.c_str(), false,
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()) {
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
deserializeJson(jsonBuffer, properties);
Expand Down
6 changes: 5 additions & 1 deletion main/config_BT.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ extern int btQueueLengthCount;
# define TimeBtwConnect 3600000 //define default time between BLE connection attempt (not used for immediate actions); in milliseconds
#endif
#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

#ifndef BLEScanDuplicateCacheSize
Expand Down Expand Up @@ -168,6 +171,7 @@ struct BTConfig_s {
bool pubBeaconUuidForTopic; // Use iBeacon UUID as topic, instead of sender (random) MAC address
bool ignoreWBlist; // Disable Whitelist & Blacklist
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
Expand Down

0 comments on commit b166719

Please sign in to comment.