mirror of
https://github.com/morgan9e/macos-stats
synced 2026-04-14 00:04:15 +09:00
feat: added better fan control for M3/M4 Apple Silicon (#2924)
* Fix Ftst key handling for Apple Silicon fan control * Update CFBundleVersion to 747 in Info.plist Signed-off-by: Alex Goodkind <alex@goodkind.io> * Update TeamId and SMC.Helper certificate identifier in Info.plist Signed-off-by: Alex Goodkind <alex@goodkind.io> * Add debug logging to SMC fan control functions * Use writeWithRetry for Apple Silicon fan control writes and bump helper version to 1.0.3 * SMC fan control: serialize ops, Ftst timing, verification, logging - Helper: serial queue for setFanMode/setFanSpeed/resetFanControl - smc.swift: 3s wait after Ftst=1, longer mode retry (100ms), SMC result logging - helpers: per-fan verification with cancel-on-supersede, clearer logs - smc.swift: neutral write logs (no 'succeeded'), FAILED on error * - Updated error handling in SMCHelper to suppress expected XPC errors (codes 4097 and 4099) during helper updates/restarts. - Removed unnecessary debug print statement in ModeButtons for improved log clarity. * Update version numbers in Info.plist files to 752 and change TeamId for SMC.Helper * Add FanMode.auto3 and isAutomatic, re-add F%dMd write in automatic path, use isAutomatic in countManualFans; bump SMC Helper to 1.0.24 * Apple Silicon fan control: direct-first writes, strip diagnostic bloat Try direct F%dMd=1 write before Ftst unlock (instant on M1, fallback on M3/M4). Remove verification system, diagnostic prints, dead code. * Apple Silicon fan control: direct-first writes Try direct F%dMd=1 write before Ftst unlock (instant on M1, fallback on M3/M4). Bump helper to 1.0.2/3, Stats/Widgets to 751. --------- Signed-off-by: Alex Goodkind <alex@goodkind.io>
This commit is contained in:
@@ -71,8 +71,24 @@ internal class Popup: PopupWrapper {
|
||||
selected: self.fanValueState.rawValue
|
||||
))
|
||||
]))
|
||||
#if arch(arm64)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(self.checkFanModesAndResetFtst), name: .checkFanModes, object: nil)
|
||||
#endif
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
#if arch(arm64)
|
||||
@objc private func checkFanModesAndResetFtst() {
|
||||
let fanViews = self.list.values.compactMap { $0 as? FanView }
|
||||
guard !fanViews.isEmpty else { return }
|
||||
guard fanViews.allSatisfy({ $0.fan.mode == .automatic }) else { return }
|
||||
SMCHelper.shared.resetFanControl()
|
||||
}
|
||||
#endif
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
@@ -455,7 +471,7 @@ internal class ChartSensorView: NSStackView {
|
||||
internal class FanView: NSStackView {
|
||||
public var sizeCallback: (() -> Void)
|
||||
|
||||
private var fan: Fan
|
||||
internal var fan: Fan
|
||||
private var ready: Bool = false
|
||||
|
||||
private var helperView: NSView? = nil
|
||||
@@ -638,7 +654,7 @@ internal class FanView: NSStackView {
|
||||
height: view.frame.height - 8
|
||||
), mode: self.fan.mode)
|
||||
buttons.callback = { [weak self] (mode: FanMode) in
|
||||
if let fan = self?.fan, fan.mode != mode {
|
||||
if let fan = self?.fan, mode == .automatic || fan.mode != mode {
|
||||
self?.fan.mode = mode
|
||||
self?.fan.customMode = mode
|
||||
SMCHelper.shared.setFanMode(fan.id, mode: mode.rawValue)
|
||||
@@ -1072,6 +1088,7 @@ private class ModeButtons: NSStackView {
|
||||
self.callback(.automatic)
|
||||
|
||||
NotificationCenter.default.post(name: .syncFansControl, object: nil, userInfo: ["mode": "automatic"])
|
||||
NotificationCenter.default.post(name: .checkFanModes, object: nil)
|
||||
}
|
||||
|
||||
@objc private func manualMode(_ sender: NSButton) {
|
||||
|
||||
@@ -352,6 +352,14 @@ extension SensorsReader {
|
||||
}
|
||||
|
||||
private func getFanMode(_ id: Int) -> FanMode {
|
||||
#if arch(arm64)
|
||||
// Apple Silicon: Read F%dMd directly
|
||||
// Mode values: 0 = auto, 1 = manual, 3 = system (treated as auto for UI)
|
||||
let modeValue = Int(SMC.shared.getValue("F\(id)Md") ?? 0)
|
||||
return modeValue == 1 ? .forced : .automatic
|
||||
#else
|
||||
// Legacy Intel: Use FS! bitmask
|
||||
// Bitmask: 0 = all auto, 1 = fan 0 forced, 2 = fan 1 forced, 3 = both forced
|
||||
let fansMode: Int = Int(SMC.shared.getValue("FS! ") ?? 0)
|
||||
var mode: FanMode = .automatic
|
||||
|
||||
@@ -366,6 +374,7 @@ extension SensorsReader {
|
||||
}
|
||||
|
||||
return mode
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user