for ssh tunnels, we need to use the same adress as given in the address bar, only changing port number to 8010
311 lines
9.3 KiB
HTML
311 lines
9.3 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Pump Control</title>
|
|
<style>
|
|
body, html {
|
|
height: 100%;
|
|
margin: 0;
|
|
padding: 0;
|
|
background-color: lightgrey;
|
|
display: flex;
|
|
}
|
|
|
|
.svg-container {
|
|
flex: 2;
|
|
height: 100%;
|
|
position: relative;
|
|
display: flex;
|
|
}
|
|
|
|
#pump-svg {
|
|
width: 100%;
|
|
height: 100%;
|
|
display: block;
|
|
border-radius: 12px;
|
|
}
|
|
|
|
.control-panel {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: flex-start;
|
|
padding: 10px;
|
|
background-color: #B8EBE5;
|
|
border-radius: 12px;
|
|
}
|
|
|
|
.control-panel p {
|
|
font-size: 20px;
|
|
font-family:verdana;
|
|
}
|
|
|
|
|
|
.control-panel h {
|
|
font-size: 32px;
|
|
font-family:verdana;
|
|
}
|
|
|
|
.button-container {
|
|
display: flex;
|
|
flex-direction: rows;
|
|
gap: 10px;
|
|
margin-bottom: 20px;
|
|
font-size: 20px;
|
|
font-family:verdana;
|
|
}
|
|
|
|
.control-button {
|
|
padding: 10px;
|
|
background-color: #AFB0B1;
|
|
color: black;
|
|
border: none;
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
width: 100px;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.control-button:hover {
|
|
background-color: #DADBDC;
|
|
}
|
|
|
|
#outputtext {
|
|
width: 100%;
|
|
height: 200px;
|
|
resize: none;
|
|
border-radius: 12px;
|
|
}
|
|
|
|
.content-container {
|
|
display: flex;
|
|
flex-direction: row;
|
|
gap: 10px;
|
|
margin-bottom: 20px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="content-container">
|
|
<! object id="pump-svg" type="image/svg+xml" data="/static/UI5.svg"><! /object>
|
|
{% include svg_ui %}
|
|
<div class="control-panel">
|
|
<h1> DIL5 Control </h1>
|
|
<p> States </p>
|
|
<div class="button-container">
|
|
<button id = "test-btn" class="control-button" onclick="handleStateClick('TEST')">Test</button>
|
|
<button id = "condense-btn" class="control-button" onclick="handleStateClick('CONDENSE')">Condense</button>
|
|
<button id = "circulate-btn" class="control-button" onclick="handleStateClick('CIRCULATE')">Circulate</button>
|
|
<button id = "remove-btn" class="control-button" onclick="handleStateClick('REMOVE')">Remove</button>
|
|
<button id = "manual-btn" class="control-button" onclick="handleStateClick('MANUAL')">Manual</button>
|
|
</div>
|
|
<p> Status messages </p>
|
|
<textarea name="outputtext" id="outputtext" rows="10" cols="30" readonly></textarea>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
|
|
<script>
|
|
|
|
const svgElements = {};
|
|
|
|
var colors = {true: "#66ffba", false: "#ff3067", error: "#ffff00", clicked: "#ffffff", ok: "#ffffff"};
|
|
|
|
let active_state = "MANUAL";
|
|
|
|
var description;
|
|
var changeFuncs = {};
|
|
var updateValues = {};
|
|
|
|
function handle_describing(action, modpar, data) {
|
|
description = data;
|
|
for (const mod of Object.keys(data.modules)) {
|
|
const mdesc = data.modules[mod];
|
|
if (! mdesc) {
|
|
console.log('bad mod', mod)
|
|
continue;
|
|
}
|
|
const elems = document.querySelectorAll("[id^='" + mod + ":']");
|
|
let stateElement = null;
|
|
let clickElement = null;
|
|
elems.forEach(elem => {
|
|
let [parmod, ...func] = elem.id.split('-');
|
|
const [mod, param] = parmod.split(':');
|
|
// console.log(mod, param, func);
|
|
if (func.includes("click")) {
|
|
clickElement = elem;
|
|
addClickListener(elem, mod, toggleTarget);
|
|
}
|
|
if (func.includes("fault")) {
|
|
changeFuncs[mod + ":status"] = function (value) {
|
|
changeFill(elem, value[0] < 400 ? "ok" : "error");
|
|
}
|
|
}
|
|
if (func.includes("state")) {
|
|
stateElement = elem;
|
|
changeFuncs[mod + ":" + (param || 'value')] = function (value) {
|
|
changeFill(elem, value);
|
|
}
|
|
}
|
|
if (func.includes("text")) {
|
|
const pat = elem.textContent;
|
|
changeFuncs[mod + ":" + (param || 'value')] = function (value) {
|
|
elem.textContent = pat.replace('*', value);
|
|
elem.style.fill = "#d5d5d5";
|
|
}
|
|
}
|
|
if (func.includes("command")) {
|
|
console.log(func, mod, param);
|
|
addClickListener(elem, mod + ":" + param, sendCommand);
|
|
}
|
|
})
|
|
if (stateElement && clickElement) {
|
|
clickElement.stateElement = stateElement;
|
|
}
|
|
}
|
|
console.log('ACTIVATE', changeFuncs);
|
|
doSend("activate");
|
|
}
|
|
|
|
function handle_update(action, modpar, data) {
|
|
if (modpar.startsWith('compressor')) console.log(action, modpar, data);
|
|
if (modpar in changeFuncs) {
|
|
updateValues[modpar] = data[0];
|
|
}
|
|
}
|
|
|
|
handle_reply = handle_update;
|
|
handle_changed = handle_update;
|
|
|
|
function handle_error_update(action, modpar, data) {
|
|
}
|
|
|
|
function handleMSG(msg) {
|
|
const [action, modpar, ...tail] = msg.split(" ");
|
|
let data = tail.join(' ');
|
|
if (data) {
|
|
data = JSON.parse(data);
|
|
}
|
|
handler = window["handle_" + action];
|
|
if (handler) {
|
|
handler(action, modpar, data);
|
|
} else {
|
|
console.log(msg);
|
|
}
|
|
}
|
|
|
|
function processUpdates() {
|
|
let updates = updateValues;
|
|
updateValues = {};
|
|
for (const [modpar, value] of Object.entries(updates)) {
|
|
if (modpar.startsWith('compressor')) console.log('process', modpar, value);
|
|
changeFuncs[modpar](value);
|
|
}
|
|
requestAnimationFrame(processUpdates);
|
|
}
|
|
|
|
|
|
function handleStateClick(state) {
|
|
changeState("dil", state);
|
|
document.getElementById(state.toLowerCase() + "-btn").style.backgroundColor = "white";
|
|
document.getElementById(active_state.toLowerCase() + "-btn").style.backgroundColor = "rgb(175, 176, 177)";
|
|
active_state = state;
|
|
}
|
|
|
|
|
|
function updateState(state) {
|
|
document.getElementById(state.toLowerCase() + "-btn").style.backgroundColor = "white";
|
|
document.getElementById(active_state.toLowerCase() + "-btn").style.backgroundColor = "rgb(175, 176, 177)";
|
|
active_state = state;
|
|
}
|
|
|
|
function changeFill(element, state) {
|
|
stateElement = element.stateElement || element;
|
|
stateElement.state = state;
|
|
if (state in colors) {
|
|
stateElement.style.fill = colors[state];
|
|
} else {
|
|
stateElement.style.fill = "#eaeaea" ;
|
|
}
|
|
}
|
|
|
|
function writeToScreen(message) {
|
|
const output = document.getElementById("outputtext");
|
|
output.value += message;
|
|
output.scrollTop = output.scrollHeight;
|
|
}
|
|
|
|
function doConnect(uri) {
|
|
websocket = new WebSocket(uri);
|
|
websocket.onopen = evt => onOpen(evt);
|
|
websocket.onclose = evt => onClose(evt);
|
|
websocket.onmessage = evt => handleMSG(evt.data);
|
|
websocket.onerror = evt => onError(evt);
|
|
}
|
|
|
|
function onOpen(evt) {
|
|
writeToScreen("Connected to DIL5\n");
|
|
doSend("describe");
|
|
/*
|
|
for (var mod in ctr_state) {
|
|
readValue(mod);
|
|
}
|
|
startPolling();
|
|
*/
|
|
}
|
|
|
|
function changeState(mod, value) {
|
|
doSend(`change ${mod}:target "${value}"`);
|
|
//writeToScreen(`change ${mod}:target "${value}"\n`);
|
|
}
|
|
|
|
function onClose(evt) {
|
|
writeToScreen("disconnected\n");
|
|
}
|
|
|
|
function onError(evt) {
|
|
if (evt.data === undefined) {
|
|
writeToScreen("Unable to connect to DIL5 as websocket is not connectable\n");
|
|
} else {
|
|
writeToScreen("error: " + evt.data + '\n');
|
|
websocket.close();
|
|
}
|
|
|
|
}
|
|
|
|
function doSend(message) {
|
|
console.log('>', message);
|
|
websocket.send(message);
|
|
}
|
|
|
|
function toggleTarget(element, mod) {
|
|
stateElement = element.stateElement || element
|
|
const newState = stateElement.state === false;
|
|
console.log('click', element, mod, stateElement.state, newState);
|
|
changeFill(element, "clicked");
|
|
doSend(`change ${mod}:target ${newState}`);
|
|
}
|
|
|
|
function sendCommand(element, modcmd) {
|
|
console.log('command', modcmd);
|
|
doSend(`do ${modcmd}`);
|
|
}
|
|
|
|
function addClickListener(element, arg, func) {
|
|
element.addEventListener('click', () => { func(element, arg); });
|
|
element.classList.add('clickable');
|
|
}
|
|
|
|
window.onload = function () {
|
|
doConnect('ws://' + window.location.hostname + ':8010/');
|
|
requestAnimationFrame(processUpdates);
|
|
}
|
|
</script>
|
|
|
|
|
|
</body>
|
|
</html>
|