From 247a9549203e3691bb8df157406f7dd6e3911a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Rebelo?= Date: Sat, 22 Jul 2023 20:31:26 +0100 Subject: [PATCH] Huami/Zepp OS: Improve reconnection - Remove notification on unneeded characteristics for Zepp OS devices - Reset MTU before initializing device, since the support class is reused when reconnecting, and keeping the previous high MTU before renegotiating again can make the initialization fail sometimes (band will never reply) - If any of the chunked characteristics is null during initialization, mark the device as waiting for reconnect, which will make it retry the connection later with a backoff delay. --- .../btle/AbstractBTLEDeviceSupport.java | 8 ++-- .../devices/huami/Huami2021Support.java | 9 ++++- .../service/devices/huami/HuamiSupport.java | 37 +++++++++++++++---- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java index 7de4aed26..79566f3bf 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java @@ -23,9 +23,9 @@ import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattService; -import android.location.Location; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.ArrayList; @@ -38,8 +38,6 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.Logging; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; -import nodomain.freeyourgadget.gadgetbridge.model.Reminder; -import nodomain.freeyourgadget.gadgetbridge.model.WorldClock; import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.CheckInitializedAction; import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.AbstractBleProfile; @@ -56,6 +54,8 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.AbstractBlePro * @see BtLEQueue */ public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport implements GattCallback, GattServerCallback { + private static final Logger LOG = LoggerFactory.getLogger(AbstractBTLEDeviceSupport.class); + private BtLEQueue mQueue; private Map mAvailableCharacteristics; private final Set mSupportedServices = new HashSet<>(4); @@ -136,11 +136,13 @@ public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport im */ public TransactionBuilder performInitialized(String taskName) throws IOException { if (!isConnected()) { + LOG.debug("Connecting to device for {}", taskName); if (!connect()) { throw new IOException("1: Unable to connect to device: " + getDevice()); } } if (!isInitialized()) { + LOG.debug("Initializing device for {}", taskName); // first, add a transaction that performs device initialization TransactionBuilder builder = createTransactionBuilder("Initialize device"); builder.add(new CheckInitializedAction(gbDevice)); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/Huami2021Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/Huami2021Support.java index 41cd4b51c..9a4fba27b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/Huami2021Support.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/Huami2021Support.java @@ -720,11 +720,16 @@ public abstract class Huami2021Support extends HuamiSupport implements ZeppOsFil return this; } + @Override + public HuamiSupport enableNotifications(final TransactionBuilder builder, final boolean enable) { + builder.notify(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_CHUNKEDTRANSFER_2021_READ), enable); + return this; + } + @Override public Huami2021Support enableFurtherNotifications(final TransactionBuilder builder, final boolean enable) { - builder.notify(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_CHUNKEDTRANSFER_2021_READ), enable); - + // Nothing to do here, they are already enabled from enableNotifications return this; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java index 139c8d2fd..5005a2a28 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java @@ -333,7 +333,10 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements protected boolean isMusicAppStarted = false; protected MediaManager mediaManager; private boolean heartRateNotifyEnabled; - private int mMTU = 23; + private static final int MIN_MTU = 23; + private int mMTU = MIN_MTU; + // Keep track of the previous MTU before reconnection, so that we can request it after reconnection + private int previousMtu = -1; protected int mActivitySampleSize = 4; protected Huami2021ChunkedEncoder huami2021ChunkedEncoder; @@ -371,6 +374,12 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements @Override protected TransactionBuilder initializeDevice(TransactionBuilder builder) { + if (getMTU() != MIN_MTU) { + // Reset the MTU before re-initializing the device, otherwise initialization will sometimes fail + previousMtu = getMTU(); + setMtu(MIN_MTU); + } + try { byte authFlags = getAuthFlags(); byte cryptFlags = getCryptFlags(); @@ -385,8 +394,13 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements if (characteristicChunked2021Write != null && huami2021ChunkedEncoder == null) { huami2021ChunkedEncoder = new Huami2021ChunkedEncoder(characteristicChunked2021Write, force2021Protocol(), mMTU); } - if (characteristicChunked2021Write != null && force2021Protocol()) { - new InitOperation2021(authenticate, authFlags, cryptFlags, this, builder, huami2021ChunkedEncoder, huami2021ChunkedDecoder).perform(); + if (force2021Protocol()) { + if (characteristicChunked2021Write != null && characteristicChunked2021Read != null) { + new InitOperation2021(authenticate, authFlags, cryptFlags, this, builder, huami2021ChunkedEncoder, huami2021ChunkedDecoder).perform(); + } else { + LOG.warn("Chunked 2021 characteristics are null, will attempt to reconnect"); + builder.add(new SetDeviceStateAction(getDevice(), State.WAITING_FOR_RECONNECT, getContext())); + } } else { new InitOperation(authenticate, authFlags, cryptFlags, this, builder).perform(); } @@ -510,7 +524,6 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements // TODO: tear down the notifications on quit public HuamiSupport enableNotifications(TransactionBuilder builder, boolean enable) { builder.notify(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_NOTIFICATION), enable); - builder.notify(getCharacteristic(GattService.UUID_SERVICE_CURRENT_TIME), enable); // Notify CHARACTERISTIC9 to receive random auth code builder.notify(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_AUTH), enable); if (characteristicChunked2021Read != null) { @@ -4116,6 +4129,13 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements public void phase2Initialize(TransactionBuilder builder) { LOG.info("phase2Initialize..."); + + if (previousMtu > MIN_MTU) { + // We're reconnecting - request the previously set MTU + builder.requestMtu(previousMtu); + previousMtu = -1; + } + requestBatteryInfo(builder); } @@ -4171,13 +4191,12 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements } protected void setMtu(final int mtu) { - final Prefs prefs = getDevicePrefs(); - if (!prefs.getBoolean(PREF_ALLOW_HIGH_MTU, true)) { + if (mtu > MIN_MTU && !allowHighMtu()) { LOG.warn("High MTU is not allowed, ignoring"); return; } - if (mtu < 23) { + if (mtu < MIN_MTU) { LOG.error("Device announced unreasonable low MTU of {}, ignoring", mtu); return; } @@ -4188,6 +4207,10 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements } } + protected boolean allowHighMtu() { + return getDevicePrefs().getBoolean(PREF_ALLOW_HIGH_MTU, true); + } + public int getActivitySampleSize() { return mActivitySampleSize; }