Polar / Coospo / Generic HR monitors: Fix HC sync on new samples

This commit is contained in:
José Rebelo
2026-01-17 17:59:34 +00:00
parent 9971edc2a5
commit 3118d6c4fe
3 changed files with 90 additions and 1 deletions
@@ -19,6 +19,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin;
import android.content.Intent;
import android.widget.Toast;
import androidx.annotation.CallSuper;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import nodomain.freeyourgadget.gadgetbridge.BuildConfig;
@@ -44,13 +45,14 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.battery.Batter
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.battery.BatteryInfoProfile;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.heartrate.HeartRate;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.heartrate.HeartRateProfile;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.heartrate.SensorContact;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
public class GarminSupportHrm extends GarminSupport {
private final BatteryInfoProfile<GarminSupportHrm> batteryInfoProfile;
private final HeartRateProfile<GarminSupportHrm> heartRateProfile;
private boolean newSamples = false;
public GarminSupportHrm() {
addSupportedService(BatteryInfoProfile.SERVICE_UUID);
batteryInfoProfile = new BatteryInfoProfile<>(this);
@@ -80,6 +82,32 @@ public class GarminSupportHrm extends GarminSupport {
return builder;
}
@CallSuper
@Override
public void disconnect() {
if (newSamples) {
// Since we always receive samples in realtime, signal that there are new samples when we disconnect
GB.signalActivityDataFinish(getDevice());
newSamples = false;
}
super.disconnect();
}
@CallSuper
@Override
public void dispose() {
synchronized (ConnectionMonitor) {
if (newSamples) {
// Since we always receive samples in realtime, signal that there are new samples when we disconnect
GB.signalActivityDataFinish(getDevice());
newSamples = false;
}
super.dispose();
}
}
final class BatteryListener implements IntentListener {
@Override
public void notify(Intent intent) {
@@ -134,6 +162,8 @@ public class GarminSupportHrm extends GarminSupport {
}
publish(sample);
newSamples = true;
}
}
@@ -36,6 +36,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.Dev
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfoProfile
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.heartrate.HeartRate
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.heartrate.HeartRateProfile
import nodomain.freeyourgadget.gadgetbridge.util.GB
import org.slf4j.Logger
import org.slf4j.LoggerFactory
@@ -47,6 +48,8 @@ class GenericHeartRateSupport : AbstractBTLESingleDeviceSupport(LOG) {
private val versionCmd = GBDeviceEventVersionInfo()
private val batteryCmd = GBDeviceEventBatteryInfo()
private var newSamples = false
init {
val mListener = IntentListener { intent: Intent? ->
intent?.action?.let { action ->
@@ -102,6 +105,28 @@ class GenericHeartRateSupport : AbstractBTLESingleDeviceSupport(LOG) {
return builder
}
override fun disconnect() {
if (newSamples) {
// Since we always receive samples in realtime, signal that there are new samples when we disconnect
GB.signalActivityDataFinish(device)
newSamples = false
}
super.disconnect()
}
override fun dispose() {
synchronized (ConnectionMonitor) {
if (newSamples) {
// Since we always receive samples in realtime, signal that there are new samples when we disconnect
GB.signalActivityDataFinish(device)
newSamples = false
}
super.dispose()
}
}
private fun handleDeviceInfo(deviceInfo: DeviceInfo) {
LOG.debug("Device info: {}", deviceInfo)
@@ -155,6 +180,8 @@ class GenericHeartRateSupport : AbstractBTLESingleDeviceSupport(LOG) {
rrIntervalSampleProvider.persistForDevice(context, device, rrIntervalSampleList)
}
}
newSamples = true
} catch (e: Exception) {
LOG.error("Failed to save heartRate sample", e)
}
@@ -3,6 +3,8 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.polar;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import androidx.annotation.CallSuper;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,6 +43,8 @@ public class PolarH10DeviceSupport extends AbstractBTLESingleDeviceSupport {
private final GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo();
private final GBDeviceEventBatteryInfo batteryCmd = new GBDeviceEventBatteryInfo();
private boolean newSamples = false;
public static final UUID UUID_SERVICE_DEVICE_INFORMATION = GattService.UUID_SERVICE_DEVICE_INFORMATION;
public static final UUID UUID_SERVICE_BATTERY_SERVICE = GattService.UUID_SERVICE_BATTERY_SERVICE;
public static final UUID UUID_SERVICE_HEART_RATE = GattService.UUID_SERVICE_HEART_RATE;
@@ -106,6 +110,32 @@ public class PolarH10DeviceSupport extends AbstractBTLESingleDeviceSupport {
return builder;
}
@CallSuper
@Override
public void disconnect() {
if (newSamples) {
// Since we always receive samples in realtime, signal that there are new samples when we disconnect
GB.signalActivityDataFinish(getDevice());
newSamples = false;
}
super.disconnect();
}
@CallSuper
@Override
public void dispose() {
synchronized (ConnectionMonitor) {
if (newSamples) {
// Since we always receive samples in realtime, signal that there are new samples when we disconnect
GB.signalActivityDataFinish(getDevice());
newSamples = false;
}
super.dispose();
}
}
@Override
public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, byte[] value) {
if (super.onCharacteristicChanged(gatt, characteristic, value)) {
@@ -161,6 +191,8 @@ public class PolarH10DeviceSupport extends AbstractBTLESingleDeviceSupport {
final HeartRrIntervalSampleProvider rrIntervalSampleProvider = new HeartRrIntervalSampleProvider(this.getDevice(), db.getDaoSession());
rrIntervalSampleProvider.persistForDevice(getContext(), getDevice(), rrIntervalSampleList);
}
newSamples = true;
} catch (Exception e) {
LOG.error("Error acquiring database", e);
}