EQ-3: Add support for Bluetooth pairing

latest firmware of those devices requires BT pairing
master
Michael Zanetti 2023-11-24 23:37:36 +01:00
parent 8509e44104
commit 218017cacf
9 changed files with 87 additions and 42 deletions

View File

@ -426,16 +426,16 @@ void IntegrationPluginElgato::discoverThings(ThingDiscoveryInfo *info)
return;
}
foreach (const QBluetoothDeviceInfo &deviceInfo, reply->discoveredDevices()) {
if (deviceInfo.name().contains("Avea")) {
if (!verifyExistingDevices(deviceInfo)) {
ThingDescriptor descriptor(aveaThingClassId, "Avea", deviceInfo.address().toString());
foreach (const auto &deviceInfo, reply->discoveredDevices()) {
if (deviceInfo.first.name().contains("Avea")) {
if (!verifyExistingDevices(deviceInfo.first)) {
ThingDescriptor descriptor(aveaThingClassId, "Avea", deviceInfo.first.address().toString());
ParamList params;
params.append(Param(aveaThingNameParamTypeId, deviceInfo.name()));
params.append(Param(aveaThingMacAddressParamTypeId, deviceInfo.address().toString()));
params.append(Param(aveaThingNameParamTypeId, deviceInfo.first.name()));
params.append(Param(aveaThingMacAddressParamTypeId, deviceInfo.first.address().toString()));
descriptor.setParams(params);
foreach (Thing *existingThing, myThings()) {
if (existingThing->paramValue(aveaThingMacAddressParamTypeId).toString() == deviceInfo.address().toString()) {
if (existingThing->paramValue(aveaThingMacAddressParamTypeId).toString() == deviceInfo.first.address().toString()) {
descriptor.setThingId(existingThing->id());
break;
}

View File

@ -549,17 +549,18 @@ void EqivaBluetoothDiscovery::deviceDiscoveryDone()
BluetoothDiscoveryReply *reply = static_cast<BluetoothDiscoveryReply *>(sender());
reply->deleteLater();
QList<EqivaBluetoothDiscovery::DiscoveryResult> results;
if (reply->error() != BluetoothDiscoveryReply::BluetoothDiscoveryReplyErrorNoError) {
qCWarning(dcEQ3()) << "Bluetooth discovery error:" << reply->error();
emit finished(results);
return;
}
QStringList results;
foreach (const QBluetoothDeviceInfo &deviceInfo, reply->discoveredDevices()) {
qCDebug(dcEQ3()) << "Discovered Bluetooth device" << deviceInfo.name() << deviceInfo.address().toString();
if (deviceInfo.name().contains("CC-RT-BLE")) {
results.append(deviceInfo.address().toString());
foreach (const auto &deviceInfo, reply->discoveredDevices()) {
qCDebug(dcEQ3()) << "Discovered Bluetooth device" << deviceInfo.first.name() << deviceInfo.first.address().toString();
if (deviceInfo.first.name().contains("CC-RT-BLE")) {
results.append({deviceInfo.first, deviceInfo.second});
}
}

View File

@ -133,6 +133,10 @@ class EqivaBluetoothDiscovery: public QObject
{
Q_OBJECT
public:
struct DiscoveryResult {
QBluetoothDeviceInfo deviceInfo;
QBluetoothHostInfo adapter;
};
EqivaBluetoothDiscovery(BluetoothLowEnergyManager *bluetoothManager, QObject *parent = nullptr);
bool startDiscovery();
@ -141,7 +145,7 @@ private slots:
void deviceDiscoveryDone();
signals:
void finished(const QStringList &results);
void finished(const QList<DiscoveryResult> &results);
private:
BluetoothLowEnergyManager *m_bluetoothManager = nullptr;

View File

@ -100,20 +100,19 @@ void IntegrationPluginEQ3::discoverThings(ThingDiscoveryInfo *info)
connect(info, &QObject::destroyed, eqivaBluetoothDiscovery, &EqivaBluetoothDiscovery::deleteLater);
// Discovery result handler
connect(eqivaBluetoothDiscovery, &EqivaBluetoothDiscovery::finished, info, [this, info](const QStringList results){
connect(eqivaBluetoothDiscovery, &EqivaBluetoothDiscovery::finished, info, [this, info](const QList<EqivaBluetoothDiscovery::DiscoveryResult> results){
qCDebug(dcEQ3()) << "Discovery finished";
foreach (const QString &result, results) {
qCDebug(dcEQ3()) << "Discovered EQ-3 device" << result;
ThingDescriptor descriptor(eqivaBluetoothThingClassId, "Eqiva Bluetooth Thermostat", result);
foreach (const EqivaBluetoothDiscovery::DiscoveryResult &result, results) {
qCDebug(dcEQ3()) << "Discovered EQ-3 device" << result.deviceInfo.address().toString();
ThingDescriptor descriptor(eqivaBluetoothThingClassId, "Eqiva Bluetooth Thermostat", result.deviceInfo.address().toString() + " ( via " + result.adapter.address().toString() + ")");
ParamList params;
params << Param(eqivaBluetoothThingMacAddressParamTypeId, result);
params << Param(eqivaBluetoothThingMacAddressParamTypeId, result.deviceInfo.address().toString());
params << Param(eqivaBluetoothThingAdapterParamTypeId, result.adapter.address().toString());
descriptor.setParams(params);
foreach (Thing* existingThing, myThings()) {
if (existingThing->paramValue(eqivaBluetoothThingMacAddressParamTypeId).toString() == result) {
descriptor.setThingId(existingThing->id());
break;
}
Thing *existingThing = myThings().findByParams(params);
if (existingThing) {
descriptor.setThingId(existingThing->id());
}
info->addThingDescriptor(descriptor);
}
@ -132,6 +131,36 @@ void IntegrationPluginEQ3::discoverThings(ThingDiscoveryInfo *info)
info->finish(Thing::ThingErrorThingClassNotFound);
}
void IntegrationPluginEQ3::startPairing(ThingPairingInfo *info)
{
qCDebug(dcEQ3()) << "Start pairing" << info->thingClassId();
info->finish(Thing::ThingErrorNoError, QT_TR_NOOP("Press and hold the rotary button on the device to obtain the passkey."));
}
void IntegrationPluginEQ3::confirmPairing(ThingPairingInfo *info, const QString &user, const QString &secret)
{
qCDebug(dcEQ3()) << "confirm" << info->thingName() << secret << user;
QBluetoothAddress device(info->params().paramValue(eqivaBluetoothThingMacAddressParamTypeId).toString());
QBluetoothAddress localDevice(info->params().paramValue(eqivaBluetoothThingAdapterParamTypeId).toString());
BluetoothPairingJob *job = hardwareManager()->bluetoothLowEnergyManager()->pairDevice(device, localDevice);
if (job->isFinished() && !job->success()) {
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Unable to initiate pairing with Bluetooth device."));
return;
}
connect(job, &BluetoothPairingJob::passKeyRequested, info, [secret, job](){
qCDebug(dcEQ3()) << "Pin code requested.";
job->passKeyEntered(secret);
});
connect(job, &BluetoothPairingJob::finished, info, [=](bool success){
if (!success) {
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("An error happened during Bluetooth pairing. Please try again."));
} else {
info->finish(Thing::ThingErrorNoError);
}
});
}
void IntegrationPluginEQ3::setupThing(ThingSetupInfo *info)
{
@ -231,6 +260,8 @@ void IntegrationPluginEQ3::thingRemoved(Thing *thing)
if (thing->thingClassId() == eqivaBluetoothThingClassId) {
qCDebug(dcEQ3) << "Removing Eqiva device" << thing->name();
hardwareManager()->bluetoothLowEnergyManager()->unpairDevice(QBluetoothAddress(thing->paramValue(eqivaBluetoothThingMacAddressParamTypeId).toString()),
QBluetoothAddress(thing->paramValue(eqivaBluetoothThingAdapterParamTypeId).toString()));
m_eqivaDevices.take(thing)->deleteLater();
}

View File

@ -54,6 +54,9 @@ public:
void init() override;
void discoverThings(ThingDiscoveryInfo *info) override;
void startPairing(ThingPairingInfo *info) override;
void confirmPairing(ThingPairingInfo *info, const QString &user, const QString &secret) override;
void setupThing(ThingSetupInfo *info) override;
void thingRemoved(Thing *thing) override;

View File

@ -535,13 +535,19 @@
"displayName": "Eqiva Bluetooth Smart Radiator Thermostat",
"interfaces": ["thermostat", "wirelessconnectable", "battery"],
"createMethods": ["discovery"],
"setupMethod": "JustAdd",
"setupMethod": "EnterPin",
"paramTypes": [
{
"id": "56a77560-e1a3-44fa-8136-57fe5a8d1cbe",
"name": "macAddress",
"displayName": "MAC Address",
"type": "QString"
},
{
"id": "37915a7a-65a4-48ed-8d86-d83500b38f3e",
"name": "adapter",
"displayName": "Adapter",
"type": "QString"
}
],
"stateTypes": [

View File

@ -79,15 +79,15 @@ void IntegrationPluginFlowercare::discoverThings(ThingDiscoveryInfo *info)
qCDebug(dcFlowerCare()) << "Discovery finished";
foreach (const QBluetoothDeviceInfo &deviceInfo, reply->discoveredDevices()) {
qCDebug(dcFlowerCare()) << "Discovered device" << deviceInfo.name();
if (deviceInfo.name().contains("Flower care")) {
ThingDescriptor descriptor(flowerCareThingClassId, deviceInfo.name(), deviceInfo.address().toString());
foreach (const auto &deviceInfo, reply->discoveredDevices()) {
qCDebug(dcFlowerCare()) << "Discovered device" << deviceInfo.first.name();
if (deviceInfo.first.name().contains("Flower care")) {
ThingDescriptor descriptor(flowerCareThingClassId, deviceInfo.first.name(), deviceInfo.first.address().toString());
ParamList params;
params << Param(flowerCareThingMacParamTypeId, deviceInfo.address().toString());
params << Param(flowerCareThingMacParamTypeId, deviceInfo.first.address().toString());
descriptor.setParams(params);
foreach (Thing *existingThing, myThings()) {
if (existingThing->paramValue(flowerCareThingMacParamTypeId).toString() == deviceInfo.address().toString()) {
if (existingThing->paramValue(flowerCareThingMacParamTypeId).toString() == deviceInfo.first.address().toString()) {
descriptor.setThingId(existingThing->id());
break;
}

View File

@ -65,18 +65,18 @@ void IntegrationPluginSenic::discoverThings(ThingDiscoveryInfo *info)
return;
}
foreach (const QBluetoothDeviceInfo &deviceInfo, reply->discoveredDevices()) {
if (deviceInfo.name().contains("Nuimo")) {
ThingDescriptor descriptor(nuimoThingClassId, "Nuimo", deviceInfo.name() + " (" + deviceInfo.address().toString() + ")");
foreach (const auto &deviceInfo, reply->discoveredDevices()) {
if (deviceInfo.first.name().contains("Nuimo")) {
ThingDescriptor descriptor(nuimoThingClassId, "Nuimo", deviceInfo.first.name() + " (" + deviceInfo.first.address().toString() + ")");
ParamList params;
foreach (Thing *existingThing, myThings()) {
if (existingThing->paramValue(nuimoThingMacParamTypeId).toString() == deviceInfo.address().toString()) {
if (existingThing->paramValue(nuimoThingMacParamTypeId).toString() == deviceInfo.first.address().toString()) {
descriptor.setThingId(existingThing->id());
break;
}
}
params.append(Param(nuimoThingMacParamTypeId, deviceInfo.address().toString()));
params.append(Param(nuimoThingMacParamTypeId, deviceInfo.first.address().toString()));
descriptor.setParams(params);
info->addThingDescriptor(descriptor);
}

View File

@ -66,21 +66,21 @@ void IntegrationPluginTexasInstruments::discoverThings(ThingDiscoveryInfo *info)
return;
}
foreach (const QBluetoothDeviceInfo &deviceInfo, reply->discoveredDevices()) {
foreach (const auto &deviceInfo, reply->discoveredDevices()) {
if (deviceInfo.name().contains("SensorTag")) {
if (deviceInfo.first.name().contains("SensorTag")) {
ThingDescriptor descriptor(sensorTagThingClassId, "Sensor Tag", deviceInfo.address().toString());
ThingDescriptor descriptor(sensorTagThingClassId, "Sensor Tag", deviceInfo.first.address().toString());
Things existingThing = myThings().filterByParam(sensorTagThingMacParamTypeId, deviceInfo.address().toString());
Things existingThing = myThings().filterByParam(sensorTagThingMacParamTypeId, deviceInfo.first.address().toString());
if (!existingThing.isEmpty()) {
descriptor.setThingId(existingThing.first()->id());
}
ParamList params;
params.append(Param(sensorTagThingMacParamTypeId, deviceInfo.address().toString()));
params.append(Param(sensorTagThingMacParamTypeId, deviceInfo.first.address().toString()));
foreach (Thing *existingThing, myThings()) {
if (existingThing->paramValue(sensorTagThingMacParamTypeId).toString() == deviceInfo.address().toString()) {
if (existingThing->paramValue(sensorTagThingMacParamTypeId).toString() == deviceInfo.first.address().toString()) {
descriptor.setThingId(existingThing->id());
break;
}