#!/usr/bin/perl # vim: set ai noet ts=4 sw=4 sts=4 ft=perl : use strict; use warnings "all"; use Fcntl qw(:seek); use 5.10.0; use utf8; use JSON::XS; binmode STDOUT; binmode STDERR; sub gettimestr(); sub getlastr(); sub getbatterychargestr2(); sub meminfo(); sub ifaces(); sub cpuspeed(); sub cputemp(); sub caps(); sub caps_find(); my $slow_timer = 360; # 0.333 * 360 ~= 2 min my $onesec_timer = 3; # 0.333 * 3 ~= 1 sec my @months = ('Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'); my @wdays = ('Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'); my $tmp = ''; my $charge = ''; my $la = ''; my $time = ''; my $mem = ''; my $net = ''; my $cpuspeed = ''; my $cputemp = ''; my $caps = ''; # file handles :) my $LAHANDLE; my $MEMINFOHANDLE; my $CPUTEMPHANDLE; my %CPUSCALEHANDLE; my %CPUSCALEMAXHANDLE; my $ROUTEHANDLE; my %IFSTATEHANDLE; my $CAPSHANDLE; my $ACHANDLE; my $DCHANDLE; # global vars my $CAPSPATH; my @IFACE = qw (wlan0); my %IFSTATE; my %IFPSTATE; my %IFADDR; my $ACFILE; # main json 'object'; my $ji; # input my $jo; # output # output changed flag; my $jf = 1; # if true - we should ot show json if ( -f "/sys/class/power_supply/ADP1/online") { $ACFILE = "/sys/class/power_supply/ADP1/online"; } elsif ("/sys/class/power_supply/AC/online") { $ACFILE = "/sys/class/power_supply/AC/online"; } sleep 1; syswrite STDOUT, '{"version":1} [ [], '; while (1) { if ($onesec_timer >= 3) { # $cpuspeed = cpuspeed(); $tmp = cputemp(); if ($cputemp ne $tmp) { $jf = 1; $cputemp = $tmp; } $tmp = gettimestr(); if ($time ne $tmp) { $jf = 1; $time = $tmp; } $tmp = meminfo(); if ($mem ne $tmp) { $jf = 1; $mem = $tmp; } $tmp = ifaces(); if ($net ne $tmp) { $jf = 1; $net = $tmp; } $onesec_timer = 0; } if ($slow_timer >= 360) { $tmp = getbatterychargestr2(); if ($charge ne $tmp) { $jf = 1; $charge = $tmp; } $tmp = getlastr(); if ($la ne $tmp) { $jf = 1; $la = $tmp; } $CAPSPATH = caps_find() unless (defined($CAPSPATH)); $slow_timer = 0; } $tmp = caps(); if ($caps ne $tmp) { $jf = 1; $caps = $tmp; } if ($jf) { $jo->[0]->{full_text} = $caps; $jo->[0]->{color} = '#3e78fd'; $jo->[1]->{full_text} = $net; $jo->[1]->{color} = '#3e78fd'; $jo->[1]->{full_text} = $cputemp; $jo->[1]->{color} = '#3e78fd'; $jo->[2]->{full_text} = $la; $jo->[2]->{color} = '#3e78fd'; $jo->[3]->{full_text} = $mem; $jo->[3]->{color} = '#3e78fd'; $jo->[4]->{full_text} = $charge; $jo->[4]->{color} = '#3e78fd'; $jo->[5]->{full_text} = $time; $jo->[5]->{color} = '#3e78fd'; syswrite STDOUT, encode_json($jo) . ",\n"; $jf = 0; } # tick timers $slow_timer++; $onesec_timer++; # sleep for 0.333 second; select(undef, undef, undef, 0.333); } sub gettimestr() { my ($sec, $min, $hour, $mday, $mon, $year, $wday) = (localtime)[0,1,2,3,4,5,6]; $year = $year + 1900; my $str .= sprintf(" %s, %s %s %s %02s:%02s ", $wdays[$wday], $mday, $months[$mon], $year, $hour, $min); return $str; } sub getlastr() { if (defined($LAHANDLE)) { open ($LAHANDLE, "/proc/loadavg") if (tell($LAHANDLE) == -1); } else { open ($LAHANDLE, "/proc/loadavg"); } my $la = readline($LAHANDLE); seek $LAHANDLE, SEEK_SET, 0; $la = (split(/ /, $la, 2))[0]; return ("LA: $la"); } sub getbatterychargestr2() { my $str .= "⚡ "; if (defined($ACHANDLE)) { open ($ACHANDLE, $ACFILE) if (tell($ACHANDLE) == -1); } else { open ($ACHANDLE, $ACFILE); } if (readline($ACHANDLE) == 1) { $str .= "AC"; } else { $str .= "DC"; } seek $ACHANDLE, SEEK_SET, 0; if (defined($DCHANDLE)) { open ($DCHANDLE, "/sys/class/power_supply/BAT0/capacity") if (tell($DCHANDLE) == -1); } else { open ($DCHANDLE, "/sys/class/power_supply/BAT0/capacity"); } $str .= " " . readline($DCHANDLE); chomp($str); $str .= '%'; seek $DCHANDLE, SEEK_SET, 0; return $str; } sub meminfo() { if (defined($MEMINFOHANDLE)) { open ($MEMINFOHANDLE, "/proc/meminfo") if (tell($MEMINFOHANDLE) == -1); } else { open ($MEMINFOHANDLE, "/proc/meminfo"); } my @mem; while ( ! eof($MEMINFOHANDLE) ) { push @mem, readline($MEMINFOHANDLE); } seek $MEMINFOHANDLE, SEEK_SET, 0; @mem = map { substr($_, 0, -4) } @mem; my $memavail = (split(/\s+/, $mem[2]))[1]; my $swaptotal = (split(/\s+/, $mem[14]))[1]; my $swapfree = (split(/\s+/, $mem[15]))[1]; return sprintf ( "mem/sw: %s/%s M", int($memavail / 1024), int(($swaptotal - $swapfree) / 1024) ); } sub ifaces() { my $str = ''; foreach my $if (@IFACE) { my $addr = "no addr"; my $link; if (defined($IFSTATEHANDLE{$if})) { if (tell($IFSTATEHANDLE{$if}) == -1) { unless (open ($IFSTATEHANDLE{$if}, "/sys/class/net/$if/operstate")) { $str .= "? $if: not exist"; next; } } } else { open ($IFSTATEHANDLE{$if}, "/sys/class/net/$if/operstate") or do { $str .= "? $if: not exist"; next; }; } $IFSTATE{$if} = readline($IFSTATEHANDLE{$if}); seek $IFSTATEHANDLE{$if}, SEEK_SET, 0; $IFPSTATE{$if} = $IFSTATE{$if} unless(defined($IFPSTATE{$if})); if ($IFSTATE{$if} eq "up\n") { $link = '▲'; } else { $link = '▼'; } if ($IFPSTATE{$if} ne $IFSTATE{$if}) { $IFADDR{$if} = undef; $IFPSTATE{$if} = $IFSTATE{$if} } unless (defined($IFADDR{$if})) { if (defined($ROUTEHANDLE)) { open ($ROUTEHANDLE, "/proc/self/net/route") if (tell($ROUTEHANDLE) == -1); } else { open ($ROUTEHANDLE, "/proc/self/net/route"); } my @route; while ( ! eof($ROUTEHANDLE)) { push @route, readline($ROUTEHANDLE); } seek $ROUTEHANDLE, SEEK_SET, 0; foreach my $r (@route) { if ((split(/\t/, $r, 2))[0] eq $if) { $addr = (split(/\n/, `/sbin/ip address show dev $if`))[2]; $addr =~ m/ inet (.+)\//; $IFADDR{$if} = $1; last; } } } unless (defined($IFADDR{$if})) { $str .= sprintf("%s %s: %s", $link, $if, $addr); } else { $str .= sprintf("%s %s: %s", $link, $if, $IFADDR{$if}); } } return $str; } sub cpuspeed() { my $str = 'cpu:'; opendir(C, "/sys/devices/system/cpu/cpufreq") or do { return ''; }; while (readdir(C)) { next if($_ eq '.'); next if($_ eq '..'); if (defined($CPUSCALEHANDLE{$_})) { if (tell($CPUSCALEHANDLE{$_}) == -1) { unless (open ($CPUSCALEHANDLE{$_}, "/sys/devices/system/cpu/cpufreq/$_/scaling_cur_freq")) { return ''; } } } else { open ($CPUSCALEHANDLE{$_}, "/sys/devices/system/cpu/cpufreq/$_/scaling_cur_freq") or do { return ''; }; } my $speed = readline($CPUSCALEHANDLE{$_}); seek $CPUSCALEHANDLE{$_}, SEEK_SET, 0; chomp $speed; $speed = int($speed / 1000); if (defined($CPUSCALEMAXHANDLE{$_})) { if (tell($CPUSCALEMAXHANDLE{$_}) == -1) { unless (open ($CPUSCALEMAXHANDLE{$_}, "/sys/devices/system/cpu/cpufreq/$_/scaling_max_freq")) { return ''; } } } else { open ($CPUSCALEMAXHANDLE{$_}, "/sys/devices/system/cpu/cpufreq/$_/scaling_max_freq") or do { return ''; }; } my $speedmax = readline($CPUSCALEMAXHANDLE{$_}); seek $CPUSCALEHANDLE{$_}, SEEK_SET, 0; chomp $speedmax; $speedmax = int($speedmax / 1000); $str .= sprintf(" %s/%s", $speed, $speedmax); } closedir C; return $str . " MHz"; } sub cputemp() { if (defined($CPUTEMPHANDLE)) { if (tell($CPUTEMPHANDLE) == -1) { unless (open ($CPUTEMPHANDLE, "/sys/class/hwmon/hwmon0/temp1_input")) { return ''; } } } else { open ($CPUTEMPHANDLE, "/sys/class/hwmon/hwmon0/temp1_input") or do { return ''; }; } my $t = readline($CPUTEMPHANDLE); seek $CPUTEMPHANDLE, SEEK_SET, 0; chomp $t; $t = int($t); $t = int($t / 1000) if ($t > 1000); return sprintf("%s°", $t); } sub caps() { if (defined($CAPSPATH)) { if (defined($CAPSHANDLE)) { if (tell($CAPSHANDLE) == -1) { unless (open($CAPSHANDLE, $CAPSPATH)) { $CAPSPATH = undef; return "? caps"; } } } else { open($CAPSHANDLE, $CAPSPATH) or do { $CAPSPATH = undef; return "? caps"; }; } my $state = readline($CAPSHANDLE); seek $CAPSHANDLE, SEEK_SET, 0; chomp $state; if ($state eq '1') { return '☒ caps'; } else { return '☐ caps'; } } } sub caps_find() { my $str; opendir (C, "/sys/class/input"); my $cnt = 0; while (readdir(C)) { if (-f sprintf("/sys/class/input/%s/input0::capslock/brightness", $_)) { $str = sprintf("/sys/class/input/%s/input0::capslock/brightness", $_); last; } if (-f sprintf("/sys/class/input/%s/input%s::capslock/brightness", $_, $cnt)) { $str = sprintf("/sys/class/input/%s/input%s::capslock/brightness", $_, $cnt); last; } $cnt++; } closedir C; return $str; }