@@ -36,6 +36,11 @@ class BLEDeviceStateManager: ObservableObject {
3636 @Published var connectingDevices : [ UUID : DeviceState ] = [ : ]
3737 @Published var connectionRetryStatus : [ UUID : ConnectionRetryStatus ] = [ : ]
3838
39+ /// Devices deliberately put to sleep, and when the sleep command was sent.
40+ /// Kept independent of the device dictionaries above, which are never populated.
41+ @Published private( set) var sleepingDevices : [ UUID : Date ] = [ : ]
42+ @Published private( set) var poweringDownDevices : Set < UUID > = [ ]
43+
3944 private var connectionRetryCount : [ UUID : Int ] = [ : ]
4045 private var connectionRetryTimers : [ UUID : Timer ] = [ : ]
4146 private var connectionAttemptTimers : [ UUID : Timer ] = [ : ]
@@ -171,17 +176,47 @@ class BLEDeviceStateManager: ObservableObject {
171176 }
172177
173178 /// Set device sleeping state
179+ ///
180+ /// Sleep state is held in `sleepingDevices` rather than on `DeviceState`.
181+ /// The device dictionaries are only ever populated by `addDiscoveredDevice`,
182+ /// which nothing calls, so both are permanently empty — writing sleep state
183+ /// through an optional chain into them made every setter a silent no-op and
184+ /// made `isDeviceSleeping` always return false.
174185 func setDeviceSleeping( _ uuid: UUID , isSleeping: Bool ) {
186+ if isSleeping {
187+ sleepingDevices [ uuid] = Date ( )
188+ } else {
189+ sleepingDevices. removeValue ( forKey: uuid)
190+ }
175191 discoveredDevices [ uuid] ? . isSleeping = isSleeping
176192 connectedDevices [ uuid] ? . isSleeping = isSleeping
177193 }
178194
179195 /// Set device powering down state
180196 func setDevicePoweringDown( _ uuid: UUID , isPoweringDown: Bool ) {
197+ if isPoweringDown {
198+ poweringDownDevices. insert ( uuid)
199+ } else {
200+ poweringDownDevices. remove ( uuid)
201+ }
181202 discoveredDevices [ uuid] ? . isPoweringDown = isPoweringDown
182203 connectedDevices [ uuid] ? . isPoweringDown = isPoweringDown
183204 }
184205
206+ /// Whether automatic reconnection to this device is suppressed.
207+ ///
208+ /// This is the only thing the sleep flag gates. An earlier design also
209+ /// suppressed *discovery* of a sleeping camera, which cannot be made correct:
210+ /// a camera still shutting down and a camera that just woke up emit identical
211+ /// advertisements, so any rule based on advertisements plus elapsed time
212+ /// either undoes the user's sleep command (if it stops suppressing too early)
213+ /// or hides the camera forever (if it never stops). Suppressing only automatic
214+ /// reconnection avoids the ambiguity entirely: the camera stays visible and
215+ /// manually connectable, and the app simply never reconnects on its own.
216+ func isAutoReconnectSuppressed( for uuid: UUID ) -> Bool {
217+ return isDeviceSleeping ( uuid)
218+ }
219+
185220 /// Get device state
186221 func getDeviceState( for uuid: UUID ) -> DeviceState ? {
187222 return discoveredDevices [ uuid]
@@ -204,19 +239,21 @@ class BLEDeviceStateManager: ObservableObject {
204239
205240 /// Check if device is sleeping
206241 func isDeviceSleeping( _ uuid: UUID ) -> Bool {
207- return discoveredDevices [ uuid] ? . isSleeping ?? false
242+ return sleepingDevices [ uuid] != nil
208243 }
209244
210245 /// Check if device is powering down
211246 func isDevicePoweringDown( _ uuid: UUID ) -> Bool {
212- return discoveredDevices [ uuid ] ? . isPoweringDown ?? false
247+ return poweringDownDevices . contains ( uuid )
213248 }
214249
215250 /// Remove device from all collections
216251 func removeDevice( _ uuid: UUID ) {
217252 discoveredDevices. removeValue ( forKey: uuid)
218253 connectedDevices. removeValue ( forKey: uuid)
219254 connectingDevices. removeValue ( forKey: uuid)
255+ sleepingDevices. removeValue ( forKey: uuid)
256+ poweringDownDevices. remove ( uuid)
220257 connectionRetryStatus. removeValue ( forKey: uuid)
221258 connectionRetryCount. removeValue ( forKey: uuid)
222259
@@ -241,6 +278,8 @@ class BLEDeviceStateManager: ObservableObject {
241278 discoveredDevices. removeAll ( )
242279 connectedDevices. removeAll ( )
243280 connectingDevices. removeAll ( )
281+ sleepingDevices. removeAll ( )
282+ poweringDownDevices. removeAll ( )
244283 connectionRetryStatus. removeAll ( )
245284 connectionRetryCount. removeAll ( )
246285 connectionRetryTimers. removeAll ( )
0 commit comments