-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbattery.lua
More file actions
117 lines (108 loc) · 4.1 KB
/
Copy pathbattery.lua
File metadata and controls
117 lines (108 loc) · 4.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
batteryMenu = hs.menubar.new()
local alertId = nil
local lastPctShown = nil
local pollTimer = nil
local batteryWatcher = nil
local batteryWatchdog = nil
local caffeinateWatcher = nil
local lastBatteryPct = nil
local inactive = false
local function isPowerConnected()
local _, _, _, rc = hs.execute("ioreg -rn AppleSmartBattery | grep -q '\"ExternalConnected\" = Yes'")
return rc == 0
end
local function showPersistentAlert(pct)
if not alertId then
alertId = hs.alert.show(string.format("🪫 Battery low — %.0f%%", pct), 999999)
lastPctShown = pct
elseif math.abs(pct - (lastPctShown or 0)) >= 1 then
hs.alert.closeSpecific(alertId)
alertId = hs.alert.show(string.format("🪫 Battery low — %.0f%%", pct), 999999)
lastPctShown = pct
end
end
local function closePersistentAlert()
if alertId then
hs.alert.closeSpecific(alertId)
alertId = nil
lastPctShown = nil
end
end
function updateBattery()
if inactive then return end
if hs.caffeinate.get("systemIdle") or hs.caffeinate.get("displayIdle") then return end
local pct = hs.battery.percentage()
local external = isPowerConnected()
local icon = external and "⚡" or "🪫"
-- hs.printf("[Battery] %s %.0f%% (%s)", icon, pct, external and "Connected" or "Discharging")
if pct < 10 and not external then
if not pollTimer then
pollTimer = hs.timer.doEvery(5, updateBattery)
hs.printf("[Battery] Entered low mode (polling every 5s)")
end
batteryMenu:returnToMenuBar()
batteryMenu:setTitle("🪫")
batteryMenu:setTooltip(string.format("Battery low — %.0f%%", pct))
if pct < 3 then showPersistentAlert(pct) else closePersistentAlert() end
else
if pollTimer then
pollTimer:stop()
pollTimer = nil
hs.printf("[Battery] Returning to normal polling (every 60 s)")
end
closePersistentAlert()
if batteryMenu:isInMenuBar() then batteryMenu:removeFromMenuBar() end
end
lastBatteryPct = pct
end
local function startBatteryWatcher()
if batteryWatcher then
batteryWatcher:stop()
batteryWatcher = nil
end
batteryWatcher = hs.battery.watcher.new(updateBattery)
batteryWatcher:start()
updateBattery()
hs.printf("[Battery] Battery watcher started")
end
local function startCaffeinateWatcher()
if caffeinateWatcher then caffeinateWatcher:stop() end
caffeinateWatcher = hs.caffeinate.watcher.new(function(event)
if event == hs.caffeinate.watcher.screensDidSleep
or event == hs.caffeinate.watcher.screensDidLock
or event == hs.caffeinate.watcher.systemWillSleep then
if not inactive then
inactive = true
if batteryWatcher then batteryWatcher:stop() end
if pollTimer then pollTimer:stop(); pollTimer = nil end
if batteryWatchdog then batteryWatchdog:stop() end
hs.printf("[Battery] Screen inactive — timers stopped")
end
elseif event == hs.caffeinate.watcher.screensDidUnlock
or event == hs.caffeinate.watcher.screensDidWake then
if inactive then
inactive = false
hs.printf("[Battery] Screen unlocked — restarting in 5s")
hs.timer.doAfter(5, function()
startBatteryWatcher()
if batteryWatchdog then batteryWatchdog:start() end
end)
end
end
end)
caffeinateWatcher:start()
hs.printf("[Battery] Caffeinate watcher started")
end
batteryWatchdog = hs.timer.doEvery(60, function()
if inactive then return end
if not batteryWatcher then
hs.printf("[Battery] Watchdog detected missing watcher — restarting")
startBatteryWatcher()
end
if not caffeinateWatcher or not caffeinateWatcher:start() then
hs.printf("[Battery] Watchdog detected dead watcher — restarting it")
startCaffeinateWatcher()
end
end)
startCaffeinateWatcher()
startBatteryWatcher()