Repository navigation
Reconnect with a start delay - #103
Conversation
|
The switch to CBConnectPeripheralOptionStartDelayKey, as we discussed, is good. I think it's better than the historic sleep (which might lose a reconnect), but it's a significant change, and probably should get some time on it. Yes, we use it in omnipod, so it seems pretty reliable. But still, this is a really key part of keeping everything working. As a nit, It looks like maybe scanAfterDelay is no longer used, but wasn't cleaned up. The part that I'm not sure about is the usage of holdProcess on the phone. It's unclear to me why this is changed. |
|
Thanks! Addressed in 43fc028 and 0d6d608:
Agreed on giving the start delay time. Without the hold it has run on my phone for about 1 h 20 min in the background with no gaps (16/16 readings), and before that for about 14 h with the hold. My pump wakes the app every minute, though, so I'll also get a build to the original reporter, whose setup has no other wake source, and post results here. |
|
Results from about 25 hours on my phone with 0d6d608 (Loop, phone direct mode, iPhone 16 Pro), Oct 30 12:17 to Oct 31 13:33 CDT. The app was in the background most of that time. The pump's BLE heartbeat was never engaged, and nothing from the pump woke the app, so the G7 alone was keeping Loop running in the background. Readings
Connectivity
There were no 30 to 40 minute stalls like the ones in the report. |
Summary
In direct mode on the phone, readings can stall for 30 to 40 minutes while the app is in the background and only resume once it is opened. This comes from a field report on Trio 1.0.2.35 (dev) and iOS 27.2; the problem predates 27.2. The reporter uses direct mode, and no other BLE device keeps the app awake: their pump has no heartbeat. Cf. nightscout/Trio#1699
What the reporter's log shows
didDisconnectPeripheralreconnects viascanAfterDelay(), which sleeps 2 s on a global queue. iOS suspends the app before that sleep ends, so bluetoothd has nothing pending and nothing wakes the app:didConnectfires at 10:21:43, then nothing is logged until 10:59:25. These links came from the old immediate reconnect landing in the advertising tail, where the link comes up but the sensor doesn't answer, so no Bluetooth event arrives to wake the app. The start delay keeps the reconnect out of the tail.Change (phone only; no watch changes)
CBConnectPeripheralOptionStartDelayKeyset to 30 s. bluetoothd has the request before the app can be suspended, and the delay lets the advertising tail pass. The value has to be a whole number of seconds: CoreBluetooth rejects a fractional one withCBErrorDomain Code=1("One or more parameters were invalid"). The request goes throughhandleDiscoveredPeripheral, soshouldConnectPeripheralstill decides. When the link that ended isn't the active peripheral's, or the radio is down, the manager rescans after 2 s as before. That wait is now amanagerQueue.asyncAfter, which replaces theThread.sleepinscanAfterDelay(), andscanAfterDelay()is removed.managerQueue_scanForPeripheralinstead of asking again right away. Without this backoff, a request the stack rejects outright turns into a tight connect/fail loop.managerQueue_scanForPeripheralleaves an active peripheral that is.connectingalone. Otherwise the per-cyclefetchNewDataIfNeeded→resumeScanningwould replace the delayed request with a plain connect.delegate?.bluetoothManager(_:logEvent:), so they appear in the app's own device log and not only inos_log.Testing
resumeScanningalways found the delayed request still pending and left it alone.CBErrorDomain Code=15encryption timeout, and one aCode=6link timeout. In each case the next request went out at once, and a later slot connected.