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

[BT] Device Tracker sync across gateways #1980

Closed
wants to merge 5 commits into from
Closed
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
4 changes: 1 addition & 3 deletions docs/use/ble.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,12 @@ Once the data has been transmitted to the MQTT broker, it can be easily integrat
Examples of compatible sensors among [our list](https://decoder.theengs.io/devices/devices_by_brand.html: Mi Flora, Mi jia, LYWDS02, LYWSD03MMC, ClearGrass, Mi scale, iBBQ, TPMS

## Receiving signals from BLE devices for Device Tracker detection
The gateway will detect BLE trackers from Tile, Nut, TagIt and iTag, as well as other devices with additional properties decoding like Mi Band, Amazfit, RuuviTag and others indicated as Device Trackers in the [compatible BLE devices list](https://decoder.theengs.io/devices/devices.html), and automatically create a device tracker entity following the Home Assistant discovery convention (if auto discovery is activated).
The gateway will detect BLE trackers from Tile, Nut, TagIt, iTAG, Gigaset G-Tag and TicWatch GTH (Pro), as well as other devices with additional properties decoding like Mi Band, Amazfit, RuuviTag and others indicated as Device Trackers in the [compatible BLE devices list](https://decoder.theengs.io/devices/devices.html), and automatically create a device tracker entity following the Home Assistant discovery convention (if auto discovery is activated).

The devicen tracker entity created can be attached to a person to leverage presence detection. The `away` or `not home` state is triggered if the BLE tracker is not detected during the timer defined by `presenceawaytimer`.

![Away home Home assistant view](../img/OpenMQTTGateway-BLE-tracker-Home-Assistant.png)

If you have multiple gateways, your BLE trackers may not be detected temporary by one gateway but still by the others. In this case you will see the tracker appears offline briefly and online again once it is detected by the others gateways.

By default `presenceawaytimer` is set to 120s, you can change it from the slider in your controller or with the following command (ms)

`mosquitto_pub -t home/OpenMQTTGateway/commands/MQTTtoBT/config -m '{"presenceawaytimer":66000}'`
Expand Down
2 changes: 1 addition & 1 deletion main/Zblufi.ino
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(ESP32) && defined(USE_BLUFI)

# include "NimBLEDevice.h"
# include "esp_blufi_api.h"

extern "C" {
Expand Down
52 changes: 52 additions & 0 deletions main/ZgatewayBT.ino
Original file line number Diff line number Diff line change
Expand Up @@ -376,11 +376,49 @@ void createOrUpdateDevice(const char* mac, uint8_t flags, int model, int mac_typ
}
device->sensorModel_id = model;
device->lastUpdate = millis();

// publish tracker sync message
bool isTracker = false;
std::string tag = decoder.getTheengAttribute(device->sensorModel_id, "tag");
if (tag.length() >= 4) {
isTracker = checkIfIsTracker(tag[3]);
}

if (isTracker) {
Log.trace(F("Tracker LastUpdate %u" CR), device->lastUpdate);
StaticJsonDocument<JSON_MSG_BUFFER> BLEdataBuffer;
JsonObject TrackerSyncdata = BLEdataBuffer.to<JsonObject>();
TrackerSyncdata["gatewayid"] = gateway_mac;
TrackerSyncdata["tracker"] = device->macAdr;
String origin = subjectTrackerSync;
TrackerSyncdata["origin"] = origin;
handleJsonEnqueue(TrackerSyncdata);
}

devices.push_back(device);
newDevices++;
} else {
Log.trace(F("update %s" CR), mac);
device->lastUpdate = millis();

// publish tracker sync message
bool isTracker = false;
std::string tag = decoder.getTheengAttribute(device->sensorModel_id, "tag");
if (tag.length() >= 4) {
isTracker = checkIfIsTracker(tag[3]);
}

if (isTracker) {
Log.trace(F("Tracker LastUpdate %u" CR), device->lastUpdate);
StaticJsonDocument<JSON_MSG_BUFFER> BLEdataBuffer;
JsonObject TrackerSyncdata = BLEdataBuffer.to<JsonObject>();
TrackerSyncdata["gatewayid"] = gateway_mac;
TrackerSyncdata["tracker"] = device->macAdr;
String origin = subjectTrackerSync;
TrackerSyncdata["origin"] = origin;
handleJsonEnqueue(TrackerSyncdata);
}

device->macType = mac_type;

if (flags & device_flags_isDisc) {
Expand Down Expand Up @@ -1497,6 +1535,20 @@ void MQTTtoBT(char* topicOri, JsonObject& BTdata) { // json object decoding
}
} else if (cmpToMainTopic(topicOri, subjectMQTTtoBT)) {
MQTTtoBTAction(BTdata);
} else if (strstr(topicOri, "theengs/internal") != NULL) {
if (strcmp(topicOri, subjectTrackerSync) == 0) {
if (BTdata["gatewayid"] != gateway_mac) {
for (vector<BLEdevice*>::iterator it = devices.begin(); it != devices.end(); ++it) {
if ((strcmp((*it)->macAdr, BTdata["tracker"]) == 0)) {
BLEdevice* p = *it;
if (p->lastUpdate != 0) {
p->lastUpdate = 0;
Log.notice(F("Tracker %s disassociated" CR), p->macAdr);
}
}
}
}
}
}
}
#endif
4 changes: 4 additions & 0 deletions main/config_BT.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ extern String stateBTMeasures(bool);
#define subjectBTtoMQTT "/BTtoMQTT"
#define subjectMQTTtoBTset "/commands/MQTTtoBT/config"
#define subjectMQTTtoBT "/commands/MQTTtoBT"
#define subjectTrackerSync "theengs/internal/trackersync"
// Uncomment to send undecoded device data to another gateway device for decoding
// #define MQTTDecodeTopic "undecoded"
#ifndef UseExtDecoder
Expand Down Expand Up @@ -132,6 +133,9 @@ unsigned long scanCount = 0;
# define useBeaconUuidForTopic false // define true to use iBeacon UUID as topic, instead of sender (random) MAC address
#endif

// gateway_mac for internal tracker sync
String gateway_mac = "";

/*--------------HOME ASSISTANT ROOM PRESENCE--------------*/
#define subjectHomePresence "presence/" // will send Home Assistant room presence message to this topic (first part is same for all rooms, second is room name)

Expand Down
18 changes: 17 additions & 1 deletion main/main.ino
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,17 @@ void pub(const char* topicori, JsonObject& data) {
}
serializeJson(data, dataAsString);
Log.notice(F("Send on %s msg %s" CR), topicori, dataAsString.c_str());
String topic = String(mqtt_topic) + String(gateway_name) + String(topicori);
// String topic = String(mqtt_topic) + String(gateway_name) + String(topicori);
String topic = "";
#if defined(ZgatewayBT)
if ((strcmp(topicori, subjectTrackerSync) == 0)) {
topic = subjectTrackerSync;
} else {
topic = String(mqtt_topic) + String(gateway_name) + String(topicori);
}
#else
topic = String(mqtt_topic) + String(gateway_name) + String(topicori);
#endif
#if valueAsATopic
# ifdef ZgatewayPilight
String value = data["value"];
Expand Down Expand Up @@ -912,6 +922,10 @@ void connectMQTT() {
#endif
Log.trace(F("Subscription OK to the subjects %s" CR), topic2);
}
#ifdef ZgatewayBT
client.subscribe("theengs/internal/#"); // BT internal topic channel - currently only for "theengs/internal/trackersync"
Log.trace(F("Subscription to 'theengs/internal/#'" CR));
#endif
} else {
failure_number_mqtt++; // we count the failure
Log.warning(F("failure_number_mqtt: %d" CR), failure_number_mqtt);
Expand Down Expand Up @@ -980,6 +994,7 @@ void callback(char* topic, byte* payload, unsigned int length) {
//launch the function to treat received data if this data concern OpenMQTTGateway
if ((strstr(topic, subjectMultiGTWKey) != NULL) ||
(strstr(topic, subjectGTWSendKey) != NULL) ||
(strstr(topic, "theengs/internal") != NULL) ||
(strstr(topic, subjectMQTTtoSYSupdate) != NULL))
receivingMQTT(topic, (char*)p);

Expand Down Expand Up @@ -2608,6 +2623,7 @@ String stateMeasures() {
}

#ifdef ZgatewayBT
gateway_mac = SYSdata["mac"].as<String>();
# ifdef ESP32
SYSdata["lowpowermode"] = (int)lowpowermode;
# endif
Expand Down
Loading