LaundrySorcery

git clone git://xatko.vsos.ethz.ch/LaundrySorcery.git
Log | Files | Refs

index.cgi (5618B)


      1 #!/bin/bash
      2 
      3 source delta_t.sh
      4 
      5 cat <<-EOF
      6 Content-Type: text/html
      7 
      8 <!DOCTYPE html>
      9 <HTML>
     10 	<head>
     11 		<title>LaundrySorcery</title>
     12 		<meta charset="UTF-8"/>
     13 		<style type="text/CSS">
     14 			body{
     15 				background-color:#111111;
     16 				color:silver;
     17 				font-family:sans;
     18 			}
     19 			#status{
     20 				text-align:center;
     21 				font-size:x-large;
     22 			}
     23 			#status.off .guess{
     24 				display:none;
     25 			}
     26 			.guess{
     27 				font-size:large;
     28 			}
     29 			#power{
     30 				font-size:xx-large;
     31 			}
     32 			#power img{
     33 				width:5em;
     34 				max-height:50vh;
     35 			}
     36 			#footer{
     37 				text-align:right;
     38 			}
     39 			a{
     40 				color:gold;
     41 			}
     42 			a:visited{
     43 				color:brown;
     44 			}
     45 		</style>
     46 	</head>
     47 	<body>
     48 		<div id="footer">
     49 			<a href="details.html">Details</a>
     50 		</div>
     51 		<div id="status">
     52 			<div id="power"><img src="off.svg" /></div>
     53 			<div id="delta_t"></div>
     54 			<div id="guessTime" class="guess"></div>
     55 			<div id="guessProg" class="guess"></div>
     56 		</div>
     57 		<script type="text/JavaScript">
     58 			<!--
     59 			do_notify=false;
     60 			delta_t=${RTIME};
     61 			function updateDisplay(){
     62 				if(!document.hasFocus()) return;
     63 				var g=document.getElementById("guessTime");
     64 				var g2=document.getElementById("guessProg");
     65 				var dt=document.getElementById("delta_t");
     66 				var st=document.getElementById("status");
     67 				var txt="";
     68 				var classn="";
     69 				if(delta_t < 0){
     70 					txt="since "+timeSince(-delta_t);
     71 					classn="off";
     72 				}
     73 				else{
     74 					c=guessCluster(delta_t);
     75 					txt="since "+timeSince(delta_t);
     76 					g.textContent="The crystal ball guesses: "+timeSince(Math.round(guessTimeLeft(delta_t)))+" left";
     77 					g2.textContent="Guessed program lasts "+timeSince(Math.round(c.mean));
     78 					classn="on";
     79 				}
     80 				dt.textContent=txt;
     81 				st.setAttribute("class",classn);
     82 				st.getElementsByTagName("img")[0].setAttribute("src",classn+".svg");
     83 			}
     84 
     85 			function updateDeltaT(dt){
     86 				if(do_notify){
     87 					if(delta_t<0 && dt >= 0){
     88 						new Notification("Washing machine has been turned on");
     89 					}
     90 					else if(delta_t >= 0 && dt < 0){
     91 						new Notification("Washing machine is now off");
     92 					}
     93 				}
     94 				delta_t=dt;
     95 			}
     96 
     97 			setInterval(function(){ if(delta_t>=0){delta_t++}else{delta_t--}; updateDisplay();}, 1000);
     98 			setInterval(function(){ readTextFile("print_delta_t.cgi", function(rawFile){updateDeltaT(parseInt(rawFile.responseText));});}, 20*1000);
     99 			readTextFile("clusters", function(rawFile){parseClusters(rawFile.responseText);});
    100 			clusters=[];
    101 			function Cluster(apriori, mean, variance){
    102 				this.apriori=apriori;
    103 				this.mean=mean;
    104 				this.variance=variance;
    105 			}
    106 			function parseClusters(txt){
    107 				var lines=txt.split("\n");
    108 				clusters=[];
    109 				var sum=0;
    110 				for(var i=0; i<lines.length; i++){
    111 					var line=lines[i];
    112 					if(line.length==0) continue;
    113 					var spl=line.split("\t");
    114 					clusters.push(new Cluster(parseInt(spl[0]),parseFloat(spl[1]),parseFloat(spl[2])));
    115 					sum+=parseInt(spl[0]);
    116 				}
    117 				for(var i=0; i<clusters.length; i++){
    118 					clusters[i].apriori/=sum;
    119 				}
    120 			}
    121 
    122 			function guessCluster(elapsed){
    123 				var max=-Infinity;
    124 				var maxc={};
    125 				for(var i=0; i<clusters.length; i++){
    126 					var cluster=clusters[i]
    127 					var prob=cluster.apriori*(1-cluster.cdf(elapsed));
    128 					if(prob>max){
    129 						maxc=cluster;
    130 						max=prob;
    131 					}
    132 				}
    133 				return maxc;
    134 			}
    135 
    136 			function guessTimeLeft(elapsed){
    137 				return guessTime(elapsed)-elapsed;
    138 			}
    139 
    140 			function guessTime(elapsed){
    141 				var expect=0;
    142 				var obsprior=observationPrior(elapsed);
    143 				for(var i=0; i<clusters.length; i++){
    144 					cluster=clusters[i];
    145 					var prior=(1-cluster.cdf(elapsed))*cluster.apriori/obsprior;
    146 					expect+=prior*Math.max(cluster.mean,elapsed);
    147 				}
    148 				return expect;
    149 			}
    150 
    151 			function observationPrior(elapsed){
    152 				var prior=0;
    153 				for(var i=0; i<clusters.length; i++){
    154 					cluster=clusters[i];
    155 					prior+=(1-cluster.cdf(elapsed))*cluster.apriori
    156 				}
    157 				return prior;
    158 			}
    159 
    160 			Cluster.prototype.cdf=function(to) {
    161 				variance=this.variance;
    162 				mean=this.mean;
    163 				var z = (to-mean)/Math.sqrt(2*variance);
    164 				var t = 1/(1+0.3275911*Math.abs(z));
    165 				var a1 =  0.254829592;
    166 				var a2 = -0.284496736;
    167 				var a3 =  1.421413741;
    168 				var a4 = -1.453152027;
    169 				var a5 =  1.061405429;
    170 				var erf = 1-(((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*Math.exp(-z*z);
    171 				var sign = 1;
    172 				if(z < 0){
    173 					sign = -1;
    174 				}
    175 				return (1/2)*(1+sign*erf);
    176 			}
    177 
    178 			Cluster.prototype.pdf=function(to){
    179 				mean=this.mean;
    180 				variance=this.variance;
    181 				return 1/(Math.sqrt(2*pi*variance))*Math.exp(-((to-mean)^2/(4*variance)));
    182 			}
    183 			function readTextFile(file, func){
    184 				var rawFile = new XMLHttpRequest();
    185 				rawFile.open("GET", file, true);
    186 				rawFile.onreadystatechange = function ()
    187 				{
    188 					if(rawFile.readyState === 4)
    189 					{
    190 						if(rawFile.status === 200 || rawFile.status == 0)
    191 						{
    192 							func(rawFile);
    193 						}
    194 					}
    195 				}
    196 				rawFile.send(null);
    197 			}
    198 			function timeSince(delta_t) {
    199 				var seconds = delta_t;
    200 				var timeValues=[
    201 					[60, "seconds"],
    202 					[60, "minutes"],
    203 					[24, "hours"],
    204 					[7, "days"],
    205 					[30.25, "weeks"]
    206 				];
    207 				var str="";
    208 				for(i=0; i<timeValues.length; i++){
    209 					var timeValue=timeValues[i];
    210 					if(delta_t > 0){
    211 						str=(delta_t % timeValue[0]) + " " + timeValue[1]+", "+str;
    212 						delta_t=Math.floor(delta_t/timeValue[0]);
    213 					}
    214 				}
    215 				return str.substr(0,str.length-2);
    216 			}
    217 			updateDisplay();
    218 
    219 			if("Notification" in window){
    220 				if(Notification.permission==="granted"){
    221 					do_notify=true
    222 				}
    223 				else if(Notification.permission!=="denied"){
    224 					var res=Notification.requestPermission(function(res){do_notify=(res==="granted");});
    225 				}
    226 			}
    227 			-->
    228 		</script>
    229 	</body>
    230 </HTML>
    231 EOF