Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
59025e317e |
122
tools/wled.js
Normal file
122
tools/wled.js
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
|
||||||
|
const express = require("express");
|
||||||
|
const { createProxyMiddleware } = require('http-proxy-middleware');
|
||||||
|
const path = require("path");
|
||||||
|
const nopt = require("nopt");
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
var knownOpts = {
|
||||||
|
"help": Boolean,
|
||||||
|
"port": Number,
|
||||||
|
"settings": [path],
|
||||||
|
"host": String,
|
||||||
|
"verbose": Boolean
|
||||||
|
};
|
||||||
|
var shortHands = {
|
||||||
|
"?":["--help"],
|
||||||
|
"p":["--port"],
|
||||||
|
"s":["--settings"],
|
||||||
|
"h":["--host"],
|
||||||
|
"v":["--verbose"]
|
||||||
|
};
|
||||||
|
|
||||||
|
nopt.invalidHandler = function(k,v,t) {
|
||||||
|
// TODO: console.log(k,v,t);
|
||||||
|
}
|
||||||
|
|
||||||
|
var parsedArgs = nopt(knownOpts,shortHands,process.argv,2);
|
||||||
|
|
||||||
|
if (parsedArgs.help) {
|
||||||
|
console.log("WLED Dev Server");
|
||||||
|
console.log("Usage: wled [-v] [-?] [--settings settings.js] [--userDir DIR]");
|
||||||
|
console.log(" [--port PORT] [--host HOST]");
|
||||||
|
console.log("");
|
||||||
|
console.log("Options:");
|
||||||
|
console.log(" -p, --port PORT port to listen on");
|
||||||
|
console.log(" -s, --settings FILE use specified settings file");
|
||||||
|
console.log(" --host HOST WLED instance for dynamic content");
|
||||||
|
console.log(" -v, --verbose enable verbose output");
|
||||||
|
console.log(" -?, --help show this help");
|
||||||
|
console.log("");
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// WLED_HOME - the root directory where the html files are
|
||||||
|
process.env.WLED_HOME = process.env.WLED_HOME || path.resolve(__dirname,'..','wled00','data');
|
||||||
|
|
||||||
|
parsedArgs.port = parsedArgs.port || 8080;
|
||||||
|
parsedArgs.host = parsedArgs.host || "0.0.0.0";
|
||||||
|
|
||||||
|
// get the static file reference
|
||||||
|
function static(page) {
|
||||||
|
return express.static(process.env.WLED_HOME, {index: page});
|
||||||
|
}
|
||||||
|
|
||||||
|
// add routes for each setting page
|
||||||
|
function useSettingsRoutes() {
|
||||||
|
app.use(`/settings`, static(`settings.htm`));
|
||||||
|
|
||||||
|
const settings = ['wifi', 'leds', 'ui', 'sync','time','um', 'sec'];
|
||||||
|
settings.forEach(function(setting) {
|
||||||
|
app.use(`/settings/${setting}`, static(`settings_${setting}.htm`));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// dynamic content that is proxied to real WLED instance
|
||||||
|
function useWebProxyRoutes(host) {
|
||||||
|
const httpProxy = createProxyMiddleware({ target: `http://${host}`, changeOrigin: true, logLevel: 'warn' });
|
||||||
|
const proxyRoutes = ['json', 'presets.json', 'skins.css', 'liveview'];
|
||||||
|
proxyRoutes.forEach(function(route) {
|
||||||
|
app.use(`/${route}`, httpProxy);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// proxy data to a real WLED instance
|
||||||
|
function useWebSocketProxy(host, server) {
|
||||||
|
const wsProxy = createProxyMiddleware(`ws://${host}`, { changeOrigin: true, logLevel: 'warn' });
|
||||||
|
app.use(wsProxy);
|
||||||
|
server.on('upgrade', wsProxy.upgrade);
|
||||||
|
}
|
||||||
|
|
||||||
|
// first matching route
|
||||||
|
app.use('/', static("index.htm"));
|
||||||
|
useSettingsRoutes(); // map the setting pages
|
||||||
|
useWebProxyRoutes(parsedArgs.host);
|
||||||
|
|
||||||
|
// use static files like style sheets etc
|
||||||
|
app.use(express.static(process.env.WLED_HOME));
|
||||||
|
|
||||||
|
const server = app.listen(parsedArgs.port, () => {
|
||||||
|
if (parsedArgs.verbose) {
|
||||||
|
console.log(`WLED UI listening at http://localhost:${parsedArgs.port}`)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
useWebSocketProxy(parsedArgs.host, server);
|
||||||
|
|
||||||
|
var stopping = false;
|
||||||
|
function exitWhenStopped() {
|
||||||
|
if (!stopping) {
|
||||||
|
stopping = true;
|
||||||
|
server.close(function() {
|
||||||
|
console.log('WLED UI closed');
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process.on('uncaughtException',function(err) {
|
||||||
|
util.log('[WLED] Uncaught Exception:');
|
||||||
|
if (err.stack) {
|
||||||
|
console.log(err.stack);
|
||||||
|
} else {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('SIGINT', exitWhenStopped);
|
||||||
|
process.on('SIGTERM', exitWhenStopped);
|
||||||
|
process.on('SIGHUP', exitWhenStopped);
|
||||||
|
process.on('SIGUSR2', exitWhenStopped); // for nodemon restart
|
||||||
|
process.on('SIGBREAK', exitWhenStopped); // for windows ctrl-break
|
129
wled00/data/cfg.css
Normal file
129
wled00/data/cfg.css
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: "CIcons";
|
||||||
|
src: url(data:application/font-woff;charset=utf-8;base64,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) format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--c-1: #111;
|
||||||
|
--c-f: #fff;
|
||||||
|
--c-2: #222;
|
||||||
|
--c-3: #333;
|
||||||
|
--c-4: #444;
|
||||||
|
--c-5: #555;
|
||||||
|
--c-6: #666;
|
||||||
|
--c-8: #888;
|
||||||
|
--c-b: #bbb;
|
||||||
|
--c-c: #ccc;
|
||||||
|
--c-e: #eee;
|
||||||
|
--c-d: #ddd;
|
||||||
|
--c-r: #831;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
touch-action: manipulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background-color: var(--c-2);
|
||||||
|
font-family: Helvetica, Verdana, sans-serif;
|
||||||
|
font-size: 17px;
|
||||||
|
color: var(--c-f);
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
scrollbar-width: 6px;
|
||||||
|
scrollbar-color: var(--c-sb) transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
overscroll-behavior: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icons {
|
||||||
|
font-family: "CIcons";
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 1;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header {
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--c-3);
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu {
|
||||||
|
height: calc(100% - 45px);
|
||||||
|
background-color: var(--c-3);
|
||||||
|
width: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry {
|
||||||
|
height: 45px;
|
||||||
|
color: var(--c-b);
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry:hover {
|
||||||
|
color: var(--c-f);
|
||||||
|
background-color: var(--c-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-icon {
|
||||||
|
padding: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
width: 45px;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-label {
|
||||||
|
display: inline-block;
|
||||||
|
height: 45px;
|
||||||
|
vertical-align: top;
|
||||||
|
padding: 14px 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 9px;
|
||||||
|
color: var(--c-b);
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover {
|
||||||
|
color: var(--c-f);
|
||||||
|
background-color: var(--c-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.save {
|
||||||
|
float: right;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-icon {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-label {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
#menu {
|
||||||
|
width: 45px;
|
||||||
|
}
|
||||||
|
.e-label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
71
wled00/data/cfg.htm
Normal file
71
wled00/data/cfg.htm
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="theme-color" content="#222222">
|
||||||
|
<link rel="stylesheet" href="cfg.css">
|
||||||
|
<script src="cfg_lang.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="header">
|
||||||
|
<div class="e-icon"><i class="icons"></i></div>
|
||||||
|
<div class="l e-label l10n" id="h-cfg"></div>
|
||||||
|
<div class="btn save">
|
||||||
|
<div class="b-icon"><i class="icons"></i></div>
|
||||||
|
<div class="l b-label l10n" id="b-save">Save</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="menu">
|
||||||
|
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-nw">Network</div></div>
|
||||||
|
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-hw">Hardware</div></div>
|
||||||
|
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-ui">Customization</div></div>
|
||||||
|
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-if">Interfaces</div></div>
|
||||||
|
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-tm">Schedules</div></div>
|
||||||
|
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-dx">DMX Out</div></div>
|
||||||
|
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-sr">Sound Reactive</div></div>
|
||||||
|
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-um">Usermods</div></div>
|
||||||
|
<div class="entry"><div class="e-icon"><i class="icons"></i></div><div class="l e-label l10n" id="e-ab">About</div></div>
|
||||||
|
</div>
|
||||||
|
<div id="content">
|
||||||
|
<!-- simulate sections for each menu item -->
|
||||||
|
<div id="nw">
|
||||||
|
<h2 class="l10n">Network</h2>
|
||||||
|
</div>
|
||||||
|
<div id="hw">
|
||||||
|
<h2 class="l10n">Hardware</h2>
|
||||||
|
</div>
|
||||||
|
<div id="ui">
|
||||||
|
<h2 class="l10n">Customization</h2>
|
||||||
|
</div>
|
||||||
|
<div id="if">
|
||||||
|
<h2 class="l10n">Interfaces</h2>
|
||||||
|
</div>
|
||||||
|
<div id="tm">
|
||||||
|
<h2 class="l10n">Schedules</h2>
|
||||||
|
</div>
|
||||||
|
<div id="sr">
|
||||||
|
<h2 class="l10n">Sound Reactive</h2>
|
||||||
|
</div>
|
||||||
|
<div id="um">
|
||||||
|
<h2 class="l10n">Usermods</h2>
|
||||||
|
</div>
|
||||||
|
<div id="dx">
|
||||||
|
<h2 class="l10n">DMX Out</h2>
|
||||||
|
</div>
|
||||||
|
<div id="ab">
|
||||||
|
<h2 class="l10n">About</h2>
|
||||||
|
</div>
|
||||||
|
<div id="up">
|
||||||
|
<h2 class="l10n">Update</h2>
|
||||||
|
</div>
|
||||||
|
<div id="rb">
|
||||||
|
<h2 class="l10n">Reboot</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="cfg.js" type="module"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
30
wled00/data/cfg.js
Normal file
30
wled00/data/cfg.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import $ from './dom.mjs'
|
||||||
|
import translate from './translator.mjs'
|
||||||
|
|
||||||
|
/* Dynamically create the menu
|
||||||
|
const menuItems = [
|
||||||
|
{ "icon": "", "id": "e-nw", "text": "Network" },
|
||||||
|
{ "icon": "", "id": "e-hw", "text": "Hardware" },
|
||||||
|
{ "icon": "", "id": "e-ui", "text": "Customization" },
|
||||||
|
{ "icon": "", "id": "e-if", "text": "Interfaces" },
|
||||||
|
{ "icon": "", "id": "e-tm", "text": "Schedules" },
|
||||||
|
{ "icon": "", "id": "e-dx", "text": "DMX Out" },
|
||||||
|
{ "icon": "", "id": "e-sr", "text": "Sound Reactive" },
|
||||||
|
{ "icon": "", "id": "e-um", "text": "Usermods" },
|
||||||
|
{ "icon": "", "id": "e-ab", "text": "About" }
|
||||||
|
];
|
||||||
|
|
||||||
|
$().ready(function() {
|
||||||
|
const menu = $('#menu');
|
||||||
|
menuItems.map(item =>
|
||||||
|
menu.append(`<div class="entry"><div class="e-icon"><i class="icons">${item.icon}</i></div><div class="l e-label l10n" id="${item.id}">${item.text}</div></div>`)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
// populate labels when to dom is ready but before it is rendered
|
||||||
|
$().ready(function() {
|
||||||
|
// https://www.w3.org/International/questions/qa-i18n
|
||||||
|
// Localization is sometimes written in English as l10n
|
||||||
|
translate('.l10n');
|
||||||
|
});
|
10
wled00/data/cfg_lang.js
Normal file
10
wled00/data/cfg_lang.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
(function() {
|
||||||
|
// self executing function to ensure translations is set on page load
|
||||||
|
// so we dont have to wait for fetch/xhr request
|
||||||
|
window.translations = {
|
||||||
|
"About": "Über",
|
||||||
|
"Save": "Speichern",
|
||||||
|
"Schedules": "Zeitpläne",
|
||||||
|
"Sound Reactive": "Tonreaktiv"
|
||||||
|
};
|
||||||
|
}());
|
126
wled00/data/dom.mjs
Normal file
126
wled00/data/dom.mjs
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
** DOM module - base on https://github.com/kylebarrow/chibi with IE hacks removed
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
var readyfn = [],
|
||||||
|
loadedfn = [],
|
||||||
|
domready = false,
|
||||||
|
pageloaded = false,
|
||||||
|
d = document,
|
||||||
|
w = window;
|
||||||
|
|
||||||
|
// Fire any function calls on ready event
|
||||||
|
function fireReady() {
|
||||||
|
var i;
|
||||||
|
domready = true;
|
||||||
|
for (i = 0; i < readyfn.length; i += 1) {
|
||||||
|
readyfn[i]();
|
||||||
|
}
|
||||||
|
readyfn = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire any function calls on loaded event
|
||||||
|
function fireLoaded() {
|
||||||
|
var i;
|
||||||
|
pageloaded = true;
|
||||||
|
for (i = 0; i < loadedfn.length; i += 1) {
|
||||||
|
loadedfn[i]();
|
||||||
|
}
|
||||||
|
loadedfn = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check DOM ready, page loaded
|
||||||
|
if (d.addEventListener) {
|
||||||
|
// Standards
|
||||||
|
d.addEventListener('DOMContentLoaded', fireReady, false);
|
||||||
|
w.addEventListener('load', fireLoaded, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through node array
|
||||||
|
function nodeLoop(fn, nodes) {
|
||||||
|
var i;
|
||||||
|
// Good idea to walk up the DOM
|
||||||
|
for (i = nodes.length - 1; i >= 0; i -= 1) {
|
||||||
|
fn(nodes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dom(selector) {
|
||||||
|
var self, nodes = [],
|
||||||
|
json = false,
|
||||||
|
nodelist;
|
||||||
|
|
||||||
|
if (selector) {
|
||||||
|
|
||||||
|
// Element node
|
||||||
|
if (selector instanceof HTMLElement) {
|
||||||
|
nodes = [selector]; // return element as node list
|
||||||
|
} else if (selector instanceof NodeList) {
|
||||||
|
// JSON, document object or node list
|
||||||
|
json = (typeof selector.length !== 'number');
|
||||||
|
nodes = selector;
|
||||||
|
} else if (typeof selector === 'string') {
|
||||||
|
nodelist = d.querySelectorAll(selector);
|
||||||
|
nodes = Array.from(nodelist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only attach nodes if not JSON
|
||||||
|
self = json ? {} : nodes;
|
||||||
|
|
||||||
|
// Public functions
|
||||||
|
|
||||||
|
// Fire on DOM ready
|
||||||
|
self.ready = function(fn) {
|
||||||
|
if (fn) {
|
||||||
|
if (domready) {
|
||||||
|
fn();
|
||||||
|
return self;
|
||||||
|
} else {
|
||||||
|
readyfn.push(fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Fire on page loaded
|
||||||
|
self.loaded = function(fn) {
|
||||||
|
if (fn) {
|
||||||
|
if (pageloaded) {
|
||||||
|
fn();
|
||||||
|
return self;
|
||||||
|
} else {
|
||||||
|
loadedfn.push(fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Executes a function on nodes
|
||||||
|
self.each = function(fn) {
|
||||||
|
if (typeof fn === 'function') {
|
||||||
|
nodeLoop(fn, nodes);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.first = function() {
|
||||||
|
return dom(nodes.shift());
|
||||||
|
};
|
||||||
|
|
||||||
|
// Find last
|
||||||
|
self.last = function() {
|
||||||
|
return dom(nodes.pop());
|
||||||
|
};
|
||||||
|
|
||||||
|
// append html before end of the of the tag
|
||||||
|
self.append = function(value) {
|
||||||
|
if (value) {
|
||||||
|
nodeLoop(function(elm) {
|
||||||
|
elm.insertAdjacentHTML('beforeend', value);
|
||||||
|
}, nodes);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
};
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default dom;
|
27
wled00/data/translator.mjs
Normal file
27
wled00/data/translator.mjs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import $ from './dom.mjs'
|
||||||
|
|
||||||
|
var w = window;
|
||||||
|
|
||||||
|
function getText(elm) {
|
||||||
|
return elm.textContent; // or innerText ?
|
||||||
|
}
|
||||||
|
|
||||||
|
function setText(elm, value) {
|
||||||
|
if (value) {
|
||||||
|
elm.textContent = value; // or innerText ?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform simple translation
|
||||||
|
function translateElement(elm) {
|
||||||
|
const text = getText(elm);
|
||||||
|
setText(elm, w.translations[text]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function translate(selector) {
|
||||||
|
if (w.translations) {
|
||||||
|
$(selector).each(translateElement)
|
||||||
|
} else {
|
||||||
|
console.info("no translations");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user