From 46cbf943672f89ac4b2fea9bf78657d3de09e57b Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Mon, 16 Mar 2026 16:13:42 +0100 Subject: [PATCH] add leiden_GHS --- templates/dil5.css | 82 + templates/leiden_GHS.css | 82 + templates/leiden_GHS.html | 217 +++ templates/leiden_GHS.svg | 3149 +++++++++++++++++++++++++++++++++++++ templates/secop.js | 193 +++ 5 files changed, 3723 insertions(+) create mode 100644 templates/dil5.css create mode 100644 templates/leiden_GHS.css create mode 100644 templates/leiden_GHS.html create mode 100644 templates/leiden_GHS.svg create mode 100644 templates/secop.js diff --git a/templates/dil5.css b/templates/dil5.css new file mode 100644 index 0000000..391537a --- /dev/null +++ b/templates/dil5.css @@ -0,0 +1,82 @@ +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; +} + diff --git a/templates/leiden_GHS.css b/templates/leiden_GHS.css new file mode 100644 index 0000000..391537a --- /dev/null +++ b/templates/leiden_GHS.css @@ -0,0 +1,82 @@ +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; +} + diff --git a/templates/leiden_GHS.html b/templates/leiden_GHS.html new file mode 100644 index 0000000..2f97c04 --- /dev/null +++ b/templates/leiden_GHS.html @@ -0,0 +1,217 @@ + + + + + + Pump Control + + + +
+ {% include svg_ui %} +
+ + + + + + + diff --git a/templates/leiden_GHS.svg b/templates/leiden_GHS.svg new file mode 100644 index 0000000..81ef5a7 --- /dev/null +++ b/templates/leiden_GHS.svg @@ -0,0 +1,3149 @@ + + + +A1A0A10AUX101Bypass17671314A3A4A5A6A7A8M3M1M2M4M5M6A9DO NOT OPEN!DO NOT OPEN!3281110129415165STARTNORMALRECOVERYTRAPsavetyTRAPAUTOLED TESTRESET4He3HeS4S3CompressorS1S2p2p1p3p7p6x mbarx mbarx mbarx mbarx mbarp4flowx mbarx p5p5p8x mbarto airN.C.from OVCfrom IVCfrom stillAUX. PORTto 3He in-1to 3He in-24He23He2 diff --git a/templates/secop.js b/templates/secop.js new file mode 100644 index 0000000..c2f79f7 --- /dev/null +++ b/templates/secop.js @@ -0,0 +1,193 @@ +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() { + websocket = new WebSocket("ws://linse-dil5:8010/"); + 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(); + requestAnimationFrame(processUpdates); +} \ No newline at end of file