Compare commits
30 Commits
v0.13.0-b7
...
v0.13.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef0f91d8d0 | ||
|
|
9552784e72 | ||
|
|
f068327307 | ||
|
|
1bc698ae78 | ||
|
|
1b2134d7a8 | ||
|
|
f922268af7 | ||
|
|
4865ddb377 | ||
|
|
a556732e4f | ||
|
|
0ea31cb088 | ||
|
|
b626c7620e | ||
|
|
5d90d8930e | ||
|
|
b01309c3bf | ||
|
|
961d5591bd | ||
|
|
eca3f12fed | ||
|
|
a2c8796e04 | ||
|
|
ad301fd087 | ||
|
|
02b08939cd | ||
|
|
9b0d583f1b | ||
|
|
4a0a07f158 | ||
|
|
9c864c9759 | ||
|
|
85b1c309d1 | ||
|
|
6fe43b7b5c | ||
|
|
25427ee60d | ||
|
|
be90bf0188 | ||
|
|
adcdaba199 | ||
|
|
17907589cc | ||
|
|
f333df181f | ||
|
|
4ce557a829 | ||
|
|
fc845dc936 | ||
|
|
7beae93441 |
39
CHANGELOG.md
39
CHANGELOG.md
@@ -1,6 +1,43 @@
|
||||
## WLED changelog
|
||||
|
||||
### Builds after release 0.12.0
|
||||
### WLED release 0.13.0
|
||||
|
||||
#### Build 2203142
|
||||
|
||||
- Release of WLED v0.13.0 "Toki"
|
||||
- Reduce APA102 hardware SPI frequency to 5Mhz
|
||||
- Remove `persistent` parameter in `savePreset()`
|
||||
|
||||
### Builds between releases 0.12.0 and 0.13.0
|
||||
|
||||
#### Build 2203140
|
||||
|
||||
- Added factory reset by pressing button 0 for >10 seconds
|
||||
- Added ability to set presets from DMX Effect mode
|
||||
- Simplified label hiding JS in user interface
|
||||
- Fixed JSON `{"live":true}` indefinite realtime mode
|
||||
|
||||
#### Build 2203080
|
||||
|
||||
- Disabled auto white mode in segments with no RGB bus
|
||||
- Fixed hostname string not 0-terminated
|
||||
- Fixed Popcorn mode not lighting first LED on pop
|
||||
|
||||
#### Build 2203060
|
||||
|
||||
- Dynamic hiding of unused color controls in UI (PR #2567)
|
||||
- Removed native Cronixie support and added Cronixie usermod
|
||||
- Fixed disabled timed preset expanding calendar
|
||||
- Fixed Color Order setting shown for analog busses
|
||||
- Fixed incorrect operator (#2566)
|
||||
|
||||
#### Build 2203011
|
||||
|
||||
- IR rewrite (PR #2561), supports CCT
|
||||
- Added locate button to Time settings
|
||||
- CSS fixes and adjustments
|
||||
- Consistent Tab indentation in index JS and CSS
|
||||
- Added initial contribution style guideline
|
||||
|
||||
#### Build 2202222
|
||||
|
||||
|
||||
78
CONTRIBUTING.md
Normal file
78
CONTRIBUTING.md
Normal file
@@ -0,0 +1,78 @@
|
||||
## Thank you for making WLED better!
|
||||
|
||||
Here are a few suggestions to make it easier for you to contribute!
|
||||
|
||||
### Code style
|
||||
|
||||
When in doubt, it is easiest to replicate the code style you find in the files you want to edit :)
|
||||
Below are the guidelines we use in the WLED repository.
|
||||
|
||||
#### Indentation
|
||||
|
||||
We use tabs for Indentation in Web files (.html/.css/.js) and spaces (2 per indentation level) for all other files.
|
||||
You are all set if you have enabled `Editor: Detect Indentation` in VS Code.
|
||||
|
||||
#### Blocks
|
||||
|
||||
Whether the opening bracket of e.g. an `if` block is in the same line as the condition or in a separate line is up to your discretion. If there is only one statement, leaving out block braches is acceptable.
|
||||
|
||||
Good:
|
||||
```cpp
|
||||
if (a == b) {
|
||||
doStuff(a);
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
if (a == b)
|
||||
{
|
||||
doStuff(a);
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
if (a == b) doStuff(a);
|
||||
```
|
||||
|
||||
There should always be a space between a keyword and its condition and between the condition and brace.
|
||||
Within the condition, no space should be between the paranthesis and variables.
|
||||
Spaces between variables and operators are up to the authors discretion.
|
||||
There should be no space between function names and their argument parenthesis.
|
||||
|
||||
Good:
|
||||
```cpp
|
||||
if (a == b) {
|
||||
doStuff(a);
|
||||
}
|
||||
```
|
||||
|
||||
Not good:
|
||||
```cpp
|
||||
if( a==b ){
|
||||
doStuff ( a);
|
||||
}
|
||||
```
|
||||
|
||||
#### Comments
|
||||
|
||||
Comments should have a space between the delimiting characters (e.g. `//`) and the comment text.
|
||||
Note: This is a recent change, the majority of the codebase still has comments without spaces.
|
||||
|
||||
Good:
|
||||
```
|
||||
// This is a comment.
|
||||
|
||||
/* This is a CSS inline comment */
|
||||
|
||||
/*
|
||||
* This is a comment
|
||||
* wrapping over multiple lines,
|
||||
* used in WLED for file headers and function explanations
|
||||
*/
|
||||
|
||||
<!-- This is an HTML comment -->
|
||||
```
|
||||
|
||||
There is no set character limit for a comment within a line,
|
||||
though as a rule of thumb you should wrap your comment if it exceeds the width of your editor window.
|
||||
Inline comments are OK if they describe that line only and are not exceedingly wide.
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.13.0-b7",
|
||||
"version": "0.13.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.13.0-b7",
|
||||
"version": "0.13.0",
|
||||
"description": "Tools for WLED project",
|
||||
"main": "tools/cdata.js",
|
||||
"directories": {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
; default_envs = travis_esp8266, travis_esp32
|
||||
|
||||
# Release binaries
|
||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, esp32_eth_ota1mapp, esp32s2_saola, esp32c3
|
||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, esp32s2_saola, esp32c3
|
||||
|
||||
# Build everything
|
||||
; default_envs = esp32dev, esp8285_4CH_MagicHome, codm-controller-0.6-rev2, codm-controller-0.6, esp32s2_saola, d1_mini_5CH_Shojo_PCB, d1_mini, sp501e, travis_esp8266, travis_esp32, nodemcuv2, esp32_eth, anavi_miracle_controller, esp07, esp01_1m_full, m5atom, h803wf, d1_mini_ota, heltec_wifi_kit_8, esp8285_H801, d1_mini_debug, wemos_shield_esp32, elekstube_ips
|
||||
@@ -204,9 +204,11 @@ lib_deps =
|
||||
makuna/NeoPixelBus @ 2.6.7 # 2.6.5/2.6.6 and newer do not compile on ESP core < 3.0.0
|
||||
|
||||
[esp32]
|
||||
#platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2/platform-tasmota-espressif32-2.0.2.zip
|
||||
#platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip
|
||||
platform = espressif32@3.5.0
|
||||
|
||||
platform_packages = framework-arduinoespressif32 @ https://github.com/Aircoookie/arduino-esp32.git#1.0.6.4
|
||||
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
#-DCONFIG_LITTLEFS_FOR_IDF_3_2
|
||||
@@ -320,8 +322,9 @@ lib_deps = ${esp8266.lib_deps}
|
||||
[env:esp32dev]
|
||||
board = esp32dev
|
||||
platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32 -D WLED_DISABLE_BLYNK #-D WLED_DISABLE_BROWNOUT_DET
|
||||
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32 #-D WLED_DISABLE_BLYNK #-D WLED_DISABLE_BROWNOUT_DET
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
@@ -329,17 +332,13 @@ board_build.partitions = ${esp32.default_partitions}
|
||||
[env:esp32_eth]
|
||||
board = esp32-poe
|
||||
platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
upload_speed = 921600
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1
|
||||
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 -D WLED_DISABLE_BLYNK
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
|
||||
# ESP32 ETH build that fits in old 1M app space (disables Blynk, Cronixie, and Hue sync)
|
||||
[env:esp32_eth_ota1mapp]
|
||||
extends = env:esp32_eth
|
||||
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet_OTA -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 -D WLED_DISABLE_BLYNK -D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC
|
||||
|
||||
[env:esp32s2_saola]
|
||||
board = esp32-s2-saola-1
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.2/platform-tasmota-espressif32-2.0.2.zip
|
||||
@@ -534,7 +533,7 @@ build_flags = ${common.build_flags_esp32} -D WLED_DISABLE_BROWNOUT_DET -D WLED_D
|
||||
-D LEDPIN=12
|
||||
-D RLYPIN=27
|
||||
-D BTNPIN=34
|
||||
-D WLED_DISABLE_INFRARED
|
||||
-D WLED_DISABLE_BLYNK
|
||||
-D DEFAULT_LED_COUNT=6
|
||||
# Display config
|
||||
-D ST7789_DRIVER
|
||||
|
||||
@@ -19,10 +19,14 @@ build_flags = ${common.build_flags_esp8266}
|
||||
; *** Use custom settings from file my_config.h
|
||||
-DWLED_USE_MY_CONFIG
|
||||
; *********************************************************************
|
||||
;
|
||||
;
|
||||
; *** To use the below defines/overrides, copy and paste each onto it's own line just below build_flags in the section above.
|
||||
;
|
||||
; disable specific features
|
||||
; -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
|
||||
@@ -45,3 +49,15 @@ build_flags = ${common.build_flags_esp8266}
|
||||
; 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
|
||||
;
|
||||
; set the name of the module - make sure there is a quote-backslash-quote before the name and a backslash-quote-quote after the name
|
||||
; -D SERVERNAME="\"WLED\""
|
||||
;
|
||||
; set the number of LEDs
|
||||
; -D DEFAULT_LED_COUNT=30
|
||||
;
|
||||
; set milliampere limit when using ESP pin to power leds
|
||||
; -D ABL_MILLIAMPS_DEFAULT =850
|
||||
;
|
||||
; enable IR by setting remote type
|
||||
; -D IRTYPE=0 //0 Remote disabled | 1 24-key RGB | 2 24-key with CT | 3 40-key blue | 4 40-key RGB | 5 21-key RGB | 6 6-key black | 7 9-key red | 8 JSON remote
|
||||
|
||||
@@ -27,7 +27,7 @@ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control
|
||||
- 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 analog clock (Cronixie, 7-segment and EleksTube IPS clock support via usermods)
|
||||
- Configurable Auto Brightness limit for safer operation
|
||||
- Filesystem-based config for easier backup of presets and settings
|
||||
|
||||
|
||||
8
usermods/Cronixie/readme.md
Normal file
8
usermods/Cronixie/readme.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Cronixie clock usermod
|
||||
|
||||
This usermod supports driving the Cronixie M and L clock kits by Diamex.
|
||||
|
||||
## Installation
|
||||
|
||||
Compile and upload after adding `-D USERMOD_CRONIXIE` to `build_flags` of your PlatformIO environment.
|
||||
Make sure the Auto Brightness Limiter is enabled at 420mA (!) and configure 60 WS281x LEDs.
|
||||
301
usermods/Cronixie/usermod_cronixie.h
Normal file
301
usermods/Cronixie/usermod_cronixie.h
Normal file
@@ -0,0 +1,301 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
class UsermodCronixie : public Usermod {
|
||||
private:
|
||||
unsigned long lastTime = 0;
|
||||
char cronixieDisplay[7] = "HHMMSS";
|
||||
byte _digitOut[6] = {10,10,10,10,10,10};
|
||||
byte dP[6] = {255, 255, 255, 255, 255, 255};
|
||||
|
||||
// set your config variables to their boot default value (this can also be done in readFromConfig() or a constructor if you prefer)
|
||||
bool backlight = true;
|
||||
|
||||
public:
|
||||
void initCronixie()
|
||||
{
|
||||
if (dP[0] == 255) // if dP[0] is 255, cronixie is not yet init'ed
|
||||
{
|
||||
setCronixie();
|
||||
strip.getSegment(0).grouping = 10; // 10 LEDs per digit
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (!toki.isTick()) return;
|
||||
initCronixie();
|
||||
_overlayCronixie();
|
||||
strip.trigger();
|
||||
}
|
||||
|
||||
byte getSameCodeLength(char code, int index, char const cronixieDisplay[])
|
||||
{
|
||||
byte counter = 0;
|
||||
|
||||
for (int i = index+1; i < 6; i++)
|
||||
{
|
||||
if (cronixieDisplay[i] == code)
|
||||
{
|
||||
counter++;
|
||||
} else {
|
||||
return counter;
|
||||
}
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
void setCronixie()
|
||||
{
|
||||
/*
|
||||
* digit purpose index
|
||||
* 0-9 | 0-9 (incl. random)
|
||||
* 10 | blank
|
||||
* 11 | blank, bg off
|
||||
* 12 | test upw.
|
||||
* 13 | test dnw.
|
||||
* 14 | binary AM/PM
|
||||
* 15 | BB upper +50 for no trailing 0
|
||||
* 16 | BBB
|
||||
* 17 | BBBB
|
||||
* 18 | BBBBB
|
||||
* 19 | BBBBBB
|
||||
* 20 | H
|
||||
* 21 | HH
|
||||
* 22 | HHH
|
||||
* 23 | HHHH
|
||||
* 24 | M
|
||||
* 25 | MM
|
||||
* 26 | MMM
|
||||
* 27 | MMMM
|
||||
* 28 | MMMMM
|
||||
* 29 | MMMMMM
|
||||
* 30 | S
|
||||
* 31 | SS
|
||||
* 32 | SSS
|
||||
* 33 | SSSS
|
||||
* 34 | SSSSS
|
||||
* 35 | SSSSSS
|
||||
* 36 | Y
|
||||
* 37 | YY
|
||||
* 38 | YYYY
|
||||
* 39 | I
|
||||
* 40 | II
|
||||
* 41 | W
|
||||
* 42 | WW
|
||||
* 43 | D
|
||||
* 44 | DD
|
||||
* 45 | DDD
|
||||
* 46 | V
|
||||
* 47 | VV
|
||||
* 48 | VVV
|
||||
* 49 | VVVV
|
||||
* 50 | VVVVV
|
||||
* 51 | VVVVVV
|
||||
* 52 | v
|
||||
* 53 | vv
|
||||
* 54 | vvv
|
||||
* 55 | vvvv
|
||||
* 56 | vvvvv
|
||||
* 57 | vvvvvv
|
||||
*/
|
||||
|
||||
//H HourLower | HH - Hour 24. | AH - Hour 12. | HHH Hour of Month | HHHH Hour of Year
|
||||
//M MinuteUpper | MM Minute of Hour | MMM Minute of 12h | MMMM Minute of Day | MMMMM Minute of Month | MMMMMM Minute of Year
|
||||
//S SecondUpper | SS Second of Minute | SSS Second of 10 Minute | SSSS Second of Hour | SSSSS Second of Day | SSSSSS Second of Week
|
||||
//B AM/PM | BB 0-6/6-12/12-18/18-24 | BBB 0-3... | BBBB 0-1.5... | BBBBB 0-1 | BBBBBB 0-0.5
|
||||
|
||||
//Y YearLower | YY - Year LU | YYYY - Std.
|
||||
//I MonthLower | II - Month of Year
|
||||
//W Week of Month | WW Week of Year
|
||||
//D Day of Week | DD Day Of Month | DDD Day Of Year
|
||||
|
||||
DEBUG_PRINT("cset ");
|
||||
DEBUG_PRINTLN(cronixieDisplay);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
dP[i] = 10;
|
||||
switch (cronixieDisplay[i])
|
||||
{
|
||||
case '_': dP[i] = 10; break;
|
||||
case '-': dP[i] = 11; break;
|
||||
case 'r': dP[i] = random(1,7); break; //random btw. 1-6
|
||||
case 'R': dP[i] = random(0,10); break; //random btw. 0-9
|
||||
//case 't': break; //Test upw.
|
||||
//case 'T': break; //Test dnw.
|
||||
case 'b': dP[i] = 14 + getSameCodeLength('b',i,cronixieDisplay); i = i+dP[i]-14; break;
|
||||
case 'B': dP[i] = 14 + getSameCodeLength('B',i,cronixieDisplay); i = i+dP[i]-14; break;
|
||||
case 'h': dP[i] = 70 + getSameCodeLength('h',i,cronixieDisplay); i = i+dP[i]-70; break;
|
||||
case 'H': dP[i] = 20 + getSameCodeLength('H',i,cronixieDisplay); i = i+dP[i]-20; break;
|
||||
case 'A': dP[i] = 108; i++; break;
|
||||
case 'a': dP[i] = 58; i++; break;
|
||||
case 'm': dP[i] = 74 + getSameCodeLength('m',i,cronixieDisplay); i = i+dP[i]-74; break;
|
||||
case 'M': dP[i] = 24 + getSameCodeLength('M',i,cronixieDisplay); i = i+dP[i]-24; break;
|
||||
case 's': dP[i] = 80 + getSameCodeLength('s',i,cronixieDisplay); i = i+dP[i]-80; break; //refresh more often bc. of secs
|
||||
case 'S': dP[i] = 30 + getSameCodeLength('S',i,cronixieDisplay); i = i+dP[i]-30; break;
|
||||
case 'Y': dP[i] = 36 + getSameCodeLength('Y',i,cronixieDisplay); i = i+dP[i]-36; break;
|
||||
case 'y': dP[i] = 86 + getSameCodeLength('y',i,cronixieDisplay); i = i+dP[i]-86; break;
|
||||
case 'I': dP[i] = 39 + getSameCodeLength('I',i,cronixieDisplay); i = i+dP[i]-39; break; //Month. Don't ask me why month and minute both start with M.
|
||||
case 'i': dP[i] = 89 + getSameCodeLength('i',i,cronixieDisplay); i = i+dP[i]-89; break;
|
||||
//case 'W': break;
|
||||
//case 'w': break;
|
||||
case 'D': dP[i] = 43 + getSameCodeLength('D',i,cronixieDisplay); i = i+dP[i]-43; break;
|
||||
case 'd': dP[i] = 93 + getSameCodeLength('d',i,cronixieDisplay); i = i+dP[i]-93; break;
|
||||
case '0': dP[i] = 0; break;
|
||||
case '1': dP[i] = 1; break;
|
||||
case '2': dP[i] = 2; break;
|
||||
case '3': dP[i] = 3; break;
|
||||
case '4': dP[i] = 4; break;
|
||||
case '5': dP[i] = 5; break;
|
||||
case '6': dP[i] = 6; break;
|
||||
case '7': dP[i] = 7; break;
|
||||
case '8': dP[i] = 8; break;
|
||||
case '9': dP[i] = 9; break;
|
||||
//case 'V': break; //user var0
|
||||
//case 'v': break; //user var1
|
||||
}
|
||||
}
|
||||
DEBUG_PRINT("result ");
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
DEBUG_PRINT((int)dP[i]);
|
||||
DEBUG_PRINT(" ");
|
||||
}
|
||||
DEBUG_PRINTLN((int)dP[5]);
|
||||
|
||||
_overlayCronixie(); // refresh
|
||||
}
|
||||
|
||||
void _overlayCronixie()
|
||||
{
|
||||
byte h = hour(localTime);
|
||||
byte h0 = h;
|
||||
byte m = minute(localTime);
|
||||
byte s = second(localTime);
|
||||
byte d = day(localTime);
|
||||
byte mi = month(localTime);
|
||||
int y = year(localTime);
|
||||
//this has to be changed in time for 22nd century
|
||||
y -= 2000; if (y<0) y += 30; //makes countdown work
|
||||
|
||||
if (useAMPM && !countdownMode)
|
||||
{
|
||||
if (h>12) h-=12;
|
||||
else if (h==0) h+=12;
|
||||
}
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (dP[i] < 12) _digitOut[i] = dP[i];
|
||||
else {
|
||||
if (dP[i] < 65)
|
||||
{
|
||||
switch(dP[i])
|
||||
{
|
||||
case 21: _digitOut[i] = h/10; _digitOut[i+1] = h- _digitOut[i]*10; i++; break; //HH
|
||||
case 25: _digitOut[i] = m/10; _digitOut[i+1] = m- _digitOut[i]*10; i++; break; //MM
|
||||
case 31: _digitOut[i] = s/10; _digitOut[i+1] = s- _digitOut[i]*10; i++; break; //SS
|
||||
|
||||
case 20: _digitOut[i] = h- (h/10)*10; break; //H
|
||||
case 24: _digitOut[i] = m/10; break; //M
|
||||
case 30: _digitOut[i] = s/10; break; //S
|
||||
|
||||
case 43: _digitOut[i] = weekday(localTime); _digitOut[i]--; if (_digitOut[i]<1) _digitOut[i]= 7; break; //D
|
||||
case 44: _digitOut[i] = d/10; _digitOut[i+1] = d- _digitOut[i]*10; i++; break; //DD
|
||||
case 40: _digitOut[i] = mi/10; _digitOut[i+1] = mi- _digitOut[i]*10; i++; break; //II
|
||||
case 37: _digitOut[i] = y/10; _digitOut[i+1] = y- _digitOut[i]*10; i++; break; //YY
|
||||
case 39: _digitOut[i] = 2; _digitOut[i+1] = 0; _digitOut[i+2] = y/10; _digitOut[i+3] = y- _digitOut[i+2]*10; i+=3; break; //YYYY
|
||||
|
||||
//case 16: _digitOut[i+2] = ((h0/3)&1)?1:0; i++; //BBB (BBBB NI)
|
||||
//case 15: _digitOut[i+1] = (h0>17 || (h0>5 && h0<12))?1:0; i++; //BB
|
||||
case 14: _digitOut[i] = (h0>11)?1:0; break; //B
|
||||
}
|
||||
} else
|
||||
{
|
||||
switch(dP[i])
|
||||
{
|
||||
case 71: _digitOut[i] = h/10; _digitOut[i+1] = h- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //hh
|
||||
case 75: _digitOut[i] = m/10; _digitOut[i+1] = m- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //mm
|
||||
case 81: _digitOut[i] = s/10; _digitOut[i+1] = s- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //ss
|
||||
//case 66: _digitOut[i+2] = ((h0/3)&1)?1:10; i++; //bbb (bbbb NI)
|
||||
//case 65: _digitOut[i+1] = (h0>17 || (h0>5 && h0<12))?1:10; i++; //bb
|
||||
case 64: _digitOut[i] = (h0>11)?1:10; break; //b
|
||||
|
||||
case 93: _digitOut[i] = weekday(localTime); _digitOut[i]--; if (_digitOut[i]<1) _digitOut[i]= 7; break; //d
|
||||
case 94: _digitOut[i] = d/10; _digitOut[i+1] = d- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //dd
|
||||
case 90: _digitOut[i] = mi/10; _digitOut[i+1] = mi- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //ii
|
||||
case 87: _digitOut[i] = y/10; _digitOut[i+1] = y- _digitOut[i]*10; i++; break; //yy
|
||||
case 89: _digitOut[i] = 2; _digitOut[i+1] = 0; _digitOut[i+2] = y/10; _digitOut[i+3] = y- _digitOut[i+2]*10; i+=3; break; //yyyy
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleOverlayDraw()
|
||||
{
|
||||
byte offsets[] = {5, 0, 6, 1, 7, 2, 8, 3, 9, 4};
|
||||
|
||||
for (uint16_t i = 0; i < 6; i++)
|
||||
{
|
||||
byte o = 10*i;
|
||||
byte excl = 10;
|
||||
if(_digitOut[i] < 10) excl = offsets[_digitOut[i]];
|
||||
excl += o;
|
||||
|
||||
if (backlight && _digitOut[i] <11)
|
||||
{
|
||||
uint32_t col = strip.gamma32(strip.getSegment(0).colors[1]);
|
||||
for (uint16_t j=o; j< o+10; j++) {
|
||||
if (j != excl) strip.setPixelColor(j, col);
|
||||
}
|
||||
} else
|
||||
{
|
||||
for (uint16_t j=o; j< o+10; j++) {
|
||||
if (j != excl) strip.setPixelColor(j, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addToJsonState(JsonObject& root)
|
||||
{
|
||||
root["nx"] = cronixieDisplay;
|
||||
}
|
||||
|
||||
void readFromJsonState(JsonObject& root)
|
||||
{
|
||||
if (root["nx"].is<const char*>()) {
|
||||
strncpy(cronixieDisplay, root["nx"], 6);
|
||||
}
|
||||
}
|
||||
|
||||
void addToConfig(JsonObject& root)
|
||||
{
|
||||
JsonObject top = root.createNestedObject(F("Cronixie"));
|
||||
top["backlight"] = backlight;
|
||||
}
|
||||
|
||||
bool readFromConfig(JsonObject& root)
|
||||
{
|
||||
// default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor
|
||||
// setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed)
|
||||
|
||||
JsonObject top = root[F("Cronixie")];
|
||||
|
||||
bool configComplete = !top.isNull();
|
||||
|
||||
configComplete &= getJsonValue(top["backlight"], backlight);
|
||||
|
||||
return configComplete;
|
||||
}
|
||||
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_CRONIXIE;
|
||||
}
|
||||
};
|
||||
@@ -12,6 +12,7 @@ class TFTs : public TFT_eSPI {
|
||||
private:
|
||||
uint8_t digits[NUM_DIGITS];
|
||||
|
||||
|
||||
// These read 16- and 32-bit types from the SD card file.
|
||||
// BMP data is stored little-endian, Arduino is little-endian too.
|
||||
// May need to reverse subscript order if porting elsewhere.
|
||||
@@ -33,7 +34,16 @@ private:
|
||||
}
|
||||
|
||||
uint16_t output_buffer[TFT_HEIGHT][TFT_WIDTH];
|
||||
|
||||
int16_t w = 135, h = 240, x = 0, y = 0, bufferedDigit = 255;
|
||||
uint16_t digitR, digitG, digitB, dimming = 255;
|
||||
uint32_t digitColor = 0;
|
||||
|
||||
void drawBuffer() {
|
||||
bool oldSwapBytes = getSwapBytes();
|
||||
setSwapBytes(true);
|
||||
pushImage(x, y, w, h, (uint16_t *)output_buffer);
|
||||
setSwapBytes(oldSwapBytes);
|
||||
}
|
||||
|
||||
// These BMP functions are stolen directly from the TFT_SPIFFS_BMP example in the TFT_eSPI library.
|
||||
// Unfortunately, they aren't part of the library itself, so I had to copy them.
|
||||
@@ -41,44 +51,69 @@ private:
|
||||
|
||||
//// BEGIN STOLEN CODE
|
||||
|
||||
// Draw directly from file stored in RGB565 format
|
||||
// Draw directly from file stored in RGB565 format. Fastest
|
||||
bool drawBin(const char *filename) {
|
||||
fs::File bmpFS;
|
||||
|
||||
|
||||
// Open requested file on SD card
|
||||
bmpFS = WLED_FS.open(filename, "r");
|
||||
|
||||
if (!bmpFS)
|
||||
{
|
||||
Serial.print(F("File not found: "));
|
||||
Serial.println(filename);
|
||||
return(false);
|
||||
}
|
||||
|
||||
size_t sz = bmpFS.size();
|
||||
if (sz <= 64800)
|
||||
{
|
||||
bool oldSwapBytes = getSwapBytes();
|
||||
setSwapBytes(true);
|
||||
|
||||
int16_t h = sz / (135 * 2);
|
||||
|
||||
//draw img that is shorter than 240pix into the center
|
||||
int16_t y = (height() - h) /2;
|
||||
|
||||
bmpFS.read((uint8_t *) output_buffer,sz);
|
||||
|
||||
if (!realtimeMode || realtimeOverride) strip.service();
|
||||
|
||||
pushImage(0, y, 135, h, (uint16_t *)output_buffer);
|
||||
|
||||
setSwapBytes(oldSwapBytes);
|
||||
if (sz > 64800) {
|
||||
bmpFS.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t r, g, b, dimming = 255;
|
||||
int16_t row, col;
|
||||
|
||||
//draw img that is shorter than 240pix into the center
|
||||
w = 135;
|
||||
h = sz / (w * 2);
|
||||
x = 0;
|
||||
y = (height() - h) /2;
|
||||
|
||||
uint8_t lineBuffer[w * 2];
|
||||
|
||||
if (!realtimeMode || realtimeOverride) strip.service();
|
||||
|
||||
// 0,0 coordinates are top left
|
||||
for (row = 0; row < h; row++) {
|
||||
|
||||
bmpFS.read(lineBuffer, sizeof(lineBuffer));
|
||||
uint8_t PixM, PixL;
|
||||
|
||||
// Colors are already in 16-bit R5, G6, B5 format
|
||||
for (col = 0; col < w; col++)
|
||||
{
|
||||
if (dimming == 255 && !digitColor) { // not needed, copy directly
|
||||
output_buffer[row][col] = (lineBuffer[col*2+1] << 8) | (lineBuffer[col*2]);
|
||||
} else {
|
||||
// 16 BPP pixel format: R5, G6, B5 ; bin: RRRR RGGG GGGB BBBB
|
||||
PixM = lineBuffer[col*2+1];
|
||||
PixL = lineBuffer[col*2];
|
||||
// align to 8-bit value (MSB left aligned)
|
||||
r = (PixM) & 0xF8;
|
||||
g = ((PixM << 5) | (PixL >> 3)) & 0xFC;
|
||||
b = (PixL << 3) & 0xF8;
|
||||
r *= dimming; g *= dimming; b *= dimming;
|
||||
r = r >> 8; g = g >> 8; b = b >> 8;
|
||||
if (digitColor) { // grayscale pixel coloring
|
||||
uint8_t l = (r > g) ? ((r > b) ? r:b) : ((g > b) ? g:b);
|
||||
r = g = b = l;
|
||||
r *= digitR; g *= digitG; b *= digitB;
|
||||
r = r >> 8; g = g >> 8; b = b >> 8;
|
||||
}
|
||||
output_buffer[row][col] = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawBuffer();
|
||||
|
||||
bmpFS.close();
|
||||
|
||||
return(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool drawBmp(const char *filename) {
|
||||
@@ -87,53 +122,52 @@ private:
|
||||
// Open requested file on SD card
|
||||
bmpFS = WLED_FS.open(filename, "r");
|
||||
|
||||
if (!bmpFS)
|
||||
{
|
||||
Serial.print(F("File not found: "));
|
||||
Serial.println(filename);
|
||||
return(false);
|
||||
}
|
||||
|
||||
uint32_t seekOffset;
|
||||
int16_t w, h, row;
|
||||
uint8_t r, g, b;
|
||||
uint32_t seekOffset, headerSize, paletteSize = 0;
|
||||
int16_t row;
|
||||
uint16_t r, g, b, dimming = 255, bitDepth;
|
||||
|
||||
uint16_t magic = read16(bmpFS);
|
||||
if (magic == 0xFFFF) {
|
||||
if (magic != ('B' | ('M' << 8))) { // File not found or not a BMP
|
||||
Serial.println(F("BMP not found!"));
|
||||
bmpFS.close();
|
||||
return(false);
|
||||
}
|
||||
|
||||
if (magic != 0x4D42) {
|
||||
Serial.print(F("File not a BMP. Magic: "));
|
||||
Serial.println(magic);
|
||||
bmpFS.close();
|
||||
return(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
read32(bmpFS);
|
||||
read32(bmpFS);
|
||||
seekOffset = read32(bmpFS);
|
||||
read32(bmpFS);
|
||||
w = read32(bmpFS);
|
||||
h = read32(bmpFS);
|
||||
read32(bmpFS); // filesize in bytes
|
||||
read32(bmpFS); // reserved
|
||||
seekOffset = read32(bmpFS); // start of bitmap
|
||||
headerSize = read32(bmpFS); // header size
|
||||
w = read32(bmpFS); // width
|
||||
h = read32(bmpFS); // height
|
||||
read16(bmpFS); // color planes (must be 1)
|
||||
bitDepth = read16(bmpFS);
|
||||
|
||||
if ((read16(bmpFS) != 1) || (read16(bmpFS) != 24) || (read32(bmpFS) != 0)) {
|
||||
if (read32(bmpFS) != 0 || (bitDepth != 24 && bitDepth != 1 && bitDepth != 4 && bitDepth != 8)) {
|
||||
Serial.println(F("BMP format not recognized."));
|
||||
bmpFS.close();
|
||||
return(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
//draw img that is shorter than 240pix into the center
|
||||
int16_t y = (height() - h) /2;
|
||||
uint32_t palette[256];
|
||||
if (bitDepth <= 8) // 1,4,8 bit bitmap: read color palette
|
||||
{
|
||||
read32(bmpFS); read32(bmpFS); read32(bmpFS); // size, w resolution, h resolution
|
||||
paletteSize = read32(bmpFS);
|
||||
if (paletteSize == 0) paletteSize = bitDepth * bitDepth; //if 0, size is 2^bitDepth
|
||||
bmpFS.seek(14 + headerSize); // start of color palette
|
||||
for (uint16_t i = 0; i < paletteSize; i++) {
|
||||
palette[i] = read32(bmpFS);
|
||||
}
|
||||
}
|
||||
|
||||
// draw img that is shorter than 240pix into the center
|
||||
x = (width() - w) /2;
|
||||
y = (height() - h) /2;
|
||||
|
||||
bool oldSwapBytes = getSwapBytes();
|
||||
setSwapBytes(true);
|
||||
bmpFS.seek(seekOffset);
|
||||
|
||||
uint16_t padding = (4 - ((w * 3) & 3)) & 3;
|
||||
uint8_t lineBuffer[w * 3 + padding];
|
||||
uint32_t lineSize = ((bitDepth * w +31) >> 5) * 4;
|
||||
uint8_t lineBuffer[lineSize];
|
||||
|
||||
uint8_t serviceStrip = (!realtimeMode || realtimeOverride) ? 7 : 0;
|
||||
// row is decremented as the BMP image is drawn bottom up
|
||||
@@ -142,23 +176,121 @@ private:
|
||||
bmpFS.read(lineBuffer, sizeof(lineBuffer));
|
||||
uint8_t* bptr = lineBuffer;
|
||||
|
||||
// Convert 24 to 16 bit colours while copying to output buffer.
|
||||
// Convert 24 to 16 bit colors while copying to output buffer.
|
||||
for (uint16_t col = 0; col < w; col++)
|
||||
{
|
||||
b = *bptr++;
|
||||
g = *bptr++;
|
||||
r = *bptr++;
|
||||
output_buffer[row][col] = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
|
||||
if (bitDepth == 24) {
|
||||
b = *bptr++;
|
||||
g = *bptr++;
|
||||
r = *bptr++;
|
||||
} else {
|
||||
uint32_t c = 0;
|
||||
if (bitDepth == 8) {
|
||||
c = palette[*bptr++];
|
||||
}
|
||||
else if (bitDepth == 4) {
|
||||
c = palette[(*bptr >> ((col & 0x01)?0:4)) & 0x0F];
|
||||
if (col & 0x01) bptr++;
|
||||
}
|
||||
else { // bitDepth == 1
|
||||
c = palette[(*bptr >> (7 - (col & 0x07))) & 0x01];
|
||||
if ((col & 0x07) == 0x07) bptr++;
|
||||
}
|
||||
b = c; g = c >> 8; r = c >> 16;
|
||||
}
|
||||
if (dimming != 255) { // only dimm when needed
|
||||
r *= dimming; g *= dimming; b *= dimming;
|
||||
r = r >> 8; g = g >> 8; b = b >> 8;
|
||||
}
|
||||
if (digitColor) { // grayscale pixel coloring
|
||||
uint8_t l = (r > g) ? ((r > b) ? r:b) : ((g > b) ? g:b);
|
||||
r = g = b = l;
|
||||
|
||||
r *= digitR; g *= digitG; b *= digitB;
|
||||
r = r >> 8; g = g >> 8; b = b >> 8;
|
||||
}
|
||||
output_buffer[row][col] = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xFF) >> 3);
|
||||
}
|
||||
}
|
||||
|
||||
pushImage(0, y, w, h, (uint16_t *)output_buffer);
|
||||
setSwapBytes(oldSwapBytes);
|
||||
drawBuffer();
|
||||
|
||||
bmpFS.close();
|
||||
return(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool drawClk(const char *filename) {
|
||||
fs::File bmpFS;
|
||||
|
||||
// Open requested file on SD card
|
||||
bmpFS = WLED_FS.open(filename, "r");
|
||||
|
||||
if (!bmpFS)
|
||||
{
|
||||
Serial.print("File not found: ");
|
||||
Serial.println(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t r, g, b, dimming = 255, magic;
|
||||
int16_t row, col;
|
||||
|
||||
magic = read16(bmpFS);
|
||||
if (magic != 0x4B43) { // look for "CK" header
|
||||
Serial.print(F("File not a CLK. Magic: "));
|
||||
Serial.println(magic);
|
||||
bmpFS.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
w = read16(bmpFS);
|
||||
h = read16(bmpFS);
|
||||
x = (width() - w) / 2;
|
||||
y = (height() - h) / 2;
|
||||
|
||||
uint8_t lineBuffer[w * 2];
|
||||
|
||||
if (!realtimeMode || realtimeOverride) strip.service();
|
||||
|
||||
// 0,0 coordinates are top left
|
||||
for (row = 0; row < h; row++) {
|
||||
|
||||
bmpFS.read(lineBuffer, sizeof(lineBuffer));
|
||||
uint8_t PixM, PixL;
|
||||
|
||||
// Colors are already in 16-bit R5, G6, B5 format
|
||||
for (col = 0; col < w; col++)
|
||||
{
|
||||
if (dimming == 255 && !digitColor) { // not needed, copy directly
|
||||
output_buffer[row][col+x] = (lineBuffer[col*2+1] << 8) | (lineBuffer[col*2]);
|
||||
} else {
|
||||
// 16 BPP pixel format: R5, G6, B5 ; bin: RRRR RGGG GGGB BBBB
|
||||
PixM = lineBuffer[col*2+1];
|
||||
PixL = lineBuffer[col*2];
|
||||
// align to 8-bit value (MSB left aligned)
|
||||
r = (PixM) & 0xF8;
|
||||
g = ((PixM << 5) | (PixL >> 3)) & 0xFC;
|
||||
b = (PixL << 3) & 0xF8;
|
||||
r *= dimming; g *= dimming; b *= dimming;
|
||||
r = r >> 8; g = g >> 8; b = b >> 8;
|
||||
if (digitColor) { // grayscale pixel coloring
|
||||
uint8_t l = (r > g) ? ((r > b) ? r:b) : ((g > b) ? g:b);
|
||||
r = g = b = l;
|
||||
r *= digitR; g *= digitG; b *= digitB;
|
||||
r = r >> 8; g = g >> 8; b = b >> 8;
|
||||
}
|
||||
output_buffer[row][col+x] = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawBuffer();
|
||||
|
||||
bmpFS.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
TFTs() : TFT_eSPI(), chip_select()
|
||||
{ for (uint8_t digit=0; digit < NUM_DIGITS; digit++) digits[digit] = 0; }
|
||||
@@ -167,6 +299,9 @@ public:
|
||||
enum show_t { no, yes, force };
|
||||
// A digit of 0xFF means blank the screen.
|
||||
const static uint8_t blanked = 255;
|
||||
|
||||
uint8_t tubeSegment = 1;
|
||||
uint8_t digitOffset = 0;
|
||||
|
||||
void begin() {
|
||||
pinMode(TFT_ENABLE_PIN, OUTPUT);
|
||||
@@ -182,34 +317,60 @@ public:
|
||||
|
||||
void showDigit(uint8_t digit) {
|
||||
chip_select.setDigit(digit);
|
||||
uint8_t digitToDraw = digits[digit];
|
||||
if (digitToDraw < 10) digitToDraw += digitOffset;
|
||||
|
||||
if (digits[digit] == blanked) {
|
||||
fillScreen(TFT_BLACK);
|
||||
if (digitToDraw == blanked) {
|
||||
fillScreen(TFT_BLACK); return;
|
||||
}
|
||||
else {
|
||||
// Filenames are no bigger than "255.bmp\0"
|
||||
char file_name[10];
|
||||
sprintf(file_name, "/%d.bmp", digits[digit]);
|
||||
if (WLED_FS.exists(file_name)) {
|
||||
drawBmp(file_name);
|
||||
} else {
|
||||
sprintf(file_name, "/%d.bin", digits[digit]);
|
||||
drawBin(file_name);
|
||||
}
|
||||
|
||||
// if last digit was the same, skip loading from FS to buffer
|
||||
if (!digitColor && digitToDraw == bufferedDigit) drawBuffer();
|
||||
digitR = R(digitColor); digitG = G(digitColor); digitB = B(digitColor);
|
||||
|
||||
// Filenames are no bigger than "254.bmp\0"
|
||||
char file_name[10];
|
||||
// Fastest, raw RGB565
|
||||
sprintf(file_name, "/%d.bin", digitToDraw);
|
||||
if (WLED_FS.exists(file_name)) {
|
||||
if (drawBin(file_name)) bufferedDigit = digitToDraw;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Fast, raw RGB565, see https://github.com/aly-fly/EleksTubeHAX on how to create this clk format
|
||||
sprintf(file_name, "/%d.clk", digitToDraw);
|
||||
if (WLED_FS.exists(file_name)) {
|
||||
if (drawClk(file_name)) bufferedDigit = digitToDraw;
|
||||
return;
|
||||
}
|
||||
// Slow, regular RGB888 or 1,4,8 bit palette BMP
|
||||
sprintf(file_name, "/%d.bmp", digitToDraw);
|
||||
if (drawBmp(file_name)) bufferedDigit = digitToDraw;
|
||||
return;
|
||||
}
|
||||
|
||||
void setDigit(uint8_t digit, uint8_t value, show_t show=yes) {
|
||||
uint8_t old_value = digits[digit];
|
||||
digits[digit] = value;
|
||||
|
||||
|
||||
// Color in grayscale bitmaps if Segment 1 exists
|
||||
// TODO If secondary and tertiary are black, color all in primary,
|
||||
// else color first three from Seg 1 color slots and last three from Seg 2 color slots
|
||||
WS2812FX::Segment& seg1 = strip.getSegment(tubeSegment);
|
||||
if (seg1.isActive()) {
|
||||
digitColor = strip.getPixelColor(seg1.start + digit);
|
||||
dimming = seg1.opacity;
|
||||
} else {
|
||||
digitColor = 0;
|
||||
dimming = 255;
|
||||
}
|
||||
|
||||
if (show != no && (old_value != value || show == force)) {
|
||||
showDigit(digit);
|
||||
}
|
||||
}
|
||||
uint8_t getDigit(uint8_t digit) { return digits[digit]; }
|
||||
uint8_t getDigit(uint8_t digit) {return digits[digit];}
|
||||
|
||||
void showAllDigits() { for (uint8_t digit=0; digit < NUM_DIGITS; digit++) showDigit(digit); }
|
||||
void showAllDigits() {for (uint8_t digit=0; digit < NUM_DIGITS; digit++) showDigit(digit);}
|
||||
|
||||
// Making chip_select public so we don't have to proxy all methods, and the caller can just use it directly.
|
||||
ChipSelect chip_select;
|
||||
|
||||
@@ -5,16 +5,17 @@ It enables running all WLED effects on the background SK6812 lighting, while dis
|
||||
Code is largely based on https://github.com/SmittyHalibut/EleksTubeHAX by Mark Smith!
|
||||
|
||||
Supported:
|
||||
- Display with custom bitmaps or raw RGB565 images (.bin) from filesystem
|
||||
- Display with custom bitmaps (.bmp) or raw RGB565 images (.bin) from filesystem
|
||||
- Background lighting
|
||||
- Power button
|
||||
- All 4 hardware buttons
|
||||
- RTC (with RTC usermod)
|
||||
- Standard WLED time features (NTP, DST, timezones)
|
||||
|
||||
Not supported:
|
||||
- 3 navigation buttons, on-device setup
|
||||
- On-device setup with buttons (WiFi setup only)
|
||||
|
||||
Your images must be exactly 135 pixels wide and 1-240 pixels high.
|
||||
Your images must be 1-135 pixels wide and 1-240 pixels high.
|
||||
For BMP, 1, 4, 8, and 24 bits per pixel formats are supported.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -25,7 +26,20 @@ Use LED pin 12, relay pin 27 and button pin 34.
|
||||
|
||||
## Use of RGB565 images
|
||||
|
||||
Binary 16-bit per pixel RGB565 format `.bin` images are now supported. This has the benefit of only using 2/3rds of the file size a `.bmp` has.
|
||||
Binary 16-bit per pixel RGB565 format `.bin` and `.clk` images are now supported. This has the benefit of only using 2/3rds of the file size a 24 BPP `.bmp` has.
|
||||
The drawback is that this format cannot be handled by common image programs and that an extra conversion step is needed.
|
||||
You can use https://lvgl.io/tools/imageconverter to convert your .bmp to a .bin file (settings `True color` and `Binary RGB565`)
|
||||
Thank you to @RedNax67 for adding .bin support.
|
||||
You can use https://lvgl.io/tools/imageconverter to convert your .bmp to a .bin file (settings `True color` and `Binary RGB565`).
|
||||
Thank you to @RedNax67 for adding .bin and .clk support.
|
||||
For most clockface designs, using 4 or 8 BPP BMP formats will save even more file size:
|
||||
|
||||
| Bits per pixel | File size in kB (for 135x240 img) | % of 24 BPP BMP | Max unique colors
|
||||
| --- | --- | --- | --- |
|
||||
24 | 98 | 100% | 16M (66K)
|
||||
16 (.clk) | 64.8 | 66% | 66K
|
||||
8 | 33.7 | 34% | 256
|
||||
4 | 16.4 | 17% | 16
|
||||
1 | 4.9 | 5% | 2
|
||||
|
||||
Comparison 1 vs. 4 vs. 8 vs. 24 BPP. With this clockface on the actual clock, 4 bit looks good, and 8 bit is almost indistinguishable from 24 bit.
|
||||
|
||||

|
||||
@@ -6,6 +6,13 @@
|
||||
|
||||
class ElekstubeIPSUsermod : public Usermod {
|
||||
private:
|
||||
// strings to reduce flash memory usage (used more than twice)
|
||||
static const char _name[];
|
||||
static const char _tubeSeg[];
|
||||
static const char _digitOffset[];
|
||||
|
||||
char cronixieDisplay[7] = "HHMMSS";
|
||||
|
||||
TFTs tfts;
|
||||
void updateClockDisplay(TFTs::show_t show=TFTs::yes) {
|
||||
bool set[6] = {false};
|
||||
@@ -21,6 +28,8 @@ class ElekstubeIPSUsermod : public Usermod {
|
||||
set[i] = false; //display HHMMSS time
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t hr = hour(localTime);
|
||||
uint8_t hrTens = hr/10;
|
||||
uint8_t mi = minute(localTime);
|
||||
@@ -37,6 +46,10 @@ class ElekstubeIPSUsermod : public Usermod {
|
||||
unsigned long lastTime = 0;
|
||||
public:
|
||||
|
||||
uint8_t lastBri;
|
||||
uint32_t lastCols[6];
|
||||
TFTs::show_t fshow=TFTs::yes;
|
||||
|
||||
void setup() {
|
||||
tfts.begin();
|
||||
tfts.fillScreen(TFT_BLACK);
|
||||
@@ -47,14 +60,99 @@ class ElekstubeIPSUsermod : public Usermod {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (toki.isTick()) {
|
||||
updateLocalTime();
|
||||
updateClockDisplay();
|
||||
if (!toki.isTick()) return;
|
||||
updateLocalTime();
|
||||
|
||||
WS2812FX::Segment& seg1 = strip.getSegment(tfts.tubeSegment);
|
||||
if (seg1.isActive()) {
|
||||
bool update = false;
|
||||
if (seg1.opacity != lastBri) update = true;
|
||||
lastBri = seg1.opacity;
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
uint32_t c = strip.getPixelColor(seg1.start + i);
|
||||
if (c != lastCols[i]) update = true;
|
||||
lastCols[i] = c;
|
||||
}
|
||||
if (update) fshow=TFTs::force;
|
||||
} else if (lastCols[0] != 0) { // Segment 1 deleted
|
||||
fshow=TFTs::force;
|
||||
lastCols[0] = 0;
|
||||
}
|
||||
|
||||
updateClockDisplay(fshow);
|
||||
fshow=TFTs::yes;
|
||||
}
|
||||
|
||||
/**
|
||||
* addToConfig() (called from set.cpp) stores persistent properties to cfg.json
|
||||
*/
|
||||
void addToConfig(JsonObject &root) {
|
||||
// we add JSON object: {"EleksTubeIPS": {"tubeSegment": 1, "digitOffset": 0}}
|
||||
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
|
||||
top[FPSTR(_tubeSeg)] = tfts.tubeSegment;
|
||||
top[FPSTR(_digitOffset)] = tfts.digitOffset;
|
||||
DEBUG_PRINTLN(F("EleksTube config saved."));
|
||||
}
|
||||
|
||||
/**
|
||||
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
|
||||
*
|
||||
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
||||
*/
|
||||
bool readFromConfig(JsonObject &root) {
|
||||
// we look for JSON object: {"EleksTubeIPS": {"tubeSegment": 1, "digitOffset": 0}}
|
||||
DEBUG_PRINT(FPSTR(_name));
|
||||
|
||||
JsonObject top = root[FPSTR(_name)];
|
||||
if (top.isNull()) {
|
||||
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
||||
return false;
|
||||
}
|
||||
|
||||
tfts.tubeSegment = top[FPSTR(_tubeSeg)] | tfts.tubeSegment;
|
||||
uint8_t digitOffsetPrev = tfts.digitOffset;
|
||||
tfts.digitOffset = top[FPSTR(_digitOffset)] | tfts.digitOffset;
|
||||
if (tfts.digitOffset > 240) tfts.digitOffset = 240;
|
||||
if (tfts.digitOffset != digitOffsetPrev) fshow=TFTs::force;
|
||||
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
return !top[FPSTR(_digitOffset)].isNull();
|
||||
}
|
||||
|
||||
/*
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void addToJsonState(JsonObject& root)
|
||||
{
|
||||
root["nx"] = cronixieDisplay;
|
||||
root[FPSTR(_digitOffset)] = tfts.digitOffset;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void readFromJsonState(JsonObject& root)
|
||||
{
|
||||
if (root["nx"].is<const char*>()) {
|
||||
strncpy(cronixieDisplay, root["nx"], 6);
|
||||
}
|
||||
|
||||
uint8_t digitOffsetPrev = tfts.digitOffset;
|
||||
tfts.digitOffset = root[FPSTR(_digitOffset)] | tfts.digitOffset;
|
||||
if (tfts.digitOffset > 240) tfts.digitOffset = 240;
|
||||
if (tfts.digitOffset != digitOffsetPrev) fshow=TFTs::force;
|
||||
}
|
||||
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_ELEKSTUBE_IPS;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// strings to reduce flash memory usage (used more than twice)
|
||||
const char ElekstubeIPSUsermod::_name[] PROGMEM = "EleksTubeIPS";
|
||||
const char ElekstubeIPSUsermod::_tubeSeg[] PROGMEM = "tubeSegment";
|
||||
const char ElekstubeIPSUsermod::_digitOffset[] PROGMEM = "digitOffset";
|
||||
|
||||
76
usermods/RelayBlinds/index.htm
Normal file
76
usermods/RelayBlinds/index.htm
Normal file
@@ -0,0 +1,76 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<title>Blinds</title>
|
||||
<script>
|
||||
strA = "";
|
||||
function send()
|
||||
{
|
||||
nocache = "&nocache=" + Math.random() * 1000000;
|
||||
var request = new XMLHttpRequest();
|
||||
// send HTTP request
|
||||
request.open("GET", "win/" + strA +nocache, true);
|
||||
request.send(null);
|
||||
strA = "";
|
||||
}
|
||||
function up()
|
||||
{
|
||||
strA = "&U0=2";
|
||||
send();
|
||||
}
|
||||
function down()
|
||||
{
|
||||
strA = "&U0=1";
|
||||
send();
|
||||
}
|
||||
function OpenSettings()
|
||||
{
|
||||
window.open("/settings", "_self");
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
background: linear-gradient(45deg,#0ca,#0ac);
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
svg {
|
||||
width: 30vw;
|
||||
padding: 2vh;
|
||||
}
|
||||
.tool_box {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
</style>
|
||||
<style id="holderjs-style" type="text/css"></style></head>
|
||||
<body class=" __plain_text_READY__">
|
||||
<svg style="position: absolute; width: 0; height: 0; overflow: hidden;" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<symbol id="icon-box-add" viewBox="0 0 32 32">
|
||||
<path d="M26 2h-20l-6 6v21c0 0.552 0.448 1 1 1h30c0.552 0 1-0.448 1-1v-21l-6-6zM16 26l-10-8h6v-6h8v6h6l-10 8zM4.828 6l2-2h18.343l2 2h-22.343z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-box-remove" viewBox="0 0 32 32">
|
||||
<path d="M26 2h-20l-6 6v21c0 0.552 0.448 1 1 1h30c0.552 0 1-0.448 1-1v-21l-6-6zM20 20v6h-8v-6h-6l10-8 10 8h-6zM4.828 6l2-2h18.343l2 2h-22.343z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-cog" viewBox="0 0 32 32">
|
||||
<path d="M29.181 19.070c-1.679-2.908-0.669-6.634 2.255-8.328l-3.145-5.447c-0.898 0.527-1.943 0.829-3.058 0.829-3.361 0-6.085-2.742-6.085-6.125h-6.289c0.008 1.044-0.252 2.103-0.811 3.070-1.679 2.908-5.411 3.897-8.339 2.211l-3.144 5.447c0.905 0.515 1.689 1.268 2.246 2.234 1.676 2.903 0.672 6.623-2.241 8.319l3.145 5.447c0.895-0.522 1.935-0.82 3.044-0.82 3.35 0 6.067 2.725 6.084 6.092h6.289c-0.003-1.034 0.259-2.080 0.811-3.038 1.676-2.903 5.399-3.894 8.325-2.219l3.145-5.447c-0.899-0.515-1.678-1.266-2.232-2.226zM16 22.479c-3.578 0-6.479-2.901-6.479-6.479s2.901-6.479 6.479-6.479c3.578 0 6.479 2.901 6.479 6.479s-2.901 6.479-6.479 6.479z"></path>
|
||||
</symbol>
|
||||
</defs>
|
||||
</svg>
|
||||
<div id="tbB" class="tool_box">
|
||||
<svg id="upb" onclick="up()"><use xlink:href="#icon-box-remove"></use></svg>
|
||||
<svg id="dnb" onclick="down()"><use xlink:href="#icon-box-add"></use></svg>
|
||||
<svg id="stb" onclick="OpenSettings()"><use xlink:href="#icon-cog"></use></svg>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
1
usermods/RelayBlinds/presets.json
Normal file
1
usermods/RelayBlinds/presets.json
Normal file
@@ -0,0 +1 @@
|
||||
{"0":{},"2":{"n":"▲","win":"U0=2"},"1":{"n":"▼","win":"U0=1"}}
|
||||
8
usermods/RelayBlinds/readme.md
Normal file
8
usermods/RelayBlinds/readme.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# RelayBlinds usermod
|
||||
|
||||
This simple usermod toggles two relay pins momentarily (default for 500ms) when `userVar0` is set.
|
||||
This can be used to e.g. "push" the buttons of a window blinds motor controller.
|
||||
|
||||
v1 usermod. Please replace usermod.cpp in the `wled00` directory with the one in this file.
|
||||
You may upload `index.htm` to `[WLED-IP]/edit` to replace the default lighting UI with a simple Up/Down button one.
|
||||
Also, a simple `presets.json` file is available, this makes the relay actions controllable via two presets to facilitate control e.g. via the default UI or Alexa.
|
||||
83
usermods/RelayBlinds/usermod.cpp
Normal file
83
usermods/RelayBlinds/usermod.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
#include "wled.h"
|
||||
|
||||
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
|
||||
|
||||
//gets called once at boot. Do all initialization that doesn't depend on network here
|
||||
void userSetup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
||||
void userConnected()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Physical IO
|
||||
*/
|
||||
#define PIN_UP_RELAY 4
|
||||
#define PIN_DN_RELAY 5
|
||||
#define PIN_ON_TIME 500
|
||||
bool upActive = false, upActiveBefore = false, downActive = false, downActiveBefore = false;
|
||||
unsigned long upStartTime = 0, downStartTime = 0;
|
||||
|
||||
void handleRelay()
|
||||
{
|
||||
//up and down relays
|
||||
if (userVar0) {
|
||||
upActive = true;
|
||||
if (userVar0 == 1) {
|
||||
upActive = false;
|
||||
downActive = true;
|
||||
}
|
||||
userVar0 = 0;
|
||||
}
|
||||
|
||||
if (upActive)
|
||||
{
|
||||
if(!upActiveBefore)
|
||||
{
|
||||
pinMode(PIN_UP_RELAY, OUTPUT);
|
||||
digitalWrite(PIN_UP_RELAY, LOW);
|
||||
upActiveBefore = true;
|
||||
upStartTime = millis();
|
||||
DEBUG_PRINTLN("UPA");
|
||||
}
|
||||
if (millis()- upStartTime > PIN_ON_TIME)
|
||||
{
|
||||
upActive = false;
|
||||
DEBUG_PRINTLN("UPN");
|
||||
}
|
||||
} else if (upActiveBefore)
|
||||
{
|
||||
pinMode(PIN_UP_RELAY, INPUT);
|
||||
upActiveBefore = false;
|
||||
}
|
||||
|
||||
if (downActive)
|
||||
{
|
||||
if(!downActiveBefore)
|
||||
{
|
||||
pinMode(PIN_DN_RELAY, OUTPUT);
|
||||
digitalWrite(PIN_DN_RELAY, LOW);
|
||||
downActiveBefore = true;
|
||||
downStartTime = millis();
|
||||
}
|
||||
if (millis()- downStartTime > PIN_ON_TIME)
|
||||
{
|
||||
downActive = false;
|
||||
}
|
||||
} else if (downActiveBefore)
|
||||
{
|
||||
pinMode(PIN_DN_RELAY, INPUT);
|
||||
downActiveBefore = false;
|
||||
}
|
||||
}
|
||||
|
||||
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
|
||||
void userLoop()
|
||||
{
|
||||
handleRelay();
|
||||
}
|
||||
@@ -64,7 +64,7 @@ class AutoSaveUsermod : public Usermod {
|
||||
PSTR("~ %02d-%02d %02d:%02d:%02d ~"),
|
||||
month(localTime), day(localTime),
|
||||
hour(localTime), minute(localTime), second(localTime));
|
||||
savePreset(autoSavePreset, true, presetNameBuffer);
|
||||
savePreset(autoSavePreset, presetNameBuffer);
|
||||
}
|
||||
|
||||
void inline displayOverlay() {
|
||||
|
||||
@@ -65,7 +65,7 @@ void hourChime()
|
||||
//strip.resetSegments();
|
||||
selectWordSegments(true);
|
||||
colorUpdated(CALL_MODE_FX_CHANGED);
|
||||
savePreset(13, false);
|
||||
//savePreset(255);
|
||||
selectWordSegments(false);
|
||||
//strip.getSegment(0).setOption(0, true);
|
||||
strip.getSegment(0).setOption(2, true);
|
||||
@@ -299,7 +299,7 @@ void userLoop()
|
||||
if (minute(localTime) == 1){
|
||||
//turn off background segment;
|
||||
strip.getSegment(0).setOption(2, false);
|
||||
//applyPreset(13);
|
||||
//applyPreset(255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2346,7 +2346,7 @@ uint16_t WS2812FX::mode_ripple_rainbow(void) {
|
||||
// incandescent bulbs change color as they get dim down.
|
||||
#define COOL_LIKE_INCANDESCENT 1
|
||||
|
||||
CRGB WS2812FX::twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat)
|
||||
CRGB IRAM_ATTR WS2812FX::twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat)
|
||||
{
|
||||
// Overall twinkle speed (changed)
|
||||
uint16_t ticks = ms / SEGENV.aux0;
|
||||
@@ -2784,16 +2784,9 @@ uint16_t WS2812FX::mode_popcorn(void) {
|
||||
if (numPopcorn == 0) numPopcorn = 1;
|
||||
|
||||
for(uint8_t i = 0; i < numPopcorn; i++) {
|
||||
bool isActive = popcorn[i].pos >= 0.0f;
|
||||
|
||||
if (isActive) { // if kernel is active, update its position
|
||||
if (popcorn[i].pos >= 0.0f) { // if kernel is active, update its position
|
||||
popcorn[i].pos += popcorn[i].vel;
|
||||
popcorn[i].vel += gravity;
|
||||
uint32_t col = color_wheel(popcorn[i].colIndex);
|
||||
if (!SEGMENT.palette && popcorn[i].colIndex < NUM_COLORS) col = SEGCOLOR(popcorn[i].colIndex);
|
||||
|
||||
uint16_t ledIndex = popcorn[i].pos;
|
||||
if (ledIndex < SEGLEN) setPixelColor(ledIndex, col);
|
||||
} else { // if kernel is inactive, randomly pop it
|
||||
if (random8() < 2) { // POP!!!
|
||||
popcorn[i].pos = 0.01f;
|
||||
@@ -2812,6 +2805,13 @@ uint16_t WS2812FX::mode_popcorn(void) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (popcorn[i].pos >= 0.0f) { // draw now active popcorn (either active before or just popped)
|
||||
uint32_t col = color_wheel(popcorn[i].colIndex);
|
||||
if (!SEGMENT.palette && popcorn[i].colIndex < NUM_COLORS) col = SEGCOLOR(popcorn[i].colIndex);
|
||||
|
||||
uint16_t ledIndex = popcorn[i].pos;
|
||||
if (ledIndex < SEGLEN) setPixelColor(ledIndex, col);
|
||||
}
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
|
||||
22
wled00/FX.h
22
wled00/FX.h
@@ -247,7 +247,7 @@ class WS2812FX {
|
||||
|
||||
// segment parameters
|
||||
public:
|
||||
typedef struct Segment { // 30 (32 in memory) bytes
|
||||
typedef struct Segment { // 31 (32 in memory) bytes
|
||||
uint16_t start;
|
||||
uint16_t stop; //segment invalid if stop == 0
|
||||
uint16_t offset;
|
||||
@@ -260,6 +260,7 @@ class WS2812FX {
|
||||
uint8_t opacity;
|
||||
uint32_t colors[NUM_COLORS];
|
||||
uint8_t cct; //0==1900K, 255==10091K
|
||||
uint8_t _capabilities;
|
||||
char *name;
|
||||
bool setColor(uint8_t slot, uint32_t c, uint8_t segn) { //returns true if changed
|
||||
if (slot >= NUM_COLORS || segn >= MAX_NUM_SEGMENTS) return false;
|
||||
@@ -335,7 +336,8 @@ class WS2812FX {
|
||||
return vLength;
|
||||
}
|
||||
uint8_t differs(Segment& b);
|
||||
uint8_t getLightCapabilities();
|
||||
inline uint8_t getLightCapabilities() {return _capabilities;}
|
||||
void refreshLightCapabilities();
|
||||
} segment;
|
||||
|
||||
// segment runtime parameters
|
||||
@@ -623,7 +625,7 @@ class WS2812FX {
|
||||
setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
|
||||
setColor(uint8_t slot, uint32_t c),
|
||||
setCCT(uint16_t k),
|
||||
setBrightness(uint8_t b),
|
||||
setBrightness(uint8_t b, bool direct = false),
|
||||
setRange(uint16_t i, uint16_t i2, uint32_t col),
|
||||
setShowCallback(show_callback cb),
|
||||
setTransition(uint16_t t),
|
||||
@@ -655,7 +657,8 @@ class WS2812FX {
|
||||
paletteFade = 0,
|
||||
paletteBlend = 0,
|
||||
milliampsPerLed = 55,
|
||||
cctBlending = 0,
|
||||
autoWhiteMode = RGBW_MODE_DUAL,
|
||||
cctBlending = 0,
|
||||
getBrightness(void),
|
||||
getModeCount(void),
|
||||
getPaletteCount(void),
|
||||
@@ -668,9 +671,13 @@ class WS2812FX {
|
||||
setPixelSegment(uint8_t n),
|
||||
gamma8(uint8_t),
|
||||
gamma8_cal(uint8_t, float),
|
||||
sin_gap(uint16_t),
|
||||
get_random_wheel_index(uint8_t);
|
||||
|
||||
inline uint8_t sin_gap(uint16_t in) {
|
||||
if (in & 0x100) return 0;
|
||||
return sin8(in + 192); // correct phase shift of sine so that it starts and stops at 0
|
||||
}
|
||||
|
||||
int8_t
|
||||
tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec);
|
||||
|
||||
@@ -887,14 +894,15 @@ class WS2812FX {
|
||||
|
||||
uint32_t _colors_t[3];
|
||||
uint8_t _bri_t;
|
||||
bool _no_rgb = false;
|
||||
|
||||
uint8_t _segment_index = 0;
|
||||
uint8_t _segment_index_palette_last = 99;
|
||||
uint8_t _mainSegment;
|
||||
|
||||
segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 24 bytes per element
|
||||
// start, stop, offset, speed, intensity, palette, mode, options, grouping, spacing, opacity (unused), color[]
|
||||
{0, 7, 0, DEFAULT_SPEED, 128, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}}
|
||||
// start, stop, offset, speed, intensity, palette, mode, options, grouping, spacing, opacity (unused), color[], capabilities
|
||||
{0, 7, 0, DEFAULT_SPEED, 128, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}, 0}
|
||||
};
|
||||
segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element
|
||||
friend class Segment_runtime;
|
||||
|
||||
@@ -133,7 +133,8 @@ void WS2812FX::service() {
|
||||
|
||||
if (!SEGMENT.isActive()) continue;
|
||||
|
||||
if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary
|
||||
// last condition ensures all solid segments are updated at the same time
|
||||
if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0))
|
||||
{
|
||||
if (SEGMENT.grouping == 0) SEGMENT.grouping = 1; //sanity check
|
||||
doShow = true;
|
||||
@@ -152,10 +153,18 @@ void WS2812FX::service() {
|
||||
_colors_t[slot] = transitions[t].currentColor(SEGMENT.colors[slot]);
|
||||
}
|
||||
if (!cctFromRgb || correctWB) busses.setSegmentCCT(_cct_t, correctWB);
|
||||
for (uint8_t c = 0; c < 3; c++) _colors_t[c] = gamma32(_colors_t[c]);
|
||||
for (uint8_t c = 0; c < NUM_COLORS; c++) {
|
||||
_colors_t[c] = gamma32(_colors_t[c]);
|
||||
}
|
||||
handle_palette();
|
||||
|
||||
// if segment is not RGB capable, force None auto white mode
|
||||
// If not RGB capable, also treat palette as if default (0), as palettes set white channel to 0
|
||||
_no_rgb = !(SEGMENT.getLightCapabilities() & 0x01);
|
||||
if (_no_rgb) Bus::setAutoWhiteMode(RGBW_MODE_MANUAL_ONLY);
|
||||
delay = (this->*_mode[SEGMENT.mode])(); //effect function
|
||||
if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++;
|
||||
Bus::setAutoWhiteMode(strip.autoWhiteMode);
|
||||
}
|
||||
|
||||
SEGENV.next_time = nowUp + delay;
|
||||
@@ -418,7 +427,7 @@ void WS2812FX::setCCT(uint16_t k) {
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812FX::setBrightness(uint8_t b) {
|
||||
void WS2812FX::setBrightness(uint8_t b, bool direct) {
|
||||
if (gammaCorrectBri) b = gamma8(b);
|
||||
if (_brightness == b) return;
|
||||
_brightness = b;
|
||||
@@ -428,8 +437,13 @@ void WS2812FX::setBrightness(uint8_t b) {
|
||||
_segments[i].setOption(SEG_OPTION_FREEZE, false);
|
||||
}
|
||||
}
|
||||
unsigned long t = millis();
|
||||
if (_segment_runtimes[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) show(); //apply brightness change immediately if no refresh soon
|
||||
if (direct) {
|
||||
// would be dangerous if applied immediately (could exceed ABL), but will not output until the next show()
|
||||
busses.setBrightness(b);
|
||||
} else {
|
||||
unsigned long t = millis();
|
||||
if (_segment_runtimes[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) show(); //apply brightness change immediately if no refresh soon
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getBrightness(void) {
|
||||
@@ -561,11 +575,14 @@ uint8_t WS2812FX::Segment::differs(Segment& b) {
|
||||
return d;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::Segment::getLightCapabilities() {
|
||||
if (!isActive()) return 0;
|
||||
void WS2812FX::Segment::refreshLightCapabilities() {
|
||||
if (!isActive()) {
|
||||
_capabilities = 0; return;
|
||||
}
|
||||
uint8_t capabilities = 0;
|
||||
uint8_t awm = Bus::getAutoWhiteMode();
|
||||
uint8_t awm = instance->autoWhiteMode;
|
||||
bool whiteSlider = (awm == RGBW_MODE_DUAL || awm == RGBW_MODE_MANUAL_ONLY);
|
||||
bool segHasValidBus = false;
|
||||
|
||||
for (uint8_t b = 0; b < busses.getNumBusses(); b++) {
|
||||
Bus *bus = busses.getBus(b);
|
||||
@@ -573,12 +590,13 @@ uint8_t WS2812FX::Segment::getLightCapabilities() {
|
||||
if (bus->getStart() >= stop) continue;
|
||||
if (bus->getStart() + bus->getLength() <= start) continue;
|
||||
|
||||
segHasValidBus = true;
|
||||
uint8_t type = bus->getType();
|
||||
if (!whiteSlider || (type != TYPE_ANALOG_1CH && (cctFromRgb || type != TYPE_ANALOG_2CH)))
|
||||
if (type != TYPE_ANALOG_1CH && (cctFromRgb || type != TYPE_ANALOG_2CH))
|
||||
{
|
||||
capabilities |= 0x01; //segment supports RGB (full color)
|
||||
capabilities |= 0x01; // segment supports RGB (full color)
|
||||
}
|
||||
if (bus->isRgbw() && whiteSlider) capabilities |= 0x02; //segment supports white channel
|
||||
if (bus->isRgbw() && whiteSlider) capabilities |= 0x02; // segment supports white channel
|
||||
if (!cctFromRgb) {
|
||||
switch (type) {
|
||||
case TYPE_ANALOG_5CH:
|
||||
@@ -588,7 +606,10 @@ uint8_t WS2812FX::Segment::getLightCapabilities() {
|
||||
}
|
||||
if (correctWB && type != TYPE_ANALOG_1CH) capabilities |= 0x04; //white balance correction (uses CCT slider)
|
||||
}
|
||||
return capabilities;
|
||||
// if seg has any bus, but no bus has RGB, it by definition supports white (at least for now)
|
||||
// In case of no RGB, disregard auto white mode and always show a white slider
|
||||
if (segHasValidBus && !(capabilities & 0x01)) capabilities |= 0x02; // segment supports white channel
|
||||
_capabilities = capabilities;
|
||||
}
|
||||
|
||||
//used for JSON API info.leds.rgbw. Little practical use, deprecate with info.leds.rgbw.
|
||||
@@ -627,7 +648,8 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping,
|
||||
Segment& seg = _segments[n];
|
||||
|
||||
//return if neither bounds nor grouping have changed
|
||||
if (seg.start == i1 && seg.stop == i2
|
||||
bool boundsUnchanged = (seg.start == i1 && seg.stop == i2);
|
||||
if (boundsUnchanged
|
||||
&& (!grouping || (seg.grouping == grouping && seg.spacing == spacing))
|
||||
&& (offset == UINT16_MAX || offset == seg.offset)) return;
|
||||
|
||||
@@ -652,6 +674,7 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping,
|
||||
}
|
||||
if (offset < UINT16_MAX) seg.offset = offset;
|
||||
_segment_runtimes[n].markForReset();
|
||||
if (!boundsUnchanged) seg.refreshLightCapabilities();
|
||||
}
|
||||
|
||||
void WS2812FX::restartRuntime() {
|
||||
@@ -741,6 +764,8 @@ void WS2812FX::fixInvalidSegments() {
|
||||
{
|
||||
if (_segments[i].start >= _length) setSegment(i, 0, 0);
|
||||
if (_segments[i].stop > _length) setSegment(i, _segments[i].start, _length);
|
||||
// this is always called as the last step after finalizeInit(), update covered bus types
|
||||
getSegment(i).refreshLightCapabilities();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -918,12 +943,6 @@ uint16_t IRAM_ATTR WS2812FX::triwave16(uint16_t in)
|
||||
return 0xFFFF - (in - 0x8000)*2;
|
||||
}
|
||||
|
||||
uint8_t IRAM_ATTR WS2812FX::sin_gap(uint16_t in) {
|
||||
if (in & 0x100) return 0;
|
||||
//if (in > 255) return 0;
|
||||
return sin8(in + 192); //correct phase shift of sine so that it starts and stops at 0
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates a tristate square wave w/ attac & decay
|
||||
* @param x input value 0-255
|
||||
@@ -1116,22 +1135,17 @@ void WS2812FX::handle_palette(void)
|
||||
*/
|
||||
uint32_t IRAM_ATTR WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri)
|
||||
{
|
||||
if (SEGMENT.palette == 0 && mcol < 3) {
|
||||
if ((SEGMENT.palette == 0 && mcol < 3) || _no_rgb) {
|
||||
uint32_t color = SEGCOLOR(mcol);
|
||||
if (pbri != 255) {
|
||||
CRGB crgb_color = col_to_crgb(color);
|
||||
crgb_color.nscale8_video(pbri);
|
||||
return crgb_to_col(crgb_color);
|
||||
} else {
|
||||
return color;
|
||||
}
|
||||
if (pbri == 255) return color;
|
||||
return RGBW32(scale8_video(R(color),pbri), scale8_video(G(color),pbri), scale8_video(B(color),pbri), scale8_video(W(color),pbri));
|
||||
}
|
||||
|
||||
uint8_t paletteIndex = i;
|
||||
if (mapping && SEGLEN > 1) paletteIndex = (i*255)/(SEGLEN -1);
|
||||
if (!wrap) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
|
||||
CRGB fastled_col;
|
||||
fastled_col = ColorFromPalette( currentPalette, paletteIndex, pbri, (paletteBlend == 3)? NOBLEND:LINEARBLEND);
|
||||
fastled_col = ColorFromPalette(currentPalette, paletteIndex, pbri, (paletteBlend == 3)? NOBLEND:LINEARBLEND);
|
||||
|
||||
return crgb_to_col(fastled_col);
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
#endif
|
||||
|
||||
//APA102
|
||||
#define B_HS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarSpiMethod> //hardware SPI
|
||||
#define B_HS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarSpi5MhzMethod> //hardware SPI
|
||||
#define B_SS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarMethod> //soft SPI
|
||||
|
||||
//LPD8806
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
* Physical IO
|
||||
*/
|
||||
|
||||
#define WLED_DEBOUNCE_THRESHOLD 50 //only consider button input of at least 50ms as valid (debouncing)
|
||||
#define WLED_LONG_PRESS 600 //long press if button is released after held for at least 600ms
|
||||
#define WLED_DOUBLE_PRESS 350 //double press if another press within 350ms after a short press
|
||||
#define WLED_LONG_REPEATED_ACTION 300 //how often a repeated action (e.g. dimming) is fired on long press on button IDs >0
|
||||
#define WLED_LONG_AP 6000 //how long the button needs to be held to activate WLED-AP
|
||||
#define WLED_DEBOUNCE_THRESHOLD 50 // only consider button input of at least 50ms as valid (debouncing)
|
||||
#define WLED_LONG_PRESS 600 // long press if button is released after held for at least 600ms
|
||||
#define WLED_DOUBLE_PRESS 350 // double press if another press within 350ms after a short press
|
||||
#define WLED_LONG_REPEATED_ACTION 300 // how often a repeated action (e.g. dimming) is fired on long press on button IDs >0
|
||||
#define WLED_LONG_AP 5000 // how long button 0 needs to be held to activate WLED-AP
|
||||
#define WLED_LONG_FACTORY_RESET 10000 // how long button 0 needs to be held to trigger a factory reset
|
||||
|
||||
static const char _mqtt_topic_button[] PROGMEM = "%s/button/%d"; // optimize flash usage
|
||||
|
||||
@@ -236,8 +237,14 @@ void handleButton()
|
||||
bool doublePress = buttonWaitTime[b]; //did we have a short press before?
|
||||
buttonWaitTime[b] = 0;
|
||||
|
||||
if (b == 0 && dur > WLED_LONG_AP) { //long press on button 0 (when released)
|
||||
WLED::instance().initAP(true);
|
||||
if (b == 0 && dur > WLED_LONG_AP) { // long press on button 0 (when released)
|
||||
if (dur > WLED_LONG_FACTORY_RESET) { // factory reset if pressed > 10 seconds
|
||||
WLED_FS.format();
|
||||
clearEEPROM();
|
||||
doReboot = true;
|
||||
} else {
|
||||
WLED::instance().initAP(true);
|
||||
}
|
||||
} else if (!buttonLongPressed[b]) { //short press
|
||||
if (b != 1 && !macroDoublePress[b]) { //don't wait for double press on buttons without a default action if no double press macro set
|
||||
shortPressAction(b);
|
||||
|
||||
@@ -80,18 +80,20 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
|
||||
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
|
||||
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]);
|
||||
Bus::setAutoWhiteMode(hw_led[F("rgbwm")] | Bus::getAutoWhiteMode());
|
||||
CJSON(strip.autoWhiteMode, hw_led[F("rgbwm")]);
|
||||
Bus::setAutoWhiteMode(strip.autoWhiteMode);
|
||||
strip.fixInvalidSegments(); // refreshes segment light capabilities (in case auto white mode changed)
|
||||
CJSON(correctWB, hw_led["cct"]);
|
||||
CJSON(cctFromRgb, hw_led[F("cr")]);
|
||||
CJSON(strip.cctBlending, hw_led[F("cb")]);
|
||||
Bus::setCCTBlend(strip.cctBlending);
|
||||
strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS
|
||||
CJSON(strip.cctBlending, hw_led[F("cb")]);
|
||||
Bus::setCCTBlend(strip.cctBlending);
|
||||
strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS
|
||||
|
||||
JsonArray ins = hw_led["ins"];
|
||||
|
||||
if (fromFS || !ins.isNull()) {
|
||||
uint8_t s = 0; // bus iterator
|
||||
busses.removeAll();
|
||||
if (fromFS) busses.removeAll(); // can't safely manipulate busses directly in network callback
|
||||
uint32_t mem = 0;
|
||||
for (JsonObject elm : ins) {
|
||||
if (s >= WLED_MAX_BUSSES) break;
|
||||
@@ -113,11 +115,17 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
uint8_t ledType = elm["type"] | TYPE_WS2812_RGB;
|
||||
bool reversed = elm["rev"];
|
||||
bool refresh = elm["ref"] | false;
|
||||
ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh
|
||||
ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh
|
||||
s++;
|
||||
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst);
|
||||
mem += BusManager::memUsage(bc);
|
||||
if (mem <= MAX_LED_MEMORY && busses.getNumBusses() <= WLED_MAX_BUSSES) busses.add(bc); // finalization will be done in WLED::beginStrip()
|
||||
if (fromFS) {
|
||||
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst);
|
||||
mem += BusManager::memUsage(bc);
|
||||
if (mem <= MAX_LED_MEMORY && busses.getNumBusses() <= WLED_MAX_BUSSES) busses.add(bc); // finalization will be done in WLED::beginStrip()
|
||||
} else {
|
||||
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
||||
busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst);
|
||||
doInitBusses = true;
|
||||
}
|
||||
}
|
||||
// finalization done in beginStrip()
|
||||
}
|
||||
@@ -196,6 +204,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
}
|
||||
}
|
||||
CJSON(irEnabled, hw["ir"]["type"]);
|
||||
CJSON(irApplyToAllSelected, hw["ir"]["sel"]);
|
||||
|
||||
JsonObject relay = hw[F("relay")];
|
||||
int hw_relay_pin = relay["pin"] | -2;
|
||||
@@ -355,10 +364,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
CJSON(latitude, if_ntp[F("lt")]);
|
||||
|
||||
JsonObject ol = doc[F("ol")];
|
||||
prev = overlayDefault;
|
||||
CJSON(overlayDefault ,ol[F("clock")]); // 0
|
||||
CJSON(overlayCurrent ,ol[F("clock")]); // 0
|
||||
CJSON(countdownMode, ol[F("cntdwn")]);
|
||||
if (prev != overlayDefault) overlayCurrent = overlayDefault;
|
||||
|
||||
CJSON(overlayMin, ol["min"]);
|
||||
CJSON(overlayMax, ol[F("max")]);
|
||||
@@ -399,15 +406,15 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
if (act) timerWeekday[it]++;
|
||||
}
|
||||
if (it<8) {
|
||||
JsonObject start = timer["start"];
|
||||
byte startm = start["mon"];
|
||||
if (startm) timerMonth[it] = (startm << 4);
|
||||
JsonObject start = timer["start"];
|
||||
byte startm = start["mon"];
|
||||
if (startm) timerMonth[it] = (startm << 4);
|
||||
CJSON(timerDay[it], start["day"]);
|
||||
JsonObject end = timer["end"];
|
||||
CJSON(timerDayEnd[it], end["day"]);
|
||||
byte endm = end["mon"];
|
||||
if (startm) timerMonth[it] += endm & 0x0F;
|
||||
if (!(timerMonth[it] & 0x0F)) timerMonth[it] += 12; //default end month to 12
|
||||
JsonObject end = timer["end"];
|
||||
CJSON(timerDayEnd[it], end["day"]);
|
||||
byte endm = end["mon"];
|
||||
if (startm) timerMonth[it] += endm & 0x0F;
|
||||
if (!(timerMonth[it] & 0x0F)) timerMonth[it] += 12; //default end month to 12
|
||||
}
|
||||
it++;
|
||||
}
|
||||
@@ -571,9 +578,9 @@ void serializeConfig() {
|
||||
hw_led[F("ledma")] = strip.milliampsPerLed;
|
||||
hw_led["cct"] = correctWB;
|
||||
hw_led[F("cr")] = cctFromRgb;
|
||||
hw_led[F("cb")] = strip.cctBlending;
|
||||
hw_led["fps"] = strip.getTargetFps();
|
||||
hw_led[F("rgbwm")] = Bus::getAutoWhiteMode();
|
||||
hw_led[F("cb")] = strip.cctBlending;
|
||||
hw_led["fps"] = strip.getTargetFps();
|
||||
hw_led[F("rgbwm")] = strip.autoWhiteMode;
|
||||
|
||||
JsonArray hw_led_ins = hw_led.createNestedArray("ins");
|
||||
|
||||
@@ -630,6 +637,7 @@ void serializeConfig() {
|
||||
JsonObject hw_ir = hw.createNestedObject("ir");
|
||||
hw_ir["pin"] = irPin;
|
||||
hw_ir["type"] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled )
|
||||
hw_ir["sel"] = irApplyToAllSelected;
|
||||
|
||||
JsonObject hw_relay = hw.createNestedObject(F("relay"));
|
||||
hw_relay["pin"] = rlyPin;
|
||||
@@ -763,7 +771,7 @@ void serializeConfig() {
|
||||
if_ntp[F("lt")] = latitude;
|
||||
|
||||
JsonObject ol = doc.createNestedObject("ol");
|
||||
ol[F("clock")] = overlayDefault;
|
||||
ol[F("clock")] = overlayCurrent;
|
||||
ol[F("cntdwn")] = countdownMode;
|
||||
|
||||
ol["min"] = overlayMin;
|
||||
@@ -791,11 +799,11 @@ void serializeConfig() {
|
||||
timers_ins0["macro"] = timerMacro[i];
|
||||
timers_ins0[F("dow")] = timerWeekday[i] >> 1;
|
||||
if (i<8) {
|
||||
JsonObject start = timers_ins0.createNestedObject("start");
|
||||
JsonObject start = timers_ins0.createNestedObject("start");
|
||||
start["mon"] = (timerMonth[i] >> 4) & 0xF;
|
||||
start["day"] = timerDay[i];
|
||||
JsonObject end = timers_ins0.createNestedObject("end");
|
||||
end["mon"] = timerMonth[i] & 0xF;
|
||||
JsonObject end = timers_ins0.createNestedObject("end");
|
||||
end["mon"] = timerMonth[i] & 0xF;
|
||||
end["day"] = timerDayEnd[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,33 +10,6 @@ void setRandomColor(byte* rgb)
|
||||
colorHStoRGB(lastRandomIndex*256,255,rgb);
|
||||
}
|
||||
|
||||
void colorFromUint32(uint32_t in, bool secondary)
|
||||
{
|
||||
byte *_col = secondary ? colSec : col;
|
||||
_col[0] = R(in);
|
||||
_col[1] = G(in);
|
||||
_col[2] = B(in);
|
||||
_col[3] = W(in);
|
||||
}
|
||||
|
||||
//load a color without affecting the white channel
|
||||
void colorFromUint24(uint32_t in, bool secondary)
|
||||
{
|
||||
byte *_col = secondary ? colSec : col;
|
||||
_col[0] = R(in);
|
||||
_col[1] = G(in);
|
||||
_col[2] = B(in);
|
||||
}
|
||||
|
||||
//relatively change white brightness, minumum A=5
|
||||
void relativeChangeWhite(int8_t amount, byte lowerBoundary)
|
||||
{
|
||||
int16_t new_val = (int16_t) col[3] + amount;
|
||||
if (new_val > 0xFF) new_val = 0xFF;
|
||||
else if (new_val < lowerBoundary) new_val = lowerBoundary;
|
||||
col[3] = new_val;
|
||||
}
|
||||
|
||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
|
||||
{
|
||||
float h = ((float)hue)/65535.0;
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
#define USERMOD_RGB_ROTARY_ENCODER 22 //Usermod "rgb-rotary-encoder.h"
|
||||
#define USERMOD_ID_QUINLED_AN_PENTA 23 //Usermod "quinled-an-penta.h"
|
||||
#define USERMOD_ID_SSDR 24 //Usermod "usermod_v2_seven_segment_display_reloaded.h"
|
||||
#define USERMOD_ID_CRONIXIE 25 //Usermod "usermod_cronixie.h"
|
||||
|
||||
//Access point behavior
|
||||
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
||||
|
||||
@@ -45,12 +45,10 @@ body {
|
||||
text-align: center;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
scrollbar-width: 6px;
|
||||
scrollbar-color: var(--c-sb) transparent;
|
||||
scrollbar-width: 6px;
|
||||
scrollbar-color: var(--c-sb) transparent;
|
||||
}
|
||||
|
||||
html,
|
||||
@@ -93,7 +91,7 @@ button {
|
||||
bottom: calc(var(--bh) + 6px);
|
||||
right: 4px;
|
||||
color: var(--c-6);
|
||||
cursor: pointer;
|
||||
cursor: pointer;
|
||||
writing-mode: vertical-rl;
|
||||
}
|
||||
|
||||
@@ -128,11 +126,6 @@ button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.segt {
|
||||
table-layout: fixed;
|
||||
width: 76%;
|
||||
}
|
||||
|
||||
.segtd {
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
@@ -167,25 +160,25 @@ button {
|
||||
}
|
||||
|
||||
.edit-icon {
|
||||
position: absolute;
|
||||
right: -26px;
|
||||
top: 10px;
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: -26px;
|
||||
top: 10px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
top: 10px;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
top: 10px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.search-cancel-icon {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 9px;
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 9px;
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.flr {
|
||||
@@ -286,7 +279,7 @@ button {
|
||||
padding-top: 0;
|
||||
margin-top: 11px;
|
||||
height: calc(100% - 11px);
|
||||
-webkit-overflow-scrolling: touch;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.smooth { transition: transform calc(var(--f, 1)*.5s) ease-out }
|
||||
@@ -294,6 +287,7 @@ button {
|
||||
.tab-label {
|
||||
margin: 0 0 -5px 0;
|
||||
padding-bottom: 4px;
|
||||
display: var(--bhd);
|
||||
}
|
||||
|
||||
.overlay {
|
||||
@@ -332,7 +326,7 @@ button {
|
||||
|
||||
#fxb0 {
|
||||
margin-bottom: 2px;
|
||||
filter: drop-shadow(0 0 1px #000);
|
||||
filter: drop-shadow(0 0 1px #000);
|
||||
}
|
||||
|
||||
.first {
|
||||
@@ -382,7 +376,7 @@ button {
|
||||
}
|
||||
|
||||
.modal button:hover {
|
||||
background-color: var(--c-4);
|
||||
background-color: var(--c-4);
|
||||
}
|
||||
|
||||
#info {
|
||||
@@ -394,7 +388,7 @@ button {
|
||||
}
|
||||
|
||||
#ndlt {
|
||||
margin: 12px 0;
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
.valtd i {
|
||||
@@ -430,7 +424,7 @@ button {
|
||||
}
|
||||
|
||||
#kn td {
|
||||
padding-bottom: 12px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
#lv {
|
||||
@@ -469,27 +463,27 @@ img {
|
||||
border-radius: 17px;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
--bg: var(--c-f);
|
||||
--bg: var(--c-f);
|
||||
}
|
||||
|
||||
#rwrap .sliderdisplay { --bg: #f00; }
|
||||
#gwrap .sliderdisplay { --bg: #0f0; }
|
||||
#bwrap .sliderdisplay { --bg: #00f; }
|
||||
#wbal .sliderdisplay, #kwrap .sliderdisplay {
|
||||
background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #cbdbff);
|
||||
background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #cbdbff);
|
||||
}
|
||||
|
||||
.sliderbubble {
|
||||
width: 36px;
|
||||
line-height: 24px;
|
||||
background: var(--c-3);
|
||||
position: absolute;
|
||||
transform: translateX(-50%);
|
||||
border-radius: 12px;
|
||||
margin-left: 12px;
|
||||
margin-top: 3px;
|
||||
padding: 0px;
|
||||
display: inline;
|
||||
width: 36px;
|
||||
line-height: 24px;
|
||||
background: var(--c-3);
|
||||
position: absolute;
|
||||
transform: translateX(-50%);
|
||||
border-radius: 12px;
|
||||
margin-left: 12px;
|
||||
margin-top: 3px;
|
||||
padding: 0px;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
@@ -540,28 +534,29 @@ input[type=range]:active + .sliderbubble {
|
||||
display: inline;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
#wwrap, #wbal {
|
||||
/* hide color controls until enabled in updateUI() */
|
||||
#pwrap, #wwrap, #wbal, #rgbwrap, #palwrap {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Slider wrapper div */
|
||||
.sliderwrap {
|
||||
height: 30px;
|
||||
width: 240px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Segment power button + brightness slider wrapper div */
|
||||
.sbs {
|
||||
margin: 0px -20px 5px -6px;
|
||||
}
|
||||
|
||||
/* Segment brightness slider wrapper div */
|
||||
.sws {
|
||||
width: 230px;
|
||||
}
|
||||
|
||||
.sis {
|
||||
width: 214px !important;
|
||||
margin-left: -7px;
|
||||
}
|
||||
|
||||
/* Dynamically hide brightness slider label */
|
||||
.hd {
|
||||
display: var(--bhd);
|
||||
}
|
||||
@@ -576,10 +571,6 @@ input[type=range]:active + .sliderbubble {
|
||||
width: 260px;
|
||||
}
|
||||
|
||||
#rgbwrap {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 8px;
|
||||
margin: 10px;
|
||||
@@ -587,7 +578,7 @@ input[type=range]:active + .sliderbubble {
|
||||
font-size: 19px;
|
||||
background-color: var(--c-3);
|
||||
color: var(--c-f);
|
||||
cursor: pointer;
|
||||
cursor: pointer;
|
||||
border: 0px solid white;
|
||||
border-radius: 25px;
|
||||
transition-duration: 0.5s;
|
||||
@@ -595,6 +586,14 @@ input[type=range]:active + .sliderbubble {
|
||||
-webkit-transform:translate3d(0,0,0);*/
|
||||
}
|
||||
|
||||
/* Small round button (color selectors, icon-only round buttons) */
|
||||
.xxs {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 6px;
|
||||
}
|
||||
|
||||
/* Segments/presets auxiliary buttons (Add segment, Create preset, ...) */
|
||||
.btn-s {
|
||||
width: 276px;
|
||||
background-color: var(--c-2);
|
||||
@@ -606,61 +605,80 @@ input[type=range]:active + .sliderbubble {
|
||||
margin: 0px 8px 4px 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.btna-icon {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
/* Wide button used in presets (Save, playlist test, delete) */
|
||||
.btn-p {
|
||||
width: 216px;
|
||||
}
|
||||
.btn-xs {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
margin: 2px 0 0 0;
|
||||
|
||||
/* Delete preset from playlist button */
|
||||
.btn-pl-del {
|
||||
margin: 0 0 0 3px;
|
||||
}
|
||||
|
||||
/* Add preset to playlist "+" button */
|
||||
.btn-pl-add {
|
||||
margin-left: 5px;
|
||||
margin: 3px 0 0 8px;
|
||||
}
|
||||
|
||||
|
||||
/* Quick color select buttons wrapper div */
|
||||
#qcs-w {
|
||||
margin-top: 10px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Quick color select buttons */
|
||||
.qcs {
|
||||
padding: 14px;
|
||||
margin: 2px;
|
||||
border-radius: 14px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Quick color select Black button (has white border) */
|
||||
.qcsb {
|
||||
padding: 13px;
|
||||
border: 1px solid var(--c-f);
|
||||
}
|
||||
|
||||
/* Hex color input wrapper div */
|
||||
#hexw {
|
||||
margin-top: 5px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Transition time input */
|
||||
#tt {
|
||||
text-align: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Color slot select buttons (1,2,3) */
|
||||
.cl {
|
||||
width: 42px;
|
||||
width: 38.5px;
|
||||
height: 38.5px;
|
||||
margin: 7px;
|
||||
background-color: #000;
|
||||
box-shadow: 0 0 0 1.5px #fff;
|
||||
}
|
||||
.selected.cl {
|
||||
box-shadow: 0 0 0 5px #fff;
|
||||
}
|
||||
|
||||
/* Playlist preset select */
|
||||
.sel-pl {
|
||||
width: 192px;
|
||||
background-position: 168px 16px;
|
||||
margin: 8px 3px 0 0;
|
||||
width: 192px;
|
||||
background-position: 168px 16px;
|
||||
margin: 8px 3px 0 0;
|
||||
}
|
||||
|
||||
/* Playlist end preset select */
|
||||
.sel-ple {
|
||||
width: 216px;
|
||||
background-position: 192px 16px;
|
||||
background-position: 192px 16px;
|
||||
}
|
||||
|
||||
select {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='white'><polygon points='0,0 100,0 50,50'/></svg>") no-repeat;
|
||||
background-size: 12px;
|
||||
@@ -691,7 +709,6 @@ input[type=number], input[type=text] {
|
||||
outline: none;
|
||||
width: 50px;
|
||||
-webkit-appearance: textfield;
|
||||
-moz-appearance: textfield;
|
||||
appearance: textfield;
|
||||
}
|
||||
|
||||
@@ -708,7 +725,7 @@ textarea {
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: var(--c-b);
|
||||
background: var(--c-b);
|
||||
}
|
||||
|
||||
input[type=text] {
|
||||
@@ -716,18 +733,18 @@ input[type=text] {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ptxt {
|
||||
width: 200px !important;
|
||||
margin: 26px 0 6px 12px !important;
|
||||
input[type=text].ptxt {
|
||||
width: 200px;
|
||||
margin: 26px 0 6px 12px;
|
||||
}
|
||||
|
||||
.stxt {
|
||||
display: none;
|
||||
margin-top: 6px !important;
|
||||
input[type=text].stxt {
|
||||
display: none;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.qltxt {
|
||||
width: 50px !important;
|
||||
input[type=text].qltxt {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
input[type=number]:focus, input[type=text]:focus {
|
||||
@@ -756,42 +773,50 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
}
|
||||
|
||||
.segn {
|
||||
border-radius: 5px !important;
|
||||
border-radius: 5px !important;
|
||||
margin: 3px 0 6px 0 !important;
|
||||
}
|
||||
|
||||
.segname {
|
||||
.pname, .plname, .segname {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 50%;
|
||||
padding: 9px 0;
|
||||
transform: translateX(-50%);
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.segntxt {
|
||||
max-width: 160px;
|
||||
overflow: hidden;
|
||||
text-overflow: clip;
|
||||
max-width: 160px;
|
||||
overflow: hidden;
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
||||
.pname {
|
||||
.segname {
|
||||
top: 0px;
|
||||
padding: 9px 0;
|
||||
}
|
||||
.pname, .plname {
|
||||
width: 208px;
|
||||
padding: 8px 0;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: clip;
|
||||
}
|
||||
.pname {
|
||||
top: 1px;
|
||||
}
|
||||
.plname {
|
||||
top:0;
|
||||
}
|
||||
|
||||
.pid {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
padding: 11px 0px 0px 11px;
|
||||
font-size: 16px;
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
padding: 11px 0px 0px 11px;
|
||||
font-size: 16px;
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
color: var(--c-b);
|
||||
}
|
||||
|
||||
@@ -803,11 +828,7 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
padding: 6px 0 0 0;
|
||||
}
|
||||
|
||||
.xxs {
|
||||
width: 40px;
|
||||
margin: 6px;
|
||||
}
|
||||
|
||||
/* Quick preset select buttons */
|
||||
.psts {
|
||||
background-color: var(--c-3);
|
||||
color: var(--c-f);
|
||||
@@ -816,20 +837,17 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
/* Segment apply button (checkmark) */
|
||||
.cnf {
|
||||
color: var(--c-f);
|
||||
cursor: pointer;
|
||||
background: var(--c-3);
|
||||
border-radius: 5px;
|
||||
padding: 8.5px 21px 5px;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.cnf-s {
|
||||
position: absolute;
|
||||
bottom: 100px;
|
||||
right: 23px;
|
||||
padding: 7px 22px;
|
||||
}
|
||||
|
||||
/* Segment power button icon */
|
||||
.pwr {
|
||||
color: var(--c-6);
|
||||
transform: translate(2px, 3px);
|
||||
@@ -840,17 +858,10 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
color: var(--c-f);
|
||||
}
|
||||
|
||||
.half {
|
||||
padding: 7.5px;
|
||||
bottom: 35px;
|
||||
}
|
||||
|
||||
.del {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
color: var(--c-f);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.check, .radio {
|
||||
@@ -874,9 +885,9 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
}
|
||||
|
||||
.fxchkl {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 8px;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 8px;
|
||||
}
|
||||
|
||||
.check input, .radio input {
|
||||
@@ -889,19 +900,22 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
|
||||
.checkmark, .radiomark {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
background-color: var(--c-3);
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
background-color: var(--c-4);
|
||||
border-radius: 10px;
|
||||
/*border: 1px solid var(--c-2);*/
|
||||
}
|
||||
|
||||
.checkmark {
|
||||
top: 6px;
|
||||
}
|
||||
|
||||
.radiomark {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
border-radius: 50%;
|
||||
background-color: transparent;
|
||||
background-color: transparent;
|
||||
top: 7px;
|
||||
}
|
||||
|
||||
.schk {
|
||||
@@ -923,7 +937,7 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
|
||||
|
||||
.check:hover input ~ .checkmark {
|
||||
background-color: var(--c-4);
|
||||
background-color: var(--c-5);
|
||||
}
|
||||
|
||||
.check input:checked ~ .checkmark {
|
||||
@@ -941,8 +955,8 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
}
|
||||
|
||||
.check .checkmark:after {
|
||||
left: 9px;
|
||||
top: 5px;
|
||||
left: 8px;
|
||||
top: 4px;
|
||||
width: 5px;
|
||||
height: 10px;
|
||||
border: solid var(--c-f);
|
||||
@@ -972,7 +986,7 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.seg {
|
||||
.seg, .pres {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
padding: 8px;
|
||||
@@ -985,29 +999,41 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
border-radius: 20px;
|
||||
text-align: left;
|
||||
transition: background-color 0.5s;
|
||||
filter: brightness(1);
|
||||
filter: brightness(1); /* required for slider background to render? */
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: var(--c-4);
|
||||
}
|
||||
/* "selected" CSS class is applied to the segment when it is the main segment.
|
||||
By default, do not highlight. Can be overridden by skin.css */
|
||||
.selected.seg {
|
||||
background-color: var(--c-2); /* var(--c-4); */
|
||||
}
|
||||
.selected .checkmark, .selected .radiokmark {
|
||||
background-color: var(--c-4); /* var(--c-6); */
|
||||
}
|
||||
|
||||
.list {
|
||||
position: relative;
|
||||
transition: background-color 0.5s;
|
||||
margin: auto auto 10px;
|
||||
padding-bottom: 10px;
|
||||
width: 230px;
|
||||
margin: auto auto 10px;
|
||||
padding-bottom: 10px;
|
||||
width: 230px;
|
||||
}
|
||||
|
||||
.lstI {
|
||||
position: sticky;
|
||||
overflow: hidden;
|
||||
position: sticky;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.fxbtn {
|
||||
margin: 20px auto;
|
||||
padding: 8px 0;
|
||||
margin: 20px auto;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.lstI:hover {
|
||||
background: var(--c-4);
|
||||
background: var(--c-4);
|
||||
}
|
||||
|
||||
.lstI:last-child {
|
||||
@@ -1030,7 +1056,7 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
.lstI.selected {
|
||||
background: var(--c-5);
|
||||
top: 95px;
|
||||
bottom: -11px;
|
||||
bottom: -11px;
|
||||
}
|
||||
|
||||
.lstI.sticky {
|
||||
@@ -1041,26 +1067,26 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
margin: 3px 0;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
font-size: 19px;
|
||||
font-size: 19px;
|
||||
}
|
||||
|
||||
.lstIprev {
|
||||
width: 220px;
|
||||
height: 5px;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 5px;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 5px;
|
||||
}
|
||||
|
||||
input[type="text"].search {
|
||||
display: block;
|
||||
width: 230px;
|
||||
box-sizing: border-box;
|
||||
padding: 8px 8px 9px 38px;
|
||||
margin: 6px auto 0 auto;
|
||||
padding: 8px 8px 9px 38px;
|
||||
margin: 6px auto 0 auto;
|
||||
text-align: left;
|
||||
background-color: var(--c-3);
|
||||
background-color: var(--c-3);
|
||||
}
|
||||
|
||||
input[type="text"].search:focus {
|
||||
@@ -1098,9 +1124,13 @@ input[type="text"].search:not(:placeholder-shown) {
|
||||
}
|
||||
|
||||
.hrz {
|
||||
width: auto;
|
||||
height: 2px;
|
||||
background-color: var(--c-b);
|
||||
width: auto;
|
||||
height: 2px;
|
||||
background-color: var(--c-b);
|
||||
}
|
||||
|
||||
.no-margin {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
@@ -1120,8 +1150,8 @@ input[type="text"].search:not(:placeholder-shown) {
|
||||
|
||||
@media all and (max-width: 335px) {
|
||||
.sliderbubble {
|
||||
display: none;
|
||||
}
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 550px) and (min-width: 374px) {
|
||||
@@ -1146,6 +1176,6 @@ input[type="text"].search:not(:placeholder-shown) {
|
||||
|
||||
@media all and (max-width: 1249px) {
|
||||
#buttonPcm {
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,13 +44,15 @@
|
||||
|
||||
<div class ="container">
|
||||
<div id="Colors" class="tabcontent">
|
||||
<div id="picker" class="noslide"></div>
|
||||
<div id="vwrap">
|
||||
<div class="sliderwrap il" id="vwrap">
|
||||
<input id="sliderV" class="noslide" oninput="fromV()" onchange="setColor(0)" max="100" min="0" type="range" value="128" step="any" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div><br>
|
||||
</div>
|
||||
<div id="pwrap">
|
||||
<div id="picker" class="noslide"></div>
|
||||
<div id="vwrap">
|
||||
<div class="sliderwrap il" id="vwrap">
|
||||
<input id="sliderV" class="noslide" oninput="fromV()" onchange="setColor(0)" max="100" min="0" type="range" value="128" step="any" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div><br>
|
||||
</div>
|
||||
</div>
|
||||
<div id="kwrap">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderK" class="noslide" oninput="fromK()" onchange="setColor(0)" max="10091" min="1900" type="range" value="6550" />
|
||||
@@ -106,34 +108,28 @@
|
||||
</div>
|
||||
<div id="hexw">
|
||||
<input id="hexc" type="text" class="noslide" onkeydown="hexEnter()" autocomplete="off" maxlength="8" />
|
||||
<button id="hexcnf" class="xxs btn" onclick="fromHex();"><i class="icons btna-icon"></i></button>
|
||||
<button id="hexcnf" class="xxs btn" onclick="fromHex();"><i class="icons no-margin"></i></button>
|
||||
</div>
|
||||
<p class="labels">
|
||||
<i class="icons sel-icon" onclick="tglHex()"></i>
|
||||
Color palette
|
||||
</p>
|
||||
<div class="il">
|
||||
<div id="pallist" class="list">
|
||||
<div class="lstI" data-id="0">
|
||||
<label class="check schkl">
|
||||
|
||||
<input type="radio" value="${palettes[i].id}" name="palette" onChange="setPalette()">
|
||||
<span class="radiomark schk"></span>
|
||||
</label>
|
||||
<div class="lstIcontent">
|
||||
<span class="lstIname">
|
||||
Default
|
||||
</span>
|
||||
<div id="palwrap">
|
||||
<p class="labels">
|
||||
<i class="icons sel-icon" onclick="tglHex()"></i>
|
||||
Color palette
|
||||
</p>
|
||||
<div class="il">
|
||||
<div id="pallist" class="list">
|
||||
<div class="lstI" data-id="0">
|
||||
<label class="check schkl">
|
||||
|
||||
<input type="radio" value="${palettes[i].id}" name="palette" onChange="setPalette()">
|
||||
<span class="radiomark schk"></span>
|
||||
</label>
|
||||
<div class="lstIcontent">
|
||||
<span class="lstIname">
|
||||
Default
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lstI">
|
||||
<div class="lstIcontent">
|
||||
<span class="lstIname">
|
||||
Loading...
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -141,7 +137,7 @@
|
||||
<div id="Effects" class="tabcontent">
|
||||
<p class="labels">Effect speed</p>
|
||||
<div class="staytop">
|
||||
<i class="icons slider-icon" onclick="tglFreeze()"></i>
|
||||
<i class="icons slider-icon" style="cursor: pointer;" onclick="tglFreeze()"></i>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderSpeed" class="noslide" onchange="setSpeed()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||
<output class="sliderbubble hidden"></output>
|
||||
@@ -227,7 +223,6 @@
|
||||
<button class="btn" onclick="setLor(2)">Override until reboot</button><br>
|
||||
<span class="h">For best performance, it is recommended to turn off the streaming source when not in use.</span>
|
||||
</div>
|
||||
|
||||
<i id="roverstar" class="icons huge" onclick="setLor(0)"></i><br>
|
||||
<script src="iro.js"></script>
|
||||
<script src="rangetouch.js"></script>
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
//page js
|
||||
var loc = false, locip;
|
||||
var noNewSegs = false;
|
||||
var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, syncSend = false, syncTglRecv = true, isRgbw = false;
|
||||
var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, syncSend = false, syncTglRecv = true;
|
||||
var hasWhite = false, hasRGB = false, hasCCT = false;
|
||||
var whites = [0,0,0];
|
||||
var selColors;
|
||||
var colors = [[0,0,0],[0,0,0],[0,0,0]];
|
||||
var expanded = [false];
|
||||
var powered = [true];
|
||||
var nlDur = 60, nlTar = 0;
|
||||
var nlMode = false;
|
||||
var selectedFx = 0;
|
||||
var csel = 0;
|
||||
var csel = 0; // selected color slot (0-2)
|
||||
var currentPreset = -1;
|
||||
var lastUpdate = 0;
|
||||
var segCount = 0, ledCount = 0, lowestUnused = 0, maxSeg = 0, lSeg = 0;
|
||||
@@ -27,7 +28,7 @@ var fxlist = d.getElementById('fxlist'), pallist = d.getElementById('pallist');
|
||||
var cfg = {
|
||||
theme:{base:"dark", bg:{url:""}, alpha:{bg:0.6,tab:0.8}, color:{bg:""}},
|
||||
comp :{colors:{picker: true, rgb: false, quick: true, hex: false},
|
||||
labels:true, pcmbot:false, pid:true, seglen:false, css:true, hdays:false}
|
||||
labels:true, pcmbot:false, pid:true, seglen:false, css:true, hdays:false}
|
||||
};
|
||||
var hol = [
|
||||
[0,11,24,4,"https://aircoookie.github.io/xmas.png"], // christmas
|
||||
@@ -40,14 +41,14 @@ var hol = [
|
||||
var cpick = new iro.ColorPicker("#picker", {
|
||||
width: 260,
|
||||
wheelLightness: false,
|
||||
wheelAngle: 270,
|
||||
wheelDirection: "clockwise",
|
||||
layout: [
|
||||
{
|
||||
component: iro.ui.Wheel,
|
||||
options: {}
|
||||
}
|
||||
]
|
||||
wheelAngle: 270,
|
||||
wheelDirection: "clockwise",
|
||||
layout: [
|
||||
{
|
||||
component: iro.ui.Wheel,
|
||||
options: {}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
function handleVisibilityChange() {
|
||||
@@ -60,27 +61,48 @@ function sCol(na, col) {
|
||||
d.documentElement.style.setProperty(na, col);
|
||||
}
|
||||
|
||||
function isRgbBlack(a, s) {
|
||||
return (a[s][0] == 0 && a[s][1] == 0 && a[s][2] == 0);
|
||||
}
|
||||
|
||||
// returns RGB color from a given slot s 0-2 from color array a
|
||||
function rgbStr(a, s) {
|
||||
return "rgb(" + a[s][0] + "," + a[s][1] + "," + a[s][2] + ")";
|
||||
}
|
||||
|
||||
// brightness approximation for selecting white as text color if background bri < 127, and black if higher
|
||||
function rgbBri(a, s) {
|
||||
var R = a[s][0], G = a[s][1], B = a[s][2];
|
||||
return 0.2126*R + 0.7152*G + 0.0722*B;
|
||||
}
|
||||
|
||||
// sets background of color slot selectors
|
||||
function setCSL(s) {
|
||||
var cd = d.getElementsByClassName('cl')[s];
|
||||
var w = whites[s];
|
||||
if (hasRGB && !isRgbBlack(colors, s)) {
|
||||
cd.style.background = rgbStr(colors, s);
|
||||
cd.style.color = rgbBri(colors, s) > 127 ? "#000":"#fff";
|
||||
if (hasWhite && w > 0) {
|
||||
cd.style.background = `linear-gradient(180deg, ${rgbStr(colors, s)} 30%, ${rgbStr([[w,w,w]], 0)})`;
|
||||
}
|
||||
} else {
|
||||
if (!hasWhite) w = 0;
|
||||
cd.style.background = rgbStr([[w,w,w]], 0);
|
||||
cd.style.color = w > 127 ? "#000":"#fff";
|
||||
}
|
||||
}
|
||||
|
||||
function applyCfg()
|
||||
{
|
||||
cTheme(cfg.theme.base === "light");
|
||||
var bg = cfg.theme.color.bg;
|
||||
if (bg) sCol('--c-1', bg);
|
||||
var ccfg = cfg.comp.colors;
|
||||
d.getElementById('hexw').style.display = ccfg.hex ? "block":"none";
|
||||
d.getElementById('picker').style.display = ccfg.picker ? "block":"none";
|
||||
d.getElementById('vwrap').style.display = ccfg.picker ? "block":"none";
|
||||
d.getElementById('kwrap').style.display = ccfg.picker ? "block":"none";
|
||||
d.getElementById('rgbwrap').style.display = ccfg.rgb ? "block":"none";
|
||||
d.getElementById('qcs-w').style.display = ccfg.quick ? "block":"none";
|
||||
if (lastinfo.leds) updateUI(); // update component visibility
|
||||
var l = cfg.comp.labels;
|
||||
var e = d.querySelectorAll('.tab-label');
|
||||
for (var i=0; i<e.length; i++)
|
||||
e[i].style.display = l ? "block":"none";
|
||||
e = d.querySelector('.hd');
|
||||
e.style.display = l ? "block":"none";
|
||||
sCol('--tbp',l ? "14px 14px 10px 14px":"10px 22px 4px 22px");
|
||||
sCol('--bbp',l ? "9px 0 7px 0":"10px 0 4px 0");
|
||||
sCol('--bhd',l ? "block":"none");
|
||||
sCol('--bhd',l ? "block":"none"); // hides/shows button labels
|
||||
sCol('--bmt',l ? "0px":"5px");
|
||||
sCol('--t-b', cfg.theme.alpha.tab);
|
||||
size();
|
||||
@@ -107,45 +129,45 @@ function tglLabels()
|
||||
|
||||
function cTheme(light) {
|
||||
if (light) {
|
||||
sCol('--c-1','#eee');
|
||||
sCol('--c-f','#000');
|
||||
sCol('--c-2','#ddd');
|
||||
sCol('--c-3','#bbb');
|
||||
sCol('--c-4','#aaa');
|
||||
sCol('--c-5','#999');
|
||||
sCol('--c-6','#999');
|
||||
sCol('--c-8','#888');
|
||||
sCol('--c-b','#444');
|
||||
sCol('--c-c','#333');
|
||||
sCol('--c-e','#111');
|
||||
sCol('--c-d','#222');
|
||||
sCol('--c-r','#c42');
|
||||
sCol('--c-o','rgba(204, 204, 204, 0.9)');
|
||||
sCol('--c-sb','#0003'); sCol('--c-sbh','#0006');
|
||||
sCol('--c-tb','rgba(204, 204, 204, var(--t-b))');
|
||||
sCol('--c-tba','rgba(170, 170, 170, var(--t-b))');
|
||||
sCol('--c-tbh','rgba(204, 204, 204, var(--t-b))');
|
||||
d.getElementById('imgw').style.filter = "invert(0.8)";
|
||||
} else {
|
||||
sCol('--c-1','#111');
|
||||
sCol('--c-f','#fff');
|
||||
sCol('--c-2','#222');
|
||||
sCol('--c-3','#333');
|
||||
sCol('--c-4','#444');
|
||||
sCol('--c-5','#555');
|
||||
sCol('--c-6','#666');
|
||||
sCol('--c-8','#888');
|
||||
sCol('--c-b','#bbb');
|
||||
sCol('--c-c','#ccc');
|
||||
sCol('--c-e','#eee');
|
||||
sCol('--c-d','#ddd');
|
||||
sCol('--c-r','#831');
|
||||
sCol('--c-o','rgba(34, 34, 34, 0.9)');
|
||||
sCol('--c-sb','#fff3'); sCol('--c-sbh','#fff5');
|
||||
sCol('--c-tb','rgba(34, 34, 34, var(--t-b))');
|
||||
sCol('--c-tba','rgba(102, 102, 102, var(--t-b))');
|
||||
sCol('--c-tbh','rgba(51, 51, 51, var(--t-b))');
|
||||
d.getElementById('imgw').style.filter = "unset";
|
||||
sCol('--c-1','#eee');
|
||||
sCol('--c-f','#000');
|
||||
sCol('--c-2','#ddd');
|
||||
sCol('--c-3','#bbb');
|
||||
sCol('--c-4','#aaa');
|
||||
sCol('--c-5','#999');
|
||||
sCol('--c-6','#999');
|
||||
sCol('--c-8','#888');
|
||||
sCol('--c-b','#444');
|
||||
sCol('--c-c','#333');
|
||||
sCol('--c-e','#111');
|
||||
sCol('--c-d','#222');
|
||||
sCol('--c-r','#c42');
|
||||
sCol('--c-o','rgba(204, 204, 204, 0.9)');
|
||||
sCol('--c-sb','#0003'); sCol('--c-sbh','#0006');
|
||||
sCol('--c-tb','rgba(204, 204, 204, var(--t-b))');
|
||||
sCol('--c-tba','rgba(170, 170, 170, var(--t-b))');
|
||||
sCol('--c-tbh','rgba(204, 204, 204, var(--t-b))');
|
||||
d.getElementById('imgw').style.filter = "invert(0.8)";
|
||||
} else { // default dark theme
|
||||
sCol('--c-1','#111');
|
||||
sCol('--c-f','#fff');
|
||||
sCol('--c-2','#222');
|
||||
sCol('--c-3','#333');
|
||||
sCol('--c-4','#444');
|
||||
sCol('--c-5','#555');
|
||||
sCol('--c-6','#666');
|
||||
sCol('--c-8','#888');
|
||||
sCol('--c-b','#bbb');
|
||||
sCol('--c-c','#ccc');
|
||||
sCol('--c-e','#eee');
|
||||
sCol('--c-d','#ddd');
|
||||
sCol('--c-r','#831');
|
||||
sCol('--c-o','rgba(34, 34, 34, 0.9)');
|
||||
sCol('--c-sb','#fff3'); sCol('--c-sbh','#fff5');
|
||||
sCol('--c-tb','rgba(34, 34, 34, var(--t-b))');
|
||||
sCol('--c-tba','rgba(102, 102, 102, var(--t-b))');
|
||||
sCol('--c-tbh','rgba(51, 51, 51, var(--t-b))');
|
||||
d.getElementById('imgw').style.filter = "unset";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,10 +246,6 @@ function onLoad() {
|
||||
loadBg(cfg.theme.bg.url);
|
||||
if (cfg.comp.css) loadSkinCSS('skinCss');
|
||||
|
||||
var cd = d.getElementById('csl').children;
|
||||
for (var i = 0; i < cd.length; i++) {
|
||||
cd[i].style.backgroundColor = "rgb(0, 0, 0)";
|
||||
}
|
||||
selectSlot(0);
|
||||
updateTablinks(0);
|
||||
resetUtil();
|
||||
@@ -357,7 +375,7 @@ function cpBck() {
|
||||
copyText.select();
|
||||
copyText.setSelectionRange(0, 999999);
|
||||
d.execCommand("copy");
|
||||
|
||||
|
||||
showToast("Copied to clipboard!");
|
||||
}
|
||||
|
||||
@@ -370,7 +388,7 @@ function presetError(empty)
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
var cn = `<div class="seg c">`;
|
||||
var cn = `<div class="pres c">`;
|
||||
if (empty)
|
||||
cn += `You have no presets yet!`;
|
||||
else
|
||||
@@ -418,7 +436,7 @@ function loadPresets(callback = null)
|
||||
})
|
||||
.then(res => {
|
||||
if (!res.ok) {
|
||||
showErrorToast();
|
||||
showErrorToast();
|
||||
}
|
||||
return res.json();
|
||||
})
|
||||
@@ -479,9 +497,9 @@ function populatePresets(fromls)
|
||||
if (qll) pQL.push([i, qll]);
|
||||
is.push(i);
|
||||
|
||||
cn += `<div class="seg pres" id="p${i}o">`;
|
||||
cn += `<div class="pres" id="p${i}o">`;
|
||||
if (cfg.comp.pid) cn += `<div class="pid">${i}</div>`;
|
||||
cn += `<div class="segname pname" onclick="setPreset(${i})">${isPlaylist(i)?"<i class='icons btn-icon'></i>":""}${pName(i)}</div>
|
||||
cn += `<div class="${isPlaylist(i)?'plname':'pname'}" onclick="setPreset(${i})">${isPlaylist(i)?"<i class='icons btn-icon'></i>":""}${pName(i)}</div>
|
||||
<i class="icons e-icon flr ${expanded[i+100] ? "exp":""}" id="sege${i+100}" onclick="expand(${i+100})"></i>
|
||||
<div class="segin" id="seg${i+100}"></div>
|
||||
</div><br>`;
|
||||
@@ -524,7 +542,7 @@ function populateInfo(i)
|
||||
urows += inforow(k,val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var vcn = "Kuuhaku";
|
||||
if (i.ver.startsWith("0.13.")) vcn = "Toki";
|
||||
@@ -536,8 +554,8 @@ function populateInfo(i)
|
||||
${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")}
|
||||
${inforow("Uptime",getRuntimeStr(i.uptime))}
|
||||
${inforow("Free heap",heap," kB")}
|
||||
${inforow("Estimated current",pwru)}
|
||||
${inforow("Frames / second",i.leds.fps)}
|
||||
${inforow("Estimated current",pwru)}
|
||||
${inforow("Frames / second",i.leds.fps)}
|
||||
${inforow("MAC address",i.mac)}
|
||||
${inforow("Filesystem",i.fs.u + "/" + i.fs.t + " kB (" +Math.round(i.fs.u*100/i.fs.t) + "%)")}
|
||||
${inforow("Environment",i.arch + " " + i.core + " (" + i.lwip + ")")}
|
||||
@@ -560,7 +578,7 @@ function populateSegments(s)
|
||||
if (i == lowestUnused) lowestUnused = i+1;
|
||||
if (i > lSeg) lSeg = i;
|
||||
|
||||
cn += `<div class="seg">
|
||||
cn += `<div class="seg ${i==s.mainseg ? 'selected' : ''}">
|
||||
<label class="check schkl">
|
||||
|
||||
<input type="checkbox" id="seg${i}sel" onchange="selSeg(${i})" ${inst.sel ? "checked":""}>
|
||||
@@ -576,7 +594,7 @@ function populateSegments(s)
|
||||
<div class="sbs">
|
||||
<i class="icons e-icon pwr ${powered[i] ? "act":""}" id="seg${i}pwr" onclick="setSegPwr(${i})"></i>
|
||||
<div class="sliderwrap il sws">
|
||||
<input id="seg${i}bri" class="noslide sis" onchange="setSegBri(${i})" oninput="updateTrail(this)" max="255" min="1" type="range" value="${inst.bri}" />
|
||||
<input id="seg${i}bri" class="noslide" onchange="setSegBri(${i})" oninput="updateTrail(this)" max="255" min="1" type="range" value="${inst.bri}" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -601,7 +619,7 @@ function populateSegments(s)
|
||||
<tr>
|
||||
<td class="segtd"><input class="noslide segn" id="seg${i}grp" type="number" min="1" max="255" value="${inst.grp}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
|
||||
<td class="segtd"><input class="noslide segn" id="seg${i}spc" type="number" min="0" max="255" value="${inst.spc}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
|
||||
<td class="segtd"><i class="icons e-icon cnf cnf-s" id="segc${i}" onclick="setSeg(${i})"></i></td>
|
||||
<td class="segtd"><i class="icons e-icon cnf" id="segc${i}" onclick="setSeg(${i})"></i></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="h" id="seg${i}len"></div>
|
||||
@@ -616,8 +634,8 @@ function populateSegments(s)
|
||||
<span class="checkmark schk"></span>
|
||||
</label>
|
||||
<div class="del">
|
||||
<button class="btn btn-i btn-xs" id="segr${i}" title="Repeat until end" onclick="rptSeg(${i})"><i class="icons btn-icon"></i></button>
|
||||
<button class="btn btn-i btn-xs" id="segd${i}" title="Delete" onclick="delSeg(${i})"><i class="icons btn-icon"></i></button>
|
||||
<button class="xxs btn no-margin" id="segr${i}" title="Repeat until end" onclick="rptSeg(${i})"><i class="icons no-margin"></i></button>
|
||||
<button class="xxs btn no-margin" id="segd${i}" title="Delete" onclick="delSeg(${i})"><i class="icons no-margin"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div><br>`;
|
||||
@@ -695,14 +713,13 @@ function populatePalettes(palettes)
|
||||
for (let i = 0; i < palettes.length; i++) {
|
||||
html += generateListItemHtml(
|
||||
'palette',
|
||||
palettes[i].id,
|
||||
palettes[i].name,
|
||||
'setPalette',
|
||||
palettes[i].id,
|
||||
palettes[i].name,
|
||||
'setPalette',
|
||||
`<div class="lstIprev" style="${genPalPrevCss(palettes[i].id)}"></div>`,
|
||||
palettes[i].class,
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
pallist.innerHTML=html;
|
||||
}
|
||||
|
||||
@@ -754,11 +771,11 @@ function genPalPrevCss(id)
|
||||
g = Math.random() * 255;
|
||||
b = Math.random() * 255;
|
||||
} else {
|
||||
if (selColors) {
|
||||
if (colors) {
|
||||
let pos = element[1] - 1;
|
||||
r = selColors[pos][0];
|
||||
g = selColors[pos][1];
|
||||
b = selColors[pos][2];
|
||||
r = colors[pos][0];
|
||||
g = colors[pos][1];
|
||||
b = colors[pos][2];
|
||||
}
|
||||
}
|
||||
if (index === false) {
|
||||
@@ -773,7 +790,7 @@ function genPalPrevCss(id)
|
||||
|
||||
function generateListItemHtml(listName, id, name, clickAction, extraHtml = '', extraClass = '')
|
||||
{
|
||||
return `<div class="lstI btn fxbtn ${extraClass}" data-id="${id}" onClick="${clickAction}(${id})">
|
||||
return `<div class="lstI btn fxbtn ${extraClass}" data-id="${id}" onClick="${clickAction}(${id})">
|
||||
<label class="radio fxchkl">
|
||||
<input type="radio" value="${id}" name="${listName}">
|
||||
<span class="radiomark"></span>
|
||||
@@ -784,32 +801,32 @@ function generateListItemHtml(listName, id, name, clickAction, extraHtml = '', e
|
||||
${extraHtml}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
|
||||
function btype(b){
|
||||
switch (b) {
|
||||
case 32: return "ESP32";
|
||||
case 82: return "ESP8266";
|
||||
}
|
||||
return "?";
|
||||
switch (b) {
|
||||
case 32: return "ESP32";
|
||||
case 82: return "ESP8266";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
function bname(o){
|
||||
if (o.name=="WLED") return o.ip;
|
||||
return o.name;
|
||||
if (o.name=="WLED") return o.ip;
|
||||
return o.name;
|
||||
}
|
||||
|
||||
function populateNodes(i,n)
|
||||
{
|
||||
var cn="";
|
||||
var urows="";
|
||||
var nnodes = 0;
|
||||
var nnodes = 0;
|
||||
if (n.nodes) {
|
||||
n.nodes.sort((a,b) => (a.name).localeCompare(b.name));
|
||||
for (var x=0;x<n.nodes.length;x++) {
|
||||
var o = n.nodes[x];
|
||||
if (o.name) {
|
||||
var url = `<button class="btn btna-icon tab" onclick="location.assign('http://${o.ip}');">${bname(o)}</button>`;
|
||||
var url = `<button class="btn no-margin tab" onclick="location.assign('http://${o.ip}');">${bname(o)}</button>`;
|
||||
urows += inforow(url,`${btype(o.type)}<br><i>${o.vid==0?"N/A":o.vid}</i>`);
|
||||
nnodes++;
|
||||
nnodes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -904,20 +921,21 @@ function updateLen(s)
|
||||
//updates background color of currently selected preset
|
||||
function updatePA()
|
||||
{
|
||||
var ps = d.getElementsByClassName("seg"); //reset all preset buttons
|
||||
for (let i = 0; i < ps.length; i++) {
|
||||
ps[i].style.backgroundColor = "var(--c-2)";
|
||||
var ps = d.getElementsByClassName("pres"); //reset all preset buttons
|
||||
for (var i of ps) {
|
||||
i.classList.remove("selected");
|
||||
}
|
||||
ps = d.getElementsByClassName("psts"); //reset all quick selectors
|
||||
for (let i = 0; i < ps.length; i++) {
|
||||
ps[i].style.backgroundColor = "var(--c-2)";
|
||||
for (var i of ps) {
|
||||
i.classList.remove("selected");
|
||||
}
|
||||
if (currentPreset > 0) {
|
||||
var acv = d.getElementById(`p${currentPreset}o`);
|
||||
if (acv && !expanded[currentPreset+100])
|
||||
acv.style.background = "var(--c-6)"; //highlight current preset
|
||||
acv.classList.add("selected");
|
||||
acv = d.getElementById(`p${currentPreset}qlb`);
|
||||
if (acv) acv.style.background = "var(--c-6)"; //highlight quick selector
|
||||
if (acv)
|
||||
acv.classList.add("selected");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -930,9 +948,15 @@ function updateUI()
|
||||
updateTrail(d.getElementById('sliderBri'));
|
||||
updateTrail(d.getElementById('sliderSpeed'));
|
||||
updateTrail(d.getElementById('sliderIntensity'));
|
||||
d.getElementById('wwrap').style.display = (isRgbw) ? "block":"none";
|
||||
d.getElementById('wbal').style.display = (lastinfo.leds.cct) ? "block":"none";
|
||||
d.getElementById('kwrap').style.display = (lastinfo.leds.cct) ? "none":"block";
|
||||
d.getElementById('wwrap').style.display = (hasWhite) ? "block":"none";
|
||||
d.getElementById('wbal').style.display = (hasCCT) ? "block":"none";
|
||||
var ccfg = cfg.comp.colors;
|
||||
d.getElementById('hexw').style.display = ccfg.hex ? "block":"none";
|
||||
d.getElementById('pwrap').style.display = (hasRGB && ccfg.picker) ? "block":"none";
|
||||
d.getElementById('kwrap').style.display = (hasRGB && !hasCCT && ccfg.picker) ? "block":"none";
|
||||
d.getElementById('rgbwrap').style.display = (hasRGB && ccfg.rgb) ? "block":"none";
|
||||
d.getElementById('qcs-w').style.display = (hasRGB && ccfg.quick) ? "block":"none";
|
||||
d.getElementById('palwrap').style.display = hasRGB ? "block":"none";
|
||||
|
||||
updatePA();
|
||||
updatePSliders();
|
||||
@@ -952,7 +976,14 @@ function compare(a, b) {
|
||||
}
|
||||
function cmpP(a, b) {
|
||||
if (!a[1].n) return (a[0] > b[0]);
|
||||
return a[1].n.localeCompare(b[1].n,undefined, {numeric: true});
|
||||
//return a[1].n.localeCompare(b[1].n,undefined, {numeric: true});
|
||||
// sort playlists first, followed by presets with characters and last presets with special 1st character
|
||||
const c = a[1].n.charCodeAt(0);
|
||||
const d = b[1].n.charCodeAt(0);
|
||||
if ((c>47 && c<58) || (c>64 && c<91) || (c>96 && c<123) || c>255) x = '='; else x = '>';
|
||||
if ((d>47 && d<58) || (d>64 && d<91) || (d>96 && d<123) || d>255) y = '='; else y = '>';
|
||||
const n = (a[1].playlist ? '<' : x) + a[1].n;
|
||||
return n.localeCompare((b[1].playlist ? '<' : y) + b[1].n, undefined, {numeric: true});
|
||||
}
|
||||
|
||||
//forces a WebSockets reconnect if timeout (error toast), or successful HTTP response to JSON request
|
||||
@@ -964,10 +995,10 @@ function reconnectWS() {
|
||||
|
||||
function makeWS() {
|
||||
if (ws) return;
|
||||
ws = new WebSocket('ws://'+(loc?locip:window.location.hostname)+'/ws');
|
||||
ws = new WebSocket((window.location.protocol == 'https:'?'wss':'ws')+'://'+(loc?locip:window.location.hostname)+'/ws');
|
||||
ws.binaryType = "arraybuffer";
|
||||
ws.onmessage = function(event) {
|
||||
if (event.data instanceof ArrayBuffer) return; //liveview packet
|
||||
if (event.data instanceof ArrayBuffer) return; //liveview packet
|
||||
var json = JSON.parse(event.data);
|
||||
clearTimeout(jsonTimeout);
|
||||
jsonTimeout = null;
|
||||
@@ -996,90 +1027,108 @@ function makeWS() {
|
||||
}
|
||||
|
||||
function readState(s,command=false) {
|
||||
isOn = s.on;
|
||||
d.getElementById('sliderBri').value= s.bri;
|
||||
nlA = s.nl.on;
|
||||
nlDur = s.nl.dur;
|
||||
nlTar = s.nl.tbri;
|
||||
nlMode = s.nl.mode;
|
||||
syncSend = s.udpn.send;
|
||||
currentPreset = s.ps;
|
||||
tr = s.transition;
|
||||
d.getElementById('tt').value = tr/10;
|
||||
isOn = s.on;
|
||||
d.getElementById('sliderBri').value= s.bri;
|
||||
nlA = s.nl.on;
|
||||
nlDur = s.nl.dur;
|
||||
nlTar = s.nl.tbri;
|
||||
nlMode = s.nl.mode;
|
||||
syncSend = s.udpn.send;
|
||||
currentPreset = s.ps;
|
||||
tr = s.transition;
|
||||
d.getElementById('tt').value = tr/10;
|
||||
|
||||
var selc=0; var ind=0;
|
||||
populateSegments(s);
|
||||
for (let i = 0; i < (s.seg||[]).length; i++)
|
||||
{
|
||||
if(s.seg[i].sel) {selc = ind; break;} ind++;
|
||||
}
|
||||
var i=s.seg[selc];
|
||||
if (!i) {
|
||||
showToast('No Segments!', true);
|
||||
updateUI();
|
||||
return;
|
||||
}
|
||||
|
||||
selColors = i.col;
|
||||
var cd = d.getElementById('csl').children;
|
||||
for (let e = 2; e >= 0; e--)
|
||||
{
|
||||
cd[e].style.backgroundColor = "rgb(" + i.col[e][0] + "," + i.col[e][1] + "," + i.col[e][2] + ")";
|
||||
if (isRgbw) whites[e] = parseInt(i.col[e][3]);
|
||||
selectSlot(csel);
|
||||
}
|
||||
if (i.cct != null && i.cct>=0) d.getElementById("sliderA").value = i.cct;
|
||||
populateSegments(s);
|
||||
var selc=0;
|
||||
var sellvl=0; // 0: selc is invalid, 1: selc is mainseg, 2: selc is first selected
|
||||
hasRGB = hasWhite = hasCCT = false;
|
||||
for (let i = 0; i < (s.seg||[]).length; i++)
|
||||
{
|
||||
if (sellvl == 0 && s.seg[i].id == s.mainseg) {
|
||||
selc = i;
|
||||
sellvl = 1;
|
||||
}
|
||||
if (s.seg[i].sel) {
|
||||
if (sellvl < 2) selc = i; // get first selected segment
|
||||
sellvl = 2;
|
||||
var lc = lastinfo.leds.seglc[s.seg[i].id];
|
||||
hasRGB |= lc & 0x01;
|
||||
hasWhite |= lc & 0x02;
|
||||
hasCCT |= lc & 0x04;
|
||||
}
|
||||
}
|
||||
var i=s.seg[selc];
|
||||
if (sellvl == 1) {
|
||||
var lc = lastinfo.leds.seglc[i.id];
|
||||
hasRGB = lc & 0x01;
|
||||
hasWhite = lc & 0x02;
|
||||
hasCCT = lc & 0x04;
|
||||
}
|
||||
if (!i) {
|
||||
showToast('No Segments!', true);
|
||||
updateUI();
|
||||
return;
|
||||
}
|
||||
|
||||
colors = i.col;
|
||||
for (let e = 0; e < 3; e++)
|
||||
{
|
||||
if (i.col[e].length > 3) whites[e] = parseInt(i.col[e][3]);
|
||||
setCSL(e);
|
||||
}
|
||||
selectSlot(csel);
|
||||
if (i.cct != null && i.cct>=0) d.getElementById("sliderA").value = i.cct;
|
||||
|
||||
d.getElementById('sliderSpeed').value = i.sx;
|
||||
d.getElementById('sliderIntensity').value = i.ix;
|
||||
d.getElementById('sliderSpeed').value = i.sx;
|
||||
d.getElementById('sliderIntensity').value = i.ix;
|
||||
|
||||
// Effects
|
||||
var selFx = fxlist.querySelector(`input[name="fx"][value="${i.fx}"]`);
|
||||
if (selFx) selFx.checked = true;
|
||||
else location.reload(); //effect list is gone (e.g. if restoring tab). Reload.
|
||||
// Effects
|
||||
var selFx = fxlist.querySelector(`input[name="fx"][value="${i.fx}"]`);
|
||||
if (selFx) selFx.checked = true;
|
||||
else location.reload(); //effect list is gone (e.g. if restoring tab). Reload.
|
||||
|
||||
var selElement = fxlist.querySelector('.selected');
|
||||
if (selElement) {
|
||||
selElement.classList.remove('selected')
|
||||
}
|
||||
var selectedEffect = fxlist.querySelector(`.lstI[data-id="${i.fx}"]`);
|
||||
selectedEffect.classList.add('selected');
|
||||
selectedFx = i.fx;
|
||||
var selElement = fxlist.querySelector('.selected');
|
||||
if (selElement) {
|
||||
selElement.classList.remove('selected')
|
||||
}
|
||||
var selectedEffect = fxlist.querySelector(`.lstI[data-id="${i.fx}"]`);
|
||||
selectedEffect.classList.add('selected');
|
||||
selectedFx = i.fx;
|
||||
|
||||
// Palettes
|
||||
pallist.querySelector(`input[name="palette"][value="${i.pal}"]`).checked = true;
|
||||
selElement = pallist.querySelector('.selected');
|
||||
if (selElement) {
|
||||
selElement.classList.remove('selected')
|
||||
}
|
||||
pallist.querySelector(`.lstI[data-id="${i.pal}"]`).classList.add('selected');
|
||||
// Palettes
|
||||
pallist.querySelector(`input[name="palette"][value="${i.pal}"]`).checked = true;
|
||||
selElement = pallist.querySelector('.selected');
|
||||
if (selElement) {
|
||||
selElement.classList.remove('selected')
|
||||
}
|
||||
pallist.querySelector(`.lstI[data-id="${i.pal}"]`).classList.add('selected');
|
||||
|
||||
if (!command) {
|
||||
selectedEffect.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'nearest',
|
||||
});
|
||||
}
|
||||
if (!command) {
|
||||
selectedEffect.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'nearest',
|
||||
});
|
||||
}
|
||||
|
||||
if (s.error && s.error != 0) {
|
||||
var errstr = "";
|
||||
switch (s.error) {
|
||||
case 10:
|
||||
errstr = "Could not mount filesystem!";
|
||||
break;
|
||||
case 11:
|
||||
errstr = "Not enough space to save preset!";
|
||||
break;
|
||||
case 12:
|
||||
errstr = "Preset not found.";
|
||||
break;
|
||||
case 19:
|
||||
errstr = "A filesystem error has occured.";
|
||||
break;
|
||||
}
|
||||
showToast('Error ' + s.error + ": " + errstr, true);
|
||||
}
|
||||
updateUI();
|
||||
if (s.error && s.error != 0) {
|
||||
var errstr = "";
|
||||
switch (s.error) {
|
||||
case 10:
|
||||
errstr = "Could not mount filesystem!";
|
||||
break;
|
||||
case 11:
|
||||
errstr = "Not enough space to save preset!";
|
||||
break;
|
||||
case 12:
|
||||
errstr = "Preset not found.";
|
||||
break;
|
||||
case 19:
|
||||
errstr = "A filesystem error has occured.";
|
||||
break;
|
||||
}
|
||||
showToast('Error ' + s.error + ": " + errstr, true);
|
||||
}
|
||||
updateUI();
|
||||
}
|
||||
|
||||
var jsonTimeout;
|
||||
@@ -1102,15 +1151,15 @@ function requestJson(command, rinfo = true) {
|
||||
var type = command ? 'post':'get';
|
||||
if (command)
|
||||
{
|
||||
command.v = true; //get complete API response
|
||||
command.time = Math.floor(Date.now() / 1000);
|
||||
var t = d.getElementById('tt');
|
||||
if (t.validity.valid && command.transition===undefined) {
|
||||
var tn = parseInt(t.value*10);
|
||||
if (tn != tr) command.transition = tn;
|
||||
}
|
||||
command.v = true; //get complete API response
|
||||
command.time = Math.floor(Date.now() / 1000);
|
||||
var t = d.getElementById('tt');
|
||||
if (t.validity.valid && command.transition===undefined) {
|
||||
var tn = parseInt(t.value*10);
|
||||
if (tn != tr) command.transition = tn;
|
||||
}
|
||||
req = JSON.stringify(command);
|
||||
if (req.length > 1000) useWs = false; //do not send very long requests over websocket
|
||||
if (req.length > 1000) useWs = false; //do not send very long requests over websocket
|
||||
}
|
||||
|
||||
if (useWs) {
|
||||
@@ -1176,7 +1225,6 @@ function requestJson(command, rinfo = true) {
|
||||
name = "(L) " + name;
|
||||
}
|
||||
d.title = name;
|
||||
isRgbw = info.leds.wv;
|
||||
ledCount = info.leds.count;
|
||||
syncTglRecv = info.str;
|
||||
maxSeg = info.leds.maxseg;
|
||||
@@ -1243,7 +1291,7 @@ function toggleLiveview() {
|
||||
}
|
||||
|
||||
function toggleInfo() {
|
||||
if (isNodes) toggleNodes();
|
||||
if (isNodes) toggleNodes();
|
||||
isInfo = !isInfo;
|
||||
if (isInfo) populateInfo(lastinfo);
|
||||
d.getElementById('info').style.transform = (isInfo) ? "translateY(0px)":"translateY(100%)";
|
||||
@@ -1272,18 +1320,19 @@ function makeSeg() {
|
||||
<br>
|
||||
<div class="segin expanded">
|
||||
<input type="text" class="ptxt stxt noslide" id="seg${lowestUnused}t" autocomplete="off" maxlength=32 value="" placeholder="Enter name..."/>
|
||||
<table class="segt">
|
||||
<table class="infot">
|
||||
<tr>
|
||||
<td class="segtd">Start LED</td>
|
||||
<td class="segtd">${cfg.comp.seglen?"Length":"Stop LED"}</td>
|
||||
<td class="segtd">Apply</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="segtd"><input class="noslide segn" id="seg${lowestUnused}s" type="number" min="0" max="${ledCount-1}" value="${ns}" oninput="updateLen(${lowestUnused})" onkeydown="segEnter(${lowestUnused})"></td>
|
||||
<td class="segtd"><input class="noslide segn" id="seg${lowestUnused}e" type="number" min="0" max="${ledCount-(cfg.comp.seglen?ns:0)}" value="${ledCount-(cfg.comp.seglen?ns:0)}" oninput="updateLen(${lowestUnused})" onkeydown="segEnter(${lowestUnused})"></td>
|
||||
<td class="segtd"><i class="icons e-icon cnf" id="segc${lowestUnused}" onclick="setSeg(${lowestUnused}); resetUtil();"></i></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="h" id="seg${lowestUnused}len">${ledCount - ns} LED${ledCount - ns >1 ? "s":""}</div>
|
||||
<i class="icons e-icon cnf cnf-s half" id="segc${lowestUnused}" onclick="setSeg(${lowestUnused}); resetUtil();"></i>
|
||||
</div>
|
||||
</div>`;
|
||||
d.getElementById('segutil').innerHTML = cn;
|
||||
@@ -1380,8 +1429,8 @@ function plR(p) {
|
||||
}
|
||||
|
||||
function makeP(i,pl) {
|
||||
var content = "";
|
||||
if (pl) {
|
||||
var content = "";
|
||||
if (pl) {
|
||||
var rep = plJson[i].repeat ? plJson[i].repeat : 0;
|
||||
content = `<div class="first c">Playlist Entries</div>
|
||||
<div id="ple${i}"></div>
|
||||
@@ -1405,7 +1454,7 @@ function makeP(i,pl) {
|
||||
</div>
|
||||
<button class="btn btn-i btn-p" onclick="testPl(${i}, this)"><i class='icons btn-icon'></i>Test</button>`;
|
||||
}
|
||||
else content = `<label class="check revchkl">
|
||||
else content = `<label class="check revchkl">
|
||||
Include brightness
|
||||
<input type="checkbox" id="p${i}ibtgl" checked>
|
||||
<span class="checkmark schk"></span>
|
||||
@@ -1446,38 +1495,38 @@ ${(i>0)? ('<div class="h">ID ' +i+ '</div>'):""}`;
|
||||
}
|
||||
|
||||
function makePUtil() {
|
||||
d.getElementById('putil').innerHTML = `<div class="seg pres">
|
||||
<div class="segname newseg">
|
||||
d.getElementById('putil').innerHTML = `<div class="pres">
|
||||
<div class="pname newseg">
|
||||
New preset</div>
|
||||
<div class="segin expanded">
|
||||
${makeP(0)}</div></div>`;
|
||||
}
|
||||
|
||||
function makePlEntry(p,i) {
|
||||
return `
|
||||
<div class="plentry">
|
||||
<select class="btn sel sel-pl" onchange="plePs(${p},${i},this)" data-val=${plJson[p].ps[i]} data-index=${i}>
|
||||
return `
|
||||
<div class="plentry">
|
||||
<select class="btn sel sel-pl" onchange="plePs(${p},${i},this)" data-val=${plJson[p].ps[i]} data-index=${i}>
|
||||
${makePlSel()}
|
||||
</select>
|
||||
<button class="btn btn-i btn-xs btn-pl-del" onclick="delPl(${p},${i})"><i class="icons btn-icon"></i></button>
|
||||
</select>
|
||||
<button class="xxs btn btn-pl-del" onclick="delPl(${p},${i})"><i class="icons no-margin"></i></button>
|
||||
<div class="h plnl">Duration</div><div class="h plnl">Transition</div><div class="h pli">#${i+1}</div><br>
|
||||
<input class="noslide pln" type="number" max=6553.0 min=0.2 step=0.1 oninput="pleDur(${p},${i},this)" value=${plJson[p].dur[i]/10.0}>
|
||||
<input class="noslide pln" type="number" max=65.0 min=0.0 step=0.1 oninput="pleTr(${p},${i},this)" value=${plJson[p].transition[i]/10.0}> s
|
||||
<button class="btn btn-i btn-xs btn-pl-add" onclick="addPl(${p},${i})"><i class="icons btn-icon"></i></button>
|
||||
<div class="hrz"></div>
|
||||
</div>`;
|
||||
<button class="xxs btn btn-pl-add" onclick="addPl(${p},${i})"><i class="icons no-margin"></i></button>
|
||||
<div class="hrz"></div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function makePlUtil() {
|
||||
if (pNum < 1) {
|
||||
showToast("Please make a preset first!"); return;
|
||||
}
|
||||
if (pNum < 1) {
|
||||
showToast("Please make a preset first!"); return;
|
||||
}
|
||||
if (plJson[0].transition[0] < 0) plJson[0].transition[0] = tr;
|
||||
d.getElementById('putil').innerHTML = `<div class="seg pres">
|
||||
<div class="segname newseg">
|
||||
New playlist</div>
|
||||
<div class="segin expanded" id="seg100">
|
||||
${makeP(0,true)}</div></div>`;
|
||||
d.getElementById('putil').innerHTML = `<div class="pres">
|
||||
<div class="pname newseg">
|
||||
New playlist</div>
|
||||
<div class="segin expanded" id="seg100">
|
||||
${makeP(0,true)}</div></div>`;
|
||||
|
||||
refreshPlE(0);
|
||||
}
|
||||
@@ -1497,15 +1546,17 @@ function tglCs(i){
|
||||
function tglSegn(s)
|
||||
{
|
||||
d.getElementById(`seg${s}t`).style.display =
|
||||
(window.getComputedStyle(d.getElementById(`seg${s}t`)).display === "none") ? "inline":"none";
|
||||
(window.getComputedStyle(d.getElementById(`seg${s}t`)).display === "none") ? "inline":"none";
|
||||
}
|
||||
|
||||
// Select only the clicked segment and unselect all others
|
||||
function selSegEx(s)
|
||||
{
|
||||
var obj = {"seg":[]};
|
||||
for (let i=0; i<=lSeg; i++){
|
||||
obj.seg.push({"sel":(i==s)?true:false});
|
||||
}
|
||||
for (let i=0; i<=lSeg; i++) obj.seg.push({"id":i,"sel":(i==s)});
|
||||
// optionally, force mainseg to be first selected
|
||||
// WLED internally regards the first selected as mainseg regardless of this as long as any segment is selected
|
||||
//obj.mainseg = s;
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
@@ -1520,7 +1571,7 @@ function rptSeg(s)
|
||||
var name = d.getElementById(`seg${s}t`).value;
|
||||
var start = parseInt(d.getElementById(`seg${s}s`).value);
|
||||
var stop = parseInt(d.getElementById(`seg${s}e`).value);
|
||||
if (stop == 0) {return;}
|
||||
if (stop == 0) return;
|
||||
var rev = d.getElementById(`seg${s}rev`).checked;
|
||||
var mi = d.getElementById(`seg${s}mi`).checked;
|
||||
var sel = d.getElementById(`seg${s}sel`).checked;
|
||||
@@ -1748,16 +1799,12 @@ function delP(i) {
|
||||
|
||||
function selectSlot(b) {
|
||||
csel = b;
|
||||
var cd = d.getElementById('csl').children;
|
||||
for (let i = 0; i < cd.length; i++) {
|
||||
cd[i].style.border="2px solid white";
|
||||
cd[i].style.margin="5px";
|
||||
cd[i].style.width="42px";
|
||||
var cd = d.getElementsByClassName('cl');
|
||||
for (var i of cd) {
|
||||
i.classList.remove("selected");
|
||||
}
|
||||
cd[csel].style.border="5px solid white";
|
||||
cd[csel].style.margin="2px";
|
||||
cd[csel].style.width="50px";
|
||||
setPicker(cd[csel].style.backgroundColor);
|
||||
cd[csel].classList.add("selected");
|
||||
setPicker(rgbStr(colors, csel));
|
||||
//force slider update on initial load (picker "color:change" not fired if black)
|
||||
if (cpick.color.value == 0) updatePSliders();
|
||||
d.getElementById('sliderW').value = whites[csel];
|
||||
@@ -1792,7 +1839,7 @@ function updatePSliders() {
|
||||
s = d.getElementById('sliderB');
|
||||
s.value = col.b; updateTrail(s,3);
|
||||
|
||||
//update hex field
|
||||
//update hex field
|
||||
var str = cpick.color.hexString.substring(1);
|
||||
var w = whites[csel];
|
||||
if (w > 0) str += w.toString(16);
|
||||
@@ -1800,24 +1847,26 @@ function updatePSliders() {
|
||||
d.getElementById('hexcnf').style.backgroundColor = "var(--c-3)";
|
||||
|
||||
//update value slider
|
||||
var v = d.getElementById('sliderV');
|
||||
v.value = cpick.color.value;
|
||||
var v = d.getElementById('sliderV');
|
||||
v.value = cpick.color.value;
|
||||
//background color as if color had full value
|
||||
var hsv = {"h":cpick.color.hue,"s":cpick.color.saturation,"v":100};
|
||||
var c = iro.Color.hsvToRgb(hsv);
|
||||
var cs = 'rgb('+c.r+','+c.g+','+c.b+')';
|
||||
v.parentNode.getElementsByClassName('sliderdisplay')[0].style.setProperty('--bg',cs);
|
||||
updateTrail(v);
|
||||
var hsv = {"h":cpick.color.hue,"s":cpick.color.saturation,"v":100};
|
||||
var c = iro.Color.hsvToRgb(hsv);
|
||||
var cs = 'rgb('+c.r+','+c.g+','+c.b+')';
|
||||
v.parentNode.getElementsByClassName('sliderdisplay')[0].style.setProperty('--bg',cs);
|
||||
updateTrail(v);
|
||||
|
||||
//update Kelvin slider
|
||||
d.getElementById('sliderK').value = cpick.color.kelvin;
|
||||
// update Kelvin slider
|
||||
d.getElementById('sliderK').value = cpick.color.kelvin;
|
||||
}
|
||||
|
||||
// Fired when a key is pressed while in the HEX color input
|
||||
function hexEnter() {
|
||||
d.getElementById('hexcnf').style.backgroundColor = "var(--c-6)";
|
||||
if(event.keyCode == 13) fromHex();
|
||||
}
|
||||
|
||||
// Fired when a key is pressed while in a segment input
|
||||
function segEnter(s) {
|
||||
if(event.keyCode == 13) setSeg(s);
|
||||
}
|
||||
@@ -1861,17 +1910,13 @@ function fromRgb()
|
||||
|
||||
//sr 0: from RGB sliders, 1: from picker, 2: from hex
|
||||
function setColor(sr) {
|
||||
var cd = d.getElementById('csl').children;
|
||||
if (sr == 1 && cd[csel].style.backgroundColor == "rgb(0, 0, 0)") cpick.color.setChannel('hsv', 'v', 100);
|
||||
cd[csel].style.backgroundColor = cpick.color.rgbString;
|
||||
if (sr == 1 && colors[csel][0] == 0 && colors[csel][1] == 0 && colors[csel][2] == 0) cpick.color.setChannel('hsv', 'v', 100);
|
||||
if (sr != 2) whites[csel] = parseInt(d.getElementById('sliderW').value);
|
||||
var col = cpick.color.rgb;
|
||||
var obj = {"seg": {"col": [[col.r, col.g, col.b, whites[csel]],[],[]]}};
|
||||
if (csel == 1) {
|
||||
obj = {"seg": {"col": [[],[col.r, col.g, col.b, whites[csel]],[]]}};
|
||||
} else if (csel == 2) {
|
||||
obj = {"seg": {"col": [[],[],[col.r, col.g, col.b, whites[csel]]]}};
|
||||
}
|
||||
colors[csel] = [col.r, col.g, col.b, whites[csel]];
|
||||
setCSL(csel);
|
||||
var obj = {"seg": {"col": [[],[],[]]}};
|
||||
obj.seg.col[csel] = colors[csel];
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
@@ -1934,7 +1979,6 @@ function loadPalettesData(callback = null)
|
||||
var d = new Date();
|
||||
if (palettesDataJson && palettesDataJson.vid == lastinfo.vid) {
|
||||
palettesData = palettesDataJson.p;
|
||||
//redrawPalPrev() //?
|
||||
if (callback) callback();
|
||||
return;
|
||||
}
|
||||
@@ -2001,10 +2045,10 @@ function search(searchField) {
|
||||
}
|
||||
|
||||
function cancelSearch(ic) {
|
||||
var searchField = ic.parentElement.getElementsByClassName('search')[0];
|
||||
searchField.value = "";
|
||||
search(searchField);
|
||||
searchField.focus();
|
||||
var searchField = ic.parentElement.getElementsByClassName('search')[0];
|
||||
searchField.value = "";
|
||||
search(searchField);
|
||||
searchField.focus();
|
||||
}
|
||||
|
||||
//make sure "dur" and "transition" are arrays with at least the length of "ps"
|
||||
@@ -2041,9 +2085,9 @@ function expand(i,a)
|
||||
d.getElementById('seg' +i).style.display = (expanded[i]) ? "block":"none";
|
||||
d.getElementById('sege' +i).style.transform = (expanded[i]) ? "rotate(180deg)":"rotate(0deg)";
|
||||
if (i < 100) {
|
||||
d.getElementById(`seg${i}nedit`).style.display = (expanded[i]) ? "inline":"none";
|
||||
return; //no preset, we are done
|
||||
}
|
||||
d.getElementById(`seg${i}nedit`).style.display = (expanded[i]) ? "inline":"none";
|
||||
return; //no preset, we are done
|
||||
}
|
||||
|
||||
var p = i-100;
|
||||
d.getElementById(`p${p}o`).style.background = (expanded[i] || p != currentPreset)?"var(--c-2)":"var(--c-6)";
|
||||
@@ -2111,9 +2155,9 @@ function move(e) {
|
||||
var f = +(s*dx/w).toFixed(2);
|
||||
|
||||
if ((clientX != 0) &&
|
||||
(iSlide > 0 || s < 0) && (iSlide < N - 1 || s > 0) &&
|
||||
f > 0.12 &&
|
||||
d.getElementsByClassName("tabcontent")[iSlide].scrollTop == scrollS) {
|
||||
(iSlide > 0 || s < 0) && (iSlide < N - 1 || s > 0) &&
|
||||
f > 0.12 &&
|
||||
d.getElementsByClassName("tabcontent")[iSlide].scrollTop == scrollS) {
|
||||
_C.style.setProperty('--i', iSlide -= s);
|
||||
f = 1 - f;
|
||||
updateTablinks(iSlide);
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
ws.send("{'lv':true}");
|
||||
} else {
|
||||
console.info("Peek WS opening");
|
||||
ws = new WebSocket("ws://"+document.location.host+"/ws");
|
||||
ws = new WebSocket((window.location.protocol == "https:"?"wss":"ws")+"://"+document.location.host+"/ws");
|
||||
ws.onopen = function () {
|
||||
console.info("Peek WS open");
|
||||
ws.send("{'lv':true}");
|
||||
|
||||
@@ -3,22 +3,15 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=500">
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||
<title>LED Settings</title>
|
||||
<script>
|
||||
var d=document,laprev=55,maxB=1,maxM=4000,maxPB=4096,maxL=1333,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32
|
||||
var customStarts=false,startsDirty=[],maxCOOverrides=5;
|
||||
function H()
|
||||
{
|
||||
window.open("https://kno.wled.ge/features/settings/#led-settings");
|
||||
}
|
||||
function B()
|
||||
{
|
||||
window.open("/settings","_self");
|
||||
}
|
||||
function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");}
|
||||
function B(){window.open("/settings","_self");}
|
||||
function gId(n){return d.getElementById(n);}
|
||||
function off(n){
|
||||
d.getElementsByName(n)[0].value = -1;
|
||||
}
|
||||
function off(n){d.getElementsByName(n)[0].value = -1;}
|
||||
var timeout;
|
||||
function showToast(text, error = false)
|
||||
{
|
||||
@@ -71,7 +64,6 @@
|
||||
if (bquot > 100) {var msg = "Too many LEDs for me to handle!"; if (maxM < 10000) msg += "\n\rConsider using an ESP32."; alert(msg);}
|
||||
if (d.Sf.checkValidity()) d.Sf.submit(); //https://stackoverflow.com/q/37323914
|
||||
}
|
||||
function S(){GetV();checkSi();setABL();}
|
||||
function enABL()
|
||||
{
|
||||
var en = gId('able').checked;
|
||||
@@ -165,7 +157,7 @@
|
||||
}
|
||||
gId("rf"+n).onclick = (t == 31) ? (function(){return false}) : (function(){}); // prevent change for TM1814
|
||||
isRGBW |= (t == 30 || t == 31 || (t > 40 && t < 46 && t != 43)); // RGBW checkbox, TYPE_xxxx values from const.h
|
||||
gId("co"+n).style.display = ((t>=80 && t<96) || t == 41 || t == 42) ? "none":"inline"; // hide color order for PWM W & WW/CW
|
||||
gId("co"+n).style.display = ((t>=80 && t<96) || (t > 40 && t < 48)) ? "none":"inline"; // hide color order for PWM
|
||||
gId("dig"+n+"c").style.display = (t > 40 && t < 48) ? "none":"inline"; // hide count for analog
|
||||
gId("dig"+n+"r").style.display = (t>=80 && t<96) ? "none":"inline"; // hide reversed for virtual
|
||||
gId("dig"+n+"s").style.display = ((t>=80 && t<96) || (t > 40 && t < 48)) ? "none":"inline"; // hide skip 1st for virtual & analog
|
||||
@@ -188,13 +180,13 @@
|
||||
var n = LCs[i].name.substring(2); // bus number
|
||||
// do we have a led count field
|
||||
if (nm=="LC") {
|
||||
var c=parseInt(LCs[i].value,10);
|
||||
if (!customStarts || !startsDirty[n]) gId("ls"+n).value=sLC;
|
||||
gId("ls"+n).disabled = !customStarts;
|
||||
var c=parseInt(LCs[i].value,10); //get LED count
|
||||
if (!customStarts || !startsDirty[n]) gId("ls"+n).value=sLC; //update start value
|
||||
gId("ls"+n).disabled = !customStarts; //enable/disable field editing
|
||||
if(c){
|
||||
var s = parseInt(gId("ls"+n).value);
|
||||
if (s+c > sLC) sLC = s+c;
|
||||
if(c>maxLC)maxLC=c;
|
||||
var s = parseInt(gId("ls"+n).value); //start value
|
||||
if (s+c > sLC) sLC = s+c; //update total count
|
||||
if(c>maxLC)maxLC=c; //max per output
|
||||
var t = parseInt(d.getElementsByName("LT"+n)[0].value); // LED type SELECT
|
||||
if (t<80) sPC+=c; //virtual out busses do not count towards physical LEDs
|
||||
} // increase led count
|
||||
@@ -313,7 +305,7 @@ ${i+1}:
|
||||
<option value="80">DDP RGB (network)</option>
|
||||
<!--option value="81">E1.31 RGB (network)</option-->
|
||||
<!--option value="82">ArtNet RGB (network)</option-->
|
||||
</select>
|
||||
</select><br>
|
||||
<div id="co${i}" style="display:inline">Color Order:
|
||||
<select name="CO${i}">
|
||||
<option value="0">GRB</option>
|
||||
@@ -322,8 +314,7 @@ ${i+1}:
|
||||
<option value="3">RBG</option>
|
||||
<option value="4">BGR</option>
|
||||
<option value="5">GBR</option>
|
||||
</select></div>
|
||||
<br>
|
||||
</select><br></div>
|
||||
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" id="ls${i}" class="l starts" min="0" max="8191" value="${lastEnd(i)}" oninput="startsDirty[${i}]=true;UI();" required />
|
||||
<div id="dig${i}c" style="display:inline">Length: <input type="number" name="LC${i}" class="l" min="1" max="${maxPB}" value="1" required oninput="UI()" /></div>
|
||||
<br>
|
||||
@@ -369,6 +360,7 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
gId("com_entries").insertAdjacentHTML("beforeend", b);
|
||||
gId("xo"+i).value = co;
|
||||
btnCOM(i+1);
|
||||
UI();
|
||||
}
|
||||
|
||||
function remCOM() {
|
||||
@@ -377,6 +369,7 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
if (i === 0) return;
|
||||
entries[i-1].remove();
|
||||
btnCOM(i-1);
|
||||
UI();
|
||||
}
|
||||
|
||||
function resetCOM(_newMaxCOOverrides=undefined) {
|
||||
@@ -396,8 +389,8 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
|
||||
function addBtn(i,p,t) {
|
||||
var c = gId("btns").innerHTML;
|
||||
var bt = "BT" + String.fromCharCode((i<10?48:55)+i);;
|
||||
var be = "BE" + String.fromCharCode((i<10?48:55)+i);;
|
||||
var bt = "BT" + String.fromCharCode((i<10?48:55)+i);
|
||||
var be = "BE" + String.fromCharCode((i<10?48:55)+i);
|
||||
c += `Button ${i} GPIO: <input type="number" min="-1" max="40" name="${bt}" onchange="UI()" class="xs" value="${p}">`;
|
||||
c += ` <select name="${be}">`
|
||||
c += `<option value="0" ${t==0?"selected":""}>Disabled</option>`;
|
||||
@@ -463,7 +456,7 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
let lines = e.target.result;
|
||||
var c = JSON.parse(lines);
|
||||
if (c.hw) {
|
||||
if (c.hw.led) {
|
||||
if (c.hw.led) {
|
||||
for (var i=0; i<10; i++) addLEDs(-1);
|
||||
var l = c.hw.led;
|
||||
l.ins.forEach((v,i,a)=>{
|
||||
@@ -504,6 +497,7 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
}
|
||||
}
|
||||
}
|
||||
function S(){GetV();checkSi();setABL();}
|
||||
function GetV()
|
||||
{
|
||||
//values injected by server while sending HTML
|
||||
@@ -584,8 +578,8 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
<option value=7>9-key red</option>
|
||||
<option value=8>JSON remote</option>
|
||||
</select><span style="cursor: pointer;" onclick="off('IR')"> ×</span><br>
|
||||
Apply IR change to main segment only: <input type="checkbox" name="MSO"><br>
|
||||
<div id="json" style="display:none;">JSON file: <input type="file" name="data" accept=".json"> <input type="button" value="Upload" onclick="uploadFile('/ir.json');"><br></div>
|
||||
<div id="toast"></div>
|
||||
<a href="https://kno.wled.ge/interfaces/infrared/" target="_blank">IR info</a><br>
|
||||
Relay GPIO: <input type="number" min="-1" max="33" name="RL" onchange="UI()" class="xs"> Invert <input type="checkbox" name="RM"><span style="cursor: pointer;" onclick="off('RL')"> ×</span><br>
|
||||
<hr style="width:260px">
|
||||
@@ -638,5 +632,6 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
<hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||
</form>
|
||||
<div id="toast"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<title>Time Settings</title>
|
||||
<script>
|
||||
var d=document;
|
||||
var el=false;
|
||||
var ms=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
|
||||
var cals = 'style="font-size:27px;margin-top:-6px;cursor:pointer"'; //hack as to not repeat CSS on all pages
|
||||
function H()
|
||||
@@ -31,26 +32,11 @@
|
||||
{
|
||||
var t = gId("WD"+i);
|
||||
t.style.display = t.style.display!=="none" ? "none" : "";
|
||||
o.innerHTML = t.style.display==="none" ? "🗓" : "✕";
|
||||
o.innerHTML = t.style.display==="none" ? "📅" : "✕";
|
||||
}
|
||||
function Cs()
|
||||
{
|
||||
gId("cac").style.display="none";
|
||||
gId("coc").style.display="block";
|
||||
gId("ccc").style.display="none";
|
||||
if (gId("ca").selected)
|
||||
{
|
||||
gId("cac").style.display="block";
|
||||
}
|
||||
if (gId("cc").selected)
|
||||
{
|
||||
gId("coc").style.display="none";
|
||||
gId("ccc").style.display="block";
|
||||
}
|
||||
if (gId("cn").selected)
|
||||
{
|
||||
gId("coc").style.display="none";
|
||||
}
|
||||
gId("cac").style.display=(gN("OL").checked)?"block":"none";
|
||||
}
|
||||
function BTa()
|
||||
{
|
||||
@@ -99,7 +85,7 @@
|
||||
for(j=0;j<8;j++) {
|
||||
gId("W"+i+j).checked=wd>>j&1;
|
||||
}
|
||||
if ((wd&127) != 127 || (i<8 && (gN("M"+i).value != 1 || gN("D"+i).value != 1 || gN("P"+i).value != 12 || gN("E"+i).value != 31))) {
|
||||
if ((wd&254) != 254 || (i<8 && (gN("M"+i).value != 1 || gN("D"+i).value != 1 || gN("P"+i).value != 12 || gN("E"+i).value != 31))) {
|
||||
expand(gId("CB"+i),i); //expand macros with custom DOW or date range set
|
||||
}
|
||||
}
|
||||
@@ -130,6 +116,20 @@
|
||||
td = tr.insertCell(3);
|
||||
td.innerHTML = `<input name="MD${b}" type="number" class="s" min="0" max="250" value="${d}" required>`;
|
||||
}
|
||||
function getLoc() {
|
||||
if (!el) {
|
||||
window.addEventListener("message", (event) => {
|
||||
if (event.origin !== "https://locate.wled.me") return;
|
||||
if (event.data instanceof Object) {
|
||||
d.Sf.LT.value = event.data.lat;
|
||||
d.Sf.LN.value = event.data.lon;
|
||||
updLoc();
|
||||
}
|
||||
}, false);
|
||||
el = true;
|
||||
}
|
||||
window.open("https://locate.wled.me","_blank");
|
||||
}
|
||||
function updLoc(i) {
|
||||
if (parseFloat(d.Sf.LT.value)<0) { d.Sf.LTR.value = "S"; d.Sf.LT.value = -1*parseFloat(d.Sf.LT.value); } else d.Sf.LTR.value = "N";
|
||||
if (parseFloat(d.Sf.LN.value)<0) { d.Sf.LNR.value = "W"; d.Sf.LN.value = -1*parseFloat(d.Sf.LN.value); } else d.Sf.LNR.value = "E";
|
||||
@@ -179,27 +179,18 @@
|
||||
UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<br>
|
||||
Current local time is <span class="times">unknown</span>.<br>
|
||||
Latitude: <select name="LTR"><option value="N">N</option><option value="S">S</option></select><input name="LT" type="number" class="xl" min="0" max="66.6" step="0.01"><br>
|
||||
Longitude: <select name="LNR"><option value="E">E</option><option value="W">W</option></select><input name="LN" type="number" class="xl" min="0" max="180" step="0.01">
|
||||
Longitude: <select name="LNR"><option value="E">E</option><option value="W">W</option></select><input name="LN" type="number" class="xl" min="0" max="180" step="0.01"><br>
|
||||
<button type="button" id="locbtn" onclick="getLoc()">Get location</button>
|
||||
<div><i>(opens new tab, only works in browser)</i></div>
|
||||
<div id="sun" class="times"></div>
|
||||
<h3>Clock</h3>
|
||||
Clock Overlay:
|
||||
<select name="OL" onchange="Cs()">
|
||||
<option value="0" id="cn" selected>None</option>
|
||||
<option value="1" id="ca">Analog Clock</option>
|
||||
<option value="2">Single Digit Clock</option>
|
||||
<option value="3" id="cc">Cronixie Clock</option>
|
||||
</select><br>
|
||||
<div id="coc">
|
||||
First LED: <input name="O1" type="number" min="0" max="255" required> Last LED: <input name="O2" type="number" min="0" max="255" required><br>
|
||||
<div id="cac">
|
||||
Analog Clock overlay: <input type="checkbox" name="OL" onchange="Cs()"><br>
|
||||
<div id="cac">
|
||||
First LED: <input name="O1" type="number" min="0" max="255" required> Last LED: <input name="O2" type="number" min="0" max="255" required><br>
|
||||
12h LED: <input name="OM" type="number" min="0" max="255" required><br>
|
||||
Show 5min marks: <input type="checkbox" name="O5"><br></div>
|
||||
Show 5min marks: <input type="checkbox" name="O5"><br>
|
||||
Seconds (as trail): <input type="checkbox" name="OS"><br>
|
||||
</div>
|
||||
<div id="ccc">
|
||||
Cronixie Display: <input name="CX" maxlength="6"><br>
|
||||
Cronixie Backlight: <input type="checkbox" name="CB"><br>
|
||||
</div>
|
||||
Countdown Mode: <input type="checkbox" name="CE"><br>
|
||||
Countdown Goal:<br>
|
||||
Date: <nowrap>20<input name="CY" class="xs" type="number" min="0" max="99" required>-<input name="CI" class="xs" type="number" min="1" max="12" required>-<input name="CD" class="xs" type="number" min="1" max="31" required></nowrap><br>
|
||||
|
||||
@@ -1,83 +1,83 @@
|
||||
body {
|
||||
font-family: Verdana, sans-serif;
|
||||
text-align: center;
|
||||
background: #222;
|
||||
color: #fff;
|
||||
line-height: 200%%; /* %% because of AsyncWebServer */
|
||||
margin: 0;
|
||||
font-family: Verdana, sans-serif;
|
||||
text-align: center;
|
||||
background: #222;
|
||||
color: #fff;
|
||||
line-height: 200%%; /* %% because of AsyncWebServer */
|
||||
margin: 0;
|
||||
}
|
||||
hr {
|
||||
border-color: #666;
|
||||
border-color: #666;
|
||||
}
|
||||
a {
|
||||
color: #28f;
|
||||
text-decoration: none;
|
||||
color: #28f;
|
||||
text-decoration: none;
|
||||
}
|
||||
button, .btn {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.3ch solid #333;
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
margin: 12px 8px 8px;
|
||||
padding: 1px 6px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
background: #333;
|
||||
color: #fff;
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.3ch solid #333;
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
margin: 12px 8px 8px;
|
||||
padding: 1px 6px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.lnk {
|
||||
border: 0;
|
||||
border: 0;
|
||||
}
|
||||
.helpB {
|
||||
text-align: left;
|
||||
position: absolute;
|
||||
width: 60px;
|
||||
text-align: left;
|
||||
position: absolute;
|
||||
width: 60px;
|
||||
}
|
||||
input {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.5ch solid #333;
|
||||
background: #333;
|
||||
color: #fff;
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.5ch solid #333;
|
||||
}
|
||||
input:disabled {
|
||||
color: #888;
|
||||
color: #888;
|
||||
}
|
||||
input[type="number"] {
|
||||
width: 4em;
|
||||
margin: 2px;
|
||||
width: 4em;
|
||||
margin: 2px;
|
||||
}
|
||||
input[type="number"].xxl {
|
||||
width: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
input[type="number"].xl {
|
||||
width: 85px;
|
||||
width: 85px;
|
||||
}
|
||||
input[type="number"].l {
|
||||
width: 63px;
|
||||
width: 63px;
|
||||
}
|
||||
input[type="number"].m {
|
||||
width: 56px;
|
||||
width: 56px;
|
||||
}
|
||||
input[type="number"].s {
|
||||
width: 49px;
|
||||
width: 49px;
|
||||
}
|
||||
input[type="number"].xs {
|
||||
width: 42px;
|
||||
width: 42px;
|
||||
}
|
||||
input[type="checkbox"] {
|
||||
transform: scale(1.5);
|
||||
transform: scale(1.5);
|
||||
}
|
||||
select {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.5ch solid #333;
|
||||
background: #333;
|
||||
color: #fff;
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.5ch solid #333;
|
||||
}
|
||||
td {
|
||||
padding: 2px;
|
||||
padding: 2px;
|
||||
}
|
||||
.d5 {
|
||||
width: 4.5em !important;
|
||||
width: 4.5em !important;
|
||||
}
|
||||
#toast {
|
||||
opacity: 0;
|
||||
@@ -92,7 +92,7 @@ td {
|
||||
text-align: center;
|
||||
z-index: 5;
|
||||
transform: translateX(-50%%); /* %% because of AsyncWebServer */
|
||||
max-width: 90%%; /* %% because of AsyncWebServer */
|
||||
max-width: 90%%; /* %% because of AsyncWebServer */
|
||||
left: 50%%; /* %% because of AsyncWebServer */
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
||||
return; // nothing to do
|
||||
break;
|
||||
|
||||
case DMX_MODE_SINGLE_RGB:
|
||||
case DMX_MODE_SINGLE_RGB: // RGB only
|
||||
if (uni != e131Universe) return;
|
||||
if (dmxChannels-DMXAddress+1 < 3) return;
|
||||
realtimeLock(realtimeTimeoutMs, mde);
|
||||
@@ -121,7 +121,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
||||
setRealtimePixel(i, e131_data[DMXAddress+0], e131_data[DMXAddress+1], e131_data[DMXAddress+2], wChannel);
|
||||
break;
|
||||
|
||||
case DMX_MODE_SINGLE_DRGB:
|
||||
case DMX_MODE_SINGLE_DRGB: // Dimmer + RGB
|
||||
if (uni != e131Universe) return;
|
||||
if (dmxChannels-DMXAddress+1 < 4) return;
|
||||
realtimeLock(realtimeTimeoutMs, mde);
|
||||
@@ -130,15 +130,19 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
||||
if (DMXOldDimmer != e131_data[DMXAddress+0]) {
|
||||
DMXOldDimmer = e131_data[DMXAddress+0];
|
||||
bri = e131_data[DMXAddress+0];
|
||||
strip.setBrightness(bri);
|
||||
strip.setBrightness(bri, true);
|
||||
}
|
||||
for (uint16_t i = 0; i < totalLen; i++)
|
||||
setRealtimePixel(i, e131_data[DMXAddress+1], e131_data[DMXAddress+2], e131_data[DMXAddress+3], wChannel);
|
||||
break;
|
||||
|
||||
case DMX_MODE_EFFECT:
|
||||
case DMX_MODE_EFFECT: // Length 1: Apply Preset ID, length 11-13: apply effect config
|
||||
if (uni != e131Universe) return;
|
||||
if (dmxChannels-DMXAddress+1 < 11) return;
|
||||
if (dmxChannels-DMXAddress+1 < 11) {
|
||||
if (dmxChannels-DMXAddress+1 > 1) return;
|
||||
applyPreset(e131_data[DMXAddress+0], CALL_MODE_NOTIFICATION);
|
||||
return;
|
||||
}
|
||||
if (DMXOldDimmer != e131_data[DMXAddress+0]) {
|
||||
DMXOldDimmer = e131_data[DMXAddress+0];
|
||||
bri = e131_data[DMXAddress+0];
|
||||
@@ -180,7 +184,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
||||
previousLeds = 0;
|
||||
// First DMX address is dimmer in DMX_MODE_MULTIPLE_DRGB mode.
|
||||
if (DMXMode == DMX_MODE_MULTIPLE_DRGB) {
|
||||
strip.setBrightness(e131_data[dmxOffset++]);
|
||||
strip.setBrightness(e131_data[dmxOffset++], true);
|
||||
}
|
||||
} else {
|
||||
// All subsequent universes start at the first channel.
|
||||
|
||||
@@ -58,10 +58,7 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau
|
||||
|
||||
|
||||
//colors.cpp
|
||||
void colorFromUint32(uint32_t in, bool secondary = false);
|
||||
void colorFromUint24(uint32_t in, bool secondary = false);
|
||||
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
||||
void relativeChangeWhite(int8_t amount, byte lowerBoundary = 0);
|
||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
|
||||
void colorKtoRGB(uint16_t kelvin, byte* rgb);
|
||||
void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb
|
||||
@@ -108,11 +105,9 @@ void sendImprovInfoResponse();
|
||||
void sendImprovRPCResponse(uint8_t commandId);
|
||||
|
||||
//ir.cpp
|
||||
bool decodeIRCustom(uint32_t code);
|
||||
//bool decodeIRCustom(uint32_t code);
|
||||
void applyRepeatActions();
|
||||
void relativeChange(byte* property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF);
|
||||
void changeEffectSpeed(int8_t amount);
|
||||
void changeEffectIntensity(int8_t amount);
|
||||
byte relativeChange(byte property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF);
|
||||
void decodeIR(uint32_t code);
|
||||
void decodeIR24(uint32_t code);
|
||||
void decodeIR24OLD(uint32_t code);
|
||||
@@ -144,6 +139,8 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
|
||||
#endif
|
||||
|
||||
//led.cpp
|
||||
void setValuesFromSegment(uint8_t s);
|
||||
void setValuesFromMainSeg();
|
||||
void setValuesFromFirstSelectedSeg();
|
||||
void resetTimebase();
|
||||
void toggleOnOff();
|
||||
@@ -180,17 +177,10 @@ void calculateSunriseAndSunset();
|
||||
void setTimeFromAPI(uint32_t timein);
|
||||
|
||||
//overlay.cpp
|
||||
void initCronixie();
|
||||
void handleOverlays();
|
||||
void handleOverlayDraw();
|
||||
void _overlayAnalogCountdown();
|
||||
void _overlayAnalogClock();
|
||||
|
||||
byte getSameCodeLength(char code, int index, char const cronixieDisplay[]);
|
||||
void setCronixie();
|
||||
void _overlayCronixie();
|
||||
void _drawOverlayCronixie();
|
||||
|
||||
//playlist.cpp
|
||||
void shufflePlaylist();
|
||||
void unloadPlaylist();
|
||||
@@ -200,8 +190,8 @@ void handlePlaylist();
|
||||
//presets.cpp
|
||||
bool applyPreset(byte index, byte callMode = CALL_MODE_DIRECT_CHANGE);
|
||||
inline bool applyTemporaryPreset() {return applyPreset(255);};
|
||||
void savePreset(byte index, bool persist = true, const char* pname = nullptr, JsonObject saveobj = JsonObject());
|
||||
inline void saveTemporaryPreset() {savePreset(255, false);};
|
||||
void savePreset(byte index, const char* pname = nullptr, JsonObject saveobj = JsonObject());
|
||||
inline void saveTemporaryPreset() {savePreset(255);};
|
||||
void deletePreset(byte index);
|
||||
|
||||
//set.cpp
|
||||
|
||||
@@ -42,7 +42,7 @@ function B(){window.history.back()}function U(){document.getElementById("uf").st
|
||||
.bt{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}input[type=file]{font-size:16px}body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%}#msg{display:none}
|
||||
</style></head><body><h2>WLED Software Update</h2><form method="POST"
|
||||
action="/update" id="uf" enctype="multipart/form-data" onsubmit="U()">
|
||||
Installed version: 0.13.0-b7<br>Download the latest binary: <a
|
||||
Installed version: 0.13.0<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" required><br><input
|
||||
@@ -85,7 +85,7 @@ charset="utf-8"><meta name="theme-color" content="#222222"><title>
|
||||
WLED Live Preview</title><style>
|
||||
body{margin:0}#canv{background:#000;filter:brightness(175%);width:100%;height:100%;position:absolute}
|
||||
</style></head><body><div id="canv"><script>
|
||||
function updatePreview(e){var n="linear-gradient(90deg,",t=e.length;for(i=2;i<t;i+=3)n+=`rgb(${e[i]},${e[i+1]},${e[i+2]})`,i<t-3&&(n+=",");n+=")",document.getElementById("canv").style.background=n}function getLiveJson(e){try{if("[object ArrayBuffer]"===toString.call(e.data)){let e=new Uint8Array(event.data);if(76!=e[0])return;updatePreview(e)}}catch(e){console.error("Peek WS error:",e)}}var ws=top.window.ws;ws&&ws.readyState===WebSocket.OPEN?(console.info("Peek uses top WS"),ws.send("{'lv':true}")):(console.info("Peek WS opening"),(ws=new WebSocket("ws://"+document.location.host+"/ws")).onopen=function(){console.info("Peek WS open"),ws.send("{'lv':true}")}),ws.binaryType="arraybuffer",ws.addEventListener("message",getLiveJson)
|
||||
function updatePreview(e){var n="linear-gradient(90deg,",o=e.length;for(i=2;i<o;i+=3)n+=`rgb(${e[i]},${e[i+1]},${e[i+2]})`,i<o-3&&(n+=",");n+=")",document.getElementById("canv").style.background=n}function getLiveJson(e){try{if("[object ArrayBuffer]"===toString.call(e.data)){let e=new Uint8Array(event.data);if(76!=e[0])return;updatePreview(e)}}catch(e){console.error("Peek WS error:",e)}}var ws=top.window.ws;ws&&ws.readyState===WebSocket.OPEN?(console.info("Peek uses top WS"),ws.send("{'lv':true}")):(console.info("Peek WS opening"),(ws=new WebSocket(("https:"==window.location.protocol?"wss":"ws")+"://"+document.location.host+"/ws")).onopen=function(){console.info("Peek WS open"),ws.send("{'lv':true}")}),ws.binaryType="arraybuffer",ws.addEventListener("message",getLiveJson)
|
||||
</script></body></html>)=====";
|
||||
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
4418
wled00/html_ui.h
4418
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@@ -189,7 +189,7 @@ void sendImprovInfoResponse() {
|
||||
out[11] = 4; //Firmware len ("WLED")
|
||||
out[12] = 'W'; out[13] = 'L'; out[14] = 'E'; out[15] = 'D';
|
||||
uint8_t lengthSum = 17;
|
||||
uint8_t vlen = sprintf_P(out+lengthSum,PSTR("0.13.0-b7/%i"),VERSION);
|
||||
uint8_t vlen = sprintf_P(out+lengthSum,PSTR("0.13.0/%i"),VERSION);
|
||||
out[16] = vlen; lengthSum += vlen;
|
||||
uint8_t hlen = 7;
|
||||
#ifdef ESP8266
|
||||
|
||||
689
wled00/ir.cpp
689
wled00/ir.cpp
@@ -73,56 +73,94 @@ void presetFallback(uint8_t presetID, uint8_t effectID, uint8_t paletteID)
|
||||
{
|
||||
byte prevError = errorFlag;
|
||||
if (!applyPreset(presetID, CALL_MODE_BUTTON_PRESET)) {
|
||||
effectCurrent = effectID;
|
||||
effectCurrent = effectID;
|
||||
effectPalette = paletteID;
|
||||
errorFlag = prevError; //clear error 12 from non-existent preset
|
||||
}
|
||||
}
|
||||
|
||||
//Add what your custom IR codes should trigger here. Guide: https://github.com/Aircoookie/WLED/wiki/Infrared-Control
|
||||
//IR codes themselves can be defined directly after "case" or in "ir_codes.h"
|
||||
bool decodeIRCustom(uint32_t code)
|
||||
byte relativeChange(byte property, int8_t amount, byte lowerBoundary, byte higherBoundary)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
//just examples, feel free to modify or remove
|
||||
case IRCUSTOM_ONOFF : toggleOnOff(); break;
|
||||
case IRCUSTOM_MACRO1 : applyPreset(1, CALL_MODE_BUTTON_PRESET); break;
|
||||
|
||||
default: return false;
|
||||
}
|
||||
if (code != IRCUSTOM_MACRO1) colorUpdated(CALL_MODE_BUTTON); //don't update color again if we apply macro, it already does it
|
||||
return true;
|
||||
int16_t new_val = (int16_t) property + amount;
|
||||
if (lowerBoundary >= higherBoundary) return property;
|
||||
if (new_val > higherBoundary) new_val = higherBoundary;
|
||||
if (new_val < lowerBoundary) new_val = lowerBoundary;
|
||||
return (byte)constrain(new_val, 0, 255);
|
||||
}
|
||||
|
||||
void relativeChange(byte* property, int8_t amount, byte lowerBoundary, byte higherBoundary)
|
||||
void changeEffect(uint8_t fx)
|
||||
{
|
||||
int16_t new_val = (int16_t) *property + amount;
|
||||
if (new_val > higherBoundary) new_val = higherBoundary;
|
||||
else if (new_val < lowerBoundary) new_val = lowerBoundary;
|
||||
*property = (byte)constrain(new_val,0.1,255.1);
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
strip.setMode(i, fx);
|
||||
}
|
||||
setValuesFromFirstSelectedSeg();
|
||||
} else {
|
||||
strip.setMode(strip.getMainSegmentId(), fx);
|
||||
setValuesFromMainSeg();
|
||||
}
|
||||
stateChanged = true;
|
||||
}
|
||||
|
||||
void changePalette(uint8_t pal)
|
||||
{
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
seg.palette = pal;
|
||||
}
|
||||
setValuesFromFirstSelectedSeg();
|
||||
} else {
|
||||
strip.getMainSegment().palette = pal;
|
||||
setValuesFromMainSeg();
|
||||
}
|
||||
stateChanged = true;
|
||||
}
|
||||
|
||||
void changeEffectSpeed(int8_t amount)
|
||||
{
|
||||
if (effectCurrent != 0) {
|
||||
int16_t new_val = (int16_t) effectSpeed + amount;
|
||||
effectSpeed = (byte)constrain(new_val,0.1,255.1);
|
||||
} else { // if Effect == "solid Color", change the hue of the primary color
|
||||
effectSpeed = (byte)constrain(new_val,0,255);
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
seg.speed = effectSpeed;
|
||||
}
|
||||
setValuesFromFirstSelectedSeg();
|
||||
} else {
|
||||
strip.getMainSegment().speed = effectSpeed;
|
||||
setValuesFromMainSeg();
|
||||
}
|
||||
} else { // if Effect == "solid Color", change the hue of the primary color
|
||||
WS2812FX::Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
CRGB fastled_col;
|
||||
fastled_col.red = col[0];
|
||||
fastled_col.green = col[1];
|
||||
fastled_col.blue = col[2];
|
||||
fastled_col.red = R(sseg.colors[0]);
|
||||
fastled_col.green = G(sseg.colors[0]);
|
||||
fastled_col.blue = B(sseg.colors[0]);
|
||||
CHSV prim_hsv = rgb2hsv_approximate(fastled_col);
|
||||
int16_t new_val = (int16_t) prim_hsv.h + amount;
|
||||
int16_t new_val = (int16_t)prim_hsv.h + amount;
|
||||
if (new_val > 255) new_val -= 255; // roll-over if bigger than 255
|
||||
if (new_val < 0) new_val += 255; // roll-over if smaller than 0
|
||||
prim_hsv.h = (byte)new_val;
|
||||
hsv2rgb_rainbow(prim_hsv, fastled_col);
|
||||
col[0] = fastled_col.red;
|
||||
col[1] = fastled_col.green;
|
||||
col[2] = fastled_col.blue;
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
seg.colors[0] = RGBW32(fastled_col.red, fastled_col.green, fastled_col.blue, W(sseg.colors[0]));
|
||||
}
|
||||
setValuesFromFirstSelectedSeg();
|
||||
} else {
|
||||
strip.getMainSegment().colors[0] = RGBW32(fastled_col.red, fastled_col.green, fastled_col.blue, W(sseg.colors[0]));
|
||||
setValuesFromMainSeg();
|
||||
}
|
||||
}
|
||||
stateChanged = true;
|
||||
|
||||
if(amount > 0) lastRepeatableAction = ACTION_SPEED_UP;
|
||||
if(amount < 0) lastRepeatableAction = ACTION_SPEED_DOWN;
|
||||
@@ -133,65 +171,132 @@ void changeEffectIntensity(int8_t amount)
|
||||
{
|
||||
if (effectCurrent != 0) {
|
||||
int16_t new_val = (int16_t) effectIntensity + amount;
|
||||
effectIntensity = (byte)constrain(new_val,0.1,255.1);
|
||||
} else { // if Effect == "solid Color", change the saturation of the primary color
|
||||
effectIntensity = (byte)constrain(new_val,0,255);
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
seg.intensity = effectIntensity;
|
||||
}
|
||||
setValuesFromFirstSelectedSeg();
|
||||
} else {
|
||||
strip.getMainSegment().speed = effectIntensity;
|
||||
setValuesFromMainSeg();
|
||||
}
|
||||
} else { // if Effect == "solid Color", change the saturation of the primary color
|
||||
WS2812FX::Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
CRGB fastled_col;
|
||||
fastled_col.red = col[0];
|
||||
fastled_col.green = col[1];
|
||||
fastled_col.blue = col[2];
|
||||
fastled_col.red = R(sseg.colors[0]);
|
||||
fastled_col.green = G(sseg.colors[0]);
|
||||
fastled_col.blue = B(sseg.colors[0]);
|
||||
CHSV prim_hsv = rgb2hsv_approximate(fastled_col);
|
||||
int16_t new_val = (int16_t) prim_hsv.s + amount;
|
||||
prim_hsv.s = (byte)constrain(new_val,0.1,255.1); // constrain to 0-255
|
||||
prim_hsv.s = (byte)constrain(new_val,0,255); // constrain to 0-255
|
||||
hsv2rgb_rainbow(prim_hsv, fastled_col);
|
||||
col[0] = fastled_col.red;
|
||||
col[1] = fastled_col.green;
|
||||
col[2] = fastled_col.blue;
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
seg.colors[0] = RGBW32(fastled_col.red, fastled_col.green, fastled_col.blue, W(sseg.colors[0]));
|
||||
}
|
||||
setValuesFromFirstSelectedSeg();
|
||||
} else {
|
||||
strip.getMainSegment().colors[0] = RGBW32(fastled_col.red, fastled_col.green, fastled_col.blue, W(sseg.colors[0]));
|
||||
setValuesFromMainSeg();
|
||||
}
|
||||
}
|
||||
stateChanged = true;
|
||||
|
||||
if(amount > 0) lastRepeatableAction = ACTION_INTENSITY_UP;
|
||||
if(amount < 0) lastRepeatableAction = ACTION_INTENSITY_DOWN;
|
||||
lastRepeatableValue = amount;
|
||||
}
|
||||
|
||||
void changeColor(uint32_t c, int16_t cct=-1)
|
||||
{
|
||||
if (irApplyToAllSelected) {
|
||||
// main segment may not be selected!
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
byte capabilities = seg.getLightCapabilities();
|
||||
uint32_t mask = 0;
|
||||
bool isRGB = GET_BIT(capabilities, 0); // when RGBW_MODE_AUTO_ACCURATE this is always true
|
||||
bool hasW = GET_BIT(capabilities, 1);
|
||||
bool isCCT = GET_BIT(capabilities, 2);
|
||||
if (isRGB) mask |= 0x00FFFFFF; // RGB
|
||||
if (hasW) mask |= 0xFF000000; // white
|
||||
if (hasW && (strip.autoWhiteMode == RGBW_MODE_AUTO_ACCURATE) && (c & 0xFF000000)) { // white channel & white specified
|
||||
seg.setColor(0, c | 0xFFFFFF, i); // for accurate mode we fake white
|
||||
} else if (c & mask) seg.setColor(0, c & mask, i); // only apply if not black
|
||||
if (isCCT && cct >= 0) seg.setCCT(cct, i);
|
||||
}
|
||||
setValuesFromFirstSelectedSeg();
|
||||
} else {
|
||||
byte i = strip.getMainSegmentId();
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
byte capabilities = seg.getLightCapabilities();
|
||||
uint32_t mask = 0;
|
||||
bool isRGB = GET_BIT(capabilities, 0);
|
||||
bool hasW = GET_BIT(capabilities, 1);
|
||||
bool isCCT = GET_BIT(capabilities, 2);
|
||||
if (isRGB) mask |= 0x00FFFFFF; // RGB
|
||||
if (hasW) mask |= 0xFF000000; // white
|
||||
if (hasW && (strip.autoWhiteMode == RGBW_MODE_AUTO_ACCURATE) && (c & 0xFF000000)) { // white channel & white specified
|
||||
seg.setColor(0, c | 0xFFFFFF, i); // for accurate mode we fake white
|
||||
} else if (c & mask) seg.setColor(0, c & mask, i); // only apply if not black
|
||||
if (isCCT && cct >= 0) seg.setCCT(cct, i);
|
||||
setValuesFromMainSeg();
|
||||
}
|
||||
stateChanged = true;
|
||||
}
|
||||
|
||||
void changeWhite(int8_t amount, int16_t cct=-1)
|
||||
{
|
||||
WS2812FX::Segment& seg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
byte r = R(seg.colors[0]);
|
||||
byte g = G(seg.colors[0]);
|
||||
byte b = B(seg.colors[0]);
|
||||
byte w = relativeChange(W(seg.colors[0]), amount, 5);
|
||||
changeColor(RGBW32(r, g, b, w), cct);
|
||||
}
|
||||
|
||||
void decodeIR(uint32_t code)
|
||||
{
|
||||
if (code == 0xFFFFFFFF) //repeated code, continue brightness up/down
|
||||
{
|
||||
if (code == 0xFFFFFFFF) {
|
||||
//repeated code, continue brightness up/down
|
||||
irTimesRepeated++;
|
||||
applyRepeatActions();
|
||||
return;
|
||||
}
|
||||
lastValidCode = 0; irTimesRepeated = 0;
|
||||
lastRepeatableAction = ACTION_NONE;
|
||||
if (decodeIRCustom(code)) return;
|
||||
|
||||
if (irEnabled == 8) { // any remote configurable with ir.json file
|
||||
decodeIRJson(code);
|
||||
colorUpdated(CALL_MODE_BUTTON);
|
||||
stateUpdated(CALL_MODE_BUTTON);
|
||||
return;
|
||||
}
|
||||
if (code > 0xFFFFFF) return; //invalid code
|
||||
|
||||
switch (irEnabled) {
|
||||
case 1:
|
||||
if (code > 0xF80000) {
|
||||
decodeIR24OLD(code); // white 24-key remote (old) - it sends 0xFF0000 values
|
||||
} else {
|
||||
decodeIR24(code); // 24-key remote - 0xF70000 to 0xF80000
|
||||
}
|
||||
if (code > 0xF80000) decodeIR24OLD(code); // white 24-key remote (old) - it sends 0xFF0000 values
|
||||
else decodeIR24(code); // 24-key remote - 0xF70000 to 0xF80000
|
||||
break;
|
||||
case 2: decodeIR24CT(code); break; // white 24-key remote with CW, WW, CT+ and CT- keys
|
||||
case 3: decodeIR40(code); break; // blue 40-key remote with 25%, 50%, 75% and 100% keys
|
||||
case 4: decodeIR44(code); break; // white 44-key remote with color-up/down keys and DIY1 to 6 keys
|
||||
case 5: decodeIR21(code); break; // white 21-key remote
|
||||
case 6: decodeIR6(code); break; // black 6-key learning remote defaults: "CH" controls brightness,
|
||||
// "VOL +" controls effect, "VOL -" controls colour/palette, "MUTE"
|
||||
// sets bright plain white
|
||||
case 2: decodeIR24CT(code); break; // white 24-key remote with CW, WW, CT+ and CT- keys
|
||||
case 3: decodeIR40(code); break; // blue 40-key remote with 25%, 50%, 75% and 100% keys
|
||||
case 4: decodeIR44(code); break; // white 44-key remote with color-up/down keys and DIY1 to 6 keys
|
||||
case 5: decodeIR21(code); break; // white 21-key remote
|
||||
case 6: decodeIR6(code); break; // black 6-key learning remote defaults: "CH" controls brightness,
|
||||
// "VOL +" controls effect, "VOL -" controls colour/palette, "MUTE"
|
||||
// sets bright plain white
|
||||
case 7: decodeIR9(code); break;
|
||||
//case 8: return; // ir.json file, handled above switch statement
|
||||
default: return;
|
||||
}
|
||||
|
||||
if (nightlightActive && bri == 0) nightlightActive = false;
|
||||
colorUpdated(CALL_MODE_BUTTON); //for notifier, IR is considered a button input
|
||||
stateUpdated(CALL_MODE_BUTTON); //for notifier, IR is considered a button input
|
||||
}
|
||||
|
||||
void applyRepeatActions()
|
||||
@@ -200,50 +305,50 @@ void applyRepeatActions()
|
||||
decodeIRJson(lastValidCode);
|
||||
return;
|
||||
} else switch (lastRepeatableAction) {
|
||||
case ACTION_BRIGHT_UP : incBrightness(); colorUpdated(CALL_MODE_BUTTON); return;
|
||||
case ACTION_BRIGHT_DOWN : decBrightness(); colorUpdated(CALL_MODE_BUTTON); return;
|
||||
case ACTION_SPEED_UP : changeEffectSpeed(lastRepeatableValue); colorUpdated(CALL_MODE_BUTTON); return;
|
||||
case ACTION_SPEED_DOWN : changeEffectSpeed(lastRepeatableValue); colorUpdated(CALL_MODE_BUTTON); return;
|
||||
case ACTION_INTENSITY_UP : changeEffectIntensity(lastRepeatableValue); colorUpdated(CALL_MODE_BUTTON); return;
|
||||
case ACTION_INTENSITY_DOWN : changeEffectIntensity(lastRepeatableValue); colorUpdated(CALL_MODE_BUTTON); return;
|
||||
case ACTION_BRIGHT_UP : incBrightness(); stateUpdated(CALL_MODE_BUTTON); return;
|
||||
case ACTION_BRIGHT_DOWN : decBrightness(); stateUpdated(CALL_MODE_BUTTON); return;
|
||||
case ACTION_SPEED_UP : changeEffectSpeed(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return;
|
||||
case ACTION_SPEED_DOWN : changeEffectSpeed(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return;
|
||||
case ACTION_INTENSITY_UP : changeEffectIntensity(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return;
|
||||
case ACTION_INTENSITY_DOWN : changeEffectIntensity(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return;
|
||||
default: break;
|
||||
}
|
||||
if (lastValidCode == IR40_WPLUS) {
|
||||
relativeChangeWhite(10);
|
||||
colorUpdated(CALL_MODE_BUTTON);
|
||||
if (lastValidCode == IR40_WPLUS) {
|
||||
changeWhite(10);
|
||||
stateUpdated(CALL_MODE_BUTTON);
|
||||
} else if (lastValidCode == IR40_WMINUS) {
|
||||
relativeChangeWhite(-10, 5);
|
||||
colorUpdated(CALL_MODE_BUTTON);
|
||||
changeWhite(-10);
|
||||
stateUpdated(CALL_MODE_BUTTON);
|
||||
} else if ((lastValidCode == IR24_ON || lastValidCode == IR40_ON) && irTimesRepeated > 7 ) {
|
||||
nightlightActive = true;
|
||||
nightlightStartTime = millis();
|
||||
colorUpdated(CALL_MODE_BUTTON);
|
||||
stateUpdated(CALL_MODE_BUTTON);
|
||||
}
|
||||
}
|
||||
|
||||
void decodeIR24(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR24_BRIGHTER : incBrightness(); break;
|
||||
case IR24_DARKER : decBrightness(); 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;
|
||||
case IR24_ORANGE : colorFromUint32(COLOR_ORANGE); break;
|
||||
case IR24_YELLOWISH : colorFromUint32(COLOR_YELLOWISH); break;
|
||||
case IR24_YELLOW : colorFromUint32(COLOR_YELLOW); break;
|
||||
case IR24_GREEN : colorFromUint32(COLOR_GREEN); break;
|
||||
case IR24_GREENISH : colorFromUint32(COLOR_GREENISH); break;
|
||||
case IR24_TURQUOISE : colorFromUint32(COLOR_TURQUOISE); break;
|
||||
case IR24_CYAN : colorFromUint32(COLOR_CYAN); break;
|
||||
case IR24_AQUA : colorFromUint32(COLOR_AQUA); break;
|
||||
case IR24_BLUE : colorFromUint32(COLOR_BLUE); break;
|
||||
case IR24_DEEPBLUE : colorFromUint32(COLOR_DEEPBLUE); break;
|
||||
case IR24_PURPLE : colorFromUint32(COLOR_PURPLE); break;
|
||||
case IR24_MAGENTA : colorFromUint32(COLOR_MAGENTA); break;
|
||||
case IR24_PINK : colorFromUint32(COLOR_PINK); break;
|
||||
case IR24_WHITE : colorFromUint32(COLOR_WHITE); effectCurrent = 0; break;
|
||||
case IR24_BRIGHTER : incBrightness(); break;
|
||||
case IR24_DARKER : decBrightness(); break;
|
||||
case IR24_OFF : if (bri > 0) briLast = bri; bri = 0; break;
|
||||
case IR24_ON : bri = briLast; break;
|
||||
case IR24_RED : changeColor(COLOR_RED); break;
|
||||
case IR24_REDDISH : changeColor(COLOR_REDDISH); break;
|
||||
case IR24_ORANGE : changeColor(COLOR_ORANGE); break;
|
||||
case IR24_YELLOWISH : changeColor(COLOR_YELLOWISH); break;
|
||||
case IR24_YELLOW : changeColor(COLOR_YELLOW); break;
|
||||
case IR24_GREEN : changeColor(COLOR_GREEN); break;
|
||||
case IR24_GREENISH : changeColor(COLOR_GREENISH); break;
|
||||
case IR24_TURQUOISE : changeColor(COLOR_TURQUOISE); break;
|
||||
case IR24_CYAN : changeColor(COLOR_CYAN); break;
|
||||
case IR24_AQUA : changeColor(COLOR_AQUA); break;
|
||||
case IR24_BLUE : changeColor(COLOR_BLUE); break;
|
||||
case IR24_DEEPBLUE : changeColor(COLOR_DEEPBLUE); break;
|
||||
case IR24_PURPLE : changeColor(COLOR_PURPLE); break;
|
||||
case IR24_MAGENTA : changeColor(COLOR_MAGENTA); break;
|
||||
case IR24_PINK : changeColor(COLOR_PINK); break;
|
||||
case IR24_WHITE : changeColor(COLOR_WHITE); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR24_FLASH : presetFallback(1, FX_MODE_COLORTWINKLE, effectPalette); break;
|
||||
case IR24_STROBE : presetFallback(2, FX_MODE_RAINBOW_CYCLE, effectPalette); break;
|
||||
case IR24_FADE : presetFallback(3, FX_MODE_BREATH, effectPalette); break;
|
||||
@@ -256,30 +361,30 @@ void decodeIR24(uint32_t code)
|
||||
void decodeIR24OLD(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR24_OLD_BRIGHTER : incBrightness(); break;
|
||||
case IR24_OLD_DARKER : decBrightness(); 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;
|
||||
case IR24_OLD_ORANGE : colorFromUint32(COLOR_ORANGE); break;
|
||||
case IR24_OLD_YELLOWISH : colorFromUint32(COLOR_YELLOWISH); break;
|
||||
case IR24_OLD_YELLOW : colorFromUint32(COLOR_YELLOW); break;
|
||||
case IR24_OLD_GREEN : colorFromUint32(COLOR_GREEN); break;
|
||||
case IR24_OLD_GREENISH : colorFromUint32(COLOR_GREENISH); break;
|
||||
case IR24_OLD_TURQUOISE : colorFromUint32(COLOR_TURQUOISE); break;
|
||||
case IR24_OLD_CYAN : colorFromUint32(COLOR_CYAN); break;
|
||||
case IR24_OLD_AQUA : colorFromUint32(COLOR_AQUA); break;
|
||||
case IR24_OLD_BLUE : colorFromUint32(COLOR_BLUE); break;
|
||||
case IR24_OLD_DEEPBLUE : colorFromUint32(COLOR_DEEPBLUE); break;
|
||||
case IR24_OLD_PURPLE : colorFromUint32(COLOR_PURPLE); break;
|
||||
case IR24_OLD_MAGENTA : colorFromUint32(COLOR_MAGENTA); break;
|
||||
case IR24_OLD_PINK : colorFromUint32(COLOR_PINK); break;
|
||||
case IR24_OLD_WHITE : colorFromUint32(COLOR_WHITE); effectCurrent = 0; break;
|
||||
case IR24_OLD_FLASH : presetFallback(1, FX_MODE_COLORTWINKLE, 0); break;
|
||||
case IR24_OLD_STROBE : presetFallback(2, FX_MODE_RAINBOW_CYCLE, 0); break;
|
||||
case IR24_OLD_FADE : presetFallback(3, FX_MODE_BREATH, 0); break;
|
||||
case IR24_OLD_SMOOTH : presetFallback(4, FX_MODE_RAINBOW, 0); break;
|
||||
case IR24_OLD_BRIGHTER : incBrightness(); break;
|
||||
case IR24_OLD_DARKER : decBrightness(); break;
|
||||
case IR24_OLD_OFF : if (bri > 0) briLast = bri; bri = 0; break;
|
||||
case IR24_OLD_ON : bri = briLast; break;
|
||||
case IR24_OLD_RED : changeColor(COLOR_RED); break;
|
||||
case IR24_OLD_REDDISH : changeColor(COLOR_REDDISH); break;
|
||||
case IR24_OLD_ORANGE : changeColor(COLOR_ORANGE); break;
|
||||
case IR24_OLD_YELLOWISH : changeColor(COLOR_YELLOWISH); break;
|
||||
case IR24_OLD_YELLOW : changeColor(COLOR_YELLOW); break;
|
||||
case IR24_OLD_GREEN : changeColor(COLOR_GREEN); break;
|
||||
case IR24_OLD_GREENISH : changeColor(COLOR_GREENISH); break;
|
||||
case IR24_OLD_TURQUOISE : changeColor(COLOR_TURQUOISE); break;
|
||||
case IR24_OLD_CYAN : changeColor(COLOR_CYAN); break;
|
||||
case IR24_OLD_AQUA : changeColor(COLOR_AQUA); break;
|
||||
case IR24_OLD_BLUE : changeColor(COLOR_BLUE); break;
|
||||
case IR24_OLD_DEEPBLUE : changeColor(COLOR_DEEPBLUE); break;
|
||||
case IR24_OLD_PURPLE : changeColor(COLOR_PURPLE); break;
|
||||
case IR24_OLD_MAGENTA : changeColor(COLOR_MAGENTA); break;
|
||||
case IR24_OLD_PINK : changeColor(COLOR_PINK); break;
|
||||
case IR24_OLD_WHITE : changeColor(COLOR_WHITE); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR24_OLD_FLASH : presetFallback(1, FX_MODE_COLORTWINKLE, 0); break;
|
||||
case IR24_OLD_STROBE : presetFallback(2, FX_MODE_RAINBOW_CYCLE, 0); break;
|
||||
case IR24_OLD_FADE : presetFallback(3, FX_MODE_BREATH, 0); break;
|
||||
case IR24_OLD_SMOOTH : presetFallback(4, FX_MODE_RAINBOW, 0); break;
|
||||
default: return;
|
||||
}
|
||||
lastValidCode = code;
|
||||
@@ -292,28 +397,26 @@ void decodeIR24CT(uint32_t code)
|
||||
case IR24_CT_DARKER : decBrightness(); 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;
|
||||
case IR24_CT_ORANGE : colorFromUint32(COLOR_ORANGE); break;
|
||||
case IR24_CT_YELLOWISH : colorFromUint32(COLOR_YELLOWISH); break;
|
||||
case IR24_CT_YELLOW : colorFromUint32(COLOR_YELLOW); break;
|
||||
case IR24_CT_GREEN : colorFromUint32(COLOR_GREEN); break;
|
||||
case IR24_CT_GREENISH : colorFromUint32(COLOR_GREENISH); break;
|
||||
case IR24_CT_TURQUOISE : colorFromUint32(COLOR_TURQUOISE); break;
|
||||
case IR24_CT_CYAN : colorFromUint32(COLOR_CYAN); break;
|
||||
case IR24_CT_AQUA : colorFromUint32(COLOR_AQUA); break;
|
||||
case IR24_CT_BLUE : colorFromUint32(COLOR_BLUE); break;
|
||||
case IR24_CT_DEEPBLUE : colorFromUint32(COLOR_DEEPBLUE); break;
|
||||
case IR24_CT_PURPLE : colorFromUint32(COLOR_PURPLE); break;
|
||||
case IR24_CT_MAGENTA : colorFromUint32(COLOR_MAGENTA); break;
|
||||
case IR24_CT_PINK : colorFromUint32(COLOR_PINK); break;
|
||||
case IR24_CT_COLDWHITE : colorFromUint32(COLOR2_COLDWHITE); effectCurrent = 0; break;
|
||||
case IR24_CT_WARMWHITE : colorFromUint32(COLOR2_WARMWHITE); effectCurrent = 0; break;
|
||||
case IR24_CT_CTPLUS : colorFromUint32(COLOR2_COLDWHITE2); effectCurrent = 0; break;
|
||||
case IR24_CT_CTMINUS : colorFromUint32(COLOR2_WARMWHITE2); effectCurrent = 0; break;
|
||||
case IR24_CT_MEMORY : {
|
||||
if (col[3] > 0) col[3] = 0;
|
||||
else colorFromUint32(COLOR2_NEUTRALWHITE); effectCurrent = 0; } break;
|
||||
case IR24_CT_RED : changeColor(COLOR_RED); break;
|
||||
case IR24_CT_REDDISH : changeColor(COLOR_REDDISH); break;
|
||||
case IR24_CT_ORANGE : changeColor(COLOR_ORANGE); break;
|
||||
case IR24_CT_YELLOWISH : changeColor(COLOR_YELLOWISH); break;
|
||||
case IR24_CT_YELLOW : changeColor(COLOR_YELLOW); break;
|
||||
case IR24_CT_GREEN : changeColor(COLOR_GREEN); break;
|
||||
case IR24_CT_GREENISH : changeColor(COLOR_GREENISH); break;
|
||||
case IR24_CT_TURQUOISE : changeColor(COLOR_TURQUOISE); break;
|
||||
case IR24_CT_CYAN : changeColor(COLOR_CYAN); break;
|
||||
case IR24_CT_AQUA : changeColor(COLOR_AQUA); break;
|
||||
case IR24_CT_BLUE : changeColor(COLOR_BLUE); break;
|
||||
case IR24_CT_DEEPBLUE : changeColor(COLOR_DEEPBLUE); break;
|
||||
case IR24_CT_PURPLE : changeColor(COLOR_PURPLE); break;
|
||||
case IR24_CT_MAGENTA : changeColor(COLOR_MAGENTA); break;
|
||||
case IR24_CT_PINK : changeColor(COLOR_PINK); break;
|
||||
case IR24_CT_COLDWHITE : changeColor(COLOR_COLDWHITE2, 255); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR24_CT_WARMWHITE : changeColor(COLOR_WARMWHITE2, 0); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR24_CT_CTPLUS : changeColor(COLOR_COLDWHITE, strip.getSegment(strip.getMainSegmentId()).cct+1); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR24_CT_CTMINUS : changeColor(COLOR_WARMWHITE, strip.getSegment(strip.getMainSegmentId()).cct-1); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR24_CT_MEMORY : changeColor(COLOR_NEUTRALWHITE, 127); changeEffect(FX_MODE_STATIC); break;
|
||||
default: return;
|
||||
}
|
||||
lastValidCode = code;
|
||||
@@ -321,57 +424,53 @@ void decodeIR24CT(uint32_t code)
|
||||
|
||||
void decodeIR40(uint32_t code)
|
||||
{
|
||||
WS2812FX::Segment& seg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
byte r = R(seg.colors[0]);
|
||||
byte g = G(seg.colors[0]);
|
||||
byte b = B(seg.colors[0]);
|
||||
byte w = W(seg.colors[0]);
|
||||
switch (code) {
|
||||
case IR40_BPLUS : incBrightness(); break;
|
||||
case IR40_BMINUS : decBrightness(); 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;
|
||||
case IR40_ORANGE : colorFromUint24(COLOR_ORANGE); break;
|
||||
case IR40_YELLOWISH : colorFromUint24(COLOR_YELLOWISH); break;
|
||||
case IR40_YELLOW : colorFromUint24(COLOR_YELLOW); break;
|
||||
case IR40_GREEN : colorFromUint24(COLOR_GREEN); break;
|
||||
case IR40_GREENISH : colorFromUint24(COLOR_GREENISH); break;
|
||||
case IR40_TURQUOISE : colorFromUint24(COLOR_TURQUOISE); break;
|
||||
case IR40_CYAN : colorFromUint24(COLOR_CYAN); break;
|
||||
case IR40_AQUA : colorFromUint24(COLOR_AQUA); break;
|
||||
case IR40_BLUE : colorFromUint24(COLOR_BLUE); break;
|
||||
case IR40_DEEPBLUE : colorFromUint24(COLOR_DEEPBLUE); break;
|
||||
case IR40_PURPLE : colorFromUint24(COLOR_PURPLE); break;
|
||||
case IR40_MAGENTA : colorFromUint24(COLOR_MAGENTA); break;
|
||||
case IR40_PINK : colorFromUint24(COLOR_PINK); break;
|
||||
case IR40_WARMWHITE2 : {
|
||||
if (strip.hasWhiteChannel()) {colorFromUint32(COLOR2_WARMWHITE2); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_WARMWHITE2); } break;
|
||||
case IR40_WARMWHITE : {
|
||||
if (strip.hasWhiteChannel()) {colorFromUint32(COLOR2_WARMWHITE); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_WARMWHITE); } break;
|
||||
case IR40_WHITE : {
|
||||
if (strip.hasWhiteChannel()) {colorFromUint32(COLOR2_NEUTRALWHITE); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_NEUTRALWHITE); } break;
|
||||
case IR40_COLDWHITE : {
|
||||
if (strip.hasWhiteChannel()) {colorFromUint32(COLOR2_COLDWHITE); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_COLDWHITE); } break;
|
||||
case IR40_COLDWHITE2 : {
|
||||
if (strip.hasWhiteChannel()) {colorFromUint32(COLOR2_COLDWHITE2); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_COLDWHITE2); } break;
|
||||
case IR40_WPLUS : relativeChangeWhite(10); break;
|
||||
case IR40_WMINUS : relativeChangeWhite(-10, 5); break;
|
||||
case IR40_WOFF : whiteLast = col[3]; col[3] = 0; break;
|
||||
case IR40_WON : col[3] = whiteLast; break;
|
||||
case IR40_W25 : bri = 63; break;
|
||||
case IR40_W50 : bri = 127; break;
|
||||
case IR40_W75 : bri = 191; break;
|
||||
case IR40_W100 : bri = 255; break;
|
||||
case IR40_QUICK : changeEffectSpeed( 16); break;
|
||||
case IR40_SLOW : changeEffectSpeed(-16); break;
|
||||
case IR40_JUMP7 : changeEffectIntensity( 16); break;
|
||||
case IR40_AUTO : changeEffectIntensity(-16); break;
|
||||
case IR40_BPLUS : incBrightness(); break;
|
||||
case IR40_BMINUS : decBrightness(); break;
|
||||
case IR40_OFF : if (bri > 0) briLast = bri; bri = 0; break;
|
||||
case IR40_ON : bri = briLast; break;
|
||||
case IR40_RED : changeColor(COLOR_RED); break;
|
||||
case IR40_REDDISH : changeColor(COLOR_REDDISH); break;
|
||||
case IR40_ORANGE : changeColor(COLOR_ORANGE); break;
|
||||
case IR40_YELLOWISH : changeColor(COLOR_YELLOWISH); break;
|
||||
case IR40_YELLOW : changeColor(COLOR_YELLOW); break;
|
||||
case IR40_GREEN : changeColor(COLOR_GREEN); break;
|
||||
case IR40_GREENISH : changeColor(COLOR_GREENISH); break;
|
||||
case IR40_TURQUOISE : changeColor(COLOR_TURQUOISE); break;
|
||||
case IR40_CYAN : changeColor(COLOR_CYAN); break;
|
||||
case IR40_AQUA : changeColor(COLOR_AQUA); break;
|
||||
case IR40_BLUE : changeColor(COLOR_BLUE); break;
|
||||
case IR40_DEEPBLUE : changeColor(COLOR_DEEPBLUE); break;
|
||||
case IR40_PURPLE : changeColor(COLOR_PURPLE); break;
|
||||
case IR40_MAGENTA : changeColor(COLOR_MAGENTA); break;
|
||||
case IR40_PINK : changeColor(COLOR_PINK); break;
|
||||
case IR40_WARMWHITE2 : changeColor(COLOR_WARMWHITE2, 0); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR40_WARMWHITE : changeColor(COLOR_WARMWHITE, 63); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR40_WHITE : changeColor(COLOR_NEUTRALWHITE, 127); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR40_COLDWHITE : changeColor(COLOR_COLDWHITE, 191); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR40_COLDWHITE2 : changeColor(COLOR_COLDWHITE2, 255); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR40_WPLUS : changeWhite(10); break;
|
||||
case IR40_WMINUS : changeWhite(-10); break;
|
||||
case IR40_WOFF : if (w) whiteLast = w; changeColor(RGBW32(r, g, b, 0)); break;
|
||||
case IR40_WON : changeColor(RGBW32(r, g, b, whiteLast)); break;
|
||||
case IR40_W25 : bri = 63; break;
|
||||
case IR40_W50 : bri = 127; break;
|
||||
case IR40_W75 : bri = 191; break;
|
||||
case IR40_W100 : bri = 255; break;
|
||||
case IR40_QUICK : changeEffectSpeed( 16); break;
|
||||
case IR40_SLOW : changeEffectSpeed(-16); break;
|
||||
case IR40_JUMP7 : changeEffectIntensity( 16); break;
|
||||
case IR40_AUTO : changeEffectIntensity(-16); break;
|
||||
case IR40_JUMP3 : presetFallback(1, FX_MODE_STATIC, 0); break;
|
||||
case IR40_FADE3 : presetFallback(2, FX_MODE_BREATH, 0); break;
|
||||
case IR40_FADE7 : presetFallback(3, FX_MODE_FIRE_FLICKER, 0); break;
|
||||
case IR40_FLASH : presetFallback(4, FX_MODE_RAINBOW, 0); break;
|
||||
default: return;
|
||||
}
|
||||
lastValidCode = code;
|
||||
}
|
||||
@@ -379,62 +478,51 @@ void decodeIR40(uint32_t code)
|
||||
void decodeIR44(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR44_BPLUS : incBrightness(); break;
|
||||
case IR44_BMINUS : decBrightness(); 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;
|
||||
case IR44_ORANGE : colorFromUint24(COLOR_ORANGE); break;
|
||||
case IR44_YELLOWISH : colorFromUint24(COLOR_YELLOWISH); break;
|
||||
case IR44_YELLOW : colorFromUint24(COLOR_YELLOW); break;
|
||||
case IR44_GREEN : colorFromUint24(COLOR_GREEN); break;
|
||||
case IR44_GREENISH : colorFromUint24(COLOR_GREENISH); break;
|
||||
case IR44_TURQUOISE : colorFromUint24(COLOR_TURQUOISE); break;
|
||||
case IR44_CYAN : colorFromUint24(COLOR_CYAN); break;
|
||||
case IR44_AQUA : colorFromUint24(COLOR_AQUA); break;
|
||||
case IR44_BLUE : colorFromUint24(COLOR_BLUE); break;
|
||||
case IR44_DEEPBLUE : colorFromUint24(COLOR_DEEPBLUE); break;
|
||||
case IR44_PURPLE : colorFromUint24(COLOR_PURPLE); break;
|
||||
case IR44_MAGENTA : colorFromUint24(COLOR_MAGENTA); break;
|
||||
case IR44_PINK : colorFromUint24(COLOR_PINK); break;
|
||||
case IR44_WHITE : {
|
||||
if (strip.hasWhiteChannel()) {
|
||||
if (col[3] > 0) col[3] = 0;
|
||||
else { colorFromUint32(COLOR2_NEUTRALWHITE); effectCurrent = 0; }
|
||||
} else colorFromUint24(COLOR_NEUTRALWHITE); } break;
|
||||
case IR44_WARMWHITE2 : {
|
||||
if (strip.hasWhiteChannel()) {colorFromUint32(COLOR2_WARMWHITE2); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_WARMWHITE2); } break;
|
||||
case IR44_WARMWHITE : {
|
||||
if (strip.hasWhiteChannel()) {colorFromUint32(COLOR2_WARMWHITE); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_WARMWHITE); } break;
|
||||
case IR44_COLDWHITE : {
|
||||
if (strip.hasWhiteChannel()) {colorFromUint32(COLOR2_COLDWHITE); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_COLDWHITE); } break;
|
||||
case IR44_COLDWHITE2 : {
|
||||
if (strip.hasWhiteChannel()) {colorFromUint32(COLOR2_COLDWHITE2); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_COLDWHITE2); } break;
|
||||
case IR44_REDPLUS : relativeChange(&effectCurrent, 1, 0, MODE_COUNT); break;
|
||||
case IR44_REDMINUS : relativeChange(&effectCurrent, -1, 0); break;
|
||||
case IR44_GREENPLUS : relativeChange(&effectPalette, 1, 0, strip.getPaletteCount() -1); break;
|
||||
case IR44_GREENMINUS : relativeChange(&effectPalette, -1, 0); break;
|
||||
case IR44_BLUEPLUS : changeEffectIntensity( 16); break;
|
||||
case IR44_BLUEMINUS : changeEffectIntensity(-16); break;
|
||||
case IR44_QUICK : changeEffectSpeed( 16); break;
|
||||
case IR44_SLOW : changeEffectSpeed(-16); break;
|
||||
case IR44_BPLUS : incBrightness(); break;
|
||||
case IR44_BMINUS : decBrightness(); break;
|
||||
case IR44_OFF : if (bri > 0) briLast = bri; bri = 0; break;
|
||||
case IR44_ON : bri = briLast; break;
|
||||
case IR44_RED : changeColor(COLOR_RED); break;
|
||||
case IR44_REDDISH : changeColor(COLOR_REDDISH); break;
|
||||
case IR44_ORANGE : changeColor(COLOR_ORANGE); break;
|
||||
case IR44_YELLOWISH : changeColor(COLOR_YELLOWISH); break;
|
||||
case IR44_YELLOW : changeColor(COLOR_YELLOW); break;
|
||||
case IR44_GREEN : changeColor(COLOR_GREEN); break;
|
||||
case IR44_GREENISH : changeColor(COLOR_GREENISH); break;
|
||||
case IR44_TURQUOISE : changeColor(COLOR_TURQUOISE); break;
|
||||
case IR44_CYAN : changeColor(COLOR_CYAN); break;
|
||||
case IR44_AQUA : changeColor(COLOR_AQUA); break;
|
||||
case IR44_BLUE : changeColor(COLOR_BLUE); break;
|
||||
case IR44_DEEPBLUE : changeColor(COLOR_DEEPBLUE); break;
|
||||
case IR44_PURPLE : changeColor(COLOR_PURPLE); break;
|
||||
case IR44_MAGENTA : changeColor(COLOR_MAGENTA); break;
|
||||
case IR44_PINK : changeColor(COLOR_PINK); break;
|
||||
case IR44_WHITE : changeColor(COLOR_NEUTRALWHITE, 127); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR44_WARMWHITE2 : changeColor(COLOR_WARMWHITE2, 0); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR44_WARMWHITE : changeColor(COLOR_WARMWHITE, 63); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR44_COLDWHITE : changeColor(COLOR_COLDWHITE, 191); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR44_COLDWHITE2 : changeColor(COLOR_COLDWHITE2, 255); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR44_REDPLUS : changeEffect(relativeChange(effectCurrent, 1, 0, MODE_COUNT -1)); break;
|
||||
case IR44_REDMINUS : changeEffect(relativeChange(effectCurrent, -1, 0, MODE_COUNT -1)); break;
|
||||
case IR44_GREENPLUS : changePalette(relativeChange(effectPalette, 1, 0, strip.getPaletteCount() -1)); break;
|
||||
case IR44_GREENMINUS : changePalette(relativeChange(effectPalette, -1, 0, strip.getPaletteCount() -1)); break;
|
||||
case IR44_BLUEPLUS : changeEffectIntensity( 16); break;
|
||||
case IR44_BLUEMINUS : changeEffectIntensity(-16); break;
|
||||
case IR44_QUICK : changeEffectSpeed( 16); break;
|
||||
case IR44_SLOW : changeEffectSpeed(-16); break;
|
||||
case IR44_DIY1 : presetFallback(1, FX_MODE_STATIC, 0); break;
|
||||
case IR44_DIY2 : presetFallback(2, FX_MODE_BREATH, 0); break;
|
||||
case IR44_DIY3 : presetFallback(3, FX_MODE_FIRE_FLICKER, 0); break;
|
||||
case IR44_DIY4 : presetFallback(4, FX_MODE_RAINBOW, 0); break;
|
||||
case IR44_DIY5 : presetFallback(5, FX_MODE_METEOR_SMOOTH, 0); break;
|
||||
case IR44_DIY6 : presetFallback(6, FX_MODE_RAIN, 0); break;
|
||||
case IR44_AUTO : effectCurrent = FX_MODE_STATIC; break;
|
||||
case IR44_FLASH : effectCurrent = FX_MODE_PALETTE; break;
|
||||
case IR44_JUMP3 : bri = 63; break;
|
||||
case IR44_JUMP7 : bri = 127; break;
|
||||
case IR44_FADE3 : bri = 191; break;
|
||||
case IR44_FADE7 : bri = 255; break;
|
||||
case IR44_AUTO : changeEffect(FX_MODE_STATIC); break;
|
||||
case IR44_FLASH : changeEffect(FX_MODE_PALETTE); break;
|
||||
case IR44_JUMP3 : bri = 63; break;
|
||||
case IR44_JUMP7 : bri = 127; break;
|
||||
case IR44_FADE3 : bri = 191; break;
|
||||
case IR44_FADE7 : bri = 255; break;
|
||||
default: return;
|
||||
}
|
||||
lastValidCode = code;
|
||||
}
|
||||
@@ -442,28 +530,28 @@ void decodeIR44(uint32_t code)
|
||||
void decodeIR21(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR21_BRIGHTER: incBrightness(); break;
|
||||
case IR21_DARKER: decBrightness(); 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;
|
||||
case IR21_ORANGE: colorFromUint32(COLOR_ORANGE); break;
|
||||
case IR21_YELLOWISH: colorFromUint32(COLOR_YELLOWISH); break;
|
||||
case IR21_GREEN: colorFromUint32(COLOR_GREEN); break;
|
||||
case IR21_GREENISH: colorFromUint32(COLOR_GREENISH); break;
|
||||
case IR21_TURQUOISE: colorFromUint32(COLOR_TURQUOISE); break;
|
||||
case IR21_CYAN: colorFromUint32(COLOR_CYAN); break;
|
||||
case IR21_BLUE: colorFromUint32(COLOR_BLUE); break;
|
||||
case IR21_DEEPBLUE: colorFromUint32(COLOR_DEEPBLUE); break;
|
||||
case IR21_PURPLE: colorFromUint32(COLOR_PURPLE); break;
|
||||
case IR21_PINK: colorFromUint32(COLOR_PINK); break;
|
||||
case IR21_WHITE: colorFromUint32(COLOR_WHITE); effectCurrent = 0; break;
|
||||
case IR21_FLASH: presetFallback(1, FX_MODE_COLORTWINKLE, 0); break;
|
||||
case IR21_STROBE: presetFallback(2, FX_MODE_RAINBOW_CYCLE, 0); break;
|
||||
case IR21_FADE: presetFallback(3, FX_MODE_BREATH, 0); break;
|
||||
case IR21_SMOOTH: presetFallback(4, FX_MODE_RAINBOW, 0); break;
|
||||
default: return;
|
||||
case IR21_BRIGHTER: incBrightness(); break;
|
||||
case IR21_DARKER: decBrightness(); break;
|
||||
case IR21_OFF: if (bri > 0) briLast = bri; bri = 0; break;
|
||||
case IR21_ON: bri = briLast; break;
|
||||
case IR21_RED: changeColor(COLOR_RED); break;
|
||||
case IR21_REDDISH: changeColor(COLOR_REDDISH); break;
|
||||
case IR21_ORANGE: changeColor(COLOR_ORANGE); break;
|
||||
case IR21_YELLOWISH: changeColor(COLOR_YELLOWISH); break;
|
||||
case IR21_GREEN: changeColor(COLOR_GREEN); break;
|
||||
case IR21_GREENISH: changeColor(COLOR_GREENISH); break;
|
||||
case IR21_TURQUOISE: changeColor(COLOR_TURQUOISE); break;
|
||||
case IR21_CYAN: changeColor(COLOR_CYAN); break;
|
||||
case IR21_BLUE: changeColor(COLOR_BLUE); break;
|
||||
case IR21_DEEPBLUE: changeColor(COLOR_DEEPBLUE); break;
|
||||
case IR21_PURPLE: changeColor(COLOR_PURPLE); break;
|
||||
case IR21_PINK: changeColor(COLOR_PINK); break;
|
||||
case IR21_WHITE: changeColor(COLOR_WHITE); changeEffect(FX_MODE_STATIC); break;
|
||||
case IR21_FLASH: presetFallback(1, FX_MODE_COLORTWINKLE, 0); break;
|
||||
case IR21_STROBE: presetFallback(2, FX_MODE_RAINBOW_CYCLE, 0); break;
|
||||
case IR21_FADE: presetFallback(3, FX_MODE_BREATH, 0); break;
|
||||
case IR21_SMOOTH: presetFallback(4, FX_MODE_RAINBOW, 0); break;
|
||||
default: return;
|
||||
}
|
||||
lastValidCode = code;
|
||||
}
|
||||
@@ -471,31 +559,32 @@ void decodeIR21(uint32_t code)
|
||||
void decodeIR6(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR6_POWER: toggleOnOff(); break;
|
||||
case IR6_CHANNEL_UP: incBrightness(); break;
|
||||
case IR6_CHANNEL_DOWN: decBrightness(); break;
|
||||
case IR6_VOLUME_UP: relativeChange(&effectCurrent, 1, 0, MODE_COUNT); break; // next effect
|
||||
case IR6_VOLUME_DOWN: // next palette
|
||||
relativeChange(&effectPalette, 1, 0, strip.getPaletteCount() -1);
|
||||
case IR6_POWER: toggleOnOff(); break;
|
||||
case IR6_CHANNEL_UP: incBrightness(); break;
|
||||
case IR6_CHANNEL_DOWN: decBrightness(); break;
|
||||
case IR6_VOLUME_UP: changeEffect(relativeChange(effectCurrent, 1, 0, MODE_COUNT -1)); break;
|
||||
case IR6_VOLUME_DOWN: changePalette(relativeChange(effectPalette, 1, 0, strip.getPaletteCount() -1));
|
||||
switch(lastIR6ColourIdx) {
|
||||
case 0: colorFromUint32(COLOR_RED); break;
|
||||
case 1: colorFromUint32(COLOR_REDDISH); break;
|
||||
case 2: colorFromUint32(COLOR_ORANGE); break;
|
||||
case 3: colorFromUint32(COLOR_YELLOWISH); break;
|
||||
case 4: colorFromUint32(COLOR_GREEN); break;
|
||||
case 5: colorFromUint32(COLOR_GREENISH); break;
|
||||
case 6: colorFromUint32(COLOR_TURQUOISE); break;
|
||||
case 7: colorFromUint32(COLOR_CYAN); break;
|
||||
case 8: colorFromUint32(COLOR_BLUE); break;
|
||||
case 9: colorFromUint32(COLOR_DEEPBLUE); break;
|
||||
case 10:colorFromUint32(COLOR_PURPLE); break;
|
||||
case 11:colorFromUint32(COLOR_PINK); break;
|
||||
case 12:colorFromUint32(COLOR_WHITE); break;
|
||||
default: break;
|
||||
case 0: changeColor(COLOR_RED); break;
|
||||
case 1: changeColor(COLOR_REDDISH); break;
|
||||
case 2: changeColor(COLOR_ORANGE); break;
|
||||
case 3: changeColor(COLOR_YELLOWISH); break;
|
||||
case 4: changeColor(COLOR_GREEN); break;
|
||||
case 5: changeColor(COLOR_GREENISH); break;
|
||||
case 6: changeColor(COLOR_TURQUOISE); break;
|
||||
case 7: changeColor(COLOR_CYAN); break;
|
||||
case 8: changeColor(COLOR_BLUE); break;
|
||||
case 9: changeColor(COLOR_DEEPBLUE); break;
|
||||
case 10:changeColor(COLOR_PURPLE); break;
|
||||
case 11:changeColor(COLOR_PINK); break;
|
||||
case 12:changeColor(COLOR_WHITE); break;
|
||||
default: break;
|
||||
}
|
||||
lastIR6ColourIdx++;
|
||||
if(lastIR6ColourIdx > 12) lastIR6ColourIdx = 0; break;
|
||||
case IR6_MUTE: effectCurrent = 0; effectPalette = 0; colorFromUint32(COLOR_WHITE); bri=255; break;
|
||||
if(lastIR6ColourIdx > 12) lastIR6ColourIdx = 0;
|
||||
break;
|
||||
case IR6_MUTE: changeEffect(FX_MODE_STATIC); changePalette(0); changeColor(COLOR_WHITE); bri=255; break;
|
||||
default: return;
|
||||
}
|
||||
lastValidCode = code;
|
||||
}
|
||||
@@ -503,17 +592,15 @@ void decodeIR6(uint32_t code)
|
||||
void decodeIR9(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR9_POWER : toggleOnOff(); break;
|
||||
case IR9_A : presetFallback(1, FX_MODE_COLORTWINKLE, effectPalette); break;
|
||||
case IR9_B : presetFallback(2, FX_MODE_RAINBOW_CYCLE, effectPalette); break;
|
||||
case IR9_C : presetFallback(3, FX_MODE_BREATH, effectPalette); break;
|
||||
case IR9_UP : incBrightness(); break;
|
||||
case IR9_DOWN : decBrightness(); break;
|
||||
//case IR9_UP : changeEffectIntensity(16); break;
|
||||
//case IR9_DOWN : changeEffectIntensity(-16); break;
|
||||
case IR9_LEFT : changeEffectSpeed(-16); break;
|
||||
case IR9_RIGHT : changeEffectSpeed(16); break;
|
||||
case IR9_SELECT : relativeChange(&effectCurrent, 1, 0, MODE_COUNT); break;
|
||||
case IR9_POWER : toggleOnOff(); break;
|
||||
case IR9_A : presetFallback(1, FX_MODE_COLORTWINKLE, effectPalette); break;
|
||||
case IR9_B : presetFallback(2, FX_MODE_RAINBOW_CYCLE, effectPalette); break;
|
||||
case IR9_C : presetFallback(3, FX_MODE_BREATH, effectPalette); break;
|
||||
case IR9_UP : incBrightness(); break;
|
||||
case IR9_DOWN : decBrightness(); break;
|
||||
case IR9_LEFT : changeEffectSpeed(-16); break;
|
||||
case IR9_RIGHT : changeEffectSpeed(16); break;
|
||||
case IR9_SELECT : changeEffect(relativeChange(effectCurrent, 1, 0, MODE_COUNT -1)); break;
|
||||
default: return;
|
||||
}
|
||||
lastValidCode = code;
|
||||
@@ -575,7 +662,7 @@ void decodeIRJson(uint32_t code)
|
||||
cmdStr = fdo["cmd"].as<String>();
|
||||
jsonCmdObj = fdo["cmd"]; //object
|
||||
|
||||
if (jsonCmdObj.isNull())
|
||||
if (jsonCmdObj.isNull()) // we could also use: fdo["cmd"].is<String>()
|
||||
{
|
||||
if (cmdStr.startsWith("!")) {
|
||||
// call limited set of C functions
|
||||
@@ -586,37 +673,33 @@ void decodeIRJson(uint32_t code)
|
||||
lastValidCode = code;
|
||||
decBrightness();
|
||||
} else if (cmdStr.startsWith(F("!presetF"))) { //!presetFallback
|
||||
uint8_t p1 = fdo["PL"] ? fdo["PL"] : 1;
|
||||
uint8_t p2 = fdo["FX"] ? fdo["FX"] : random8(MODE_COUNT);
|
||||
uint8_t p3 = fdo["FP"] ? fdo["FP"] : 0;
|
||||
uint8_t p1 = fdo["PL"] | 1;
|
||||
uint8_t p2 = fdo["FX"] | random8(MODE_COUNT -1);
|
||||
uint8_t p3 = fdo["FP"] | 0;
|
||||
presetFallback(p1, p2, p3);
|
||||
}
|
||||
} else {
|
||||
// HTTP API command
|
||||
if (cmdStr.indexOf("~") || fdo["rpt"])
|
||||
{
|
||||
// repeatable action
|
||||
lastValidCode = code;
|
||||
String apireq = "win"; apireq += '&'; // reduce flash string usage
|
||||
if (cmdStr.indexOf("~") || fdo["rpt"]) lastValidCode = code; // repeatable action
|
||||
if (!cmdStr.startsWith(apireq)) cmdStr = apireq + cmdStr; // if no "win&" prefix
|
||||
if (!irApplyToAllSelected && cmdStr.indexOf(F("SS="))<0) {
|
||||
char tmp[10];
|
||||
sprintf_P(tmp, PSTR("&SS=%d"), strip.getMainSegmentId());
|
||||
cmdStr += tmp;
|
||||
}
|
||||
if (effectCurrent == 0 && cmdStr.indexOf("FP=") > -1) {
|
||||
// setting palette but it wont show because effect is solid
|
||||
effectCurrent = FX_MODE_GRADIENT;
|
||||
}
|
||||
if (!cmdStr.startsWith("win&")) {
|
||||
cmdStr = "win&" + cmdStr;
|
||||
}
|
||||
fdo.clear(); //clear JSON buffer (it is no longer needed)
|
||||
handleSet(nullptr, cmdStr, false); // no colorUpdated() call here
|
||||
fdo.clear(); // clear JSON buffer (it is no longer needed)
|
||||
handleSet(nullptr, cmdStr, false); // no stateUpdated() call here
|
||||
}
|
||||
} else {
|
||||
// command is JSON object
|
||||
// command is JSON object (TODO: currently will not handle irApplyToAllSelected correctly)
|
||||
if (jsonCmdObj[F("psave")].isNull()) deserializeState(jsonCmdObj, CALL_MODE_BUTTON_PRESET);
|
||||
else {
|
||||
uint8_t psave = jsonCmdObj[F("psave")].as<int>();
|
||||
char pname[33];
|
||||
sprintf_P(pname, PSTR("IR Preset %d"), psave);
|
||||
fdo.clear();
|
||||
if (psave > 0 && psave < 251) savePreset(psave, true, pname, fdo);
|
||||
if (psave > 0 && psave < 251) savePreset(psave, pname, fdo);
|
||||
}
|
||||
}
|
||||
releaseJSONBufferLock();
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
//Infrared codes for 24-key remote from http://woodsgood.ca/projects/2015/02/13/rgb-led-strip-controllers-ir-codes/
|
||||
#define IR24_BRIGHTER 0xF700FF
|
||||
#define IR24_DARKER 0xF7807F
|
||||
#define IR24_OFF 0xF740BF
|
||||
#define IR24_OFF 0xF740BF
|
||||
#define IR24_ON 0xF7C03F
|
||||
#define IR24_RED 0xF720DF
|
||||
#define IR24_REDDISH 0xF710EF
|
||||
@@ -35,7 +35,7 @@
|
||||
#define IR24_YELLOW 0xF728D7
|
||||
#define IR24_GREEN 0xF7A05F
|
||||
#define IR24_GREENISH 0xF7906F
|
||||
#define IR24_TURQUOISE 0xF7B04F
|
||||
#define IR24_TURQUOISE 0xF7B04F
|
||||
#define IR24_CYAN 0xF78877
|
||||
#define IR24_AQUA 0xF7A857
|
||||
#define IR24_BLUE 0xF7609F
|
||||
@@ -76,30 +76,30 @@
|
||||
#define IR24_CT_MEMORY 0xF7E817 // MEMORY
|
||||
|
||||
// 24-key defs for old remote control
|
||||
#define IR24_OLD_BRIGHTER 0xFF906F // Brightness Up
|
||||
#define IR24_OLD_DARKER 0xFFB847 // Brightness Down
|
||||
#define IR24_OLD_OFF 0xFFF807 // Power OFF
|
||||
#define IR24_OLD_ON 0xFFB04F // Power On
|
||||
#define IR24_OLD_RED 0xFF9867 // RED
|
||||
#define IR24_OLD_REDDISH 0xFFE817 // Light RED
|
||||
#define IR24_OLD_ORANGE 0xFF02FD // Orange
|
||||
#define IR24_OLD_YELLOWISH 0xFF50AF // Light Orange
|
||||
#define IR24_OLD_YELLOW 0xFF38C7 // YELLOW
|
||||
#define IR24_OLD_GREEN 0xFFD827 // GREEN
|
||||
#define IR24_OLD_GREENISH 0xFF48B7 // Light GREEN
|
||||
#define IR24_OLD_TURQUOISE 0xFF32CD // TURQUOISE
|
||||
#define IR24_OLD_BRIGHTER 0xFF906F // Brightness Up
|
||||
#define IR24_OLD_DARKER 0xFFB847 // Brightness Down
|
||||
#define IR24_OLD_OFF 0xFFF807 // Power OFF
|
||||
#define IR24_OLD_ON 0xFFB04F // Power On
|
||||
#define IR24_OLD_RED 0xFF9867 // RED
|
||||
#define IR24_OLD_REDDISH 0xFFE817 // Light RED
|
||||
#define IR24_OLD_ORANGE 0xFF02FD // Orange
|
||||
#define IR24_OLD_YELLOWISH 0xFF50AF // Light Orange
|
||||
#define IR24_OLD_YELLOW 0xFF38C7 // YELLOW
|
||||
#define IR24_OLD_GREEN 0xFFD827 // GREEN
|
||||
#define IR24_OLD_GREENISH 0xFF48B7 // Light GREEN
|
||||
#define IR24_OLD_TURQUOISE 0xFF32CD // TURQUOISE
|
||||
#define IR24_OLD_CYAN 0xFF7887 // CYAN
|
||||
#define IR24_OLD_AQUA 0xFF28D7 // AQUA
|
||||
#define IR24_OLD_BLUE 0xFF8877 // BLUE
|
||||
#define IR24_OLD_AQUA 0xFF28D7 // AQUA
|
||||
#define IR24_OLD_BLUE 0xFF8877 // BLUE
|
||||
#define IR24_OLD_DEEPBLUE 0xFF6897 // Dark BLUE
|
||||
#define IR24_OLD_PURPLE 0xFF20DF // PURPLE
|
||||
#define IR24_OLD_MAGENTA 0xFF708F // MAGENTA
|
||||
#define IR24_OLD_PINK 0xFFF00F // PINK
|
||||
#define IR24_OLD_WHITE 0xFFA857 // WHITE
|
||||
#define IR24_OLD_FLASH 0xFFB24D // FLASH Mode
|
||||
#define IR24_OLD_STROBE 0xFF00FF // STROBE Mode
|
||||
#define IR24_OLD_FADE 0xFF58A7 // FADE Mode
|
||||
#define IR24_OLD_SMOOTH 0xFF30CF // SMOOTH Mode
|
||||
#define IR24_OLD_PURPLE 0xFF20DF // PURPLE
|
||||
#define IR24_OLD_MAGENTA 0xFF708F // MAGENTA
|
||||
#define IR24_OLD_PINK 0xFFF00F // PINK
|
||||
#define IR24_OLD_WHITE 0xFFA857 // WHITE
|
||||
#define IR24_OLD_FLASH 0xFFB24D // FLASH Mode
|
||||
#define IR24_OLD_STROBE 0xFF00FF // STROBE Mode
|
||||
#define IR24_OLD_FADE 0xFF58A7 // FADE Mode
|
||||
#define IR24_OLD_SMOOTH 0xFF30CF // SMOOTH Mode
|
||||
|
||||
// 40-key defs for blue remote control
|
||||
#define IR40_BPLUS 0xFF3AC5 //
|
||||
@@ -212,32 +212,27 @@
|
||||
#define IR21_FADE 0xFF02FD
|
||||
#define IR21_SMOOTH 0xFFC23D
|
||||
|
||||
#define COLOR_RED 0xFF0000
|
||||
#define COLOR_REDDISH 0xFF7800
|
||||
#define COLOR_ORANGE 0xFFA000
|
||||
#define COLOR_YELLOWISH 0xFFC800
|
||||
#define COLOR_YELLOW 0xFFFF00
|
||||
#define COLOR_GREEN 0x00FF00
|
||||
#define COLOR_GREENISH 0x00FF78
|
||||
#define COLOR_TURQUOISE 0x00FFA0
|
||||
#define COLOR_CYAN 0x00FFDC
|
||||
#define COLOR_AQUA 0x00C8FF
|
||||
#define COLOR_BLUE 0x00A0FF
|
||||
#define COLOR_DEEPBLUE 0x0000FF
|
||||
#define COLOR_PURPLE 0xAA00FF
|
||||
#define COLOR_MAGENTA 0xFF00DC
|
||||
#define COLOR_PINK 0xFF00A0
|
||||
#define COLOR_WHITE 0xFFFFDC
|
||||
#define COLOR_WARMWHITE2 0xFFAA69
|
||||
#define COLOR_WARMWHITE 0xFFBF8E
|
||||
#define COLOR_NEUTRALWHITE 0xFFD4B4
|
||||
#define COLOR_COLDWHITE 0xFFE9D9
|
||||
#define COLOR_COLDWHITE2 0xFFFFFF
|
||||
#define COLOR2_WARMWHITE2 0xFFFF9900
|
||||
#define COLOR2_WARMWHITE 0xFF825A00
|
||||
#define COLOR2_NEUTRALWHITE 0xFF000000
|
||||
#define COLOR2_COLDWHITE 0xFF7F7F7F
|
||||
#define COLOR2_COLDWHITE2 0xFFFFFFFF
|
||||
#define COLOR_RED 0xFF0000
|
||||
#define COLOR_REDDISH 0xFF7800
|
||||
#define COLOR_ORANGE 0xFFA000
|
||||
#define COLOR_YELLOWISH 0xFFC800
|
||||
#define COLOR_YELLOW 0xFFFF00
|
||||
#define COLOR_GREEN 0x00FF00
|
||||
#define COLOR_GREENISH 0x00FF78
|
||||
#define COLOR_TURQUOISE 0x00FFA0
|
||||
#define COLOR_CYAN 0x00FFDC
|
||||
#define COLOR_AQUA 0x00C8FF
|
||||
#define COLOR_BLUE 0x00A0FF
|
||||
#define COLOR_DEEPBLUE 0x0000FF
|
||||
#define COLOR_PURPLE 0xAA00FF
|
||||
#define COLOR_MAGENTA 0xFF00DC
|
||||
#define COLOR_PINK 0xFF00A0
|
||||
#define COLOR_WHITE 0xFFFFFFFF
|
||||
#define COLOR_WARMWHITE2 0xFFFFAA69
|
||||
#define COLOR_WARMWHITE 0xFFFFBF8E
|
||||
#define COLOR_NEUTRALWHITE 0xFFFFD4B4
|
||||
#define COLOR_COLDWHITE 0xFFFFE9D9
|
||||
#define COLOR_COLDWHITE2 0xFFFFFFFF
|
||||
|
||||
#define ACTION_NONE 0
|
||||
#define ACTION_BRIGHT_UP 1
|
||||
@@ -246,4 +241,4 @@
|
||||
#define ACTION_SPEED_DOWN 4
|
||||
#define ACTION_INTENSITY_UP 5
|
||||
#define ACTION_INTENSITY_DOWN 6
|
||||
#define ACTION_POWER 7
|
||||
#define ACTION_POWER 7
|
||||
|
||||
@@ -177,7 +177,12 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
if (!iarr.isNull()) {
|
||||
uint8_t oldSegId = strip.setPixelSegment(id);
|
||||
|
||||
//freeze and init to black
|
||||
// set brightness immediately and disable transition
|
||||
transitionDelayTemp = 0;
|
||||
jsonTransitionOnce = true;
|
||||
strip.setBrightness(scaledBri(bri), true);
|
||||
|
||||
// freeze and init to black
|
||||
if (!seg.getOption(SEG_OPTION_FREEZE)) {
|
||||
seg.setOption(SEG_OPTION_FREEZE, true);
|
||||
strip.fill(0);
|
||||
@@ -200,7 +205,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
JsonArray icol = iarr[i];
|
||||
if (!icol.isNull()) { //array, e.g. [255,0,0]
|
||||
byte sz = icol.size();
|
||||
if (sz > 0 || sz < 5) copyArray(icol, rgbw);
|
||||
if (sz > 0 && sz < 5) copyArray(icol, rgbw);
|
||||
} else { //hex string, e.g. "FF0000"
|
||||
byte brgbw[] = {0,0,0,0};
|
||||
const char* hexCol = iarr[i];
|
||||
@@ -263,7 +268,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
transitionDelayTemp *= 100;
|
||||
jsonTransitionOnce = true;
|
||||
}
|
||||
strip.setTransition(transitionDelayTemp);
|
||||
strip.setTransition(transitionDelayTemp); // required here for color transitions to have correct duration
|
||||
|
||||
tr = root[F("tb")] | -1;
|
||||
if (tr >= 0) strip.timebase = ((uint32_t)tr) - millis();
|
||||
@@ -290,10 +295,16 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
realtimeOverride = root[F("lor")] | realtimeOverride;
|
||||
if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS;
|
||||
|
||||
bool liveEnabled = false;
|
||||
if (root.containsKey("live")) {
|
||||
bool lv = root["live"];
|
||||
if (lv) realtimeLock(65000); //enter realtime without timeout
|
||||
else realtimeTimeout = 0; //cancel realtime mode immediately
|
||||
if (lv) {
|
||||
transitionDelayTemp = 0;
|
||||
jsonTransitionOnce = true;
|
||||
liveEnabled = true; // triggers realtimeLock() below
|
||||
realtimeLock(65000);
|
||||
}
|
||||
else realtimeTimeout = 0; //cancel realtime mode immediately
|
||||
}
|
||||
|
||||
strip.setMainSegmentId(root[F("mainseg")] | strip.getMainSegmentId());
|
||||
@@ -330,19 +341,13 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
if (root["nx"].is<const char*>()) {
|
||||
strncpy(cronixieDisplay, root["nx"], 6);
|
||||
}
|
||||
#endif
|
||||
|
||||
usermods.readFromJsonState(root);
|
||||
|
||||
loadLedmap = root[F("ledmap")] | loadLedmap;
|
||||
|
||||
byte ps = root[F("psave")];
|
||||
if (ps > 0) {
|
||||
savePreset(ps, true, nullptr, root);
|
||||
savePreset(ps, nullptr, root);
|
||||
} else {
|
||||
ps = root[F("pdel")]; //deletion
|
||||
if (ps > 0) {
|
||||
@@ -376,6 +381,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
}
|
||||
|
||||
stateUpdated(callMode);
|
||||
if (liveEnabled) realtimeTimeout = UINT32_MAX; // force indefinite timeout if this request contained {"live":true}
|
||||
|
||||
return stateResponse;
|
||||
}
|
||||
@@ -503,15 +509,6 @@ void serializeInfo(JsonObject root)
|
||||
|
||||
JsonObject leds = root.createNestedObject("leds");
|
||||
leds[F("count")] = strip.getLengthTotal();
|
||||
leds[F("rgbw")] = strip.hasRGBWBus(); //deprecated, use info.leds.lc
|
||||
leds[F("wv")] = false; //deprecated, use info.leds.lc
|
||||
leds["cct"] = correctWB || strip.hasCCTBus(); //deprecated, use info.leds.lc
|
||||
switch (Bus::getAutoWhiteMode()) {
|
||||
case RGBW_MODE_MANUAL_ONLY:
|
||||
case RGBW_MODE_DUAL:
|
||||
if (strip.hasWhiteChannel()) leds[F("wv")] = true;
|
||||
break;
|
||||
}
|
||||
|
||||
leds[F("pwr")] = strip.currentMilliamps;
|
||||
leds["fps"] = strip.getFps();
|
||||
@@ -530,6 +527,10 @@ void serializeInfo(JsonObject root)
|
||||
|
||||
leds["lc"] = totalLC;
|
||||
|
||||
leds[F("rgbw")] = strip.hasRGBWBus(); // deprecated, use info.leds.lc
|
||||
leds[F("wv")] = totalLC & 0x02; // deprecated, true if white slider should be displayed for any segment
|
||||
leds["cct"] = totalLC & 0x04; // deprecated, use info.leds.lc
|
||||
|
||||
root[F("str")] = syncToggleReceive;
|
||||
|
||||
root[F("name")] = serverDescription;
|
||||
@@ -619,7 +620,7 @@ void serializeInfo(JsonObject root)
|
||||
#ifndef WLED_DISABLE_BLYNK
|
||||
os += 0x20;
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
#ifdef USERMOD_CRONIXIE
|
||||
os += 0x10;
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_FILESYSTEM
|
||||
|
||||
@@ -3,15 +3,24 @@
|
||||
/*
|
||||
* LED methods
|
||||
*/
|
||||
void setValuesFromFirstSelectedSeg()
|
||||
|
||||
void setValuesFromMainSeg() { setValuesFromSegment(strip.getMainSegmentId()); }
|
||||
void setValuesFromFirstSelectedSeg() { setValuesFromSegment(strip.getFirstSelectedSegId()); }
|
||||
void setValuesFromSegment(uint8_t s)
|
||||
{
|
||||
WS2812FX::Segment& seg = strip.getFirstSelectedSeg();
|
||||
colorFromUint32(seg.colors[0]);
|
||||
colorFromUint32(seg.colors[1], true);
|
||||
effectCurrent = seg.mode;
|
||||
effectSpeed = seg.speed;
|
||||
WS2812FX::Segment& seg = strip.getSegment(s);
|
||||
col[0] = R(seg.colors[0]);
|
||||
col[1] = G(seg.colors[0]);
|
||||
col[2] = B(seg.colors[0]);
|
||||
col[3] = W(seg.colors[0]);
|
||||
colSec[0] = R(seg.colors[1]);
|
||||
colSec[1] = G(seg.colors[1]);
|
||||
colSec[2] = B(seg.colors[1]);
|
||||
colSec[3] = W(seg.colors[1]);
|
||||
effectCurrent = seg.mode;
|
||||
effectSpeed = seg.speed;
|
||||
effectIntensity = seg.intensity;
|
||||
effectPalette = seg.palette;
|
||||
effectPalette = seg.palette;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,20 +35,14 @@ void applyValuesToSelectedSegs()
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (i != firstSel && (!seg.isActive() || !seg.isSelected())) continue;
|
||||
|
||||
if (effectSpeed != selsegPrev.speed) {
|
||||
seg.speed = effectSpeed; stateChanged = true;}
|
||||
if (effectIntensity != selsegPrev.intensity) {
|
||||
seg.intensity = effectIntensity; stateChanged = true;}
|
||||
if (effectPalette != selsegPrev.palette) {
|
||||
seg.palette = effectPalette; stateChanged = true;}
|
||||
if (effectCurrent != selsegPrev.mode) {
|
||||
strip.setMode(i, effectCurrent); stateChanged = true;}
|
||||
uint32_t col0 = RGBW32(col[0],col[1],col[2],col[3]);
|
||||
if (effectSpeed != selsegPrev.speed) {seg.speed = effectSpeed; stateChanged = true;}
|
||||
if (effectIntensity != selsegPrev.intensity) {seg.intensity = effectIntensity; stateChanged = true;}
|
||||
if (effectPalette != selsegPrev.palette) {seg.palette = effectPalette; stateChanged = true;}
|
||||
if (effectCurrent != selsegPrev.mode) {strip.setMode(i, effectCurrent); stateChanged = true;}
|
||||
uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]);
|
||||
uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
|
||||
if (col0 != selsegPrev.colors[0]) {
|
||||
seg.setColor(0, col0, i); stateChanged = true;}
|
||||
if (col1 != selsegPrev.colors[1]) {
|
||||
seg.setColor(1, col1, i); stateChanged = true;}
|
||||
if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0, i); stateChanged = true;}
|
||||
if (col1 != selsegPrev.colors[1]) {seg.setColor(1, col1, i); stateChanged = true;}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -169,7 +169,6 @@ void handleTime() {
|
||||
updateLocalTime();
|
||||
checkTimers();
|
||||
checkCountdown();
|
||||
handleOverlays();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,31 +3,6 @@
|
||||
/*
|
||||
* Used to draw clock overlays over the strip
|
||||
*/
|
||||
|
||||
void initCronixie()
|
||||
{
|
||||
if (overlayCurrent == 3 && dP[0] == 255) //if dP[0] is 255, cronixie is not yet init'ed
|
||||
{
|
||||
setCronixie();
|
||||
strip.getSegment(0).grouping = 10; //10 LEDs per digit
|
||||
} else if (dP[0] < 255 && overlayCurrent != 3)
|
||||
{
|
||||
strip.getSegment(0).grouping = 1;
|
||||
dP[0] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//handleOverlays is essentially the equivalent of usermods.loop
|
||||
void handleOverlays()
|
||||
{
|
||||
initCronixie();
|
||||
if (overlayCurrent == 3) {
|
||||
_overlayCronixie();//Diamex cronixie clock kit
|
||||
strip.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _overlayAnalogClock()
|
||||
{
|
||||
@@ -114,253 +89,9 @@ void _overlayAnalogCountdown()
|
||||
|
||||
void handleOverlayDraw() {
|
||||
usermods.handleOverlayDraw();
|
||||
if (!overlayCurrent) return;
|
||||
switch (overlayCurrent)
|
||||
{
|
||||
case 1: _overlayAnalogClock(); break;
|
||||
case 3: _drawOverlayCronixie(); break;
|
||||
}
|
||||
if (overlayCurrent == 1) _overlayAnalogClock();
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for the Cronixie clock
|
||||
* Support for the Cronixie clock has moved to a usermod, compile with "-D USERMOD_CRONIXIE" to enable
|
||||
*/
|
||||
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
byte _digitOut[6] = {10,10,10,10,10,10};
|
||||
|
||||
byte getSameCodeLength(char code, int index, char const cronixieDisplay[])
|
||||
{
|
||||
byte counter = 0;
|
||||
|
||||
for (int i = index+1; i < 6; i++)
|
||||
{
|
||||
if (cronixieDisplay[i] == code)
|
||||
{
|
||||
counter++;
|
||||
} else {
|
||||
return counter;
|
||||
}
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
void setCronixie()
|
||||
{
|
||||
/*
|
||||
* digit purpose index
|
||||
* 0-9 | 0-9 (incl. random)
|
||||
* 10 | blank
|
||||
* 11 | blank, bg off
|
||||
* 12 | test upw.
|
||||
* 13 | test dnw.
|
||||
* 14 | binary AM/PM
|
||||
* 15 | BB upper +50 for no trailing 0
|
||||
* 16 | BBB
|
||||
* 17 | BBBB
|
||||
* 18 | BBBBB
|
||||
* 19 | BBBBBB
|
||||
* 20 | H
|
||||
* 21 | HH
|
||||
* 22 | HHH
|
||||
* 23 | HHHH
|
||||
* 24 | M
|
||||
* 25 | MM
|
||||
* 26 | MMM
|
||||
* 27 | MMMM
|
||||
* 28 | MMMMM
|
||||
* 29 | MMMMMM
|
||||
* 30 | S
|
||||
* 31 | SS
|
||||
* 32 | SSS
|
||||
* 33 | SSSS
|
||||
* 34 | SSSSS
|
||||
* 35 | SSSSSS
|
||||
* 36 | Y
|
||||
* 37 | YY
|
||||
* 38 | YYYY
|
||||
* 39 | I
|
||||
* 40 | II
|
||||
* 41 | W
|
||||
* 42 | WW
|
||||
* 43 | D
|
||||
* 44 | DD
|
||||
* 45 | DDD
|
||||
* 46 | V
|
||||
* 47 | VV
|
||||
* 48 | VVV
|
||||
* 49 | VVVV
|
||||
* 50 | VVVVV
|
||||
* 51 | VVVVVV
|
||||
* 52 | v
|
||||
* 53 | vv
|
||||
* 54 | vvv
|
||||
* 55 | vvvv
|
||||
* 56 | vvvvv
|
||||
* 57 | vvvvvv
|
||||
*/
|
||||
|
||||
//H HourLower | HH - Hour 24. | AH - Hour 12. | HHH Hour of Month | HHHH Hour of Year
|
||||
//M MinuteUpper | MM Minute of Hour | MMM Minute of 12h | MMMM Minute of Day | MMMMM Minute of Month | MMMMMM Minute of Year
|
||||
//S SecondUpper | SS Second of Minute | SSS Second of 10 Minute | SSSS Second of Hour | SSSSS Second of Day | SSSSSS Second of Week
|
||||
//B AM/PM | BB 0-6/6-12/12-18/18-24 | BBB 0-3... | BBBB 0-1.5... | BBBBB 0-1 | BBBBBB 0-0.5
|
||||
|
||||
//Y YearLower | YY - Year LU | YYYY - Std.
|
||||
//I MonthLower | II - Month of Year
|
||||
//W Week of Month | WW Week of Year
|
||||
//D Day of Week | DD Day Of Month | DDD Day Of Year
|
||||
|
||||
DEBUG_PRINT("cset ");
|
||||
DEBUG_PRINTLN(cronixieDisplay);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
dP[i] = 10;
|
||||
switch (cronixieDisplay[i])
|
||||
{
|
||||
case '_': dP[i] = 10; break;
|
||||
case '-': dP[i] = 11; break;
|
||||
case 'r': dP[i] = random(1,7); break; //random btw. 1-6
|
||||
case 'R': dP[i] = random(0,10); break; //random btw. 0-9
|
||||
//case 't': break; //Test upw.
|
||||
//case 'T': break; //Test dnw.
|
||||
case 'b': dP[i] = 14 + getSameCodeLength('b',i,cronixieDisplay); i = i+dP[i]-14; break;
|
||||
case 'B': dP[i] = 14 + getSameCodeLength('B',i,cronixieDisplay); i = i+dP[i]-14; break;
|
||||
case 'h': dP[i] = 70 + getSameCodeLength('h',i,cronixieDisplay); i = i+dP[i]-70; break;
|
||||
case 'H': dP[i] = 20 + getSameCodeLength('H',i,cronixieDisplay); i = i+dP[i]-20; break;
|
||||
case 'A': dP[i] = 108; i++; break;
|
||||
case 'a': dP[i] = 58; i++; break;
|
||||
case 'm': dP[i] = 74 + getSameCodeLength('m',i,cronixieDisplay); i = i+dP[i]-74; break;
|
||||
case 'M': dP[i] = 24 + getSameCodeLength('M',i,cronixieDisplay); i = i+dP[i]-24; break;
|
||||
case 's': dP[i] = 80 + getSameCodeLength('s',i,cronixieDisplay); i = i+dP[i]-80; break; //refresh more often bc. of secs
|
||||
case 'S': dP[i] = 30 + getSameCodeLength('S',i,cronixieDisplay); i = i+dP[i]-30; break;
|
||||
case 'Y': dP[i] = 36 + getSameCodeLength('Y',i,cronixieDisplay); i = i+dP[i]-36; break;
|
||||
case 'y': dP[i] = 86 + getSameCodeLength('y',i,cronixieDisplay); i = i+dP[i]-86; break;
|
||||
case 'I': dP[i] = 39 + getSameCodeLength('I',i,cronixieDisplay); i = i+dP[i]-39; break; //Month. Don't ask me why month and minute both start with M.
|
||||
case 'i': dP[i] = 89 + getSameCodeLength('i',i,cronixieDisplay); i = i+dP[i]-89; break;
|
||||
//case 'W': break;
|
||||
//case 'w': break;
|
||||
case 'D': dP[i] = 43 + getSameCodeLength('D',i,cronixieDisplay); i = i+dP[i]-43; break;
|
||||
case 'd': dP[i] = 93 + getSameCodeLength('d',i,cronixieDisplay); i = i+dP[i]-93; break;
|
||||
case '0': dP[i] = 0; break;
|
||||
case '1': dP[i] = 1; break;
|
||||
case '2': dP[i] = 2; break;
|
||||
case '3': dP[i] = 3; break;
|
||||
case '4': dP[i] = 4; break;
|
||||
case '5': dP[i] = 5; break;
|
||||
case '6': dP[i] = 6; break;
|
||||
case '7': dP[i] = 7; break;
|
||||
case '8': dP[i] = 8; break;
|
||||
case '9': dP[i] = 9; break;
|
||||
//case 'V': break; //user var0
|
||||
//case 'v': break; //user var1
|
||||
}
|
||||
}
|
||||
DEBUG_PRINT("result ");
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
DEBUG_PRINT((int)dP[i]);
|
||||
DEBUG_PRINT(" ");
|
||||
}
|
||||
DEBUG_PRINTLN((int)dP[5]);
|
||||
|
||||
_overlayCronixie(); //refresh
|
||||
}
|
||||
|
||||
void _overlayCronixie()
|
||||
{
|
||||
byte h = hour(localTime);
|
||||
byte h0 = h;
|
||||
byte m = minute(localTime);
|
||||
byte s = second(localTime);
|
||||
byte d = day(localTime);
|
||||
byte mi = month(localTime);
|
||||
int y = year(localTime);
|
||||
//this has to be changed in time for 22nd century
|
||||
y -= 2000; if (y<0) y += 30; //makes countdown work
|
||||
|
||||
if (useAMPM && !countdownMode)
|
||||
{
|
||||
if (h>12) h-=12;
|
||||
else if (h==0) h+=12;
|
||||
}
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (dP[i] < 12) _digitOut[i] = dP[i];
|
||||
else {
|
||||
if (dP[i] < 65)
|
||||
{
|
||||
switch(dP[i])
|
||||
{
|
||||
case 21: _digitOut[i] = h/10; _digitOut[i+1] = h- _digitOut[i]*10; i++; break; //HH
|
||||
case 25: _digitOut[i] = m/10; _digitOut[i+1] = m- _digitOut[i]*10; i++; break; //MM
|
||||
case 31: _digitOut[i] = s/10; _digitOut[i+1] = s- _digitOut[i]*10; i++; break; //SS
|
||||
|
||||
case 20: _digitOut[i] = h- (h/10)*10; break; //H
|
||||
case 24: _digitOut[i] = m/10; break; //M
|
||||
case 30: _digitOut[i] = s/10; break; //S
|
||||
|
||||
case 43: _digitOut[i] = weekday(localTime); _digitOut[i]--; if (_digitOut[i]<1) _digitOut[i]= 7; break; //D
|
||||
case 44: _digitOut[i] = d/10; _digitOut[i+1] = d- _digitOut[i]*10; i++; break; //DD
|
||||
case 40: _digitOut[i] = mi/10; _digitOut[i+1] = mi- _digitOut[i]*10; i++; break; //II
|
||||
case 37: _digitOut[i] = y/10; _digitOut[i+1] = y- _digitOut[i]*10; i++; break; //YY
|
||||
case 39: _digitOut[i] = 2; _digitOut[i+1] = 0; _digitOut[i+2] = y/10; _digitOut[i+3] = y- _digitOut[i+2]*10; i+=3; break; //YYYY
|
||||
|
||||
//case 16: _digitOut[i+2] = ((h0/3)&1)?1:0; i++; //BBB (BBBB NI)
|
||||
//case 15: _digitOut[i+1] = (h0>17 || (h0>5 && h0<12))?1:0; i++; //BB
|
||||
case 14: _digitOut[i] = (h0>11)?1:0; break; //B
|
||||
}
|
||||
} else
|
||||
{
|
||||
switch(dP[i])
|
||||
{
|
||||
case 71: _digitOut[i] = h/10; _digitOut[i+1] = h- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //hh
|
||||
case 75: _digitOut[i] = m/10; _digitOut[i+1] = m- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //mm
|
||||
case 81: _digitOut[i] = s/10; _digitOut[i+1] = s- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //ss
|
||||
//case 66: _digitOut[i+2] = ((h0/3)&1)?1:10; i++; //bbb (bbbb NI)
|
||||
//case 65: _digitOut[i+1] = (h0>17 || (h0>5 && h0<12))?1:10; i++; //bb
|
||||
case 64: _digitOut[i] = (h0>11)?1:10; break; //b
|
||||
|
||||
case 93: _digitOut[i] = weekday(localTime); _digitOut[i]--; if (_digitOut[i]<1) _digitOut[i]= 7; break; //d
|
||||
case 94: _digitOut[i] = d/10; _digitOut[i+1] = d- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //dd
|
||||
case 90: _digitOut[i] = mi/10; _digitOut[i+1] = mi- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //ii
|
||||
case 87: _digitOut[i] = y/10; _digitOut[i+1] = y- _digitOut[i]*10; i++; break; //yy
|
||||
case 89: _digitOut[i] = 2; _digitOut[i+1] = 0; _digitOut[i+2] = y/10; _digitOut[i+3] = y- _digitOut[i+2]*10; i+=3; break; //yyyy
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _drawOverlayCronixie()
|
||||
{
|
||||
byte offsets[] = {5, 0, 6, 1, 7, 2, 8, 3, 9, 4};
|
||||
|
||||
for (uint16_t i = 0; i < 6; i++)
|
||||
{
|
||||
byte o = 10*i;
|
||||
byte excl = 10;
|
||||
if(_digitOut[i] < 10) excl = offsets[_digitOut[i]];
|
||||
excl += o;
|
||||
|
||||
if (cronixieBacklight && _digitOut[i] <11)
|
||||
{
|
||||
uint32_t col = strip.gamma32(strip.getSegment(0).colors[1]);
|
||||
for (uint16_t j=o; j< o+10; j++) {
|
||||
if (j != excl) strip.setPixelColor(j, col);
|
||||
}
|
||||
} else
|
||||
{
|
||||
for (uint16_t j=o; j< o+10; j++) {
|
||||
if (j != excl) strip.setPixelColor(j, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else // WLED_DISABLE_CRONIXIE
|
||||
byte getSameCodeLength(char code, int index, char const cronixieDisplay[]) { return 0; }
|
||||
void setCronixie() {}
|
||||
void _overlayCronixie() {}
|
||||
void _drawOverlayCronixie() {}
|
||||
#endif
|
||||
|
||||
@@ -50,12 +50,13 @@ bool applyPreset(byte index, byte callMode)
|
||||
return false;
|
||||
}
|
||||
|
||||
void savePreset(byte index, bool persist, const char* pname, JsonObject saveobj)
|
||||
void savePreset(byte index, const char* pname, JsonObject saveobj)
|
||||
{
|
||||
if (index == 0 || (index > 250 && persist) || (index<255 && !persist)) return;
|
||||
if (index == 0 || (index > 250 && index < 255)) return;
|
||||
char tmp[12];
|
||||
JsonObject sObj = saveobj;
|
||||
|
||||
bool persist = (index == 255);
|
||||
const char *filename = persist ? "/presets.json" : "/tmp.json";
|
||||
|
||||
if (!fileDoc) {
|
||||
|
||||
@@ -84,10 +84,11 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
autoSegments = request->hasArg(F("MS"));
|
||||
correctWB = request->hasArg(F("CCT"));
|
||||
cctFromRgb = request->hasArg(F("CR"));
|
||||
strip.cctBlending = request->arg(F("CB")).toInt();
|
||||
Bus::setCCTBlend(strip.cctBlending);
|
||||
Bus::setAutoWhiteMode(request->arg(F("AW")).toInt());
|
||||
strip.setTargetFps(request->arg(F("FR")).toInt());
|
||||
strip.cctBlending = request->arg(F("CB")).toInt();
|
||||
Bus::setCCTBlend(strip.cctBlending);
|
||||
strip.autoWhiteMode = (request->arg(F("AW")).toInt());
|
||||
Bus::setAutoWhiteMode(strip.autoWhiteMode);
|
||||
strip.setTargetFps(request->arg(F("FR")).toInt());
|
||||
|
||||
for (uint8_t s = 0; s < WLED_MAX_BUSSES; s++) {
|
||||
char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin
|
||||
@@ -145,6 +146,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
irPin = -1;
|
||||
}
|
||||
irEnabled = request->arg(F("IT")).toInt();
|
||||
irApplyToAllSelected = !request->hasArg(F("MSO"));
|
||||
|
||||
int hw_rly_pin = request->arg(F("RL")).toInt();
|
||||
if (pinManager.allocatePin(hw_rly_pin,true, PinOwner::Relay)) {
|
||||
@@ -321,10 +323,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
// force a sunrise/sunset re-calculation
|
||||
calculateSunriseAndSunset();
|
||||
|
||||
if (request->hasArg(F("OL"))) {
|
||||
overlayDefault = request->arg(F("OL")).toInt();
|
||||
overlayCurrent = overlayDefault;
|
||||
}
|
||||
overlayCurrent = request->hasArg(F("OL")) ? 1 : 0;
|
||||
|
||||
overlayMin = request->arg(F("O1")).toInt();
|
||||
overlayMax = request->arg(F("O2")).toInt();
|
||||
@@ -332,10 +331,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
analogClock5MinuteMarks = request->hasArg(F("O5"));
|
||||
analogClockSecondsTrail = request->hasArg(F("OS"));
|
||||
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
strlcpy(cronixieDisplay,request->arg(F("CX")).c_str(),7);
|
||||
cronixieBacklight = request->hasArg(F("CB"));
|
||||
#endif
|
||||
countdownMode = request->hasArg(F("CE"));
|
||||
countdownYear = request->arg(F("CY")).toInt();
|
||||
countdownMonth = request->arg(F("CI")).toInt();
|
||||
@@ -551,6 +546,8 @@ void parseNumber(const char* str, byte* val, byte minv, byte maxv)
|
||||
{
|
||||
if (str == nullptr || str[0] == '\0') return;
|
||||
if (str[0] == 'r') {*val = random8(minv,maxv); return;}
|
||||
bool wrap = false;
|
||||
if (str[0] == 'w' && strlen(str) > 1) {str++; wrap = true;}
|
||||
if (str[0] == '~') {
|
||||
int out = atoi(str +1);
|
||||
if (out == 0)
|
||||
@@ -563,9 +560,13 @@ void parseNumber(const char* str, byte* val, byte minv, byte maxv)
|
||||
*val = (int)(*val +1) > (int)maxv ? minv : max((int)minv,(*val +1)); //+1, wrap around
|
||||
}
|
||||
} else {
|
||||
out += *val;
|
||||
if (out > maxv) out = maxv;
|
||||
if (out < minv) out = minv;
|
||||
if (wrap && *val == maxv && out > 0) out = minv;
|
||||
else if (wrap && *val == minv && out < 0) out = maxv;
|
||||
else {
|
||||
out += *val;
|
||||
if (out > maxv) out = maxv;
|
||||
if (out < minv) out = minv;
|
||||
}
|
||||
*val = out;
|
||||
}
|
||||
} else
|
||||
@@ -795,7 +796,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
if (pos > 0) {
|
||||
byte temp;
|
||||
for (uint8_t i=0; i<4; i++) {
|
||||
temp = colIn[i];
|
||||
temp = colIn[i];
|
||||
colIn[i] = colInSec[i];
|
||||
colInSec[i] = temp;
|
||||
}
|
||||
@@ -829,13 +830,14 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
|
||||
stateChanged |= (fxModeChanged || speedChanged || intensityChanged || paletteChanged);
|
||||
|
||||
// apply to main and all selected segments to prevent #1618.
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (i != selectedSeg && (singleSegment || !seg.isActive() || !seg.isSelected())) continue;
|
||||
if (i != selectedSeg && (singleSegment || !seg.isActive() || !seg.isSelected())) continue; // skip non main segments if not applying to all
|
||||
if (fxModeChanged) strip.setMode(i, effectIn);
|
||||
if (speedChanged) seg.speed = speedIn;
|
||||
if (speedChanged) seg.speed = speedIn;
|
||||
if (intensityChanged) seg.intensity = intensityIn;
|
||||
if (paletteChanged) seg.palette = paletteIn;
|
||||
if (paletteChanged) seg.palette = paletteIn;
|
||||
}
|
||||
|
||||
//set advanced overlay
|
||||
@@ -936,24 +938,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
pos = req.indexOf(F("RB"));
|
||||
if (pos > 0) doReboot = true;
|
||||
|
||||
//cronixie
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
//mode, 1 countdown
|
||||
// clock mode, 0: normal, 1: countdown
|
||||
pos = req.indexOf(F("NM="));
|
||||
if (pos > 0) countdownMode = (req.charAt(pos+3) != '0');
|
||||
|
||||
pos = req.indexOf(F("NX=")); //sets digits to code
|
||||
if (pos > 0) {
|
||||
strlcpy(cronixieDisplay, req.substring(pos + 3, pos + 9).c_str(), 7);
|
||||
setCronixie();
|
||||
}
|
||||
|
||||
pos = req.indexOf(F("NB="));
|
||||
if (pos > 0) //sets backlight
|
||||
{
|
||||
cronixieBacklight = (req.charAt(pos+3) != '0');
|
||||
}
|
||||
#endif
|
||||
|
||||
pos = req.indexOf(F("U0=")); //user var 0
|
||||
if (pos > 0) {
|
||||
|
||||
@@ -148,16 +148,18 @@ void realtimeLock(uint32_t timeoutMs, byte md)
|
||||
}
|
||||
}
|
||||
|
||||
realtimeTimeout = millis() + timeoutMs;
|
||||
if (timeoutMs == 255001 || timeoutMs == 65000) realtimeTimeout = UINT32_MAX;
|
||||
if (realtimeTimeout != UINT32_MAX) {
|
||||
realtimeTimeout = millis() + timeoutMs;
|
||||
if (timeoutMs == 255001 || timeoutMs == 65000) realtimeTimeout = UINT32_MAX;
|
||||
}
|
||||
// if strip is off (bri==0) and not already in RTM
|
||||
if (bri == 0 && !realtimeMode) {
|
||||
strip.setBrightness(scaledBri(briLast));
|
||||
if (briT == 0 && !realtimeMode) {
|
||||
strip.setBrightness(scaledBri(briLast), true);
|
||||
}
|
||||
realtimeMode = md;
|
||||
|
||||
if (arlsForceMaxBri && !realtimeOverride) strip.setBrightness(scaledBri(255));
|
||||
if (md == REALTIME_MODE_GENERIC) strip.show();
|
||||
if (arlsForceMaxBri && !realtimeOverride) strip.setBrightness(scaledBri(255), true);
|
||||
if (briT > 0 && md == REALTIME_MODE_GENERIC) strip.show();
|
||||
}
|
||||
|
||||
|
||||
@@ -652,19 +654,16 @@ void sendSysInfoUDP()
|
||||
uint8_t sequenceNumber = 0; // this needs to be shared across all outputs
|
||||
|
||||
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8_t *buffer, uint8_t bri, bool isRGBW) {
|
||||
if (!interfacesInited) return 1; // network not initialised
|
||||
if (!interfacesInited || !client[0] || !length) return 1; // network not initialised or dummy/unset IP address
|
||||
|
||||
WiFiUDP ddpUdp;
|
||||
|
||||
switch (type) {
|
||||
case 0: // DDP
|
||||
{
|
||||
// calclate the number of UDP packets we need to send
|
||||
// calculate the number of UDP packets we need to send
|
||||
uint16_t channelCount = length * 3; // 1 channel for every R,G,B value
|
||||
uint16_t packetCount = channelCount / DDP_CHANNELS_PER_PACKET;
|
||||
if (channelCount % DDP_CHANNELS_PER_PACKET) {
|
||||
packetCount++;
|
||||
}
|
||||
uint16_t packetCount = ((channelCount-1) / DDP_CHANNELS_PER_PACKET) +1;
|
||||
|
||||
// there are 3 channels per RGB pixel
|
||||
uint32_t channel = 0; // TODO: allow specifying the start channel
|
||||
|
||||
@@ -104,6 +104,10 @@
|
||||
#include "../usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h"
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_CRONIXIE
|
||||
#include "../usermods/Cronixie/usermod_cronixie.h"
|
||||
#endif
|
||||
|
||||
#ifdef QUINLED_AN_PENTA
|
||||
#include "../usermods/quinled-an-penta/quinled-an-penta.h"
|
||||
#endif
|
||||
@@ -200,6 +204,10 @@ void registerUsermods()
|
||||
usermods.add(new UsermodSSDR());
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_CRONIXIE
|
||||
usermods.add(new UsermodCronixie());
|
||||
#endif
|
||||
|
||||
#ifdef QUINLED_AN_PENTA
|
||||
usermods.add(new QuinLEDAnPentaUsermod());
|
||||
#endif
|
||||
|
||||
@@ -62,18 +62,19 @@ void prepareHostname(char* hostname)
|
||||
hostname[pos] = '-';
|
||||
pos++;
|
||||
}
|
||||
// else do nothing - no leading hyphens and do not include hyphens for all other characters.
|
||||
pC++;
|
||||
}
|
||||
// if the hostname is left blank, use the mac address/default mdns name
|
||||
if (pos < 6) {
|
||||
sprintf(hostname + 5, "%*s", 6, escapedMac.c_str() + 6);
|
||||
} else { //last character must not be hyphen
|
||||
while (pos > 0 && hostname[pos -1] == '-') {
|
||||
hostname[pos -1] = 0;
|
||||
pos--;
|
||||
}
|
||||
// else do nothing - no leading hyphens and do not include hyphens for all other characters.
|
||||
pC++;
|
||||
}
|
||||
// if the hostname is left blank, use the mac address/default mdns name
|
||||
if (pos < 6) {
|
||||
sprintf(hostname + 5, "%*s", 6, escapedMac.c_str() + 6);
|
||||
} else { //last character must not be hyphen
|
||||
hostname[pos] = '\0'; // terminate string
|
||||
while (pos > 0 && hostname[pos -1] == '-') {
|
||||
hostname[pos -1] = '\0';
|
||||
pos--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//handle Ethernet connection event
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
/*
|
||||
Main sketch, global variable declarations
|
||||
@title WLED project sketch
|
||||
@version 0.13.0-b7
|
||||
@version 0.13.0
|
||||
@author Christian Schwinne
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2202222
|
||||
#define VERSION 2203142
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
@@ -26,7 +26,6 @@
|
||||
// You can choose some of these features to disable:
|
||||
//#define WLED_DISABLE_ALEXA // saves 11kb
|
||||
//#define WLED_DISABLE_BLYNK // saves 6kb
|
||||
//#define WLED_DISABLE_CRONIXIE // saves 3kb
|
||||
//#define WLED_DISABLE_HUESYNC // saves 4kb
|
||||
//#define WLED_DISABLE_INFRARED // there is no pin left for this on ESP8266-01, saves 12kb
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
@@ -294,7 +293,11 @@ WLED_GLOBAL uint16_t transitionDelay _INIT(750); // default crossfade duratio
|
||||
WLED_GLOBAL byte briMultiplier _INIT(100); // % of brightness to set (to limit power, if you set it to 50 and set bri to 255, actual brightness will be 127)
|
||||
|
||||
// User Interface CONFIG
|
||||
WLED_GLOBAL char serverDescription[33] _INIT("WLED"); // Name of module
|
||||
#ifndef SERVERNAME
|
||||
WLED_GLOBAL char serverDescription[33] _INIT("WLED"); // Name of module - use default
|
||||
#else
|
||||
WLED_GLOBAL char serverDescription[33] _INIT(SERVERNAME); // use predefined name
|
||||
#endif
|
||||
WLED_GLOBAL bool syncToggleReceive _INIT(false); // UIs which only have a single button for sync should toggle send+receive if this is true, only send otherwise
|
||||
|
||||
// Sync CONFIG
|
||||
@@ -303,7 +306,12 @@ WLED_GLOBAL bool nodeListEnabled _INIT(true);
|
||||
WLED_GLOBAL bool nodeBroadcastEnabled _INIT(true);
|
||||
|
||||
WLED_GLOBAL byte buttonType[WLED_MAX_BUTTONS] _INIT({BTN_TYPE_PUSH});
|
||||
WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver
|
||||
#if defined(IRTYPE) && defined(IRPIN)
|
||||
WLED_GLOBAL byte irEnabled _INIT(IRTYPE); // Infrared receiver
|
||||
#else
|
||||
WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver disabled
|
||||
#endif
|
||||
WLED_GLOBAL bool irApplyToAllSelected _INIT(true); //apply IR to all selected segments
|
||||
|
||||
WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port
|
||||
WLED_GLOBAL uint16_t udpPort2 _INIT(65506); // WLED notifier supplemental port
|
||||
@@ -379,18 +387,13 @@ WLED_GLOBAL bool useAMPM _INIT(false); // 12h/24h clock format
|
||||
WLED_GLOBAL byte currentTimezone _INIT(0); // Timezone ID. Refer to timezones array in wled10_ntp.ino
|
||||
WLED_GLOBAL int utcOffsetSecs _INIT(0); // Seconds to offset from UTC before timzone calculation
|
||||
|
||||
WLED_GLOBAL byte overlayDefault _INIT(0); // 0: no overlay 1: analog clock 2: single-digit clock 3: cronixie
|
||||
WLED_GLOBAL byte overlayCurrent _INIT(0); // 0: no overlay 1: analog clock 2: was single-digit clock 3: was cronixie
|
||||
WLED_GLOBAL byte overlayMin _INIT(0), overlayMax _INIT(DEFAULT_LED_COUNT - 1); // boundaries of overlay mode
|
||||
|
||||
WLED_GLOBAL byte analogClock12pixel _INIT(0); // The pixel in your strip where "midnight" would be
|
||||
WLED_GLOBAL bool analogClockSecondsTrail _INIT(false); // Display seconds as trail of LEDs instead of a single pixel
|
||||
WLED_GLOBAL bool analogClock5MinuteMarks _INIT(false); // Light pixels at every 5-minute position
|
||||
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
WLED_GLOBAL char cronixieDisplay[7] _INIT("HHMMSS"); // Cronixie Display mask. See wled13_cronixie.ino
|
||||
WLED_GLOBAL bool cronixieBacklight _INIT(true); // Allow digits to be back-illuminated
|
||||
#endif
|
||||
|
||||
WLED_GLOBAL bool countdownMode _INIT(false); // Clock will count down towards date
|
||||
WLED_GLOBAL byte countdownYear _INIT(20), countdownMonth _INIT(1); // Countdown target date, year is last two digits
|
||||
WLED_GLOBAL byte countdownDay _INIT(1) , countdownHour _INIT(0);
|
||||
@@ -497,12 +500,6 @@ WLED_GLOBAL bool hueAuthRequired _INIT(false);
|
||||
WLED_GLOBAL bool hueReceived _INIT(false);
|
||||
WLED_GLOBAL bool hueStoreAllowed _INIT(false), hueNewKey _INIT(false);
|
||||
|
||||
// overlays
|
||||
WLED_GLOBAL byte overlayCurrent _INIT(overlayDefault);
|
||||
|
||||
// cronixie
|
||||
WLED_GLOBAL byte dP[] _INIT_N(({ 255, 255, 255, 255, 255, 255 }));
|
||||
|
||||
// countdown
|
||||
WLED_GLOBAL unsigned long countdownTime _INIT(1514764800L);
|
||||
WLED_GLOBAL bool countdownOverTriggered _INIT(true);
|
||||
|
||||
@@ -141,8 +141,7 @@ void loadSettingsFromEEPROM()
|
||||
useAMPM = EEPROM.read(329);
|
||||
strip.gammaCorrectBri = EEPROM.read(330);
|
||||
strip.gammaCorrectCol = EEPROM.read(331);
|
||||
overlayDefault = EEPROM.read(332);
|
||||
if (lastEEPROMversion < 8 && overlayDefault > 0) overlayDefault--; //overlay mode 1 (solid) was removed
|
||||
overlayCurrent = EEPROM.read(332);
|
||||
|
||||
alexaEnabled = EEPROM.read(333);
|
||||
|
||||
@@ -199,11 +198,6 @@ void loadSettingsFromEEPROM()
|
||||
countdownSec = EEPROM.read(2161);
|
||||
setCountdown();
|
||||
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
readStringFromEEPROM(2165, cronixieDisplay, 6);
|
||||
cronixieBacklight = EEPROM.read(2171);
|
||||
#endif
|
||||
|
||||
//macroBoot = EEPROM.read(2175);
|
||||
macroAlexaOn = EEPROM.read(2176);
|
||||
macroAlexaOff = EEPROM.read(2177);
|
||||
@@ -365,8 +359,6 @@ void loadSettingsFromEEPROM()
|
||||
//2551 - 2559 reserved for Usermods, usable by default
|
||||
//2560 - 2943 usable, NOT reserved (need to increase EEPSIZE accordingly, new WLED core features may override this section)
|
||||
//2944 - 3071 reserved for Usermods (need to increase EEPSIZE to 3072 in const.h)
|
||||
|
||||
overlayCurrent = overlayDefault;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -174,7 +174,6 @@ void handleSerial()
|
||||
if (!realtimeOverride) setRealtimePixel(pixel++, red, green, blue, 0);
|
||||
if (--count > 0) state = AdaState::Data_Red;
|
||||
else {
|
||||
if (!realtimeMode && bri == 0) strip.setBrightness(briLast);
|
||||
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_ADALIGHT);
|
||||
|
||||
if (!realtimeOverride) strip.show();
|
||||
|
||||
@@ -382,9 +382,9 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('c',SET_F("MS"),autoSegments);
|
||||
sappend('c',SET_F("CCT"),correctWB);
|
||||
sappend('c',SET_F("CR"),cctFromRgb);
|
||||
sappend('v',SET_F("CB"),strip.cctBlending);
|
||||
sappend('v',SET_F("FR"),strip.getTargetFps());
|
||||
sappend('v',SET_F("AW"),Bus::getAutoWhiteMode());
|
||||
sappend('v',SET_F("CB"),strip.cctBlending);
|
||||
sappend('v',SET_F("FR"),strip.getTargetFps());
|
||||
sappend('v',SET_F("AW"),strip.autoWhiteMode);
|
||||
|
||||
for (uint8_t s=0; s < busses.getNumBusses(); s++) {
|
||||
Bus* bus = busses.getBus(s);
|
||||
@@ -462,6 +462,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('v',SET_F("TT"),touchThreshold);
|
||||
sappend('v',SET_F("IR"),irPin);
|
||||
sappend('v',SET_F("IT"),irEnabled);
|
||||
sappend('c',SET_F("MSO"),!irApplyToAllSelected);
|
||||
}
|
||||
|
||||
if (subPage == 3)
|
||||
@@ -574,16 +575,13 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sprintf_P(tm, PSTR("Sunrise: %02d:%02d Sunset: %02d:%02d"), hour(sunrise), minute(sunrise), hour(sunset), minute(sunset));
|
||||
sappends('m',SET_F("(\"times\")[1]"),tm);
|
||||
}
|
||||
sappend('i',SET_F("OL"),overlayCurrent);
|
||||
sappend('c',SET_F("OL"),overlayCurrent);
|
||||
sappend('v',SET_F("O1"),overlayMin);
|
||||
sappend('v',SET_F("O2"),overlayMax);
|
||||
sappend('v',SET_F("OM"),analogClock12pixel);
|
||||
sappend('c',SET_F("OS"),analogClockSecondsTrail);
|
||||
sappend('c',SET_F("O5"),analogClock5MinuteMarks);
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
sappends('s',SET_F("CX"),cronixieDisplay);
|
||||
sappend('c',SET_F("CB"),cronixieBacklight);
|
||||
#endif
|
||||
|
||||
sappend('c',SET_F("CE"),countdownMode);
|
||||
sappend('v',SET_F("CY"),countdownYear);
|
||||
sappend('v',SET_F("CI"),countdownMonth);
|
||||
|
||||
Reference in New Issue
Block a user