From 218017cacf364677c34c840941905f4c62973355 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Fri, 24 Nov 2023 23:37:36 +0100 Subject: [PATCH] EQ-3: Add support for Bluetooth pairing latest firmware of those devices requires BT pairing --- elgato/integrationpluginelgato.cpp | 14 ++--- eq-3/eqivabluetooth.cpp | 13 ++--- eq-3/eqivabluetooth.h | 6 ++- eq-3/integrationplugineq-3.cpp | 51 +++++++++++++++---- eq-3/integrationplugineq-3.h | 3 ++ eq-3/integrationplugineq-3.json | 8 ++- flowercare/integrationpluginflowercare.cpp | 12 ++--- senic/integrationpluginsenic.cpp | 10 ++-- .../integrationplugintexasinstruments.cpp | 12 ++--- 9 files changed, 87 insertions(+), 42 deletions(-) diff --git a/elgato/integrationpluginelgato.cpp b/elgato/integrationpluginelgato.cpp index 87adacbe..65961388 100644 --- a/elgato/integrationpluginelgato.cpp +++ b/elgato/integrationpluginelgato.cpp @@ -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; } diff --git a/eq-3/eqivabluetooth.cpp b/eq-3/eqivabluetooth.cpp index 78e22720..e84c0ac6 100644 --- a/eq-3/eqivabluetooth.cpp +++ b/eq-3/eqivabluetooth.cpp @@ -549,17 +549,18 @@ void EqivaBluetoothDiscovery::deviceDiscoveryDone() BluetoothDiscoveryReply *reply = static_cast(sender()); reply->deleteLater(); + QList 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}); } } diff --git a/eq-3/eqivabluetooth.h b/eq-3/eqivabluetooth.h index 8a58b357..da458e91 100644 --- a/eq-3/eqivabluetooth.h +++ b/eq-3/eqivabluetooth.h @@ -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 &results); private: BluetoothLowEnergyManager *m_bluetoothManager = nullptr; diff --git a/eq-3/integrationplugineq-3.cpp b/eq-3/integrationplugineq-3.cpp index 7d05b3e2..84357963 100644 --- a/eq-3/integrationplugineq-3.cpp +++ b/eq-3/integrationplugineq-3.cpp @@ -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 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(); } diff --git a/eq-3/integrationplugineq-3.h b/eq-3/integrationplugineq-3.h index d8282e6e..f1bdab49 100644 --- a/eq-3/integrationplugineq-3.h +++ b/eq-3/integrationplugineq-3.h @@ -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; diff --git a/eq-3/integrationplugineq-3.json b/eq-3/integrationplugineq-3.json index e98af5dd..3e82139c 100644 --- a/eq-3/integrationplugineq-3.json +++ b/eq-3/integrationplugineq-3.json @@ -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": [ diff --git a/flowercare/integrationpluginflowercare.cpp b/flowercare/integrationpluginflowercare.cpp index 61d6429d..4f9c1271 100644 --- a/flowercare/integrationpluginflowercare.cpp +++ b/flowercare/integrationpluginflowercare.cpp @@ -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; } diff --git a/senic/integrationpluginsenic.cpp b/senic/integrationpluginsenic.cpp index dab42dd9..ceca3bcc 100644 --- a/senic/integrationpluginsenic.cpp +++ b/senic/integrationpluginsenic.cpp @@ -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); } diff --git a/texasinstruments/integrationplugintexasinstruments.cpp b/texasinstruments/integrationplugintexasinstruments.cpp index 9892fbff..e4501661 100644 --- a/texasinstruments/integrationplugintexasinstruments.cpp +++ b/texasinstruments/integrationplugintexasinstruments.cpp @@ -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; }