Merge branch 'master' of https://github.com/aircoookie/WLED into dev

Conflicts:
	tools/cdata.js
	usermods/PIR_sensor_switch/readme.md
	usermods/Temperature/readme.md
	wled00/FX.h
	wled00/FX_fcn.cpp
	wled00/bus_manager.h
	wled00/bus_wrapper.h
	wled00/cfg.cpp
	wled00/const.h
	wled00/data/settings.htm
	wled00/data/settings_leds.htm
	wled00/data/settings_um.htm
	wled00/html_settings.h
	wled00/json.cpp
	wled00/mqtt.cpp
	wled00/set.cpp
	wled00/wled.cpp
	wled00/wled.h
	wled00/wled_eeprom.cpp
	wled00/wled_server.cpp
	wled00/xml.cpp
This commit is contained in:
Blaz Kristan 2021-05-18 15:45:34 +02:00
commit bfd7be543a
37 changed files with 1565 additions and 1271 deletions

View File

@ -2,6 +2,36 @@
### Builds after release 0.12.0
#### Build 2105171
- Always copy MQTT payloads to prevent non-0-terminated strings
- Updated ArduinoJson to 6.18.0
- Added experimental support for `{"on":"t"}` to toggle on/off state via JSON
#### Build 2105120
- Fixed possibility of non-0-terminated MQTT payloads
- Fixed two warnings regarding integer comparison
#### Build 2105112
- Usermod settings page no usermods message
- Lowered min speed for Drip effect
#### Build 2105111
- Fixed various Codacy code style and logic issues
#### Build 2105110
- Added Usermod settings page and configurable usermods (PR #1951)
- Added experimental `/json/cfg` endpoint for changing settings from JSON (see #1944, not part of official API)
#### Build 2105070
- Fixed not turning on after pressing "Off" on IR remote twice (#1950)
- Fixed OTA update file selection from Android app (TODO: file type verification in JS, since android can't deal with accept='.bin' attribute)
#### Build 2104220
- Version bump to 0.12.1-b1 "Hikari"

View File

@ -114,9 +114,6 @@ build_unflags =
# enables all features for travis CI
build_flags_all_features =
-D WLED_USE_ANALOG_LED
-D WLED_USE_H801
-D WLED_ENABLE_5CH_LEDS
-D WLED_ENABLE_ADALIGHT
-D WLED_ENABLE_DMX
-D WLED_ENABLE_MQTT
@ -289,7 +286,7 @@ platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m128k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -D WLED_USE_ANALOG_LEDS
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA
[env:esp8285_4CH_H801]
board = esp8285
@ -297,7 +294,7 @@ platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m128k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -D WLED_USE_ANALOG_LEDS -D WLED_USE_H801
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA
[env:esp8285_5CH_H801]
board = esp8285
@ -305,7 +302,7 @@ platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m128k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -D WLED_USE_ANALOG_LEDS -D WLED_USE_H801 -D WLED_ENABLE_5CH_LEDS
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA
[env:d1_mini_5CH_Shojo_PCB]
board = d1_mini
@ -313,7 +310,7 @@ platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_4m1m}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D WLED_USE_SHOJO_PCB -D WLED_ENABLE_5CH_LEDS
build_flags = ${common.build_flags_esp8266} -D WLED_USE_SHOJO_PCB
# ------------------------------------------------------------------------------
# DEVELOPMENT BOARDS
@ -405,6 +402,7 @@ build_flags = ${common.build_flags_esp32} ${common.debug_flags} ${common.build_f
# ------------------------------------------------------------------------------
# codm pixel controller board configurations
# codm-controller-0.6 can also be used for the TYWE3S controller
# ------------------------------------------------------------------------------
[env:codm-controller-0.6]

View File

@ -39,12 +39,8 @@ build_flags = ${common.build_flags_esp8266}
; PIN defines for 2 wire LEDs
-D CLKPIN=0
-D DATAPIN=2
; to drive analog LED strips (aka 5050), uncomment the following
; PWM pins 5,12,13,15 are used with Magic Home LED Controller (default)
-D WLED_USE_ANALOG_LEDS
; for the H801 controller (PINs 15,13,12,14 (W2 = 04)) uncomment this
; -D WLED_USE_H801
; for the BW-LT11 controller (PINs 12,4,14,5 ) uncomment this
; -D WLED_USE_BWLT11
; and to enable channel 5 for RGBW-CT led strips this
; -D WLED_USE_5CH_LEDS
; to drive analog LED strips (aka 5050) hardware configuration is no longer necessary
; configure the settings in the UI as follows (hard):
; for the Magic Home LED Controller use PWM pins 5,12,13,15
; for the H801 controller use PINs 15,13,12,14 (W2 = 04)
; for the BW-LT11 controller use PINs 12,4,14,5

View File

@ -344,6 +344,10 @@ const char PAGE_settings_dmx[] PROGMEM = R"=====()=====";
str
.replace(/\<link rel="stylesheet".*\>/gms, "")
.replace(/\<style\>.*\<\/style\>/gms, "%CSS%%SCSS%")
.replace(
/function GetV().*\<\/script\>/gms,
"function GetV() {var d=document;\n"
),
}
],
"wled00/html_settings.h"

232
tools/fps_test.htm Normal file
View File

@ -0,0 +1,232 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>WLED frame rate test tool</title>
<style>
body {
background-color: #222;
color: #fff;
font-family: Helvetica, Verdana, sans-serif;
}
input {
background-color: #333;
color: #fff;
}
#ip {
width: 100px;
}
#secs {
width: 36px;
}
#csva {
position: absolute;
top: -100px; /*gtfo*/
}
button {
background-color: #333;
color: #fff;
}
table, th, td {
border: 1px solid #aaa;
border-collapse: collapse;
text-align: center;
}
.red {
color: #d20;
}
</style>
<script>
var gotfx = false, running = false;
var pos = 0, prev = 0, min = 999, max = 0, fpslist = [], names = [], names_checked = [];
var to;
function S() {
document.getElementById('ip').value = localStorage.getItem('locIpFps');
if (document.getElementById('ip').value) req(false);
}
function loadC() {
hide(false);
var list = localStorage.getItem('fpsFxSelection');
if (!list) return;
list = JSON.parse(list);
var chks = document.querySelectorAll('.fxcheck');
for (let i = 0; i < chks.length; i++) {
if (i < list.length) chks[i].checked = list[i];
}
}
function saveC() {
var list = [];
var chks = document.querySelectorAll('.fxcheck');
for (let i = 0; i < chks.length; i++) {
list.push(chks[i].checked);
}
localStorage.setItem('fpsFxSelection', JSON.stringify(list));
}
function setC(c) {
hide(false);
var chks = document.querySelectorAll('.fxcheck');
for (let i = 0; i < chks.length; i++) {
chks[i].checked = (c == 255);
}
if (c == 1 && chks.length > 100) {
chks[1].checked = true; //Blink
chks[15].checked = true; //Running
chks[16].checked = true; //Saw
chks[37].checked = true; //Running 2
chks[44].checked = true; //Tetrix
chks[63].checked = true; //Pride 2015
chks[74].checked = true; //Colortwinkles
chks[101].checked = true;//Pacifica
}
}
function hide(h) {
var trs = document.querySelectorAll('.trs');
var chks = document.querySelectorAll('.fxcheck');
for (let i = 0; i < trs.length; i++) {
trs[i].style.display = (h && !chks[i].checked) ? "none":"table-row";
}
}
function run(init) {
if (init) {
running = !running;
document.getElementById('runbtn').innerText = running ? 'Stop':'Run';
if (running) {pos = 0; prev = -1; min = 999; max = 0; fpslist = []; names_checked = []; hide(true);}
clearTimeout(to);
if (!running) {req({seg:{fx:0},v:true,stop:true}); return;}
}
if (!gotfx) {req(false); return;}
var chks = document.querySelectorAll('.fxcheck');
var fpsb = document.querySelectorAll('.fps');
if (prev >= 0) {pos++};
if (pos >= chks.length) {run(true); return;} //end
while (!chks[pos].checked) {
fpsb[pos].innerText = "-";
pos++;
if (pos >= chks.length) {run(true); return;} //end
}
names_checked.push(names[pos]);
var extra = {};
try {
extra = JSON.parse(document.getElementById('ej').value);
} catch (e) {
}
var cmd = {seg:{fx:pos},v:true};
Object.assign(cmd, extra);
req(cmd);
}
function req(command) {
var ip = document.getElementById('ip').value;
if (!ip) {alert("Please enter WLED IP"); return;}
if (ip != localStorage.getItem('locIpFps')) localStorage.setItem('locIpFps', document.getElementById('ip').value);
var url = command ? `http://${ip}/json/si` : `http://${ip}/json/effects`;
var type = command ? 'post':'get';
var req = undefined;
if (command)
{
req = JSON.stringify(command);
}
fetch
(url, {
method: type,
headers: {
"Content-type": "application/json; charset=UTF-8"
},
body: req
})
.then(res => {
if (!res.ok) {
alert('Data malfunction');
}
return res.json();
})
.then(json => {
if (!json) {
alert('Empty response'); return;
}
if (!command) {
names = json;
var tblc = '';
for (let i = 0; i < json.length; i++) {
tblc += `<tr class="trs"><td><input type="checkbox" class="fxcheck" /></td><td>${i}</td><td>${json[i]}</td><td class="fps"></td></tr>`
}
var tbl = `<table>
<tr>
<th>Test?</th><th>ID</th><th>Effect Name</th><th>FPS</th>
</tr>
${tblc}
</table>`;
document.getElementById('tablecon').innerHTML = tbl;
setC(1);
loadC();
gotfx = true;
document.getElementById('runbtn').innerText = "Run";
} else {
if (!json.info) return;
document.getElementById('leds').innerText = json.info.leds.count;
document.getElementById('seg').innerText = json.state.seg[0].len;
document.getElementById('bri').innerText = json.state.bri;
if (prev >= 0) {
var lastfps = parseInt(json.info.leds.fps); //previous FX
if (lastfps < min) min = lastfps;
if (lastfps > max) max = lastfps;
fpslist.push(lastfps);
var sum = 0;
for (let i = 0; i < fpslist.length; i++) {
sum += fpslist[i];
}
sum /= fpslist.length;
document.getElementById('fps_min').innerText = min;
document.getElementById('fps_max').innerText = max;
document.getElementById('fps_avg').innerText = Math.round(sum*10)/10;
var fpsb = document.querySelectorAll('.fps');
fpsb[prev].innerHTML = lastfps;
}
prev = pos;
var delay = parseInt(document.getElementById('secs').value)*1000;
delay = Math.min(Math.max(delay, 2000), 15000)
if (!command.stop) to = setTimeout(run,delay);
}
})
.catch(function (error) {
alert('Comms malfunction');
console.log(error);
});
}
function csv(n) {
var txt = "";
for (let i = 0; i < fpslist.length; i++) {
if (!n) txt += names_checked[i] + ',';
txt += fpslist[i]; txt += "\n";
}
document.getElementById('csva').value = txt;
var copyText = document.getElementById('csva');
copyText.select();
copyText.setSelectionRange(0, 999999);
document.execCommand("copy");
}
</script>
</head>
<body onload="S()">
<h2>Starship monitoring dashboard</h2>
(or rather just a WLED frame rate tester lol)<br><br>
IP: <input id="ip" /><br>
Time per effect: <input type=number id=secs value=5 max=15 min=2 />s<br>
Effects to test:
<button type="button" onclick="setC(255)">All</button>
<button type="button" onclick="setC(1)">Selection 1</button>
<button type="button" onclick="setC(0)">None</button>
<button type="button" onclick="loadC()">Get LS</button>
<button type="button" class="red" onclick="saveC()">Save to LS</button><br>
Extra JSON: <input id="ej" /><br>
<button type="button" onclick="run(true)" id="runbtn">Fetch FX list</button><br>
LEDs: <span id="leds">-</span>, Seg: <span id="seg">-</span>, Bri: <span id="bri">-</span><br>
FPS min: <span id="fps_min">-</span>, max: <span id="fps_max">-</span>, avg: <span id="fps_avg">-</span><br><br>
<div id="tablecon">
</div><br>
<button type="button" onclick="csv(false)">Copy csv to clipboard</button>
<button type="button" onclick="csv(true)">Copy csv (FPS only)</button>
<textarea id=csva></textarea>
</body>
</html>

View File

@ -9,9 +9,7 @@ The LED strip is switched [using a relay](https://github.com/Aircoookie/WLED/wik
## Webinterface
The info page in the web interface shows the items below
- the remaining time of the off timer.
**I recommend to deactivate the sensor before an OTA update and activate it again afterwards**.
The info page in the web interface shows the remaining time of the off timer.
## Sensor connection
@ -63,7 +61,10 @@ void registerUsermods()
## API to enable/disable the PIR sensor from outside. For example from another usermod.
To query or change the PIR sensor state the methods `bool PIRsensorEnabled()` and `void EnablePIRsensor(bool enable)` are available.
To query or change the PIR sensor state the methods `bool PIRsensorEnabled()` and `void EnablePIRsensor(bool enable)` are available.
When the PIR sensor state changes an MQTT message is broadcasted with topic `wled/deviceMAC/motion` and message `on` or `off`.
Usermod can also be configured to just send MQTT message and not change WLED state using settings page as well as responding to motion only during nighttime (assuming NTP and lattitude/longitude are set to determine sunrise/sunset times).
### There are two options to get access to the usermod instance:

View File

@ -3,7 +3,7 @@
Based on the excellent `QuinLED_Dig_Uno_Temp_MQTT` by srg74 and 400killer!
This usermod will read from an attached DS18B20 temperature sensor (as available on the QuinLED Dig-Uno)
The temperature is displayed both in the Info section of the web UI as well as published to the `/temperature` MQTT topic if enabled.
This usermod will be expanded with support for different sensor types in the future.
This usermod may be expanded with support for different sensor types in the future.
If temperature sensor is not detected during boot, this usermod will be disabled.
@ -16,18 +16,19 @@ Copy the example `platformio_override.ini` to the root directory. This file sho
* `USERMOD_DALLASTEMPERATURE` - define this to have this user mod included wled00\usermods_list.cpp
* `USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT` - the number of milliseconds after boot to take first measurement, defaults to 20 seconds
All parameters can be configured at runtime using Usermods settings page.
All parameters can be configured at runtime using Usermods settings page, including pin, selection to display temerature in degrees Celsius or Farenheit mand measurement interval.
## Project link
* [QuinLED-Dig-Uno](https://quinled.info/2018/09/15/quinled-dig-uno/) - Project link
* [Srg74-WLED-Wemos-shield](https://github.com/srg74/WLED-wemos-shield) - another great DIY WLED board
### PlatformIO requirements
If you are using `platformio_override.ini`, you should be able to refresh the task list and see your custom task, for example `env:d1_mini_usermod_dallas_temperature_C`.
If you are not using `platformio_override.ini`, you might have to uncomment `DallasTemperature@~3.8.0`,`OneWire@~2.3.5 under` `[common]` section in `platformio.ini`:
If you are not using `platformio_override.ini`, you might have to uncomment `OneWire@~2.3.5 under` `[common]` section in `platformio.ini`:
```ini
# platformio.ini
@ -41,8 +42,7 @@ default_envs = d1_mini
...
lib_deps =
...
#For Dallas sensor uncomment following 2 lines
DallasTemperature@~3.8.0
#For Dallas sensor uncomment following line
OneWire@~2.3.5
...
```

Binary file not shown.

View File

@ -34,7 +34,7 @@
*/
uint16_t WS2812FX::mode_static(void) {
fill(SEGCOLOR(0));
return (SEGMENT.getOption(SEG_OPTION_TRANSITIONAL)) ? FRAMETIME : 380; //update faster if in transition
return (SEGMENT.getOption(SEG_OPTION_TRANSITIONAL)) ? FRAMETIME : 350; //update faster if in transition
}
@ -1436,8 +1436,8 @@ uint16_t WS2812FX::mode_tricolor_fade(void)
}
byte stp = prog; // % 256
uint32_t color = 0;
for(uint16_t i = 0; i < SEGLEN; i++) {
uint32_t color;
if (stage == 2) {
color = color_blend(color_from_palette(i, true, PALETTE_SOLID_WRAP, 2), color2, stp);
} else if (stage == 1) {
@ -3050,7 +3050,7 @@ uint16_t WS2812FX::mode_drip(void)
numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3
float gravity = -0.001 - (SEGMENT.speed/50000.0);
float gravity = -0.0005 - (SEGMENT.speed/50000.0);
gravity *= SEGLEN;
int sourcedrop = 12;

View File

@ -612,6 +612,7 @@ class WS2812FX {
bool
isRgbw = false,
isOffRefreshRequred = false, //periodic refresh is required for the strip to remain off.
gammaCorrectBri = false,
gammaCorrectCol = true,
applyToAllSelected = true,

View File

@ -1,124 +0,0 @@
/*
Editor: https://www.visualmicro.com/
This file is for intellisense purpose only.
Visual micro (and the arduino ide) ignore this code during compilation. This code is automatically maintained by visualmicro, manual changes to this file will be overwritten
The contents of the _vm sub folder can be deleted prior to publishing a project
All non-arduino files created by visual micro and all visual studio project or solution files can be freely deleted and are not required to compile a sketch (do not delete your own code!).
Note: debugger breakpoints are stored in '.sln' or '.asln' files, knowledge of last uploaded breakpoints is stored in the upload.vmps.xml file. Both files are required to continue a previous debug session without needing to compile and upload again
Hardware: ESP32 Dev Module, Platform=esp32, Package=esp32
*/
#if defined(_VMICRO_INTELLISENSE)
#ifndef _VSARDUINO_H_
#define _VSARDUINO_H_
#define __ESP32_esp32__
#define __ESP32_ESP32__
#define ESP_PLATFORM
#define HAVE_CONFIG_H
#define GCC_NOT_5_2_0 0
#define WITH_POSIX
#define F_CPU 240000000L
#define ARDUINO 108011
#define ARDUINO_ESP32_DEV
#define ARDUINO_ARCH_ESP32
#define ESP32
#define CORE_DEBUG_LEVEL 0
#define __cplusplus 201103L
#define _Pragma(x)
#undef __cplusplus
#define __cplusplus 201103L
#define __STDC__
#define __ARM__
#define __arm__
#define __inline__
#define __asm__(...)
#define __extension__
#define __ATTR_PURE__
#define __ATTR_CONST__
#define __volatile__
#define __ASM
#define __INLINE
#define __attribute__(noinline)
//#define _STD_BEGIN
//#define EMIT
#define WARNING
#define _Lockit
#define __CLR_OR_THIS_CALL
#define C4005
#define _NEW
typedef bool _Bool;
typedef int _read;
typedef int _seek;
typedef int _write;
typedef int _close;
typedef int __cleanup;
//#define inline
#define __builtin_clz
#define __builtin_clzl
#define __builtin_clzll
#define __builtin_labs
#define __builtin_va_list
typedef int __gnuc_va_list;
#define __ATOMIC_ACQ_REL
#define __CHAR_BIT__
#define _EXFUN()
typedef unsigned char byte;
extern "C" void __cxa_pure_virtual() {;}
typedef long __INTPTR_TYPE__ ;
typedef long __UINTPTR_TYPE__ ;
typedef long __SIZE_TYPE__ ;
typedef long __PTRDIFF_TYPE__;
typedef long pthread_t;
typedef long pthread_key_t;
typedef long pthread_once_t;
typedef long pthread_mutex_t;
typedef long pthread_mutex_t;
typedef long pthread_cond_t;
#include "arduino.h"
#include <pins_arduino.h>
#define interrupts() sei()
#define noInterrupts() cli()
#define ESP_LOGI(tag, ...)
#include "wled00.ino"
#include "wled01_eeprom.ino"
#include "wled02_xml.ino"
#include "wled03_set.ino"
#include "wled04_file.ino"
#include "wled05_init.ino"
#include "wled06_usermod.ino"
#include "wled07_notify.ino"
#include "wled08_led.ino"
#include "wled09_button.ino"
#include "wled10_ntp.ino"
#include "wled11_ol.ino"
#include "wled12_alexa.ino"
#include "wled13_cronixie.ino"
#include "wled14_colors.ino"
#include "wled15_hue.ino"
#include "wled16_blynk.ino"
#include "wled17_mqtt.ino"
#include "wled18_server.ino"
#include "wled19_json.ino"
#include "wled20_ir.ino"
#endif
#endif

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -63,7 +63,7 @@ class Bus {
return _start;
}
void setStart(uint16_t start) {
inline void setStart(uint16_t start) {
_start = start;
}
@ -81,7 +81,7 @@ class Bus {
return false;
}
virtual uint8_t skipFirstLed() {
virtual uint8_t skippedLeds() {
return 0;
}
@ -184,10 +184,10 @@ class BusDigital : public Bus {
}
inline bool isRgbw() {
return _rgbw;
return (_rgbw || _type == TYPE_SK6812_RGBW || _type == TYPE_TM1814);
}
inline uint8_t skipFirstLed() {
inline uint8_t skippedLeds() {
return _skip;
}
@ -451,6 +451,11 @@ class BusManager {
return Bus::isRgbw(type);
}
//Return true if the strip requires a refresh to stay off.
static bool isOffRefreshRequred(uint8_t type) {
return type == TYPE_TM1814;
}
private:
uint8_t numBusses = 0;
Bus* busses[WLED_MAX_BUSSES];

View File

@ -12,24 +12,7 @@ void getStringFromJson(char* dest, const char* src, size_t len) {
if (src != nullptr) strlcpy(dest, src, len);
}
void deserializeConfig() {
bool fromeep = false;
bool success = deserializeConfigSec();
if (!success) { //if file does not exist, try reading from EEPROM
deEEPSettings();
fromeep = true;
}
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DEBUG_PRINTLN(F("Reading settings from /cfg.json..."));
success = readObjectFromFile("/cfg.json", nullptr, &doc);
if (!success) { //if file does not exist, try reading from EEPROM
if (!fromeep) deEEPSettings();
return;
}
bool deserializeConfig(JsonObject doc, bool fromFS) {
//int rev_major = doc["rev"][0]; // 1
//int rev_minor = doc["rev"][1]; // 0
@ -103,52 +86,61 @@ void deserializeConfig() {
CJSON(strip.rgbwMode, hw_led[F("rgbwm")]);
JsonArray ins = hw_led["ins"];
uint8_t s = 0; // bus iterator
strip.isRgbw = false;
busses.removeAll();
uint32_t mem = 0;
for (JsonObject elm : ins) {
if (s >= WLED_MAX_BUSSES) break;
uint8_t pins[5] = {255, 255, 255, 255, 255};
JsonArray pinArr = elm["pin"];
if (pinArr.size() == 0) continue;
uint8_t i = 0;
for (int p : pinArr) {
pins[i++] = p;
if (i>4) break;
}
uint16_t length = elm[F("len")];
if (length==0 || length+lC > MAX_LEDS) continue; // zero length or we reached max. number of LEDs, just stop
uint16_t start = elm[F("start")] | 0;
if (start >= lC+length) continue; // something is very wrong :)
uint8_t colorOrder = elm[F("order")];
uint8_t skipFirst = elm[F("skip")];
uint8_t ledType = elm["type"] | TYPE_WS2812_RGB;
bool reversed = elm["rev"];
//RGBW mode is enabled if at least one of the strips is RGBW
// if ((bool)elm[F("rgbw")]) SET_BIT(ledType,7); else UNSET_BIT(ledType,7); // hack bit 7 to indicate RGBW (as an override if necessary)
// strip.isRgbw |= (bool)elm[F("rgbw")];
strip.isRgbw = (strip.isRgbw || Bus::isRgbw(ledType));
s++;
lC += length;
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst);
mem += BusManager::memUsage(bc);
DEBUG_PRINT(F(" Adding bus no. "));
DEBUG_PRINTLN(busses.getNumBusses());
if (mem <= MAX_LED_MEMORY && busses.getNumBusses() <= WLED_MAX_BUSSES) busses.add(bc); // finalization will be done in WLED::beginStrip()
if (fromFS || !ins.isNull()) {
uint8_t s = 0; // bus iterator
strip.isRgbw = false;
busses.removeAll();
uint32_t mem = 0;
for (JsonObject elm : ins) {
if (s >= WLED_MAX_BUSSES) break;
uint8_t pins[5] = {255, 255, 255, 255, 255};
JsonArray pinArr = elm["pin"];
if (pinArr.size() == 0) continue;
pins[0] = pinArr[0];
uint8_t i = 0;
for (int p : pinArr) {
pins[i++] = p;
if (i>4) break;
}
uint16_t length = elm[F("len")];
if (length==0 || length+lC > MAX_LEDS) continue; // zero length or we reached max. number of LEDs, just stop
uint16_t start = elm[F("start")] | 0;
if (start >= lC+length) continue; // something is very wrong :)
uint8_t colorOrder = elm[F("order")];
uint8_t skipFirst = elm[F("skip")];
uint8_t ledType = elm["type"] | TYPE_WS2812_RGB;
bool reversed = elm["rev"];
//RGBW mode is enabled if at least one of the strips is RGBW
// if ((bool)elm[F("rgbw")]) SET_BIT(ledType,7); else UNSET_BIT(ledType,7); // hack bit 7 to indicate RGBW (as an override if necessary)
// strip.isRgbw |= (bool)elm[F("rgbw")];
strip.isRgbw = (strip.isRgbw || BusManager::isRgbw(ledType));
//refresh is required to remain off if at least one of the strips requires the refresh.
strip.isOffRefreshRequred |= BusManager::isOffRefreshRequred(ledType);
s++;
lC += length;
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst);
mem += BusManager::memUsage(bc);
DEBUG_PRINT(F(" Adding bus no. "));
DEBUG_PRINTLN(busses.getNumBusses());
if (mem <= MAX_LED_MEMORY && busses.getNumBusses() <= WLED_MAX_BUSSES) busses.add(bc); // finalization will be done in WLED::beginStrip()
}
//strip.finalizeInit();
}
if (lC > ledCount) ledCount = lC; // fix incorrect total length (honour analog setup)
DEBUG_PRINTLN(F(" Done LEDs."));
JsonObject hw_btn_ins_0 = hw[F("btn")][F("ins")][0];
CJSON(buttonType, hw_btn_ins_0["type"]);
int hw_btn_pin = hw_btn_ins_0["pin"][0];
if (pinManager.allocatePin(hw_btn_pin,false)) {
btnPin = hw_btn_pin;
pinMode(btnPin, INPUT_PULLUP);
} else {
btnPin = -1;
int hw_btn_pin = hw_btn_ins_0[F("pin")][0] | -2; //-2 = not present in doc, keep current. -1 = disable
if (hw_btn_pin > -2) {
if (pinManager.allocatePin(hw_btn_pin,false)) {
btnPin = hw_btn_pin;
pinMode(btnPin, INPUT_PULLUP);
} else {
btnPin = -1;
}
}
JsonArray hw_btn_ins_0_macros = hw_btn_ins_0[F("macros")];
@ -156,25 +148,27 @@ void deserializeConfig() {
CJSON(macroLongPress,hw_btn_ins_0_macros[1]);
CJSON(macroDoublePress, hw_btn_ins_0_macros[2]);
//int hw_btn_ins_0_type = hw_btn_ins_0["type"]; // 0
#ifndef WLED_DISABLE_INFRARED
int hw_ir_pin = hw["ir"]["pin"] | -1; // 4
if (pinManager.allocatePin(hw_ir_pin,false)) {
irPin = hw_ir_pin;
} else {
irPin = -1;
int hw_ir_pin = hw["ir"]["pin"] | -2; // 4
if (hw_ir_pin > -2) {
if (pinManager.allocatePin(hw_ir_pin,false)) {
irPin = hw_ir_pin;
} else {
irPin = -1;
}
}
#endif
CJSON(irEnabled, hw["ir"]["type"]);
JsonObject relay = hw[F("relay")];
int hw_relay_pin = relay["pin"] | -1;
if (hw_relay_pin>=0 && pinManager.allocatePin(hw_relay_pin,true)) {
rlyPin = hw_relay_pin;
pinMode(rlyPin, OUTPUT);
} else {
rlyPin = -1;
int hw_relay_pin = relay["pin"] | -2;
if (hw_relay_pin > -2) {
if (pinManager.allocatePin(hw_relay_pin,true)) {
rlyPin = hw_relay_pin;
pinMode(rlyPin, OUTPUT);
} else {
rlyPin = -1;
}
}
if (relay.containsKey("rev")) {
rlyMde = !relay["rev"];
@ -202,8 +196,9 @@ void deserializeConfig() {
JsonObject light_nl = light["nl"];
CJSON(nightlightMode, light_nl[F("mode")]);
CJSON(nightlightDelayMinsDefault, light_nl["dur"]);
nightlightDelayMins = nightlightDelayMinsDefault;
byte prev = nightlightDelayMinsDefault;
CJSON(nightlightDelayMinsDefault, light_nl[F("dur")]);
if (nightlightDelayMinsDefault != prev) nightlightDelayMins = nightlightDelayMinsDefault;
CJSON(nightlightTargetBri, light_nl[F("tbri")]);
CJSON(macroNl, light_nl[F("macro")]);
@ -231,12 +226,14 @@ void deserializeConfig() {
JsonObject if_sync_recv = if_sync["recv"];
CJSON(receiveNotificationBrightness, if_sync_recv["bri"]);
CJSON(receiveNotificationColor, if_sync_recv["col"]);
CJSON(receiveNotificationEffects, if_sync_recv["fx"]);
CJSON(receiveNotificationEffects, if_sync_recv[F("fx")]);
//! following line might be a problem if called after boot
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
JsonObject if_sync_send = if_sync["send"];
prev = notifyDirectDefault;
CJSON(notifyDirectDefault, if_sync_send[F("dir")]);
notifyDirect = notifyDirectDefault;
if (notifyDirectDefault != prev) notifyDirect = notifyDirectDefault;
CJSON(notifyButton, if_sync_send[F("btn")]);
CJSON(notifyAlexa, if_sync_send[F("va")]);
CJSON(notifyHue, if_sync_send[F("hue")]);
@ -321,9 +318,10 @@ void deserializeConfig() {
CJSON(latitude, if_ntp[F("lt")]);
JsonObject ol = doc[F("ol")];
prev = overlayDefault;
CJSON(overlayDefault ,ol[F("clock")]); // 0
CJSON(countdownMode, ol[F("cntdwn")]);
overlayCurrent = overlayDefault;
if (prev != overlayDefault) overlayCurrent = overlayDefault;
CJSON(overlayMin, ol["min"]);
CJSON(overlayMax, ol[F("max")]);
@ -398,7 +396,32 @@ void deserializeConfig() {
DEBUG_PRINTLN(F("Starting usermod config."));
JsonObject usermods_settings = doc["um"];
usermods.readFromConfig(usermods_settings);
if (!usermods_settings.isNull()) usermods.readFromConfig(usermods_settings);
if (fromFS) return false;
doReboot = doc[F("rb")] | doReboot;
return (doc["sv"] | true);
}
void deserializeConfigFromFS() {
bool fromeep = false;
bool success = deserializeConfigSec();
if (!success) { //if file does not exist, try reading from EEPROM
deEEPSettings();
fromeep = true;
}
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DEBUG_PRINTLN(F("Reading settings from /cfg.json..."));
success = readObjectFromFile("/cfg.json", nullptr, &doc);
if (!success) { //if file does not exist, try reading from EEPROM
if (!fromeep) deEEPSettings();
return;
}
deserializeConfig(doc.as<JsonObject>(), true);
}
void serializeConfig() {
@ -480,8 +503,8 @@ void serializeConfig() {
uint8_t nPins = bus->getPins(pins);
for (uint8_t i = 0; i < nPins; i++) ins_pin.add(pins[i]);
ins[F("order")] = bus->getColorOrder();
ins["rev"] = bus->reversed;
ins[F("skip")] = bus->skipFirstLed();
ins["rev"] = bus->reversed;
ins[F("skip")] = bus->skippedLeds();
ins["type"] = bus->getType();
ins[F("rgbw")] = bus->isRgbw();
}

View File

@ -10,18 +10,18 @@
margin: 0;
}
html {
--h: 10.55vh;
--h: 10.2vh;
}
button {
background: #333;
color: #fff;
font-family: Verdana, Helvetica, sans-serif;
border: 0.3ch solid #333;
display: inline-block;
border: 1px solid #333;
font-size: 6vmin;
height: var(--h);
width: 95%;
margin-top: 2.4vh;
margin-top: 2vh;
}
</style>
<script>

View File

@ -181,9 +181,7 @@
}
}
function GetV()
{
}
function GetV(){var d=document;}
</script>
<style>
@import url("style.css");

View File

@ -3,14 +3,15 @@
<head lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=500">
<title>UI Settings</title>
<title>Usermod Settings</title>
<script>
var d = document;
var umCfg = {};
var pins = [6,7,8,9,10,11];
var pinO = ["reserved","reserved","reserved","reserved","reserved","reserved"], owner;
var pinO = ["rsvd","rsvd","rsvd","rsvd","rsvd","rsvd"], owner;
var loc = false, locip;
var urows;
var numM = 0;
function gId(s) { return d.getElementById(s); }
function isO(i) { return (i && typeof i === 'object' && !Array.isArray(i)); }
function H() { window.open("https://github.com/Aircoookie/WLED/wiki/Settings#usermod-settings"); }
@ -24,7 +25,9 @@
localStorage.setItem('locIp', locip);
}
}
ldS();
GetV();
if (numM > 0 || locip) ldS();
else gId("um").innerHTML = "No Usermods installed.";
}
function check(o,k) {
var n = o.name.replace("[]","").substr(-3);
@ -99,11 +102,8 @@
urows += `<hr><h3>${k}</h3>`;
addField(k,'unknown',o);
}
if (urows==="")
urows = "No Usermods configuration found.<br>Press <i>Save</i> to initialize defaults if usermods were compiled in.";
} else {
urows = "Usermods configuration not found.<br>Most likely no Usermods exist.<br>Press <i>Save</i> to try to initialize defaults.";
}
if (urows==="") urows = "Usermods configuration not found.<br>Press <i>Save</i> to initialize defaults.";
gId("um").innerHTML = urows;
})
.catch(function (error) {

View File

@ -43,7 +43,7 @@
Installed version: ##VERSION##<br>
Download the latest binary: <a href="https://github.com/Aircoookie/WLED/releases" target="_blank">
<img src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a><br>
<input type='file' class="bt" name='update' accept=".bin" required><br>
<input type='file' class="bt" name='update' required><br> <!--should have accept='.bin', but it prevents file upload from android app-->
<input type='submit' class="bt" value='Update!' ><br>
<button type="button" class="bt" onclick="B()">Back</button></form>
<div id="msg"><b>Updating...</b><br>Please do not close or refresh the page :)</div>

View File

@ -26,7 +26,8 @@ void handleButton();
void handleIO();
//cfg.cpp
void deserializeConfig();
bool deserializeConfig(JsonObject doc, bool fromFS = false);
void deserializeConfigFromFS();
bool deserializeConfigSec();
void serializeConfig();
void serializeConfigSec();

View File

@ -55,13 +55,12 @@ bool bufferedFind(const char *target, bool fromStart = true) {
size_t targetLen = strlen(target);
size_t index = 0;
uint16_t bufsize = 0, count = 0;
byte buf[FS_BUFSIZE];
if (fromStart) f.seek(0);
while (f.position() < f.size() -1) {
bufsize = f.read(buf, FS_BUFSIZE);
count = 0;
uint16_t bufsize = f.read(buf, FS_BUFSIZE);
uint16_t count = 0;
while (count < bufsize) {
if(buf[count] != target[index])
index = 0; // reset index if any char does not match
@ -97,13 +96,12 @@ bool bufferedFindSpace(uint16_t targetLen, bool fromStart = true) {
if (!f || !f.size()) return false;
uint16_t index = 0;
uint16_t bufsize = 0, count = 0;
byte buf[FS_BUFSIZE];
if (fromStart) f.seek(0);
while (f.position() < f.size() -1) {
bufsize = f.read(buf, FS_BUFSIZE);
count = 0;
uint16_t bufsize = f.read(buf, FS_BUFSIZE);
uint16_t count = 0;
while (count < bufsize) {
if(buf[count] == ' ') {
@ -140,13 +138,12 @@ bool bufferedFindObjectEnd() {
if (!f || !f.size()) return false;
uint16_t objDepth = 0; //num of '{' minus num of '}'. return once 0
uint16_t bufsize = 0, count = 0;
//size_t start = f.position();
byte buf[FS_BUFSIZE];
while (f.position() < f.size() -1) {
bufsize = f.read(buf, FS_BUFSIZE);
count = 0;
uint16_t bufsize = f.read(buf, FS_BUFSIZE);
uint16_t count = 0;
while (count < bufsize) {
if (buf[count] == '{') objDepth++;

View File

@ -45,10 +45,10 @@ action="/update" id="uf" enctype="multipart/form-data" onsubmit="U()">
Installed version: 0.12.2-bl3<br>Download the latest binary: <a
href="https://github.com/Aircoookie/WLED/releases" target="_blank"><img
src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square">
</a><br><input type="file" class="bt" name="update" accept=".bin" required><br>
<input type="submit" class="bt" value="Update!"><br><button type="button"
class="bt" onclick="B()">Back</button></form><div id="msg"><b>Updating...</b>
<br>Please do not close or refresh the page :)</div></body></html>)=====";
</a><br><input type="file" class="bt" name="update" required><br><input
type="submit" class="bt" value="Update!"><br><button type="button" class="bt"
onclick="B()">Back</button></form><div id="msg"><b>Updating...</b><br>
Please do not close or refresh the page :)</div></body></html>)=====";
// Autogenerated from wled00/data/welcome.htm, do not edit!!

View File

@ -12,7 +12,7 @@ const char PAGE_settingsCss[] PROGMEM = R"=====(<style>body{font-family:Verdana,
// Autogenerated from wled00/data/settings.htm, do not edit!!
const char PAGE_settings[] PROGMEM = R"=====(<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>WLED Settings
</title><style>
body{text-align:center;background:#222;height:100px;margin:0}html{--h:10.55vh}button{background:#333;color:#fff;font-family:Verdana,Helvetica,sans-serif;border:.3ch solid #333;display:inline-block;font-size:6vmin;height:var(--h);width:95%%;margin-top:2.4vh}
body{text-align:center;background:#222;height:100px;margin:0}html{--h:10.2vh}button{background:#333;color:#fff;font-family:Verdana,Helvetica,sans-serif;display:inline-block;border:1px solid #333;font-size:6vmin;height:var(--h);width:95%%;margin-top:2vh}
</style><script>
function BB(){window.frameElement&&(document.getElementById("b").style.display="none",document.documentElement.style.setProperty("--h","13.86vh"))}
</script></head><body onload="BB()"><form action="/"><button type="submit"
@ -395,9 +395,9 @@ type="submit">Save & Reboot</button></form></body></html>)=====";
// Autogenerated from wled00/data/settings_um.htm, do not edit!!
const char PAGE_settings_um[] PROGMEM = R"=====(<!DOCTYPE html><html><head lang="en"><meta charset="utf-8"><meta
name="viewport" content="width=500"><title>UI Settings</title><script>
var owner,locip,urows,d=document,umCfg={},pins=[6,7,8,9,10,11],pinO=["reserved","reserved","reserved","reserved","reserved","reserved"],loc=!1;function gId(e){return d.getElementById(e)}function isO(e){return e&&"object"==typeof e&&!Array.isArray(e)}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#usermod-settings")}function B(){window.open("/settings","_self")}function S(){"file:"==window.location.protocol&&(loc=!0,(locip=localStorage.getItem("locIp"))||(locip=prompt("File Mode. Please enter WLED IP!"),localStorage.setItem("locIp",locip))),ldS()}function check(e,o){var i=e.name.replace("[]","").substr(-3);if("number"==e.type&&"pin"==i.substr(0,3))for(var n=0;n<pins.length;n++)if(o!=pinO[n]){if(e.value==pins[n]||e.value<-1||e.value>39){e.style.color="red";break}e.style.color=e.value>33?"orange":"#fff"}}function getPins(e){if(isO(e))for(const[i,n]of Object.entries(e))if(isO(n))owner=i,getPins(n);else if("pin"==i.replace("[]","").substr(-3))if(Array.isArray(n))for(var o=0;o<n.length;o++)n[o]>=0&&(pins.push(n[o]),pinO.push(owner));else n>=0&&(pins.push(n),pinO.push(owner));else if(Array.isArray(n))for(o=0;o<n.length;o++)getPins(n[o])}function addField(e,o,i,n=!1){if(isO(i))for(const[o,n]of Object.entries(i))addField(e,o,n);else if(Array.isArray(i))for(var r=0;r<i.length;r++)addField(e,o,i[r],!0);else{var s,t;switch(typeof i){case"boolean":s="checkbox",t=i?'checked value="on"':"";break;case"number":s="number",t=`value="${parseInt(i,10)}"`;break;case"string":default:s="text",t=`value="${i}"`}"checkbox"==s&&(urows+=`<input type="hidden" name="${e}_${o}${n?"[]":""}" value="off">`),urows+=`${o}: <input type="${s}" name="${e}_${o}${n?"[]":""}" ${t} oninput="check(this,'${e}')"><br>`}}function ldS(){fetch((loc?"http://"+locip:"")+"/cfg.json",{method:"get"}).then(e=>(e.ok||(gId("lserr").style.display="inline"),e.json())).then(e=>{if(umCfg=e.um,getPins(e),urows="",isO(umCfg)){for(const[e,o]of Object.entries(umCfg))urows+=`<hr><h3>${e}</h3>`,addField(e,"unknown",o);""===urows&&(urows="No Usermods configuration found.<br>Press <i>Save</i> to initialize defaults if usermods were compiled in.")}else urows="Usermods configuration not found.<br>Most likely no Usermods exist.<br>Press <i>Save</i> to try to initialize defaults.";gId("um").innerHTML=urows}).catch((function(e){gId("lserr").style.display="inline",console.log(e)}))}function svS(e){e.preventDefault(),console.log(d.Sf),d.Sf.checkValidity()&&d.Sf.submit()}function GetV(){}
</script>%CSS%%SCSS%</head><body onload="S()"><form
name="viewport" content="width=500"><title>Usermod Settings</title><script>
var owner,locip,urows,d=document,umCfg={},pins=[6,7,8,9,10,11],pinO=["rsvd","rsvd","rsvd","rsvd","rsvd","rsvd"],loc=!1,numM=0;function gId(e){return d.getElementById(e)}function isO(e){return e&&"object"==typeof e&&!Array.isArray(e)}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#usermod-settings")}function B(){window.open("/settings","_self")}function S(){"file:"==window.location.protocol&&(loc=!0,(locip=localStorage.getItem("locIp"))||(locip=prompt("File Mode. Please enter WLED IP!"),localStorage.setItem("locIp",locip))),GetV(),numM>0||locip?ldS():gId("um").innerHTML="No Usermods installed."}function check(e,n){var o=e.name.replace("[]","").substr(-3);if("number"==e.type&&"pin"==o.substr(0,3))for(var i=0;i<pins.length;i++)if(n!=pinO[i]){if(e.value==pins[i]||e.value<-1||e.value>39){e.style.color="red";break}e.style.color=e.value>33?"orange":"#fff"}}function getPins(e){if(isO(e))for(const[o,i]of Object.entries(e))if(isO(i))owner=o,getPins(i);else if("pin"==o.replace("[]","").substr(-3))if(Array.isArray(i))for(var n=0;n<i.length;n++)i[n]>=0&&(pins.push(i[n]),pinO.push(owner));else i>=0&&(pins.push(i),pinO.push(owner));else if(Array.isArray(i))for(n=0;n<i.length;n++)getPins(i[n])}function addField(e,n,o,i=!1){if(isO(o))for(const[n,i]of Object.entries(o))addField(e,n,i);else if(Array.isArray(o))for(var t=0;t<o.length;t++)addField(e,n,o[t],!0);else{var r,s;switch(typeof o){case"boolean":r="checkbox",s=o?'checked value="on"':"";break;case"number":r="number",s=`value="${parseInt(o,10)}"`;break;case"string":default:r="text",s=`value="${o}"`}"checkbox"==r&&(urows+=`<input type="hidden" name="${e}_${n}${i?"[]":""}" value="off">`),urows+=`${n}: <input type="${r}" name="${e}_${n}${i?"[]":""}" ${s} oninput="check(this,'${e}')"><br>`}}function ldS(){fetch((loc?"http://"+locip:"")+"/cfg.json",{method:"get"}).then(e=>(e.ok||(gId("lserr").style.display="inline"),e.json())).then(e=>{if(umCfg=e.um,getPins(e),urows="",isO(umCfg))for(const[e,n]of Object.entries(umCfg))urows+=`<hr><h3>${e}</h3>`,addField(e,"unknown",n);""===urows&&(urows="Usermods configuration not found.<br>Press <i>Save</i> to initialize defaults."),gId("um").innerHTML=urows}).catch((function(e){gId("lserr").style.display="inline",console.log(e)}))}function svS(e){e.preventDefault(),console.log(d.Sf),d.Sf.checkValidity()&&d.Sf.submit()}function GetV() {var d=document;
%CSS%%SCSS%</head><body onload="S()"><form
id="form_s" name="Sf" method="post" onsubmit="svS(event)"><div class="toprow">
<div class="helpB"><button type="button" onclick="H()">?</button></div><button
type="button" onclick="B()">Back</button><button type="submit">Save</button><br>

View File

@ -227,7 +227,7 @@ void decodeIR24(uint32_t code)
switch (code) {
case IR24_BRIGHTER : incBrightness(); break;
case IR24_DARKER : decBrightness(); break;
case IR24_OFF : briLast = bri; bri = 0; break;
case IR24_OFF : if (bri > 0) briLast = bri; bri = 0; break;
case IR24_ON : bri = briLast; break;
case IR24_RED : colorFromUint32(COLOR_RED); break;
case IR24_REDDISH : colorFromUint32(COLOR_REDDISH); break;
@ -259,7 +259,7 @@ void decodeIR24OLD(uint32_t code)
switch (code) {
case IR24_OLD_BRIGHTER : incBrightness(); break;
case IR24_OLD_DARKER : decBrightness(); break;
case IR24_OLD_OFF : briLast = bri; bri = 0; break;
case IR24_OLD_OFF : if (bri > 0) briLast = bri; bri = 0; break;
case IR24_OLD_ON : bri = briLast; break;
case IR24_OLD_RED : colorFromUint32(COLOR_RED); break;
case IR24_OLD_REDDISH : colorFromUint32(COLOR_REDDISH); break;
@ -292,7 +292,7 @@ void decodeIR24CT(uint32_t code)
switch (code) {
case IR24_CT_BRIGHTER : incBrightness(); break;
case IR24_CT_DARKER : decBrightness(); break;
case IR24_CT_OFF : briLast = bri; bri = 0; break;
case IR24_CT_OFF : if (bri > 0) briLast = bri; bri = 0; break;
case IR24_CT_ON : bri = briLast; break;
case IR24_CT_RED : colorFromUint32(COLOR_RED); break;
case IR24_CT_REDDISH : colorFromUint32(COLOR_REDDISH); break;
@ -327,7 +327,7 @@ void decodeIR40(uint32_t code)
switch (code) {
case IR40_BPLUS : incBrightness(); break;
case IR40_BMINUS : decBrightness(); break;
case IR40_OFF : briLast = bri; bri = 0; break;
case IR40_OFF : if (bri > 0) briLast = bri; bri = 0; break;
case IR40_ON : bri = briLast; break;
case IR40_RED : colorFromUint24(COLOR_RED); break;
case IR40_REDDISH : colorFromUint24(COLOR_REDDISH); break;
@ -384,7 +384,7 @@ void decodeIR44(uint32_t code)
switch (code) {
case IR44_BPLUS : incBrightness(); break;
case IR44_BMINUS : decBrightness(); break;
case IR44_OFF : briLast = bri; bri = 0; break;
case IR44_OFF : if (bri > 0) briLast = bri; bri = 0; break;
case IR44_ON : bri = briLast; break;
case IR44_RED : colorFromUint24(COLOR_RED); break;
case IR44_REDDISH : colorFromUint24(COLOR_REDDISH); break;
@ -447,7 +447,7 @@ void decodeIR21(uint32_t code)
switch (code) {
case IR21_BRIGHTER: incBrightness(); break;
case IR21_DARKER: decBrightness(); break;
case IR21_OFF: briLast = bri; bri = 0; break;
case IR21_OFF: if (bri > 0) briLast = bri; bri = 0; break;
case IR21_ON: bri = briLast; break;
case IR21_RED: colorFromUint32(COLOR_RED); break;
case IR21_REDDISH: colorFromUint32(COLOR_REDDISH); break;

View File

@ -166,7 +166,7 @@ void deserializeSegment(JsonObject elem, byte it)
if (icol.isNull()) break;
byte sz = icol.size();
if (sz == 0 && sz > 4) break;
if (sz == 0 || sz > 4) break;
int rgbw[] = {0,0,0,0};
copyArray(icol, rgbw);
@ -198,6 +198,8 @@ bool deserializeState(JsonObject root)
bool on = root["on"] | (bri > 0);
if (!on != !bri) toggleOnOff();
if (root["on"].is<const char*>() && root["on"].as<const char*>()[0] == 't') toggleOnOff();
int tr = root[F("transition")] | -1;
if (tr >= 0)
{
@ -798,21 +800,24 @@ void serveJson(AsyncWebServerRequest* request, uint8_t versionAPI)
const String& url = request->url();
if (url.indexOf("state") > 0) subJson = 1;
else if (url.indexOf("info") > 0) subJson = 2;
else if (url.indexOf("si") > 0) subJson = 3;
else if (url.indexOf("si") > 0) subJson = 3;
else if (url.indexOf("nodes") > 0) subJson = 4;
else if (url.indexOf("palx") > 0) subJson = 5;
else if (url.indexOf("palx") > 0) subJson = 5;
else if (url.indexOf("live") > 0) {
serveLiveLeds(request);
return;
}
else if (url.indexOf(F("eff")) > 0) {
else if (url.indexOf(F("eff")) > 0) {
request->send_P(200, "application/json", JSON_mode_names);
return;
}
else if (url.indexOf("pal") > 0) {
else if (url.indexOf("pal") > 0) {
request->send_P(200, "application/json", JSON_palette_names);
return;
}
else if (url.indexOf("cfg") > 0 && handleFileRead(request, "/cfg.json")) {
return;
}
else if (url.length() > 6) { //not just /json
request->send( 501, "application/json", F("{\"error\":\"Not implemented\"}"));
return;

View File

@ -52,23 +52,22 @@ void onMqttConnect(bool sessionPresent)
}
void onMqttMessage(char* topic, char* payload0, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
DEBUG_PRINT(F("MQTT msg: "));
DEBUG_PRINTLN(topic);
// paranoia check to avoid npe if no payload
if (payload0==nullptr) {
if (payload==nullptr) {
DEBUG_PRINTLN(F("no payload -> leave"));
return;
}
// payload is not always null terminated
char *payload = new char[len+1];
if (payload==nullptr) return; // out of memory
strncpy(payload,payload0,len);
payload[len] = '\0';
DEBUG_PRINTLN(payload);
//make a copy of the payload to 0-terminate it
char* payloadStr = new char[len+1];
if (payloadStr == nullptr) return; //no mem
strncpy(payloadStr, payload, len);
payloadStr[len] = '\0';
DEBUG_PRINTLN(payloadStr);
size_t topicPrefixLen = strlen(mqttDeviceTopic);
if (strncmp(topic, mqttDeviceTopic, topicPrefixLen) == 0) {
@ -79,8 +78,8 @@ void onMqttMessage(char* topic, char* payload0, AsyncMqttClientMessageProperties
topic += topicPrefixLen;
} else {
// Non-Wled Topic used here. Probably a usermod subscribed to this topic.
usermods.onMqttMessage(topic, payload);
delete[] payload;
usermods.onMqttMessage(topic, payloadStr);
delete[] payloadStr;
return;
}
}
@ -88,26 +87,26 @@ void onMqttMessage(char* topic, char* payload0, AsyncMqttClientMessageProperties
//Prefix is stripped from the topic at this point
if (strcmp_P(topic, PSTR("/col")) == 0) {
colorFromDecOrHexString(col, payload);
colorFromDecOrHexString(col, (char*)payloadStr);
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
} else if (strcmp_P(topic, PSTR("/api")) == 0) {
if (payload[0] == '{') { //JSON API
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
deserializeJson(doc, payload);
deserializeJson(doc, payloadStr);
deserializeState(doc.as<JsonObject>());
} else { //HTTP API
String apireq = "win&";
apireq += payload;
apireq += (char*)payloadStr;
handleSet(nullptr, apireq);
}
} else if (strlen(topic) != 0) {
// non standard topic, check with usermods
usermods.onMqttMessage(topic, payload);
usermods.onMqttMessage(topic, payloadStr);
} else {
// topmost topic (just wled/MAC)
parseMQTTBriPayload(payload);
parseMQTTBriPayload(payloadStr);
}
delete[] payload;
delete[] payloadStr;
}
@ -132,7 +131,7 @@ void publishMqtt()
strcpy(subuf, mqttDeviceTopic);
strcat_P(subuf, PSTR("/status"));
mqtt->publish(subuf, 0, true, "online"); // do not retain message
mqtt->publish(subuf, 0, false, "online"); // do not retain message
char apires[1024];
XML_response(nullptr, apires);

View File

@ -112,7 +112,7 @@ void updateTimezone() {
break;
}
case TZ_AUSTRALIA_NORTHERN : {
tcrStandard = {First, Sun, Apr, 3, 570}; //ACST = UTC + 9.5 hours
tcrDaylight = {First, Sun, Apr, 3, 570}; //ACST = UTC + 9.5 hours
tcrStandard = tcrDaylight;
break;
}

View File

@ -63,10 +63,9 @@ void _overlayAnalogClock()
}
if (analogClock5MinuteMarks)
{
int pix;
for (int i = 0; i <= 12; i++)
for (byte i = 0; i <= 12; i++)
{
pix = analogClock12pixel + round((overlaySize / 12.0) *i);
int pix = analogClock12pixel + round((overlaySize / 12.0) *i);
if (pix > overlayMax) pix -= overlaySize;
strip.setPixelColor(pix, 0x00FFAA);
}

View File

@ -19,14 +19,14 @@ uint16_t playlistEntryDur = 0;
void shufflePlaylist() {
int currentIndex = playlistLen, randomIndex;
int currentIndex = playlistLen;
PlaylistEntry temporaryValue, *entries = reinterpret_cast<PlaylistEntry*>(playlistEntries);
// While there remain elements to shuffle...
while (currentIndex--) {
// Pick a random element...
randomIndex = random(0, currentIndex);
int randomIndex = random(0, currentIndex);
// And swap it with the current element.
temporaryValue = entries[currentIndex];
entries[currentIndex] = entries[randomIndex];

View File

@ -31,7 +31,7 @@ bool isAsterisksOnly(const char* str, byte maxLen)
void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
{
//0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec 7: DMX
//0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec 7: DMX 8: usermods
if (subPage <1 || subPage >8) return;
//WIFI SETTINGS
@ -84,7 +84,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (btnPin>=0 && pinManager.isPinAllocated(btnPin)) pinManager.deallocatePin(btnPin);
strip.isRgbw = false;
uint8_t colorOrder, type, skip;
uint16_t length, start;
uint8_t pins[5] = {255, 255, 255, 255, 255};

File diff suppressed because it is too large Load Diff

View File

@ -220,7 +220,7 @@ void WLED::loop()
yield();
if (!offMode)
if (!offMode || strip.isOffRefreshRequred)
strip.service();
#ifdef ESP8266
else if (!noWifiSleep)
@ -370,7 +370,7 @@ void WLED::setup()
updateFSInfo();
DEBUG_PRINTLN(F("Reading config"));
deserializeConfig();
deserializeConfigFromFS();
/*
#if STATUSLED
bool lStatusLed = false;

View File

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

View File

@ -321,7 +321,7 @@ void loadSettingsFromEEPROM()
notifyMacro = EEPROM.read(2201);
strip.rgbwMode = EEPROM.read(2203);
//was skipFirstLed = EEPROM.read(2204);
//skipFirstLed = EEPROM.read(2204);
if (EEPROM.read(2210) || EEPROM.read(2211) || EEPROM.read(2212))
{

View File

@ -85,6 +85,7 @@ void initServer()
AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/json", [](AsyncWebServerRequest *request) {
bool verboseResponse = false;
uint8_t vAPI = 1;
bool isConfig = false;
{ //scope JsonDocument so it releases its buffer
DynamicJsonDocument jsonBuffer(JSON_BUFFER_SIZE);
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t*)(request->_tempObject));
@ -92,16 +93,26 @@ void initServer()
if (error || root.isNull()) {
request->send(400, "application/json", F("{\"error\":9}")); return;
}
const String& url = request->url();
isConfig = url.indexOf("cfg") > -1;
if (!isConfig) {
if (root.containsKey("rev"))
{
vAPI = root["rev"] | 1;
}
fileDoc = &jsonBuffer; // used for applying presets (presets.cpp)
verboseResponse = deserializeState(root);
fileDoc = nullptr;
fileDoc = &jsonBuffer; // used for applying presets (presets.cpp)
verboseResponse = deserializeState(root);
fileDoc = nullptr;
} else {
verboseResponse = deserializeConfig(root); //use verboseResponse to determine whether cfg change should be saved immediately
}
}
if (verboseResponse) { //if JSON contains "v"
serveJson(request,vAPI); return;
if (verboseResponse) {
if (!isConfig) {
serveJson(request,vAPI); return; //if JSON contains "v"
} else {
serializeConfig(); //Save new settings to FS
}
}
request->send(200, "application/json", F("{\"success\":true}"));
});

View File

@ -185,7 +185,7 @@ void getSettingsJS(byte subPage, char* dest)
obuf = dest;
olen = 0;
if (subPage <1 || subPage >7) return;
if (subPage <1 || subPage >8) return;
if (subPage == 1)
{
@ -361,7 +361,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',co,bus->getColorOrder());
sappend('v',ls,bus->getStart());
sappend('c',cv,bus->reversed);
sappend('c',sl,bus->skipFirstLed());
sappend('c',sl,bus->skippedLeds());
// sappend('c',ew,bus->isRgbw());
}
sappend('v',SET_F("MA"),strip.ablMilliampsMax);
@ -577,7 +577,15 @@ void getSettingsJS(byte subPage, char* dest)
sappend('i',SET_F("CH13"),DMXFixtureMap[12]);
sappend('i',SET_F("CH14"),DMXFixtureMap[13]);
sappend('i',SET_F("CH15"),DMXFixtureMap[14]);
}
}
#endif
if (subPage == 8) //usermods
{
oappend(SET_F("numM="));
oappendi(usermods.getModCount());
oappend(";");
}
oappend(SET_F("}</script>"));
}