add web ui
This commit is contained in:
@@ -171,6 +171,14 @@ void cmd_dm_print_single(json_object *req, json_object *res)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clear display
|
||||||
|
void cmd_dm_clear(json_object *req, json_object *res)
|
||||||
|
{
|
||||||
|
devicemgr_clearscreen();
|
||||||
|
json_object_object_add(res, "ack", json_object_new_boolean(true));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ping device
|
// ping device
|
||||||
void cmd_dr_ping(json_object *req, json_object *res)
|
void cmd_dr_ping(json_object *req, json_object *res)
|
||||||
@@ -375,6 +383,11 @@ json_object *parse_command(json_object *req)
|
|||||||
cmd_dm_print(req, res);
|
cmd_dm_print(req, res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
else if (strcmp(command, "dm_clear") == 0)
|
||||||
|
{
|
||||||
|
cmd_dm_clear(req, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
else if (strcmp(command, "dr_ping") == 0)
|
else if (strcmp(command, "dr_ping") == 0)
|
||||||
{
|
{
|
||||||
cmd_dr_ping(req, res);
|
cmd_dr_ping(req, res);
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ int devicemgr_readStatus(int device_id)
|
|||||||
u_int32_t _counter = 0;
|
u_int32_t _counter = 0;
|
||||||
u_int8_t _status =
|
u_int8_t _status =
|
||||||
sfbus_read_status(devices[device_id].rs485_descriptor, devices[device_id].address, &_voltage, &_counter);
|
sfbus_read_status(devices[device_id].rs485_descriptor, devices[device_id].address, &_voltage, &_counter);
|
||||||
|
|
||||||
if (_status == 0xFF)
|
if (_status == 0xFF)
|
||||||
{
|
{
|
||||||
devices[device_id].powerState = UNKNOWN;
|
devices[device_id].powerState = UNKNOWN;
|
||||||
@@ -252,16 +253,16 @@ void setSingle(int id, char flap)
|
|||||||
{
|
{
|
||||||
printf("match char %i %i %i\n", test_char, *symbols[ix], ix);
|
printf("match char %i %i %i\n", test_char, *symbols[ix], ix);
|
||||||
sfbus_display_full(devices[id].rs485_descriptor, devices[id].address, ix);
|
sfbus_display_full(devices[id].rs485_descriptor, devices[id].address, ix);
|
||||||
|
devices[id].current_flap = ix;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
devices[nextFreeSlot].current_flap = flap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSingleRaw(int id, int flap)
|
void setSingleRaw(int id, int flap)
|
||||||
{
|
{
|
||||||
sfbus_display_full(devices[id].rs485_descriptor, devices[id].address, flap);
|
sfbus_display_full(devices[id].rs485_descriptor, devices[id].address, flap);
|
||||||
devices[nextFreeSlot].current_flap = flap;
|
devices[id].current_flap = flap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void devicemgr_printText(const char *text, int x, int y)
|
void devicemgr_printText(const char *text, int x, int y)
|
||||||
@@ -287,6 +288,21 @@ void devicemgr_printFlap(int flap, int x, int y)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clears complete screen
|
||||||
|
void devicemgr_clearscreen()
|
||||||
|
{
|
||||||
|
for (int ix = 0; ix < SFDEVICE_MAXDEV; ix++)
|
||||||
|
{
|
||||||
|
if (devices[ix].address > 0)
|
||||||
|
{
|
||||||
|
if (devices[ix].current_flap != 0)
|
||||||
|
{
|
||||||
|
setSingleRaw(ix, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int devicemgr_register(int rs485_descriptor, u_int16_t address, int x, int y, int nid)
|
int devicemgr_register(int rs485_descriptor, u_int16_t address, int x, int y, int nid)
|
||||||
{
|
{
|
||||||
if (nid < 0)
|
if (nid < 0)
|
||||||
@@ -384,7 +400,7 @@ int devicemgr_load(char *file)
|
|||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
char* read_ret = fgets(line_in_file, JSON_MAX_LINE_LEN, fptr); // read line from file
|
char *read_ret = fgets(line_in_file, JSON_MAX_LINE_LEN, fptr); // read line from file
|
||||||
stringlen = strlen(line_in_file);
|
stringlen = strlen(line_in_file);
|
||||||
// printf("Read line with chars: %i : %s", stringlen, line_in_file); // only for testing
|
// printf("Read line with chars: %i : %s", stringlen, line_in_file); // only for testing
|
||||||
jobj = json_tokener_parse_ex(tok, line_in_file, stringlen);
|
jobj = json_tokener_parse_ex(tok, line_in_file, stringlen);
|
||||||
|
|||||||
@@ -35,4 +35,5 @@ void devicemgr_printText(const char *text, int x, int y);
|
|||||||
void devicemgr_printFlap(int flap, int x, int y);
|
void devicemgr_printFlap(int flap, int x, int y);
|
||||||
int devicemgr_load(char *file);
|
int devicemgr_load(char *file);
|
||||||
int devicemgr_load_single(json_object *device_obj);
|
int devicemgr_load_single(json_object *device_obj);
|
||||||
int devicemgr_remove(int id);
|
int devicemgr_remove(int id);
|
||||||
|
void devicemgr_clearscreen();
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <wsserver/ws.h>
|
#include <wsserver/ws.h>
|
||||||
|
|
||||||
#define WS_SERVER_PORT 8080
|
#define WS_SERVER_PORT 8089
|
||||||
#define WS_SERVER_ADDR "localhost"
|
#define WS_SERVER_ADDR "localhost"
|
||||||
|
|
||||||
int start_webserver();
|
int start_webserver();
|
||||||
|
|||||||
4
software/web_gui/css/pico.min.css
vendored
Normal file
4
software/web_gui/css/pico.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
224
software/web_gui/index.html
Normal file
224
software/web_gui/index.html
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="color-scheme" content="light dark">
|
||||||
|
<link rel="stylesheet" href="css/pico.min.css">
|
||||||
|
<script type="text/javascript" src="js/sfc.js"></script>
|
||||||
|
<title>Hello world!</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<dialog id="dialog_change_calibration">
|
||||||
|
<article>
|
||||||
|
<h2>Change calibration</h2>
|
||||||
|
<section>
|
||||||
|
<form id="form_change_calibration">
|
||||||
|
<label>
|
||||||
|
New calibration data (default 1400):
|
||||||
|
<input id="form_change_calibration_data" name="calibration" type="number"
|
||||||
|
placeholder="Calibration Value" value="1400" />
|
||||||
|
</label>
|
||||||
|
</form>
|
||||||
|
<footer>
|
||||||
|
<button class="secondary btn_cancel">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button class="btn_confirm">Confirm</button>
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<dialog id="change_address">
|
||||||
|
<article>
|
||||||
|
<h2>Change address</h2>
|
||||||
|
<section>
|
||||||
|
<form id="form_change_calibration">
|
||||||
|
<label>
|
||||||
|
Current address:
|
||||||
|
<input id="form_change_address_old" name="addr_old" type="number" placeholder="Current Address"
|
||||||
|
value="0" />
|
||||||
|
New address:
|
||||||
|
<input id="form_change_address_new" name="addr_new" type="number" placeholder="New Address" />
|
||||||
|
</label>
|
||||||
|
</form>
|
||||||
|
<footer>
|
||||||
|
<button class="secondary btn_cancel">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button class="btn_confirm">Confirm</button>
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<dialog id="dialog_add_device">
|
||||||
|
<article>
|
||||||
|
<h2>Add device</h2>
|
||||||
|
<section>
|
||||||
|
<form id="form_change_calibration">
|
||||||
|
<label>
|
||||||
|
Device address:
|
||||||
|
<input id="form_add_device_addr" name="addr_old" type="number" placeholder="Current Address"
|
||||||
|
value="0" />
|
||||||
|
Device position:
|
||||||
|
<fieldset role="group">
|
||||||
|
<input id="form_add_device_x" name="x" type="x" placeholder="Position X" value="0" />
|
||||||
|
<input id="form_add_device_y" name="y" type="y" placeholder="Position Y" value="0" />
|
||||||
|
</fieldset>
|
||||||
|
</label>
|
||||||
|
</form>
|
||||||
|
<footer>
|
||||||
|
<button class="secondary btn_cancel">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button class="btn_confirm">Confirm</button>
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<main class="container">
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
<li><strong>SplitFlap</strong></li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><a onclick="changeView('view_display')" class="secondary">Display</a></li>
|
||||||
|
<li>
|
||||||
|
<details class="dropdown">
|
||||||
|
<summary>
|
||||||
|
Configuration
|
||||||
|
</summary>
|
||||||
|
<ul dir="rtl">
|
||||||
|
<li><a onclick="changeView('view_conf_modules')">Modules</a></li>
|
||||||
|
<li><a href="#">Layout</a></li>
|
||||||
|
<li><a onclick="changeView('view_storage')">Storage</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<div id="view_display"><!-- Main View : print -->
|
||||||
|
<h1>Display Something!</h1>
|
||||||
|
<form id="form_display">
|
||||||
|
<fieldset>
|
||||||
|
<label>
|
||||||
|
Text to display:
|
||||||
|
<input id="form_display_str" name="text" placeholder="Text" />
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Position on display:
|
||||||
|
<fieldset role="group">
|
||||||
|
<input id="form_display_x" name="x" type="x" placeholder="Position X" value="0" />
|
||||||
|
<input id="form_display_y" name="y" type="y" placeholder="Position Y" value="0" />
|
||||||
|
</fieldset>
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<input type="button" onClick="btn_display()" value="Display" />
|
||||||
|
<input type="button" onClick="btn_clear()" value="Clear screen" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="view_conf_modules" style="display: none;">
|
||||||
|
<h1>Module config</h1>
|
||||||
|
<div role="group">
|
||||||
|
<button id="btn_refresh" onClick="load_module_conf()">Refresh</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template id="module_list_template">
|
||||||
|
<details name="example" open>
|
||||||
|
<summary class="module_header"></summary>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Property</th>
|
||||||
|
<th scope="col">Value</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Module ID</th>
|
||||||
|
<td>12,104</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Address</th>
|
||||||
|
<td>4,880</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Calibration</th>
|
||||||
|
<td>12,104</td>
|
||||||
|
<td><button>Set</button></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Status</th>
|
||||||
|
<td>12,104</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Rotations</th>
|
||||||
|
<td>12,104</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Position</th>
|
||||||
|
<td>12,104</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Motor On</th>
|
||||||
|
<td>12,104</td>
|
||||||
|
<td><input name="power" type="checkbox" role="switch" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Voltage</th>
|
||||||
|
<td>12,104</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Current flap</th>
|
||||||
|
<td>12,104</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Error flags</th>
|
||||||
|
<td>-</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
<div role="group">
|
||||||
|
<button class="btn_reset">Reset</button>
|
||||||
|
<button class="btn_remove secondary pico-background-red-500">Remove</button>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
<hr />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div id="module_list"></div>
|
||||||
|
<div role="group">
|
||||||
|
<button class="btn_add" onclick="display_dialog_add_device()">Add Module</button>
|
||||||
|
<button class="btn_assign" onclick="display_dialog_change_address()">Assign Address</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="view_storage" style="display: none;"><!-- Main View : print -->
|
||||||
|
<h1>Load/Save Config!</h1>
|
||||||
|
<div role="group">
|
||||||
|
<button class="btn_load" onclick="btn_load()">Load Config</button>
|
||||||
|
</div>
|
||||||
|
<div role="group">
|
||||||
|
<button class="btn_save" onclick="btn_save()">Safe Config</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
255
software/web_gui/js/sfc.js
Normal file
255
software/web_gui/js/sfc.js
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
// Create WebSocket connection.
|
||||||
|
let hostname = location.host;
|
||||||
|
if (hostname === "") {
|
||||||
|
hostname = "localhost";
|
||||||
|
}
|
||||||
|
console.log(`Connecting to ws://${hostname}`);
|
||||||
|
|
||||||
|
const socket = new WebSocket(`ws://${hostname}/manage/`);
|
||||||
|
|
||||||
|
// Connection opened
|
||||||
|
socket.addEventListener("open", (event) => {
|
||||||
|
SFCCommandAsync({ "command": "dm_load" });
|
||||||
|
|
||||||
|
//changeView("view_storage");
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.addEventListener("message", (event) => {
|
||||||
|
switch (last_command) {
|
||||||
|
case "dm_dump":
|
||||||
|
parse_module_conf(JSON.parse(event.data));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function toAddressStr(address) {
|
||||||
|
const hexbase = address.toString(16).padStart(4, '0').toUpperCase();
|
||||||
|
return `0x${hexbase}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send command
|
||||||
|
function SFCCommandAsync(data) {
|
||||||
|
last_command = data.command;
|
||||||
|
socket.send(JSON.stringify(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 msg = {
|
||||||
|
"command": "dm_print",
|
||||||
|
"string": text,
|
||||||
|
"x": x,
|
||||||
|
"y": y
|
||||||
|
}
|
||||||
|
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 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let modules = [];
|
||||||
|
|
||||||
|
function load_module_conf() {
|
||||||
|
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 ID ${mod["id"]} : ${mod["status"]["device"]}`;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function btn_save(){
|
||||||
|
const msg = {
|
||||||
|
"command": "dm_save",
|
||||||
|
}
|
||||||
|
SFCCommandAsync(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
function btn_load(){
|
||||||
|
const msg = {
|
||||||
|
"command": "dm_load",
|
||||||
|
}
|
||||||
|
SFCCommandAsync(msg);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user