fix(fan): mode 或目标转速读取失败时沿用起步窗口
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
1 parent
6782efa805
commit
8919dabb6c
2 files changed
+27
-7
No files matched your search
@@ -50,13 +50,17 @@ struct FanStartupTracker {
|
||||
/// 曾读到状态键的风扇;之后读不到视为偶发失败,沿用原窗口而不是改用手动目标推断。
|
||||
private var reportsStatus: Set<Int> = []
|
||||
|
||||
mutating func update(id: Int, current: Double, target: Double, isManual: Bool,
|
||||
/// target、isManual 为 nil 表示该键读取失败。
|
||||
mutating func update(id: Int, current: Double, target: Double?, isManual: Bool?,
|
||||
status: Double?, now: TimeInterval) -> Bool {
|
||||
if status != nil { reportsStatus.insert(id) }
|
||||
if current == 0, status == nil, reportsStatus.contains(id) {
|
||||
// 缺少判断依据时视为偶发失败,沿用原窗口,避免恢复读数后重新开始提示。
|
||||
let unknown = status == nil && (reportsStatus.contains(id) || target == nil || isManual == nil)
|
||||
if current == 0, unknown {
|
||||
return startedAt[id].map { now - $0 < 10 } ?? false
|
||||
}
|
||||
let starting = status.map { $0 == 1 } ?? (isManual && target.isFinite && target > 0)
|
||||
let manualTarget = isManual == true && target.map { $0.isFinite && $0 > 0 } == true
|
||||
let starting = status.map { $0 == 1 } ?? manualTarget
|
||||
guard current == 0, starting else {
|
||||
startedAt[id] = nil
|
||||
return false
|
||||
@@ -96,12 +100,14 @@ public final class FanControl {
|
||||
guard let current = smc.double(SMCKey("F\(id)Ac")) else { return nil }
|
||||
let minimum = smc.double(SMCKey("F\(id)Mn")) ?? 0
|
||||
let maximum = smc.double(SMCKey("F\(id)Mx")) ?? 0
|
||||
let target = smc.double(SMCKey("F\(id)Tg")) ?? current
|
||||
let mode = smc.double(modeKey(id)) ?? 0
|
||||
let targetReading = smc.double(SMCKey("F\(id)Tg"))
|
||||
let target = targetReading ?? current
|
||||
let modeReading = smc.double(modeKey(id))
|
||||
let mode = modeReading ?? 0
|
||||
// 仅在读数为零时多读一个状态键,运行中的风扇沿用原采样开销。
|
||||
let status = current == 0 ? smc.double(SMCKey("F\(id)St")) : nil
|
||||
let isStarting = startup.update(id: id, current: current, target: target,
|
||||
isManual: mode == 1, status: status, now: now)
|
||||
let isStarting = startup.update(id: id, current: current, target: targetReading,
|
||||
isManual: modeReading.map { $0 == 1 }, status: status, now: now)
|
||||
return FanState(id: id, current: current, minimum: minimum, maximum: maximum,
|
||||
target: target, isManual: mode == 1, isStarting: isStarting)
|
||||
}
|
||||
|
||||
@@ -72,6 +72,20 @@ struct FanStartupTests {
|
||||
#expect(!failureWithManualTarget)
|
||||
}
|
||||
|
||||
@Test func transientModeOrTargetFailureKeepsTheFallbackWindow() {
|
||||
var tracker = FanStartupTracker()
|
||||
let initiallyStarting = tracker.update(id: 0, current: 0, target: 2000, isManual: true, status: nil, now: 0)
|
||||
#expect(initiallyStarting)
|
||||
let modeFailure = tracker.update(id: 0, current: 0, target: 2000, isManual: nil, status: nil, now: 5)
|
||||
#expect(modeFailure)
|
||||
let targetFailure = tracker.update(id: 0, current: 0, target: nil, isManual: true, status: nil, now: 11)
|
||||
#expect(!targetFailure)
|
||||
let afterRecovery = tracker.update(id: 0, current: 0, target: 2000, isManual: true, status: nil, now: 12)
|
||||
#expect(!afterRecovery)
|
||||
let neverStarted = tracker.update(id: 1, current: 0, target: nil, isManual: nil, status: nil, now: 12)
|
||||
#expect(!neverStarted)
|
||||
}
|
||||
|
||||
@Test func failedFanCountDoesNotRestartAnExpiredWindow() {
|
||||
var tracker = FanStartupTracker()
|
||||
let initiallyStarting = tracker.update(id: 0, current: 0, target: 2000, isManual: true, status: nil, now: 0)
|
||||
|
||||
Reference in new issue
Block a user