2 # * * * * * nice -n20 /root/bin/heat -s
5 my $schedulefile="/root/heat.schedule";
6 my $statefile="/root/heat.state";
7 my $resetfile="/root/heat.reset";
8 my $usbrelay="/root/bin/usbrelay";
9 my $logfile="/var/log/heat.log";
19 my $F=do { local $/; <F>; };
20 defined $F or die "read $fname: $!";
21 close F or die "read-close $fname: $!";
25 my($fname,$content,$mode)=@_;
27 open F,($mode||">").$fname or die "$fname: $!";
28 print F $content or die "write $fname: $!";
29 close F or die "write-close $fname: $!";
34 writefile $logfile,POSIX::strftime("%Y-%m-%dT%H:%M:%S",localtime)." $s\n",">>";
39 system $cmd and die "$cmd: $!";
41 my($trash,$min,$hour)=localtime;
42 my $minutes=$hour*60+$min;
43 if (($ARGV[0]||"")=~/^[@]0?(\d+):0?(\d+)$/) {
50 if (-e $schedulefile) {
51 $schedule=readfile $schedulefile;
52 while ($schedule=~s/^(0?(\d+):0?(\d+)) ([01s])\n//) {
54 warn "$schedulefile set twice for: $1" if defined $schedule{$tm};
55 $schedule{$tm-24*60}="$1 $4\n";
56 $schedule{$tm }="$1 $4\n";
57 $schedule{$tm+24*60}="$1 $4\n";
59 warn "$schedulefile garbage: $schedule" if $schedule ne "";
60 warn "Empty $schedulefile" if !%schedule;
63 return undef if !%schedule;
65 my($bestprev,$prev,$bestnext,$next);
66 for my $found (keys(%schedule)) {
68 next if defined $bestprev&&$bestprev>$found;
70 $prev=$schedule{$found};
72 next if defined $bestnext&&$bestnext<$found;
74 $next=$schedule{$found};
77 die "No bestprev" if !defined $bestprev;
78 die "No bestnext" if !defined $bestnext;
81 $finishline=schedulenext($minutes);
82 $finishline=[$finishline->[1]] if $finishline;
83 my $silent=shift if ($ARGV[0]||"") eq "-s";
84 logmsg "command: ".join(" ",@ARGV) if !$silent&&@ARGV;
90 info join("",@$finishline) if defined $finishline;
93 my $reset=readfile $resetfile if -e $resetfile;
94 my($resetminutes,$resetstate);
96 $reset=~/^0?(\d+)[:.]0?(\d+) ([01s]|reset)\n$/ or warn "Invalid $resetfile: $reset";
97 $resetminutes=$1*60+$2;
98 $resetstate=($3 eq "reset"?undef:$3);
100 sub unlink_resetfile() {
101 unlink $resetfile or die "$resetfile: $!";
102 logmsg "remove reset: $reset";
103 $reset=$resetminutes=undef;
105 if (defined $reset) {
107 unlink_resetfile if $resetminutes==$minutes;
109 sub finishlinereset() {
110 $finishline=schedulenext $resetminutes;
112 $finishline=[$reset,$finishline->[1]];
114 $finishline=[$reset];
117 finishlinereset if defined $reset;
118 my $state=readfile $statefile;
122 if (!defined $newstate&&defined $resetstate&&!defined $resetminutes) {
123 $newstate=$resetstate;
124 logmsg "reset: $newstate";
126 sub printminutes($) {
128 return sprintf "%02d:%02d",int($m/60),$m%60;
131 if (!defined $newstate&&!defined $reset&&%schedule) {
132 my $prev=schedulenext($minutes);
135 if ($prev=~m{ (.)\n$}) {
137 logmsg "scheduled: $prev";
141 $newstate=$state if !defined $newstate;
143 if (!defined $newstate) {
147 die "state!={s|0|1}" if $newstate!~/^[s01]$/;
150 writefile $statefile,"$newstate\n" if $state ne $newstate;
151 logmsg "$state->$newstate" if $state ne $newstate;
152 if ($newstate ne "s") {
153 my $pid=readfile "pidof -x dnf;true|";
154 die "\n".printminutes($minutes)." change $state".($state eq $newstate?"":"->$newstate")." refused: dnf running: $pid" if $pid;
156 my $both={"s"=>[0,0],"0"=>[1,0],"1"=>[1,1]}->{$newstate};
157 spawn "$usbrelay 1 ".$both->[0];
158 spawn "$usbrelay 2 ".$both->[1];
162 die "Excessive args: ".join(" ",@ARGV) if @ARGV;
163 if (!defined $newreset) {
165 if (!$silent&&defined $reset) {
167 $finishline=schedulenext($minutes);
168 $finishline=[$finishline->[1]] if $finishline;
173 if ($reset=~/^\d+$/) {
174 $resetminutes=($reset+$minutes)%(24*60);
175 $reset=printminutes($resetminutes)." reset\n";
180 $reset=printminutes($resetminutes)." $newstate\n";
183 writefile $resetfile,$reset;
184 logmsg "new reset: $reset";