Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BLE] Add moving beacon detection #1636

Merged
merged 1 commit into from
May 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -102,6 +102,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 ESP
Expand Down Expand Up @@ -146,6 +147,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 @@ -222,6 +224,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 @@ -272,6 +276,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 @@ -485,14 +490,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 @@ -503,6 +509,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 @@ -717,8 +735,7 @@ void procBLETask(void* pvParameters) {
} else {
Log.trace(F("Filtered MAC device" CR));
}
if (BTConfig.presenceEnable)
updateDevicesStatus();
updateDevicesStatus();
}
delete (advertisedDevice);
}
Expand Down Expand Up @@ -941,6 +958,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 @@ -1040,6 +1058,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