iOS/Sources/Shared/API/PeriodicUpdateManager.swift
Zac West 2250a779ea
Periodically update sensors from local push extension (#2138)
## Summary
When the Local Push extension is running (when we're on Wi-Fi in an SSID marked as 'Internal' and location is set to Always), we're given a persistent opportunity to do work. When we're running, we now update sensors on a regular interval.

## Link to pull request in Documentation repository
Documentation: home-assistant/companion.home-assistant#753

## Any other notes
Updating the metadata/sensors every 5 minutes (by default) should have minimal, if any, battery implications. This follows the same setting as the "Periodic" timer which we use for foreground updates.
2022-05-24 03:30:25 +00:00

67 lines
2.3 KiB
Swift

#if os(iOS)
import Foundation
import PromiseKit
import UIKit
public class PeriodicUpdateManager {
public let applicationStateGetter: () -> UIApplication.State
public init(applicationStateGetter: @escaping () -> UIApplication.State) {
self.applicationStateGetter = applicationStateGetter
}
private var periodicUpdateTimer: Timer? {
willSet {
if periodicUpdateTimer != newValue {
periodicUpdateTimer?.invalidate()
}
}
}
public static var supportsBackgroundPeriodicUpdates: Bool {
Current.isCatalyst || Current.isAppExtension
}
public func invalidatePeriodicUpdateTimer(forBackground: Bool = false) {
if !Self.supportsBackgroundPeriodicUpdates || !forBackground {
periodicUpdateTimer = nil
}
}
private func schedulePeriodicUpdateTimer() {
guard periodicUpdateTimer == nil || periodicUpdateTimer?.isValid == false else {
return
}
guard Self.supportsBackgroundPeriodicUpdates || applicationStateGetter() != .background else {
// it's fine to schedule, but we don't wanna fire two when we come back to foreground later
Current.Log.info("not scheduling periodic update; backgrounded")
return
}
guard let interval = Current.settingsStore.periodicUpdateInterval else {
Current.Log.info("not scheduling periodic update; disabled")
return
}
periodicUpdateTimer = Timer.scheduledTimer(withTimeInterval: interval, repeats: false) { [weak self] _ in
self?.connectAPI(reason: .periodic)
}
}
public func connectAPI(reason: HomeAssistantAPI.ConnectReason) {
Current.backgroundTask(withName: "connect-api") { _ in
when(resolved: Current.apis.map { api in
api.Connect(reason: reason)
}).asVoid()
}.done {
Current.Log.info("Connect finished for reason \(reason)")
}.catch { error in
// if the error is e.g. token is invalid, we'll force onboarding through status-code-watching mechanisms
Current.Log.error("Couldn't connect for reason \(reason): \(error)")
}.finally {
self.schedulePeriodicUpdateTimer()
}
}
}
#endif