<h3>PiThrottler Control</h3>
<select id="preset" onchange="changePreset();">
</select>
- <div class="slidecontainer">
- Latency<br />
- <input type="range" min="0" max="1000" style="width:400px;" value="0" class="slider" id="latencyRange" oninput="document.getElementById('latency').innerHTML = this.value;"> <span id="latency">0</span> ms
- </div>
- <div class="slidecontainer">
- Packet Loss<br />
- <input type="range" min="0" max="95" style="width:400px;" value="0" class="slider" id="plossRange" oninput="document.getElementById('ploss').innerHTML = this.value;"> <span id="ploss">0</span> %
- </div>
- <div class="slidecontainer">
- Throughput Limitation (0 for unlimited)<br />
- <input type="range" min="0" max="20000" style="width:400px;" value="0" class="slider" id="tpRange" oninput="document.getElementById('tp').innerHTML = this.value;"> <span id="tp">0</span> kb/s
- </div>
+ <table>
+ <tr><th></th><th>Inbound</th><th>Outbound</th></tr>
+ <tr><td>Latency</td>
+ <td class="slidecontainer">
+ <input type="range" min="0" max="1000" value="0" class="slider" id="latencyinRange" oninput="document.getElementById('latencyin').innerHTML = this.value;"> <span id="latencyin">0</span> ms
+ </td>
+ <td class="slidecontainer">
+ <input type="range" min="0" max="1000" value="0" class="slider" id="latencyoutRange" oninput="document.getElementById('latencyout').innerHTML = this.value;"> <span id="latencyout">0</span> ms
+ </td>
+ </tr>
+ <tr><td>Packet Loss</td>
+ <td class="slidecontainer">
+ <input type="range" min="0" max="95" value="0" class="slider" id="plossinRange" oninput="document.getElementById('plossin').innerHTML = this.value;"> <span id="plossin">0</span> %
+ </td>
+ <td class="slidecontainer">
+ <input type="range" min="0" max="95" value="0" class="slider" id="plossoutRange" oninput="document.getElementById('plossout').innerHTML = this.value;"> <span id="plossout">0</span> %
+ </td>
+ </tr>
+ <tr><td>Throughput Limit (0=unlimited)</td>
+ <td class="slidecontainer">
+ <input type="range" min="0" max="200" value="0" class="slider" id="tpdownRange" oninput="document.getElementById('tpdown').innerHTML = Math.pow(this.value, 2);"> <span id="tpdown">0</span> kb/s
+ </td>
+ <td class="slidecontainer">
+ <input type="range" min="0" max="200" value="0" class="slider" id="tpupRange" oninput="document.getElementById('tpup').innerHTML = Math.pow(this.value, 2);"> <span id="tpup">0</span> kb/s
+ </td>
+ </tr>
+ </table>
+ <br/>
+ <br/>
<button onclick="saveSettings();">Save Settings</button>
<button onclick="checkForUpdates();">Check for Updates</button>
<div id="updateStatus"></div>
font-family:Arial;
}
+table {
+ margin:auto;
+ text-align:left;
+}
+
+th {
+ text-align:center;
+}
+
+tr {
+ height:30px;
+}
+
+td:first-child {
+ text-align:right;
+}
+
+td {
+ padding-left:5px;
+ padding-right:5px;
+ min-width:270px;
+}
+
select, button {
width: 160px;
height: 30px;
color: #1c87c9;
}
+.slider {
+ width:180px;
+}
+
select:hover, button:hover {
background-color:#303030;
}
const presets = {
Unlimited: {
label: "Unlimited",
- latency: 0,
- ploss: 0,
- throughput: 0
+ latencyin: 0,
+ plossin: 0,
+ throughputdown: 0,
+ latencyout: 0,
+ plossout: 0,
+ throughputup: 0
},
F4G: {
label: "4G Fast",
- latency: 30,
- ploss: 0,
- throughput: 20000
+ latencyin: 30,
+ plossin: 0,
+ throughputdown: 20000,
+ latencyout: 30,
+ plossout: 0,
+ throughputup: 20000
},
S4G: {
label: "4G Slow",
- latency: 150,
- ploss: 1,
- throughput: 10000
+ latencyin: 75,
+ plossin: 1,
+ throughputdown: 10000,
+ latencyout: 75,
+ plossout: 1,
+ throughputup: 10000
},
F3G: {
label: "3G Fast",
- latency: 110,
- ploss: 0,
- throughput: 5000
+ latencyin: 55,
+ plossin: 0,
+ throughputdown: 5000,
+ latencyout: 55,
+ plossout: 0,
+ throughputup: 5000
},
S3G: {
label: "3G Slow",
- latency: 200,
- ploss: 3,
- throughput: 1000
+ latencyin: 100,
+ plossin: 3,
+ throughputdown: 1000,
+ latencyout: 100,
+ plossout: 3,
+ throughputup: 1000
}
};
function saveSettings() {
- fetch("/set?latency=" + document.getElementById("latencyRange").value + "&ploss=" + document.getElementById("plossRange").value + "&throughput=" + document.getElementById("tpRange").value);
+ fetch("/set?latencyin=" +
+ document.getElementById("latencyinRange").value + "&latencyout=" +
+ document.getElementById("latencyoutRange").value + "&plossin=" +
+ document.getElementById("plossinRange").value + "&plossout=" +
+ document.getElementById("plossoutRange").value + "&throughputdown=" +
+ Math.pow(document.getElementById("tpdownRange").value, 2) + "&throughputup=" +
+ Math.pow(document.getElementById("tpupRange").value, 2));
}
async function checkForUpdates() {
function changePreset() {
var preset = document.getElementById("preset").value;
- document.getElementById("latencyRange").value = presets[preset].latency;
- document.getElementById("latency").innerHTML = presets[preset].latency;
- document.getElementById("plossRange").value = presets[preset].ploss;
- document.getElementById("ploss").innerHTML = presets[preset].ploss;
- document.getElementById("tpRange").value = presets[preset].throughput;
- document.getElementById("tp").innerHTML = presets[preset].throughput;
+ document.getElementById("latencyinRange").value = presets[preset].latencyin;
+ document.getElementById("latencyin").innerHTML = presets[preset].latencyin;
+ document.getElementById("plossinRange").value = presets[preset].plossin;
+ document.getElementById("plossin").innerHTML = presets[preset].plossin;
+ document.getElementById("tpdownRange").value = Math.sqrt(presets[preset].throughputdown);
+ document.getElementById("tpdown").innerHTML = presets[preset].throughputdown;
+ document.getElementById("latencyoutRange").value = presets[preset].latencyout;
+ document.getElementById("latencyout").innerHTML = presets[preset].latencyout;
+ document.getElementById("plossoutRange").value = presets[preset].plossout;
+ document.getElementById("plossout").innerHTML = presets[preset].plossout;
+ document.getElementById("tpupRange").value = Math.sqrt(presets[preset].throughputup);
+ document.getElementById("tpup").innerHTML = presets[preset].throughputup;
}
\ No newline at end of file
if (req.url.startsWith("/set")) {
let searchParams = new URL("http://localhost:2121" + req.url).searchParams;
- var latency = searchParams.get("latency");
- var ploss = searchParams.get("ploss");
- var throughput = searchParams.get("throughput");
-
- if (!latency) {
- latency = 0;
+ var latencyin = searchParams.get("latencyin");
+ var latencyout = searchParams.get("latencyout");
+ var plossin = searchParams.get("plossin");
+ var plossout = searchParams.get("plossout");
+ var throughputdown = searchParams.get("throughputdown");
+ var throughputup = searchParams.get("throughputup");
+
+ if (!latencyin) {
+ latencyin = 0;
+ }
+ if (!latencyout) {
+ latencyout = 0;
+ }
+ if (!plossin) {
+ plossin = 0;
}
- if (!ploss) {
- ploss = 0;
+ if (!plossout) {
+ plossout = 0;
}
- if (!throughput) {
- throughput = 0;
+ if (!throughputdown) {
+ throughputdown = 0;
+ }
+ if (!throughputup) {
+ throughputup = 0;
}
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.setHeader('Access-Control-Allow-Origin', '*');
- res.end("Setting parameters, latency: " + latency + " ms, packet loss: " + ploss + "%, Throughput: " + throughput + " kbit/s");
+ res.end("Setting parameters, latency in: " + latencyin + " ms, out: " + latencyout + " ms, packet loss in: " + plossin + "%, out: " + plossout + "%, Throughput in: " + throughputdown + " kbit/s, out: " + throughputup);
exec("sudo tc qdisc del dev wlan0 root");
exec("sudo tc qdisc del dev wlan0 root");
+ exec("sudo tc qdisc del dev eth0 root");
+
+ let currentParentIn = "root";
+ let currentParentOut = "root";
- if (latency > 0 || ploss > 0) {
+ if (latencyin > 0 || plossin > 0) {
let command = "sudo tc qdisc add dev wlan0 root handle 30: netem";
- if (latency > 0) {
- command += " delay " + latency + "ms";
+ if (latencyin > 0) {
+ command += " delay " + latencyin + "ms";
}
- if (ploss > 0) {
- command += " loss " + ploss + "%";
+ if (plossin > 0) {
+ command += " loss " + plossin + "%";
}
exec(command);
- console.log("Setting lattency and packet loss");
+ console.log("Setting inbound lattency and packet loss");
+
+ currentParentIn = "parent 30:1";
}
- if (throughput > 0) {
- let command = "sudo tc qdisc add dev wlan0 ";
+ if (latencyout > 0 || plossout > 0) {
+ let command = "sudo tc qdisc add dev eth0 root handle 50: netem";
- if (latency > 0 || ploss > 0) {
- command += "parent 30:1";
- } else {
- command += "root";
+ if (latencyout > 0) {
+ command += " delay " + latencyout + "ms";
+ }
+ if (plossout > 0) {
+ command += " loss " + plossout + "%";
}
- command += " tbf rate " + throughput + "kbit burst 32kbit latency 500ms";
exec(command);
- console.log("Setting bandwidth limitation");
+ console.log("Setting outbound latency and packet loss");
+
+ currentParentOut = "parent 50:1";
}
-
+
+ if (throughputdown > 0) {
+ let command = "sudo tc qdisc add dev wlan0 " + currentParentIn + " handle 40:";
+
+ currentParentIn = "parent 40:1";
+
+ command += " tbf rate " + throughputdown + "kbit burst 32kbit latency 500ms";
+ exec(command);
+ console.log("Setting down bandwidth limitation");
+ }
+
+ if (throughputup > 0) {
+ let command = "sudo tc qdisc add dev eth0 " + currentParentOut + " handle 60:";
+
+ currentParentOut = "parent 60:1";
+
+ command += " tbf rate " + throughputup + "kbit burst 32kbit latency 500ms";
+ exec(command);
+ console.log("Setting up bandwidth limitation");
+ }
+
return;
}