Add WiFi status
[khatus.git] / bin / khatus_loop
CommitLineData
438d0d5f
SK
1#! /bin/bash
2
4d314e0f
SK
3set -e
4
0d116e88
SK
5produce_net_wifi_status() {
6 nmcli \
7 -f ACTIVE,SSID,SIGNAL \
8 -t \
9 d wifi \
10 | awk \
11 -F ':' \
12 '
13 BEGIN {wifi_status = "--"}
14 $1 == "yes" {wifi_status = $2 ":" $3 "%"}
15 END {print wifi_status}
16 '
17}
18
ad0b3a5b
SK
19produce_bluetooth_power() {
20 echo -e 'show \n quit' \
21 | bluetoothctl \
22 | awk '
23 /^Controller / {
24 controller = $2;
25 controllers[++ctrl_count] = controller;
26 }
27 /^\t[A-Z][A-Za-z]+:/ {
28 key = $1;
29 sub(":$", "", key);
30 val = $2;
31 for (i=3; i<=NF; i++) {
32 val = val " " $i};
33 data[controller, key] = val;
34 }
35 END {
36 # Using the 1st seen controller. Should we select specific instead?
37 power_status = data[controllers[1], "Powered"];
38 if (ctrl_count > 0) {
39 if (power_status == "no") {
40 power_status = "off"
41 } else if (power_status == "yes") {
42 power_status = "on"
43 } else {
44 printf("Unexpected bluetooth power status: %s\n", power_status)\
45 > "/dev/stderr";
46 power_status = "ERROR"
47 }
48 } else {
49 power_status = "off" # TODO: Perhaps use differentiated marker?
50 }
51 printf("%s", power_status);
52 }'
53}
54
bbb42518
SK
55produce_screen_brightness() {
56 screen_brightness_device_path="$1"
57 echo "\
58 $(cat $screen_brightness_device_path/max_brightness) \
59 $(cat $screen_brightness_device_path/brightness)\
60 "
61}
62
61e5a351
SK
63produce_volume() {
64 pactl list sinks \
65 | awk '
66 /^\tMute:/ {
67 printf("%s,", $0);
68 }
69 /^\tVolume:/ {
70 for (i=2; i<=NF; i++) printf(" %s", $i);
71 }' \
72 | awk -v RS=',' '
73 /^[ \t]*Mute:/ {mute = $2}
74 /^[ \t]*front-left:/ {left = $4}
75 /^[ \t]*front-right:/ {right = $4}
76 END {
77 if (mute == "yes") {
78 printf("x")
79 } else {
80 printf("%s %s", left, right)
81 }
82 }
83 '
84}
85
365549a9
SK
86produce_mpd_state() {
87 echo 'status' \
88 | nc 127.0.0.1 6600 \
89 | awk '
90 {
91 status[$1] = $2
92 }
93
94 /^time: +[0-9]+:[0-9]+$/ {
95 split($2, time, ":")
96 seconds_current = time[1]
97 seconds_total = time[2]
98
99 hours = int(seconds_current / 60 / 60);
100 secs_beyond_hours = seconds_current - (hours * 60 * 60);
101 mins = int(secs_beyond_hours / 60);
102 secs = secs_beyond_hours - (mins * 60);
103 if (hours > 0) {
104 current_time = sprintf("%d:%.2d:%.2d", hours, mins, secs)
105 } else {
106 current_time = sprintf("%.2d:%.2d", mins, secs)
107 }
108
109 if (seconds_total > 0) {
110 time_percentage = (seconds_current / seconds_total) * 100
111 current_percentage = sprintf("%d%%", time_percentage)
112 } else {
113 current_percentage = "~"
114 }
115 }
116
117 END {
118 state = status["state:"]
119
120 if (state == "play") {
121 symbol = "▶"
122 } else if (state == "pause") {
123 symbol = "❚❚"
124 } else if (state == "stop") {
125 symbol = "⬛"
126 } else {
127 symbol = "--"
128 }
129
130 printf(\
131 "%s %s %s",
132 status["state:"], current_time, current_percentage\
133 )
134 }
135 '
136}
137
138produce_mpd_song() {
139 echo 'currentsong' \
140 | nc 127.0.0.1 6600 \
141 | awk '
142 /^OK/ {
143 next
144 }
145
146 {
147 key = $1
148 sub("^" key " +", "")
149 val = $0
150 data[key] = val
151 }
152
153 END {
154 name = data["Name:"]
155 title = data["Title:"]
156 file = data["file:"]
157
158 if (name) {
159 out = name
160 } else if (title) {
161 out = title
162 } else if (file) {
163 last = split(file, parts, "/")
164 out = parts[last]
165 } else {
166 out = ""
167 }
168 print out
169 }
170 '
171}
438d0d5f 172
6339a4f8 173produce_weather() {
4d314e0f
SK
174 weather_station_id="$1"
175 metar -d "$weather_station_id" 2>&1 \
438d0d5f
SK
176 | awk '
177 /METAR pattern not found in NOAA data/ {
178 failures++
179 }
180
181 /^Temperature/ {
182 celsius = $3;
183 fahrenheit = (celsius * (9 / 5)) + 32;
184 temperature = fahrenheit
185 }
186
187 END {
188 if (failures > 0) {
189 temperature = "--"
190 }
191 print temperature "°F"
192 }'
193}
194
6339a4f8 195produce_datetime() {
438d0d5f
SK
196 date +'%a %b %d %H:%M:%S'
197}
198
6339a4f8 199consume() {
438d0d5f
SK
200 pipe="$1"
201 tail -f "$pipe" \
202 | stdbuf -o L awk \
365549a9
SK
203 -v opt_debug=0 \
204 -v opt_mpd_song_max_chars=10 \
438d0d5f 205 '
0d116e88
SK
206 /^in:NET_WIFI_STATUS/\
207 {
208 split_msg_parts()
209 db["net_wifi_status"] = msg_body
210 }
211
ad0b3a5b
SK
212 /^in:BLUETOOTH_POWER/\
213 {
214 split_msg_parts()
215 db["bluetooth_power"] = msg_body
216 }
217
bbb42518
SK
218 /^in:SCREEN_BRIGHTNESS/\
219 {
220 split_msg_parts()
221 set_screen_brightness()
222 }
223
61e5a351
SK
224 /^in:VOLUME/\
225 {
226 split_msg_parts()
227 db["volume"] = msg_body
228 }
229
365549a9
SK
230 /^in:MPD_STATE/\
231 {
232 split_msg_parts()
233 db["mpd_state"] = $1
234 db["mpd_curr_song_time"] = $2
235 db["mpd_curr_song_percent"] = $3
236 }
237
238 /^in:MPD_SONG/\
438d0d5f 239 {
365549a9
SK
240 split_msg_parts()
241 db["mpd_curr_song_name"] = msg_body
438d0d5f
SK
242 }
243
365549a9 244 /^in:WEATHER/\
438d0d5f 245 {
365549a9
SK
246 split_msg_parts()
247 db["weather_temperature"] = msg_body
438d0d5f
SK
248 }
249
365549a9 250 /^in:DATE_TIME/\
438d0d5f 251 {
365549a9
SK
252 split_msg_parts()
253 db["datetime"] = msg_body
254 }
255
256 /^out:BAR/\
257 {
258 split_msg_parts()
438d0d5f
SK
259 print make_bar()
260 }
261
365549a9 262
bbb42518
SK
263 function set_screen_brightness( max, cur) {
264 max = $1
265 cur = $2
266 db["screen_brightness"] = (cur / max) * 100
267 }
268
365549a9
SK
269 function split_msg_parts() {
270 msg_head = $1
271 sub("^" msg_head " +", "")
272 msg_body = $0
273 debug(msg_head, msg_body)
438d0d5f
SK
274 }
275
365549a9 276 function make_bar( position, bar, sep, i, j) {
0d116e88 277 position[++i] = make_status_net()
ad0b3a5b 278 position[++i] = sprintf("B=%s", db["bluetooth_power"])
bbb42518 279 position[++i] = sprintf("*%d%%", db["screen_brightness"])
61e5a351 280 position[++i] = sprintf("(%s)", db["volume"])
365549a9 281 position[++i] = make_status_mpd()
438d0d5f
SK
282 position[++i] = db["weather_temperature"]
283 position[++i] = db["datetime"]
284 bar = ""
285 sep = ""
286 for (j = 1; j <= i; j++) {
287 bar = bar sep position[j]
288 sep = " "
289 }
290 return bar
291 }
365549a9 292
0d116e88
SK
293 function make_status_net() {
294 return sprintf("N[w:%s]", db["net_wifi_status"])
295 }
296
365549a9
SK
297 function make_status_mpd( state, status) {
298 state = db["mpd_state"]
299
300 if (state == "play") {
301 status = make_status_mpd_state_known("▶")
302 } else if (state == "pause") {
303 status = make_status_mpd_state_known("❚❚")
304 } else if (state == "stop") {
305 status = make_status_mpd_state_known("⬛")
306 } else {
307 status = make_status_mpd_state_unknown("--")
308 }
309
310 return sprintf("[%s]", status)
311 }
312
313 function make_status_mpd_state_known(symbol) {
314 return sprintf(\
315 "%s %s %s %s",
316 symbol,
317 db["mpd_curr_song_time"],
318 db["mpd_curr_song_percent"],
319 substr(db["mpd_curr_song_name"], 1, opt_mpd_song_max_chars)\
320 )
321 }
322
323 function make_status_mpd_state_unknown(symbol) {
324 return sprintf("%s", symbol)
325 }
326
327 function debug(location, msg) {
328 if (opt_debug) {
329 print_error(location, msg)
330 }
331 }
332
333 function print_error(location, msg) {
334 print(location " ==> " msg) > "/dev/stderr"
335 }
438d0d5f
SK
336 '
337}
338
6339a4f8 339produce_bar_req() {
438d0d5f
SK
340 echo ''
341}
342
343spawn() {
344 cmd="$1"
345 pipe="$2"
365549a9 346 msg_head="$3"
438d0d5f
SK
347 interval="$4"
348 while true; do
365549a9 349 echo "${msg_head} $($cmd)" > "$pipe"
438d0d5f
SK
350 sleep "$interval"
351 done &
352}
353
354main() {
4d314e0f
SK
355 # Defaults
356 dir_data="$HOME/.khatus"
357 weather_station_id='KJFK'
bbb42518 358 screen_brightness_device_name='acpi_video0'
4d314e0f
SK
359
360 # User-overrides
361 OPTS=$(
362 getopt \
363 -o '' \
bbb42518 364 -l data-dir:,weather-station:screen-device: \
4d314e0f
SK
365 -- "$@"
366 )
367 eval set -- "$OPTS"
368 while true
369 do
370 case "$1" in
371 --data-dir)
372 dir_data="$2"
373 shift 2
374 ;;
375 --weather-station)
376 weather_station_id="$2"
377 shift 2
378 ;;
bbb42518
SK
379 --screen-device)
380 screen_brightness_device_name="$2"
381 shift 2
382 ;;
4d314e0f
SK
383 --)
384 shift
385 break
386 ;;
387 esac
388 done
389
0c0ebbe1 390 pipe="$dir_data/khatus_data_pipe"
bbb42518
SK
391 screen_brightness_device_path='/sys/class/backlight'
392 screen_brightness_device_path+="/$screen_brightness_device_name"
0c0ebbe1 393
4d314e0f
SK
394 ( echo "Khatus starting with the following parameters:"
395 ( echo " dir_data|= $dir_data"
0c0ebbe1 396 echo " pipe|= $pipe"
bbb42518
SK
397 echo " screen_brightness_device_name|=$screen_brightness_device_name"
398 echo " screen_brightness_device_path|=$screen_brightness_device_path"
4d314e0f
SK
399 echo " weather_station_id|= $weather_station_id"
400 ) | column -ts\|
401 echo ''
402 ) >&2
403
4d314e0f 404 mkdir -p "$dir_data"
438d0d5f
SK
405 rm -f "$pipe"
406 mkfifo "$pipe"
407
bbb42518
SK
408 cmd_produce_screen_brightness='produce_screen_brightness'
409 cmd_produce_screen_brightness+=" $screen_brightness_device_path"
0c0ebbe1
SK
410 cmd_produce_weather="produce_weather $weather_station_id"
411
4d314e0f 412 # TODO: Redirect each worker's stderr to a dedicated log file
0c0ebbe1 413 spawn produce_datetime "$pipe" 'in:DATE_TIME' 1
bbb42518 414 spawn "$cmd_produce_screen_brightness" "$pipe" 'in:SCREEN_BRIGHTNESS' 1
0c0ebbe1
SK
415 spawn "$cmd_produce_weather" "$pipe" 'in:WEATHER' $(( 30 * 60 ))
416 spawn produce_mpd_state "$pipe" 'in:MPD_STATE' 1
417 spawn produce_mpd_song "$pipe" 'in:MPD_SONG' 1
418 spawn produce_volume "$pipe" 'in:VOLUME' 1
ad0b3a5b 419 spawn produce_bluetooth_power "$pipe" 'in:BLUETOOTH_POWER' 5
0d116e88 420 spawn produce_net_wifi_status "$pipe" 'in:NET_WIFI_STATUS' 5
0c0ebbe1
SK
421 spawn produce_bar_req "$pipe" 'out:BAR' 1
422 consume "$pipe"
438d0d5f
SK
423}
424
425main $@
This page took 0.062133 seconds and 4 git commands to generate.