-
Notifications
You must be signed in to change notification settings - Fork 0
/
status
executable file
·297 lines (252 loc) · 8.76 KB
/
status
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
#!/usr/bin/env fish
# this status is implemented by a series of generator functions called on different periods
# by convention these functions are paired with an out variable and a period variable
# the out variable is the string representation of the output of generation
# the period denotes how frequently in seconds to run the generator
#
# a period of -1 denotes a generator which should not be run on a period
#
# only functions whos base name is listed in the names variable will be checked
set names wifi audio player cpu memory brightness power datetime weather
# this sends the status text over the fifo pipe, and is called at the bottom of the file
function write_display
echo "all status $player_out $weather_out $audio_out $wifi_out $brightness_out $memory_out $cpu_out $power_out $datetime_out" >$FIFO
end
# ---- utils ----
function subprocess_call --argument name
fish -c "$(functions $name); $name" &
end
# ---- end utils ----
# ---- generators ----
# a repeated pattern is to use refresh status inside a subprocess computation for "async" work
# the computation is run inside a subprocess that writes its result to the refresh dir
set wifi_out ""
set wifi_period 120
function wifi_fn
# this is an expensive piece of work...
function compute_wifi
set wifi_value (nmcli -f IN-USE,SSID,RATE,SIGNAL dev wifi | awk '/\*/ {$1=""; print $0 }' | string trim)
refresh_status wifi "^fg($fish_color_redirection)[$wifi_value%]"
end
subprocess_call compute_wifi
end
set audio_out ""
# refreshed on keyboard shortcut
set audio_period -1
function audio_fn
set default_sink (wpctl get-volume @DEFAULT_AUDIO_SINK@)
set volume (echo $default_sink | rg -o ': ((?:\\d|\\.)+)' -r '$1')
set volume (math "$volume * 100")
set icon
set color "$fish_color_command"
if echo $default_sink | rg MUTED >/dev/null
set icon
set color "$fish_color_error"
end
set audio_out "^fg($color)[$icon $volume%]"
end
set player_out ""
set player_period -1
# player is bound to playerctl events
function player_fn
set player_out ""
end
function player_watcher
fish -c "playerctl --follow metadata --format '{{title}} by {{artist}}'" | while read -l value
refresh_status player "^fg($fish_color_comment)$(string shorten --max 60 "$value")"
end
end
subprocess_call player_watcher
set weather_out ""
set happy_weather_period 1800 # 30 minutes
set offline_weather_period 300 # 5 minutes
set error_weather_period 3600 # 60 minutes
set weather_period $happy_weather_period
# this could be in a subprocess, but its very infrequent...
# and subprocesses cant mutate periods
function weather_fn
echo curling weather
set resp \
(curl -sw '\n%{http_code}\n' 'https://wttr.in?format=%t,%20feels%20%f%20%c')
if test $status -eq 0
set lines (string split '\n' $resp)
set weather_desc $lines[1]
set http_code $lines[-1]
if test $http_code = 200
set weather_out "^fg(#ebdbb2)[$(string trim $weather_desc)]"
set weather_period $happy_weather_period
else
# http error code :3
set http_status_label (http_status $http_code)
set weather_out "^fg(#ebdbb2)[$(string lower $http_status_label)]"
set weather_period $error_weather_period
end
else
# offline
echo retrying in $offline_weather_period
set weather_period $offline_weather_period
end
end
set cpu_out ""
set cpu_period 15
function cpu_fn
set -l cpu (grep -o "^[^ ]*" /proc/loadavg)
set -l graph (tracked_statistic_graph --key=cpu --min_height=8 --width=5 $cpu)
set cpu_out "^fg($fish_color_command) $cpu $graph"
end
set memory_out ""
set memory_period 15
function memory_fn
set -l memory (free -h | sed -n "2s/\([^ ]* *\)\{2\}\([^ ]*\).*/\2/p")
set -l memory_bytes (free | sed -n "2s/\([^ ]* *\)\{2\}\([^ ]*\).*/\2/p")
set -l graph (tracked_statistic_graph -kmemory -h1.6e+7 -w5 $memory_bytes)
set memory_out "^fg($fish_color_quote) $memory $graph"
end
set brightness_out ""
set brightness_period 240
set backlight /sys/class/backlight/amdgpu_bl2/
function brightness_fn
set val (math --scale 1 "($(cat $backlight/brightness) / $(cat $backlight/max_brightness)) * 100")
set brightness_out "^fg($fish_color_comment) $val%"
end
# ---- power section ----
set battery_path /sys/class/power_supply/BAT0
# computed with n+1
set max_samples 9
set current_samples (bat $battery_path/current_now)
function list_sum
set total 0
for val in $argv
set total (math "$total + $val")
end
echo $total
end
# sample the cumulative average of the current
function average_current
set --append current_samples (bat $battery_path/current_now)
set average (math "$(list_sum $current_samples) / $(count $current_samples)")
while test (count $current_samples) -gt $max_samples
set --erase current_samples[1]
end
echo $average
end
# math, rounded and padded to 1 sig fig to reduce shift
function padmath -a compute
printf "%.1f" (math --scale 1 $compute)
end
set power_out ""
set power_period 15
set battery_icons
function power_fn
set power_percent (cat $battery_path/capacity)
set battery_icon $battery_icons[(math --scale 0 "$power_percent / 10 + 1")]
set power_status (cat /sys/class/power_supply/BAT0/status)
set detail " "
if test "$power_status" = Discharging
set discharge_watts (padmath \
"$(cat $battery_path/current_now) * $(cat $battery_path/voltage_now) * 1e-12")
set time_remaining (date -u -d @(math "($(bat $battery_path/charge_now) / $(average_current)) * 60 * 60") +"%-H:%M")
set watts_graph (tracked_statistic_graph --key=watts --min_height=25 --width=5 (math "max(0, $discharge_watts - 4)"))
# padding to 18 prevents layout shift when watts goes above then below 10
# USUALLY an estimate of 10 hours or greater is paired with a wattage below 10
set detail (string pad -w 18 " $discharge_watts""w $time_remaining $watts_graph ")
end
if test "$power_status" = Charging
set detail " "
end
set power_out "^fg($fish_color_comment)[$battery_icon""$detail""$power_percent%]"
end
# ---- end power section ----
set datetime_out ""
set datetime_period 60
function datetime_fn
echo "update date"
set datetime_out "^fg(ffffff)$(date "+%a %d %b %I:%M %P")"
end
# ---- end generators ----
set status_pid_dir "$XDG_RUNTIME_DIR/status_pid"
# ---- startup work ----
# remove the old status if it is still running
if test -e $status_pid_dir
kill (cat $status_pid_dir)
end
# store our pid so a future status can kill us
printf "%s" "$fish_pid" >$status_pid_dir
set FIFO "$XDG_RUNTIME_DIR/sandbar"
if test ! -e "$FIFO"
mkfifo "$FIFO"
end
set needs_refresh_dir "$XDG_RUNTIME_DIR/status_needs_refresh"
# clean out any previous refresh requests
if test -e $needs_refresh_dir
rm $needs_refresh_dir/*
rmdir $needs_refresh_dir
end
mkdir $needs_refresh_dir
set min_period 60
for name in $names
set p {$name}_period
if test $$p -ne -1 -a $$p -lt $min_period
set min_period $$p
end
end
echo min period: $min_period
# instead of computing the right initial seconds, let period slip correct
set sec 0
# try to prevent drift
function compute_sleep_time
set current_seconds (date +%S)
math "$min_period - ($current_seconds % $min_period)"
end
function update -a name
set period {$name}_period
if test $$period -ne -1 -a (math "$sec % $$period") -eq 0
{$name}_fn
end
end
function tick
echo "tick $sec"
for name in $names
update $name
end
end
function refresh
echo "doing refresh"
for refresh in (ls $needs_refresh_dir)
set value (cat $needs_refresh_dir/$refresh)
# if the refresh request contains data use it instead of the generator function
if test -n "$value"
echo "refreshing $refresh; applying value"
set {$refresh}_out $value
else
echo "refreshing $refresh; running fn"
{$refresh}_fn
end
rm $needs_refresh_dir/$refresh
end
end
# set inital values
begin
for name in $names
{$name}_fn
end
refresh
write_display
end
# ---- end startup work ----
echo entering main loop
while true
set awoken true
sleep (compute_sleep_time) && set awoken false &
wait sleep 2>/dev/null
if $awoken
refresh
else
tick
end
write_display
# if we have fallen catastrophically out of sync, slip some period(s) to line up
# this prioritizes clock accuracy over hitting every period consistently
set current_seconds (date +%S)
set sec (math "$sec + $min_period + (floor (($current_seconds - ($sec % 60)) / $min_period) * $min_period)")
end