Added WebSockets support to UI

This commit is contained in:
cschwinne 2021-07-02 01:46:42 +02:00
parent dc01c907f1
commit 40c8fdbf64
6 changed files with 2316 additions and 2265 deletions

View File

@ -2,6 +2,10 @@
### Builds after release 0.12.0
#### Build 2107021
- Added WebSockets support to UI
#### Build 2107020
- Send websockets on every state change

View File

@ -970,12 +970,12 @@ input[type=number]::-webkit-outer-spin-button {
z-index: 1;
}
#selectPalette .lstI.selected {
#pallist .lstI.selected {
top: 27px;
bottom: -11px;
}
#selectPalette .lstI.sticky {
#pallist .lstI.sticky {
top: -11px;
}

View File

@ -93,7 +93,7 @@
Color palette
</p>
<div class="il">
<div id="selectPalette" class="list">
<div id="pallist" class="list">
<div class="lstI" data-id="0">
<label class="check schkl">
&nbsp;

View File

@ -7,7 +7,7 @@ var selColors;
var expanded = [false];
var powered = [true];
var nlDur = 60, nlTar = 0;
var nlFade = false;
var nlMode = false;
var selectedFx = 0;
var csel = 0;
var currentPreset = -1;
@ -22,6 +22,8 @@ var pJson = {};
var pN = "", pI = 0, pNum = 0;
var pmt = 1, pmtLS = 0, pmtLast = 0;
var lastinfo = {};
var ws, useWs = false;
var fxlist = d.getElementById('fxlist'), pallist = d.getElementById('pallist');
var cfg = {
theme:{base:"dark", bg:{url:""}, alpha:{bg:0.6,tab:0.8}, color:{bg:""}},
comp :{colors:{picker: true, rgb: false, quick: true, hex: false}, labels:true, pcmbot:false, pid:true}
@ -619,7 +621,7 @@ function populateEffects(effects)
);
}
d.getElementById('fxlist').innerHTML=html;
fxlist.innerHTML=html;
}
function populatePalettes(palettes)
@ -653,12 +655,12 @@ function populatePalettes(palettes)
);
}
d.getElementById('selectPalette').innerHTML=html;
pallist.innerHTML=html;
}
function redrawPalPrev()
{
let palettes = d.querySelectorAll('#selectPalette .lstI');
let palettes = d.querySelectorAll('#pallist .lstI');
for (let i = 0; i < palettes.length; i++) {
let id = palettes[i].dataset.id;
let lstPrev = palettes[i].querySelector('.lstIprev');
@ -909,97 +911,16 @@ function cmpP(a, b) {
return a[1].n.localeCompare(b[1].n,undefined, {numeric: true});
}
var jsonTimeout;
var reqsLegal = false;
function requestJson(command, rinfo = true, verbose = true) {
d.getElementById('connind').style.backgroundColor = "#a90";
if (command && !reqsLegal) return; //stop post requests from chrome onchange event on page restore
lastUpdate = new Date();
if (!jsonTimeout) jsonTimeout = setTimeout(showErrorToast, 3000);
var req = null;
var e1 = d.getElementById('fxlist');
var e2 = d.getElementById('selectPalette');
var url = rinfo ? '/json/si': (command ? '/json/state':'/json');
if (loc) {
url = `http://${locip}${url}`;
}
var type = command ? 'post':'get';
if (command)
{
command.v = verbose;
command.time = Math.floor(Date.now() / 1000);
req = JSON.stringify(command);
//console.log(req);
}
fetch
(url, {
method: type,
headers: {
"Content-type": "application/json; charset=UTF-8"
},
body: req
})
.then(res => {
if (!res.ok) {
showErrorToast();
}
return res.json();
})
.then(json => {
function makeWS() {
if (ws) return;
ws = new WebSocket('ws://'+(loc?locip:window.location.hostname)+'/ws');
ws.onmessage = function(event) {
clearTimeout(jsonTimeout);
jsonTimeout = null;
clearErrorToast();
d.getElementById('connind').style.backgroundColor = "#070";
if (!json) {
showToast('Empty response', true);
}
if (json.success) {
return;
}
var s = json;
if (!command || rinfo) {
if (!rinfo) {
pmt = json.info.fs.pmt;
if (pmt != pmtLS || pmt == 0) {
setTimeout(loadPresets,99);
}
else {
populatePresets(true);
}
pmtLast = pmt;
populateEffects(json.effects);
populatePalettes(json.palettes);
reqsLegal = true;
}
d.getElementById('connind').style.backgroundColor = "#079";
var json = JSON.parse(event.data);
var info = json.info;
var name = info.name;
d.getElementById('namelabel').innerHTML = name;
if (name === "Dinnerbone") {
d.documentElement.style.transform = "rotate(180deg)";
}
if (info.live) {
name = "(Live) " + name;
}
if (loc) {
name = "(L) " + name;
}
d.title = name;
isRgbw = info.leds.wv;
ledCount = info.leds.count;
syncTglRecv = info.str;
maxSeg = info.leds.maxseg;
pmt = info.fs.pmt;
if (!command && pmt != pmtLast) {
setTimeout(loadPresets,99);
}
pmtLast = pmt;
d.getElementById('buttonNodes').style.display = (info.ndc > 0 && window.innerWidth > 770) ? "block":"none";
lastinfo = info;
if (isInfo) {
@ -1007,16 +928,20 @@ function requestJson(command, rinfo = true, verbose = true) {
}
s = json.state;
displayRover(info, s);
if (!rinfo) loadPalettesData();
readState(json.state);
};
ws.onclose = function(event) {
d.getElementById('connind').style.backgroundColor = "#831";
}
}
function readState(s,command=false) {
isOn = s.on;
d.getElementById('sliderBri').value= s.bri;
nlA = s.nl.on;
nlDur = s.nl.dur;
nlTar = s.nl.tbri;
nlFade = s.nl.fade;
nlMode = s.nl.mode;
syncSend = s.udpn.send;
currentPreset = s.ps;
tr = s.transition;
@ -1049,25 +974,25 @@ function requestJson(command, rinfo = true, verbose = true) {
d.getElementById('sliderIntensity').value = i.ix;
// Effects
var selFx = e1.querySelector(`input[name="fx"][value="${i.fx}"]`);
var selFx = fxlist.querySelector(`input[name="fx"][value="${i.fx}"]`);
if (selFx) selFx.checked = true;
else location.reload(); //effect list is gone (e.g. if restoring tab). Reload.
var selElement = e1.querySelector('.selected');
var selElement = fxlist.querySelector('.selected');
if (selElement) {
selElement.classList.remove('selected')
}
var selectedEffect = e1.querySelector(`.lstI[data-id="${i.fx}"]`);
var selectedEffect = fxlist.querySelector(`.lstI[data-id="${i.fx}"]`);
selectedEffect.classList.add('selected');
selectedFx = i.fx;
// Palettes
e2.querySelector(`input[name="palette"][value="${i.pal}"]`).checked = true;
selElement = e2.querySelector('.selected');
pallist.querySelector(`input[name="palette"][value="${i.pal}"]`).checked = true;
selElement = pallist.querySelector('.selected');
if (selElement) {
selElement.classList.remove('selected')
}
e2.querySelector(`.lstI[data-id="${i.pal}"]`).classList.add('selected');
pallist.querySelector(`.lstI[data-id="${i.pal}"]`).classList.add('selected');
if (!command) {
selectedEffect.scrollIntoView({
@ -1095,6 +1020,115 @@ function requestJson(command, rinfo = true, verbose = true) {
showToast('Error ' + s.error + ": " + errstr, true);
}
updateUI();
}
var jsonTimeout;
var reqsLegal = false;
function requestJson(command, rinfo = true, verbose = true) {
d.getElementById('connind').style.backgroundColor = "#a90";
if (command && !reqsLegal) return; //stop post requests from chrome onchange event on page restore
lastUpdate = new Date();
if (!jsonTimeout) jsonTimeout = setTimeout(showErrorToast, 3000);
var req = null;
var url = rinfo ? '/json/si': (command ? '/json/state':'/json');
if (loc) {
url = `http://${locip}${url}`;
}
var type = command ? 'post':'get';
if (command)
{
command.v = verbose;
command.time = Math.floor(Date.now() / 1000);
req = JSON.stringify(command);
}
if ((command || rinfo) && ws && ws.readyState === WebSocket.OPEN) {
ws.send(req?req:'{"v":true}');
return;
}
fetch
(url, {
method: type,
headers: {
"Content-type": "application/json; charset=UTF-8"
},
body: req
})
.then(res => {
if (!res.ok) {
showErrorToast();
}
return res.json();
})
.then(json => {
clearTimeout(jsonTimeout);
jsonTimeout = null;
clearErrorToast();
d.getElementById('connind').style.backgroundColor = "#070";
if (!json) {
showToast('Empty response', true);
}
if (json.success) {
return;
}
var s = json;
if (!command || rinfo) { //we have info object
if (!rinfo) { //entire JSON (on load)
pmt = json.info.fs.pmt;
if (pmt != pmtLS || pmt == 0) {
setTimeout(loadPresets,99);
}
else {
populatePresets(true);
}
pmtLast = pmt;
populateEffects(json.effects);
populatePalettes(json.palettes);
reqsLegal = true;
}
var info = json.info;
var name = info.name;
d.getElementById('namelabel').innerHTML = name;
if (name === "Dinnerbone") {
d.documentElement.style.transform = "rotate(180deg)";
}
if (info.live) {
name = "(Live) " + name;
}
if (loc) {
name = "(L) " + name;
}
d.title = name;
isRgbw = info.leds.wv;
ledCount = info.leds.count;
syncTglRecv = info.str;
maxSeg = info.leds.maxseg;
pmt = info.fs.pmt;
if (!ws && info.ws > -1) setTimeout(makeWS,1000);
if (!command && pmt != pmtLast) {
setTimeout(loadPresets,99);
}
pmtLast = pmt;
d.getElementById('buttonNodes').style.display = (info.ndc > 0 && window.innerWidth > 770) ? "block":"none";
lastinfo = info;
if (isInfo) {
populateInfo(info);
}
s = json.state;
displayRover(info, s);
if (!rinfo) loadPalettesData();
}
readState(s,command);
})
.catch(function (error) {
showToast(error, true);
@ -1113,7 +1147,7 @@ function toggleNl() {
nlA = !nlA;
if (nlA)
{
showToast(`Timer active. Your light will turn ${nlTar > 0 ? "on":"off"} ${nlFade ? "over":"after"} ${nlDur} minutes.`);
showToast(`Timer active. Your light will turn ${nlTar > 0 ? "on":"off"} ${nlMode ? "over":"after"} ${nlDur} minutes.`);
} else {
showToast('Timer deactivated.');
}
@ -1483,15 +1517,15 @@ function setX(ind = null) {
function setPalette(paletteId = null)
{
if (paletteId === null) {
paletteId = parseInt(d.querySelector('#selectPalette input[name="palette"]:checked').value);
paletteId = parseInt(d.querySelector('#pallist input[name="palette"]:checked').value);
} else {
d.querySelector(`#selectPalette input[name="palette"][value="${paletteId}`).checked = true;
d.querySelector(`#pallist input[name="palette"][value="${paletteId}`).checked = true;
}
var selElement = d.querySelector('#selectPalette .selected');
var selElement = d.querySelector('#pallist .selected');
if (selElement) {
selElement.classList.remove('selected')
}
d.querySelector(`#selectPalette .lstI[data-id="${paletteId}"]`).classList.add('selected');
d.querySelector(`#pallist .lstI[data-id="${paletteId}"]`).classList.add('selected');
var obj = {"seg": {"pal": paletteId}};
requestJson(obj);
}

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2107020
#define VERSION 2107021
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG