Files
split-flap-controller/software/pc_client/nginx/www/web_gui/js/sfc.js
2025-10-22 23:11:02 +02:00

327 lines
9.4 KiB
JavaScript

let socket;
/* After Document load, change view according to url and connect to ws server */
document.addEventListener("DOMContentLoaded", function () {
const urlSection = location.href.split("#")[1];
if (urlSection) {
changeView(urlSection);
}
SFCConnect();
});
/* function to conenct to ws server */
function SFCConnect() {
// Create WebSocket connection.
let hostname = location.host;
if (hostname === "") {
hostname = "localhost";
}
console.log(`Connecting to ws://${hostname}`);
socket = new WebSocket(`ws://${hostname}/manage/`);
// Connection opened
socket.addEventListener("open", (event) => {
notify("success", "connected!");
load_module_conf();
});
socket.addEventListener("close", (event) => {
notify("warn", "ws connection failed!. Reconnect in 5s");
setTimeout(() => {
SFCConnect();
}, 5000)
});
socket.addEventListener("message", (event) => {
const data = JSON.parse(event.data)
console.log(data)
switch (last_command) {
case "dm_dump":
parse_module_conf(data);
break;
}
if (data.ack) {
notify("success", "command sent!");
}
});
}
/* function to send command */
function SFCCommandAsync(data) {
if (socket && socket.readyState !== WebSocket.CLOSED) {
last_command = data.command;
socket.send(JSON.stringify(data));
} else {
notify("error", "ws not connected!");
}
}
/* utility function to format int to hex string */
function toAddressStr(address) {
const hexbase = address.toString(16).padStart(4, '0').toUpperCase();
return `0x${hexbase}`;
}
let messageCounter = 0;
function notify(severity, text) {
const template = document.querySelector("#notification");
const clone = template.content.cloneNode(true);
const tbody = document.querySelector("#message_container");
clone.querySelector("div").classList.add(`notification-${severity}`)
clone.querySelector("div").querySelector("p").innerHTML = text;
const messageDivID = `notification-dyn-${messageCounter}`
clone.querySelector("div").id = messageDivID;
messageCounter += 1;
setTimeout(function () {
//document.querySelector(`#${messageDivID}`).style.transition = "opacity 1s ease";
document.querySelector(`#${messageDivID}`).style.opacity = 0;
setTimeout(function () {
document.querySelector(`#${messageDivID}`).remove();
}, 1001);
}, 2000);
tbody.appendChild(clone);
document.querySelector(`#${messageDivID}`).style.opacity = 0.7;
}
function btn_display() {
const text = document.getElementById("form_display_str").value;
const x = Number(document.getElementById("form_display_x").value);
const y = Number(document.getElementById("form_display_y").value);
const mode = document.getElementById("form_display_mode").value;
console.log(mode)
const msg = {
"command": "dm_print",
"string": text,
"x": x,
"y": y,
"full": mode == "false" ? false : true
}
SFCCommandAsync(msg);
}
function btn_clear() {
const msg = {
"command": "dm_clear",
}
SFCCommandAsync(msg);
}
function btn_reset_module(address) {
const msg = {
"command": "dr_reset",
"address": address
}
SFCCommandAsync(msg);
}
function btn_save() {
const msg = {
"command": "dm_save",
}
SFCCommandAsync(msg);
}
function btn_load() {
const msg = {
"command": "dm_load",
}
SFCCommandAsync(msg);
}
function changeView(id) {
document.getElementById('view_display').style.display = 'none';
document.getElementById('view_conf_modules').style.display = 'none';
document.getElementById('view_storage').style.display = 'none';
document.getElementById(id).style.display = 'block';
switch (id) {
case 'view_display':
break;
case 'view_conf_modules':
load_module_conf();
break;
}
// append to url
//location.href = "test"
const newHref = `${location.href.split("#")[0]}#${id}`;
location.href = newHref;
// close menu
document.getElementById('menu_dropdown').removeAttribute('open');
}
let modules = [];
function load_module_conf() {
if (socket) {
document.getElementById('btn_refresh').ariaBusy = 'true';
document.getElementById('btn_refresh').disabled = true;
SFCCommandAsync({ "command": "dm_dump" });
}
}
function parse_module_conf(data) {
if (data["devices"]) {
modules = data["devices"];
const tbody = document.querySelector("#module_list");
tbody.innerHTML = "";
for (let i = 0; i < modules.length; i++) {
const mod = modules[i];
const template = document.querySelector("#module_list_template");
const clone = template.content.cloneNode(true);
let summary = clone.querySelector("summary");
summary.textContent = `Module ${mod["id"]} : ${mod["status"]["device"]} | Addr: ${toAddressStr(mod["address"])} , Pos: (${mod["position"]["x"]}, ${mod["position"]["y"]})`;
switch (mod["status"]["device"]) {
case 'ONLINE':
summary.classList.add("pico-color-jade-500");
break
case 'OFFLINE':
summary.classList.add("pico-color-red-500");
break;
}
// fill table
let td = clone.querySelectorAll("td");
td[0].textContent = mod["id"];
td[2].textContent = `${mod["address"]} (${toAddressStr(mod["address"])})`;
td[4].textContent = `${mod["calibration"]} (${toAddressStr(mod["calibration"])})`;
td[6].textContent = mod["status"]["device"];
td[8].textContent = mod["status"]["rotations"];
td[10].textContent = `${mod["position"]["x"]}, ${mod["position"]["y"]}`;
td[12].textContent = mod["status"]["power"];
td[14].textContent = `${Math.round((mod["status"]["voltage"]) * 100) / 100} V`;
td[16].textContent = `id: ${mod["flapID"]}, char: '${mod["flapChar"]}'`;
// prepare flags
let flags = [];
Object.keys(mod["status"]["flags"]).forEach(flag => {
if (mod["status"]["flags"][flag]) {
flags.push(flag);
}
});
if (flags.length > 0) {
td[18].textContent = flags.join(", ");
}
clone.querySelector(".btn_reset").onclick = function () {
btn_reset_module(mod["address"]);
};
clone.querySelector(".btn_remove").onclick = function () {
const msg = {
"command": "dm_remove",
"id": mod["id"],
}
SFCCommandAsync(msg);
setTimeout(function () {
load_module_conf();
}, 200);
};
td[13].querySelector("input").checked = mod["status"]["power"];
// define set calibration button
td[5].querySelector("button").onclick = function () {
const dialog = document.getElementById("dialog_change_calibration");
dialog.showModal();
const dialog_el = dialog.querySelector("article").querySelector("section").querySelector("footer");
dialog_el.querySelector(".btn_confirm").onclick = function () {
const msg = {
"command": "dr_setcalibration",
"address": mod["address"],
"calibration": Number(dialog.querySelector("#form_change_calibration_data").value)
}
SFCCommandAsync(msg);
setTimeout(function () {
btn_reset_module(mod["address"]);
load_module_conf();
}, 200);
dialog.close();
};
dialog_el.querySelector(".btn_cancel").onclick = function () {
dialog.close();
}
};
// define power button
td[13].querySelector("input").onclick = function () {
const msg = {
"command": "dr_power",
"address": mod["address"],
"power": td[13].querySelector("input").checked
}
SFCCommandAsync(msg);
setTimeout(function () {
load_module_conf();
}, 200);
}
tbody.appendChild(clone);
document.getElementById('btn_refresh').ariaBusy = 'false';
document.getElementById('btn_refresh').disabled = false;
}
}
console.log(modules);
}
function display_dialog_change_address() {
const dialog = document.getElementById("change_address");
dialog.showModal();
const dialog_el = dialog.querySelector("article").querySelector("section").querySelector("footer");
const addr_old = Number(dialog.querySelector("#form_change_address_old").value);
const addr_new = Number(dialog.querySelector("#form_change_address_new").value);
dialog_el.querySelector(".btn_confirm").onclick = function () {
const msg = {
"command": "dr_setaddress",
"address": addr_old,
"newaddress": addr_new,
}
SFCCommandAsync(msg);
setTimeout(function () {
btn_reset_module(addr_old);
load_module_conf();
}, 200);
dialog.close();
};
dialog_el.querySelector(".btn_cancel").onclick = function () {
dialog.close();
}
}
function display_dialog_add_device() {
const dialog = document.getElementById("dialog_add_device");
dialog.showModal();
const dialog_el = dialog.querySelector("article").querySelector("section").querySelector("footer");
dialog_el.querySelector(".btn_confirm").onclick = function () {
const msg = {
"command": "dm_register",
"address": Number(dialog.querySelector("#form_add_device_addr").value),
"x": Number(dialog.querySelector("#form_add_device_x").value),
"y": Number(dialog.querySelector("#form_add_device_y").value)
}
SFCCommandAsync(msg);
setTimeout(function () {
load_module_conf();
}, 200);
dialog.close();
};
dialog_el.querySelector(".btn_cancel").onclick = function () {
dialog.close();
}
}