|
|
|
<!DOCTYPE html>
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<meta charset="utf-8">
|
|
|
|
<title>Breadflow Web Control</title>
|
|
|
|
<style>
|
|
|
|
* {
|
|
|
|
box-sizing: content-box;
|
|
|
|
}
|
|
|
|
h1 {
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
#ctab {
|
|
|
|
width: 1400px;
|
|
|
|
margin: 0 auto;
|
|
|
|
border: 1px solid #ccc;
|
|
|
|
border-collapse: collapse;
|
|
|
|
}
|
|
|
|
#td-side {
|
|
|
|
border-left: 1px solid #ccc;
|
|
|
|
width: 340px;
|
|
|
|
padding: 15px;
|
|
|
|
vertical-align: top;
|
|
|
|
padding-top: 22px;
|
|
|
|
}
|
|
|
|
#td-img {
|
|
|
|
vertical-align: top;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<h1>Breadflow {version}</h1>
|
|
|
|
|
|
|
|
<table id="ctab">
|
|
|
|
<tr>
|
|
|
|
<td id="td-img">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 660 430">
|
|
|
|
<style>
|
|
|
|
.ticks, .frame {
|
|
|
|
stroke-width: 1px;
|
|
|
|
fill: none;
|
|
|
|
stroke: black;
|
|
|
|
}
|
|
|
|
|
|
|
|
.ylabels text {
|
|
|
|
font-size: 10px;
|
|
|
|
text-anchor: start;
|
|
|
|
font-family: Droid Sans, sans-serif;
|
|
|
|
vertical-align: middle;
|
|
|
|
}
|
|
|
|
|
|
|
|
.grid {
|
|
|
|
stroke-dasharray: 2;
|
|
|
|
stroke: #dbdbdb;
|
|
|
|
}
|
|
|
|
|
|
|
|
.series {
|
|
|
|
stroke-width: 2px;
|
|
|
|
fill: none;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
<g transform="translate(10,15)">
|
|
|
|
<path d="M100,0 v400m100,-400 v400m100,-400 v400m100,-400 v400m100,-400 v400m100,-400 v400"
|
|
|
|
class="grid" transform="translate(0,0)" id="grid-v" />
|
|
|
|
<path d="M0,100 h600m-600,100 h600m-600,100 h600m-600,100"
|
|
|
|
class="grid" stroke-dashoffset="0" id="grid-h" />
|
|
|
|
<path d="M600,0 h10m-10,100 h10m-10,100 h10m-10,100 h10m-10,100 h10" class="ticks" />
|
|
|
|
<path d="M600,10
|
|
|
|
h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,20
|
|
|
|
h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,20
|
|
|
|
h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,20
|
|
|
|
h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5" class="ticks" />
|
|
|
|
<g class="series">
|
|
|
|
<path d="{ser-set}" stroke="blue" id="ser-set" /><!--M0,400L600,0-->
|
|
|
|
<path d="{ser-act}" stroke="red" id="ser-act" /><!--M0,0L300,100L600,400-->
|
|
|
|
</g>
|
|
|
|
<path d="M0,0h600v400h-600Z" class="frame" />
|
|
|
|
<g class="ylabels" transform="translate(630,3)">
|
|
|
|
<text x="-15" y="0">400 °C</text>
|
|
|
|
<text x="-15" y="100">300 °C</text>
|
|
|
|
<text x="-15" y="200">200 °C</text>
|
|
|
|
<text x="-15" y="300">100 °C</text>
|
|
|
|
<text x="-15" y="400">0 °C</text>
|
|
|
|
</g>
|
|
|
|
</g>
|
|
|
|
</svg>
|
|
|
|
</td>
|
|
|
|
<td id="td-side">
|
|
|
|
t<sub>sens</sub> = <span id="temp">{temp}</span>°C<br>
|
|
|
|
|
|
|
|
<form action="/set" method="POST">
|
|
|
|
<h3>Oven Control</h3>
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
|
|
<th>Heater:</th>
|
|
|
|
<td><select name="fire">
|
|
|
|
<option value="0" {fire_dis_ck}>Disable</option>
|
|
|
|
<option value="1" {fire_en_ck}>Enable</option>
|
|
|
|
</select></td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>t<sub>set</sub> =</th>
|
|
|
|
<td><input type="number" step="1" name="tset" value="{tset}"></td>
|
|
|
|
</tr>
|
|
|
|
<tr><td></td><td><input type="submit" value="Set"></td></tr>
|
|
|
|
</table>
|
|
|
|
</form>
|
|
|
|
|
|
|
|
<form action="/set" method="POST">
|
|
|
|
<h3>PID tuning</h3>
|
|
|
|
<table>
|
|
|
|
<tr><th>Kp = </th><td><input type="number" step="any" name="kp" value="{kp}"></td></tr>
|
|
|
|
<tr><th>Ki = </th><td><input type="number" step="any" name="ki" value="{ki}"></td></tr>
|
|
|
|
<tr><th>Kd = </th><td><input type="number" step="any" name="kd" value="{kd}"></td></tr>
|
|
|
|
<tr><td></td><td><input type="submit" value="Set"></td></tr>
|
|
|
|
</table>
|
|
|
|
</form>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
let Qi = function (x) { return document.getElementById(x) };
|
|
|
|
const REFR_TIME = 1000;
|
|
|
|
function update(data) {
|
|
|
|
if (data) {
|
|
|
|
let rows = data.split('\x1e');
|
|
|
|
rows.forEach(function (v) {
|
|
|
|
let [k, va] = v.split('\x1f');
|
|
|
|
switch (k) {
|
|
|
|
case 'ser-set':
|
|
|
|
Qi('ser-set').setAttribute('d', va);
|
|
|
|
break;
|
|
|
|
case 'ser-act':
|
|
|
|
Qi('ser-act').setAttribute('d', va);
|
|
|
|
break;
|
|
|
|
case 'timeshift':
|
|
|
|
Qi('grid-v').setAttribute('transform', 'translate(-'+(va*5)+',0)');
|
|
|
|
Qi('grid-h').setAttribute('stroke-dashoffset', -va * 5);
|
|
|
|
break;
|
|
|
|
case 'temp':
|
|
|
|
Qi('temp').innerHTML = va;
|
|
|
|
break;
|
|
|
|
// form fields are not live updated.
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
let xhr=new XMLHttpRequest();
|
|
|
|
xhr.onreadystatechange = function () {
|
|
|
|
if (xhr.readyState===4){
|
|
|
|
if (xhr.status===200) {
|
|
|
|
update(xhr.responseText);
|
|
|
|
}
|
|
|
|
setTimeout(update, REFR_TIME);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
xhr.onerror = function () {
|
|
|
|
setTimeout(update, REFR_TIME);
|
|
|
|
};
|
|
|
|
xhr.open('GET', '/data');
|
|
|
|
xhr.send();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setTimeout(update, REFR_TIME);
|
|
|
|
</script>
|