From 412d4df44e347435f2bb8572e627ca496b915562 Mon Sep 17 00:00:00 2001 From: bbedward Date: Thu, 17 Jul 2025 16:21:20 -0400 Subject: [PATCH 1/5] bluetooth: expose rssi --- src/bluetooth/device.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/bluetooth/device.hpp b/src/bluetooth/device.hpp index 23f230f..57ea031 100644 --- a/src/bluetooth/device.hpp +++ b/src/bluetooth/device.hpp @@ -99,6 +99,9 @@ class BluetoothDevice: public QObject { Q_PROPERTY(bool batteryAvailable READ batteryAvailable NOTIFY batteryAvailableChanged); /// Battery level of the connected device, from `0.0` to `1.0`. Only valid if @@batteryAvailable is true. Q_PROPERTY(qreal battery READ default NOTIFY batteryChanged BINDABLE bindableBattery); + /// Received Signal Strength Indicator in dBm. Only valid when device is discoverable/advertising. + /// Typical values range from -30 (very close) to -90 (far away). Values of 0 indicate no signal data. + Q_PROPERTY(qint16 rssi READ rssi NOTIFY rssiChanged BINDABLE bindableRssi); /// The Bluetooth adapter this device belongs to. Q_PROPERTY(BluetoothAdapter* adapter READ adapter NOTIFY adapterChanged); /// DBus path of the device under the `org.bluez` system service. @@ -145,6 +148,8 @@ class BluetoothDevice: public QObject { [[nodiscard]] bool wakeAllowed() const { return this->bWakeAllowed; } void setWakeAllowed(bool wakeAllowed); + [[nodiscard]] qint16 rssi() const { return this->bRssi; } + [[nodiscard]] bool pairing() const { return this->bPairing; } [[nodiscard]] QBindable bindableAddress() { return &this->bAddress; } @@ -159,6 +164,7 @@ class BluetoothDevice: public QObject { [[nodiscard]] QBindable bindableIcon() { return &this->bIcon; } [[nodiscard]] QBindable bindableBattery() { return &this->bBattery; } [[nodiscard]] QBindable bindableState() { return &this->bState; } + [[nodiscard]] QBindable bindableRssi() { return &this->bRssi; } void addInterface(const QString& interface, const QVariantMap& properties); void removeInterface(const QString& interface); @@ -178,6 +184,7 @@ class BluetoothDevice: public QObject { void iconChanged(); void batteryAvailableChanged(); void batteryChanged(); + void rssiChanged(); void adapterChanged(); private: @@ -201,6 +208,7 @@ class BluetoothDevice: public QObject { Q_OBJECT_BINDABLE_PROPERTY(BluetoothDevice, qreal, bBattery, &BluetoothDevice::batteryChanged); Q_OBJECT_BINDABLE_PROPERTY(BluetoothDevice, BluetoothDeviceState::Enum, bState, &BluetoothDevice::stateChanged); Q_OBJECT_BINDABLE_PROPERTY(BluetoothDevice, bool, bPairing, &BluetoothDevice::pairingChanged); + Q_OBJECT_BINDABLE_PROPERTY(BluetoothDevice, qint16, bRssi, &BluetoothDevice::rssiChanged); QS_DBUS_BINDABLE_PROPERTY_GROUP(BluetoothDevice, properties); QS_DBUS_PROPERTY_BINDING(BluetoothDevice, pAddress, bAddress, properties, "Address"); @@ -214,6 +222,7 @@ class BluetoothDevice: public QObject { QS_DBUS_PROPERTY_BINDING(BluetoothDevice, pWakeAllowed, bWakeAllowed, properties, "WakeAllowed"); QS_DBUS_PROPERTY_BINDING(BluetoothDevice, pIcon, bIcon, properties, "Icon"); QS_DBUS_PROPERTY_BINDING(BluetoothDevice, pAdapterPath, bAdapterPath, properties, "Adapter"); + QS_DBUS_PROPERTY_BINDING(BluetoothDevice, pRssi, bRssi, properties, "RSSI", true); QS_DBUS_BINDABLE_PROPERTY_GROUP(BluetoothDevice, batteryProperties); QS_DBUS_PROPERTY_BINDING(BluetoothDevice, BatteryPercentage, pBattery, bBattery, batteryProperties, "Percentage", true); From d9f0a4e726e1b91c15ec6aef4a4987f2eae9b761 Mon Sep 17 00:00:00 2001 From: bbedward Date: Thu, 17 Jul 2025 16:49:36 -0400 Subject: [PATCH 2/5] bluetooth: mark rssi as a non-required property --- src/bluetooth/device.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bluetooth/device.hpp b/src/bluetooth/device.hpp index 57ea031..05afeba 100644 --- a/src/bluetooth/device.hpp +++ b/src/bluetooth/device.hpp @@ -222,7 +222,7 @@ class BluetoothDevice: public QObject { QS_DBUS_PROPERTY_BINDING(BluetoothDevice, pWakeAllowed, bWakeAllowed, properties, "WakeAllowed"); QS_DBUS_PROPERTY_BINDING(BluetoothDevice, pIcon, bIcon, properties, "Icon"); QS_DBUS_PROPERTY_BINDING(BluetoothDevice, pAdapterPath, bAdapterPath, properties, "Adapter"); - QS_DBUS_PROPERTY_BINDING(BluetoothDevice, pRssi, bRssi, properties, "RSSI", true); + QS_DBUS_PROPERTY_BINDING(BluetoothDevice, pRssi, bRssi, properties, "RSSI", false); QS_DBUS_BINDABLE_PROPERTY_GROUP(BluetoothDevice, batteryProperties); QS_DBUS_PROPERTY_BINDING(BluetoothDevice, BatteryPercentage, pBattery, bBattery, batteryProperties, "Percentage", true); From 2f2037463c1f7c17a9111ce469ab07aeeebb90ef Mon Sep 17 00:00:00 2001 From: bbedward Date: Thu, 17 Jul 2025 18:43:51 -0400 Subject: [PATCH 3/5] bluetooth: normalize signal strength instead of raw rssi --- src/bluetooth/device.cpp | 24 ++++++++++++++++++++++++ src/bluetooth/device.hpp | 14 +++++++------- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/bluetooth/device.cpp b/src/bluetooth/device.cpp index 7265b24..4dc614e 100644 --- a/src/bluetooth/device.cpp +++ b/src/bluetooth/device.cpp @@ -1,4 +1,5 @@ #include "device.hpp" +#include #include #include @@ -46,12 +47,35 @@ BluetoothDevice::BluetoothDevice(const QString& path, QObject* parent): QObject( } this->properties.setInterface(this->mInterface); + + this->bRssi.subscribe([this]() { emit this->signalStrengthChanged(); }); } BluetoothAdapter* BluetoothDevice::adapter() const { return Bluez::instance()->adapter(this->bAdapterPath.value().path()); } +qint32 BluetoothDevice::signalStrength() const { + // Convert RSSI (dBm) to a normalized 0-100 scale + // Based on practical Bluetooth RSSI ranges: + // -30 to -40 dBm = 85-100 + // -40 to -55 dBm = 65-85 + // -55 to -65 dBm = 45-65 + // -65 to -75 dBm = 25-45 + // -75 to -85 dBm = 10-25 + // <= -85 dBm = 0-10 + + auto rssiValue = this->bRssi.value(); + if (rssiValue == 0) { + return 0; + } + + auto rssi = std::max(static_cast(-100), std::min(static_cast(-30), rssiValue)); + auto normalized = static_cast(((rssi + 100) / 70.0) * 100.0); + + return std::max(0, std::min(100, normalized)); +} + void BluetoothDevice::setConnected(bool connected) { if (connected == this->bConnected) return; diff --git a/src/bluetooth/device.hpp b/src/bluetooth/device.hpp index 05afeba..9abacf6 100644 --- a/src/bluetooth/device.hpp +++ b/src/bluetooth/device.hpp @@ -99,9 +99,8 @@ class BluetoothDevice: public QObject { Q_PROPERTY(bool batteryAvailable READ batteryAvailable NOTIFY batteryAvailableChanged); /// Battery level of the connected device, from `0.0` to `1.0`. Only valid if @@batteryAvailable is true. Q_PROPERTY(qreal battery READ default NOTIFY batteryChanged BINDABLE bindableBattery); - /// Received Signal Strength Indicator in dBm. Only valid when device is discoverable/advertising. - /// Typical values range from -30 (very close) to -90 (far away). Values of 0 indicate no signal data. - Q_PROPERTY(qint16 rssi READ rssi NOTIFY rssiChanged BINDABLE bindableRssi); + /// Signal strength as a normalized score from 0 to 100, where higher is better (stronger signal). + Q_PROPERTY(qint32 signalStrength READ signalStrength NOTIFY signalStrengthChanged BINDABLE bindableSignalStrength); /// The Bluetooth adapter this device belongs to. Q_PROPERTY(BluetoothAdapter* adapter READ adapter NOTIFY adapterChanged); /// DBus path of the device under the `org.bluez` system service. @@ -148,7 +147,7 @@ class BluetoothDevice: public QObject { [[nodiscard]] bool wakeAllowed() const { return this->bWakeAllowed; } void setWakeAllowed(bool wakeAllowed); - [[nodiscard]] qint16 rssi() const { return this->bRssi; } + [[nodiscard]] qint32 signalStrength() const; [[nodiscard]] bool pairing() const { return this->bPairing; } @@ -164,7 +163,7 @@ class BluetoothDevice: public QObject { [[nodiscard]] QBindable bindableIcon() { return &this->bIcon; } [[nodiscard]] QBindable bindableBattery() { return &this->bBattery; } [[nodiscard]] QBindable bindableState() { return &this->bState; } - [[nodiscard]] QBindable bindableRssi() { return &this->bRssi; } + [[nodiscard]] QBindable bindableSignalStrength() { return &this->bSignalStrength; } void addInterface(const QString& interface, const QVariantMap& properties); void removeInterface(const QString& interface); @@ -184,7 +183,7 @@ class BluetoothDevice: public QObject { void iconChanged(); void batteryAvailableChanged(); void batteryChanged(); - void rssiChanged(); + void signalStrengthChanged(); void adapterChanged(); private: @@ -208,7 +207,8 @@ class BluetoothDevice: public QObject { Q_OBJECT_BINDABLE_PROPERTY(BluetoothDevice, qreal, bBattery, &BluetoothDevice::batteryChanged); Q_OBJECT_BINDABLE_PROPERTY(BluetoothDevice, BluetoothDeviceState::Enum, bState, &BluetoothDevice::stateChanged); Q_OBJECT_BINDABLE_PROPERTY(BluetoothDevice, bool, bPairing, &BluetoothDevice::pairingChanged); - Q_OBJECT_BINDABLE_PROPERTY(BluetoothDevice, qint16, bRssi, &BluetoothDevice::rssiChanged); + Q_OBJECT_BINDABLE_PROPERTY(BluetoothDevice, qint32, bSignalStrength, &BluetoothDevice::signalStrengthChanged); + Q_OBJECT_BINDABLE_PROPERTY(BluetoothDevice, qint16, bRssi); QS_DBUS_BINDABLE_PROPERTY_GROUP(BluetoothDevice, properties); QS_DBUS_PROPERTY_BINDING(BluetoothDevice, pAddress, bAddress, properties, "Address"); From 29ce74da059d2244f5737583707af21f72d02195 Mon Sep 17 00:00:00 2001 From: bbedward Date: Fri, 18 Jul 2025 22:36:48 -0400 Subject: [PATCH 4/5] bluetooth: adjust signal strength algorithm --- src/bluetooth/device.cpp | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/bluetooth/device.cpp b/src/bluetooth/device.cpp index 4dc614e..333a953 100644 --- a/src/bluetooth/device.cpp +++ b/src/bluetooth/device.cpp @@ -56,24 +56,23 @@ BluetoothAdapter* BluetoothDevice::adapter() const { } qint32 BluetoothDevice::signalStrength() const { - // Convert RSSI (dBm) to a normalized 0-100 scale - // Based on practical Bluetooth RSSI ranges: - // -30 to -40 dBm = 85-100 - // -40 to -55 dBm = 65-85 - // -55 to -65 dBm = 45-65 - // -65 to -75 dBm = 25-45 - // -75 to -85 dBm = 10-25 - // <= -85 dBm = 0-10 - - auto rssiValue = this->bRssi.value(); - if (rssiValue == 0) { - return 0; - } + if (this->bRssi.value() == 0) return 0; - auto rssi = std::max(static_cast(-100), std::min(static_cast(-30), rssiValue)); - auto normalized = static_cast(((rssi + 100) / 70.0) * 100.0); + auto rssi = std::clamp(static_cast(this->bRssi.value()), -100.0, -30.0); - return std::max(0, std::min(100, normalized)); + if (rssi >= -60.0) { + auto percentage = 75.0 + ((rssi + 60.0) / 30.0) * 25.0; + return static_cast(std::round(percentage)); + } + if (rssi >= -80.0) { + auto percentage = 9.0 + ((rssi + 80.0) / 20.0) * 66.0; + return static_cast(std::round(percentage)); + } + if (rssi >= -90.0) { + auto percentage = 0.0 + ((rssi + 90.0) / 10.0) * 9.0; + return static_cast(std::round(percentage)); + } + return 0; } void BluetoothDevice::setConnected(bool connected) { From 4758f4ba79e2e53ac3aa009afe1bd15d9a432a50 Mon Sep 17 00:00:00 2001 From: bbedward Date: Fri, 18 Jul 2025 22:45:48 -0400 Subject: [PATCH 5/5] Simplify function --- src/bluetooth/device.cpp | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/bluetooth/device.cpp b/src/bluetooth/device.cpp index 333a953..306ea31 100644 --- a/src/bluetooth/device.cpp +++ b/src/bluetooth/device.cpp @@ -56,23 +56,22 @@ BluetoothAdapter* BluetoothDevice::adapter() const { } qint32 BluetoothDevice::signalStrength() const { - if (this->bRssi.value() == 0) return 0; - - auto rssi = std::clamp(static_cast(this->bRssi.value()), -100.0, -30.0); - - if (rssi >= -60.0) { - auto percentage = 75.0 + ((rssi + 60.0) / 30.0) * 25.0; - return static_cast(std::round(percentage)); - } - if (rssi >= -80.0) { - auto percentage = 9.0 + ((rssi + 80.0) / 20.0) * 66.0; - return static_cast(std::round(percentage)); + const auto rssi = this->bRssi.value(); + auto percent = 0.0; + + if (rssi == 0) { + percent = 0.0; + } else if (rssi >= -30) { + percent = 100.0; + } else if (rssi >= -60) { + percent = 75.0 + ((rssi + 60.0) / 30.0) * 25.0; + } else if (rssi >= -80) { + percent = 9.0 + ((rssi + 80.0) / 20.0) * 66.0; + } else if (rssi >= -90) { + percent = ((rssi + 90.0) / 10.0) * 9.0; } - if (rssi >= -90.0) { - auto percentage = 0.0 + ((rssi + 90.0) / 10.0) * 9.0; - return static_cast(std::round(percentage)); - } - return 0; + + return static_cast(std::lround(std::clamp(percent, 0.0, 100.0))); } void BluetoothDevice::setConnected(bool connected) {