Fix abnormal energy status output
[khatus.git] / bin / khatus_controller
CommitLineData
f37162a4
SK
1#! /usr/bin/awk -f
2
3/^in:ENERGY/\
4{
5 split_msg_parts()
cae87802 6 sub("%$", "", $2)
f37162a4
SK
7 db["energy_state"] = $1
8 db["energy_percentage"] = $2
9}
10
11/^in:MEMORY/\
12{
13 split_msg_parts()
14 db["memory_total"] = $1
15 db["memory_used"] = $2
16}
17
18/^in:FAN +status:/\
19{
20 split_msg_parts()
21 db["fan_status"] = $2
22}
23
24/^in:FAN +speed:/\
25{
26 split_msg_parts()
27 db["fan_speed"] = $2
28}
29
30/^in:FAN +level:/\
31{
32 split_msg_parts()
33 db["fan_level"] = $2
34}
35
36/^in:TEMPERATURE/\
37{
38 split_msg_parts()
39 db["temperature"] = $1
40}
41
42/^in:LOAD_AVG/\
43{
44 split_msg_parts()
45 set_load_avg()
46}
47
48/^in:DISK_IO/\
49{
50 split_msg_parts()
51 set_disk_io()
52}
53
54/^in:DISK_SPACE/\
55{
56 split_msg_parts()
57 db["disk_space_used"] = msg_body
58}
59
60/^in:NET_ADDR_IO/\
61{
62 split_msg_parts()
63 set_net_addr_io()
64}
65
66/^in:NET_WIFI_STATUS/\
67{
68 split_msg_parts()
69 db["net_wifi_status"] = msg_body
70}
71
72/^in:BLUETOOTH_POWER/\
73{
74 split_msg_parts()
75 db["bluetooth_power"] = msg_body
76}
77
78/^in:SCREEN_BRIGHTNESS/\
79{
80 split_msg_parts()
81 set_screen_brightness()
82}
83
84/^in:VOLUME/\
85{
86 split_msg_parts()
87 db["volume"] = msg_body
88}
89
90/^in:MPD_STATE/\
91{
92 split_msg_parts()
93 db["mpd_state"] = $1
94 db["mpd_curr_song_time"] = $2
95 db["mpd_curr_song_percent"] = $3
96}
97
98/^in:MPD_SONG/\
99{
100 split_msg_parts()
101 db["mpd_curr_song_name"] = msg_body
102}
103
104/^in:WEATHER/\
105{
106 split_msg_parts()
107 db["weather_temperature"] = msg_body
108}
109
110/^in:DATE_TIME/\
111{
112 split_msg_parts()
113 db["datetime"] = msg_body
cae87802
SK
114 output_msg_status_bar(make_status_bar())
115}
116
117{
118 alert_check_all()
119}
120
121function alert_check_all() {
122 alert_check_energy()
123}
124
125# TODO: Generalize alert spec lang
126# - trigger threshold
127# - above/bellow/equal to threshold value
128# - priority
129# - snooze time (if already alerted, when to re-alert?)
130# - text: subject/body
131function alert_check_energy( state, remaining, subj, body) {
132 state = db["energy_state"]
133 remaining = db["energy_percentage"]
134 if (state == "discharging") {
135 if (remaining < 5) {
136 subj = "Energy_CRITICALLY_Low"
137 body = sprintf("%d%% CHARGE NOW!!! GO GO GO!!!", remaining)
138 alert_trigger_hi(subj, body)
139 } else if (remaining < 10) {
140 subj = "Energy_Very_Low"
141 body = sprintf("%d%% Plug it in ASAP.", remaining)
142 alert_trigger_hi(subj, body)
143 } else if (remaining < 15) {
144 subj = "Energy_Low"
145 body = sprintf("%d%% Get the charger.", remaining)
146 alert_trigger_hi(subj, body)
147 } else if (remaining < 50) {
148 if (!state__alerts__energy__notified_bellow_half) {
149 state__alerts__energy__notified_bellow_half = 1
150 subj = "Energy_Bellow_Half"
151 body = sprintf("%d%% Where is the charger?", remaining)
152 alert_trigger_hi(subj, body)
153 }
154 }
155 } else {
156 # TODO: Reconsider the competing global-state organizing-conventions
157 state__alerts__energy__notified_bellow_half = 0
158 }
159}
160
161function alert_trigger_low(subject, body) {
162 alert_trigger("low", subject, body)
163}
164
165function alert_trigger_med(subject, body) {
166 alert_trigger("med", subject, body)
167}
168
169function alert_trigger_hi(subject, body) {
170 alert_trigger("hi", subject, body)
171}
172
173function alert_trigger(priority, subject, body, msg) {
174 # priority : "low" | "med" | "hi"
175 # subject : no spaces
176 # body : anything
177 msg = sprintf("%s %s %s", priority, subject, body)
178 output_msg_alert(msg)
179}
180
181function output_msg_alert(msg) {
182 # TODO: Should alerts go into a dedicated channel?
183 output_msg("ALERT", msg, "/dev/stdout")
184}
185
186function output_msg_status_bar(msg) {
187 output_msg("STATUS_BAR", msg, "/dev/stdout")
188}
189
190function output_msg(type, content, channel) {
191 print(type, content) > channel
f37162a4
SK
192}
193
194function set_load_avg( sched) {
195 split($4, sched, "/")
196 db["load_avg_1min"] = $1
197 db["load_avg_5min"] = $2
198 db["load_avg_15min"] = $3
199 db["kern_sched_queue_runnable"] = sched[1]
200 db["kern_sched_queue_total"] = sched[2]
201 db["kern_sched_latest_pid"] = $5
202}
203
204function set_disk_io( curr_w, curr_r, prev_w, prev_r) {
205 curr_w = $1
206 curr_r = $2
207 prev_w = db["disk_io_curr_w"]
208 prev_r = db["disk_io_curr_r"]
209 db["disk_io_curr_w"] = curr_w
210 db["disk_io_curr_r"] = curr_r
211 db["disk_io_diff_w"] = curr_w - prev_w
212 db["disk_io_diff_r"] = curr_r - prev_r
213}
214
215function set_net_addr_io( \
216 interface, address, io_curr_w, io_curr_r, io_prev_w, io_prev_r\
217) {
218 interface = $1
219 address = $2
220 io_curr_w = $3
221 io_curr_r = $4
222 if (interface) {
223 if (address && io_curr_w && io_curr_r) {
224 # recalculate
225 io_prev_w = net_io_curr_w[interface]
226 io_prev_r = net_io_curr_r[interface]
227
228 net_addr[interface] = address
229 net_io_curr_w[interface] = io_curr_w
230 net_io_curr_r[interface] = io_curr_r
231 net_io_diff_w[interface] = io_curr_w - io_prev_w
232 net_io_diff_r[interface] = io_curr_r - io_prev_r
233 } else {
234 # clear
235 net_addr[interface] = ""
236 net_io_curr_w[interface] = 0
237 net_io_curr_r[interface] = 0
238 net_io_diff_w[interface] = 0
239 net_io_diff_r[interface] = 0
240 }
241 }
242}
243
244function set_screen_brightness( max, cur) {
245 max = $1
246 cur = $2
247 db["screen_brightness"] = (cur / max) * 100
248}
249
250function split_msg_parts() {
251 msg_head = $1
252 sub("^" msg_head " +", "")
253 msg_body = $0
254 debug(msg_head, msg_body)
255}
256
cae87802 257function make_status_bar( position, bar, sep, i, j) {
f37162a4
SK
258 position[++i] = make_status_energy()
259 position[++i] = make_status_mem()
260 position[++i] = make_status_cpu()
261 position[++i] = make_status_disk()
262 position[++i] = make_status_net()
263 position[++i] = sprintf("B=%s", db["bluetooth_power"])
264 position[++i] = sprintf("*%d%%", db["screen_brightness"])
265 position[++i] = sprintf("(%s)", db["volume"])
266 position[++i] = make_status_mpd()
267 position[++i] = db["weather_temperature"]
268 position[++i] = db["datetime"]
269 bar = ""
270 sep = ""
271 for (j = 1; j <= i; j++) {
272 bar = bar sep position[j]
273 sep = " "
274 }
275 return bar
276}
277
278function make_status_energy( state, direction_of_change) {
279 state = db["energy_state"]
280 if (state == "discharging") {
281 direction_of_change = "<"
282 } else if (state == "charging") {
283 direction_of_change = ">"
284 } else {
285 direction_of_change = "="
286 };
54dfed9e 287 return sprintf("E%s%s%%", direction_of_change, db["energy_percentage"])
f37162a4
SK
288}
289
290function make_status_mem( total, used, percent, status) {
291 total = db["memory_total"]
292 used = db["memory_used"]
293 # To avoid division by zero when data is missing
294 if (total && used) {
295 percent = round((used / total) * 100)
296 status = sprintf("%d%%", percent)
297 } else {
298 status = "__"
299 }
300 return sprintf("M=%s", status)
301}
302
303function make_status_cpu( load, temp, fan) {
304 load = db["load_avg_1min"]
305 temp = db["temperature"] / 1000
306 fan = db["fan_speed"]
307 return sprintf("C=[%4.2f %d°C %4drpm]", load, temp, fan)
308}
309
310function make_status_disk( bytes_per_sector, bytes_per_mb, w, r) {
311 bytes_per_sector = 512
312 bytes_per_mb = 1024 * 1024
313 w = (db["disk_io_diff_w"] * bytes_per_sector) / bytes_per_mb
314 r = (db["disk_io_diff_r"] * bytes_per_sector) / bytes_per_mb
315 return \
316 sprintf("D=[%s %0.3f▲ %0.3f▼]", db["disk_space_used"], w, r)
317}
318
319function make_status_net( \
320 out,
321 number_of_interfaces_to_show,
322 n,
323 array_of_prefixes_of_interfaces_to_show,
324 prefix,
325 interface,
326 label,
327 count_printed,
328 sep,
329 io_stat,
330 dw, dr,
331 bytes_per_unit\
332) {
333 out = ""
334 number_of_interfaces_to_show = \
335 split(\
336 opt_prefixes_of_net_interfaces_to_show,\
337 array_of_prefixes_of_interfaces_to_show,\
338 ","\
339 )
340 for (n = 1; n <= number_of_interfaces_to_show; n++) {
341 prefix = array_of_prefixes_of_interfaces_to_show[n]
342 for (interface in net_addr) {
343 if (interface ~ ("^" prefix)) {
344 label = substr(interface, 1, 1)
345 if (net_addr[interface]) {
346 bytes_per_mb = 1024 * 1024 # TODO: option
347 dw = net_io_diff_w[interface] / bytes_per_mb
348 dr = net_io_diff_r[interface] / bytes_per_mb
349 io_stat = sprintf("%0.3f▲ %0.3f▼", dw, dr)
350 } else {
351 io_stat = "--"
352 }
353 if (interface ~ "^w") {
354 label = label ":" db["net_wifi_status"]
355 }
356 if (++count_printed > 1) {
357 sep = " "
358 } else {
359 sep = ""
360 }
361 out = out sep label ":" io_stat
362 }
363 }
364 }
365 return sprintf("N[%s]", out)
366}
367
368function make_status_mpd( state, status) {
369 state = db["mpd_state"]
370
371 if (state == "play") {
372 status = make_status_mpd_state_known("▶")
373 } else if (state == "pause") {
374 status = make_status_mpd_state_known("❚❚")
375 } else if (state == "stop") {
376 status = make_status_mpd_state_known("⬛")
377 } else {
378 status = make_status_mpd_state_unknown("--")
379 }
380
381 return sprintf("[%s]", status)
382}
383
384function make_status_mpd_state_known(symbol) {
385 return sprintf(\
386 "%s %s %s %s",
387 symbol,
388 db["mpd_curr_song_time"],
389 db["mpd_curr_song_percent"],
390 substr(db["mpd_curr_song_name"], 1, opt_mpd_song_max_chars)\
391 )
392}
393
394function make_status_mpd_state_unknown(symbol) {
395 return sprintf("%s", symbol)
396}
397
398function round(n) {
399 return int(n + 0.5)
400}
401
402function debug(location, msg) {
403 if (opt_debug) {
cae87802 404 output_msg("DEBUG", location " ==> " msg, "/dev/stderr")
f37162a4
SK
405 }
406}
This page took 0.068618 seconds and 4 git commands to generate.