Merge branch 'master' into dev

This commit is contained in:
Blaž Kristan 2021-07-08 13:39:22 +02:00
commit 944b857825
9 changed files with 2336 additions and 2279 deletions

View File

@ -2,6 +2,24 @@
### Builds after release 0.12.0
#### Build 2107080
- Made Peek use the main websocket connection instead of opening a second one
- Temperature usermod fix (from @blazoncek's dev branch)
#### Build 2107070
- More robust initial resource loading in UI
- Added `getJsonValue()` for usermod config parsing (PR #2061)
- Fixed preset saving over websocket
- Alpha ESP32 S2 support (filesystem does not work) (PR #2067)
#### Build 2107042
- Updated ArduinoJson to 6.18.1
- Improved Twinkleup effect
- Fixed preset immediately deselecting when set via HTTP API `PL=`
#### Build 2107041
- Restored support for "PL=~" mistakenly removed in 2106300

View File

@ -213,6 +213,7 @@ build_flags = -g
-DARDUINO_ARCH_ESP32
-DCONFIG_LITTLEFS_FOR_IDF_3_2
-DARDUINO_ARCH_ESP32S2
-DCONFIG_IDF_TARGET_ESP32S2
lib_deps =
${env.lib_deps}
@ -294,6 +295,19 @@ build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1
lib_deps = ${esp32.lib_deps}
[env:esp32s2_saola]
board = esp32dev
board_build.mcu = esp32s2
platform = espressif32
platform_packages =
toolchain-xtensa32s2
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.0-alpha1
framework = arduino
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
upload_speed = 460800
build_unflags = ${common.build_unflags}
lib_deps = ${esp32s2.lib_deps}
[env:esp8285_4CH_MagicHome]
board = esp8285
platform = ${common.platform_wled_default}
@ -378,15 +392,14 @@ build_flags = ${common.build_flags_esp32}
-D LEDPIN=16
-D RLYPIN=19
-D BTNPIN=17
-D IRPIN=18
-D UWLED_USE_MY_CONFIG
; -D USERMOD_DALLASTEMPERATURE
; -D USERMOD_DALLASTEMPERATURE_CELCIUS
; -D USERMOD_FOUR_LINE_DISPLAY
; -D TEMPERATURE_PIN=21
-D USERMOD_DALLASTEMPERATURE
-D USERMOD_FOUR_LINE_DISPLAY
-D TEMPERATURE_PIN=23
lib_deps = ${esp32.lib_deps}
; OneWire@~2.3.5
; milesburton/DallasTemperature@^3.9.0
; U8g2@~2.27.2
OneWire@~2.3.5
U8g2@~2.28.11
[env:m5atom]
board = esp32dev
@ -470,4 +483,3 @@ build_flags = ${common.build_flags_esp32} -D WLED_DISABLE_BROWNOUT_DET -D WLED_D
-D USER_SETUP_LOADED
monitor_filters = esp32_exception_decoder
lib_deps = ${esp32.lib_deps} TFT_eSPI

View File

@ -125,10 +125,8 @@
#endif
//APA102
#define B_HS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarSpiMethod> // hardware SPI
#define B_SS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarMethod> // soft SPI
#define B_HS_DOT_4 NeoPixelBrightnessBus<DotStarLbgrFeature,DotStarSpiMethod> // HW SPI, RGBW mode?
#define B_SS_DOT_4 NeoPixelBrightnessBus<DotStarLbgrFeature,DotStarMethod> // soft SPI, RGBW mode?
#define B_HS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarSpiMethod> //hardware SPI
#define B_SS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarMethod> //soft SPI
//LPD8806
#define B_HS_LPD_3 NeoPixelBrightnessBus<Lpd8806GrbFeature, Lpd8806SpiMethod>
@ -666,7 +664,7 @@ class PolyBus {
#ifndef CONFIG_IDF_TARGET_ESP32S2
if (num > 9) return I_NONE;
if (num > 7) offset = num -7;
#else
#else //ESP32 S2 only has 4 RMT channels
if (num > 5) return I_NONE;
if (num > 4) offset = num -4;
#endif

View File

@ -23,7 +23,7 @@ var pJson = {}, eJson = {}, lJson = {};
var pN = "", pI = 0, pNum = 0;
var pmt = 1, pmtLS = 0, pmtLast = 0;
var lastinfo = {};
var ws, noWS = false;
var ws;
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, seglen:false}
@ -239,7 +239,7 @@ function onLoad()
loadFX(function() {
loadPresets(function() {
loadInfo(function() {
requestJson({'v':true}, false, true);
requestJson({'v':true}, false);
});
});
});
@ -253,6 +253,7 @@ function onLoad()
if (localStorage.getItem('pcm') == "true") togglePcMode(true);
var sls = d.querySelectorAll('input[type="range"]');
for (var sl of sls) {
//sl.addEventListener('input', updateBubble, true);
sl.addEventListener('touchstart', toggleBubble);
sl.addEventListener('touchend', toggleBubble);
}
@ -395,6 +396,20 @@ function presetError(empty)
function loadPresets(callback = null)
{
//1st boot (because there is a callback)
if (callback && pmt == pmtLS && pmt > 0) {
//we have a copy of the presets in local storage and don't need to fetch another one
populatePresets(true);
pmtLast = pmt;
callback();
return;
}
//afterwards
if (!callback && pmt == pmtLast) return;
pmtLast = pmt;
var url = (loc?`http://${locip}`:'') + '/presets.json';
fetch(url, {
@ -415,7 +430,10 @@ function loadPresets(callback = null)
showToast(error, true);
console.log(error);
presetError(false);
if (callback) callback();
//if (callback) callback();
})
.finally(() => {
if (callback) setTimeout(callback,99);
});
}
@ -1056,11 +1074,13 @@ function makeWS() {
if (ws) return;
ws = new WebSocket('ws://'+(loc?locip:window.location.hostname)+'/ws');
ws.onmessage = function(event) {
var json = JSON.parse(event.data);
if (json.leds) return; //liveview packet
clearTimeout(jsonTimeout);
jsonTimeout = null;
clearErrorToast();
gId('connind').style.backgroundColor = "#079";
var json = JSON.parse(event.data);
// json object should contain json.info AND json.state (but may not)
var info = json.info;
if (info) {
lastinfo = info;
@ -1164,7 +1184,7 @@ function readState(s,command=false)
var jsonTimeout;
var reqsLegal = false;
function requestJson(command, rinfo = true, verbose = true, callback = null)
function requestJson(command, rinfo = true)
{
gId('connind').style.backgroundColor = "#a90";
if (command && !reqsLegal) return; //stop post requests from chrome onchange event on page restore
@ -1173,15 +1193,18 @@ function requestJson(command, rinfo = true, verbose = true, callback = null)
var req = null;
var url = (loc?`http://${locip}`:'') + (rinfo ? '/json/si': (command ? '/json/state':'/json/si'));
var useWs = ((command || rinfo) && ws && ws.readyState === WebSocket.OPEN);
var type = command ? 'post':'get';
if (command)
{
command.v = verbose;
command.v = true; // force complete /json/si API response
command.time = Math.floor(Date.now() / 1000);
req = JSON.stringify(command);
if (req.length > 1000) useWs = false; //do not send very long requests over websocket
}
if ((command || rinfo) && ws && ws.readyState === WebSocket.OPEN) {
if (useWs) {
ws.send(req?req:'{"v":true}');
return;
}
@ -1203,20 +1226,15 @@ function requestJson(command, rinfo = true, verbose = true, callback = null)
clearErrorToast();
gId('connind').style.backgroundColor = "#070";
if (!json) { showToast('Empty response', true); return; }
if (json.success) {
if (callback) callback();
return;
}
if (json.success) return;
var s = json.state ? json.state : json;
readState(s);
reqsLegal = true;
reconnectWS();
if (callback) callback();
})
.catch(function (error) {
showToast(error, true);
console.log(error);
if (callback) callback();
});
}
@ -1225,7 +1243,7 @@ function togglePower()
isOn = !isOn;
var obj = {"on": isOn};
obj.transition = parseInt(gId('tt').value*10);
requestJson(obj, false, noWS);
requestJson(obj, false);
}
function toggleNl()
@ -1258,6 +1276,7 @@ function toggleLiveview()
var url = (loc?`http://${locip}`:'') + "/liveview";
gId('liveview').src = (isLv) ? url:"about:blank";
gId('buttonSr').className = (isLv) ? "active":"";
if (!isLv && ws && ws.readyState === WebSocket.OPEN) ws.send('{"lv":false}');
size();
}
@ -1598,7 +1617,7 @@ function setX(ind = null)
d.querySelector(`#fxlist .lstI[data-id="${ind}"]`).classList.add('selected');
var obj = {"seg": {"fx": parseInt(ind)}};
requestJson(obj, false, noWS);
requestJson(obj, false);
}
function setPalette(paletteId = null)
@ -1614,39 +1633,39 @@ function setPalette(paletteId = null)
}
d.querySelector(`#pallist .lstI[data-id="${paletteId}"]`).classList.add('selected');
var obj = {"seg": {"pal": paletteId}};
requestJson(obj, false, noWS);
requestJson(obj, false);
}
function setBri()
{
var obj = {"bri": parseInt(gId('sliderBri').value)};
obj.transition = parseInt(gId('tt').value*10);
requestJson(obj, false, noWS);
requestJson(obj, false);
}
function setSpeed()
{
var obj = {"seg": {"sx": parseInt(gId('sliderSpeed').value)}};
requestJson(obj, false, noWS);
requestJson(obj, false);
}
function setIntensity()
{
var obj = {"seg": {"ix": parseInt(gId('sliderIntensity').value)}};
requestJson(obj, false, noWS);
requestJson(obj, false);
}
function setLor(i)
{
var obj = {"lor": i};
requestJson(obj, false, noWS);
requestJson(obj, false);
}
function setPreset(i)
{
var obj = {"ps": i};
showToast("Loading preset " + pName(i) +" (" + i + ")");
requestJson(obj, false, noWS);
requestJson(obj, false);
}
function saveP(i,pl)
@ -1689,7 +1708,7 @@ function saveP(i,pl)
if (pQN.length > 0) obj.ql = pQN;
showToast("Saving " + pN +" (" + pI + ")");
requestJson(obj, false, noWS);
requestJson(obj, false);
if (obj.o) {
pJson[pI] = obj;
delete pJson[pI].psave;
@ -1716,18 +1735,18 @@ function testPl(i,bt) {
bt.innerHTML = "<i class='icons btn-icon'>&#xe38f;</i>Stop";
var obj = {};
obj.playlist = plJson[i];
requestJson(obj, false, noWS);
requestJson(obj, false);
}
function stopPl() {
requestJson({playlist:{}}, false, noWS)
requestJson({playlist:{}}, false)
}
function delP(i) {
var bt = gId(`p${i}del`);
if (bt.dataset.cnf == 1) {
var obj = {"pdel": i};
requestJson(obj, false, noWS);
requestJson(obj, false);
delete pJson[i];
populatePresets();
} else {
@ -1837,7 +1856,7 @@ function setColor(sr)
updateHex();
updateRgb();
obj.transition = parseInt(gId('tt').value*10);
requestJson(obj, false, noWS);
requestJson(obj, false);
}
var hc = 0;
@ -1875,7 +1894,7 @@ function rSegs()
requestJson(obj, false);
}
function loadPalettesData()
function loadPalettesData(callback = null)
{
if (palettesData) return;
const lsKey = "wledPalx";
@ -1885,6 +1904,8 @@ function loadPalettesData()
palettesDataJson = JSON.parse(palettesDataJson);
if (palettesDataJson && palettesDataJson.vid == lastinfo.vid) {
palettesData = palettesDataJson.p;
//redrawPalPrev() //?
if (callback) callback();
return;
}
} catch (e) {}
@ -1897,6 +1918,7 @@ function loadPalettesData()
vid: lastinfo.vid
}));
redrawPalPrev();
if (callback) setTimeout(callback, 99); //go on to connect websocket
});
}
@ -1922,7 +1944,6 @@ function getPalettesData(page, callback)
.catch(function(error) {
showToast(error, true);
console.log(error);
presetError(false);
});
}

View File

@ -21,18 +21,6 @@
<body>
<div id="canv" />
<script>
console.info("Live-Preview websocket opening");
var socket = new WebSocket("ws://"+document.location.host+"/ws");
socket.onopen = function () {
console.info("Live-Preview websocket is opened");
socket.send("{'lv':true,'rev':2}");
}
socket.onclose = function () { console.info("Live-Preview websocket is closing"); }
socket.onerror = function (event) { console.error("Live-Preview websocket error:", event); }
function updatePreview(leds) {
var str = "linear-gradient(90deg,";
var len = leds.length;
@ -46,7 +34,7 @@
document.getElementById("canv").style.background = str;
}
socket.onmessage = function (event) {
function getLiveJson(event) {
try {
var json = JSON.parse(event.data);
if (json && json.leds) {
@ -54,9 +42,23 @@
}
}
catch (err) {
console.error("Live-Preview websocket error:",err);
}
console.error("Live-Preview ws error:",err);
}
}
var ws = top.window.ws;
if (ws && ws.readyState === WebSocket.OPEN) {
console.info("Use top WS for peek");
ws.send("{'lv':true}");
} else {
console.info("Peek ws opening");
ws = new WebSocket("ws://"+document.location.host+"/ws");
ws.onopen = function () {
console.info("Peek WS opened");
ws.send("{'lv':true}");
}
}
ws.addEventListener('message',getLiveJson);
</script>
</body>
</html>

View File

@ -85,7 +85,7 @@ charset="utf-8"><meta name="theme-color" content="#222222"><title>
WLED Live Preview</title><style>
body{margin:0}#canv{background:#000;filter:brightness(175%);width:100%;height:100%;position:absolute}
</style></head><body><div id="canv"><script>
console.info("Live-Preview websocket opening");var socket=new WebSocket("ws://"+document.location.host+"/ws");function updatePreview(e){var o="linear-gradient(90deg,",n=e.length;for(i=0;i<n;i++){var r=e[i];r.length>6&&(r=r.substring(2)),o+="#"+r,i<n-1&&(o+=",")}o+=")",document.getElementById("canv").style.background=o}socket.onopen=function(){console.info("Live-Preview websocket is opened"),socket.send("{'lv':true,'rev':2}")},socket.onclose=function(){console.info("Live-Preview websocket is closing")},socket.onerror=function(e){console.error("Live-Preview websocket error:",e)},socket.onmessage=function(e){try{var o=JSON.parse(e.data);o&&o.leds&&requestAnimationFrame((function(){updatePreview(o.leds)}))}catch(e){console.error("Live-Preview websocket error:",e)}}
function updatePreview(e){var n="linear-gradient(90deg,",o=e.length;for(i=0;i<o;i++){var t=e[i];t.length>6&&(t=t.substring(2)),n+="#"+t,i<o-1&&(n+=",")}n+=")",document.getElementById("canv").style.background=n}function getLiveJson(e){try{var n=JSON.parse(e.data);n&&n.leds&&requestAnimationFrame((function(){updatePreview(n.leds)}))}catch(e){console.error("Live-Preview ws error:",e)}}var ws=top.window.ws;ws&&ws.readyState===WebSocket.OPEN?(console.info("Use top WS for peek"),ws.send("{'lv':true}")):(console.info("Peek ws opening"),(ws=new WebSocket("ws://"+document.location.host+"/ws")).onopen=function(){console.info("Peek WS opened"),ws.send("{'lv':true}")}),ws.addEventListener("message",getLiveJson)
</script></body></html>)=====";

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 2107072
#define VERSION 2107080
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG

View File

@ -16,7 +16,6 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
if(type == WS_EVT_CONNECT){
//client connected
sendDataWs(client);
//client->ping();
} else if(type == WS_EVT_DISCONNECT){
//client disconnected
if (client->id() == wsLiveClientId) wsLiveClientId = 0;
@ -24,7 +23,7 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
//data packet
AwsFrameInfo * info = (AwsFrameInfo*)arg;
if(info->final && info->index == 0 && info->len == len){
//the whole message is in a single frame and we got all of it's data (max. 1450byte)
//the whole message is in a single frame and we got all of its data (max. 1450byte)
if(info->opcode == WS_TEXT)
{
bool verboseResponse = false;
@ -42,10 +41,11 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
if (root.containsKey("lv"))
{
wsLiveClientId = root["lv"] ? client->id() : 0;
} else {
fileDoc = &jsonBuffer;
verboseResponse = deserializeState(root);
fileDoc = nullptr;
}
fileDoc = &jsonBuffer; // used for applying presets (presets.cpp)
verboseResponse = deserializeState(root);
fileDoc = nullptr;
}
//update if it takes longer than 300ms until next "broadcast"
if (verboseResponse && (millis() - lastInterfaceUpdate < 1700 || !interfaceUpdateCallMode)) sendDataWs(client);