From 7234cb36188112c535396eef68e8f044c986063d Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Thu, 8 Oct 2026 14:38:23 -0500 Subject: [PATCH] Thin Live Activity glucose points so one-minute CGMs fit the size limit ActivityKit drops updates whose content state encodes to more than 4 KB, without an error. Libre sensors report every minute, so the activity carried the 100-sample cap plus the prediction line: about 5.4 KB in JSON, against about 3 KB for a G7. Every update was dropped and the activity stayed on the empty placeholder, showing 0.0 and "Open the app to update the widget" (LoopKit/Loop#2456). Send the chart at most one point per ~5 minutes, keeping the latest. The current value and delta still use every sample. --- .../Live Activity/LiveActivityManager.swift | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Loop/Managers/Live Activity/LiveActivityManager.swift b/Loop/Managers/Live Activity/LiveActivityManager.swift index a9db6b7e3e..ebd2273caa 100644 --- a/Loop/Managers/Live Activity/LiveActivityManager.swift +++ b/Loop/Managers/Live Activity/LiveActivityManager.swift @@ -185,7 +185,8 @@ class LiveActivityManager : LiveActivityManagerProxy { ) } - let yAxisPoints = glucoseSamples.map{ item in item.quantity.doubleValue(for: unit) } + predicatedGlucose + let chartSamples = Self.thinned(glucoseSamples) + let yAxisPoints = chartSamples.map{ item in item.quantity.doubleValue(for: unit) } + predicatedGlucose let chartYAxis = ChartAxisGenerator.getYAxis( points: yAxisPoints, isMmol: unit == LoopUnit.millimolesPerLiter @@ -204,9 +205,8 @@ class LiveActivityManager : LiveActivityManagerProxy { isCloseLoop: statusContext?.isClosedLoop ?? false, lastCompleted: statusContext?.lastLoopCompleted, bottomRow: bottomRow, - // In order to prevent maxSize errors, only allow the last 100 samples to be sent - // Will most likely not be an issue, might be an issue for debugging/CGM simulator with 5sec interval - glucoseSamples: glucoseSamples.suffix(100).map { item in + // ActivityKit silently drops updates over 4 KB + glucoseSamples: chartSamples.suffix(100).map { item in return GlucoseSampleAttributes(x: item.startDate, y: item.quantity.doubleValue(for: unit)) }, predicatedGlucose: predicatedGlucose, @@ -345,6 +345,18 @@ class LiveActivityManager : LiveActivityManagerProxy { // If the chart start falls past the half-hour mark (HH:31–HH:59), pull it back to HH:30 // so that the nearest hour label is never truncated at the left edge. + /// At most one sample per ~5 minutes, keeping the latest, so one-minute CGMs fit the update size limit. + static func thinned(_ samples: [StoredGlucoseSample], minimumSpacing: TimeInterval = .minutes(4.5)) -> [StoredGlucoseSample] { + var kept: [StoredGlucoseSample] = [] + for sample in samples.reversed() { + if let last = kept.last, last.startDate.timeIntervalSince(sample.startDate) < minimumSpacing { + continue + } + kept.append(sample) + } + return kept.reversed() + } + private func adjustedChartStart(_ date: Date) -> Date { let calendar = Calendar.current let minute = calendar.component(.minute, from: date)