diff --git a/.gitignore b/.gitignore
index db3138f50..a95dd5ac2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.pio
+.cache
.pioenvs
.piolibdeps
.vscode
@@ -6,6 +7,8 @@
/wled00/Release
/wled00/extLibs
/platformio_override.ini
+/wled00/my_config.h
+/build_output
.DS_Store
.gitignore
.clang-format
diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile
new file mode 100644
index 000000000..29d75d19d
--- /dev/null
+++ b/.gitpod.Dockerfile
@@ -0,0 +1,5 @@
+FROM gitpod/workspace-full
+
+USER gitpod
+
+RUN pip3 install -U platformio
diff --git a/.gitpod.yml b/.gitpod.yml
new file mode 100644
index 000000000..cc416b1c2
--- /dev/null
+++ b/.gitpod.yml
@@ -0,0 +1,12 @@
+tasks:
+ - command: platformio run
+
+image:
+ file: .gitpod.Dockerfile
+
+vscode:
+ extensions:
+ - ms-vscode.cpptools@0.26.3:u3GsZ5PK12Ddr79vh4TWgQ==
+ - eamodio.gitlens@10.2.1:e0IYyp0efFqVsrZwsIe8CA==
+ - Atishay-Jain.All-Autocomplete@0.0.23:fbZNfSpnd8XkAHGfAPS2rA==
+ - 2gua.rainbow-brackets@0.0.6:Tbu8dTz0i+/bgcKQTQ5b8g==
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4581c0ab4..6403fb912 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,61 @@
### Development versions after the 0.10.2 release
+#### Build 2011200
+
+- Added HEX color receiving to JSON API with `"col":["RRGGBBWW"]` format
+- Moved Kelvin color receiving in JSON API from `"col":[[val]]` to `"col":[val]` format
+ _Notice:_ This is technically a breaking change. Since no release was made since the introduction and the Kelvin property was not previously documented in the wiki,
+ impact should be minimal.
+- BTNPIN can now be disabled by setting to -1 (fixes #1237)
+
+#### Build 2011180
+
+- Platformio.ini updates and streamlining (PR #1266)
+- my_config.h custom compile settings system (not yet used for much, adapted from PR #1266)
+- Added Hawaii timezone (HST)
+- Linebreak after 5 quick select buttons
+
+#### Build 2011154
+
+- Fixed RGBW saved incorrectly
+- Fixed pmt caching requesting /presets.json too often
+- Fixed deEEP not copying the first segment of EEPROM preset 16
+
+#### Build 2011153
+
+- Fixed an ESP32 end-of-file issue
+- Fixed useRGBW not read from cfg.json
+
+#### Build 2011152
+
+- Version bump to 0.11.0p "Mirai"
+- Increased max. num of segments to 12 (ESP8266) / 16 (ESP32)
+- Up to 250 presets stored in the `presets.json` file in filesystem
+- Complete overhaul of the Presets UI tab
+- Updated iro.js to v5 (fixes black color wheel)
+- Added white temperature slider to color wheel
+- Add JSON settings serialization/deserialization to cfg.json and wsec.json
+- Added deEEP to convert the EEPROM settings and presets to files
+- Playlist support - JSON only for now
+- New v2 usermod methods `addToConfig()` and `readFromConfig()` (see EXAMPLE_v2 for doc)
+- Added Ethernet support for ESP32 (PR #1316)
+- IP addresses are now handled by the `Network` class
+- New `esp32_poe` PIO environment
+- Use EspAsyncWebserver Aircoookie fork v.2.0.0 (hiding wsec.json)
+- Removed `WLED_DISABLE_FILESYSTEM` and `WLED_ENABLE_FS_SERVING` defines as they are now required
+- Added pin manager
+- UI performance improvements (no drop shadows)
+- More explanatory error messages in UI
+- Improved candle brightness
+- Return remaining nightlight time `nl.rem` in JSON API (PR #1302)
+- UI sends timestamp with every command, allowing for timed presets without using NTP
+- Added gamma calculation (yet unused)
+- Added LED type definitions to const.h (yet unused)
+- Added nicer 404 page
+- Removed `NP` and `MS=` macro HTTP API commands
+- Removed macros from Time settings
+
#### Build 2011120
- Added the ability for the /api MQTT topic to receive JSON API payloads
@@ -43,6 +98,7 @@
- Added Loxone parser (PR #1185)
- Added support for kelvin input via `K=` HTTP and `"col":[[val]]` JSON API calls
+ _Notice:_ `"col":[[val]]` removed in build 2011200, use `"col":[val]`
- Added supplementary UDP socket (#1205)
- TMP2.net receivable by default
- UDP sockets accept HTTP and JSON API commands
diff --git a/package.json b/package.json
index b0aa7ceb2..4e431090f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "wled",
- "version": "0.10.2",
+ "version": "0.11.0p",
"description": "Tools for WLED project",
"main": "tools/cdata.js",
"directories": {
diff --git a/pio/gzip-firmware.py b/pio/gzip-firmware.py
new file mode 100644
index 000000000..2d0283011
--- /dev/null
+++ b/pio/gzip-firmware.py
@@ -0,0 +1,23 @@
+Import('env')
+import os
+import shutil
+import gzip
+
+OUTPUT_DIR = "build_output{}".format(os.path.sep)
+
+def bin_gzip(source, target, env):
+ variant = str(target[0]).split(os.path.sep)[2]
+
+ # create string with location and file names based on variant
+ bin_file = "{}firmware{}{}.bin".format(OUTPUT_DIR, os.path.sep, variant)
+ gzip_file = "{}firmware{}{}.bin.gz".format(OUTPUT_DIR, os.path.sep, variant)
+
+ # check if new target files exist and remove if necessary
+ if os.path.isfile(gzip_file): os.remove(gzip_file)
+
+ # write gzip firmware file
+ with open(bin_file,"rb") as fp:
+ with gzip.open(gzip_file, "wb", compresslevel = 9) as f:
+ shutil.copyfileobj(fp, f)
+
+env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_gzip])
diff --git a/pio/name-firmware.py b/pio/name-firmware.py
new file mode 100644
index 000000000..90ea9867f
--- /dev/null
+++ b/pio/name-firmware.py
@@ -0,0 +1,34 @@
+Import('env')
+import os
+import shutil
+
+OUTPUT_DIR = "build_output{}".format(os.path.sep)
+
+def bin_rename_copy(source, target, env):
+ variant = str(target[0]).split(os.path.sep)[2]
+
+ # check if output directories exist and create if necessary
+ if not os.path.isdir(OUTPUT_DIR):
+ os.mkdir(OUTPUT_DIR)
+
+ for d in ['firmware', 'map']:
+ if not os.path.isdir("{}{}".format(OUTPUT_DIR, d)):
+ os.mkdir("{}{}".format(OUTPUT_DIR, d))
+
+ # create string with location and file names based on variant
+ map_file = "{}map{}{}.map".format(OUTPUT_DIR, os.path.sep, variant)
+ bin_file = "{}firmware{}{}.bin".format(OUTPUT_DIR, os.path.sep, variant)
+
+ # check if new target files exist and remove if necessary
+ for f in [map_file, bin_file]:
+ if os.path.isfile(f):
+ os.remove(f)
+
+ # copy firmware.bin to firmware/.bin
+ shutil.copy(str(target[0]), bin_file)
+
+ # copy firmware.map to map/.map
+ if os.path.isfile("firmware.map"):
+ shutil.move("firmware.map", map_file)
+
+env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_rename_copy])
diff --git a/pio/obj-dump.py b/pio/obj-dump.py
new file mode 100644
index 000000000..91bc3de58
--- /dev/null
+++ b/pio/obj-dump.py
@@ -0,0 +1,9 @@
+# Little convenience script to get an object dump
+
+Import('env')
+
+def obj_dump_after_elf(source, target, env):
+ print("Create firmware.asm")
+ env.Execute("xtensa-lx106-elf-objdump "+ "-D " + str(target[0]) + " > "+ "${PROGNAME}.asm")
+
+env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", [obj_dump_after_elf])
diff --git a/pio/strip-floats.py b/pio/strip-floats.py
new file mode 100644
index 000000000..da916ebe2
--- /dev/null
+++ b/pio/strip-floats.py
@@ -0,0 +1,15 @@
+Import('env')
+
+#
+# Dump build environment (for debug)
+#print env.Dump()
+#
+
+flags = " ".join(env['LINKFLAGS'])
+flags = flags.replace("-u _printf_float", "")
+flags = flags.replace("-u _scanf_float", "")
+newflags = flags.split()
+
+env.Replace(
+ LINKFLAGS=newflags
+)
\ No newline at end of file
diff --git a/pio/user_config_copy.py b/pio/user_config_copy.py
new file mode 100644
index 000000000..1251ca178
--- /dev/null
+++ b/pio/user_config_copy.py
@@ -0,0 +1,9 @@
+Import('env')
+import os
+import shutil
+
+# copy WLED00/my_config_sample.h to WLED00/my_config.h
+if os.path.isfile("wled00/my_config.h"):
+ print ("*** use existing my_config.h ***")
+else:
+ shutil.copy("wled00/my_config_sample.h", "wled00/my_config.h")
diff --git a/platformio.ini b/platformio.ini
index 139eaf30d..c23047e68 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -2,20 +2,13 @@
; Please visit documentation: https://docs.platformio.org/page/projectconf.html
[platformio]
-src_dir = ./wled00
-data_dir = ./wled00/data
-lib_dir = ./wled00/src
-build_cache_dir = ~/.buildcache
-extra_configs =
- platformio_override.ini
-
# ------------------------------------------------------------------------------
# ENVIRONMENTS
#
# Please uncomment one of the lines below to select your board(s)
# ------------------------------------------------------------------------------
-# Travis CI binaries
+# Travis CI binaries (comment this out with a ';' when building for your own board)
default_envs = travis_esp8266, travis_esp32
# Release binaries
@@ -41,36 +34,21 @@ default_envs = travis_esp8266, travis_esp32
; default_envs = m5atom
; default_envs = esp32_poe
+src_dir = ./wled00
+data_dir = ./wled00/data
+build_cache_dir = ~/.buildcache
+extra_configs =
+ platformio_override.ini
+
[common]
# ------------------------------------------------------------------------------
# PLATFORM:
# !! DO NOT confuse platformio's ESP8266 development platform with Arduino core for ESP8266
#
-# arduino core 2.3.0 = platformIO 1.5.0
-# arduino core 2.4.0 = platformIO 1.6.0
-# arduino core 2.4.1 = platformIO 1.7.3
-# arduino core 2.4.2 = platformIO 1.8.0
-# arduino core 2.5.0 = platformIO 2.0.4
-# arduino core 2.5.1 = platformIO 2.1.1
-# arduino core 2.5.2 = platformIO 2.2.3
-# arduino core 2.6.1 = platformIO 2.3.0
-# arduino core 2.6.2 = platformIO 2.3.1
# arduino core 2.6.3 = platformIO 2.3.2
# arduino core 2.7.0 = platformIO 2.5.0
# ------------------------------------------------------------------------------
-arduino_core_2_3_0 = espressif8266@1.5.0
-arduino_core_2_4_0 = espressif8266@1.6.0
-arduino_core_2_4_1 = espressif8266@1.7.3
-arduino_core_2_4_2 = espressif8266@1.8.0
-arduino_core_2_5_0 = espressif8266@2.0.4
-arduino_core_2_5_1 = espressif8266@2.1.1
-arduino_core_2_5_2 = espressif8266@2.2.3
-arduino_core_2_6_1 = espressif8266@2.3.0
-arduino_core_2_6_2 = espressif8266@2.3.1
arduino_core_2_6_3 = espressif8266@2.3.3
-arduino_core_2_7_1 = espressif8266@2.5.1
-arduino_core_2_7_2 = espressif8266@2.6.0
-arduino_core_2_7_3 = espressif8266@2.6.1
arduino_core_2_7_4 = espressif8266@2.6.2
# Development platforms
@@ -79,8 +57,8 @@ arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/
# Platform to use for ESP8266
platform_wled_default = ${common.arduino_core_2_7_4}
-# We use 2.7.0+ on analog boards because of PWM flicker fix
-platform_latest = ${common.arduino_core_2_7_4}
+# We use 2.7.4.7 for all, includes PWM flicker fix and Wstring optimization
+platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
# ------------------------------------------------------------------------------
# FLAGS: DEBUG
@@ -91,7 +69,7 @@ debug_flags = -D DEBUG=1 -D WLED_DEBUG -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT
#-DDEBUG_ESP_CORE is not working right now
# ------------------------------------------------------------------------------
-# FLAGS: ldscript
+# FLAGS: ldscript (available ldscripts at https://github.com/esp8266/Arduino/tree/master/tools/sdk/ld)
# ldscript_512k ( 512 KB) = 487 KB sketch, 4 KB eeprom, no spiffs, 16 KB reserved
# ldscript_1m0m (1024 KB) = 999 KB sketch, 4 KB eeprom, no spiffs, 16 KB reserved
# ldscript_2m1m (2048 KB) = 1019 KB sketch, 4 KB eeprom, 1004 KB spiffs, 16 KB reserved
@@ -102,6 +80,7 @@ debug_flags = -D DEBUG=1 -D WLED_DEBUG -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT
# -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH = v1.4 Higher Bandwidth (default)
# -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY = v2 Lower Memory
# -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH = v2 Higher Bandwidth
+# -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
#
# BearSSL performance:
# When building with -DSECURE_CLIENT=SECURE_CLIENT_BEARSSL, please add `board_build.f_cpu = 160000000` to the environment configuration
@@ -114,18 +93,35 @@ debug_flags = -D DEBUG=1 -D WLED_DEBUG -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT
# TLS_RSA_WITH_AES_256_CBC_SHA / AES256-SHA
# This reduces the OTA size with ~45KB, so it's especially useful on low memory boards (512k/1m).
# ------------------------------------------------------------------------------
-build_flags = -g -w -DMQTT_MAX_PACKET_SIZE=1024 -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
- -DSECURE_CLIENT=SECURE_CLIENT_BEARSSL -DBEARSSL_SSL_BASIC
- #build_flags for the IRremoteESP8266 library (enabled decoders have to appear here)
+build_flags =
+ -Wno-switch
+ -Wno-deprecated-declarations
+ -Wno-write-strings
+ -Wno-unused-variable
+ -Wno-unused-value
+ -Wno-sign-compare
+ -Wno-unused-but-set-variable
+ -Wno-return-type
+ -Wno-sequence-point
+ -Wno-narrowing
+ -Wno-reorder
+ -DMQTT_MAX_PACKET_SIZE=1024
+ -DSECURE_CLIENT=SECURE_CLIENT_BEARSSL
+ -DBEARSSL_SSL_BASIC
+ -D CORE_DEBUG_LEVEL=0
+ -D NDEBUG
+ #build_flags for the IRremoteESP8266 library (enabled decoders have to appear here)
-D _IR_ENABLE_DEFAULT_=false
-D DECODE_HASH=true
-D DECODE_NEC=true
-D DECODE_SONY=true
-D DECODE_SAMSUNG=true
-D DECODE_LG=true
-
-build_flags_esp8266 = ${common.build_flags} -DESP8266
-build_flags_esp32 = ${common.build_flags} -DARDUINO_ARCH_ESP32
+ -DWLED_USE_MY_CONFIG
+
+build_unflags =
+ -Wall
+ -Wdeprecated-declarations
# enables all features for travis CI
build_flags_all_features =
@@ -137,13 +133,39 @@ build_flags_all_features =
-D WLED_ENABLE_MQTT
-D WLED_ENABLE_WEBSOCKETS
+build_flags_esp8266 = ${common.build_flags} ${esp8266.build_flags}
+build_flags_esp32 = ${common.build_flags} ${esp32.build_flags}
+
ldscript_512k = eagle.flash.512k.ld ;for older versions change this to eagle.flash.512k0.ld
ldscript_1m0m = eagle.flash.1m.ld ;for older versions change this to eagle.flash.1m0.ld
+ldscript_1m128k = eagle.flash.1m128.ld
+ldscript_2m512k = eagle.flash.2m512.ld
ldscript_2m1m = eagle.flash.2m1m.ld
ldscript_4m1m = eagle.flash.4m1m.ld
-ldscript_4m3m = eagle.flash.4m3m.ld
-shared_libdeps_dir = ./wled00/src
+[esp8266]
+build_flags =
+ -DESP8266
+ -DFP_IN_IROM
+; NONOSDK22x_190703 = 2.2.2-dev(38a443e)
+ -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703
+; lwIP 2 - Higher Bandwidth no Features
+ -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
+; VTABLES in Flash
+ -DVTABLES_IN_FLASH
+; restrict to minimal mime-types
+ -DMIMETYPE_MINIMAL
+
+[esp32]
+build_flags = -w -g
+ -DARDUINO_ARCH_ESP32
+ -DCONFIG_LITTLEFS_FOR_IDF_3_2
+
+[scripts_defaults]
+extra_scripts = pio/name-firmware.py
+ pio/gzip-firmware.py
+ pio/strip-floats.py
+ pio/user_config_copy.py
# ------------------------------------------------------------------------------
# COMMON SETTINGS:
@@ -153,8 +175,6 @@ framework = arduino
board_build.flash_mode = dout
monitor_speed = 115200
upload_speed = 115200
-lib_extra_dirs =
- ${common.shared_libdeps_dir}
# ------------------------------------------------------------------------------
# LIBRARIES: required dependencies
@@ -166,24 +186,27 @@ lib_extra_dirs =
lib_compat_mode = strict
lib_deps =
FastLED@3.3.2
- #NeoPixelBus@2.5.7
- https://github.com/Makuna/NeoPixelBus
+ NeoPixelBus@2.6.0
ESPAsyncTCP@1.2.0
ESPAsyncUDP
AsyncTCP@1.0.3
- https://github.com/Aircoookie/ESPAsyncWebServer
IRremoteESP8266@2.7.3
+ https://github.com/lorol/LITTLEFS.git
+ https://github.com/Aircoookie/ESPAsyncWebServer.git@~2.0.0
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
#TFT_eSPI
#For use SSD1306 OLED display uncomment following
#U8g2@~2.27.2
#For Dallas sensor uncomment following 2 lines
#OneWire@~2.3.5
+ #milesburton/DallasTemperature@^3.9.0
#For BME280 sensor uncomment following
#BME280@~3.0.0
lib_ignore =
AsyncTCP
+extra_scripts = ${scripts_defaults.extra_scripts}
+
# ------------------------------------------------------------------------------
# WLED BUILDS
# ------------------------------------------------------------------------------
@@ -191,14 +214,18 @@ lib_ignore =
[env:nodemcuv2]
board = nodemcuv2
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}
# Unsupported environment due to insufficient flash
[env:esp01]
board = esp01
platform = ${common.platform_wled_default}
+platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_512k}
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK
-D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED -D WLED_DISABLE_MQTT -D WLED_DISABLE_WEBSOCKETS
@@ -206,44 +233,58 @@ build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -D WLED_DISABLE_
[env:esp01_1m_ota]
board = esp01_1m
platform = ${common.platform_wled_default}
+platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m0m}
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK -D WLED_DISABLE_CRONIXIE
-D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED -D WLED_DISABLE_MQTT -D WLED_DISABLE_WEBSOCKETS
[env:esp01_1m_full]
board = esp01_1m
platform = ${common.platform_wled_default}
-board_build.ldscript = ${common.ldscript_1m0m}
+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
[env:esp07]
board = esp07
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}
[env:d1_mini]
board = d1_mini
platform = ${common.platform_wled_default}
+platform_packages = ${common.platform_packages}
upload_speed = 921600
board_build.ldscript = ${common.ldscript_4m1m}
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266}
+monitor_filters = esp8266_exception_decoder
[env:heltec_wifi_kit_8]
board = d1_mini
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}
[env:h803wf]
board = d1_mini
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 LEDPIN=1 -D WLED_DISABLE_INFRARED
[env:esp32dev]
board = esp32dev
-platform = espressif32@1.12.4
+platform = espressif32@2.0
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32}
lib_ignore =
ESPAsyncTCP
@@ -251,35 +292,44 @@ lib_ignore =
[env:esp32_poe]
board = esp32-poe
-platform = espressif32@1.12.4
+platform = espressif32@2.0
upload_speed = 921600
-build_flags = ${common.build_flags_esp32} ${common.debug_flags} -D RLYPIN=-1 -D WLED_USE_ETHERNET
+build_unflags = ${common.build_unflags}
+build_flags = ${common.build_flags_esp32} -D RLYPIN=-1 -D WLED_USE_ETHERNET
lib_ignore =
ESPAsyncTCP
ESPAsyncUDP
[env:esp8285_4CH_MagicHome]
board = esp8285
-platform = ${common.platform_latest}
+platform = ${common.platform_wled_default}
+platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m0m}
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_HUESYNC -D WLED_USE_ANALOG_LEDS
[env:esp8285_4CH_H801]
board = esp8285
-platform = ${common.platform_latest}
+platform = ${common.platform_wled_default}
+platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m0m}
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_HUESYNC -D WLED_USE_ANALOG_LEDS -D WLED_USE_H801
[env:esp8285_5CH_H801]
board = esp8285
-platform = ${common.platform_latest}
+platform = ${common.platform_wled_default}
+platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m0m}
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_HUESYNC -D WLED_USE_ANALOG_LEDS -D WLED_USE_H801 -D WLED_ENABLE_5CH_LEDS
[env:d1_mini_5CH_Shojo_PCB]
board = d1_mini
-platform = ${common.platform_latest}
+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
# ------------------------------------------------------------------------------
@@ -290,7 +340,9 @@ build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D WLED_USE_
board = d1_mini
build_type = debug
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} ${common.debug_flags}
[env:d1_mini_ota]
@@ -299,7 +351,9 @@ upload_protocol = espota
# exchange for your WLED IP
upload_port = "10.10.1.27"
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}
# ------------------------------------------------------------------------------
@@ -308,38 +362,49 @@ build_flags = ${common.build_flags_esp8266}
[env:custom_LEDPIN_4]
board = d1_mini
-platform = ${common.platform_latest}
+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 LEDPIN=4 -D IRPIN=5
[env:custom_LEDPIN_16]
board = d1_mini
-platform = ${common.platform_latest}
+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 LEDPIN=16
[env:custom_LEDPIN_3]
board = d1_mini
-platform = ${common.platform_latest}
+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 LEDPIN=3
[env:custom_APA102]
board = d1_mini
-platform = ${common.platform_latest}
+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 USE_APA102
[env:custom_WS2801]
board = d1_mini
-platform = ${common.platform_latest}
+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 USE_WS2801
[env:custom32_LEDPIN_16]
board = esp32dev
-platform = espressif32@1.12.4
+platform = espressif32@2.0
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} -D LEDPIN=16
lib_ignore =
ESPAsyncTCP
@@ -347,7 +412,8 @@ lib_ignore =
[env:custom32_TOUCHPIN_T0]
board = esp32dev
-platform = espressif32@1.12.4
+platform = espressif32@2.0
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} -D TOUCHPIN=T0
lib_ignore =
ESPAsyncTCP
@@ -355,10 +421,11 @@ lib_ignore =
[env:wemos_shield_esp32]
board = esp32dev
-platform = espressif32@1.12.4
+platform = espressif32@2.0
upload_port = /dev/cu.SLAB_USBtoUART
monitor_port = /dev/cu.SLAB_USBtoUART
upload_speed = 460800
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} -D LEDPIN=16 -D RLYPIN=19 -D BTNPIN=17
lib_ignore =
ESPAsyncTCP
@@ -366,11 +433,12 @@ lib_ignore =
[env:m5atom]
board = esp32dev
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} -D LEDPIN=27 -D BTNPIN=39
lib_ignore =
ESPAsyncTCP
ESPAsyncUDP
-platform = espressif32@1.12.4
+platform = espressif32@2.0
[env:sp501e]
board = esp_wroom_02
@@ -385,11 +453,13 @@ build_flags = ${common.build_flags_esp8266} -D LEDPIN=3 -D BTNPIN=1
[env:travis_esp8266]
extends = env:d1_mini
build_type = debug
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} ${common.debug_flags} ${common.build_flags_all_features}
[env:travis_esp32]
extends = env:esp32dev
-build_type = debug
+; build_type = debug
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} ${common.debug_flags} ${common.build_flags_all_features}
# ------------------------------------------------------------------------------
@@ -399,35 +469,47 @@ build_flags = ${common.build_flags_esp32} ${common.debug_flags} ${common.build_f
[env:codm-controller-0.4]
board = esp_wroom_02
platform = ${common.platform_wled_default}
+platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m1m}
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D LEDPIN=3
[env:codm-controller-0.4-WS2801]
board = esp_wroom_02
-platform = ${common.platform_latest}
+platform = ${common.platform_wled_default}
+platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m1m}
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D USE_WS2801 -D CLKPIN=13 -D DATAPIN=3
[env:codm-controller-0.4-APA102]
board = esp_wroom_02
-platform = ${common.platform_latest}
+platform = ${common.platform_wled_default}
+platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m1m}
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D USE_APA102 -D CLKPIN=13 -D DATAPIN=3
[env:codm-controller-0.5]
board = esp_wroom_02
platform = ${common.platform_wled_default}
+platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m1m}
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266}
[env:codm-controller-0.5-WS2801]
board = esp_wroom_02
-platform = ${common.platform_latest}
+platform = ${common.platform_wled_default}
+platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m1m}
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D USE_WS2801 #-D CLKPIN=0 -D DATAPIN=2
[env:codm-controller-0.5-APA102]
board = esp_wroom_02
-platform = ${common.platform_latest}
+platform = ${common.platform_wled_default}
+platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m1m}
+build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D USE_APA102 #-D CLKPIN=0 -D DATAPIN=2
diff --git a/platformio_override.ini.example b/platformio_override.ini.example
index 240c486ab..cf9da2682 100644
--- a/platformio_override.ini.example
+++ b/platformio_override.ini.example
@@ -5,19 +5,26 @@
# Please visit documentation: https://docs.platformio.org/page/projectconf.html
[platformio]
-default_envs = esp8266_1m_custom
+default_envs = WLED_tasmota_1M
-[env:esp8266_1m_custom]
+[env:WLED_tasmota_1M]
board = esp01_1m
-platform = ${common.arduino_core_2_4_2}
+platform = ${common.platform_wled_default}
+platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m0m}
-build_flags = ${common.build_flags_esp8266}
- -D WLED_DISABLE_OTA
- -D WLED_DISABLE_ALEXA
- -D WLED_DISABLE_BLYNK
- -D WLED_DISABLE_CRONIXIE
- -D WLED_DISABLE_HUESYNC
- -D WLED_DISABLE_INFRARED
+build_unflags = ${common.build_unflags}
+build_flags = ${common.build_flags_esp8266}
+; *********************************************************************
+; *** Use custom settings from file my_config.h
+ -DWLED_USE_MY_CONFIG
+; *********************************************************************
+; -D WLED_DISABLE_OTA
+; -D WLED_DISABLE_ALEXA
+; -D WLED_DISABLE_BLYNK
+; -D WLED_DISABLE_CRONIXIE
+; -D WLED_DISABLE_HUESYNC
+; -D WLED_DISABLE_INFRARED
+; -D WLED_DISABLE_WEBSOCKETS
; PIN defines - uncomment and change, if needed:
; -D LEDPIN=2
; -D BTNPIN=0
@@ -30,11 +37,11 @@ build_flags = ${common.build_flags_esp8266}
; -D USE_WS2801
; -D USE_LPD8806
; PIN defines for 2 wire LEDs
-; -D CLKPIN=0
-; -D DATAPIN=2
+ -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
+ -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
diff --git a/readme.md b/readme.md
index c3a1f2add..866db4aaf 100644
--- a/readme.md
+++ b/readme.md
@@ -6,6 +6,7 @@
+
@@ -21,19 +22,20 @@ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control
- Settings page - configuration over network
- Access Point and station mode - automatic failsafe AP
- Support for RGBW strips
-- 16 user presets to save and load colors/effects easily, supports cycling through them.
-- Macro functions to automatically execute API calls
+- Up to 250 user presets to save and load colors/effects easily, supports cycling through them.
+- Presets can be used to automatically execute API calls
- Nightlight function (gradually dims down)
- Full OTA software updatability (HTTP + ArduinoOTA), password protectable
- Configurable analog clock + support for the Cronixie kit by Diamex
- Configurable Auto Brightness limit for safer operation
+- Filesystem-based config for easier backup of presets and settings
## 💡 Supported light control interfaces
- WLED app for [Android](https://play.google.com/store/apps/details?id=com.aircoookie.WLED) and [iOS](https://apps.apple.com/us/app/wled/id1475695033)
- JSON and HTTP request APIs
- MQTT
- Blynk IoT
-- E1.31, Art-Net and TPM2.net
+- E1.31, Art-Net, DDP and TPM2.net
- [Hyperion](https://github.com/hyperion-project/hyperion.ng)
- UDP realtime
- Alexa voice control (including dimming and color)
diff --git a/tools/cdata.js b/tools/cdata.js
index 584dbdad5..aa473deb1 100644
--- a/tools/cdata.js
+++ b/tools/cdata.js
@@ -386,6 +386,14 @@ const char PAGE_dmxmap[] PROGMEM = R"=====()=====";
method: "plaintext",
filter: "html-minify",
},
+ {
+ file: "404.htm",
+ name: "PAGE_404",
+ prepend: "=====(",
+ append: ")=====",
+ method: "plaintext",
+ filter: "html-minify",
+ },
{
file: "favicon.ico",
name: "favicon",
diff --git a/usermods/EXAMPLE_v2/usermod_v2_example.h b/usermods/EXAMPLE_v2/usermod_v2_example.h
index e67ef8da2..ef68e907c 100644
--- a/usermods/EXAMPLE_v2/usermod_v2_example.h
+++ b/usermods/EXAMPLE_v2/usermod_v2_example.h
@@ -103,7 +103,43 @@ class MyExampleUsermod : public Usermod {
userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
}
-
+
+
+ /*
+ * addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
+ * It will be called by WLED when settings are actually saved (for example, LED settings are saved)
+ * If you want to force saving the current state, use serializeConfig() in your loop().
+ *
+ * CAUTION: serializeConfig() will initiate a filesystem write operation.
+ * It might cause the LEDs to stutter and will cause flash wear if called too often.
+ * Use it sparingly and always in the loop, never in network callbacks!
+ *
+ * addToConfig() will also not yet add your setting to one of the settings pages automatically.
+ * To make that work you still have to add the setting to the HTML, xml.cpp and set.cpp manually.
+ *
+ * I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
+ */
+ void addToConfig(JsonObject& root)
+ {
+ JsonObject top = root.createNestedObject("exampleUsermod");
+ top["great"] = userVar0; //save this var persistently whenever settings are saved
+ }
+
+
+ /*
+ * readFromConfig() can be used to read back the custom settings you added with addToConfig().
+ * This is called by WLED when settings are loaded (currently this only happens once immediately after boot)
+ *
+ * readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes),
+ * but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
+ * If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
+ */
+ void readFromConfig(JsonObject& root)
+ {
+ JsonObject top = root["top"];
+ userVar0 = top["great"] | 42; //The value right of the pipe "|" is the default value in case your setting was not present in cfg.json (e.g. first boot)
+ }
+
/*
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index 5ad5de2e0..bac929ff8 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -2726,7 +2726,7 @@ uint16_t WS2812FX::candle(bool multi)
//max. flicker range controlled by intensity
uint8_t valrange = SEGMENT.intensity;
- uint8_t rndval = valrange >> 1;
+ uint8_t rndval = valrange >> 1; //max 127
//step (how much to move closer to target per frame) coarsely set by speed
uint8_t speedFactor = 4;
@@ -2763,9 +2763,9 @@ uint16_t WS2812FX::candle(bool multi)
}
if (newTarget) {
- s_target = random8(rndval) + random8(rndval);
+ s_target = random8(rndval) + random8(rndval); //between 0 and rndval*2 -2 = 252
if (s_target < (rndval >> 1)) s_target = (rndval >> 1) + random8(rndval);
- uint8_t offset = (255 - valrange) >> 1;
+ uint8_t offset = (255 - valrange);
s_target += offset;
uint8_t dif = (s_target > s) ? s_target - s : s - s_target;
diff --git a/wled00/FX.h b/wled00/FX.h
index 6c893692f..7ec99bfdd 100644
--- a/wled00/FX.h
+++ b/wled00/FX.h
@@ -40,8 +40,12 @@
#define DEFAULT_INTENSITY (uint8_t)128
#define DEFAULT_COLOR (uint32_t)0xFFAA00
+#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
/* Not used in all effects yet */
#define WLED_FPS 42
@@ -50,9 +54,9 @@
/* each segment uses 52 bytes of SRAM memory, so if you're application fails because of
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
#ifdef ESP8266
- #define MAX_NUM_SEGMENTS 10
+ #define MAX_NUM_SEGMENTS 12
#else
- #define MAX_NUM_SEGMENTS 10
+ #define MAX_NUM_SEGMENTS 16
#endif
/* How much data bytes all segments combined may allocate */
@@ -452,6 +456,7 @@ class WS2812FX {
setRange(uint16_t i, uint16_t i2, uint32_t col),
setShowCallback(show_callback cb),
setTransitionMode(bool t),
+ calcGammaTable(float),
trigger(void),
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0),
resetSegments(),
@@ -485,6 +490,7 @@ class WS2812FX {
//getFirstSelectedSegment(void),
getMainSegmentId(void),
gamma8(uint8_t),
+ gamma8_cal(uint8_t, float),
get_random_wheel_index(uint8_t);
int8_t
diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp
index ad459aba5..099f77cd0 100644
--- a/wled00/FX_fcn.cpp
+++ b/wled00/FX_fcn.cpp
@@ -965,8 +965,8 @@ void WS2812FX::setRgbwPwm(void) {
void WS2812FX::setRgbwPwm() {}
#endif
-//gamma 2.4 lookup table used for color correction
-const byte gammaT[] = {
+//gamma 2.8 lookup table used for color correction
+byte gammaT[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
@@ -984,6 +984,17 @@ const byte gammaT[] = {
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
+uint8_t WS2812FX::gamma8_cal(uint8_t b, float gamma) {
+ return (int)(pow((float)b / 255.0, gamma) * 255 + 0.5);
+}
+
+void WS2812FX::calcGammaTable(float gamma)
+{
+ for (uint16_t i = 0; i < 256; i++) {
+ gammaT[i] = gamma8_cal(i, gamma);
+ }
+}
+
uint8_t WS2812FX::gamma8(uint8_t b)
{
return gammaT[b];
diff --git a/wled00/alexa.cpp b/wled00/alexa.cpp
index 05e460931..d97f0804d 100644
--- a/wled00/alexa.cpp
+++ b/wled00/alexa.cpp
@@ -46,7 +46,7 @@ void onAlexaChange(EspalexaDevice* dev)
bri = briLast;
colorUpdated(NOTIFIER_CALL_MODE_ALEXA);
}
- } else applyMacro(macroAlexaOn);
+ } else applyPreset(macroAlexaOn);
} else if (m == EspalexaDeviceProperty::off)
{
if (!macroAlexaOff)
@@ -57,7 +57,7 @@ void onAlexaChange(EspalexaDevice* dev)
bri = 0;
colorUpdated(NOTIFIER_CALL_MODE_ALEXA);
}
- } else applyMacro(macroAlexaOff);
+ } else applyPreset(macroAlexaOff);
} else if (m == EspalexaDeviceProperty::bri)
{
bri = espalexaDevice->getValue();
diff --git a/wled00/button.cpp b/wled00/button.cpp
index 280a571af..7adbf68bd 100644
--- a/wled00/button.cpp
+++ b/wled00/button.cpp
@@ -11,13 +11,13 @@ void shortPressAction()
toggleOnOff();
colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
} else {
- applyMacro(macroButton);
+ applyPreset(macroButton);
}
}
bool isButtonPressed()
{
- #ifdef BTNPIN
+ #if defined(BTNPIN) && BTNPIN > -1
if (digitalRead(BTNPIN) == LOW) return true;
#endif
#ifdef TOUCHPIN
@@ -29,7 +29,7 @@ bool isButtonPressed()
void handleButton()
{
-#if defined(BTNPIN) || defined(TOUCHPIN)
+#if (defined(BTNPIN) && BTNPIN > -1) || defined(TOUCHPIN)
if (!buttonEnabled) return;
if (isButtonPressed()) //pressed
@@ -41,7 +41,7 @@ void handleButton()
{
if (!buttonLongPressed)
{
- if (macroLongPress) {applyMacro(macroLongPress);}
+ if (macroLongPress) {applyPreset(macroLongPress);}
else _setRandomColor(false,true);
buttonLongPressed = true;
@@ -62,7 +62,7 @@ void handleButton()
else if (!buttonLongPressed) { //short press
if (macroDoublePress)
{
- if (doublePress) applyMacro(macroDoublePress);
+ if (doublePress) applyPreset(macroDoublePress);
else buttonWaitTime = millis();
} else shortPressAction();
}
diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp
new file mode 100644
index 000000000..07afdf603
--- /dev/null
+++ b/wled00/cfg.cpp
@@ -0,0 +1,680 @@
+#include "wled.h"
+
+/*
+ * Serializes and parses the cfg.json and wsec.json settings files, stored in internal FS.
+ * The structure of the JSON is not to be considered an official API and may change without notice.
+ */
+
+//simple macro for ArduinoJSON's or syntax
+#define CJSON(a,b) a = b | a
+
+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;
+ }
+
+ //deserializeJson(doc, json);
+
+ //int rev_major = doc[F("rev")][0]; // 1
+ //int rev_minor = doc[F("rev")][1]; // 0
+
+ //long vid = doc[F("vid")]; // 2010020
+
+ JsonObject id = doc[F("id")];
+ getStringFromJson(cmDNS, id[F("mdns")], 33);
+ getStringFromJson(serverDescription, id[F("name")], 33);
+ getStringFromJson(alexaInvocationName, id[F("inv")], 33);
+
+ JsonObject nw_ins_0 = doc["nw"][F("ins")][0];
+ getStringFromJson(clientSSID, nw_ins_0[F("ssid")], 33);
+ //int nw_ins_0_pskl = nw_ins_0[F("pskl")];
+ //The WiFi PSK is normally not contained in the regular file for security reasons.
+ //If it is present however, we will use it
+ getStringFromJson(clientPass, nw_ins_0["psk"], 65);
+
+ JsonArray nw_ins_0_ip = nw_ins_0[F("ip")];
+ JsonArray nw_ins_0_gw = nw_ins_0[F("gw")];
+ JsonArray nw_ins_0_sn = nw_ins_0[F("sn")];
+
+ for (byte i = 0; i < 4; i++) {
+ CJSON(staticIP[i], nw_ins_0_ip[i]);
+ CJSON(staticGateway[i], nw_ins_0_gw[i]);
+ CJSON(staticSubnet[i], nw_ins_0_sn[i]);
+ }
+
+ JsonObject ap = doc[F("ap")];
+ getStringFromJson(apSSID, ap[F("ssid")], 33);
+ getStringFromJson(apPass, ap["psk"] , 65); //normally not present due to security
+ //int ap_pskl = ap[F("pskl")];
+
+ CJSON(apChannel, ap[F("chan")]);
+ if (apChannel > 13 || apChannel < 1) apChannel = 1;
+
+ CJSON(apHide, ap[F("hide")]);
+ if (apHide > 1) apHide = 1;
+
+ CJSON(apBehavior, ap[F("behav")]);
+
+ /*
+ JsonArray ap_ip = ap[F("ip")];
+ for (byte i = 0; i < 4; i++) {
+ apIP[i] = ap_ip;
+ }*/
+
+ noWifiSleep = doc[F("wifi")][F("sleep")] | !noWifiSleep; // inverted
+ noWifiSleep = !noWifiSleep;
+ //int wifi_phy = doc[F("wifi")][F("phy")]; //force phy mode n?
+
+ JsonObject hw = doc[F("hw")];
+
+ JsonObject hw_led = hw[F("led")];
+ CJSON(ledCount, hw_led[F("total")]);
+ if (ledCount > MAX_LEDS) ledCount = MAX_LEDS;
+
+ CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
+ CJSON(strip.milliampsPerLed, hw_led[F("ledma")]);
+ CJSON(strip.reverseMode, hw_led[F("rev")]);
+
+ JsonObject hw_led_ins_0 = hw_led[F("ins")][0];
+ //bool hw_led_ins_0_en = hw_led_ins_0[F("en")]; // true
+ //int hw_led_ins_0_start = hw_led_ins_0[F("start")]; // 0
+ //int hw_led_ins_0_len = hw_led_ins_0[F("len")]; // 1200
+
+ //int hw_led_ins_0_pin_0 = hw_led_ins_0[F("pin")][0]; // 2
+
+ strip.colorOrder = hw_led_ins_0[F("order")];
+ //bool hw_led_ins_0_rev = hw_led_ins_0[F("rev")]; // false
+ skipFirstLed = hw_led_ins_0[F("skip")]; // 0
+ useRGBW = (hw_led_ins_0[F("type")] == TYPE_SK6812_RGBW);
+
+ JsonObject hw_btn_ins_0 = hw[F("btn")][F("ins")][0];
+ buttonEnabled = hw_btn_ins_0[F("en")] | buttonEnabled;
+
+ //int hw_btn_ins_0_pin_0 = hw_btn_ins_0[F("pin")][0]; // 0
+
+ JsonArray hw_btn_ins_0_macros = hw_btn_ins_0[F("macros")];
+ CJSON(macroButton, hw_btn_ins_0_macros[0]);
+ 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[F("type")]; // 0
+
+ //int hw_ir_pin = hw[F("ir")][F("pin")]; // 4
+ CJSON(irEnabled, hw[F("ir")][F("type")]); // 0
+
+ //int hw_relay_pin = hw[F("relay")][F("pin")]; // 12
+ //bool hw_relay_rev = hw[F("relay")][F("rev")]; // false
+
+ //int hw_status_pin = hw[F("status")][F("pin")]; // -1
+
+ JsonObject light = doc[F("light")];
+ CJSON(briMultiplier, light[F("scale-bri")]);
+ CJSON(strip.paletteBlend, light[F("pal-mode")]);
+
+ float light_gc_bri = light[F("gc")]["bri"];
+ float light_gc_col = light[F("gc")][F("col")]; // 2.8
+ if (light_gc_bri > 1.5) strip.gammaCorrectBri = true;
+ else if (light_gc_bri > 0.5) strip.gammaCorrectBri = false;
+ if (light_gc_col > 1.5) strip.gammaCorrectCol = true;
+ else if (light_gc_col > 0.5) strip.gammaCorrectCol = false;
+
+ JsonObject light_tr = light[F("tr")];
+ CJSON(fadeTransition, light_tr[F("mode")]);
+ int tdd = light_tr[F("dur")] | -1;
+ if (tdd >= 0) transitionDelayDefault = tdd * 100;
+ CJSON(strip.paletteFade, light_tr[F("pal")]);
+
+ JsonObject light_nl = light["nl"];
+ CJSON(nightlightMode, light_nl[F("mode")]);
+ CJSON(nightlightDelayMinsDefault, light_nl[F("dur")]);
+ nightlightDelayMins = nightlightDelayMinsDefault;
+
+ CJSON(nightlightTargetBri, light_nl[F("tbri")]);
+ CJSON(macroNl, light_nl[F("macro")]);
+
+ JsonObject def = doc[F("def")];
+ CJSON(bootPreset, def[F("ps")]);
+ CJSON(turnOnAtBoot, def["on"]); // true
+ CJSON(briS, def["bri"]); // 128
+ if (briS == 0) briS = 255;
+
+ JsonObject def_cy = def[F("cy")];
+ CJSON(presetCyclingEnabled, def_cy["on"]);
+
+ CJSON(presetCycleMin, def_cy[F("range")][0]);
+ CJSON(presetCycleMax, def_cy[F("range")][1]);
+
+ tdd = def_cy[F("dur")] | -1;
+ if (tdd >= 0) presetCycleTime = tdd * 100;
+
+ JsonObject interfaces = doc["if"];
+
+ JsonObject if_sync = interfaces[F("sync")];
+ CJSON(udpPort, if_sync[F("port0")]); // 21324
+ CJSON(udpPort2, if_sync[F("port1")]); // 65506
+
+ JsonObject if_sync_recv = if_sync[F("recv")];
+ CJSON(receiveNotificationBrightness, if_sync_recv["bri"]);
+ CJSON(receiveNotificationColor, if_sync_recv[F("col")]);
+ CJSON(receiveNotificationEffects, if_sync_recv[F("fx")]);
+ receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
+
+ JsonObject if_sync_send = if_sync[F("send")];
+ CJSON(notifyDirectDefault, if_sync_send[F("dir")]);
+ notifyDirect = notifyDirectDefault;
+ CJSON(notifyButton, if_sync_send[F("btn")]);
+ CJSON(notifyAlexa, if_sync_send[F("va")]);
+ CJSON(notifyHue, if_sync_send[F("hue")]);
+ CJSON(notifyMacro, if_sync_send[F("macro")]);
+ CJSON(notifyTwice, if_sync_send[F("twice")]);
+
+ JsonObject if_live = interfaces[F("live")];
+ CJSON(receiveDirect, if_live[F("en")]);
+ CJSON(e131Port, if_live[F("port")]); // 5568
+ CJSON(e131Multicast, if_live[F("mc")]);
+
+ JsonObject if_live_dmx = if_live[F("dmx")];
+ CJSON(e131Universe, if_live_dmx[F("uni")]);
+ CJSON(e131SkipOutOfSequence, if_live_dmx[F("seqskip")]);
+ CJSON(DMXAddress, if_live_dmx[F("addr")]);
+ CJSON(DMXMode, if_live_dmx[F("mode")]);
+
+ tdd = if_live[F("timeout")] | -1;
+ if (tdd >= 0) realtimeTimeoutMs = tdd * 100;
+ CJSON(arlsForceMaxBri, if_live[F("maxbri")]);
+ CJSON(arlsDisableGammaCorrection, if_live[F("no-gc")]); // false
+ CJSON(arlsOffset, if_live[F("offset")]); // 0
+
+ CJSON(alexaEnabled, interfaces[F("va")][F("alexa")]); // false
+
+ CJSON(macroAlexaOn, interfaces[F("va")][F("macros")][0]);
+ CJSON(macroAlexaOff, interfaces[F("va")][F("macros")][1]);
+
+ const char* apikey = interfaces[F("blynk")][F("token")] | "Hidden";
+ tdd = strnlen(apikey, 36);
+ if (tdd > 20 || tdd == 0)
+ getStringFromJson(blynkApiKey, apikey, 36); //normally not present due to security
+
+ JsonObject if_mqtt = interfaces[F("mqtt")];
+ CJSON(mqttEnabled, if_mqtt[F("en")]);
+ getStringFromJson(mqttServer, if_mqtt[F("broker")], 33);
+ CJSON(mqttPort, if_mqtt[F("port")]); // 1883
+ getStringFromJson(mqttUser, if_mqtt[F("user")], 41);
+ getStringFromJson(mqttPass, if_mqtt["psk"], 41); //normally not present due to security
+ getStringFromJson(mqttClientID, if_mqtt[F("cid")], 41);
+
+ getStringFromJson(mqttDeviceTopic, if_mqtt[F("topics")][F("device")], 33); // "wled/test"
+ getStringFromJson(mqttGroupTopic, if_mqtt[F("topics")][F("group")], 33); // ""
+
+ JsonObject if_hue = interfaces[F("hue")];
+ CJSON(huePollingEnabled, if_hue[F("en")]);
+ CJSON(huePollLightId, if_hue[F("id")]);
+ tdd = if_hue[F("iv")] | -1;
+ if (tdd >= 2) huePollIntervalMs = tdd * 100;
+
+ JsonObject if_hue_recv = if_hue[F("recv")];
+ CJSON(hueApplyOnOff, if_hue_recv["on"]);
+ CJSON(hueApplyBri, if_hue_recv["bri"]);
+ CJSON(hueApplyColor, if_hue_recv[F("col")]);
+
+ JsonArray if_hue_ip = if_hue[F("ip")];
+
+ for (byte i = 0; i < 4; i++)
+ CJSON(hueIP[i], if_hue_ip[i]);
+
+ JsonObject if_ntp = interfaces[F("ntp")];
+ CJSON(ntpEnabled, if_ntp[F("en")]);
+ getStringFromJson(ntpServerName, if_ntp[F("host")], 33); // "1.wled.pool.ntp.org"
+ CJSON(currentTimezone, if_ntp[F("tz")]);
+ CJSON(utcOffsetSecs, if_ntp[F("offset")]);
+ CJSON(useAMPM, if_ntp[F("ampm")]);
+
+ JsonObject ol = doc[F("ol")];
+ CJSON(overlayDefault ,ol[F("clock")]); // 0
+ CJSON(countdownMode, ol[F("cntdwn")]);
+ overlayCurrent = overlayDefault;
+
+ JsonArray ol_cntdwn = ol[F("cntdwn")]; //[20,12,31,23,59,59]
+
+ //timed macro rules
+ JsonObject tm = doc[F("timers")];
+ JsonObject cntdwn = tm[F("cntdwn")];
+ JsonArray cntdwn_goal = cntdwn[F("goal")];
+ CJSON(countdownYear, cntdwn_goal[0]);
+ CJSON(countdownMonth, cntdwn_goal[1]);
+ CJSON(countdownDay, cntdwn_goal[2]);
+ CJSON(countdownHour, cntdwn_goal[3]);
+ CJSON(countdownMin, cntdwn_goal[4]);
+ CJSON(countdownSec, cntdwn_goal[5]);
+ CJSON(macroCountdown, cntdwn[F("macro")]);
+
+ JsonArray timers = tm[F("ins")];
+ uint8_t it = 0;
+ for (JsonObject timer : timers) {
+ if (it > 7) break;
+ CJSON(timerHours[it], timer[F("hour")]);
+ CJSON(timerMinutes[it], timer[F("min")]);
+ CJSON(timerMacro[it], timer[F("macro")]);
+
+ byte dowPrev = timerWeekday[it];
+ bool actPrev = timerWeekday[it] & 0x01;
+ CJSON(timerWeekday[it], timer[F("dow")]);
+ if (timerWeekday[it] != dowPrev) { //present in JSON
+ timerWeekday[it] <<= 1; //add active bit
+ bool act = timer[F("en")] | actPrev;
+ if (act) timerWeekday[it]++;
+ }
+
+ it++;
+ }
+
+ JsonObject ota = doc["ota"];
+ const char* pwd = ota["psk"]; //normally not present due to security
+
+ bool pwdCorrect = !otaLock; //always allow access if ota not locked
+ if (pwd != nullptr && strncmp(otaPass, pwd, 33) == 0) pwdCorrect = true;
+
+ if (pwdCorrect) { //only accept these values from cfg.json if ota is unlocked (else from wsec.json)
+ CJSON(otaLock, ota[F("lock")]);
+ CJSON(wifiLock, ota[F("lock-wifi")]);
+ CJSON(aOtaEnabled, ota[F("aota")]);
+ getStringFromJson(otaPass, pwd, 33); //normally not present due to security
+ }
+
+ #ifdef WLED_ENABLE_DMX
+ JsonObject dmx = doc["dmx"];
+ CJSON(DMXChannels, dmx[F("chan")]);
+ CJSON(DMXGap,dmx[F("gap")]);
+ CJSON(DMXStart, dmx[F("start")]);
+ CJSON(DMXStartLED,dmx[F("start-led")]);
+
+ JsonArray dmx_fixmap = dmx.createNestedArray("fixmap");
+ it = 0;
+ for (int i : dmx_fixmap) {
+ if (it > 14) break;
+ DMXFixtureMap[i] = i;
+ it++;
+ }
+ #endif
+
+ JsonObject usermods_settings = doc["um"];
+ usermods.readFromConfig(usermods_settings);
+}
+
+void serializeConfig() {
+ serializeConfigSec();
+
+ DEBUG_PRINTLN(F("Writing settings to /cfg.json..."));
+
+ DynamicJsonDocument doc(JSON_BUFFER_SIZE);
+
+ //{ //scope this to reduce stack size
+ JsonArray rev = doc.createNestedArray("rev");
+ rev.add(1); //major settings revision
+ rev.add(0); //minor settings revision
+
+ doc[F("vid")] = VERSION;
+
+ JsonObject id = doc.createNestedObject("id");
+ id[F("mdns")] = cmDNS;
+ id[F("name")] = serverDescription;
+ id[F("inv")] = alexaInvocationName;
+
+ JsonObject nw = doc.createNestedObject("nw");
+
+ JsonArray nw_ins = nw.createNestedArray("ins");
+
+ JsonObject nw_ins_0 = nw_ins.createNestedObject();
+ nw_ins_0[F("ssid")] = clientSSID;
+ nw_ins_0[F("pskl")] = strlen(clientPass);
+
+ JsonArray nw_ins_0_ip = nw_ins_0.createNestedArray("ip");
+ JsonArray nw_ins_0_gw = nw_ins_0.createNestedArray("gw");
+ JsonArray nw_ins_0_sn = nw_ins_0.createNestedArray("sn");
+
+ for (byte i = 0; i < 4; i++) {
+ nw_ins_0_ip.add(staticIP[i]);
+ nw_ins_0_gw.add(staticGateway[i]);
+ nw_ins_0_sn.add(staticSubnet[i]);
+ }
+
+ JsonObject ap = doc.createNestedObject("ap");
+ ap[F("ssid")] = apSSID;
+ ap[F("pskl")] = strlen(apPass);
+ ap[F("chan")] = apChannel;
+ ap[F("behav")] = apBehavior;
+
+ JsonArray ap_ip = ap.createNestedArray("ip");
+ ap_ip.add(4);
+ ap_ip.add(3);
+ ap_ip.add(2);
+ ap_ip.add(1);
+
+ JsonObject wifi = doc.createNestedObject("wifi");
+ wifi[F("sleep")] = !noWifiSleep;
+ wifi[F("phy")] = 1;
+
+ JsonObject hw = doc.createNestedObject("hw");
+
+ JsonObject hw_led = hw.createNestedObject("led");
+ hw_led[F("total")] = ledCount;
+ hw_led[F("maxpwr")] = strip.ablMilliampsMax;
+ hw_led[F("ledma")] = strip.milliampsPerLed;
+ hw_led[F("rev")] = strip.reverseMode;
+
+ JsonArray hw_led_ins = hw_led.createNestedArray("ins");
+
+ JsonObject hw_led_ins_0 = hw_led_ins.createNestedObject();
+ hw_led_ins_0[F("en")] = true;
+ hw_led_ins_0[F("start")] = 0;
+ hw_led_ins_0[F("len")] = ledCount;
+ JsonArray hw_led_ins_0_pin = hw_led_ins_0.createNestedArray("pin");
+ hw_led_ins_0_pin.add(LEDPIN);
+ #ifdef DATAPIN
+ hw_led_ins_0_pin.add(DATAPIN);
+ #endif
+ hw_led_ins_0[F("order")] = strip.colorOrder; //color order
+ hw_led_ins_0[F("rev")] = false;
+ hw_led_ins_0[F("skip")] = skipFirstLed ? 1 : 0;
+
+ //this is very crude and temporary
+ byte ledType = TYPE_WS2812_RGB;
+ if (useRGBW) ledType = TYPE_SK6812_RGBW;
+ #ifdef USE_WS2801
+ ledType = TYPE_WS2801;
+ #endif
+ #ifdef USE_APA102
+ ledType = TYPE_APA102;
+ #endif
+ #ifdef USE_LPD8806
+ ledType = TYPE_LPD8806;
+ #endif
+ #ifdef USE_P9813
+ ledType = TYPE_P9813;
+ #endif
+ #ifdef USE_TM1814
+ ledType = TYPE_TM1814;
+ #endif
+
+ hw_led_ins_0[F("type")] = ledType;
+
+ JsonObject hw_btn = hw.createNestedObject("btn");
+
+ JsonArray hw_btn_ins = hw_btn.createNestedArray("ins");
+
+ #if defined(BTNPIN) && BTNPIN > -1
+ JsonObject hw_btn_ins_0 = hw_btn_ins.createNestedObject();
+ hw_btn_ins_0[F("type")] = (buttonEnabled) ? BTN_TYPE_PUSH : BTN_TYPE_NONE;
+
+ JsonArray hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin");
+ hw_btn_ins_0_pin.add(BTNPIN);
+
+ JsonArray hw_btn_ins_0_macros = hw_btn_ins_0.createNestedArray("macros");
+ hw_btn_ins_0_macros.add(macroButton);
+ hw_btn_ins_0_macros.add(macroLongPress);
+ hw_btn_ins_0_macros.add(macroDoublePress);
+ #endif
+
+ #if defined(IRPIN) && IRPIN > -1
+ JsonObject hw_ir = hw.createNestedObject("ir");
+ hw_ir[F("pin")] = IR_PIN;
+ hw_ir[F("type")] = 0;
+ #endif
+
+ #if defined(RLYPIN) && RLYPIN > -1
+ JsonObject hw_relay = hw.createNestedObject("relay");
+ hw_relay[F("pin")] = RLYPIN;
+ hw_relay[F("rev")] = (RLYMDE) ? false : true;
+ JsonObject hw_status = hw.createNestedObject("status");
+ hw_status[F("pin")] = -1;
+ #endif
+
+ JsonObject light = doc.createNestedObject("light");
+ light[F("scale-bri")] = briMultiplier;
+ light[F("pal-mode")] = strip.paletteBlend;
+
+ JsonObject light_gc = light.createNestedObject("gc");
+ light_gc["bri"] = (strip.gammaCorrectBri) ? 2.8 : 1.0;
+ light_gc[F("col")] = (strip.gammaCorrectCol) ? 2.8 : 1.0;
+
+ JsonObject light_tr = light.createNestedObject("tr");
+ light_tr[F("mode")] = fadeTransition;
+ light_tr[F("dur")] = transitionDelayDefault / 100;
+ light_tr[F("pal")] = strip.paletteFade;
+
+ JsonObject light_nl = light.createNestedObject("nl");
+ light_nl[F("mode")] = nightlightMode;
+ light_nl[F("dur")] = nightlightDelayMinsDefault;
+ light_nl[F("tbri")] = nightlightTargetBri;
+ light_nl[F("macro")] = macroNl;
+
+ JsonObject def = doc.createNestedObject("def");
+ def[F("ps")] = bootPreset;
+ def["on"] = turnOnAtBoot;
+ def["bri"] = briS;
+
+ //to be removed once preset cycles are presets
+ if (saveCurrPresetCycConf) {
+ JsonObject def_cy = def.createNestedObject("cy");
+ def_cy["on"] = presetCyclingEnabled;
+
+ JsonArray def_cy_range = def_cy.createNestedArray("range");
+ def_cy_range.add(presetCycleMin);
+ def_cy_range.add(presetCycleMax);
+ def_cy[F("dur")] = presetCycleTime / 100;
+ }
+
+ JsonObject interfaces = doc.createNestedObject("if");
+
+ JsonObject if_sync = interfaces.createNestedObject("sync");
+ if_sync[F("port0")] = udpPort;
+ if_sync[F("port1")] = udpPort2;
+
+ JsonObject if_sync_recv = if_sync.createNestedObject("recv");
+ if_sync_recv["bri"] = receiveNotificationBrightness;
+ if_sync_recv[F("col")] = receiveNotificationColor;
+ if_sync_recv[F("fx")] = receiveNotificationEffects;
+
+ JsonObject if_sync_send = if_sync.createNestedObject("send");
+ if_sync_send[F("dir")] = notifyDirect;
+ if_sync_send[F("btn")] = notifyButton;
+ if_sync_send[F("va")] = notifyAlexa;
+ if_sync_send[F("hue")] = notifyHue;
+ if_sync_send[F("macro")] = notifyMacro;
+ if_sync_send[F("twice")] = notifyTwice;
+
+ JsonObject if_live = interfaces.createNestedObject("live");
+ if_live[F("en")] = receiveDirect;
+ if_live[F("port")] = e131Port;
+ if_live[F("mc")] = e131Multicast;
+
+ JsonObject if_live_dmx = if_live.createNestedObject("dmx");
+ if_live_dmx[F("uni")] = e131Universe;
+ if_live_dmx[F("seqskip")] = e131SkipOutOfSequence;
+ if_live_dmx[F("addr")] = DMXAddress;
+ if_live_dmx[F("mode")] = DMXMode;
+ if_live[F("timeout")] = realtimeTimeoutMs / 100;
+ if_live[F("maxbri")] = arlsForceMaxBri;
+ if_live[F("no-gc")] = arlsDisableGammaCorrection;
+ if_live[F("offset")] = arlsOffset;
+
+ JsonObject if_va = interfaces.createNestedObject("va");
+ if_va[F("alexa")] = alexaEnabled;
+
+ JsonArray if_va_macros = if_va.createNestedArray("macros");
+ if_va_macros.add(macroAlexaOn);
+ if_va_macros.add(macroAlexaOff);
+ JsonObject if_blynk = interfaces.createNestedObject("blynk");
+ if_blynk[F("token")] = strlen(blynkApiKey) ? "Hidden":"";
+
+ JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
+ if_mqtt[F("en")] = mqttEnabled;
+ if_mqtt[F("broker")] = mqttServer;
+ if_mqtt[F("port")] = mqttPort;
+ if_mqtt[F("user")] = mqttUser;
+ if_mqtt[F("pskl")] = strlen(mqttPass);
+ if_mqtt[F("cid")] = mqttClientID;
+
+ JsonObject if_mqtt_topics = if_mqtt.createNestedObject("topics");
+ if_mqtt_topics[F("device")] = mqttDeviceTopic;
+ if_mqtt_topics[F("group")] = mqttGroupTopic;
+
+ JsonObject if_hue = interfaces.createNestedObject("hue");
+ if_hue[F("en")] = huePollingEnabled;
+ if_hue[F("id")] = huePollLightId;
+ if_hue[F("iv")] = huePollIntervalMs / 100;
+
+ JsonObject if_hue_recv = if_hue.createNestedObject("recv");
+ if_hue_recv["on"] = hueApplyOnOff;
+ if_hue_recv["bri"] = hueApplyBri;
+ if_hue_recv[F("col")] = hueApplyColor;
+
+ JsonArray if_hue_ip = if_hue.createNestedArray("ip");
+ for (byte i = 0; i < 4; i++) {
+ if_hue_ip.add(hueIP[i]);
+ }
+
+ JsonObject if_ntp = interfaces.createNestedObject("ntp");
+ if_ntp[F("en")] = ntpEnabled;
+ if_ntp[F("host")] = ntpServerName;
+ if_ntp[F("tz")] = currentTimezone;
+ if_ntp[F("offset")] = utcOffsetSecs;
+ if_ntp[F("ampm")] = useAMPM;
+
+ JsonObject ol = doc.createNestedObject("ol");
+ ol[F("clock")] = overlayDefault;
+ ol[F("cntdwn")] = countdownMode;
+
+ JsonObject timers = doc.createNestedObject("timers");
+
+ JsonObject cntdwn = timers.createNestedObject("cntdwn");
+ JsonArray goal = cntdwn.createNestedArray("goal");
+ goal.add(countdownYear); goal.add(countdownMonth); goal.add(countdownDay);
+ goal.add(countdownHour); goal.add(countdownMin); goal.add(countdownSec);
+ cntdwn[F("macro")] = macroCountdown;
+
+ JsonArray timers_ins = timers.createNestedArray("ins");
+
+ for (byte i = 0; i < 8; i++) {
+ if (timerMacro[i] == 0 && timerHours[i] == 0 && timerMinutes[i] == 0) continue;
+ JsonObject timers_ins0 = timers_ins.createNestedObject();
+ timers_ins0[F("en")] = (timerWeekday[i] & 0x01);
+ timers_ins0[F("hour")] = timerHours[i];
+ timers_ins0[F("min")] = timerMinutes[i];
+ timers_ins0[F("macro")] = timerMacro[i];
+ timers_ins0[F("dow")] = timerWeekday[i] >> 1;
+ }
+
+ JsonObject ota = doc.createNestedObject("ota");
+ ota[F("lock")] = otaLock;
+ ota[F("lock-wifi")] = wifiLock;
+ ota[F("pskl")] = strlen(otaPass);
+ ota[F("aota")] = aOtaEnabled;
+
+ #ifdef WLED_ENABLE_DMX
+ JsonObject dmx = doc.createNestedObject("dmx");
+ dmx[F("chan")] = DMXChannels;
+ dmx[F("gap")] = DMXGap;
+ dmx[F("start")] = DMXStart;
+ dmx[F("start-led")] = DMXStartLED;
+
+ JsonArray dmx_fixmap = dmx.createNestedArray("fixmap");
+ for (byte i = 0; i < 15; i++)
+ dmx_fixmap.add(DMXFixtureMap[i]);
+ #endif
+ //}
+
+ JsonObject usermods_settings = doc.createNestedObject("um");
+ usermods.addToConfig(usermods_settings);
+
+ File f = WLED_FS.open("/cfg.json", "w");
+ if (f) serializeJson(doc, f);
+ f.close();
+}
+
+//settings in /wsec.json, not accessible via webserver, for passwords and tokens
+bool deserializeConfigSec() {
+ DEBUG_PRINTLN(F("Reading settings from /wsec.json..."));
+
+ DynamicJsonDocument doc(JSON_BUFFER_SIZE);
+
+ bool success = readObjectFromFile("/wsec.json", nullptr, &doc);
+ if (!success) return false;
+
+ JsonObject nw_ins_0 = doc["nw"][F("ins")][0];
+ getStringFromJson(clientPass, nw_ins_0["psk"], 65);
+
+ JsonObject ap = doc[F("ap")];
+ getStringFromJson(apPass, ap["psk"] , 65);
+
+ JsonObject interfaces = doc["if"];
+
+ const char* apikey = interfaces["blynk"][F("token")] | "Hidden";
+ int tdd = strnlen(apikey, 36);
+ if (tdd > 20 || tdd == 0)
+ getStringFromJson(blynkApiKey, apikey, 36);
+
+ JsonObject if_mqtt = interfaces[F("mqtt")];
+ getStringFromJson(mqttPass, if_mqtt["psk"], 41);
+
+ getStringFromJson(hueApiKey, interfaces[F("hue")][F("key")], 47);
+
+ JsonObject ota = doc["ota"];
+ getStringFromJson(otaPass, ota[F("pwd")], 33);
+ CJSON(otaLock, ota[F("lock")]);
+ CJSON(wifiLock, ota[F("lock-wifi")]);
+ CJSON(aOtaEnabled, ota[F("aota")]);
+
+ return true;
+}
+
+void serializeConfigSec() {
+ DEBUG_PRINTLN(F("Writing settings to /wsec.json..."));
+
+ DynamicJsonDocument doc(JSON_BUFFER_SIZE);
+
+ JsonObject nw = doc.createNestedObject("nw");
+
+ JsonArray nw_ins = nw.createNestedArray("ins");
+
+ JsonObject nw_ins_0 = nw_ins.createNestedObject();
+ nw_ins_0["psk"] = clientPass;
+
+ JsonObject ap = doc.createNestedObject("ap");
+ ap["psk"] = apPass;
+
+ JsonObject interfaces = doc.createNestedObject("if");
+ JsonObject if_blynk = interfaces.createNestedObject("blynk");
+ if_blynk[F("token")] = blynkApiKey;
+ JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
+ if_mqtt["psk"] = mqttPass;
+ JsonObject if_hue = interfaces.createNestedObject("hue");
+ if_hue[F("key")] = hueApiKey;
+
+ JsonObject ota = doc.createNestedObject("ota");
+ ota[F("pwd")] = otaPass;
+ ota[F("lock")] = otaLock;
+ ota[F("lock-wifi")] = wifiLock;
+ ota[F("aota")] = aOtaEnabled;
+
+ File f = WLED_FS.open("/wsec.json", "w");
+ if (f) serializeJson(doc, f);
+ f.close();
+}
\ No newline at end of file
diff --git a/wled00/colors.cpp b/wled00/colors.cpp
index 7fc3a8aa0..0996de07f 100644
--- a/wled00/colors.cpp
+++ b/wled00/colors.cpp
@@ -177,7 +177,7 @@ void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.develo
}
#endif // WLED_DISABLE_HUESYNC
-
+//RRGGBB / WWRRGGBB order for hex
void colorFromDecOrHexString(byte* rgb, char* in)
{
if (in[0] == 0) return;
@@ -198,6 +198,27 @@ void colorFromDecOrHexString(byte* rgb, char* in)
rgb[2] = c & 0xFF;
}
+//contrary to the colorFromDecOrHexString() function, this uses the more standard RRGGBB / RRGGBBWW order
+bool colorFromHexString(byte* rgb, const char* in) {
+ if (in == nullptr) return false;
+ size_t inputSize = strnlen(in, 9);
+ if (inputSize != 6 && inputSize != 8) return false;
+
+ uint32_t c = strtoul(in, NULL, 16);
+
+ if (inputSize == 6) {
+ rgb[0] = (c >> 16) & 0xFF;
+ rgb[1] = (c >> 8) & 0xFF;
+ rgb[2] = c & 0xFF;
+ } else {
+ rgb[0] = (c >> 24) & 0xFF;
+ rgb[1] = (c >> 16) & 0xFF;
+ rgb[2] = (c >> 8) & 0xFF;
+ rgb[3] = c & 0xFF;
+ }
+ return true;
+}
+
float minf (float v, float w)
{
if (w > v) return v;
diff --git a/wled00/const.h b/wled00/const.h
index a68101201..8dc1a2860 100644
--- a/wled00/const.h
+++ b/wled00/const.h
@@ -72,20 +72,46 @@
#define DMX_MODE_MULTIPLE_RGB 4 //every LED is addressed with its own RGB (ledCount * 3 channels)
#define DMX_MODE_MULTIPLE_DRGB 5 //every LED is addressed with its own RGB and share a master dimmer (ledCount * 3 + 1 channels)
-//Light capability byte (unused)
+//Light capability byte (unused) 0bRRCCTTTT
+//bits 0/1/2/3: specifies a type of LED driver. A single "driver" may have different chip models but must have the same protocol/behavior
+//bits 4/5: specifies the class of LED driver - 0b00 (dec. 0-15) unconfigured/reserved
+// - 0b01 (dec. 16-31) digital (data pin only)
+// - 0b10 (dec. 32-47) analog (PWM)
+// - 0b11 (dec. 48-63) digital (data + clock / SPI)
+//bits 6/7 are reserved and set to 0b00
+
#define TYPE_NONE 0 //light is not configured
#define TYPE_RESERVED 1 //unused. Might indicate a "virtual" light
-#define TYPE_WS2812_RGB 2
-#define TYPE_SK6812_RGBW 3
-#define TYPE_WS2812_WWA 4 //amber + warm + cold white
-#define TYPE_WS2801 5
-#define TYPE_ANALOG_1CH 6 //single channel PWM. Uses value of brightest RGBW channel
-#define TYPE_ANALOG_2CH 7 //analog WW + CW
-#define TYPE_ANALOG_3CH 8 //analog RGB
-#define TYPE_ANALOG_4CH 9 //analog RGBW
-#define TYPE_ANALOG_5CH 10 //analog RGB + WW + CW
-#define TYPE_APA102 11
-#define TYPE_LPD8806 12
+//Digital types (data pin only) (16-31)
+#define TYPE_WS2812_1CH 20 //white-only chips
+#define TYPE_WS2812_WWA 21 //amber + warm + cold white
+#define TYPE_WS2812_RGB 22
+#define TYPE_GS8608 23 //same driver as WS2812, but will require signal 2x per second (else displays test pattern)
+#define TYPE_WS2811_400KHZ 24 //half-speed WS2812 protocol, used by very old WS2811 units
+#define TYPE_SK6812_RGBW 30
+//"Analog" types (PWM) (32-47)
+#define TYPE_ONOFF 40 //binary output (relays etc.)
+#define TYPE_ANALOG_1CH 41 //single channel PWM. Uses value of brightest RGBW channel
+#define TYPE_ANALOG_2CH 42 //analog WW + CW
+#define TYPE_ANALOG_3CH 43 //analog RGB
+#define TYPE_ANALOG_4CH 44 //analog RGBW
+#define TYPE_ANALOG_5CH 45 //analog RGB + WW + CW
+//Digital types (data + clock / SPI) (48-63)
+#define TYPE_WS2801 50
+#define TYPE_APA102 51
+#define TYPE_LPD8806 52
+#define TYPE_P9813 53
+#define TYPE_TM1814 54
+
+
+//Button type
+#define BTN_TYPE_NONE 0
+#define BTN_TYPE_RESERVED 1
+#define BTN_TYPE_PUSH 2
+#define BTN_TYPE_PUSH_ACT_HIGH 3 //not implemented
+#define BTN_TYPE_SWITCH 4 //not implemented
+#define BTN_TYPE_SWITCH_ACT_HIGH 5 //not implemented
+
//Hue error codes
#define HUE_ERROR_INACTIVE 0
@@ -105,19 +131,29 @@
#define SEG_OPTION_FREEZE 5 //Segment contents will not be refreshed
#define SEG_OPTION_TRANSITIONAL 7
+// WLED Error modes
+#define ERR_NONE 0 // All good :)
+#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?)
+#define ERR_JSON 9 // JSON parsing failed (input too large?)
+#define ERR_FS_BEGIN 10 // Could not init filesystem (no partition?)
+#define ERR_FS_QUOTA 11 // The FS is full or the maximum file size is reached
+#define ERR_FS_PLOAD 12 // It was attempted to load a preset that does not exist
+#define ERR_FS_GENERAL 19 // A general unspecified filesystem error occured
+
//Timer mode types
#define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness
#define NL_MODE_FADE 1 //Fade to target brightness gradually
#define NL_MODE_COLORFADE 2 //Fade to target brightness and secondary color gradually
#define NL_MODE_SUN 3 //Sunrise/sunset. Target brightness is set immediately, then Sunrise effect is started. Max 60 min.
-//EEPROM size
-#define EEPSIZE 2560 //Maximum is 4096
#define NTP_PACKET_SIZE 48
-// maximum number of LEDs - MAX_LEDS is coming from the JSON response getting too big, MAX_LEDS_DMA will become a timing issue
+// maximum number of LEDs - more than 1500 LEDs (or 500 DMA "LEDPIN 3" driven ones) will cause a low memory condition on ESP8266
+#ifndef MAX_LEDS
#define MAX_LEDS 1500
+#endif
+
#define MAX_LEDS_DMA 500
// string temp buffer (now stored in stack locally)
@@ -127,6 +163,7 @@
#define ABL_MILLIAMPS_DEFAULT 850; // auto lower brightness to stay close to milliampere limit
+
#define TOUCH_THRESHOLD 32 // limit to recognize a touch, higher value means more sensitive
// Size of buffer for API JSON object (increase for more segments)
diff --git a/wled00/data/404.html b/wled00/data/404.htm
similarity index 97%
rename from wled00/data/404.html
rename to wled00/data/404.htm
index 92f87d3d0..1b7c95fc0 100644
--- a/wled00/data/404.html
+++ b/wled00/data/404.htm
@@ -35,7 +35,6 @@
color: white;
border: 0px solid white;
border-radius: 25px;
- filter: drop-shadow(0px 0px 1px #000);
}
diff --git a/wled00/data/index.htm b/wled00/data/index.htm
index 8b532de8e..13da23c45 100644
--- a/wled00/data/index.htm
+++ b/wled00/data/index.htm
@@ -204,7 +204,6 @@ button {
.tab {
background-color: transparent;
color: var(--c-d);
- /*filter: drop-shadow(0px 0px 0px #111);*/
}
.bot {
@@ -254,7 +253,7 @@ button {
width: calc(var(--n)*100%);
height: calc(100% - var(--tp) - var(--bh));
margin-top: var(--tp);
- transform: translate(calc(var(--tx, 0px) + var(--i, 0)/var(--n)*-100%));
+ transform: translate(calc(var(--i, 0)/var(--n)*-100%));
overscroll-behavior: none;
}
@@ -324,6 +323,7 @@ button {
#fxb0 {
margin-bottom: 2px;
+ filter: drop-shadow(0 0 1px #000);
}
.first {
@@ -511,7 +511,6 @@ input[type=range]::-moz-range-thumb {
#picker {
margin: 10px auto;
width: 260px;
- filter: drop-shadow(0px 0px 1px #000);
}
#rgbwrap {
@@ -527,7 +526,6 @@ input[type=range]::-moz-range-thumb {
color: var(--c-f);
border: 0px solid white;
border-radius: 25px;
- filter: drop-shadow(0px 0px 1px #000);
transition-duration: 0.5s;
-webkit-backface-visibility: hidden;
-webkit-transform:translate3d(0,0,0);
@@ -548,6 +546,9 @@ input[type=range]::-moz-range-thumb {
.btna-icon {
margin: 0px;
}
+.btn-p {
+ width: 216px;
+}
#qcs-w {
margin-top: 10px;
@@ -600,7 +601,7 @@ input[type=number], input[type=text] {
padding: 8px;
margin: 6px 6px 6px 0;
font-size: 19px;
- transition: background 0.2s;
+ transition: background-color 0.2s;
outline: none;
width: 50px;
-webkit-appearance: textfield;
@@ -608,12 +609,37 @@ input[type=number], input[type=text] {
appearance: textfield;
}
+textarea {
+ background: var(--c-2);
+ color: var(--c-f);
+ width: 236px;
+ height: 90px;
+ border-radius: 5px;
+ border: 2px solid #555;
+ outline: none;
+ resize: none;
+ font-size: 19px;
+}
+
+::selection {
+ background: var(--c-b);
+}
+
input[type=text] {
width: 100px;
border-radius: 25px;
text-align: center;
}
+.ptxt {
+ width: 200px !important;
+ margin: 26px 0 6px 12px !important;
+}
+
+.stxt {
+ width: 50px !important;
+}
+
input[type=number]:focus, input[type=text]:focus {
background: var(--c-6);
}
@@ -629,13 +655,22 @@ input[type=number]::-webkit-outer-spin-button {
.segname {
position: absolute;
- top: 10px;
+ top: 0px;
left: 50%;
+ padding: 9px 0;
transform: translateX(-50%);
white-space: nowrap;
cursor: pointer;
}
+.pname {
+ width: 208px;
+ padding: 8px 0;
+ text-align: center;
+ overflow: hidden;
+ text-overflow: clip;
+}
+
.newseg {
cursor: default;
}
@@ -649,41 +684,28 @@ input[type=number]::-webkit-outer-spin-button {
margin: 6px;
}
-.rect {
- border-radius: 5px;
-}
-
.psts {
- background-color: var(--c-2);
- color: var(--c-8);
- cursor: default;
-}
-.stored {
background-color: var(--c-3);
color: var(--c-f);
cursor: pointer;
-}
-.saving {
- background-color: var(--c-3);
- color: var(--c-f);
- cursor: pointer;
-}
-.stored.saving {
- background-color: var(--c-r);
- color: var(--c-f);
+ padding: 2px 0 0 0;
+ height: 40px;
}
.cnf {
- position: absolute;
- top: 66px;
- right: 28px;
color: var(--c-f);
cursor: pointer;
background: var(--c-3);
- padding: 43px 6px;
border-radius: 5px;
}
+.cnf-s {
+ position: absolute;
+ top: 66px;
+ right: 28px;
+ padding: 43px 6px;
+}
+
.pwr {
color: var(--c-6);
transform: translate(2px, 3px);
@@ -695,7 +717,7 @@ input[type=number]::-webkit-outer-spin-button {
}
.half {
- padding: 6px 6px;
+ padding: 7.5px;
top: 64px;
}
@@ -718,7 +740,7 @@ input[type=number]::-webkit-outer-spin-button {
.schkl {
padding: 2px 22px 0px 35px;
- margin-bottom: 0px;
+ margin: 0 0 0 2px;
}
.revchkl {
@@ -742,7 +764,7 @@ input[type=number]::-webkit-outer-spin-button {
height: 25px;
width: 25px;
background-color: var(--c-3);
- border-radius: 5px;
+ border-radius: 10px;
}
.schk {
@@ -813,9 +835,14 @@ input[type=number]::-webkit-outer-spin-button {
background-color: var(--c-2);
color: var(--c-f);
border: 0px solid white;
- border-radius: 5px;
- filter: drop-shadow(0px 0px 1px #000);
+ border-radius: 20px;
text-align: left;
+ transition: background-color 0.5s;
+ filter: brightness(1);
+}
+
+.pres {
+ margin-bottom: 6px;
}
.segin {
@@ -827,6 +854,19 @@ input[type=number]::-webkit-outer-spin-button {
display: block;
}
+.c {
+ text-align: center;
+}
+
+.po2 {
+ display: none;
+ margin-top: 8px;
+}
+
+.pwarn {
+ color: red;
+}
+
::-webkit-scrollbar {
width: 6px;
}
@@ -991,34 +1031,20 @@ input[type=number]::-webkit-outer-spin-button {
-
+
-
Load from slot
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Slot 16 can save all segments.
+
+
+
+
+
+
+
+ Loading...
+