Skip to content

Commit

Permalink
Implement MQTT discovery
Browse files Browse the repository at this point in the history
  • Loading branch information
emericg committed Oct 10, 2022
1 parent 63ad5c4 commit 4ee3559
Show file tree
Hide file tree
Showing 11 changed files with 283 additions and 53 deletions.
19 changes: 18 additions & 1 deletion src/DeviceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "DeviceManager.h"
#include "DatabaseManager.h"
#include "SettingsManager.h"
#include "MqttManager.h"

#include "device.h"
#include "devices/device_flowercare.h"
Expand Down Expand Up @@ -1396,6 +1397,7 @@ void DeviceManager::addBleDevice(const QBluetoothDeviceInfo &info)

// Theengs device maybe?
if (!d) d = createTheengsDevice_fromAdv(info);
else d->setTheengsModelId("", getDeviceModelIdTheengs_fromAdv(info));

if (d)
{
Expand Down Expand Up @@ -1427,7 +1429,22 @@ void DeviceManager::addBleDevice(const QBluetoothDeviceInfo &info)
}
}

//
// Add it to the MQTT broker?
MqttManager *mqtt = MqttManager::getInstance();
if (mqtt && mqtt->getStatus())
{
QString deviceName = d->getName();
QString deviceModel_theengs = d->getModel();
QString deviceManufacturer_theengs = getDeviceBrandTheengs(deviceModel_theengs);
QString deviceAddr = d->getAddressMAC();
QString device_props = getDevicePropsTheengs(deviceModel_theengs);

// Device discovery
DeviceTheengs::createDiscoveryMQTT(deviceAddr, deviceName, deviceModel_theengs,
deviceManufacturer_theengs, device_props);
}

// Connect and handle update
connect(d, &Device::deviceUpdated, this, &DeviceManager::refreshDevices_finished);
connect(d, &Device::deviceSynced, this, &DeviceManager::syncDevices_finished);

Expand Down
11 changes: 9 additions & 2 deletions src/DeviceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ class DeviceManager: public QObject
Device *createTheengsDevice_fromDb(const QString &deviceName, const QString &deviceModel_theengs, const QString &deviceAddr);
Device *createTheengsDevice_fromAdv(const QBluetoothDeviceInfo &deviceInfo);

// THEENGS
// THEENGS dev
void fakeTheengsDevices();
void fakeTheengsData();

Expand Down Expand Up @@ -225,7 +225,14 @@ private slots:
void invalidate();

// THEENGS
Q_INVOKABLE QString getDeviceModelTheengs(const QString &modelid) const;
static Q_INVOKABLE QString getDeviceNameTheengs(const QString &modelid);
static Q_INVOKABLE QString getDeviceModelTheengs(const QString &modelid);
static Q_INVOKABLE QString getDeviceBrandTheengs(const QString &modelid);
static Q_INVOKABLE QString getDevicePropsTheengs(const QString &modelid);
QString getDeviceModelIdTheengs_fromAdv(const QBluetoothDeviceInfo &deviceInfo);

public slots:
void discoverTheengsDevices();
};

/* ************************************************************************** */
Expand Down
56 changes: 27 additions & 29 deletions src/DeviceManager_advertisement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ void DeviceManager::updateBleDevice(const QBluetoothDeviceInfo &info,

QString mac_qstr = dd->getAddressMAC();
mac_qstr.remove(':');
std::string mac_str = mac_qstr.toStdString();

const QList<quint16> &manufacturerIds = info.manufacturerIds();
for (const auto id: manufacturerIds)
Expand All @@ -76,14 +75,14 @@ void DeviceManager::updateBleDevice(const QBluetoothDeviceInfo &info,
dd->parseAdvertisementData(DeviceUtils::BLE_ADV_MANUFACTURERDATA,
id, info.manufacturerData(id));

DynamicJsonDocument doc(2048);
doc["id"] = mac_str;
ArduinoJson::DynamicJsonDocument doc(2048);
doc["id"] = mac_qstr.toStdString();
doc["name"] = info.name().toStdString();
doc["manufacturerdata"] = QByteArray::number(endian_flip_16(id), 16).rightJustified(4, '0').toStdString() + info.manufacturerData(id).toHex().toStdString();
doc["rssi"] = info.rssi();

TheengsDecoder a;
JsonObject obj = doc.as<JsonObject>();
ArduinoJson::JsonObject obj = doc.as<ArduinoJson::JsonObject>();

if (a.decodeBLEJson(obj) >= 0)
{
Expand All @@ -93,16 +92,17 @@ void DeviceManager::updateBleDevice(const QBluetoothDeviceInfo &info,
serializeJson(obj, output);
//qDebug() << "output:" << output.c_str();

dd->setTheengsModelId(QString::fromStdString(doc["model"]), QString::fromStdString(doc["model_id"]));

DeviceTheengs *ddd = dynamic_cast<DeviceTheengs*>(dd);
if (ddd) ddd->parseTheengsAdvertisement(QString::fromStdString(output));

SettingsManager *sm = SettingsManager::getInstance();
MqttManager *mq = MqttManager::getInstance();
if (sm && mq && !mac_str.empty())
if (sm && mq && !mac_qstr.isEmpty())
{
QString topic = sm->getMqttTopicA() + "/" + sm->getMqttTopicB() + "/BTtoMQTT/" + mac_qstr;

status = mq->publish(topic, QString::fromStdString(output));
status = mq->publishData(topic, QString::fromStdString(output));
}

status = true;
Expand All @@ -126,14 +126,14 @@ void DeviceManager::updateBleDevice(const QBluetoothDeviceInfo &info,
dd->parseAdvertisementData(DeviceUtils::BLE_ADV_MANUFACTURERDATA,
id.toUInt16(), info.serviceData(id));

DynamicJsonDocument doc(2048);
doc["id"] = mac_str;
ArduinoJson::DynamicJsonDocument doc(2048);
doc["id"] = mac_qstr.toStdString();
doc["name"] = info.name().toStdString();
doc["servicedata"] = info.serviceData(id).toHex().toStdString();
doc["servicedatauuid"] = QByteArray::number(id.toUInt16(), 16).rightJustified(4, '0').toStdString();
doc["rssi"] = info.rssi();

JsonObject obj = doc.as<JsonObject>();
ArduinoJson::JsonObject obj = doc.as<ArduinoJson::JsonObject>();

TheengsDecoder dec;
if (dec.decodeBLEJson(obj) >= 0)
Expand All @@ -145,16 +145,17 @@ void DeviceManager::updateBleDevice(const QBluetoothDeviceInfo &info,
serializeJson(obj, output);
//qDebug() << "output:" << output.c_str();

dd->setTheengsModelId(QString::fromStdString(doc["model"]), QString::fromStdString(doc["model_id"]));

DeviceTheengs *ddd = dynamic_cast<DeviceTheengs*>(dd);
if (ddd) ddd->parseTheengsAdvertisement(QString::fromStdString(output));

SettingsManager *sm = SettingsManager::getInstance();
MqttManager *mq = MqttManager::getInstance();
if (sm && mq)
if (sm && mq && !mac_qstr.isEmpty())
{
QString topic = sm->getMqttTopicA() + "/" + sm->getMqttTopicB() + "/BTtoMQTT/" + mac_qstr;

status = mq->publish(topic, QString::fromStdString(output));
status = mq->publishData(topic, QString::fromStdString(output));
}

status = true;
Expand Down Expand Up @@ -207,8 +208,7 @@ void DeviceManager::updateBleDevice(const QBluetoothDeviceInfo &info,
if (!status && !appleOS) // UN-KNOWN DEVICES ///////////////////////////////////////////
{
QString mac_qstr = info.address().toString();
QString mac_qstr_clean = mac_qstr;
std::string mac_str = mac_qstr.toStdString();
mac_qstr.remove(':');

const QList<quint16> &manufacturerIds = info.manufacturerIds();
for (const auto id: manufacturerIds)
Expand All @@ -218,14 +218,14 @@ void DeviceManager::updateBleDevice(const QBluetoothDeviceInfo &info,
// << "manufacturer data" << Qt::dec << info.manufacturerData(id).count() << Qt::hex
// << "bytes:" << info.manufacturerData(id).toHex();

DynamicJsonDocument doc(2048);
doc["id"] = mac_str;
ArduinoJson::DynamicJsonDocument doc(2048);
doc["id"] = mac_qstr.toStdString();
doc["name"] = info.name().toStdString();
doc["manufacturerdata"] = QByteArray::number(endian_flip_16(id), 16).rightJustified(4, '0').toStdString() + info.manufacturerData(id).toHex().toStdString();
doc["rssi"] = info.rssi();

TheengsDecoder dec;
JsonObject obj = doc.as<JsonObject>();
ArduinoJson::JsonObject obj = doc.as<ArduinoJson::JsonObject>();

if (dec.decodeBLEJson(obj) >= 0)
{
Expand All @@ -237,11 +237,10 @@ void DeviceManager::updateBleDevice(const QBluetoothDeviceInfo &info,

SettingsManager *sm = SettingsManager::getInstance();
MqttManager *mq = MqttManager::getInstance();
if (sm && mq)
if (sm && mq && !mac_qstr.isEmpty())
{
QString topic = sm->getMqttTopicA() + "/" + sm->getMqttTopicB() + "/BTtoMQTT/" + mac_qstr_clean;

status = mq->publish(topic, QString::fromStdString(output));
QString topic = sm->getMqttTopicA() + "/" + sm->getMqttTopicB() + "/BTtoMQTT/" + mac_qstr;
status = mq->publishData(topic, QString::fromStdString(output));
}

status = true;
Expand All @@ -256,15 +255,15 @@ void DeviceManager::updateBleDevice(const QBluetoothDeviceInfo &info,
// << "service data" << Qt::dec << info.serviceData(id).count() << Qt::hex
// << "bytes:" << info.serviceData(id).toHex();

DynamicJsonDocument doc(2048);
doc["id"] = mac_str;
ArduinoJson::DynamicJsonDocument doc(2048);
doc["id"] = mac_qstr.toStdString();
doc["name"] = info.name().toStdString();
doc["servicedata"] = info.serviceData(id).toHex().toStdString();
doc["servicedatauuid"] = QByteArray::number(id.toUInt16(), 16).rightJustified(4, '0').toStdString();
doc["rssi"] = info.rssi();

TheengsDecoder dec;
JsonObject obj = doc.as<JsonObject>();
ArduinoJson::JsonObject obj = doc.as<ArduinoJson::JsonObject>();

if (dec.decodeBLEJson(obj) >= 0)
{
Expand All @@ -277,11 +276,10 @@ void DeviceManager::updateBleDevice(const QBluetoothDeviceInfo &info,

SettingsManager *sm = SettingsManager::getInstance();
MqttManager *mq = MqttManager::getInstance();
if (sm && mq)
if (sm && mq && !mac_qstr.isEmpty())
{
QString topic = sm->getMqttTopicA() + "/" + sm->getMqttTopicB() + "/BTtoMQTT/" + mac_qstr_clean;

status = mq->publish(topic, QString::fromStdString(output));
QString topic = sm->getMqttTopicA() + "/" + sm->getMqttTopicB() + "/BTtoMQTT/" + mac_qstr;
status = mq->publishData(topic, QString::fromStdString(output));
}

status = true;
Expand Down
99 changes: 92 additions & 7 deletions src/DeviceManager_theengs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#include <QBluetoothAddress>
#include <QBluetoothDeviceInfo>

#include <QSqlQuery>

#include <QList>
#include <QDebug>

Expand Down Expand Up @@ -91,7 +93,7 @@ Device * DeviceManager::createTheengsDevice_fromDb(const QString &deviceName,
}
else
{
qWarning() << "Unknown device model: " << deviceModel_theengs << device_props;
qWarning() << "Unknown device model: " << deviceName << deviceModel_theengs << device_props;
}

return device;
Expand All @@ -112,13 +114,13 @@ Device * DeviceManager::createTheengsDevice_fromAdv(const QBluetoothDeviceInfo &
{
if (device_modelid_theengs.isEmpty() == false) break;

DynamicJsonDocument doc(2048);
ArduinoJson::DynamicJsonDocument doc(2048);
doc["id"] = deviceInfo.address().toString().toStdString();
doc["name"] = deviceInfo.name().toStdString();
doc["manufacturerdata"] = QByteArray::number(endian_flip_16(id), 16).rightJustified(4, '0').toStdString() + deviceInfo.manufacturerData(id).toHex().toStdString();

TheengsDecoder dec;
JsonObject obj = doc.as<JsonObject>();
ArduinoJson::JsonObject obj = doc.as<ArduinoJson::JsonObject>();

if (dec.decodeBLEJson(obj) >= 0)
{
Expand All @@ -138,14 +140,14 @@ Device * DeviceManager::createTheengsDevice_fromAdv(const QBluetoothDeviceInfo &
{
if (device_modelid_theengs.isEmpty() == false) break;

DynamicJsonDocument doc(2048);
ArduinoJson::DynamicJsonDocument doc(2048);
doc["id"] = deviceInfo.address().toString().toStdString();
doc["name"] = deviceInfo.name().toStdString();
doc["servicedata"] = deviceInfo.serviceData(id).toHex().toStdString();
doc["servicedatauuid"] = id.toString(QUuid::Id128).toStdString();

TheengsDecoder dec;
JsonObject obj = doc.as<JsonObject>();
ArduinoJson::JsonObject obj = doc.as<ArduinoJson::JsonObject>();

if (dec.decodeBLEJson(obj) >= 0)
{
Expand Down Expand Up @@ -207,9 +209,92 @@ Device * DeviceManager::createTheengsDevice_fromAdv(const QBluetoothDeviceInfo &
return device;
}

QString DeviceManager::getDeviceModelTheengs(const QString &modelid) const
QString DeviceManager::getDeviceModelIdTheengs_fromAdv(const QBluetoothDeviceInfo &deviceInfo)
{
return QString::fromUtf8(TheengsDecoder().getTheengAttribute(modelid.toLatin1(), "model"));
//qDebug() << "getDeviceModelIdTheengs_fromAdv(" << deviceInfo.name() << ")";

const QList<quint16> &manufacturerIds = deviceInfo.manufacturerIds();
for (const auto id: manufacturerIds)
{
ArduinoJson::DynamicJsonDocument doc(2048);
doc["name"] = deviceInfo.name().toStdString();
doc["manufacturerdata"] = QByteArray::number(endian_flip_16(id), 16).rightJustified(4, '0').toStdString() + deviceInfo.manufacturerData(id).toHex().toStdString();

TheengsDecoder dec;
ArduinoJson::JsonObject obj = doc.as<ArduinoJson::JsonObject>();

if (dec.decodeBLEJson(obj) >= 0)
{
QString model = QString::fromStdString(doc["model"]);
if (model == "IBEACON" && model == "IBEACON") continue;
return QString::fromStdString(doc["model_id"]);
}
}

const QList<QBluetoothUuid> &serviceIds = deviceInfo.serviceIds();
for (const auto id: serviceIds)
{
ArduinoJson::DynamicJsonDocument doc(2048);
doc["name"] = deviceInfo.name().toStdString();
doc["servicedata"] = deviceInfo.serviceData(id).toHex().toStdString();
doc["servicedatauuid"] = id.toString(QUuid::Id128).toStdString();

TheengsDecoder dec;
ArduinoJson::JsonObject obj = doc.as<ArduinoJson::JsonObject>();

if (dec.decodeBLEJson(obj) >= 0)
{
QString model = QString::fromStdString(doc["model"]);
if (model == "IBEACON" && model == "IBEACON") continue;
return QString::fromStdString(doc["model_id"]);
}
}

return QString();
}

/* ************************************************************************** */

QString DeviceManager::getDeviceNameTheengs(const QString &modelid)
{
return QString::fromUtf8(TheengsDecoder().getTheengAttribute(modelid.toLocal8Bit(), "name"));
}
QString DeviceManager::getDeviceModelTheengs(const QString &modelid)
{
return QString::fromUtf8(TheengsDecoder().getTheengAttribute(modelid.toLocal8Bit(), "model"));
}
QString DeviceManager::getDeviceBrandTheengs(const QString &modelid)
{
return QString::fromUtf8(TheengsDecoder().getTheengAttribute(modelid.toLocal8Bit(), "brand"));
}
QString DeviceManager::getDevicePropsTheengs(const QString &modelid)
{
return QString::fromUtf8(TheengsDecoder().getTheengProperties(modelid.toLocal8Bit()));
}

/* ************************************************************************** */
/* ************************************************************************** */

void DeviceManager::discoverTheengsDevices()
{
//qDebug() << "discoverTheengsDevices()";

// Load saved devices and sent discovery requests to the MQTT broker
QSqlQuery queryDevices;
if (queryDevices.exec("SELECT deviceName, deviceModel, deviceAddr FROM devices"))
{
while (queryDevices.next())
{
QString deviceName = queryDevices.value(0).toString();
QString deviceModel_theengs = queryDevices.value(1).toString();
QString deviceManufacturer_theengs = getDeviceBrandTheengs(deviceModel_theengs);
QString deviceAddr = queryDevices.value(2).toString();
QString device_props = getDevicePropsTheengs(deviceModel_theengs);

DeviceTheengs::createDiscoveryMQTT(deviceAddr, deviceName, deviceModel_theengs,
deviceManufacturer_theengs, device_props);
}
}
}

/* ************************************************************************** */
Expand Down
Loading

0 comments on commit 4ee3559

Please sign in to comment.