Merge pull request #1807 from Aircoookie/dev

Pull dev branch into master. 0.12 release soon!
This commit is contained in:
Aircoookie 2021-03-19 00:05:02 +01:00 committed by GitHub
commit 30df67721d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 6693 additions and 3310 deletions

1
.gitignore vendored
View File

@ -13,3 +13,4 @@
.gitignore .gitignore
.clang-format .clang-format
node_modules node_modules
.idea

View File

@ -2,6 +2,52 @@
### Development versions after 0.11.1 release ### Development versions after 0.11.1 release
#### Build 2103130
- Added options for Auto Node discovery
- Optimized strings (no string both F() and raw)
#### Build 2103090
- Added Auto Node discovery (PR #1683)
- Added tooltips to quick color selectors for accessibility
#### Build 2103060
- Auto start field population in bus config
#### Build 2103050
- Fixed incorrect over-memory indication in LED settings on ESP32
#### Build 2103041
- Added destructor for BusPwm (fixes #1789)
#### Build 2103040
- Fixed relay mode inverted when upgrading from 0.11.0
- Fixed no more than 2 pins per bus configurable in UI
- Changed to non-linear IR brightness steps (PR #1742)
- Fixed various warnings (PR #1744)
- Added UDP DNRGBW Mode (PR #1704)
- Added dynamic LED mapping with ledmap.json file (PR #1738)
- Added support for QuinLED-ESP32-Ethernet board
- Added support for WESP32 ethernet board (PR #1764)
- Added Caching for main UI (PR #1704)
- Added Tetrix mode (PR #1729)
- Added memory check on Bus creation
#### Build 2102050
- Version bump to 0.12.0-a0 "Hikari"
- Added FPS indication in info
- Bumped max outputs from 7 to 10 busses for ESP32
#### Build 2101310
- First alpha configurable multipin
#### Build 2101130 #### Build 2101130
- Added color transitions for all segments and slots and for segment brightness - Added color transitions for all segments and slots and for segment brightness

View File

@ -1,6 +1,6 @@
{ {
"name": "wled", "name": "wled",
"version": "0.11.1", "version": "0.12.0-a0",
"description": "Tools for WLED project", "description": "Tools for WLED project",
"main": "tools/cdata.js", "main": "tools/cdata.js",
"directories": { "directories": {

View File

@ -12,7 +12,7 @@
default_envs = travis_esp8266, travis_esp32 default_envs = travis_esp8266, travis_esp32
# Release binaries # Release binaries
; default_envs = nodemcuv2, esp01_1m_full, esp32dev, custom_WS2801, custom_APA102, custom_LEDPIN_16, custom_LEDPIN_4, custom_LEDPIN_3, custom32_LEDPIN_16, custom32_APA102 ; default_envs = nodemcuv2, esp01_1m_full, esp32dev
# Single binaries (uncomment your board) # Single binaries (uncomment your board)
; default_envs = nodemcuv2 ; default_envs = nodemcuv2
@ -95,16 +95,6 @@ debug_flags = -D DEBUG=1 -D WLED_DEBUG -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT
# This reduces the OTA size with ~45KB, so it's especially useful on low memory boards (512k/1m). # This reduces the OTA size with ~45KB, so it's especially useful on low memory boards (512k/1m).
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
build_flags = build_flags =
-Wno-switch
-Wno-deprecated-declarations
-Wno-write-strings
-Wno-unused-variable
-Wno-unused-value
-Wno-sign-compare
-Wno-unused-but-set-variable
-Wno-return-type
-Wno-sequence-point
-Wno-narrowing
-DMQTT_MAX_PACKET_SIZE=1024 -DMQTT_MAX_PACKET_SIZE=1024
-DSECURE_CLIENT=SECURE_CLIENT_BEARSSL -DSECURE_CLIENT=SECURE_CLIENT_BEARSSL
-DBEARSSL_SSL_BASIC -DBEARSSL_SSL_BASIC
@ -121,9 +111,6 @@ build_flags =
; -D USERMOD_SENSORSTOMQTT ; -D USERMOD_SENSORSTOMQTT
build_unflags = build_unflags =
-Wall
-Wreorder
-Wdeprecated-declarations
# enables all features for travis CI # enables all features for travis CI
build_flags_all_features = build_flags_all_features =
@ -159,15 +146,15 @@ build_flags =
-DMIMETYPE_MINIMAL -DMIMETYPE_MINIMAL
[esp32] [esp32]
build_flags = -w -g build_flags = -g
-DARDUINO_ARCH_ESP32 -DARDUINO_ARCH_ESP32
-DCONFIG_LITTLEFS_FOR_IDF_3_2 -DCONFIG_LITTLEFS_FOR_IDF_3_2
[scripts_defaults] [scripts_defaults]
extra_scripts = pio/name-firmware.py extra_scripts = pio-scripts/name-firmware.py
pio/gzip-firmware.py pio-scripts/gzip-firmware.py
pio/strip-floats.py pio-scripts/strip-floats.py
pio/user_config_copy.py pio-scripts/user_config_copy.py
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# COMMON SETTINGS: # COMMON SETTINGS:
@ -197,7 +184,7 @@ lib_deps =
AsyncTCP @ 1.0.3 AsyncTCP @ 1.0.3
IRremoteESP8266 @ 2.7.3 IRremoteESP8266 @ 2.7.3
https://github.com/lorol/LITTLEFS.git https://github.com/lorol/LITTLEFS.git
https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.0 https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.2
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line #For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
#TFT_eSPI #TFT_eSPI
#For use SSD1306 OLED display uncomment following #For use SSD1306 OLED display uncomment following

View File

@ -398,6 +398,14 @@ const char PAGE_dmxmap[] PROGMEM = R"=====()=====";
method: "plaintext", method: "plaintext",
filter: "html-minify", filter: "html-minify",
}, },
{
file: "liveviewws.htm",
name: "PAGE_liveviewws",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
},
{ {
file: "404.htm", file: "404.htm",
name: "PAGE_404", name: "PAGE_404",

View File

@ -0,0 +1,427 @@
/*
* Usermod for detecting people entering/leaving a staircase and switching the
* staircase on/off.
*
* Edit the Animated_Staircase_config.h file to compile this usermod for your
* specific configuration.
*
* See the accompanying README.md file for more info.
*/
#pragma once
#include "wled.h"
#include "Animated_Staircase_config.h"
#define USERMOD_ID_ANIMATED_STAIRCASE 1011
/* Initial configuration (available in API and stored in flash) */
bool enabled = true; // Enable this usermod
unsigned long segment_delay_ms = 150; // Time between switching each segment
unsigned long on_time_ms = 5 * 1000; // The time for the light to stay on
#ifndef TOP_PIR_PIN
unsigned int topMaxTimeUs = 1749; // default echo timout, top
#endif
#ifndef BOTTOM_PIR_PIN
unsigned int bottomMaxTimeUs = 1749; // default echo timout, bottom
#endif
// Time between checking of the sensors
const int scanDelay = 50;
class Animated_Staircase : public Usermod {
private:
// Lights on or off.
// Flipping this will start a transition.
bool on = false;
// Swipe direction for current transition
#define SWIPE_UP true
#define SWIPE_DOWN false
bool swipe = SWIPE_UP;
// Indicates which Sensor was seen last (to determine
// the direction when swiping off)
#define LOWER false
#define UPPER true
bool lastSensor = LOWER;
// Time of the last transition action
unsigned long lastTime = 0;
// Time of the last sensor check
unsigned long lastScanTime = 0;
// Last time the lights were switched on or off
unsigned long lastSwitchTime = 0;
// segment id between onIndex and offIndex are on.
// controll the swipe by setting/moving these indices around.
// onIndex must be less than or equal to offIndex
byte onIndex = 0;
byte offIndex = 0;
// The maximum number of configured segments.
// Dynamically updated based on user configuration.
byte maxSegmentId = 1;
byte mainSegmentId = 0;
bool saveState = false;
// These values are used by the API to read the
// last sensor state, or trigger a sensor
// through the API
bool topSensorRead = false;
bool topSensorWrite = false;
bool bottomSensorRead = false;
bool bottomSensorWrite = false;
void updateSegments() {
mainSegmentId = strip.getMainSegmentId();
WS2812FX::Segment mainsegment = strip.getSegment(mainSegmentId);
WS2812FX::Segment* segments = strip.getSegments();
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
if (!segments->isActive()) {
maxSegmentId = i - 1;
break;
}
if (i >= onIndex && i < offIndex) {
segments->setOption(SEG_OPTION_ON, 1, 1);
// We may need to copy mode and colors from segment 0 to make sure
// changes are propagated even when the config is changed during a wipe
// segments->mode = mainsegment.mode;
// segments->colors[0] = mainsegment.colors[0];
} else {
segments->setOption(SEG_OPTION_ON, 0, 1);
}
// Always mark segments as "transitional", we are animating the staircase
segments->setOption(SEG_OPTION_TRANSITIONAL, 1, 1);
}
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
}
/*
* Detects if an object is within ultrasound range.
* signalPin: The pin where the pulse is sent
* echoPin: The pin where the echo is received
* maxTimeUs: Detection timeout in microseconds. If an echo is
* received within this time, an object is detected
* and the function will return true.
*
* The speed of sound is 343 meters per second at 20 degress Celcius.
* Since the sound has to travel back and forth, the detection
* distance for the sensor in cm is (0.0343 * maxTimeUs) / 2.
*
* For practical reasons, here are some useful distances:
*
* Distance = maxtime
* 5 cm = 292 uS
* 10 cm = 583 uS
* 20 cm = 1166 uS
* 30 cm = 1749 uS
* 50 cm = 2915 uS
* 100 cm = 5831 uS
*/
bool ultrasoundRead(uint8_t signalPin,
uint8_t echoPin,
unsigned int maxTimeUs) {
digitalWrite(signalPin, HIGH);
delayMicroseconds(10);
digitalWrite(signalPin, LOW);
return pulseIn(echoPin, HIGH, maxTimeUs) > 0;
}
void checkSensors() {
if ((millis() - lastScanTime) > scanDelay) {
lastScanTime = millis();
#ifdef BOTTOM_PIR_PIN
bottomSensorRead = bottomSensorWrite || (digitalRead(BOTTOM_PIR_PIN) == HIGH);
#else
bottomSensorRead = bottomSensorWrite || ultrasoundRead(BOTTOM_TRIGGER_PIN, BOTTOM_ECHO_PIN, bottomMaxTimeUs);
#endif
#ifdef TOP_PIR_PIN
topSensorRead = topSensorWrite || (digitalRead(TOP_PIR_PIN) == HIGH);
#else
topSensorRead = topSensorWrite || ultrasoundRead(TOP_TRIGGER_PIN, TOP_ECHO_PIN, topMaxTimeUs);
#endif
// Values read, reset the flags for next API call
topSensorWrite = false;
bottomSensorWrite = false;
if (topSensorRead != bottomSensorRead) {
lastSwitchTime = millis();
if (on) {
lastSensor = topSensorRead;
} else {
// If the bottom sensor triggered, we need to swipe up, ON
swipe = bottomSensorRead;
if (swipe) {
Serial.println("ON -> Swipe up.");
} else {
Serial.println("ON -> Swipe down.");
}
if (onIndex == offIndex) {
// Position the indices for a correct on-swipe
if (swipe == SWIPE_UP) {
onIndex = mainSegmentId;
} else {
onIndex = maxSegmentId+1;
}
offIndex = onIndex;
}
on = true;
}
}
}
}
void autoPowerOff() {
if (on && ((millis() - lastSwitchTime) > on_time_ms)) {
// Swipe OFF in the direction of the last sensor detection
swipe = lastSensor;
on = false;
if (swipe) {
Serial.println("OFF -> Swipe up.");
} else {
Serial.println("OFF -> Swipe down.");
}
}
}
void updateSwipe() {
if ((millis() - lastTime) > segment_delay_ms) {
lastTime = millis();
byte oldOnIndex = onIndex;
byte oldOffIndex = offIndex;
if (on) {
// Turn on all segments
onIndex = MAX(mainSegmentId, onIndex - 1);
offIndex = MIN(maxSegmentId + 1, offIndex + 1);
} else {
if (swipe == SWIPE_UP) {
onIndex = MIN(offIndex, onIndex + 1);
} else {
offIndex = MAX(onIndex, offIndex - 1);
}
}
updateSegments();
}
}
void writeSettingsToJson(JsonObject& root) {
JsonObject staircase = root["staircase"];
if (staircase.isNull()) {
staircase = root.createNestedObject("staircase");
}
staircase["enabled"] = enabled;
staircase["segment-delay-ms"] = segment_delay_ms;
staircase["on-time-s"] = on_time_ms / 1000;
#ifdef TOP_TRIGGER_PIN
staircase["top-echo-us"] = topMaxTimeUs;
#endif
#ifdef BOTTOM_TRIGGER_PIN
staircase["bottom-echo-us"] = bottomMaxTimeUs;
#endif
}
void writeSensorsToJson(JsonObject& root) {
JsonObject staircase = root["staircase"];
if (staircase.isNull()) {
staircase = root.createNestedObject("staircase");
}
staircase["top-sensor"] = topSensorRead;
staircase["bottom-sensor"] = bottomSensorRead;
}
bool readSettingsFromJson(JsonObject& root) {
JsonObject staircase = root["staircase"];
bool changed = false;
bool shouldEnable = staircase["enabled"] | enabled;
if (shouldEnable != enabled) {
enable(shouldEnable);
changed = true;
}
unsigned long c_segment_delay_ms = staircase["segment-delay-ms"] | segment_delay_ms;
if (c_segment_delay_ms != segment_delay_ms) {
segment_delay_ms = c_segment_delay_ms;
changed = true;
}
unsigned long c_on_time_ms = (staircase["on-time-s"] | (on_time_ms / 1000)) * 1000;
if (c_on_time_ms != on_time_ms) {
on_time_ms = c_on_time_ms;
changed = true;
}
#ifdef TOP_TRIGGER_PIN
unsigned int c_topMaxTimeUs = staircase["top-echo-us"] | topMaxTimeUs;
if (c_topMaxTimeUs != topMaxTimeUs) {
topMaxTimeUs = c_topMaxTimeUs;
changed = true;
}
#endif
#ifdef BOTTOM_TRIGGER_PIN
unsigned int c_bottomMaxTimeUs = staircase["bottom-echo-us"] | bottomMaxTimeUs;
if (c_bottomMaxTimeUs != bottomMaxTimeUs) {
bottomMaxTimeUs = c_bottomMaxTimeUs;
changed = true;
}
#endif
return changed;
}
void readSensorsFromJson(JsonObject& root) {
JsonObject staircase = root["staircase"];
bottomSensorWrite = bottomSensorRead || (staircase["bottom-sensor"].as<bool>());
topSensorWrite = topSensorRead || (staircase["top-sensor"].as<bool>());
}
void enable(bool enable) {
if (enable) {
Serial.println("Animated Staircase enabled.");
Serial.print("Delay between steps: ");
Serial.print(segment_delay_ms, DEC);
Serial.print(" milliseconds.\nStairs switch off after: ");
Serial.print(on_time_ms / 1000, DEC);
Serial.println(" seconds.");
#ifdef BOTTOM_PIR_PIN
pinMode(BOTTOM_PIR_PIN, INPUT);
#else
pinMode(BOTTOM_TRIGGER_PIN, OUTPUT);
pinMode(BOTTOM_ECHO_PIN, INPUT);
#endif
#ifdef TOP_PIR_PIN
pinMode(TOP_PIR_PIN, INPUT);
#else
pinMode(TOP_TRIGGER_PIN, OUTPUT);
pinMode(TOP_ECHO_PIN, INPUT);
#endif
} else {
// Restore segment options
WS2812FX::Segment mainsegment = strip.getSegment(mainSegmentId);
WS2812FX::Segment* segments = strip.getSegments();
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
if (!segments->isActive()) {
maxSegmentId = i - 1;
break;
}
segments->setOption(SEG_OPTION_ON, 1, 1);
}
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
Serial.println("Animated Staircase disabled.");
}
enabled = enable;
}
public:
void setup() { enable(enabled); }
void loop() {
// Write changed settings from to flash (see readFromJsonState())
if (saveState) {
serializeConfig();
saveState = false;
}
if (!enabled) {
return;
}
checkSensors();
autoPowerOff();
updateSwipe();
}
uint16_t getId() { return USERMOD_ID_ANIMATED_STAIRCASE; }
/*
* Shows configuration settings to the json API. This object looks like:
*
* "staircase" : {
* "enabled" : true
* "segment-delay-ms" : 150,
* "on-time-s" : 5
* }
*
*/
void addToJsonState(JsonObject& root) {
writeSettingsToJson(root);
writeSensorsToJson(root);
Serial.println("Staircase config exposed in API.");
}
/*
* Reads configuration settings from the json API.
* See void addToJsonState(JsonObject& root)
*/
void readFromJsonState(JsonObject& root) {
// The call to serializeConfig() must be done in the main loop,
// so we set a flag to signal the main loop to save state.
saveState = readSettingsFromJson(root);
readSensorsFromJson(root);
Serial.println("Staircase config read from API.");
}
/*
* Writes the configuration to internal flash memory.
*/
void addToConfig(JsonObject& root) {
writeSettingsToJson(root);
Serial.println("Staircase config saved.");
}
/*
* Reads the configuration to internal flash memory before setup() is called.
*/
void readFromConfig(JsonObject& root) {
readSettingsFromJson(root);
Serial.println("Staircase config loaded.");
}
/*
* Shows the delay between steps and power-off time in the "info"
* tab of the web-UI.
*/
void addToJsonInfo(JsonObject& root) {
JsonObject staircase = root["u"];
if (staircase.isNull()) {
staircase = root.createNestedObject("u");
}
if (enabled) {
JsonArray usermodEnabled =
staircase.createNestedArray("Staircase enabled"); // name
usermodEnabled.add("yes"); // value
JsonArray segmentDelay =
staircase.createNestedArray("Delay between stairs"); // name
segmentDelay.add(segment_delay_ms); // value
segmentDelay.add(" milliseconds"); // unit
JsonArray onTime =
staircase.createNestedArray("Power-off stairs after"); // name
onTime.add(on_time_ms / 1000); // value
onTime.add(" seconds"); // unit
} else {
JsonArray usermodEnabled =
staircase.createNestedArray("Staircase enabled"); // name
usermodEnabled.add("no"); // value
}
}
};

View File

@ -0,0 +1,21 @@
/*
* Animated_Staircase compiletime confguration.
*
* Please see README.md on how to change this file.
*/
// Please change the pin numbering below to match your board.
#define TOP_PIR_PIN D5
#define BOTTOM_PIR_PIN D6
// Or uncumment and a pir and use an ultrasound HC-SR04 sensor,
// see README.md for details
#ifndef TOP_PIR_PIN
#define TOP_TRIGGER_PIN D2
#define TOP_ECHO_PIN D3
#endif
#ifndef BOTTOM_PIR_PIN
#define BOTTOM_TRIGGER_PIN D4
#define BOTTOM_ECHO_PIN D5
#endif

View File

@ -0,0 +1,203 @@
# Usermod Animated Staircase
This usermod makes your staircase look cool by switching it on with an animation. It uses
PIR or ultrasonic sensors at the top and bottom of your stairs to:
- Light up the steps in your walking direction, leading the way.
- Switch off the steps after you, in the direction of the last detected movement.
- Always switch on when one of the sensors detects movement, even if an effect
is still running. It can therewith handle multiple people on the stairs gracefully.
The Animated Staircase can be controlled by the WLED API. Change settings such as
speed, on/off time and distance settings by sending an HTTP request, see below.
## WLED integration
To include this usermod in your WLED setup, you have to be able to [compile WLED from source](https://github.com/Aircoookie/WLED/wiki/Compiling-WLED).
Before compiling, you have to make the following modifications:
Edit `usermods_list.cpp`:
1. Open `wled00/usermods_list.cpp`
2. add `#include "../usermods/Animated_Staircase/Animated_Staircase.h"` to the top of the file
3. add `usermods.add(new Animated_Staircase());` to the end of the `void registerUsermods()` function.
Edit `Animated_Staircase_config.h`:
1. Open `usermods/Animated_Staircase/Animated_Staircase_config.h`
2. To use PIR sensors, change these lines to match your setup:
Using D7 and D6 pin notation as used on several boards:
```cpp
#define TOP_PIR_PIN D7
#define BOTTOM_PIR_PIN D6
```
Or using GPIO numbering for pins 25 and 26:
```cpp
#define TOP_PIR_PIN 26
#define BOTTOM_PIR_PIN 25
```
To use Ultrasonic HC-SR04 sensors instead of (one of the) PIR sensors,
uncomment one of the PIR sensor lines and adjust the pin numbers for the
connected Ultrasonic sensor. In the example below we use an Ultrasonic
sensor at the bottom of the stairs:
```cpp
#define TOP_PIR_PIN 32
//#define BOTTOM_PIR_PIN D6 /* This PIR sensor is disabled */
#ifndef TOP_PIR_PIN
#define TOP_SIGNAL_PIN D2
#define TOP_ECHO_PIN D3
#endif
#ifndef BOTTOM_PIR_PIN /* If the bottom PIR is disabled, */
#define BOTTOM_SIGNAL_PIN 25 /* This Ultrasonic sensor is used */
#define BOTTOM_ECHO_PIN 26
#endif
```
After these modifications, compile and upload your WLED binary to your board
and check the WLED info page to see if this usermod is enabled.
## Hardware installation
1. Stick the LED strip under each step of the stairs.
2. Connect the ESP8266 pin D4 or ESP32 pin D2 to the first LED data pin at the bottom step
of your stairs.
3. Connect the data-out pin at the end of each strip per step to the data-in pin on the
other end of the next step, creating one large virtual LED strip.
4. Mount sensors of choice at the bottom and top of the stairs and connect them to the ESP.
5. To make sure all LEDs get enough power and have your staircase lighted evenly, power each
step from one side, using at least AWG14 or 2.5mm^2 cable. Don't connect them serial as you
do for the datacable!
You _may_ need to use 10k pull-down resistors on the selected PIR pins, depending on the sensor.
## WLED configuration
1. In the WLED UI, confgure a segment for each step. The lowest step of the stairs is the
lowest segment id.
2. Save your segments into a preset.
3. Ideally, add the preset in the config > LED setup menu to the "apply
preset **n** at boot" setting.
## Changing behavior through API
The Staircase settings can be changed through the WLED JSON api.
**NOTE:** We are using [curl](https://curl.se/) to send HTTP POSTs to the WLED API.
If you're using Windows and want to use the curl commands, replace the `\` with a `^`
or remove them and put everything on one line.
| Setting | Description | Default |
|------------------|---------------------------------------------------------------|---------|
| enabled | Enable or disable the usermod | true |
| segment-delay-ms | Delay (milliseconds) between switching on/off each step | 150 |
| on-time-s | Time (seconds) the stairs stay lit after last detection | 5 |
| bottom-echo-us | Detection range of ultrasonic sensor | 1749 |
| bottomsensor | Manually trigger a down to up animation via API | false |
| topsensor | Manually trigger an up to down animation via API | false |
To read the current settings, open a browser to `http://xxx.xxx.xxx.xxx/json/state` (use your WLED
device IP address). The device will respond with a json object containing all WLED settings.
The staircase settings and sensor states are inside the WLED status element:
```json
{
"state": {
"staircase": {
"enabled": true,
"segment-delay-ms": 150,
"on-time-s": 5,
"bottomsensor": false,
"topsensor": false
},
}
```
### Enable/disable the usermod
By disabling the usermod you will be able to keep the LED's on, independent from the sensor
activity. This enables to play with the lights without the usermod switching them on or off.
To disable the usermod:
```bash
curl -X POST -H "Content-Type: application/json" \
-d {"staircase":{"enabled":false}} \
xxx.xxx.xxx.xxx/json/state
```
To enable the usermod again, use `"enabled":true`.
### Changing animation parameters
To change the delay between the steps to (for example) 100 milliseconds and the on-time to
10 seconds:
```bash
curl -X POST -H "Content-Type: application/json" \
-d '{"staircase":{"segment-delay-ms":100,"on-time-s":10}}' \
xxx.xxx.xxx.xxx/json/state
```
### Changing detection range of the ultrasonic HC-SR04 sensor
When an ultrasonic sensor is enabled in `Animated_Staircase_config.h`, you'll see a
`bottom-echo-us` setting appear in the json api:
```json
{
"state": {
"staircase": {
"enabled": true,
"segment-delay-ms": 150,
"on-time-s": 5,
"bottom-echo-us": 1749
},
}
```
If the HC-SR04 sensor detects an echo within 1749 microseconds (corresponding to ~30 cm
detection range from the sensor), it will trigger switching on the staircase. This setting
can be changed through the API with an HTTP POST:
```bash
curl -X POST -H "Content-Type: application/json" \
-d '{"staircase":{"bottom-echo-us":1166}}' \
xxx.xxx.xxx.xxx/json/state
```
Calculating the detection range can be performed as follows: The speed of sound is 343m/s at 20
degrees Centigrade. Since the sound has to travel back and forth, the detection range for the
sensor in cm is (0.0343 * maxTimeUs) / 2. To get you started, please find delays and distances below:
| Distance | Detection time |
|---------:|----------------:|
| 5 cm | 292 uS |
| 10 cm | 583 uS |
| 20 cm | 1166 uS |
| 30 cm | 1749 uS |
| 50 cm | 2915 uS |
| 100 cm | 5831 uS |
**Please note:** that using an HC-SR04 sensor, particularly when detecting echos at longer
distances creates delays in the WLED software, and _might_ introduce timing hickups in your animations or
a less responsive web interface. It is therefore advised to keep the detection time as short as possible.
### Animation triggering through the API
Instead of stairs activation by one of the sensors, you can also trigger the animation through
the API. To simulate triggering the bottom sensor, use:
```bash
curl -X POST -H "Content-Type: application/json" \
-d '{"staircase":{"bottomsensor":true}}' \
xxx.xxx.xxx.xxx/json/state
```
Likewise, to trigger the top sensor, use:
```bash
curl -X POST -H "Content-Type: application/json" \
-d '{"staircase":{"topsensor":true}}' \
xxx.xxx.xxx.xxx/json/state
```
Have fun with this usermod.<br/>
www.rolfje.com

View File

@ -0,0 +1,40 @@
Hello! I have written a v2 usermod for the BME280/BMP280 sensor based on the [existing v1 usermod](https://github.com/Aircoookie/WLED/blob/master/usermods/Wemos_D1_mini%2BWemos32_mini_shield/usermod_bme280.cpp). It is not just a refactor, there are many changes which I made to fit my use case, and I hope they will fit the use cases of others as well! Most notably, this usermod is *just* for the BME280 and does not control a display like in the v1 usermod designed for the WeMos shield.
- Requires libraries `BME280@~3.0.0` (by [finitespace](https://github.com/finitespace/BME280)) and `Wire`. Please add these under `lib_deps` in your `platform.ini` (or `platform_override.ini`).
- Data is published over MQTT so make sure you've enabled the MQTT sync interface.
- This usermod also writes to serial (GPIO1 on ESP8266). Please make sure nothing else listening on the serial TX pin of your board will get confused by log messages!
To enable, compile with `USERMOD_BME280` defined (i.e. `platformio_override.ini`)
```ini
build_flags =
${common.build_flags_esp8266}
-D USERMOD_BME280
```
or define `USERMOD_BME280` in `my_config.h`
```c++
#define USERMOD_BME280
```
Changes include:
- Adjustable measure intervals
- Temperature and pressure have separate intervals due to pressure not frequently changing at any constant altitude
- Adjustment of number of decimal places in published sensor values
- Separate adjustment for temperature, humidity and pressure values
- Values are rounded to the specified number of decimal places
- Pressure measured in units of hPa instead of Pa
- Calculation of heat index (apparent temperature) and dew point
- These, along with humidity measurements, are disabled if the sensor is a BMP280
- 16x oversampling of sensor during measurement
- Values are only published if they are different from the previous value
- Values are published on startup (continually until the MQTT broker acknowledges a successful publication)
Adjustments are made through preprocessor definitions at the start of the class definition.
MQTT topics are as follows:
Measurement type | MQTT topic
--- | ---
Temperature | `<deviceTopic>/temperature`
Humidity | `<deviceTopic>/humidity`
Pressure | `<deviceTopic>/pressure`
Heat index | `<deviceTopic>/heat_index`
Dew point | `<deviceTopic>/dew_point`

View File

@ -0,0 +1,212 @@
#pragma once
#include "wled.h"
#include <Arduino.h>
#include <Wire.h>
#include <BME280I2C.h> // BME280 sensor
#include <EnvironmentCalculations.h> // BME280 extended measurements
class UsermodBME280 : public Usermod
{
private:
// User-defined configuration
#define Celsius // Show temperature mesaurement in Celcius. Comment out for Fahrenheit
#define TemperatureDecimals 1 // Number of decimal places in published temperaure values
#define HumidityDecimals 0 // Number of decimal places in published humidity values
#define PressureDecimals 2 // Number of decimal places in published pressure values
#define TemperatureInterval 5 // Interval to measure temperature (and humidity, dew point if available) in seconds
#define PressureInterval 300 // Interval to measure pressure in seconds
// Sanity checks
#if !defined(TemperatureDecimals) || TemperatureDecimals < 0
#define TemperatureDecimals 0
#endif
#if !defined(HumidityDecimals) || HumidityDecimals < 0
#define HumidityDecimals 0
#endif
#if !defined(PressureDecimals) || PressureDecimals < 0
#define PressureDecimals 0
#endif
#if !defined(TemperatureInterval) || TemperatureInterval < 0
#define TemperatureInterval 1
#endif
#if !defined(PressureInterval) || PressureInterval < 0
#define PressureInterval TemperatureInterval
#endif
#ifdef ARDUINO_ARCH_ESP32 // ESP32 boards
uint8_t SCL_PIN = 22;
uint8_t SDA_PIN = 21;
#else // ESP8266 boards
uint8_t SCL_PIN = 5;
uint8_t SDA_PIN = 4;
//uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
#endif
// BME280 sensor settings
BME280I2C::Settings settings{
BME280::OSR_X16, // Temperature oversampling x16
BME280::OSR_X16, // Humidity oversampling x16
BME280::OSR_X16, // Pressure oversampling x16
// Defaults
BME280::Mode_Forced,
BME280::StandbyTime_1000ms,
BME280::Filter_Off,
BME280::SpiEnable_False,
BME280I2C::I2CAddr_0x76 // I2C address. I2C specific. Default 0x76
};
BME280I2C bme{settings};
uint8_t SensorType;
// Measurement timers
long timer;
long lastTemperatureMeasure = 0;
long lastPressureMeasure = 0;
// Current sensor values
float SensorTemperature;
float SensorHumidity;
float SensorHeatIndex;
float SensorDewPoint;
float SensorPressure;
// Track previous sensor values
float lastTemperature;
float lastHumidity;
float lastHeatIndex;
float lastDewPoint;
float lastPressure;
// Store packet IDs of MQTT publications
uint16_t mqttTemperaturePub = 0;
uint16_t mqttPressurePub = 0;
void UpdateBME280Data(int SensorType)
{
float _temperature, _humidity, _pressure;
#ifdef Celsius
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Celsius);
#else
BME280::TempUnit tempUnit(BME280::TempUnit_Fahrenheit);
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Fahrenheit);
#endif
BME280::PresUnit presUnit(BME280::PresUnit_hPa);
bme.read(_pressure, _temperature, _humidity, tempUnit, presUnit);
SensorTemperature = _temperature;
SensorHumidity = _humidity;
SensorPressure = _pressure;
if (SensorType == 1)
{
SensorHeatIndex = EnvironmentCalculations::HeatIndex(_temperature, _humidity, envTempUnit);
SensorDewPoint = EnvironmentCalculations::DewPoint(_temperature, _humidity, envTempUnit);
}
}
public:
void setup()
{
Wire.begin(SDA_PIN, SCL_PIN);
if (!bme.begin())
{
SensorType = 0;
Serial.println("Could not find BME280I2C sensor!");
}
else
{
switch (bme.chipModel())
{
case BME280::ChipModel_BME280:
SensorType = 1;
Serial.println("Found BME280 sensor! Success.");
break;
case BME280::ChipModel_BMP280:
SensorType = 2;
Serial.println("Found BMP280 sensor! No Humidity available.");
break;
default:
SensorType = 0;
Serial.println("Found UNKNOWN sensor! Error!");
}
}
}
void loop()
{
// BME280 sensor MQTT publishing
// Check if sensor present and MQTT Connected, otherwise it will crash the MCU
if (SensorType != 0 && mqtt != nullptr)
{
// Timer to fetch new temperature, humidity and pressure data at intervals
timer = millis();
if (timer - lastTemperatureMeasure >= TemperatureInterval * 1000 || mqttTemperaturePub == 0)
{
lastTemperatureMeasure = timer;
UpdateBME280Data(SensorType);
float Temperature = roundf(SensorTemperature * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
float Humidity, HeatIndex, DewPoint;
// If temperature has changed since last measure, create string populated with device topic
// from the UI and values read from sensor, then publish to broker
if (Temperature != lastTemperature)
{
String topic = String(mqttDeviceTopic) + "/temperature";
mqttTemperaturePub = mqtt->publish(topic.c_str(), 0, false, String(Temperature, TemperatureDecimals).c_str());
}
lastTemperature = Temperature; // Update last sensor temperature for next loop
if (SensorType == 1) // Only if sensor is a BME280
{
Humidity = roundf(SensorHumidity * pow(10, HumidityDecimals)) / pow(10, HumidityDecimals);
HeatIndex = roundf(SensorHeatIndex * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
DewPoint = roundf(SensorDewPoint * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
if (Humidity != lastHumidity)
{
String topic = String(mqttDeviceTopic) + "/humidity";
mqtt->publish(topic.c_str(), 0, false, String(Humidity, HumidityDecimals).c_str());
}
if (HeatIndex != lastHeatIndex)
{
String topic = String(mqttDeviceTopic) + "/heat_index";
mqtt->publish(topic.c_str(), 0, false, String(HeatIndex, TemperatureDecimals).c_str());
}
if (DewPoint != lastDewPoint)
{
String topic = String(mqttDeviceTopic) + "/dew_point";
mqtt->publish(topic.c_str(), 0, false, String(DewPoint, TemperatureDecimals).c_str());
}
lastHumidity = Humidity;
lastHeatIndex = HeatIndex;
lastDewPoint = DewPoint;
}
}
if (timer - lastPressureMeasure >= PressureInterval * 1000 || mqttPressurePub == 0)
{
lastPressureMeasure = timer;
float Pressure = roundf(SensorPressure * pow(10, PressureDecimals)) / pow(10, PressureDecimals);
if (Pressure != lastPressure)
{
String topic = String(mqttDeviceTopic) + "/pressure";
mqttPressurePub = mqtt->publish(topic.c_str(), 0, true, String(Pressure, PressureDecimals).c_str());
}
lastPressure = Pressure;
}
}
}
};

View File

@ -5,11 +5,13 @@
#include <DallasTemperature.h> //DS18B20 #include <DallasTemperature.h> //DS18B20
//Pin defaults for QuinLed Dig-Uno //Pin defaults for QuinLed Dig-Uno
#ifndef TEMPERATURE_PIN
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
#define TEMPERATURE_PIN 18 #define TEMPERATURE_PIN 18
#else //ESP8266 boards #else //ESP8266 boards
#define TEMPERATURE_PIN 14 #define TEMPERATURE_PIN 14
#endif #endif
#endif
// the frequency to check temperature, 1 minute // the frequency to check temperature, 1 minute
#ifndef USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL #ifndef USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL
@ -58,6 +60,7 @@ class UsermodTemperature : public Usermod {
} }
void getTemperature() { void getTemperature() {
if (strip.isUpdating()) return;
#ifdef USERMOD_DALLASTEMPERATURE_CELSIUS #ifdef USERMOD_DALLASTEMPERATURE_CELSIUS
temperature = sensor.getTempC(sensorDeviceAddress); temperature = sensor.getTempC(sensorDeviceAddress);
#else #else
@ -80,30 +83,28 @@ class UsermodTemperature : public Usermod {
disabled = !sensor.getAddress(sensorDeviceAddress, 0); disabled = !sensor.getAddress(sensorDeviceAddress, 0);
if (!disabled) { if (!disabled) {
DEBUG_PRINTLN("Dallas Temperature found"); DEBUG_PRINTLN(F("Dallas Temperature found"));
// set the resolution for this specific device // set the resolution for this specific device
sensor.setResolution(sensorDeviceAddress, 9, true); sensor.setResolution(sensorDeviceAddress, 9, true);
// do not block waiting for reading // do not block waiting for reading
sensor.setWaitForConversion(false); sensor.setWaitForConversion(false);
// allocate pin & prevent other use
if (!pinManager.allocatePin(TEMPERATURE_PIN,false))
disabled = true;
} else { } else {
DEBUG_PRINTLN("Dallas Temperature not found"); DEBUG_PRINTLN(F("Dallas Temperature not found"));
} }
} }
void loop() { void loop() {
if (disabled) { if (disabled || strip.isUpdating()) return;
return;
}
unsigned long now = millis(); unsigned long now = millis();
// check to see if we are due for taking a measurement // check to see if we are due for taking a measurement
// lastMeasurement will not be updated until the conversion // lastMeasurement will not be updated until the conversion
// is complete the the reading is finished // is complete the the reading is finished
if (now - lastMeasurement < USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL) if (now - lastMeasurement < USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL) return;
{
return;
}
// we are due for a measurement, if we are not already waiting // we are due for a measurement, if we are not already waiting
// for a conversion to complete, then make a new request for temps // for a conversion to complete, then make a new request for temps
@ -125,7 +126,7 @@ class UsermodTemperature : public Usermod {
// dont publish super low temperature as the graph will get messed up // dont publish super low temperature as the graph will get messed up
// the DallasTemperature library returns -127C or -196.6F when problem // the DallasTemperature library returns -127C or -196.6F when problem
// reading the sensor // reading the sensor
strcat(subuf, "/temperature"); strcat_P(subuf, PSTR("/temperature"));
mqtt->publish(subuf, 0, true, String(temperature).c_str()); mqtt->publish(subuf, 0, true, String(temperature).c_str());
} else { } else {
// publish something else to indicate status? // publish something else to indicate status?
@ -136,34 +137,32 @@ class UsermodTemperature : public Usermod {
void addToJsonInfo(JsonObject& root) { void addToJsonInfo(JsonObject& root) {
// dont add temperature to info if we are disabled // dont add temperature to info if we are disabled
if (disabled) { if (disabled) return;
return;
}
JsonObject user = root["u"]; JsonObject user = root[F("u")];
if (user.isNull()) user = root.createNestedObject("u"); if (user.isNull()) user = root.createNestedObject(F("u"));
JsonArray temp = user.createNestedArray("Temperature"); JsonArray temp = user.createNestedArray(F("Temperature"));
if (!getTemperatureComplete) { if (!getTemperatureComplete) {
// if we haven't read the sensor yet, let the user know // if we haven't read the sensor yet, let the user know
// that we are still waiting for the first measurement // that we are still waiting for the first measurement
temp.add((USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT - millis()) / 1000); temp.add((USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT - millis()) / 1000);
temp.add(" sec until read"); temp.add(F(" sec until read"));
return; return;
} }
if (temperature <= -100) { if (temperature <= -100) {
temp.add(0); temp.add(0);
temp.add(" Sensor Error!"); temp.add(F(" Sensor Error!"));
return; return;
} }
temp.add(temperature); temp.add(temperature);
#ifdef USERMOD_DALLASTEMPERATURE_CELSIUS #ifdef USERMOD_DALLASTEMPERATURE_CELSIUS
temp.add("°C"); temp.add(F("°C"));
#else #else
temp.add("°F"); temp.add(F("°F"));
#endif #endif
} }

View File

@ -545,7 +545,7 @@ uint16_t WS2812FX::dissolve(uint32_t color) {
} }
} }
if (SEGENV.call > (255 - SEGMENT.speed) + 15) if (SEGENV.call > (255 - SEGMENT.speed) + 15U)
{ {
SEGENV.aux0 = !SEGENV.aux0; SEGENV.aux0 = !SEGENV.aux0;
SEGENV.call = 0; SEGENV.call = 0;
@ -1034,7 +1034,7 @@ uint16_t WS2812FX::mode_running_random(void) {
} }
SEGENV.step++; SEGENV.step++;
if (SEGENV.step > ((255-SEGMENT.intensity) >> 4)) if (SEGENV.step > (uint8_t)((255-SEGMENT.intensity) >> 4))
{ {
SEGENV.step = 0; SEGENV.step = 0;
} }
@ -1257,7 +1257,7 @@ uint16_t WS2812FX::police_base(uint32_t color1, uint32_t color2, bool all)
for (uint16_t i = idexB; i < idexR; i++) setPixelColor(i, color2); for (uint16_t i = idexB; i < idexR; i++) setPixelColor(i, color2);
} }
} else { //regular dot-only mode } else { //regular dot-only mode
uint8_t size = 1 + SEGMENT.intensity >> 3; uint8_t size = 1 + (SEGMENT.intensity >> 3);
if (size > SEGLEN/2) size = 1+ SEGLEN/2; if (size > SEGLEN/2) size = 1+ SEGLEN/2;
for (uint8_t i=0; i <= size; i++) { for (uint8_t i=0; i <= size; i++) {
setPixelColor(idexR+i, color1); setPixelColor(idexR+i, color1);
@ -1568,9 +1568,9 @@ uint16_t WS2812FX::mode_oscillate(void)
if (SEGENV.call == 0) if (SEGENV.call == 0)
{ {
oscillators[0] = {SEGLEN/4, SEGLEN/8, 1, 1}; oscillators[0] = {(int16_t)(SEGLEN/4), (int8_t)(SEGLEN/8), 1, 1};
oscillators[1] = {SEGLEN/4*3, SEGLEN/8, 1, 2}; oscillators[1] = {(int16_t)(SEGLEN/4*3), (int8_t)(SEGLEN/8), 1, 2};
oscillators[2] = {SEGLEN/4*2, SEGLEN/8, -1, 1}; oscillators[2] = {(int16_t)(SEGLEN/4*2), (int8_t)(SEGLEN/8), -1, 1};
} }
uint32_t cycleTime = 20 + (2 * (uint32_t)(255 - SEGMENT.speed)); uint32_t cycleTime = 20 + (2 * (uint32_t)(255 - SEGMENT.speed));
@ -1919,7 +1919,6 @@ uint16_t WS2812FX::mode_noise16_2()
for (uint16_t i = 0; i < SEGLEN; i++) { for (uint16_t i = 0; i < SEGLEN; i++) {
uint16_t shift_x = SEGENV.step >> 6; // x as a function of time uint16_t shift_x = SEGENV.step >> 6; // x as a function of time
uint16_t shift_y = SEGENV.step/42;
uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field
@ -3198,8 +3197,8 @@ uint16_t WS2812FX::mode_plasma(void) {
uint8_t thatPhase = beatsin8(7,-64,64); uint8_t thatPhase = beatsin8(7,-64,64);
for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set color & brightness based on a wave as follows: for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set color & brightness based on a wave as follows:
uint8_t colorIndex = cubicwave8((i*(1+ 3*(SEGMENT.speed >> 5)))+(thisPhase) & 0xFF)/2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change. uint8_t colorIndex = cubicwave8(((i*(1+ 3*(SEGMENT.speed >> 5)))+(thisPhase)) & 0xFF)/2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change.
+ cos8((i*(1+ 2*(SEGMENT.speed >> 5)))+(thatPhase) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish. + cos8(((i*(1+ 2*(SEGMENT.speed >> 5)))+(thatPhase)) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish.
uint8_t thisBright = qsub8(colorIndex, beatsin8(6,0, (255 - SEGMENT.intensity)|0x01 )); uint8_t thisBright = qsub8(colorIndex, beatsin8(6,0, (255 - SEGMENT.intensity)|0x01 ));
CRGB color = ColorFromPalette(currentPalette, colorIndex, thisBright, LINEARBLEND); CRGB color = ColorFromPalette(currentPalette, colorIndex, thisBright, LINEARBLEND);
setPixelColor(i, color.red, color.green, color.blue); setPixelColor(i, color.red, color.green, color.blue);

View File

@ -29,12 +29,6 @@
#ifndef WS2812FX_h #ifndef WS2812FX_h
#define WS2812FX_h #define WS2812FX_h
#ifdef ESP32_MULTISTRIP
#include "../usermods/esp32_multistrip/NpbWrapper.h"
#else
#include "NpbWrapper.h"
#endif
#include "const.h" #include "const.h"
#define FASTLED_INTERNAL //remove annoying pragma messages #define FASTLED_INTERNAL //remove annoying pragma messages
@ -586,12 +580,11 @@ class WS2812FX {
ablMilliampsMax = 850; ablMilliampsMax = 850;
currentMilliamps = 0; currentMilliamps = 0;
timebase = 0; timebase = 0;
bus = new NeoPixelWrapper();
resetSegments(); resetSegments();
} }
void void
init(bool supportWhite, uint16_t countPixels, bool skipFirst), finalizeInit(bool supportWhite, uint16_t countPixels, bool skipFirst),
service(void), service(void),
blur(uint8_t), blur(uint8_t),
fill(uint32_t), fill(uint32_t),
@ -631,6 +624,8 @@ class WS2812FX {
paletteFade = 0, paletteFade = 0,
paletteBlend = 0, paletteBlend = 0,
milliampsPerLed = 55, milliampsPerLed = 55,
// getStripType(uint8_t strip=0),
// setStripType(uint8_t type, uint8_t strip=0),
getBrightness(void), getBrightness(void),
getMode(void), getMode(void),
getSpeed(void), getSpeed(void),
@ -645,12 +640,19 @@ class WS2812FX {
get_random_wheel_index(uint8_t); get_random_wheel_index(uint8_t);
int8_t int8_t
// setStripPin(uint8_t strip, int8_t pin),
// getStripPin(uint8_t strip=0),
// setStripPinClk(uint8_t strip, int8_t pin),
// getStripPinClk(uint8_t strip=0),
tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec); tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec);
uint16_t uint16_t
ablMilliampsMax, ablMilliampsMax,
currentMilliamps, currentMilliamps,
triwave16(uint16_t); // setStripLen(uint8_t strip, uint16_t len),
// getStripLen(uint8_t strip=0),
triwave16(uint16_t),
getFps();
uint32_t uint32_t
now, now,
@ -796,8 +798,6 @@ class WS2812FX {
mode_dynamic_smooth(void); mode_dynamic_smooth(void);
private: private:
NeoPixelWrapper *bus;
uint32_t crgb_to_col(CRGB fastled); uint32_t crgb_to_col(CRGB fastled);
CRGB col_to_crgb(uint32_t); CRGB col_to_crgb(uint32_t);
CRGBPalette16 currentPalette; CRGBPalette16 currentPalette;
@ -809,11 +809,12 @@ class WS2812FX {
uint16_t _usedSegmentData = 0; uint16_t _usedSegmentData = 0;
uint16_t _transitionDur = 750; uint16_t _transitionDur = 750;
uint16_t _cumulativeFps = 2;
void load_gradient_palette(uint8_t); void load_gradient_palette(uint8_t);
void handle_palette(void); void handle_palette(void);
bool bool
shouldStartBus = false,
_useRgbw = false, _useRgbw = false,
_skipFirstMode, _skipFirstMode,
_triggered; _triggered;
@ -861,12 +862,6 @@ class WS2812FX {
uint32_t _colors_t[3]; uint32_t _colors_t[3];
uint8_t _bri_t; uint8_t _bri_t;
#ifdef WLED_USE_ANALOG_LEDS
uint32_t _analogLastShow = 0;
RgbwColor _analogLastColor = 0;
uint8_t _analogLastBri = 0;
#endif
uint8_t _segment_index = 0; uint8_t _segment_index = 0;
uint8_t _segment_index_palette_last = 99; uint8_t _segment_index_palette_last = 99;
segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 24 bytes per element segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 24 bytes per element

View File

@ -47,7 +47,8 @@
19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25] 19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25]
*/ */
void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst) //do not call this method from system context (network callback)
void WS2812FX::finalizeInit(bool supportWhite, uint16_t countPixels, bool skipFirst)
{ {
if (supportWhite == _useRgbw && countPixels == _length && _skipFirstMode == skipFirst) return; if (supportWhite == _useRgbw && countPixels == _length && _skipFirstMode == skipFirst) return;
RESET_RUNTIME; RESET_RUNTIME;
@ -55,21 +56,36 @@ void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst)
_length = countPixels; _length = countPixels;
_skipFirstMode = skipFirst; _skipFirstMode = skipFirst;
uint8_t ty = 1;
if (supportWhite) ty = 2;
_lengthRaw = _length; _lengthRaw = _length;
if (_skipFirstMode) { if (_skipFirstMode) {
_lengthRaw += LED_SKIP_AMOUNT; _lengthRaw += LED_SKIP_AMOUNT;
} }
//if busses failed to load, add default (FS issue...)
if (busses.getNumBusses() == 0) {
uint8_t defPin[] = {LEDPIN};
BusConfig defCfg = BusConfig(TYPE_WS2812_RGB, defPin, 0, _lengthRaw, COL_ORDER_GRB);
busses.add(defCfg);
}
deserializeMap(); deserializeMap();
bus->Begin((NeoPixelType)ty, _lengthRaw); //make segment 0 cover the entire strip
_segments[0].start = 0; _segments[0].start = 0;
_segments[0].stop = _length; _segments[0].stop = _length;
setBrightness(_brightness); setBrightness(_brightness);
#ifdef ESP8266
for (uint8_t i = 0; i < busses.getNumBusses(); i++) {
Bus* b = busses.getBus(i);
if ((!IS_DIGITAL(b->getType()) || IS_2PIN(b->getType()))) continue;
uint8_t pins[5];
b->getPins(pins);
BusDigital* bd = static_cast<BusDigital*>(b);
if (pins[0] == 3) bd->reinit();
}
#endif
} }
void WS2812FX::service() { void WS2812FX::service() {
@ -168,19 +184,17 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
} }
} }
RgbwColor col;
col.R = r; col.G = g; col.B = b; col.W = w;
uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0; uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0;
if (SEGLEN) {//from segment if (SEGLEN) {//from segment
//color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments) //color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments)
if (_bri_t < 255) { if (_bri_t < 255) {
col.R = scale8(col.R, _bri_t); r = scale8(r, _bri_t);
col.G = scale8(col.G, _bri_t); g = scale8(g, _bri_t);
col.B = scale8(col.B, _bri_t); b = scale8(b, _bri_t);
col.W = scale8(col.W, _bri_t); w = scale8(w, _bri_t);
} }
uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b));
/* Set all the pixels in the group, ensuring _skipFirstMode is honored */ /* Set all the pixels in the group, ensuring _skipFirstMode is honored */
bool reversed = reverseMode ^ IS_REVERSE; bool reversed = reverseMode ^ IS_REVERSE;
@ -192,12 +206,12 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
if (reverseMode) indexSetRev = REV(indexSet); if (reverseMode) indexSetRev = REV(indexSet);
if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet]; if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet];
if (indexSetRev >= SEGMENT.start && indexSetRev < SEGMENT.stop) { if (indexSetRev >= SEGMENT.start && indexSetRev < SEGMENT.stop) {
bus->SetPixelColor(indexSet + skip, col); busses.setPixelColor(indexSet + skip, col);
if (IS_MIRROR) { //set the corresponding mirrored pixel if (IS_MIRROR) { //set the corresponding mirrored pixel
if (reverseMode) { if (reverseMode) {
bus->SetPixelColor(REV(SEGMENT.start) - indexSet + skip + REV(SEGMENT.stop) + 1, col); busses.setPixelColor(REV(SEGMENT.start) - indexSet + skip + REV(SEGMENT.stop) + 1, col);
} else { } else {
bus->SetPixelColor(SEGMENT.stop - indexSet + skip + SEGMENT.start - 1, col); busses.setPixelColor(SEGMENT.stop - indexSet + skip + SEGMENT.start - 1, col);
} }
} }
} }
@ -205,11 +219,13 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
} else { //live data, etc. } else { //live data, etc.
if (reverseMode) i = REV(i); if (reverseMode) i = REV(i);
if (i < customMappingSize) i = customMappingTable[i]; if (i < customMappingSize) i = customMappingTable[i];
bus->SetPixelColor(i + skip, col);
uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b));
busses.setPixelColor(i + skip, col);
} }
if (skip && i == 0) { if (skip && i == 0) {
for (uint16_t j = 0; j < skip; j++) { for (uint16_t j = 0; j < skip; j++) {
bus->SetPixelColor(j, RgbwColor(0, 0, 0, 0)); busses.setPixelColor(j, BLACK);
} }
} }
} }
@ -260,7 +276,7 @@ void WS2812FX::show(void) {
for (uint16_t i = 0; i < _length; i++) //sum up the usage of each LED for (uint16_t i = 0; i < _length; i++) //sum up the usage of each LED
{ {
RgbwColor c = bus->GetPixelColorRaw(i); RgbwColor c = busses.getPixelColor(i);
if(useWackyWS2815PowerModel) if(useWackyWS2815PowerModel)
{ {
@ -289,25 +305,30 @@ void WS2812FX::show(void) {
uint16_t scaleI = scale * 255; uint16_t scaleI = scale * 255;
uint8_t scaleB = (scaleI > 255) ? 255 : scaleI; uint8_t scaleB = (scaleI > 255) ? 255 : scaleI;
uint8_t newBri = scale8(_brightness, scaleB); uint8_t newBri = scale8(_brightness, scaleB);
bus->SetBrightness(newBri); busses.setBrightness(newBri);
currentMilliamps = (powerSum0 * newBri) / puPerMilliamp; currentMilliamps = (powerSum0 * newBri) / puPerMilliamp;
} else } else
{ {
currentMilliamps = powerSum / puPerMilliamp; currentMilliamps = powerSum / puPerMilliamp;
bus->SetBrightness(_brightness); busses.setBrightness(_brightness);
} }
currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate
currentMilliamps += _length; //add standby power back to estimate currentMilliamps += _length; //add standby power back to estimate
} else { } else {
currentMilliamps = 0; currentMilliamps = 0;
bus->SetBrightness(_brightness); busses.setBrightness(_brightness);
} }
// some buses send asynchronously and this method will return before // some buses send asynchronously and this method will return before
// all of the data has been sent. // all of the data has been sent.
// See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods // See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods
bus->Show(); busses.show();
_lastShow = millis(); unsigned long now = millis();
unsigned long diff = now - _lastShow;
uint16_t fpsCurr = 200;
if (diff > 0) fpsCurr = 1000 / diff;
_cumulativeFps = (3 * _cumulativeFps + fpsCurr) >> 2;
_lastShow = now;
} }
/** /**
@ -315,7 +336,16 @@ void WS2812FX::show(void) {
* On some hardware (ESP32), strip updates are done asynchronously. * On some hardware (ESP32), strip updates are done asynchronously.
*/ */
bool WS2812FX::isUpdating() { bool WS2812FX::isUpdating() {
return !bus->CanShow(); return !busses.canAllShow();
}
/**
* Returns the refresh rate of the LED strip. Useful for finding out whether a given setup is fast enough.
* Only updates on show() or is set to 0 fps if last show is more than 2 secs ago, so accurary varies
*/
uint16_t WS2812FX::getFps() {
if (millis() - _lastShow > 2000) return 0;
return _cumulativeFps +1;
} }
/** /**
@ -351,7 +381,6 @@ uint8_t WS2812FX::getPaletteCount()
bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t p) { bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t p) {
uint8_t mainSeg = getMainSegmentId();
Segment& seg = _segments[getMainSegmentId()]; Segment& seg = _segments[getMainSegmentId()];
uint8_t modePrev = seg.mode, speedPrev = seg.speed, intensityPrev = seg.intensity, palettePrev = seg.palette; uint8_t modePrev = seg.mode, speedPrev = seg.speed, intensityPrev = seg.intensity, palettePrev = seg.palette;
@ -417,17 +446,6 @@ void WS2812FX::setBrightness(uint8_t b) {
{ {
_segments[i].setOption(SEG_OPTION_FREEZE, false); _segments[i].setOption(SEG_OPTION_FREEZE, false);
} }
#if LEDPIN == LED_BUILTIN
shouldStartBus = true;
#endif
} else {
#if LEDPIN == LED_BUILTIN
if (shouldStartBus) {
shouldStartBus = false;
const uint8_t ty = _useRgbw ? 2 : 1;
bus->Begin((NeoPixelType)ty, _lengthRaw);
}
#endif
} }
if (SEGENV.next_time > millis() + 22 && millis() - _lastShow > MIN_SHOW_DELAY) show();//apply brightness change immediately if no refresh soon if (SEGENV.next_time > millis() + 22 && millis() - _lastShow > MIN_SHOW_DELAY) show();//apply brightness change immediately if no refresh soon
} }
@ -485,7 +503,7 @@ uint32_t WS2812FX::getPixelColor(uint16_t i)
if (i >= _lengthRaw) return 0; if (i >= _lengthRaw) return 0;
return bus->GetPixelColorRgbw(i); return busses.getPixelColor(i);
} }
WS2812FX::Segment& WS2812FX::getSegment(uint8_t id) { WS2812FX::Segment& WS2812FX::getSegment(uint8_t id) {
@ -505,12 +523,13 @@ uint32_t WS2812FX::getLastShow(void) {
return _lastShow; return _lastShow;
} }
//TODO these need to be on a per-strip basis
uint8_t WS2812FX::getColorOrder(void) { uint8_t WS2812FX::getColorOrder(void) {
return bus->GetColorOrder(); return COL_ORDER_GRB;
} }
void WS2812FX::setColorOrder(uint8_t co) { void WS2812FX::setColorOrder(uint8_t co) {
bus->SetColorOrder(co); //bus->SetColorOrder(co);
} }
void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) { void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) {
@ -962,44 +981,6 @@ bool WS2812FX::segmentsAreIdentical(Segment* a, Segment* b)
return true; return true;
} }
#ifdef WLED_USE_ANALOG_LEDS
void WS2812FX::setRgbwPwm(void) {
uint32_t nowUp = millis(); // Be aware, millis() rolls over every 49 days
if (nowUp - _analogLastShow < MIN_SHOW_DELAY) return;
_analogLastShow = nowUp;
RgbwColor c;
uint32_t col = bus->GetPixelColorRgbw(PWM_INDEX);
c.R = col >> 16; c.G = col >> 8; c.B = col; c.W = col >> 24;
byte b = getBrightness();
if (c == _analogLastColor && b == _analogLastBri) return;
// check color values for Warm / Cold white mix (for RGBW) // EsplanexaDevice.cpp
#ifdef WLED_USE_5CH_LEDS
if (c.R == 255 && c.G == 255 && c.B == 255 && c.W == 255) {
bus->SetRgbwPwm(0, 0, 0, 0, c.W * b / 255);
} else if (c.R == 127 && c.G == 127 && c.B == 127 && c.W == 255) {
bus->SetRgbwPwm(0, 0, 0, c.W * b / 512, c.W * b / 255);
} else if (c.R == 0 && c.G == 0 && c.B == 0 && c.W == 255) {
bus->SetRgbwPwm(0, 0, 0, c.W * b / 255, 0);
} else if (c.R == 130 && c.G == 90 && c.B == 0 && c.W == 255) {
bus->SetRgbwPwm(0, 0, 0, c.W * b / 255, c.W * b / 512);
} else if (c.R == 255 && c.G == 153 && c.B == 0 && c.W == 255) {
bus->SetRgbwPwm(0, 0, 0, c.W * b / 255, 0);
} else { // not only white colors
bus->SetRgbwPwm(c.R * b / 255, c.G * b / 255, c.B * b / 255, c.W * b / 255);
}
#else
bus->SetRgbwPwm(c.R * b / 255, c.G * b / 255, c.B * b / 255, c.W * b / 255);
#endif
_analogLastColor = c;
_analogLastBri = b;
}
#else
void WS2812FX::setRgbwPwm() {}
#endif
//load custom mapping table from JSON file //load custom mapping table from JSON file
void WS2812FX::deserializeMap(void) { void WS2812FX::deserializeMap(void) {

34
wled00/NodeStruct.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef WLED_NODESTRUCT_H
#define WLED_NODESTRUCT_H
/*********************************************************************************************\
* NodeStruct from the ESP Easy project (https://github.com/letscontrolit/ESPEasy)
\*********************************************************************************************/
#include <map>
#include <IPAddress.h>
#define NODE_TYPE_ID_UNDEFINED 0
#define NODE_TYPE_ID_ESP8266 82
#define NODE_TYPE_ID_ESP32 32
/*********************************************************************************************\
* NodeStruct
\*********************************************************************************************/
struct NodeStruct
{
String nodeName;
IPAddress ip;
uint8_t unit;
uint8_t age;
uint8_t nodeType;
uint32_t build;
NodeStruct() : age(0), nodeType(0), build(0)
{
for (uint8_t i = 0; i < 4; ++i) { ip[i] = 0; }
}
};
typedef std::map<uint8_t, NodeStruct> NodesMap;
#endif // WLED_NODESTRUCT_H

View File

@ -1,439 +0,0 @@
//this code is a modified version of https://github.com/Makuna/NeoPixelBus/issues/103
#ifndef NpbWrapper_h
#define NpbWrapper_h
//PIN CONFIGURATION
#ifndef LEDPIN
#define LEDPIN 2 //strip pin. Any for ESP32, gpio2 or 3 is recommended for ESP8266 (gpio2/3 are labeled D4/RX on NodeMCU and Wemos)
#endif
//#define USE_APA102 // Uncomment for using APA102 LEDs.
//#define USE_WS2801 // Uncomment for using WS2801 LEDs (make sure you have NeoPixelBus v2.5.6 or newer)
//#define USE_LPD8806 // Uncomment for using LPD8806
//#define USE_TM1814 // Uncomment for using TM1814 LEDs (make sure you have NeoPixelBus v2.5.7 or newer)
//#define USE_P9813 // Uncomment for using P9813 LEDs (make sure you have NeoPixelBus v2.5.8 or newer)
//#define WLED_USE_ANALOG_LEDS //Uncomment for using "dumb" PWM controlled LEDs (see pins below, default R: gpio5, G: 12, B: 15, W: 13)
//#define WLED_USE_H801 //H801 controller. Please uncomment #define WLED_USE_ANALOG_LEDS as well
//#define WLED_USE_5CH_LEDS //5 Channel H801 for cold and warm white
//#define WLED_USE_BWLT11
//#define WLED_USE_SHOJO_PCB
#ifndef BTNPIN
#define BTNPIN 0 //button pin. Needs to have pullup (gpio0 recommended)
#endif
#ifndef TOUCHPIN
//#define TOUCHPIN T0 //touch pin. Behaves the same as button. ESP32 only.
#endif
#ifndef IRPIN
#define IRPIN 4 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0
#endif
#ifndef RLYPIN
#define RLYPIN 12 //pin for relay, will be set HIGH if LEDs are on (-1 to disable). Also usable for standby leds, triggers,...
#endif
#ifndef AUXPIN
#define AUXPIN -1 //debug auxiliary output pin (-1 to disable)
#endif
#ifndef RLYMDE
#define RLYMDE 1 //mode for relay, 0: LOW if LEDs are on 1: HIGH if LEDs are on
#endif
//enable color order override for a specific range of the strip
//This can be useful if you want to chain multiple strings with incompatible color order
//#define COLOR_ORDER_OVERRIDE
#define COO_MIN 0
#define COO_MAX 35 //not inclusive, this would set the override for LEDs 0-34
#define COO_ORDER COL_ORDER_GRB
//END CONFIGURATION
#if defined(USE_APA102) || defined(USE_WS2801) || defined(USE_LPD8806) || defined(USE_P9813)
#ifndef CLKPIN
#define CLKPIN 0
#endif
#ifndef DATAPIN
#define DATAPIN 2
#endif
#if BTNPIN == CLKPIN || BTNPIN == DATAPIN
#undef BTNPIN // Deactivate button pin if it conflicts with one of the APA102 pins.
#endif
#endif
#ifdef WLED_USE_ANALOG_LEDS
//PWM pins - PINs 15,13,12,14 (W2 = 04)are used with H801 Wifi LED Controller
#ifdef WLED_USE_H801
#define RPIN 15 //R pin for analog LED strip
#define GPIN 13 //G pin for analog LED strip
#define BPIN 12 //B pin for analog LED strip
#define WPIN 14 //W pin for analog LED strip
#define W2PIN 04 //W2 pin for analog LED strip
#undef BTNPIN
#undef IRPIN
#define IRPIN 0 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0
#elif defined(WLED_USE_BWLT11)
//PWM pins - to use with BW-LT11
#define RPIN 12 //R pin for analog LED strip
#define GPIN 4 //G pin for analog LED strip
#define BPIN 14 //B pin for analog LED strip
#define WPIN 5 //W pin for analog LED strip
#elif defined(WLED_USE_SHOJO_PCB)
//PWM pins - to use with Shojo PCB (https://www.bastelbunker.de/esp-rgbww-wifi-led-controller-vbs-edition/)
#define RPIN 14 //R pin for analog LED strip
#define GPIN 4 //G pin for analog LED strip
#define BPIN 5 //B pin for analog LED strip
#define WPIN 15 //W pin for analog LED strip
#define W2PIN 12 //W2 pin for analog LED strip
#elif defined(WLED_USE_PLJAKOBS_PCB)
// PWM pins - to use with esp_rgbww_controller from patrickjahns/pljakobs (https://github.com/pljakobs/esp_rgbww_controller)
#define RPIN 12 //R pin for analog LED strip
#define GPIN 13 //G pin for analog LED strip
#define BPIN 14 //B pin for analog LED strip
#define WPIN 4 //W pin for analog LED strip
#define W2PIN 5 //W2 pin for analog LED strip
#undef IRPIN
#else
//Enable override of Pins by using the platformio_override.ini file
//PWM pins - PINs 5,12,13,15 are used with Magic Home LED Controller
#ifndef RPIN
#define RPIN 5 //R pin for analog LED strip
#endif
#ifndef GPIN
#define GPIN 12 //G pin for analog LED strip
#endif
#ifndef BPIN
#define BPIN 15 //B pin for analog LED strip
#endif
#ifndef WPIN
#define WPIN 13 //W pin for analog LED strip
#endif
#endif
#undef RLYPIN
#define RLYPIN -1 //disable as pin 12 is used by analog LEDs
#endif
//automatically uses the right driver method for each platform
#ifdef ARDUINO_ARCH_ESP32
#ifdef USE_APA102
#define PIXELMETHOD DotStarMethod
#elif defined(USE_WS2801)
#define PIXELMETHOD NeoWs2801Method
#elif defined(USE_LPD8806)
#define PIXELMETHOD Lpd8806Method
#elif defined(USE_TM1814)
#define PIXELMETHOD NeoTm1814Method
#elif defined(USE_P9813)
#define PIXELMETHOD P9813Method
#else
#define PIXELMETHOD NeoEsp32Rmt0Ws2812xMethod
#endif
#else //esp8266
//autoselect the right method depending on strip pin
#ifdef USE_APA102
#define PIXELMETHOD DotStarMethod
#elif defined(USE_WS2801)
#define PIXELMETHOD NeoWs2801Method
#elif defined(USE_LPD8806)
#define PIXELMETHOD Lpd8806Method
#elif defined(USE_TM1814)
#define PIXELMETHOD NeoTm1814Method
#elif defined(USE_P9813)
#define PIXELMETHOD P9813Method
#elif LEDPIN == 2
#define PIXELMETHOD NeoEsp8266Uart1Ws2813Method //if you get an error here, try to change to NeoEsp8266UartWs2813Method or update Neopixelbus
#elif LEDPIN == 3
#define PIXELMETHOD NeoEsp8266Dma800KbpsMethod
#else
#define PIXELMETHOD NeoEsp8266BitBang800KbpsMethod
#pragma message "Software BitBang will be used because of your selected LED pin. This may cause flicker. Use GPIO 2 or 3 for best results."
#endif
#endif
//you can now change the color order in the web settings
#ifdef USE_APA102
#define PIXELFEATURE3 DotStarBgrFeature
#define PIXELFEATURE4 DotStarLbgrFeature
#elif defined(USE_LPD8806)
#define PIXELFEATURE3 Lpd8806GrbFeature
#define PIXELFEATURE4 Lpd8806GrbFeature
#elif defined(USE_WS2801)
#define PIXELFEATURE3 NeoRbgFeature
#define PIXELFEATURE4 NeoRbgFeature
#elif defined(USE_TM1814)
#define PIXELFEATURE3 NeoWrgbTm1814Feature
#define PIXELFEATURE4 NeoWrgbTm1814Feature
#elif defined(USE_P9813)
#define PIXELFEATURE3 P9813BgrFeature
#define PIXELFEATURE4 NeoGrbwFeature
#else
#define PIXELFEATURE3 NeoGrbFeature
#define PIXELFEATURE4 NeoGrbwFeature
#endif
#include <NeoPixelBrightnessBus.h>
#include "const.h"
enum NeoPixelType
{
NeoPixelType_None = 0,
NeoPixelType_Grb = 1,
NeoPixelType_Grbw = 2,
NeoPixelType_End = 3
};
class NeoPixelWrapper
{
public:
NeoPixelWrapper() :
// initialize each member to null
_pGrb(NULL),
_pGrbw(NULL),
_type(NeoPixelType_None)
{
}
~NeoPixelWrapper()
{
cleanup();
}
void Begin(NeoPixelType type, uint16_t countPixels)
{
cleanup();
_type = type;
switch (_type)
{
case NeoPixelType_Grb:
#if defined(USE_APA102) || defined(USE_WS2801) || defined(USE_LPD8806) || defined(USE_P9813)
_pGrb = new NeoPixelBrightnessBus<PIXELFEATURE3,PIXELMETHOD>(countPixels, CLKPIN, DATAPIN);
#else
_pGrb = new NeoPixelBrightnessBus<PIXELFEATURE3,PIXELMETHOD>(countPixels, LEDPIN);
#endif
_pGrb->Begin();
break;
case NeoPixelType_Grbw:
#if defined(USE_APA102) || defined(USE_WS2801) || defined(USE_LPD8806) || defined(USE_P9813)
_pGrbw = new NeoPixelBrightnessBus<PIXELFEATURE4,PIXELMETHOD>(countPixels, CLKPIN, DATAPIN);
#else
_pGrbw = new NeoPixelBrightnessBus<PIXELFEATURE4,PIXELMETHOD>(countPixels, LEDPIN);
#endif
_pGrbw->Begin();
break;
}
#ifdef WLED_USE_ANALOG_LEDS
#ifdef ARDUINO_ARCH_ESP32
ledcSetup(0, 5000, 8);
ledcAttachPin(RPIN, 0);
ledcSetup(1, 5000, 8);
ledcAttachPin(GPIN, 1);
ledcSetup(2, 5000, 8);
ledcAttachPin(BPIN, 2);
if(_type == NeoPixelType_Grbw)
{
ledcSetup(3, 5000, 8);
ledcAttachPin(WPIN, 3);
#ifdef WLED_USE_5CH_LEDS
ledcSetup(4, 5000, 8);
ledcAttachPin(W2PIN, 4);
#endif
}
#else // ESP8266
//init PWM pins
pinMode(RPIN, OUTPUT);
pinMode(GPIN, OUTPUT);
pinMode(BPIN, OUTPUT);
if(_type == NeoPixelType_Grbw)
{
pinMode(WPIN, OUTPUT);
#ifdef WLED_USE_5CH_LEDS
pinMode(W2PIN, OUTPUT);
#endif
}
analogWriteRange(255); //same range as one RGB channel
analogWriteFreq(880); //PWM frequency proven as good for LEDs
#endif
#endif
}
#ifdef WLED_USE_ANALOG_LEDS
void SetRgbwPwm(uint8_t r, uint8_t g, uint8_t b, uint8_t w, uint8_t w2=0)
{
#ifdef ARDUINO_ARCH_ESP32
ledcWrite(0, r);
ledcWrite(1, g);
ledcWrite(2, b);
switch (_type) {
case NeoPixelType_Grb: break;
#ifdef WLED_USE_5CH_LEDS
case NeoPixelType_Grbw: ledcWrite(3, w); ledcWrite(4, w2); break;
#else
case NeoPixelType_Grbw: ledcWrite(3, w); break;
#endif
}
#else // ESP8266
analogWrite(RPIN, r);
analogWrite(GPIN, g);
analogWrite(BPIN, b);
switch (_type) {
case NeoPixelType_Grb: break;
#ifdef WLED_USE_5CH_LEDS
case NeoPixelType_Grbw: analogWrite(WPIN, w); analogWrite(W2PIN, w2); break;
#else
case NeoPixelType_Grbw: analogWrite(WPIN, w); break;
#endif
}
#endif
}
#endif
void Show()
{
switch (_type)
{
case NeoPixelType_Grb: _pGrb->Show(); break;
case NeoPixelType_Grbw: _pGrbw->Show(); break;
}
}
/**
* This will return true if enough time has passed since the last time Show() was called.
* This also means that calling Show() will not cause any undue waiting. If the method for
* the defined bus is hardware that sends asynchronously, then call CanShow() will let
* you know if it has finished sending the data from the last Show().
*/
bool CanShow()
{
switch (_type)
{
case NeoPixelType_Grb: return _pGrb->CanShow();
case NeoPixelType_Grbw: return _pGrbw->CanShow();
default: return true;
}
}
void SetPixelColor(uint16_t indexPixel, RgbwColor c)
{
RgbwColor col;
uint8_t co = _colorOrder;
#ifdef COLOR_ORDER_OVERRIDE
if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER;
#endif
//reorder channels to selected order
switch (co)
{
case 0: col.G = c.G; col.R = c.R; col.B = c.B; break; //0 = GRB, default
case 1: col.G = c.R; col.R = c.G; col.B = c.B; break; //1 = RGB, common for WS2811
case 2: col.G = c.B; col.R = c.R; col.B = c.G; break; //2 = BRG
case 3: col.G = c.R; col.R = c.B; col.B = c.G; break; //3 = RBG
case 4: col.G = c.B; col.R = c.G; col.B = c.R; break; //4 = BGR
default: col.G = c.G; col.R = c.B; col.B = c.R; break; //5 = GBR
}
col.W = c.W;
switch (_type) {
case NeoPixelType_Grb: {
_pGrb->SetPixelColor(indexPixel, RgbColor(col.R,col.G,col.B));
}
break;
case NeoPixelType_Grbw: {
#if defined(USE_LPD8806) || defined(USE_WS2801)
_pGrbw->SetPixelColor(indexPixel, RgbColor(col.R,col.G,col.B));
#else
_pGrbw->SetPixelColor(indexPixel, col);
#endif
}
break;
}
}
void SetBrightness(byte b)
{
switch (_type) {
case NeoPixelType_Grb: _pGrb->SetBrightness(b); break;
case NeoPixelType_Grbw:_pGrbw->SetBrightness(b); break;
}
}
void SetColorOrder(byte colorOrder) {
_colorOrder = colorOrder;
}
uint8_t GetColorOrder() {
return _colorOrder;
}
RgbwColor GetPixelColorRaw(uint16_t indexPixel) const
{
switch (_type) {
case NeoPixelType_Grb: return _pGrb->GetPixelColor(indexPixel); break;
case NeoPixelType_Grbw: return _pGrbw->GetPixelColor(indexPixel); break;
}
return 0;
}
// NOTE: Due to feature differences, some support RGBW but the method name
// here needs to be unique, thus GetPixeColorRgbw
uint32_t GetPixelColorRgbw(uint16_t indexPixel) const
{
RgbwColor col(0,0,0,0);
switch (_type) {
case NeoPixelType_Grb: col = _pGrb->GetPixelColor(indexPixel); break;
case NeoPixelType_Grbw: col = _pGrbw->GetPixelColor(indexPixel); break;
}
uint8_t co = _colorOrder;
#ifdef COLOR_ORDER_OVERRIDE
if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER;
#endif
switch (co)
{
// W G R B
case 0: return ((col.W << 24) | (col.G << 8) | (col.R << 16) | (col.B)); //0 = GRB, default
case 1: return ((col.W << 24) | (col.R << 8) | (col.G << 16) | (col.B)); //1 = RGB, common for WS2811
case 2: return ((col.W << 24) | (col.B << 8) | (col.R << 16) | (col.G)); //2 = BRG
case 3: return ((col.W << 24) | (col.B << 8) | (col.G << 16) | (col.R)); //3 = RBG
case 4: return ((col.W << 24) | (col.R << 8) | (col.B << 16) | (col.G)); //4 = BGR
case 5: return ((col.W << 24) | (col.G << 8) | (col.B << 16) | (col.R)); //5 = GBR
}
return 0;
}
uint8_t* GetPixels(void)
{
switch (_type) {
case NeoPixelType_Grb: return _pGrb->Pixels(); break;
case NeoPixelType_Grbw: return _pGrbw->Pixels(); break;
}
return 0;
}
private:
NeoPixelType _type;
// have a member for every possible type
NeoPixelBrightnessBus<PIXELFEATURE3,PIXELMETHOD>* _pGrb;
NeoPixelBrightnessBus<PIXELFEATURE4,PIXELMETHOD>* _pGrbw;
byte _colorOrder = 0;
void cleanup()
{
switch (_type) {
case NeoPixelType_Grb: delete _pGrb ; _pGrb = NULL; break;
case NeoPixelType_Grbw: delete _pGrbw; _pGrbw = NULL; break;
}
}
};
#endif

404
wled00/bus_manager.h Normal file
View File

@ -0,0 +1,404 @@
#ifndef BusManager_h
#define BusManager_h
/*
* Class for addressing various light types
*/
#include "const.h"
#include "pin_manager.h"
#include "bus_wrapper.h"
#include <Arduino.h>
//temporary struct for passing bus configuration to bus
struct BusConfig {
uint8_t type = TYPE_WS2812_RGB;
uint16_t count = 1;
uint16_t start = 0;
uint8_t colorOrder = COL_ORDER_GRB;
bool reversed = false;
uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255};
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false) {
type = busType; count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev;
uint8_t nPins = 1;
if (type > 47) nPins = 2;
else if (type > 41 && type < 46) nPins = NUM_PWM_PINS(type);
for (uint8_t i = 0; i < nPins; i++) pins[i] = ppins[i];
}
};
//parent class of BusDigital and BusPwm
class Bus {
public:
Bus(uint8_t type, uint16_t start) {
_type = type;
_start = start;
};
virtual void show() {}
virtual bool canShow() { return true; }
virtual void setPixelColor(uint16_t pix, uint32_t c) {};
virtual void setBrightness(uint8_t b) {};
virtual uint32_t getPixelColor(uint16_t pix) { return 0; };
virtual void cleanup() {};
virtual ~Bus() { //throw the bus under the bus
}
virtual uint8_t getPins(uint8_t* pinArray) { return 0; }
uint16_t getStart() {
return _start;
}
void setStart(uint16_t start) {
_start = start;
}
virtual uint16_t getLength() {
return 1;
}
virtual void setColorOrder() {}
virtual uint8_t getColorOrder() {
return COL_ORDER_RGB;
}
uint8_t getType() {
return _type;
}
bool isOk() {
return _valid;
}
bool reversed = false;
protected:
uint8_t _type = TYPE_NONE;
uint8_t _bri = 255;
uint16_t _start = 0;
bool _valid = false;
};
class BusDigital : public Bus {
public:
BusDigital(BusConfig &bc, uint8_t nr) : Bus(bc.type, bc.start) {
if (!IS_DIGITAL(bc.type) || !bc.count) return;
_pins[0] = bc.pins[0];
if (!pinManager.allocatePin(_pins[0])) return;
if (IS_2PIN(bc.type)) {
_pins[1] = bc.pins[1];
if (!pinManager.allocatePin(_pins[1])) {
cleanup(); return;
}
}
_len = bc.count;
reversed = bc.reversed;
_iType = PolyBus::getI(bc.type, _pins, nr);
if (_iType == I_NONE) return;
_busPtr = PolyBus::create(_iType, _pins, _len);
_valid = (_busPtr != nullptr);
_colorOrder = bc.colorOrder;
//Serial.printf("Successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u)\n",nr, len, type, pins[0],pins[1],_iType);
};
void show() {
PolyBus::show(_busPtr, _iType);
}
bool canShow() {
return PolyBus::canShow(_busPtr, _iType);
}
void setBrightness(uint8_t b) {
//Fix for turning off onboard LED breaking bus
#ifdef LED_BUILTIN
if (_bri == 0 && b > 0) {
if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) PolyBus::begin(_busPtr, _iType, _pins);
}
#endif
_bri = b;
PolyBus::setBrightness(_busPtr, _iType, b);
}
void setPixelColor(uint16_t pix, uint32_t c) {
if (reversed) pix = _len - pix -1;
PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrder);
}
uint32_t getPixelColor(uint16_t pix) {
if (reversed) pix = _len - pix -1;
return PolyBus::getPixelColor(_busPtr, _iType, pix, _colorOrder);
}
uint8_t getColorOrder() {
return _colorOrder;
}
uint16_t getLength() {
return _len;
}
uint8_t getPins(uint8_t* pinArray) {
uint8_t numPins = IS_2PIN(_type) ? 2 : 1;
for (uint8_t i = 0; i < numPins; i++) pinArray[i] = _pins[i];
return numPins;
}
void setColorOrder(uint8_t colorOrder) {
if (colorOrder > 5) return;
_colorOrder = colorOrder;
}
void reinit() {
PolyBus::begin(_busPtr, _iType, _pins);
}
void cleanup() {
//Serial.println("Digital Cleanup");
PolyBus::cleanup(_busPtr, _iType);
_iType = I_NONE;
_valid = false;
_busPtr = nullptr;
pinManager.deallocatePin(_pins[0]);
pinManager.deallocatePin(_pins[1]);
}
~BusDigital() {
cleanup();
}
private:
uint8_t _colorOrder = COL_ORDER_GRB;
uint8_t _pins[2] = {255, 255};
uint8_t _iType = I_NONE;
uint16_t _len = 0;
void * _busPtr = nullptr;
};
class BusPwm : public Bus {
public:
BusPwm(BusConfig &bc) : Bus(bc.type, bc.start) {
if (!IS_PWM(bc.type)) return;
uint8_t numPins = NUM_PWM_PINS(bc.type);
#ifdef ESP8266
analogWriteRange(255); //same range as one RGB channel
analogWriteFreq(WLED_PWM_FREQ);
#else
_ledcStart = pinManager.allocateLedc(numPins);
if (_ledcStart == 255) { //no more free LEDC channels
deallocatePins(); return;
}
#endif
for (uint8_t i = 0; i < numPins; i++) {
_pins[i] = bc.pins[i];
if (!pinManager.allocatePin(_pins[i])) {
deallocatePins(); return;
}
#ifdef ESP8266
pinMode(_pins[i], OUTPUT);
#else
ledcSetup(_ledcStart + i, WLED_PWM_FREQ, 8);
ledcAttachPin(_pins[i], _ledcStart + i);
#endif
}
_valid = true;
};
void setPixelColor(uint16_t pix, uint32_t c) {
if (pix != 0 || !_valid) return; //only react to first pixel
uint8_t r = c >> 16;
uint8_t g = c >> 8;
uint8_t b = c ;
uint8_t w = c >> 24;
switch (_type) {
case TYPE_ANALOG_1CH: //one channel (white), use highest RGBW value
_data[0] = max(r, max(g, max(b, w))); break;
case TYPE_ANALOG_2CH: //warm white + cold white, we'll need some nice handling here, for now just R+G channels
case TYPE_ANALOG_3CH: //standard dumb RGB
case TYPE_ANALOG_4CH: //RGBW
case TYPE_ANALOG_5CH: //we'll want the white handling from 2CH here + RGB
_data[0] = r; _data[1] = g; _data[2] = b; _data[3] = w; _data[4] = 0; break;
default: return;
}
}
//does no index check
uint32_t getPixelColor(uint16_t pix) {
return ((_data[3] << 24) | (_data[0] << 16) | (_data[1] << 8) | (_data[2]));
}
void show() {
uint8_t numPins = NUM_PWM_PINS(_type);
for (uint8_t i = 0; i < numPins; i++) {
uint8_t scaled = (_data[i] * _bri) / 255;
#ifdef ESP8266
analogWrite(_pins[i], scaled);
#else
ledcWrite(_ledcStart + i, scaled);
#endif
}
}
void setBrightness(uint8_t b) {
_bri = b;
}
uint8_t getPins(uint8_t* pinArray) {
uint8_t numPins = NUM_PWM_PINS(_type);
for (uint8_t i = 0; i < numPins; i++) pinArray[i] = _pins[i];
return numPins;
}
void cleanup() {
deallocatePins();
}
~BusPwm() {
cleanup();
}
private:
uint8_t _pins[5] = {255, 255, 255, 255, 255};
uint8_t _data[5] = {255, 255, 255, 255, 255};
#ifdef ARDUINO_ARCH_ESP32
uint8_t _ledcStart = 255;
#endif
void deallocatePins() {
uint8_t numPins = NUM_PWM_PINS(_type);
for (uint8_t i = 0; i < numPins; i++) {
if (!pinManager.isPinOk(_pins[i])) continue;
#ifdef ESP8266
digitalWrite(_pins[i], LOW); //turn off PWM interrupt
#else
if (_ledcStart < 16) ledcDetachPin(_pins[i]);
#endif
pinManager.deallocatePin(_pins[i]);
}
#ifdef ARDUINO_ARCH_ESP32
pinManager.deallocateLedc(_ledcStart, numPins);
#endif
}
};
class BusManager {
public:
BusManager() {
};
//utility to get the approx. memory usage of a given BusConfig
uint32_t memUsage(BusConfig &bc) {
uint8_t type = bc.type;
uint16_t len = bc.count;
if (type < 32) {
#ifdef ESP8266
if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem
if (type > 29) return len*20; //RGBW
return len*15;
}
if (type > 29) return len*4; //RGBW
return len*3;
#else //ESP32 RMT uses double buffer?
if (type > 29) return len*8; //RGBW
return len*6;
#endif
}
if (type > 31 && type < 48) return 5;
if (type == 44 || type == 45) return len*4; //RGBW
return len*3;
}
int add(BusConfig &bc) {
if (numBusses >= WLED_MAX_BUSSES) return -1;
if (IS_DIGITAL(bc.type)) {
busses[numBusses] = new BusDigital(bc, numBusses);
} else {
busses[numBusses] = new BusPwm(bc);
}
numBusses++;
return numBusses -1;
}
//do not call this method from system context (network callback)
void removeAll() {
//Serial.println("Removing all.");
//prevents crashes due to deleting busses while in use.
while (!canAllShow()) yield();
for (uint8_t i = 0; i < numBusses; i++) delete busses[i];
numBusses = 0;
}
void show() {
for (uint8_t i = 0; i < numBusses; i++) {
busses[i]->show();
}
}
void setPixelColor(uint16_t pix, uint32_t c) {
for (uint8_t i = 0; i < numBusses; i++) {
Bus* b = busses[i];
uint16_t bstart = b->getStart();
if (pix < bstart || pix >= bstart + b->getLength()) continue;
busses[i]->setPixelColor(pix - bstart, c);
}
}
void setBrightness(uint8_t b) {
for (uint8_t i = 0; i < numBusses; i++) {
busses[i]->setBrightness(b);
}
}
uint32_t getPixelColor(uint16_t pix) {
for (uint8_t i = 0; i < numBusses; i++) {
Bus* b = busses[i];
uint16_t bstart = b->getStart();
if (pix < bstart || pix >= bstart + b->getLength()) continue;
return b->getPixelColor(pix - bstart);
}
return 0;
}
bool canAllShow() {
for (uint8_t i = 0; i < numBusses; i++) {
if (!busses[i]->canShow()) return false;
}
return true;
}
Bus* getBus(uint8_t busNr) {
if (busNr >= numBusses) return nullptr;
return busses[busNr];
}
uint8_t getNumBusses() {
return numBusses;
}
static bool isRgbw(uint8_t type) {
if (type == TYPE_SK6812_RGBW || type == TYPE_TM1814) return true;
if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true;
return false;
}
private:
uint8_t numBusses = 0;
Bus* busses[WLED_MAX_BUSSES];
};
#endif

882
wled00/bus_wrapper.h Normal file
View File

@ -0,0 +1,882 @@
#ifndef BusWrapper_h
#define BusWrapper_h
#include "NeoPixelBrightnessBus.h"
//Hardware SPI Pins
#define P_8266_HS_MOSI 13
#define P_8266_HS_CLK 14
#define P_32_HS_MOSI 13
#define P_32_HS_CLK 14
#define P_32_VS_MOSI 23
#define P_32_VS_CLK 18
//The dirty list of possible bus types. Quite a lot...
#define I_NONE 0
//ESP8266 RGB
#define I_8266_U0_NEO_3 1
#define I_8266_U1_NEO_3 2
#define I_8266_DM_NEO_3 3
#define I_8266_BB_NEO_3 4
//RGBW
#define I_8266_U0_NEO_4 5
#define I_8266_U1_NEO_4 6
#define I_8266_DM_NEO_4 7
#define I_8266_BB_NEO_4 8
//400Kbps
#define I_8266_U0_400_3 9
#define I_8266_U1_400_3 10
#define I_8266_DM_400_3 11
#define I_8266_BB_400_3 12
//TM1418 (RGBW)
#define I_8266_U0_TM1_4 13
#define I_8266_U1_TM1_4 14
#define I_8266_DM_TM1_4 15
#define I_8266_BB_TM1_4 16
/*** ESP32 Neopixel methods ***/
//RGB
#define I_32_R0_NEO_3 17
#define I_32_R1_NEO_3 18
#define I_32_R2_NEO_3 19
#define I_32_R3_NEO_3 20
#define I_32_R4_NEO_3 21
#define I_32_R5_NEO_3 22
#define I_32_R6_NEO_3 23
#define I_32_R7_NEO_3 24
#define I_32_I0_NEO_3 25
#define I_32_I1_NEO_3 26
//RGBW
#define I_32_R0_NEO_4 27
#define I_32_R1_NEO_4 28
#define I_32_R2_NEO_4 29
#define I_32_R3_NEO_4 30
#define I_32_R4_NEO_4 31
#define I_32_R5_NEO_4 32
#define I_32_R6_NEO_4 33
#define I_32_R7_NEO_4 34
#define I_32_I0_NEO_4 35
#define I_32_I1_NEO_4 36
//400Kbps
#define I_32_R0_400_3 37
#define I_32_R1_400_3 38
#define I_32_R2_400_3 39
#define I_32_R3_400_3 40
#define I_32_R4_400_3 41
#define I_32_R5_400_3 42
#define I_32_R6_400_3 43
#define I_32_R7_400_3 44
#define I_32_I0_400_3 45
#define I_32_I1_400_3 46
//TM1418 (RGBW)
#define I_32_R0_TM1_4 47
#define I_32_R1_TM1_4 48
#define I_32_R2_TM1_4 49
#define I_32_R3_TM1_4 50
#define I_32_R4_TM1_4 51
#define I_32_R5_TM1_4 52
#define I_32_R6_TM1_4 53
#define I_32_R7_TM1_4 54
#define I_32_I0_TM1_4 55
#define I_32_I1_TM1_4 56
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
//APA102
#define I_HS_DOT_3 57 //hardware SPI
#define I_SS_DOT_3 58 //soft SPI
//LPD8806
#define I_HS_LPD_3 59
#define I_SS_LPD_3 60
//WS2801
#define I_HS_WS1_3 61
#define I_SS_WS1_3 62
//P9813
#define I_HS_P98_3 63
#define I_SS_P98_3 64
/*** ESP8266 Neopixel methods ***/
#ifdef ESP8266
//RGB
#define B_8266_U0_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266Uart0Ws2813Method> //3 chan, esp8266, gpio1
#define B_8266_U1_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266Uart1Ws2813Method> //3 chan, esp8266, gpio2
#define B_8266_DM_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266Dma800KbpsMethod> //3 chan, esp8266, gpio3
#define B_8266_BB_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266BitBang800KbpsMethod> //3 chan, esp8266, bb (any pin but 16)
//RGBW
#define B_8266_U0_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp8266Uart0Ws2813Method> //4 chan, esp8266, gpio1
#define B_8266_U1_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp8266Uart1Ws2813Method> //4 chan, esp8266, gpio2
#define B_8266_DM_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp8266Dma800KbpsMethod> //4 chan, esp8266, gpio3
#define B_8266_BB_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp8266BitBang800KbpsMethod> //4 chan, esp8266, bb (any pin)
//400Kbps
#define B_8266_U0_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266Uart0400KbpsMethod> //3 chan, esp8266, gpio1
#define B_8266_U1_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266Uart1400KbpsMethod> //3 chan, esp8266, gpio2
#define B_8266_DM_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266Dma400KbpsMethod> //3 chan, esp8266, gpio3
#define B_8266_BB_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266BitBang400KbpsMethod> //3 chan, esp8266, bb (any pin)
//TM1418 (RGBW)
#define B_8266_U0_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp8266Uart0Tm1814Method>
#define B_8266_U1_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp8266Uart1Tm1814Method>
#define B_8266_DM_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp8266DmaTm1814Method>
#define B_8266_BB_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp8266BitBangTm1814Method>
#endif
/*** ESP32 Neopixel methods ***/
#ifdef ARDUINO_ARCH_ESP32
//RGB
#define B_32_R0_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt0Ws2812xMethod>
#define B_32_R1_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt1Ws2812xMethod>
#define B_32_R2_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt2Ws2812xMethod>
#define B_32_R3_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt3Ws2812xMethod>
#define B_32_R4_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt4Ws2812xMethod>
#define B_32_R5_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt5Ws2812xMethod>
#define B_32_R6_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt6Ws2812xMethod>
#define B_32_R7_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt7Ws2812xMethod>
#define B_32_I0_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32I2s0800KbpsMethod>
#define B_32_I1_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32I2s1800KbpsMethod>
//RGBW
#define B_32_R0_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32Rmt0Ws2812xMethod>
#define B_32_R1_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32Rmt1Ws2812xMethod>
#define B_32_R2_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32Rmt2Ws2812xMethod>
#define B_32_R3_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32Rmt3Ws2812xMethod>
#define B_32_R4_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32Rmt4Ws2812xMethod>
#define B_32_R5_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32Rmt5Ws2812xMethod>
#define B_32_R6_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32Rmt6Ws2812xMethod>
#define B_32_R7_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32Rmt7Ws2812xMethod>
#define B_32_I0_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32I2s0800KbpsMethod>
#define B_32_I1_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32I2s1800KbpsMethod>
//400Kbps
#define B_32_R0_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt0400KbpsMethod>
#define B_32_R1_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt1400KbpsMethod>
#define B_32_R2_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt2400KbpsMethod>
#define B_32_R3_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt3400KbpsMethod>
#define B_32_R4_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt4400KbpsMethod>
#define B_32_R5_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt5400KbpsMethod>
#define B_32_R6_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt6400KbpsMethod>
#define B_32_R7_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt7400KbpsMethod>
#define B_32_I0_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32I2s0400KbpsMethod>
#define B_32_I1_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32I2s1400KbpsMethod>
//TM1418 (RGBW)
#define B_32_R0_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32Rmt0Tm1814Method>
#define B_32_R1_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32Rmt1Tm1814Method>
#define B_32_R2_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32Rmt2Tm1814Method>
#define B_32_R3_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32Rmt3Tm1814Method>
#define B_32_R4_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32Rmt4Tm1814Method>
#define B_32_R5_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32Rmt5Tm1814Method>
#define B_32_R6_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32Rmt6Tm1814Method>
#define B_32_R7_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32Rmt7Tm1814Method>
#define B_32_I0_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32I2s0Tm1814Method>
#define B_32_I1_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32I2s1Tm1814Method>
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
#endif
//APA102
#define B_HS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarSpiMethod> //hardware SPI
#define B_SS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarMethod> //soft SPI
//LPD8806
#define B_HS_LPD_3 NeoPixelBrightnessBus<Lpd8806GrbFeature, Lpd8806SpiMethod>
#define B_SS_LPD_3 NeoPixelBrightnessBus<Lpd8806GrbFeature, Lpd8806Method>
//WS2801
#define B_HS_WS1_3 NeoPixelBrightnessBus<NeoRbgFeature, NeoWs2801SpiMethod>
#define B_SS_WS1_3 NeoPixelBrightnessBus<NeoRbgFeature, NeoWs2801Method>
//P9813
#define B_HS_P98_3 NeoPixelBrightnessBus<P9813BgrFeature, P9813SpiMethod>
#define B_SS_P98_3 NeoPixelBrightnessBus<P9813BgrFeature, P9813Method>
//handles pointer type conversion for all possible bus types
class PolyBus {
public:
static void begin(void* busPtr, uint8_t busType, uint8_t* pins) {
switch (busType) {
case I_NONE: break;
#ifdef ESP8266
case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->Begin(); break;
case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->Begin(); break;
case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->Begin(); break;
case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->Begin(); break;
case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->Begin(); break;
case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->Begin(); break;
case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->Begin(); break;
case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->Begin(); break;
case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->Begin(); break;
case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->Begin(); break;
case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->Begin(); break;
case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->Begin(); break;
case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->Begin(); break;
case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->Begin(); break;
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->Begin(); break;
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->Begin(); break;
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Begin(); break;
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->Begin(); break;
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->Begin(); break;
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->Begin(); break;
#endif
#ifdef ARDUINO_ARCH_ESP32
case I_32_R0_NEO_3: (static_cast<B_32_R0_NEO_3*>(busPtr))->Begin(); break;
case I_32_R1_NEO_3: (static_cast<B_32_R1_NEO_3*>(busPtr))->Begin(); break;
case I_32_R2_NEO_3: (static_cast<B_32_R2_NEO_3*>(busPtr))->Begin(); break;
case I_32_R3_NEO_3: (static_cast<B_32_R3_NEO_3*>(busPtr))->Begin(); break;
case I_32_R4_NEO_3: (static_cast<B_32_R4_NEO_3*>(busPtr))->Begin(); break;
case I_32_R5_NEO_3: (static_cast<B_32_R5_NEO_3*>(busPtr))->Begin(); break;
case I_32_R6_NEO_3: (static_cast<B_32_R6_NEO_3*>(busPtr))->Begin(); break;
case I_32_R7_NEO_3: (static_cast<B_32_R7_NEO_3*>(busPtr))->Begin(); break;
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->Begin(); break;
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->Begin(); break;
case I_32_R0_NEO_4: (static_cast<B_32_R0_NEO_4*>(busPtr))->Begin(); break;
case I_32_R1_NEO_4: (static_cast<B_32_R1_NEO_4*>(busPtr))->Begin(); break;
case I_32_R2_NEO_4: (static_cast<B_32_R2_NEO_4*>(busPtr))->Begin(); break;
case I_32_R3_NEO_4: (static_cast<B_32_R3_NEO_4*>(busPtr))->Begin(); break;
case I_32_R4_NEO_4: (static_cast<B_32_R4_NEO_4*>(busPtr))->Begin(); break;
case I_32_R5_NEO_4: (static_cast<B_32_R5_NEO_4*>(busPtr))->Begin(); break;
case I_32_R6_NEO_4: (static_cast<B_32_R6_NEO_4*>(busPtr))->Begin(); break;
case I_32_R7_NEO_4: (static_cast<B_32_R7_NEO_4*>(busPtr))->Begin(); break;
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Begin(); break;
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->Begin(); break;
case I_32_R0_400_3: (static_cast<B_32_R0_400_3*>(busPtr))->Begin(); break;
case I_32_R1_400_3: (static_cast<B_32_R1_400_3*>(busPtr))->Begin(); break;
case I_32_R2_400_3: (static_cast<B_32_R2_400_3*>(busPtr))->Begin(); break;
case I_32_R3_400_3: (static_cast<B_32_R3_400_3*>(busPtr))->Begin(); break;
case I_32_R4_400_3: (static_cast<B_32_R4_400_3*>(busPtr))->Begin(); break;
case I_32_R5_400_3: (static_cast<B_32_R5_400_3*>(busPtr))->Begin(); break;
case I_32_R6_400_3: (static_cast<B_32_R6_400_3*>(busPtr))->Begin(); break;
case I_32_R7_400_3: (static_cast<B_32_R7_400_3*>(busPtr))->Begin(); break;
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Begin(); break;
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->Begin(); break;
case I_32_R0_TM1_4: (static_cast<B_32_R0_TM1_4*>(busPtr))->Begin(); break;
case I_32_R1_TM1_4: (static_cast<B_32_R1_TM1_4*>(busPtr))->Begin(); break;
case I_32_R2_TM1_4: (static_cast<B_32_R2_TM1_4*>(busPtr))->Begin(); break;
case I_32_R3_TM1_4: (static_cast<B_32_R3_TM1_4*>(busPtr))->Begin(); break;
case I_32_R4_TM1_4: (static_cast<B_32_R4_TM1_4*>(busPtr))->Begin(); break;
case I_32_R5_TM1_4: (static_cast<B_32_R5_TM1_4*>(busPtr))->Begin(); break;
case I_32_R6_TM1_4: (static_cast<B_32_R6_TM1_4*>(busPtr))->Begin(); break;
case I_32_R7_TM1_4: (static_cast<B_32_R7_TM1_4*>(busPtr))->Begin(); break;
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->Begin(); break;
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->Begin(); break;
// ESP32 can (and should, to avoid inadvertantly driving the chip select signal) specify the pins used for SPI, but only in begin()
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
#endif
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->Begin(); break;
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->Begin(); break;
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->Begin(); break;
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->Begin(); break;
}
};
static void* create(uint8_t busType, uint8_t* pins, uint16_t len) {
void* busPtr = nullptr;
switch (busType) {
case I_NONE: break;
#ifdef ESP8266
case I_8266_U0_NEO_3: busPtr = new B_8266_U0_NEO_3(len, pins[0]); break;
case I_8266_U1_NEO_3: busPtr = new B_8266_U1_NEO_3(len, pins[0]); break;
case I_8266_DM_NEO_3: busPtr = new B_8266_DM_NEO_3(len, pins[0]); break;
case I_8266_BB_NEO_3: busPtr = new B_8266_BB_NEO_3(len, pins[0]); break;
case I_8266_U0_NEO_4: busPtr = new B_8266_U0_NEO_4(len, pins[0]); break;
case I_8266_U1_NEO_4: busPtr = new B_8266_U1_NEO_4(len, pins[0]); break;
case I_8266_DM_NEO_4: busPtr = new B_8266_DM_NEO_4(len, pins[0]); break;
case I_8266_BB_NEO_4: busPtr = new B_8266_BB_NEO_4(len, pins[0]); break;
case I_8266_U0_400_3: busPtr = new B_8266_U0_400_3(len, pins[0]); break;
case I_8266_U1_400_3: busPtr = new B_8266_U1_400_3(len, pins[0]); break;
case I_8266_DM_400_3: busPtr = new B_8266_DM_400_3(len, pins[0]); break;
case I_8266_BB_400_3: busPtr = new B_8266_BB_400_3(len, pins[0]); break;
case I_8266_U0_TM1_4: busPtr = new B_8266_U0_TM1_4(len, pins[0]); break;
case I_8266_U1_TM1_4: busPtr = new B_8266_U1_TM1_4(len, pins[0]); break;
case I_8266_DM_TM1_4: busPtr = new B_8266_DM_TM1_4(len, pins[0]); break;
case I_8266_BB_TM1_4: busPtr = new B_8266_BB_TM1_4(len, pins[0]); break;
#endif
#ifdef ARDUINO_ARCH_ESP32
case I_32_R0_NEO_3: busPtr = new B_32_R0_NEO_3(len, pins[0]); break;
case I_32_R1_NEO_3: busPtr = new B_32_R1_NEO_3(len, pins[0]); break;
case I_32_R2_NEO_3: busPtr = new B_32_R2_NEO_3(len, pins[0]); break;
case I_32_R3_NEO_3: busPtr = new B_32_R3_NEO_3(len, pins[0]); break;
case I_32_R4_NEO_3: busPtr = new B_32_R4_NEO_3(len, pins[0]); break;
case I_32_R5_NEO_3: busPtr = new B_32_R5_NEO_3(len, pins[0]); break;
case I_32_R6_NEO_3: busPtr = new B_32_R6_NEO_3(len, pins[0]); break;
case I_32_R7_NEO_3: busPtr = new B_32_R7_NEO_3(len, pins[0]); break;
case I_32_I0_NEO_3: busPtr = new B_32_I0_NEO_3(len, pins[0]); break;
case I_32_I1_NEO_3: busPtr = new B_32_I1_NEO_3(len, pins[0]); break;
case I_32_R0_NEO_4: busPtr = new B_32_R0_NEO_4(len, pins[0]); break;
case I_32_R1_NEO_4: busPtr = new B_32_R1_NEO_4(len, pins[0]); break;
case I_32_R2_NEO_4: busPtr = new B_32_R2_NEO_4(len, pins[0]); break;
case I_32_R3_NEO_4: busPtr = new B_32_R3_NEO_4(len, pins[0]); break;
case I_32_R4_NEO_4: busPtr = new B_32_R4_NEO_4(len, pins[0]); break;
case I_32_R5_NEO_4: busPtr = new B_32_R5_NEO_4(len, pins[0]); break;
case I_32_R6_NEO_4: busPtr = new B_32_R6_NEO_4(len, pins[0]); break;
case I_32_R7_NEO_4: busPtr = new B_32_R7_NEO_4(len, pins[0]); break;
case I_32_I0_NEO_4: busPtr = new B_32_I0_NEO_4(len, pins[0]); break;
case I_32_I1_NEO_4: busPtr = new B_32_I1_NEO_4(len, pins[0]); break;
case I_32_R0_400_3: busPtr = new B_32_R0_400_3(len, pins[0]); break;
case I_32_R1_400_3: busPtr = new B_32_R1_400_3(len, pins[0]); break;
case I_32_R2_400_3: busPtr = new B_32_R2_400_3(len, pins[0]); break;
case I_32_R3_400_3: busPtr = new B_32_R3_400_3(len, pins[0]); break;
case I_32_R4_400_3: busPtr = new B_32_R4_400_3(len, pins[0]); break;
case I_32_R5_400_3: busPtr = new B_32_R5_400_3(len, pins[0]); break;
case I_32_R6_400_3: busPtr = new B_32_R6_400_3(len, pins[0]); break;
case I_32_R7_400_3: busPtr = new B_32_R7_400_3(len, pins[0]); break;
case I_32_I0_400_3: busPtr = new B_32_I0_400_3(len, pins[0]); break;
case I_32_I1_400_3: busPtr = new B_32_I1_400_3(len, pins[0]); break;
case I_32_R0_TM1_4: busPtr = new B_32_R0_TM1_4(len, pins[0]); break;
case I_32_R1_TM1_4: busPtr = new B_32_R1_TM1_4(len, pins[0]); break;
case I_32_R2_TM1_4: busPtr = new B_32_R2_TM1_4(len, pins[0]); break;
case I_32_R3_TM1_4: busPtr = new B_32_R3_TM1_4(len, pins[0]); break;
case I_32_R4_TM1_4: busPtr = new B_32_R4_TM1_4(len, pins[0]); break;
case I_32_R5_TM1_4: busPtr = new B_32_R5_TM1_4(len, pins[0]); break;
case I_32_R6_TM1_4: busPtr = new B_32_R6_TM1_4(len, pins[0]); break;
case I_32_R7_TM1_4: busPtr = new B_32_R7_TM1_4(len, pins[0]); break;
case I_32_I0_TM1_4: busPtr = new B_32_I0_TM1_4(len, pins[0]); break;
case I_32_I1_TM1_4: busPtr = new B_32_I1_TM1_4(len, pins[0]); break;
#endif
// for 2-wire: pins[1] is clk, pins[0] is dat. begin expects (len, clk, dat)
case I_HS_DOT_3: busPtr = new B_HS_DOT_3(len, pins[1], pins[0]); break;
case I_SS_DOT_3: busPtr = new B_SS_DOT_3(len, pins[1], pins[0]); break;
case I_HS_LPD_3: busPtr = new B_HS_LPD_3(len, pins[1], pins[0]); break;
case I_SS_LPD_3: busPtr = new B_SS_LPD_3(len, pins[1], pins[0]); break;
case I_HS_WS1_3: busPtr = new B_HS_WS1_3(len, pins[1], pins[0]); break;
case I_SS_WS1_3: busPtr = new B_SS_WS1_3(len, pins[1], pins[0]); break;
case I_HS_P98_3: busPtr = new B_HS_P98_3(len, pins[1], pins[0]); break;
case I_SS_P98_3: busPtr = new B_SS_P98_3(len, pins[1], pins[0]); break;
}
begin(busPtr, busType, pins);
return busPtr;
};
static void show(void* busPtr, uint8_t busType) {
switch (busType) {
case I_NONE: break;
#ifdef ESP8266
case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->Show(); break;
case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->Show(); break;
case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->Show(); break;
case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->Show(); break;
case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->Show(); break;
case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->Show(); break;
case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->Show(); break;
case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->Show(); break;
case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->Show(); break;
case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->Show(); break;
case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->Show(); break;
case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->Show(); break;
case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->Show(); break;
case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->Show(); break;
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->Show(); break;
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->Show(); break;
#endif
#ifdef ARDUINO_ARCH_ESP32
case I_32_R0_NEO_3: (static_cast<B_32_R0_NEO_3*>(busPtr))->Show(); break;
case I_32_R1_NEO_3: (static_cast<B_32_R1_NEO_3*>(busPtr))->Show(); break;
case I_32_R2_NEO_3: (static_cast<B_32_R2_NEO_3*>(busPtr))->Show(); break;
case I_32_R3_NEO_3: (static_cast<B_32_R3_NEO_3*>(busPtr))->Show(); break;
case I_32_R4_NEO_3: (static_cast<B_32_R4_NEO_3*>(busPtr))->Show(); break;
case I_32_R5_NEO_3: (static_cast<B_32_R5_NEO_3*>(busPtr))->Show(); break;
case I_32_R6_NEO_3: (static_cast<B_32_R6_NEO_3*>(busPtr))->Show(); break;
case I_32_R7_NEO_3: (static_cast<B_32_R7_NEO_3*>(busPtr))->Show(); break;
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->Show(); break;
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->Show(); break;
case I_32_R0_NEO_4: (static_cast<B_32_R0_NEO_4*>(busPtr))->Show(); break;
case I_32_R1_NEO_4: (static_cast<B_32_R1_NEO_4*>(busPtr))->Show(); break;
case I_32_R2_NEO_4: (static_cast<B_32_R2_NEO_4*>(busPtr))->Show(); break;
case I_32_R3_NEO_4: (static_cast<B_32_R3_NEO_4*>(busPtr))->Show(); break;
case I_32_R4_NEO_4: (static_cast<B_32_R4_NEO_4*>(busPtr))->Show(); break;
case I_32_R5_NEO_4: (static_cast<B_32_R5_NEO_4*>(busPtr))->Show(); break;
case I_32_R6_NEO_4: (static_cast<B_32_R6_NEO_4*>(busPtr))->Show(); break;
case I_32_R7_NEO_4: (static_cast<B_32_R7_NEO_4*>(busPtr))->Show(); break;
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Show(); break;
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->Show(); break;
case I_32_R0_400_3: (static_cast<B_32_R0_400_3*>(busPtr))->Show(); break;
case I_32_R1_400_3: (static_cast<B_32_R1_400_3*>(busPtr))->Show(); break;
case I_32_R2_400_3: (static_cast<B_32_R2_400_3*>(busPtr))->Show(); break;
case I_32_R3_400_3: (static_cast<B_32_R3_400_3*>(busPtr))->Show(); break;
case I_32_R4_400_3: (static_cast<B_32_R4_400_3*>(busPtr))->Show(); break;
case I_32_R5_400_3: (static_cast<B_32_R5_400_3*>(busPtr))->Show(); break;
case I_32_R6_400_3: (static_cast<B_32_R6_400_3*>(busPtr))->Show(); break;
case I_32_R7_400_3: (static_cast<B_32_R7_400_3*>(busPtr))->Show(); break;
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Show(); break;
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->Show(); break;
case I_32_R0_TM1_4: (static_cast<B_32_R0_TM1_4*>(busPtr))->Show(); break;
case I_32_R1_TM1_4: (static_cast<B_32_R1_TM1_4*>(busPtr))->Show(); break;
case I_32_R2_TM1_4: (static_cast<B_32_R2_TM1_4*>(busPtr))->Show(); break;
case I_32_R3_TM1_4: (static_cast<B_32_R3_TM1_4*>(busPtr))->Show(); break;
case I_32_R4_TM1_4: (static_cast<B_32_R4_TM1_4*>(busPtr))->Show(); break;
case I_32_R5_TM1_4: (static_cast<B_32_R5_TM1_4*>(busPtr))->Show(); break;
case I_32_R6_TM1_4: (static_cast<B_32_R6_TM1_4*>(busPtr))->Show(); break;
case I_32_R7_TM1_4: (static_cast<B_32_R7_TM1_4*>(busPtr))->Show(); break;
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->Show(); break;
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->Show(); break;
#endif
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Show(); break;
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->Show(); break;
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->Show(); break;
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->Show(); break;
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->Show(); break;
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->Show(); break;
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->Show(); break;
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->Show(); break;
}
};
static bool canShow(void* busPtr, uint8_t busType) {
switch (busType) {
case I_NONE: return true;
#ifdef ESP8266
case I_8266_U0_NEO_3: return (static_cast<B_8266_U0_NEO_3*>(busPtr))->CanShow(); break;
case I_8266_U1_NEO_3: return (static_cast<B_8266_U1_NEO_3*>(busPtr))->CanShow(); break;
case I_8266_DM_NEO_3: return (static_cast<B_8266_DM_NEO_3*>(busPtr))->CanShow(); break;
case I_8266_BB_NEO_3: return (static_cast<B_8266_BB_NEO_3*>(busPtr))->CanShow(); break;
case I_8266_U0_NEO_4: return (static_cast<B_8266_U0_NEO_4*>(busPtr))->CanShow(); break;
case I_8266_U1_NEO_4: return (static_cast<B_8266_U1_NEO_4*>(busPtr))->CanShow(); break;
case I_8266_DM_NEO_4: return (static_cast<B_8266_DM_NEO_4*>(busPtr))->CanShow(); break;
case I_8266_BB_NEO_4: return (static_cast<B_8266_BB_NEO_4*>(busPtr))->CanShow(); break;
case I_8266_U0_400_3: return (static_cast<B_8266_U0_400_3*>(busPtr))->CanShow(); break;
case I_8266_U1_400_3: return (static_cast<B_8266_U1_400_3*>(busPtr))->CanShow(); break;
case I_8266_DM_400_3: return (static_cast<B_8266_DM_400_3*>(busPtr))->CanShow(); break;
case I_8266_BB_400_3: return (static_cast<B_8266_BB_400_3*>(busPtr))->CanShow(); break;
case I_8266_U0_TM1_4: return (static_cast<B_8266_U0_TM1_4*>(busPtr))->CanShow(); break;
case I_8266_U1_TM1_4: return (static_cast<B_8266_U1_TM1_4*>(busPtr))->CanShow(); break;
case I_8266_DM_TM1_4: return (static_cast<B_8266_DM_TM1_4*>(busPtr))->CanShow(); break;
case I_8266_BB_TM1_4: return (static_cast<B_8266_BB_TM1_4*>(busPtr))->CanShow(); break;
#endif
#ifdef ARDUINO_ARCH_ESP32
case I_32_R0_NEO_3: return (static_cast<B_32_R0_NEO_3*>(busPtr))->CanShow(); break;
case I_32_R1_NEO_3: return (static_cast<B_32_R1_NEO_3*>(busPtr))->CanShow(); break;
case I_32_R2_NEO_3: return (static_cast<B_32_R2_NEO_3*>(busPtr))->CanShow(); break;
case I_32_R3_NEO_3: return (static_cast<B_32_R3_NEO_3*>(busPtr))->CanShow(); break;
case I_32_R4_NEO_3: return (static_cast<B_32_R4_NEO_3*>(busPtr))->CanShow(); break;
case I_32_R5_NEO_3: return (static_cast<B_32_R5_NEO_3*>(busPtr))->CanShow(); break;
case I_32_R6_NEO_3: return (static_cast<B_32_R6_NEO_3*>(busPtr))->CanShow(); break;
case I_32_R7_NEO_3: return (static_cast<B_32_R7_NEO_3*>(busPtr))->CanShow(); break;
case I_32_I0_NEO_3: return (static_cast<B_32_I0_NEO_3*>(busPtr))->CanShow(); break;
case I_32_I1_NEO_3: return (static_cast<B_32_I1_NEO_3*>(busPtr))->CanShow(); break;
case I_32_R0_NEO_4: return (static_cast<B_32_R0_NEO_4*>(busPtr))->CanShow(); break;
case I_32_R1_NEO_4: return (static_cast<B_32_R1_NEO_4*>(busPtr))->CanShow(); break;
case I_32_R2_NEO_4: return (static_cast<B_32_R2_NEO_4*>(busPtr))->CanShow(); break;
case I_32_R3_NEO_4: return (static_cast<B_32_R3_NEO_4*>(busPtr))->CanShow(); break;
case I_32_R4_NEO_4: return (static_cast<B_32_R4_NEO_4*>(busPtr))->CanShow(); break;
case I_32_R5_NEO_4: return (static_cast<B_32_R5_NEO_4*>(busPtr))->CanShow(); break;
case I_32_R6_NEO_4: return (static_cast<B_32_R6_NEO_4*>(busPtr))->CanShow(); break;
case I_32_R7_NEO_4: return (static_cast<B_32_R7_NEO_4*>(busPtr))->CanShow(); break;
case I_32_I0_NEO_4: return (static_cast<B_32_I0_NEO_4*>(busPtr))->CanShow(); break;
case I_32_I1_NEO_4: return (static_cast<B_32_I1_NEO_4*>(busPtr))->CanShow(); break;
case I_32_R0_400_3: return (static_cast<B_32_R0_400_3*>(busPtr))->CanShow(); break;
case I_32_R1_400_3: return (static_cast<B_32_R1_400_3*>(busPtr))->CanShow(); break;
case I_32_R2_400_3: return (static_cast<B_32_R2_400_3*>(busPtr))->CanShow(); break;
case I_32_R3_400_3: return (static_cast<B_32_R3_400_3*>(busPtr))->CanShow(); break;
case I_32_R4_400_3: return (static_cast<B_32_R4_400_3*>(busPtr))->CanShow(); break;
case I_32_R5_400_3: return (static_cast<B_32_R5_400_3*>(busPtr))->CanShow(); break;
case I_32_R6_400_3: return (static_cast<B_32_R6_400_3*>(busPtr))->CanShow(); break;
case I_32_R7_400_3: return (static_cast<B_32_R7_400_3*>(busPtr))->CanShow(); break;
case I_32_I0_400_3: return (static_cast<B_32_I0_400_3*>(busPtr))->CanShow(); break;
case I_32_I1_400_3: return (static_cast<B_32_I1_400_3*>(busPtr))->CanShow(); break;
case I_32_R0_TM1_4: return (static_cast<B_32_R0_TM1_4*>(busPtr))->CanShow(); break;
case I_32_R1_TM1_4: return (static_cast<B_32_R1_TM1_4*>(busPtr))->CanShow(); break;
case I_32_R2_TM1_4: return (static_cast<B_32_R2_TM1_4*>(busPtr))->CanShow(); break;
case I_32_R3_TM1_4: return (static_cast<B_32_R3_TM1_4*>(busPtr))->CanShow(); break;
case I_32_R4_TM1_4: return (static_cast<B_32_R4_TM1_4*>(busPtr))->CanShow(); break;
case I_32_R5_TM1_4: return (static_cast<B_32_R5_TM1_4*>(busPtr))->CanShow(); break;
case I_32_R6_TM1_4: return (static_cast<B_32_R6_TM1_4*>(busPtr))->CanShow(); break;
case I_32_R7_TM1_4: return (static_cast<B_32_R7_TM1_4*>(busPtr))->CanShow(); break;
case I_32_I0_TM1_4: return (static_cast<B_32_I0_TM1_4*>(busPtr))->CanShow(); break;
case I_32_I1_TM1_4: return (static_cast<B_32_I1_TM1_4*>(busPtr))->CanShow(); break;
#endif
case I_HS_DOT_3: return (static_cast<B_HS_DOT_3*>(busPtr))->CanShow(); break;
case I_SS_DOT_3: return (static_cast<B_SS_DOT_3*>(busPtr))->CanShow(); break;
case I_HS_LPD_3: return (static_cast<B_HS_LPD_3*>(busPtr))->CanShow(); break;
case I_SS_LPD_3: return (static_cast<B_SS_LPD_3*>(busPtr))->CanShow(); break;
case I_HS_WS1_3: return (static_cast<B_HS_WS1_3*>(busPtr))->CanShow(); break;
case I_SS_WS1_3: return (static_cast<B_SS_WS1_3*>(busPtr))->CanShow(); break;
case I_HS_P98_3: return (static_cast<B_HS_P98_3*>(busPtr))->CanShow(); break;
case I_SS_P98_3: return (static_cast<B_SS_P98_3*>(busPtr))->CanShow(); break;
}
return true;
};
static void setPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint32_t c, uint8_t co) {
uint8_t r = c >> 16;
uint8_t g = c >> 8;
uint8_t b = c >> 0;
uint8_t w = c >> 24;
RgbwColor col;
//TODO make color order override possible on a per-strip basis
#ifdef COLOR_ORDER_OVERRIDE
if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER;
#endif
//reorder channels to selected order
switch (co)
{
case 0: col.G = g; col.R = r; col.B = b; break; //0 = GRB, default
case 1: col.G = r; col.R = g; col.B = b; break; //1 = RGB, common for WS2811
case 2: col.G = b; col.R = r; col.B = g; break; //2 = BRG
case 3: col.G = r; col.R = b; col.B = g; break; //3 = RBG
case 4: col.G = b; col.R = g; col.B = r; break; //4 = BGR
default: col.G = g; col.R = b; col.B = r; break; //5 = GBR
}
col.W = w;
switch (busType) {
case I_NONE: break;
#ifdef ESP8266
case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
#endif
#ifdef ARDUINO_ARCH_ESP32
case I_32_R0_NEO_3: (static_cast<B_32_R0_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_R1_NEO_3: (static_cast<B_32_R1_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_R2_NEO_3: (static_cast<B_32_R2_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_R3_NEO_3: (static_cast<B_32_R3_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_R4_NEO_3: (static_cast<B_32_R4_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_R5_NEO_3: (static_cast<B_32_R5_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_R6_NEO_3: (static_cast<B_32_R6_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_R7_NEO_3: (static_cast<B_32_R7_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_R0_NEO_4: (static_cast<B_32_R0_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_R1_NEO_4: (static_cast<B_32_R1_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_R2_NEO_4: (static_cast<B_32_R2_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_R3_NEO_4: (static_cast<B_32_R3_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_R4_NEO_4: (static_cast<B_32_R4_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_R5_NEO_4: (static_cast<B_32_R5_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_R6_NEO_4: (static_cast<B_32_R6_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_R7_NEO_4: (static_cast<B_32_R7_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_R0_400_3: (static_cast<B_32_R0_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_R1_400_3: (static_cast<B_32_R1_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_R2_400_3: (static_cast<B_32_R2_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_R3_400_3: (static_cast<B_32_R3_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_R4_400_3: (static_cast<B_32_R4_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_R5_400_3: (static_cast<B_32_R5_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_R6_400_3: (static_cast<B_32_R6_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_R7_400_3: (static_cast<B_32_R7_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_32_R0_TM1_4: (static_cast<B_32_R0_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_R1_TM1_4: (static_cast<B_32_R1_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_R2_TM1_4: (static_cast<B_32_R2_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_R3_TM1_4: (static_cast<B_32_R3_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_R4_TM1_4: (static_cast<B_32_R4_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_R5_TM1_4: (static_cast<B_32_R5_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_R6_TM1_4: (static_cast<B_32_R6_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_R7_TM1_4: (static_cast<B_32_R7_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
#endif
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
}
};
static void setBrightness(void* busPtr, uint8_t busType, uint8_t b) {
switch (busType) {
case I_NONE: break;
#ifdef ESP8266
case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->SetBrightness(b); break;
case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->SetBrightness(b); break;
case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->SetBrightness(b); break;
case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->SetBrightness(b); break;
case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->SetBrightness(b); break;
case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->SetBrightness(b); break;
case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->SetBrightness(b); break;
case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->SetBrightness(b); break;
case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->SetBrightness(b); break;
case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->SetBrightness(b); break;
case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->SetBrightness(b); break;
case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->SetBrightness(b); break;
case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->SetBrightness(b); break;
case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->SetBrightness(b); break;
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->SetBrightness(b); break;
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->SetBrightness(b); break;
#endif
#ifdef ARDUINO_ARCH_ESP32
case I_32_R0_NEO_3: (static_cast<B_32_R0_NEO_3*>(busPtr))->SetBrightness(b); break;
case I_32_R1_NEO_3: (static_cast<B_32_R1_NEO_3*>(busPtr))->SetBrightness(b); break;
case I_32_R2_NEO_3: (static_cast<B_32_R2_NEO_3*>(busPtr))->SetBrightness(b); break;
case I_32_R3_NEO_3: (static_cast<B_32_R3_NEO_3*>(busPtr))->SetBrightness(b); break;
case I_32_R4_NEO_3: (static_cast<B_32_R4_NEO_3*>(busPtr))->SetBrightness(b); break;
case I_32_R5_NEO_3: (static_cast<B_32_R5_NEO_3*>(busPtr))->SetBrightness(b); break;
case I_32_R6_NEO_3: (static_cast<B_32_R6_NEO_3*>(busPtr))->SetBrightness(b); break;
case I_32_R7_NEO_3: (static_cast<B_32_R7_NEO_3*>(busPtr))->SetBrightness(b); break;
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->SetBrightness(b); break;
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->SetBrightness(b); break;
case I_32_R0_NEO_4: (static_cast<B_32_R0_NEO_4*>(busPtr))->SetBrightness(b); break;
case I_32_R1_NEO_4: (static_cast<B_32_R1_NEO_4*>(busPtr))->SetBrightness(b); break;
case I_32_R2_NEO_4: (static_cast<B_32_R2_NEO_4*>(busPtr))->SetBrightness(b); break;
case I_32_R3_NEO_4: (static_cast<B_32_R3_NEO_4*>(busPtr))->SetBrightness(b); break;
case I_32_R4_NEO_4: (static_cast<B_32_R4_NEO_4*>(busPtr))->SetBrightness(b); break;
case I_32_R5_NEO_4: (static_cast<B_32_R5_NEO_4*>(busPtr))->SetBrightness(b); break;
case I_32_R6_NEO_4: (static_cast<B_32_R6_NEO_4*>(busPtr))->SetBrightness(b); break;
case I_32_R7_NEO_4: (static_cast<B_32_R7_NEO_4*>(busPtr))->SetBrightness(b); break;
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetBrightness(b); break;
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->SetBrightness(b); break;
case I_32_R0_400_3: (static_cast<B_32_R0_400_3*>(busPtr))->SetBrightness(b); break;
case I_32_R1_400_3: (static_cast<B_32_R1_400_3*>(busPtr))->SetBrightness(b); break;
case I_32_R2_400_3: (static_cast<B_32_R2_400_3*>(busPtr))->SetBrightness(b); break;
case I_32_R3_400_3: (static_cast<B_32_R3_400_3*>(busPtr))->SetBrightness(b); break;
case I_32_R4_400_3: (static_cast<B_32_R4_400_3*>(busPtr))->SetBrightness(b); break;
case I_32_R5_400_3: (static_cast<B_32_R5_400_3*>(busPtr))->SetBrightness(b); break;
case I_32_R6_400_3: (static_cast<B_32_R6_400_3*>(busPtr))->SetBrightness(b); break;
case I_32_R7_400_3: (static_cast<B_32_R7_400_3*>(busPtr))->SetBrightness(b); break;
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetBrightness(b); break;
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->SetBrightness(b); break;
case I_32_R0_TM1_4: (static_cast<B_32_R0_TM1_4*>(busPtr))->SetBrightness(b); break;
case I_32_R1_TM1_4: (static_cast<B_32_R1_TM1_4*>(busPtr))->SetBrightness(b); break;
case I_32_R2_TM1_4: (static_cast<B_32_R2_TM1_4*>(busPtr))->SetBrightness(b); break;
case I_32_R3_TM1_4: (static_cast<B_32_R3_TM1_4*>(busPtr))->SetBrightness(b); break;
case I_32_R4_TM1_4: (static_cast<B_32_R4_TM1_4*>(busPtr))->SetBrightness(b); break;
case I_32_R5_TM1_4: (static_cast<B_32_R5_TM1_4*>(busPtr))->SetBrightness(b); break;
case I_32_R6_TM1_4: (static_cast<B_32_R6_TM1_4*>(busPtr))->SetBrightness(b); break;
case I_32_R7_TM1_4: (static_cast<B_32_R7_TM1_4*>(busPtr))->SetBrightness(b); break;
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->SetBrightness(b); break;
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->SetBrightness(b); break;
#endif
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetBrightness(b); break;
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->SetBrightness(b); break;
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->SetBrightness(b); break;
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->SetBrightness(b); break;
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->SetBrightness(b); break;
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->SetBrightness(b); break;
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetBrightness(b); break;
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetBrightness(b); break;
}
};
static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) {
RgbwColor col(0,0,0,0);
switch (busType) {
case I_NONE: break;
#ifdef ESP8266
case I_8266_U0_NEO_3: col = (static_cast<B_8266_U0_NEO_3*>(busPtr))->GetPixelColor(pix); break;
case I_8266_U1_NEO_3: col = (static_cast<B_8266_U1_NEO_3*>(busPtr))->GetPixelColor(pix); break;
case I_8266_DM_NEO_3: col = (static_cast<B_8266_DM_NEO_3*>(busPtr))->GetPixelColor(pix); break;
case I_8266_BB_NEO_3: col = (static_cast<B_8266_BB_NEO_3*>(busPtr))->GetPixelColor(pix); break;
case I_8266_U0_NEO_4: col = (static_cast<B_8266_U0_NEO_4*>(busPtr))->GetPixelColor(pix); break;
case I_8266_U1_NEO_4: col = (static_cast<B_8266_U1_NEO_4*>(busPtr))->GetPixelColor(pix); break;
case I_8266_DM_NEO_4: col = (static_cast<B_8266_DM_NEO_4*>(busPtr))->GetPixelColor(pix); break;
case I_8266_BB_NEO_4: col = (static_cast<B_8266_BB_NEO_4*>(busPtr))->GetPixelColor(pix); break;
case I_8266_U0_400_3: col = (static_cast<B_8266_U0_400_3*>(busPtr))->GetPixelColor(pix); break;
case I_8266_U1_400_3: col = (static_cast<B_8266_U1_400_3*>(busPtr))->GetPixelColor(pix); break;
case I_8266_DM_400_3: col = (static_cast<B_8266_DM_400_3*>(busPtr))->GetPixelColor(pix); break;
case I_8266_BB_400_3: col = (static_cast<B_8266_BB_400_3*>(busPtr))->GetPixelColor(pix); break;
case I_8266_U0_TM1_4: col = (static_cast<B_8266_U0_TM1_4*>(busPtr))->GetPixelColor(pix); break;
case I_8266_U1_TM1_4: col = (static_cast<B_8266_U1_TM1_4*>(busPtr))->GetPixelColor(pix); break;
case I_8266_DM_TM1_4: col = (static_cast<B_8266_DM_TM1_4*>(busPtr))->GetPixelColor(pix); break;
case I_8266_BB_TM1_4: col = (static_cast<B_8266_BB_TM1_4*>(busPtr))->GetPixelColor(pix); break;
#endif
#ifdef ARDUINO_ARCH_ESP32
case I_32_R0_NEO_3: col = (static_cast<B_32_R0_NEO_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_R1_NEO_3: col = (static_cast<B_32_R1_NEO_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_R2_NEO_3: col = (static_cast<B_32_R2_NEO_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_R3_NEO_3: col = (static_cast<B_32_R3_NEO_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_R4_NEO_3: col = (static_cast<B_32_R4_NEO_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_R5_NEO_3: col = (static_cast<B_32_R5_NEO_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_R6_NEO_3: col = (static_cast<B_32_R6_NEO_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_R7_NEO_3: col = (static_cast<B_32_R7_NEO_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_I0_NEO_3: col = (static_cast<B_32_I0_NEO_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_I1_NEO_3: col = (static_cast<B_32_I1_NEO_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_R0_NEO_4: col = (static_cast<B_32_R0_NEO_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_R1_NEO_4: col = (static_cast<B_32_R1_NEO_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_R2_NEO_4: col = (static_cast<B_32_R2_NEO_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_R3_NEO_4: col = (static_cast<B_32_R3_NEO_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_R4_NEO_4: col = (static_cast<B_32_R4_NEO_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_R5_NEO_4: col = (static_cast<B_32_R5_NEO_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_R6_NEO_4: col = (static_cast<B_32_R6_NEO_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_R7_NEO_4: col = (static_cast<B_32_R7_NEO_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_I0_NEO_4: col = (static_cast<B_32_I0_NEO_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_I1_NEO_4: col = (static_cast<B_32_I1_NEO_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_R0_400_3: col = (static_cast<B_32_R0_400_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_R1_400_3: col = (static_cast<B_32_R1_400_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_R2_400_3: col = (static_cast<B_32_R2_400_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_R3_400_3: col = (static_cast<B_32_R3_400_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_R4_400_3: col = (static_cast<B_32_R4_400_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_R5_400_3: col = (static_cast<B_32_R5_400_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_R6_400_3: col = (static_cast<B_32_R6_400_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_R7_400_3: col = (static_cast<B_32_R7_400_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_I0_400_3: col = (static_cast<B_32_I0_400_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_I1_400_3: col = (static_cast<B_32_I1_400_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_R0_TM1_4: col = (static_cast<B_32_R0_TM1_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_R1_TM1_4: col = (static_cast<B_32_R1_TM1_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_R2_TM1_4: col = (static_cast<B_32_R2_TM1_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_R3_TM1_4: col = (static_cast<B_32_R3_TM1_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_R4_TM1_4: col = (static_cast<B_32_R4_TM1_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_R5_TM1_4: col = (static_cast<B_32_R5_TM1_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_R6_TM1_4: col = (static_cast<B_32_R6_TM1_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_R7_TM1_4: col = (static_cast<B_32_R7_TM1_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_I0_TM1_4: col = (static_cast<B_32_I0_TM1_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_I1_TM1_4: col = (static_cast<B_32_I1_TM1_4*>(busPtr))->GetPixelColor(pix); break;
#endif
case I_HS_DOT_3: col = (static_cast<B_HS_DOT_3*>(busPtr))->GetPixelColor(pix); break;
case I_SS_DOT_3: col = (static_cast<B_SS_DOT_3*>(busPtr))->GetPixelColor(pix); break;
case I_HS_LPD_3: col = (static_cast<B_HS_LPD_3*>(busPtr))->GetPixelColor(pix); break;
case I_SS_LPD_3: col = (static_cast<B_SS_LPD_3*>(busPtr))->GetPixelColor(pix); break;
case I_HS_WS1_3: col = (static_cast<B_HS_WS1_3*>(busPtr))->GetPixelColor(pix); break;
case I_SS_WS1_3: col = (static_cast<B_SS_WS1_3*>(busPtr))->GetPixelColor(pix); break;
case I_HS_P98_3: col = (static_cast<B_HS_P98_3*>(busPtr))->GetPixelColor(pix); break;
case I_SS_P98_3: col = (static_cast<B_SS_P98_3*>(busPtr))->GetPixelColor(pix); break;
}
#ifdef COLOR_ORDER_OVERRIDE
if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER;
#endif
switch (co)
{
// W G R B
case 0: return ((col.W << 24) | (col.G << 8) | (col.R << 16) | (col.B)); //0 = GRB, default
case 1: return ((col.W << 24) | (col.R << 8) | (col.G << 16) | (col.B)); //1 = RGB, common for WS2811
case 2: return ((col.W << 24) | (col.B << 8) | (col.R << 16) | (col.G)); //2 = BRG
case 3: return ((col.W << 24) | (col.B << 8) | (col.G << 16) | (col.R)); //3 = RBG
case 4: return ((col.W << 24) | (col.R << 8) | (col.B << 16) | (col.G)); //4 = BGR
case 5: return ((col.W << 24) | (col.G << 8) | (col.B << 16) | (col.R)); //5 = GBR
}
return 0;
}
static void cleanup(void* busPtr, uint8_t busType) {
if (busPtr == nullptr) return;
switch (busType) {
case I_NONE: break;
#ifdef ESP8266
case I_8266_U0_NEO_3: delete (static_cast<B_8266_U0_NEO_3*>(busPtr)); break;
case I_8266_U1_NEO_3: delete (static_cast<B_8266_U1_NEO_3*>(busPtr)); break;
case I_8266_DM_NEO_3: delete (static_cast<B_8266_DM_NEO_3*>(busPtr)); break;
case I_8266_BB_NEO_3: delete (static_cast<B_8266_BB_NEO_3*>(busPtr)); break;
case I_8266_U0_NEO_4: delete (static_cast<B_8266_U0_NEO_4*>(busPtr)); break;
case I_8266_U1_NEO_4: delete (static_cast<B_8266_U1_NEO_4*>(busPtr)); break;
case I_8266_DM_NEO_4: delete (static_cast<B_8266_DM_NEO_4*>(busPtr)); break;
case I_8266_BB_NEO_4: delete (static_cast<B_8266_BB_NEO_4*>(busPtr)); break;
case I_8266_U0_400_3: delete (static_cast<B_8266_U0_400_3*>(busPtr)); break;
case I_8266_U1_400_3: delete (static_cast<B_8266_U1_400_3*>(busPtr)); break;
case I_8266_DM_400_3: delete (static_cast<B_8266_DM_400_3*>(busPtr)); break;
case I_8266_BB_400_3: delete (static_cast<B_8266_BB_400_3*>(busPtr)); break;
case I_8266_U0_TM1_4: delete (static_cast<B_8266_U0_TM1_4*>(busPtr)); break;
case I_8266_U1_TM1_4: delete (static_cast<B_8266_U1_TM1_4*>(busPtr)); break;
case I_8266_DM_TM1_4: delete (static_cast<B_8266_DM_TM1_4*>(busPtr)); break;
case I_8266_BB_TM1_4: delete (static_cast<B_8266_BB_TM1_4*>(busPtr)); break;
#endif
#ifdef ARDUINO_ARCH_ESP32
case I_32_R0_NEO_3: delete (static_cast<B_32_R0_NEO_3*>(busPtr)); break;
case I_32_R1_NEO_3: delete (static_cast<B_32_R1_NEO_3*>(busPtr)); break;
case I_32_R2_NEO_3: delete (static_cast<B_32_R2_NEO_3*>(busPtr)); break;
case I_32_R3_NEO_3: delete (static_cast<B_32_R3_NEO_3*>(busPtr)); break;
case I_32_R4_NEO_3: delete (static_cast<B_32_R4_NEO_3*>(busPtr)); break;
case I_32_R5_NEO_3: delete (static_cast<B_32_R5_NEO_3*>(busPtr)); break;
case I_32_R6_NEO_3: delete (static_cast<B_32_R6_NEO_3*>(busPtr)); break;
case I_32_R7_NEO_3: delete (static_cast<B_32_R7_NEO_3*>(busPtr)); break;
case I_32_I0_NEO_3: delete (static_cast<B_32_I0_NEO_3*>(busPtr)); break;
case I_32_I1_NEO_3: delete (static_cast<B_32_I1_NEO_3*>(busPtr)); break;
case I_32_R0_NEO_4: delete (static_cast<B_32_R0_NEO_4*>(busPtr)); break;
case I_32_R1_NEO_4: delete (static_cast<B_32_R1_NEO_4*>(busPtr)); break;
case I_32_R2_NEO_4: delete (static_cast<B_32_R2_NEO_4*>(busPtr)); break;
case I_32_R3_NEO_4: delete (static_cast<B_32_R3_NEO_4*>(busPtr)); break;
case I_32_R4_NEO_4: delete (static_cast<B_32_R4_NEO_4*>(busPtr)); break;
case I_32_R5_NEO_4: delete (static_cast<B_32_R5_NEO_4*>(busPtr)); break;
case I_32_R6_NEO_4: delete (static_cast<B_32_R6_NEO_4*>(busPtr)); break;
case I_32_R7_NEO_4: delete (static_cast<B_32_R7_NEO_4*>(busPtr)); break;
case I_32_I0_NEO_4: delete (static_cast<B_32_I0_NEO_4*>(busPtr)); break;
case I_32_I1_NEO_4: delete (static_cast<B_32_I1_NEO_4*>(busPtr)); break;
case I_32_R0_400_3: delete (static_cast<B_32_R0_400_3*>(busPtr)); break;
case I_32_R1_400_3: delete (static_cast<B_32_R1_400_3*>(busPtr)); break;
case I_32_R2_400_3: delete (static_cast<B_32_R2_400_3*>(busPtr)); break;
case I_32_R3_400_3: delete (static_cast<B_32_R3_400_3*>(busPtr)); break;
case I_32_R4_400_3: delete (static_cast<B_32_R4_400_3*>(busPtr)); break;
case I_32_R5_400_3: delete (static_cast<B_32_R5_400_3*>(busPtr)); break;
case I_32_R6_400_3: delete (static_cast<B_32_R6_400_3*>(busPtr)); break;
case I_32_R7_400_3: delete (static_cast<B_32_R7_400_3*>(busPtr)); break;
case I_32_I0_400_3: delete (static_cast<B_32_I0_400_3*>(busPtr)); break;
case I_32_I1_400_3: delete (static_cast<B_32_I1_400_3*>(busPtr)); break;
case I_32_R0_TM1_4: delete (static_cast<B_32_R0_TM1_4*>(busPtr)); break;
case I_32_R1_TM1_4: delete (static_cast<B_32_R1_TM1_4*>(busPtr)); break;
case I_32_R2_TM1_4: delete (static_cast<B_32_R2_TM1_4*>(busPtr)); break;
case I_32_R3_TM1_4: delete (static_cast<B_32_R3_TM1_4*>(busPtr)); break;
case I_32_R4_TM1_4: delete (static_cast<B_32_R4_TM1_4*>(busPtr)); break;
case I_32_R5_TM1_4: delete (static_cast<B_32_R5_TM1_4*>(busPtr)); break;
case I_32_R6_TM1_4: delete (static_cast<B_32_R6_TM1_4*>(busPtr)); break;
case I_32_R7_TM1_4: delete (static_cast<B_32_R7_TM1_4*>(busPtr)); break;
case I_32_I0_TM1_4: delete (static_cast<B_32_I0_TM1_4*>(busPtr)); break;
case I_32_I1_TM1_4: delete (static_cast<B_32_I1_TM1_4*>(busPtr)); break;
#endif
case I_HS_DOT_3: delete (static_cast<B_HS_DOT_3*>(busPtr)); break;
case I_SS_DOT_3: delete (static_cast<B_SS_DOT_3*>(busPtr)); break;
case I_HS_LPD_3: delete (static_cast<B_HS_LPD_3*>(busPtr)); break;
case I_SS_LPD_3: delete (static_cast<B_SS_LPD_3*>(busPtr)); break;
case I_HS_WS1_3: delete (static_cast<B_HS_WS1_3*>(busPtr)); break;
case I_SS_WS1_3: delete (static_cast<B_SS_WS1_3*>(busPtr)); break;
case I_HS_P98_3: delete (static_cast<B_HS_P98_3*>(busPtr)); break;
case I_SS_P98_3: delete (static_cast<B_SS_P98_3*>(busPtr)); break;
}
}
//gives back the internal type index (I_XX_XXX_X above) for the input
static uint8_t getI(uint8_t busType, uint8_t* pins, uint8_t num = 0) {
if (!IS_DIGITAL(busType)) return I_NONE;
if (IS_2PIN(busType)) { //SPI LED chips
bool isHSPI = false;
#ifdef ESP8266
if (pins[0] == P_8266_HS_MOSI && pins[1] == P_8266_HS_CLK) isHSPI = true;
#else
if(!num) isHSPI = true; // temporary hack to limit use of hardware SPI to a single SPI peripheral: only allow ESP32 hardware serial on segment 0
#endif
uint8_t t = I_NONE;
switch (busType) {
case TYPE_APA102: t = I_SS_DOT_3; break;
case TYPE_LPD8806: t = I_SS_LPD_3; break;
case TYPE_WS2801: t = I_SS_WS1_3; break;
case TYPE_P9813: t = I_SS_P98_3; break;
default: t=I_NONE;
}
if (t > I_NONE && isHSPI) t--; //hardware SPI has one smaller ID than software
return t;
} else {
#ifdef ESP8266
uint8_t offset = pins[0] -1; //for driver: 0 = uart0, 1 = uart1, 2 = dma, 3 = bitbang
if (offset > 3) offset = 3;
switch (busType) {
case TYPE_WS2812_RGB:
case TYPE_WS2812_WWA:
return I_8266_U0_NEO_3 + offset;
case TYPE_SK6812_RGBW:
return I_8266_U0_NEO_4 + offset;
case TYPE_WS2811_400KHZ:
return I_8266_U0_400_3 + offset;
}
#else //ESP32
uint8_t offset = num; //RMT bus # == bus index in BusManager
if (offset > 9) return I_NONE;
switch (busType) {
case TYPE_WS2812_RGB:
case TYPE_WS2812_WWA:
return I_32_R0_NEO_3 + offset;
case TYPE_SK6812_RGBW:
return I_32_R0_NEO_4 + offset;
case TYPE_WS2811_400KHZ:
return I_32_R0_400_3 + offset;
}
#endif
}
return I_NONE;
}
};
#endif

View File

@ -17,9 +17,7 @@ void shortPressAction()
bool isButtonPressed() bool isButtonPressed()
{ {
#if defined(BTNPIN) && BTNPIN > -1 if (btnPin>=0 && digitalRead(btnPin) == LOW) return true;
if (digitalRead(BTNPIN) == LOW) return true;
#endif
#ifdef TOUCHPIN #ifdef TOUCHPIN
if (touchRead(TOUCHPIN) <= TOUCH_THRESHOLD) return true; if (touchRead(TOUCHPIN) <= TOUCH_THRESHOLD) return true;
#endif #endif
@ -29,8 +27,7 @@ bool isButtonPressed()
void handleButton() void handleButton()
{ {
#if (defined(BTNPIN) && BTNPIN > -1) || defined(TOUCHPIN) if (btnPin<0 || !buttonEnabled) return;
if (!buttonEnabled) return;
if (isButtonPressed()) //pressed if (isButtonPressed()) //pressed
{ {
@ -75,7 +72,6 @@ void handleButton()
buttonWaitTime = 0; buttonWaitTime = 0;
shortPressAction(); shortPressAction();
} }
#endif
} }
void handleIO() void handleIO()
@ -88,37 +84,39 @@ void handleIO()
lastOnTime = millis(); lastOnTime = millis();
if (offMode) if (offMode)
{ {
#if RLYPIN >= 0 if (rlyPin>=0) {
digitalWrite(RLYPIN, RLYMDE); pinMode(rlyPin, OUTPUT);
#endif digitalWrite(rlyPin, rlyMde);
}
offMode = false; offMode = false;
} }
} else if (millis() - lastOnTime > 600) } else if (millis() - lastOnTime > 600)
{ {
if (!offMode) { if (!offMode) {
#if LEDPIN == LED_BUILTIN #ifdef ESP8266
//turn off built-in LED if strip is turned off
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH); digitalWrite(LED_BUILTIN, HIGH);
#endif #endif
#if RLYPIN >= 0 if (rlyPin>=0) {
digitalWrite(RLYPIN, !RLYMDE); pinMode(rlyPin, OUTPUT);
#endif digitalWrite(rlyPin, !rlyMde);
}
} }
offMode = true; offMode = true;
} }
#if AUXPIN >= 0
//output //output
if (auxActive || auxActiveBefore) if (auxPin>=1 && (auxActive || auxActiveBefore))
{ {
if (!auxActiveBefore) if (!auxActiveBefore)
{ {
auxActiveBefore = true; auxActiveBefore = true;
switch (auxTriggeredState) switch (auxTriggeredState)
{ {
case 0: pinMode(AUXPIN, INPUT); break; case 0: pinMode(auxPin, INPUT); break;
case 1: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, HIGH); break; case 1: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, HIGH); break;
case 2: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, LOW); break; case 2: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, LOW); break;
} }
auxStartTime = millis(); auxStartTime = millis();
} }
@ -128,11 +126,10 @@ void handleIO()
auxActiveBefore = false; auxActiveBefore = false;
switch (auxDefaultState) switch (auxDefaultState)
{ {
case 0: pinMode(AUXPIN, INPUT); break; case 0: pinMode(auxPin, INPUT); break;
case 1: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, HIGH); break; case 1: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, HIGH); break;
case 2: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, LOW); break; case 2: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, LOW); break;
} }
} }
} }
#endif
} }

View File

@ -30,14 +30,12 @@ void deserializeConfig() {
return; return;
} }
//deserializeJson(doc, json); //int rev_major = doc["rev"][0]; // 1
//int rev_minor = doc["rev"][1]; // 0
//int rev_major = doc[F("rev")][0]; // 1
//int rev_minor = doc[F("rev")][1]; // 0
//long vid = doc[F("vid")]; // 2010020 //long vid = doc[F("vid")]; // 2010020
JsonObject id = doc[F("id")]; JsonObject id = doc["id"];
getStringFromJson(cmDNS, id[F("mdns")], 33); getStringFromJson(cmDNS, id[F("mdns")], 33);
getStringFromJson(serverDescription, id[F("name")], 33); getStringFromJson(serverDescription, id[F("name")], 33);
getStringFromJson(alexaInvocationName, id[F("inv")], 33); getStringFromJson(alexaInvocationName, id[F("inv")], 33);
@ -49,9 +47,9 @@ void deserializeConfig() {
//If it is present however, we will use it //If it is present however, we will use it
getStringFromJson(clientPass, nw_ins_0["psk"], 65); getStringFromJson(clientPass, nw_ins_0["psk"], 65);
JsonArray nw_ins_0_ip = nw_ins_0[F("ip")]; JsonArray nw_ins_0_ip = nw_ins_0["ip"];
JsonArray nw_ins_0_gw = nw_ins_0[F("gw")]; JsonArray nw_ins_0_gw = nw_ins_0["gw"];
JsonArray nw_ins_0_sn = nw_ins_0[F("sn")]; JsonArray nw_ins_0_sn = nw_ins_0["sn"];
for (byte i = 0; i < 4; i++) { for (byte i = 0; i < 4; i++) {
CJSON(staticIP[i], nw_ins_0_ip[i]); CJSON(staticIP[i], nw_ins_0_ip[i]);
@ -59,7 +57,7 @@ void deserializeConfig() {
CJSON(staticSubnet[i], nw_ins_0_sn[i]); CJSON(staticSubnet[i], nw_ins_0_sn[i]);
} }
JsonObject ap = doc[F("ap")]; JsonObject ap = doc["ap"];
getStringFromJson(apSSID, ap[F("ssid")], 33); getStringFromJson(apSSID, ap[F("ssid")], 33);
getStringFromJson(apPass, ap["psk"] , 65); //normally not present due to security getStringFromJson(apPass, ap["psk"] , 65); //normally not present due to security
//int ap_pskl = ap[F("pskl")]; //int ap_pskl = ap[F("pskl")];
@ -74,11 +72,11 @@ void deserializeConfig() {
#ifdef WLED_USE_ETHERNET #ifdef WLED_USE_ETHERNET
JsonObject ethernet = doc[F("eth")]; JsonObject ethernet = doc[F("eth")];
CJSON(ethernetType, ethernet[F("type")]); CJSON(ethernetType, ethernet["type"]);
#endif #endif
/* /*
JsonArray ap_ip = ap[F("ip")]; JsonArray ap_ip = ap["ip"];
for (byte i = 0; i < 4; i++) { for (byte i = 0; i < 4; i++) {
apIP[i] = ap_ip; apIP[i] = ap_ip;
}*/ }*/
@ -89,44 +87,94 @@ void deserializeConfig() {
JsonObject hw = doc[F("hw")]; JsonObject hw = doc[F("hw")];
// initialize LED pins and lengths prior to other HW
JsonObject hw_led = hw[F("led")]; JsonObject hw_led = hw[F("led")];
CJSON(ledCount, hw_led[F("total")]); CJSON(ledCount, hw_led[F("total")]);
if (ledCount > MAX_LEDS) ledCount = MAX_LEDS; if (ledCount > MAX_LEDS) ledCount = MAX_LEDS;
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]); CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]); CJSON(strip.milliampsPerLed, hw_led[F("ledma")]);
CJSON(strip.reverseMode, hw_led[F("rev")]); CJSON(strip.reverseMode, hw_led["rev"]);
CJSON(strip.rgbwMode, hw_led[F("rgbwm")]); CJSON(strip.rgbwMode, hw_led[F("rgbwm")]);
JsonObject hw_led_ins_0 = hw_led[F("ins")][0]; JsonArray ins = hw_led["ins"];
//bool hw_led_ins_0_en = hw_led_ins_0[F("en")]; // true uint8_t s = 0; //bus iterator
//int hw_led_ins_0_start = hw_led_ins_0[F("start")]; // 0 useRGBW = false;
//int hw_led_ins_0_len = hw_led_ins_0[F("len")]; // 1200 busses.removeAll();
uint32_t mem = 0;
for (JsonObject elm : ins) {
if (s >= WLED_MAX_BUSSES) break;
uint8_t pins[5] = {255, 255, 255, 255, 255};
JsonArray pinArr = elm[F("pin")];
if (pinArr.size() == 0) continue;
pins[0] = pinArr[0];
uint8_t i = 0;
for (int p : pinArr) {
pins[i] = p;
i++;
if (i>4) break;
}
//int hw_led_ins_0_pin_0 = hw_led_ins_0[F("pin")][0]; // 2 uint16_t length = elm[F("len")];
if (length==0) continue;
strip.setColorOrder(hw_led_ins_0[F("order")]); uint8_t colorOrder = (int)elm[F("order")];
//bool hw_led_ins_0_rev = hw_led_ins_0[F("rev")]; // false //only use skip from the first strip (this shouldn't have been in ins obj. but remains here for compatibility)
skipFirstLed = hw_led_ins_0[F("skip")]; // 0 if (s==0) skipFirstLed = elm[F("skip")];
useRGBW = (hw_led_ins_0[F("type")] == TYPE_SK6812_RGBW); uint16_t start = elm[F("start")] | 0;
if (start >= ledCount) continue;
//limit length of strip if it would exceed total configured LEDs
if (start + length > ledCount) length = ledCount - start;
uint8_t ledType = elm["type"] | TYPE_WS2812_RGB;
bool reversed = elm["rev"];
//RGBW mode is enabled if at least one of the strips is RGBW
useRGBW = (useRGBW || BusManager::isRgbw(ledType));
s++;
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed);
mem += busses.memUsage(bc);
if (mem <= MAX_LED_MEMORY) busses.add(bc);
}
strip.finalizeInit(useRGBW, ledCount, skipFirstLed);
JsonObject hw_btn_ins_0 = hw[F("btn")][F("ins")][0]; JsonObject hw_btn_ins_0 = hw[F("btn")][F("ins")][0];
buttonEnabled = hw_btn_ins_0[F("en")] | buttonEnabled; CJSON(buttonEnabled, hw_btn_ins_0["type"]);
int hw_btn_pin = hw_btn_ins_0[F("pin")][0];
//int hw_btn_ins_0_pin_0 = hw_btn_ins_0[F("pin")][0]; // 0 if (pinManager.allocatePin(hw_btn_pin,false)) {
btnPin = hw_btn_pin;
pinMode(btnPin, INPUT_PULLUP);
} else {
btnPin = -1;
}
JsonArray hw_btn_ins_0_macros = hw_btn_ins_0[F("macros")]; JsonArray hw_btn_ins_0_macros = hw_btn_ins_0[F("macros")];
CJSON(macroButton, hw_btn_ins_0_macros[0]); CJSON(macroButton, hw_btn_ins_0_macros[0]);
CJSON(macroLongPress,hw_btn_ins_0_macros[1]); CJSON(macroLongPress,hw_btn_ins_0_macros[1]);
CJSON(macroDoublePress, hw_btn_ins_0_macros[2]); CJSON(macroDoublePress, hw_btn_ins_0_macros[2]);
//int hw_btn_ins_0_type = hw_btn_ins_0[F("type")]; // 0 //int hw_btn_ins_0_type = hw_btn_ins_0["type"]; // 0
//int hw_ir_pin = hw[F("ir")][F("pin")]; // 4 #ifndef WLED_DISABLE_INFRARED
CJSON(irEnabled, hw[F("ir")][F("type")]); // 0 int hw_ir_pin = hw["ir"]["pin"]; // 4
if (pinManager.allocatePin(hw_ir_pin,false)) {
irPin = hw_ir_pin;
} else {
irPin = -1;
}
#endif
CJSON(irEnabled, hw["ir"]["type"]);
//int hw_relay_pin = hw[F("relay")][F("pin")]; // 12 JsonObject relay = hw[F("relay")];
//bool hw_relay_rev = hw[F("relay")][F("rev")]; // false
int hw_relay_pin = relay["pin"];
if (pinManager.allocatePin(hw_relay_pin,true)) {
rlyPin = hw_relay_pin;
pinMode(rlyPin, OUTPUT);
} else {
rlyPin = -1;
}
if (relay.containsKey("rev")) {
rlyMde = !relay["rev"];
}
//int hw_status_pin = hw[F("status")][F("pin")]; // -1 //int hw_status_pin = hw[F("status")][F("pin")]; // -1
@ -135,7 +183,7 @@ void deserializeConfig() {
CJSON(strip.paletteBlend, light[F("pal-mode")]); CJSON(strip.paletteBlend, light[F("pal-mode")]);
float light_gc_bri = light[F("gc")]["bri"]; float light_gc_bri = light[F("gc")]["bri"];
float light_gc_col = light[F("gc")][F("col")]; // 2.8 float light_gc_col = light[F("gc")]["col"]; // 2.8
if (light_gc_bri > 1.5) strip.gammaCorrectBri = true; if (light_gc_bri > 1.5) strip.gammaCorrectBri = true;
else if (light_gc_bri > 0.5) strip.gammaCorrectBri = false; else if (light_gc_bri > 0.5) strip.gammaCorrectBri = false;
if (light_gc_col > 1.5) strip.gammaCorrectCol = true; if (light_gc_col > 1.5) strip.gammaCorrectCol = true;
@ -175,13 +223,13 @@ void deserializeConfig() {
CJSON(udpPort, if_sync[F("port0")]); // 21324 CJSON(udpPort, if_sync[F("port0")]); // 21324
CJSON(udpPort2, if_sync[F("port1")]); // 65506 CJSON(udpPort2, if_sync[F("port1")]); // 65506
JsonObject if_sync_recv = if_sync[F("recv")]; JsonObject if_sync_recv = if_sync["recv"];
CJSON(receiveNotificationBrightness, if_sync_recv["bri"]); CJSON(receiveNotificationBrightness, if_sync_recv["bri"]);
CJSON(receiveNotificationColor, if_sync_recv[F("col")]); CJSON(receiveNotificationColor, if_sync_recv["col"]);
CJSON(receiveNotificationEffects, if_sync_recv[F("fx")]); CJSON(receiveNotificationEffects, if_sync_recv[F("fx")]);
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects); receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
JsonObject if_sync_send = if_sync[F("send")]; JsonObject if_sync_send = if_sync["send"];
CJSON(notifyDirectDefault, if_sync_send[F("dir")]); CJSON(notifyDirectDefault, if_sync_send[F("dir")]);
notifyDirect = notifyDirectDefault; notifyDirect = notifyDirectDefault;
CJSON(notifyButton, if_sync_send[F("btn")]); CJSON(notifyButton, if_sync_send[F("btn")]);
@ -190,9 +238,13 @@ void deserializeConfig() {
CJSON(notifyMacro, if_sync_send[F("macro")]); CJSON(notifyMacro, if_sync_send[F("macro")]);
CJSON(notifyTwice, if_sync_send[F("twice")]); CJSON(notifyTwice, if_sync_send[F("twice")]);
JsonObject if_live = interfaces[F("live")]; JsonObject if_nodes = interfaces["nodes"];
CJSON(receiveDirect, if_live[F("en")]); CJSON(nodeListEnabled, if_nodes[F("list")]);
CJSON(e131Port, if_live[F("port")]); // 5568 CJSON(nodeBroadcastEnabled, if_nodes[F("bcast")]);
JsonObject if_live = interfaces["live"];
CJSON(receiveDirect, if_live["en"]);
CJSON(e131Port, if_live["port"]); // 5568
CJSON(e131Multicast, if_live[F("mc")]); CJSON(e131Multicast, if_live[F("mc")]);
JsonObject if_live_dmx = if_live[F("dmx")]; JsonObject if_live_dmx = if_live[F("dmx")];
@ -212,19 +264,19 @@ void deserializeConfig() {
CJSON(macroAlexaOn, interfaces[F("va")][F("macros")][0]); CJSON(macroAlexaOn, interfaces[F("va")][F("macros")][0]);
CJSON(macroAlexaOff, interfaces[F("va")][F("macros")][1]); CJSON(macroAlexaOff, interfaces[F("va")][F("macros")][1]);
const char* apikey = interfaces[F("blynk")][F("token")] | "Hidden"; const char* apikey = interfaces["blynk"][F("token")] | "Hidden";
tdd = strnlen(apikey, 36); tdd = strnlen(apikey, 36);
if (tdd > 20 || tdd == 0) if (tdd > 20 || tdd == 0)
getStringFromJson(blynkApiKey, apikey, 36); //normally not present due to security getStringFromJson(blynkApiKey, apikey, 36); //normally not present due to security
JsonObject if_blynk = interfaces[F("blynk")]; JsonObject if_blynk = interfaces["blynk"];
getStringFromJson(blynkHost, if_blynk[F("host")], 33); getStringFromJson(blynkHost, if_blynk[F("host")], 33);
CJSON(blynkPort, if_blynk[F("port")]); CJSON(blynkPort, if_blynk["port"]);
JsonObject if_mqtt = interfaces[F("mqtt")]; JsonObject if_mqtt = interfaces["mqtt"];
CJSON(mqttEnabled, if_mqtt[F("en")]); CJSON(mqttEnabled, if_mqtt["en"]);
getStringFromJson(mqttServer, if_mqtt[F("broker")], 33); getStringFromJson(mqttServer, if_mqtt[F("broker")], 33);
CJSON(mqttPort, if_mqtt[F("port")]); // 1883 CJSON(mqttPort, if_mqtt["port"]); // 1883
getStringFromJson(mqttUser, if_mqtt[F("user")], 41); getStringFromJson(mqttUser, if_mqtt[F("user")], 41);
getStringFromJson(mqttPass, if_mqtt["psk"], 41); //normally not present due to security getStringFromJson(mqttPass, if_mqtt["psk"], 41); //normally not present due to security
getStringFromJson(mqttClientID, if_mqtt[F("cid")], 41); getStringFromJson(mqttClientID, if_mqtt[F("cid")], 41);
@ -233,23 +285,23 @@ void deserializeConfig() {
getStringFromJson(mqttGroupTopic, if_mqtt[F("topics")][F("group")], 33); // "" getStringFromJson(mqttGroupTopic, if_mqtt[F("topics")][F("group")], 33); // ""
JsonObject if_hue = interfaces[F("hue")]; JsonObject if_hue = interfaces[F("hue")];
CJSON(huePollingEnabled, if_hue[F("en")]); CJSON(huePollingEnabled, if_hue["en"]);
CJSON(huePollLightId, if_hue[F("id")]); CJSON(huePollLightId, if_hue["id"]);
tdd = if_hue[F("iv")] | -1; tdd = if_hue[F("iv")] | -1;
if (tdd >= 2) huePollIntervalMs = tdd * 100; if (tdd >= 2) huePollIntervalMs = tdd * 100;
JsonObject if_hue_recv = if_hue[F("recv")]; JsonObject if_hue_recv = if_hue["recv"];
CJSON(hueApplyOnOff, if_hue_recv["on"]); CJSON(hueApplyOnOff, if_hue_recv["on"]);
CJSON(hueApplyBri, if_hue_recv["bri"]); CJSON(hueApplyBri, if_hue_recv["bri"]);
CJSON(hueApplyColor, if_hue_recv[F("col")]); CJSON(hueApplyColor, if_hue_recv["col"]);
JsonArray if_hue_ip = if_hue[F("ip")]; JsonArray if_hue_ip = if_hue["ip"];
for (byte i = 0; i < 4; i++) for (byte i = 0; i < 4; i++)
CJSON(hueIP[i], if_hue_ip[i]); CJSON(hueIP[i], if_hue_ip[i]);
JsonObject if_ntp = interfaces[F("ntp")]; JsonObject if_ntp = interfaces[F("ntp")];
CJSON(ntpEnabled, if_ntp[F("en")]); CJSON(ntpEnabled, if_ntp["en"]);
getStringFromJson(ntpServerName, if_ntp[F("host")], 33); // "1.wled.pool.ntp.org" getStringFromJson(ntpServerName, if_ntp[F("host")], 33); // "1.wled.pool.ntp.org"
CJSON(currentTimezone, if_ntp[F("tz")]); CJSON(currentTimezone, if_ntp[F("tz")]);
CJSON(utcOffsetSecs, if_ntp[F("offset")]); CJSON(utcOffsetSecs, if_ntp[F("offset")]);
@ -294,7 +346,7 @@ void deserializeConfig() {
CJSON(timerWeekday[it], timer[F("dow")]); CJSON(timerWeekday[it], timer[F("dow")]);
if (timerWeekday[it] != dowPrev) { //present in JSON if (timerWeekday[it] != dowPrev) { //present in JSON
timerWeekday[it] <<= 1; //add active bit timerWeekday[it] <<= 1; //add active bit
int act = timer[F("en")] | actPrev; int act = timer["en"] | actPrev;
if (act) timerWeekday[it]++; if (act) timerWeekday[it]++;
} }
@ -341,7 +393,6 @@ void serializeConfig() {
DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE);
//{ //scope this to reduce stack size
JsonArray rev = doc.createNestedArray("rev"); JsonArray rev = doc.createNestedArray("rev");
rev.add(1); //major settings revision rev.add(1); //major settings revision
rev.add(0); //minor settings revision rev.add(0); //minor settings revision
@ -390,7 +441,7 @@ void serializeConfig() {
#ifdef WLED_USE_ETHERNET #ifdef WLED_USE_ETHERNET
JsonObject ethernet = doc.createNestedObject("eth"); JsonObject ethernet = doc.createNestedObject("eth");
ethernet[F("type")] = ethernetType; ethernet["type"] = ethernetType;
#endif #endif
JsonObject hw = doc.createNestedObject("hw"); JsonObject hw = doc.createNestedObject("hw");
@ -399,83 +450,69 @@ void serializeConfig() {
hw_led[F("total")] = ledCount; hw_led[F("total")] = ledCount;
hw_led[F("maxpwr")] = strip.ablMilliampsMax; hw_led[F("maxpwr")] = strip.ablMilliampsMax;
hw_led[F("ledma")] = strip.milliampsPerLed; hw_led[F("ledma")] = strip.milliampsPerLed;
hw_led[F("rev")] = strip.reverseMode; hw_led["rev"] = strip.reverseMode;
hw_led[F("rgbwm")] = strip.rgbwMode; hw_led[F("rgbwm")] = strip.rgbwMode;
JsonArray hw_led_ins = hw_led.createNestedArray("ins"); JsonArray hw_led_ins = hw_led.createNestedArray("ins");
JsonObject hw_led_ins_0 = hw_led_ins.createNestedObject(); for (uint8_t s = 0; s < busses.getNumBusses(); s++) {
hw_led_ins_0[F("en")] = true; Bus *bus = busses.getBus(s);
hw_led_ins_0[F("start")] = 0; if (!bus || bus->getLength()==0) break;
hw_led_ins_0[F("len")] = ledCount; JsonObject ins = hw_led_ins.createNestedObject();
JsonArray hw_led_ins_0_pin = hw_led_ins_0.createNestedArray("pin"); ins["en"] = true;
hw_led_ins_0_pin.add(LEDPIN); ins[F("start")] = bus->getStart();
#ifdef DATAPIN ins[F("len")] = bus->getLength();
hw_led_ins_0_pin.add(DATAPIN); JsonArray ins_pin = ins.createNestedArray("pin");
#endif uint8_t pins[5];
hw_led_ins_0[F("order")] = strip.getColorOrder(); uint8_t nPins = bus->getPins(pins);
hw_led_ins_0[F("rev")] = false; for (uint8_t i = 0; i < nPins; i++) ins_pin.add(pins[i]);
hw_led_ins_0[F("skip")] = skipFirstLed ? 1 : 0; ins[F("order")] = bus->getColorOrder();
ins["rev"] = bus->reversed;
//this is very crude and temporary ins[F("skip")] = (skipFirstLed && s == 0) ? 1 : 0;
byte ledType = TYPE_WS2812_RGB; ins["type"] = bus->getType();
if (useRGBW) ledType = TYPE_SK6812_RGBW; }
#ifdef USE_WS2801
ledType = TYPE_WS2801;
#endif
#ifdef USE_APA102
ledType = TYPE_APA102;
#endif
#ifdef USE_LPD8806
ledType = TYPE_LPD8806;
#endif
#ifdef USE_P9813
ledType = TYPE_P9813;
#endif
#ifdef USE_TM1814
ledType = TYPE_TM1814;
#endif
hw_led_ins_0[F("type")] = ledType;
JsonObject hw_btn = hw.createNestedObject("btn"); JsonObject hw_btn = hw.createNestedObject("btn");
JsonArray hw_btn_ins = hw_btn.createNestedArray("ins"); JsonArray hw_btn_ins = hw_btn.createNestedArray("ins");
#if defined(BTNPIN) && BTNPIN > -1 // button BTNPIN
JsonObject hw_btn_ins_0 = hw_btn_ins.createNestedObject(); JsonObject hw_btn_ins_0 = hw_btn_ins.createNestedObject();
hw_btn_ins_0[F("type")] = (buttonEnabled) ? BTN_TYPE_PUSH : BTN_TYPE_NONE; hw_btn_ins_0["type"] = (buttonEnabled) ? BTN_TYPE_PUSH : BTN_TYPE_NONE;
JsonArray hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin"); JsonArray hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin");
hw_btn_ins_0_pin.add(BTNPIN); hw_btn_ins_0_pin.add(btnPin);
JsonArray hw_btn_ins_0_macros = hw_btn_ins_0.createNestedArray("macros"); JsonArray hw_btn_ins_0_macros = hw_btn_ins_0.createNestedArray("macros");
hw_btn_ins_0_macros.add(macroButton); hw_btn_ins_0_macros.add(macroButton);
hw_btn_ins_0_macros.add(macroLongPress); hw_btn_ins_0_macros.add(macroLongPress);
hw_btn_ins_0_macros.add(macroDoublePress); hw_btn_ins_0_macros.add(macroDoublePress);
#endif
#if defined(IRPIN) && IRPIN > -1 #ifndef WLED_DISABLE_INFRARED
if (irPin>=0) {
JsonObject hw_ir = hw.createNestedObject("ir"); JsonObject hw_ir = hw.createNestedObject("ir");
hw_ir[F("pin")] = IRPIN; hw_ir["pin"] = irPin;
hw_ir[F("type")] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled ) hw_ir[F("type"] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled )
}
#endif #endif
#if defined(RLYPIN) && RLYPIN > -1 JsonObject hw_relay = hw.createNestedObject(F("relay"));
JsonObject hw_relay = hw.createNestedObject("relay"); hw_relay["pin"] = rlyPin;
hw_relay[F("pin")] = RLYPIN; hw_relay["rev"] = !rlyMde;
hw_relay[F("rev")] = (RLYMDE) ? false : true;
JsonObject hw_status = hw.createNestedObject("status");
hw_status[F("pin")] = -1;
#endif
JsonObject light = doc.createNestedObject("light"); //JsonObject hw_status = hw.createNestedObject("status");
//hw_status["pin"] = -1;
JsonObject hw_aux = hw.createNestedObject("aux");
hw_aux["pin"] = auxPin;
JsonObject light = doc.createNestedObject(F("light"));
light[F("scale-bri")] = briMultiplier; light[F("scale-bri")] = briMultiplier;
light[F("pal-mode")] = strip.paletteBlend; light[F("pal-mode")] = strip.paletteBlend;
JsonObject light_gc = light.createNestedObject("gc"); JsonObject light_gc = light.createNestedObject("gc");
light_gc["bri"] = (strip.gammaCorrectBri) ? 2.8 : 1.0; light_gc["bri"] = (strip.gammaCorrectBri) ? 2.8 : 1.0;
light_gc[F("col")] = (strip.gammaCorrectCol) ? 2.8 : 1.0; light_gc["col"] = (strip.gammaCorrectCol) ? 2.8 : 1.0;
JsonObject light_tr = light.createNestedObject("tr"); JsonObject light_tr = light.createNestedObject("tr");
light_tr[F("mode")] = fadeTransition; light_tr[F("mode")] = fadeTransition;
@ -498,7 +535,7 @@ void serializeConfig() {
JsonObject def_cy = def.createNestedObject("cy"); JsonObject def_cy = def.createNestedObject("cy");
def_cy["on"] = presetCyclingEnabled; def_cy["on"] = presetCyclingEnabled;
JsonArray def_cy_range = def_cy.createNestedArray("range"); JsonArray def_cy_range = def_cy.createNestedArray(F("range"));
def_cy_range.add(presetCycleMin); def_cy_range.add(presetCycleMin);
def_cy_range.add(presetCycleMax); def_cy_range.add(presetCycleMax);
def_cy[F("dur")] = presetCycleTime; def_cy[F("dur")] = presetCycleTime;
@ -512,7 +549,7 @@ void serializeConfig() {
JsonObject if_sync_recv = if_sync.createNestedObject("recv"); JsonObject if_sync_recv = if_sync.createNestedObject("recv");
if_sync_recv["bri"] = receiveNotificationBrightness; if_sync_recv["bri"] = receiveNotificationBrightness;
if_sync_recv[F("col")] = receiveNotificationColor; if_sync_recv["col"] = receiveNotificationColor;
if_sync_recv[F("fx")] = receiveNotificationEffects; if_sync_recv[F("fx")] = receiveNotificationEffects;
JsonObject if_sync_send = if_sync.createNestedObject("send"); JsonObject if_sync_send = if_sync.createNestedObject("send");
@ -523,9 +560,13 @@ void serializeConfig() {
if_sync_send[F("macro")] = notifyMacro; if_sync_send[F("macro")] = notifyMacro;
if_sync_send[F("twice")] = notifyTwice; if_sync_send[F("twice")] = notifyTwice;
JsonObject if_nodes = interfaces.createNestedObject("nodes");
if_nodes[F("list")] = nodeListEnabled;
if_nodes[F("bcast")] = nodeBroadcastEnabled;
JsonObject if_live = interfaces.createNestedObject("live"); JsonObject if_live = interfaces.createNestedObject("live");
if_live[F("en")] = receiveDirect; if_live["en"] = receiveDirect;
if_live[F("port")] = e131Port; if_live["port"] = e131Port;
if_live[F("mc")] = e131Multicast; if_live[F("mc")] = e131Multicast;
JsonObject if_live_dmx = if_live.createNestedObject("dmx"); JsonObject if_live_dmx = if_live.createNestedObject("dmx");
@ -547,29 +588,29 @@ void serializeConfig() {
JsonObject if_blynk = interfaces.createNestedObject("blynk"); JsonObject if_blynk = interfaces.createNestedObject("blynk");
if_blynk[F("token")] = strlen(blynkApiKey) ? "Hidden":""; if_blynk[F("token")] = strlen(blynkApiKey) ? "Hidden":"";
if_blynk[F("host")] = blynkHost; if_blynk[F("host")] = blynkHost;
if_blynk[F("port")] = blynkPort; if_blynk["port"] = blynkPort;
JsonObject if_mqtt = interfaces.createNestedObject("mqtt"); JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
if_mqtt[F("en")] = mqttEnabled; if_mqtt["en"] = mqttEnabled;
if_mqtt[F("broker")] = mqttServer; if_mqtt[F("broker")] = mqttServer;
if_mqtt[F("port")] = mqttPort; if_mqtt["port"] = mqttPort;
if_mqtt[F("user")] = mqttUser; if_mqtt[F("user")] = mqttUser;
if_mqtt[F("pskl")] = strlen(mqttPass); if_mqtt[F("pskl")] = strlen(mqttPass);
if_mqtt[F("cid")] = mqttClientID; if_mqtt[F("cid")] = mqttClientID;
JsonObject if_mqtt_topics = if_mqtt.createNestedObject("topics"); JsonObject if_mqtt_topics = if_mqtt.createNestedObject(F("topics"));
if_mqtt_topics[F("device")] = mqttDeviceTopic; if_mqtt_topics[F("device")] = mqttDeviceTopic;
if_mqtt_topics[F("group")] = mqttGroupTopic; if_mqtt_topics[F("group")] = mqttGroupTopic;
JsonObject if_hue = interfaces.createNestedObject("hue"); JsonObject if_hue = interfaces.createNestedObject("hue");
if_hue[F("en")] = huePollingEnabled; if_hue["en"] = huePollingEnabled;
if_hue[F("id")] = huePollLightId; if_hue["id"] = huePollLightId;
if_hue[F("iv")] = huePollIntervalMs / 100; if_hue[F("iv")] = huePollIntervalMs / 100;
JsonObject if_hue_recv = if_hue.createNestedObject("recv"); JsonObject if_hue_recv = if_hue.createNestedObject("recv");
if_hue_recv["on"] = hueApplyOnOff; if_hue_recv["on"] = hueApplyOnOff;
if_hue_recv["bri"] = hueApplyBri; if_hue_recv["bri"] = hueApplyBri;
if_hue_recv[F("col")] = hueApplyColor; if_hue_recv["col"] = hueApplyColor;
JsonArray if_hue_ip = if_hue.createNestedArray("ip"); JsonArray if_hue_ip = if_hue.createNestedArray("ip");
for (byte i = 0; i < 4; i++) { for (byte i = 0; i < 4; i++) {
@ -577,7 +618,7 @@ void serializeConfig() {
} }
JsonObject if_ntp = interfaces.createNestedObject("ntp"); JsonObject if_ntp = interfaces.createNestedObject("ntp");
if_ntp[F("en")] = ntpEnabled; if_ntp["en"] = ntpEnabled;
if_ntp[F("host")] = ntpServerName; if_ntp[F("host")] = ntpServerName;
if_ntp[F("tz")] = currentTimezone; if_ntp[F("tz")] = currentTimezone;
if_ntp[F("offset")] = utcOffsetSecs; if_ntp[F("offset")] = utcOffsetSecs;
@ -593,10 +634,10 @@ void serializeConfig() {
ol[F("o5m")] = analogClock5MinuteMarks; ol[F("o5m")] = analogClock5MinuteMarks;
ol[F("osec")] = analogClockSecondsTrail; ol[F("osec")] = analogClockSecondsTrail;
JsonObject timers = doc.createNestedObject("timers"); JsonObject timers = doc.createNestedObject(F("timers"));
JsonObject cntdwn = timers.createNestedObject("cntdwn"); JsonObject cntdwn = timers.createNestedObject(F("cntdwn"));
JsonArray goal = cntdwn.createNestedArray("goal"); JsonArray goal = cntdwn.createNestedArray(F("goal"));
goal.add(countdownYear); goal.add(countdownMonth); goal.add(countdownDay); goal.add(countdownYear); goal.add(countdownMonth); goal.add(countdownDay);
goal.add(countdownHour); goal.add(countdownMin); goal.add(countdownSec); goal.add(countdownHour); goal.add(countdownMin); goal.add(countdownSec);
cntdwn[F("macro")] = macroCountdown; cntdwn[F("macro")] = macroCountdown;
@ -606,7 +647,7 @@ void serializeConfig() {
for (byte i = 0; i < 8; i++) { for (byte i = 0; i < 8; i++) {
if (timerMacro[i] == 0 && timerHours[i] == 0 && timerMinutes[i] == 0) continue; if (timerMacro[i] == 0 && timerHours[i] == 0 && timerMinutes[i] == 0) continue;
JsonObject timers_ins0 = timers_ins.createNestedObject(); JsonObject timers_ins0 = timers_ins.createNestedObject();
timers_ins0[F("en")] = (timerWeekday[i] & 0x01); timers_ins0["en"] = (timerWeekday[i] & 0x01);
timers_ins0[F("hour")] = timerHours[i]; timers_ins0[F("hour")] = timerHours[i];
timers_ins0[F("min")] = timerMinutes[i]; timers_ins0[F("min")] = timerMinutes[i];
timers_ins0[F("macro")] = timerMacro[i]; timers_ins0[F("macro")] = timerMacro[i];
@ -626,7 +667,7 @@ void serializeConfig() {
dmx[F("start")] = DMXStart; dmx[F("start")] = DMXStart;
dmx[F("start-led")] = DMXStartLED; dmx[F("start-led")] = DMXStartLED;
JsonArray dmx_fixmap = dmx.createNestedArray("fixmap"); JsonArray dmx_fixmap = dmx.createNestedArray(F("fixmap"));
for (byte i = 0; i < 15; i++) for (byte i = 0; i < 15; i++)
dmx_fixmap.add(DMXFixtureMap[i]); dmx_fixmap.add(DMXFixtureMap[i]);
#endif #endif
@ -652,7 +693,7 @@ bool deserializeConfigSec() {
JsonObject nw_ins_0 = doc["nw"][F("ins")][0]; JsonObject nw_ins_0 = doc["nw"][F("ins")][0];
getStringFromJson(clientPass, nw_ins_0["psk"], 65); getStringFromJson(clientPass, nw_ins_0["psk"], 65);
JsonObject ap = doc[F("ap")]; JsonObject ap = doc["ap"];
getStringFromJson(apPass, ap["psk"] , 65); getStringFromJson(apPass, ap["psk"] , 65);
JsonObject interfaces = doc["if"]; JsonObject interfaces = doc["if"];
@ -662,7 +703,7 @@ bool deserializeConfigSec() {
if (tdd > 20 || tdd == 0) if (tdd > 20 || tdd == 0)
getStringFromJson(blynkApiKey, apikey, 36); getStringFromJson(blynkApiKey, apikey, 36);
JsonObject if_mqtt = interfaces[F("mqtt")]; JsonObject if_mqtt = interfaces["mqtt"];
getStringFromJson(mqttPass, if_mqtt["psk"], 41); getStringFromJson(mqttPass, if_mqtt["psk"], 41);
getStringFromJson(hueApiKey, interfaces[F("hue")][F("key")], 47); getStringFromJson(hueApiKey, interfaces[F("hue")][F("key")], 47);

View File

@ -13,6 +13,12 @@
//increase if you need more //increase if you need more
#define WLED_MAX_USERMODS 4 #define WLED_MAX_USERMODS 4
#ifdef ESP8266
#define WLED_MAX_BUSSES 3
#else
#define WLED_MAX_BUSSES 10
#endif
//Usermod IDs //Usermod IDs
#define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present #define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present
#define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID #define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID
@ -95,6 +101,7 @@
#define TYPE_GS8608 23 //same driver as WS2812, but will require signal 2x per second (else displays test pattern) #define TYPE_GS8608 23 //same driver as WS2812, but will require signal 2x per second (else displays test pattern)
#define TYPE_WS2811_400KHZ 24 //half-speed WS2812 protocol, used by very old WS2811 units #define TYPE_WS2811_400KHZ 24 //half-speed WS2812 protocol, used by very old WS2811 units
#define TYPE_SK6812_RGBW 30 #define TYPE_SK6812_RGBW 30
#define TYPE_TM1814 31
//"Analog" types (PWM) (32-47) //"Analog" types (PWM) (32-47)
#define TYPE_ONOFF 40 //binary output (relays etc.) #define TYPE_ONOFF 40 //binary output (relays etc.)
#define TYPE_ANALOG_1CH 41 //single channel PWM. Uses value of brightest RGBW channel #define TYPE_ANALOG_1CH 41 //single channel PWM. Uses value of brightest RGBW channel
@ -107,8 +114,11 @@
#define TYPE_APA102 51 #define TYPE_APA102 51
#define TYPE_LPD8806 52 #define TYPE_LPD8806 52
#define TYPE_P9813 53 #define TYPE_P9813 53
#define TYPE_TM1814 54
#define IS_DIGITAL(t) (t & 0x10) //digital are 16-31 and 48-63
#define IS_PWM(t) (t > 40 && t < 46)
#define NUM_PWM_PINS(t) (t - 40) //for analog PWM 41-45 only
#define IS_2PIN(t) (t > 47)
//Color orders //Color orders
#define COL_ORDER_GRB 0 //GRB(w),defaut #define COL_ORDER_GRB 0 //GRB(w),defaut
@ -128,10 +138,13 @@
#define BTN_TYPE_SWITCH_ACT_HIGH 5 //not implemented #define BTN_TYPE_SWITCH_ACT_HIGH 5 //not implemented
//Ethernet board types //Ethernet board types
#define WLED_NUM_ETH_TYPES 5
#define WLED_ETH_NONE 0 #define WLED_ETH_NONE 0
#define WLED_ETH_WT32_ETH01 1 #define WLED_ETH_WT32_ETH01 1
#define WLED_ETH_ESP32_POE 2 #define WLED_ETH_ESP32_POE 2
#define WLED_ETH_WESP32 3 #define WLED_ETH_WESP32 3
#define WLED_ETH_QUINLED 4
//Hue error codes //Hue error codes
#define HUE_ERROR_INACTIVE 0 #define HUE_ERROR_INACTIVE 0
@ -159,6 +172,9 @@
#define ERR_FS_QUOTA 11 // The FS is full or the maximum file size is reached #define ERR_FS_QUOTA 11 // The FS is full or the maximum file size is reached
#define ERR_FS_PLOAD 12 // It was attempted to load a preset that does not exist #define ERR_FS_PLOAD 12 // It was attempted to load a preset that does not exist
#define ERR_FS_GENERAL 19 // A general unspecified filesystem error occured #define ERR_FS_GENERAL 19 // A general unspecified filesystem error occured
#define ERR_OVERTEMP 30 // An attached temperature sensor has measured above threshold temperature (not implemented)
#define ERR_OVERCURRENT 31 // An attached current sensor has measured a current above the threshold (not implemented)
#define ERR_UNDERVOLT 32 // An attached voltmeter has measured a voltage below the threshold (not implemented)
//Timer mode types //Timer mode types
#define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness #define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness
@ -171,18 +187,40 @@
// maximum number of LEDs - more than 1500 LEDs (or 500 DMA "LEDPIN 3" driven ones) will cause a low memory condition on ESP8266 // maximum number of LEDs - more than 1500 LEDs (or 500 DMA "LEDPIN 3" driven ones) will cause a low memory condition on ESP8266
#ifndef MAX_LEDS #ifndef MAX_LEDS
#define MAX_LEDS 1500 #ifdef ESP8266
#define MAX_LEDS 8192 //rely on memory limit to limit this to 1600 LEDs
#else
#define MAX_LEDS 8192
#endif
#endif #endif
#define MAX_LEDS_DMA 500 #ifndef MAX_LED_MEMORY
#ifdef ESP8266
#define MAX_LED_MEMORY 5000
#else
#define MAX_LED_MEMORY 64000
#endif
#endif
#ifndef MAX_LEDS_PER_BUS
#define MAX_LEDS_PER_BUS 4096
#endif
// string temp buffer (now stored in stack locally) // string temp buffer (now stored in stack locally)
#define OMAX 2048 #define OMAX 2048
#define E131_MAX_UNIVERSE_COUNT 9 #define E131_MAX_UNIVERSE_COUNT 9
#define ABL_MILLIAMPS_DEFAULT 850; // auto lower brightness to stay close to milliampere limit #define ABL_MILLIAMPS_DEFAULT 850 // auto lower brightness to stay close to milliampere limit
// PWM settings
#ifndef WLED_PWM_FREQ
#ifdef ESP8266
#define WLED_PWM_FREQ 880 //PWM frequency proven as good for LEDs
#else
#define WLED_PWM_FREQ 19531
#endif
#endif
#define TOUCH_THRESHOLD 32 // limit to recognize a touch, higher value means more sensitive #define TOUCH_THRESHOLD 32 // limit to recognize a touch, higher value means more sensitive
@ -193,4 +231,24 @@
#define JSON_BUFFER_SIZE 16384 #define JSON_BUFFER_SIZE 16384
#endif #endif
// Maximum size of node map (list of other WLED instances)
#ifdef ESP8266
#define WLED_MAX_NODES 15
#else
#define WLED_MAX_NODES 150
#endif
//this is merely a default now and can be changed at runtime
#ifndef LEDPIN
#define LEDPIN 2
#endif
#ifdef WLED_ENABLE_DMX
#if (LEDPIN == 2)
#undef LEDPIN
#define LEDPIN 3
#warning "Pin conflict compiling with DMX and LEDs on pin 2. The default LED pin has been changed to pin 3."
#endif
#endif
#endif #endif

View File

@ -90,9 +90,10 @@ button {
#namelabel { #namelabel {
position: fixed; position: fixed;
bottom: calc(var(--bh) + 5px); bottom: calc(var(--bh) + 6px);
right: 4px; right: 4px;
color: var(--c-6); color: var(--c-6);
cursor: pointer;
writing-mode: vertical-rl; writing-mode: vertical-rl;
} }
@ -165,6 +166,14 @@ button {
color: var(--c-d); color: var(--c-d);
} }
.search-cancel-icon {
position: absolute;
right: 8px;
top: 9px;
cursor: pointer;
display: none;
}
.flr { .flr {
float: right; float: right;
cursor: pointer; cursor: pointer;
@ -298,7 +307,7 @@ button {
top: -1px; top: -1px;
z-index: 1; z-index: 1;
margin-top: 1px; margin-top: 1px;
width: 274px; width: 272px;
margin: auto; margin: auto;
border-radius: 25px; border-radius: 25px;
} }
@ -307,10 +316,6 @@ button {
top: 28px; top: 28px;
} }
#staytop2 {
top: 56px;
}
#fxb0 { #fxb0 {
margin-bottom: 2px; margin-bottom: 2px;
filter: drop-shadow(0 0 1px #000); filter: drop-shadow(0 0 1px #000);
@ -366,10 +371,18 @@ button {
z-index: 3; z-index: 3;
} }
#rover { #rover, #nodes {
z-index: 2; z-index: 2;
} }
#ndlt {
margin: 12px 0;
}
.valtd i {
font-size: 14px;
}
#roverstar { #roverstar {
position: fixed; position: fixed;
top: calc(var(--th) + 5px); top: calc(var(--th) + 5px);
@ -394,11 +407,15 @@ button {
display: inline-block; display: inline-block;
} }
#kv { #kv, #kn {
max-width: 490px; max-width: 490px;
display: inline-block; display: inline-block;
} }
#kn td {
padding-bottom: 12px;
}
#lv { #lv {
max-width: 600px; max-width: 600px;
display: inline-block; display: inline-block;
@ -535,6 +552,7 @@ input[type=range]:active + .sliderbubble {
font-size: 19px; font-size: 19px;
background-color: var(--c-3); background-color: var(--c-3);
color: var(--c-f); color: var(--c-f);
cursor: pointer;
border: 0px solid white; border: 0px solid white;
border-radius: 25px; border-radius: 25px;
transition-duration: 0.5s; transition-duration: 0.5s;
@ -751,7 +769,7 @@ input[type=number]::-webkit-outer-spin-button {
cursor: pointer; cursor: pointer;
} }
.check { .check, .radio {
display: inline-block; display: inline-block;
position: relative; position: relative;
padding-bottom: 32px; padding-bottom: 32px;
@ -761,7 +779,7 @@ input[type=number]::-webkit-outer-spin-button {
} }
.schkl { .schkl {
padding: 2px 22px 0px 35px; padding: 2px 5px 0px 35px;
margin: 0 0 0 2px; margin: 0 0 0 2px;
} }
@ -771,7 +789,13 @@ input[type=number]::-webkit-outer-spin-button {
margin-top: 8px; margin-top: 8px;
} }
.check input { .fxchkl {
position: absolute;
top: 0px;
left: 8px;
}
.check input, .radio input {
position: absolute; position: absolute;
opacity: 0; opacity: 0;
cursor: pointer; cursor: pointer;
@ -779,7 +803,7 @@ input[type=number]::-webkit-outer-spin-button {
width: 0; width: 0;
} }
.checkmark { .checkmark, .radiomark {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
left: 0; left: 0;
@ -789,6 +813,13 @@ input[type=number]::-webkit-outer-spin-button {
border-radius: 10px; border-radius: 10px;
} }
.radiomark {
height: 24px;
width: 24px;
border-radius: 50%;
background-color: transparent;
}
.schk { .schk {
top: 0; top: 0;
} }
@ -815,13 +846,13 @@ input[type=number]::-webkit-outer-spin-button {
background-color: var(--c-6); background-color: var(--c-6);
} }
.checkmark:after { .checkmark:after, .radiomark:after {
content: ""; content: "";
position: absolute; position: absolute;
display: none; display: none;
} }
.check input:checked ~ .checkmark:after { .check input:checked ~ .checkmark:after, .radio input:checked ~ .radiomark:after {
display: block; display: block;
} }
@ -837,6 +868,16 @@ input[type=number]::-webkit-outer-spin-button {
transform: rotate(45deg); transform: rotate(45deg);
} }
.radio .radiomark:after {
width: 12px;
height: 12px;
top: 50%;
left: 50%;
margin: -6px;
border-radius: 50%;
background: var(--c-f);
}
.h { .h {
font-size: 13px; font-size: 13px;
text-align: center; text-align: center;
@ -863,6 +904,92 @@ input[type=number]::-webkit-outer-spin-button {
filter: brightness(1); filter: brightness(1);
} }
.list {
position: relative;
transition: background-color 0.5s;
margin: auto auto 10px;
padding-bottom: 10px;
width: 230px;
}
.lstI {
overflow: hidden;
}
.fxbtn {
margin: 20px auto;
padding: 8px 0;
}
.lstI:hover {
background: var(--c-4);
}
.lstI:last-child {
border: none;
}
.lstI.sticky, .lstI.selected {
position: sticky;
z-index: 1;
}
#selectPalette .lstI.selected {
top: 27px;
bottom: -11px;
}
#selectPalette .lstI.sticky {
top: -11px;
}
.lstI.selected {
background: var(--c-5);
top: 95px;
bottom: -11px;
}
.lstI.sticky {
top: 57px;
}
.lstIname {
margin: 3px 0;
white-space: nowrap;
cursor: pointer;
font-size: 19px;
}
.lstIprev {
width: 100%;
height: 5px;
margin: auto;
position: absolute;
bottom: 0px;
left: 0px;
}
input[type="text"].search {
display: block;
width: 230px;
box-sizing: border-box;
padding: 8px 8px 9px 38px;
margin: 6px auto 0 auto;
text-align: left;
background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' stroke='white'><ellipse fill-opacity='0' stroke-width='10' cx='35' cy='35' id='svg_1' rx='25' ry='25' /><line stroke-width='10' x1='48.5' y1='70.75' x2='92.5' y2='70.75' transform='rotate(45, 70.5, 70.75)' /></svg>")
no-repeat 10px 10px;
background-size: 20px;
background-color: var(--c-3);
}
input[type="text"].search:focus {
background-color: var(--c-4);
}
input[type="text"].search:not(:placeholder-shown) {
background-color: var(--c-5);
}
.pres { .pres {
margin-bottom: 6px; margin-bottom: 6px;
} }

View File

@ -24,6 +24,7 @@
<button id="buttonSync" onclick="toggleSync()"><i class="icons">&#xe116;</i><p class="tab-label">Sync</p></button> <button id="buttonSync" onclick="toggleSync()"><i class="icons">&#xe116;</i><p class="tab-label">Sync</p></button>
<button id="buttonSr" onclick="toggleLiveview()"><i class="icons">&#xe410;</i><p class="tab-label">Peek</p></button> <button id="buttonSr" onclick="toggleLiveview()"><i class="icons">&#xe410;</i><p class="tab-label">Peek</p></button>
<button id="buttonI" onclick="toggleInfo()"><i class="icons">&#xe34b;</i><p class="tab-label">Info</p></button> <button id="buttonI" onclick="toggleInfo()"><i class="icons">&#xe34b;</i><p class="tab-label">Info</p></button>
<button id="buttonNodes" onclick="toggleNodes()"><i class="icons">&#xe22d;</i><p class="tab-label">Nodes</p></button></div>
<button onclick="window.location.href = '/settings';"><i class="icons">&#xe0a2;</i><p class="tab-label">Config</p></button> <button onclick="window.location.href = '/settings';"><i class="icons">&#xe0a2;</i><p class="tab-label">Config</p></button>
<button id="buttonPcm" onclick="togglePcMode(true)"><i class="icons">&#xe23d;</i><p class="tab-label">PC Mode</p></button> <button id="buttonPcm" onclick="togglePcMode(true)"><i class="icons">&#xe23d;</i><p class="tab-label">PC Mode</p></button>
</div> </div>
@ -66,17 +67,17 @@
</div> </div>
</div> </div>
<div id="qcs-w"> <div id="qcs-w">
<div class="qcs" onclick="pC('#ff0000');" style="background-color:#ff0000;"></div> <div class="qcs" onclick="pC('#ff0000');" title="Red" style="background-color:#ff0000;"></div>
<div class="qcs" onclick="pC('#ffa000');" style="background-color:#ffa000;"></div> <div class="qcs" onclick="pC('#ffa000');" title="Orange" style="background-color:#ffa000;"></div>
<div class="qcs" onclick="pC('#ffc800');" style="background-color:#ffc800;"></div> <div class="qcs" onclick="pC('#ffc800');" title="Yellow" style="background-color:#ffc800;"></div>
<div class="qcs" onclick="pC('#ffe0a0');" style="background-color:#ffe0a0;"></div> <div class="qcs" onclick="pC('#ffe0a0');" title="Warm White" style="background-color:#ffe0a0;"></div>
<div class="qcs" onclick="pC('#ffffff');" style="background-color:#ffffff;"></div> <div class="qcs" onclick="pC('#ffffff');" title="White" style="background-color:#ffffff;"></div>
<div class="qcs qcsb" onclick="pC('#000000');" style="background-color:#000000;"></div><br> <div class="qcs qcsb" onclick="pC('#000000');" title="Black" style="background-color:#000000;"></div><br>
<div class="qcs" onclick="pC('#ff00ff');" style="background-color:#ff00ff;"></div> <div class="qcs" onclick="pC('#ff00ff');" title="Pink" style="background-color:#ff00ff;"></div>
<div class="qcs" onclick="pC('#0000ff');" style="background-color:#0000ff;"></div> <div class="qcs" onclick="pC('#0000ff');" title="Blue" style="background-color:#0000ff;"></div>
<div class="qcs" onclick="pC('#00ffc8');" style="background-color:#00ffc8;"></div> <div class="qcs" onclick="pC('#00ffc8');" title="Cyan" style="background-color:#00ffc8;"></div>
<div class="qcs" onclick="pC('#08ff00');" style="background-color:#08ff00;"></div> <div class="qcs" onclick="pC('#08ff00');" title="Green" style="background-color:#08ff00;"></div>
<div class="qcs" onclick="pC('rnd');" style="background-color:var(--c-3); padding: 4px 8px; transform: translateY(-10px);">R</div> <div class="qcs" onclick="pC('rnd');" title="Random" style="background-color:var(--c-3); padding: 4px 8px; transform: translateY(-10px);">R</div>
</div> </div>
<div id="csl"> <div id="csl">
<button class="xxs cl btn" onclick="selectSlot(0);">1</button> <button class="xxs cl btn" onclick="selectSlot(0);">1</button>
@ -87,13 +88,33 @@
<input id="hexc" type="text" class="noslide" onkeydown="hexEnter(this)" autocomplete="off" maxlength="8" /> <input id="hexc" type="text" class="noslide" onkeydown="hexEnter(this)" autocomplete="off" maxlength="8" />
<button id="hexcnf" class="xxs btn" onclick="fromHex();"><i class="icons btna-icon">&#xe390;</i></button> <button id="hexcnf" class="xxs btn" onclick="fromHex();"><i class="icons btna-icon">&#xe390;</i></button>
</div> </div>
<p class="labels">Color palette</p> <p class="labels">
<div class="il">
<i class="icons sel-icon" onclick="tglHex()">&#xe2b3;</i> <i class="icons sel-icon" onclick="tglHex()">&#xe2b3;</i>
<select class="btn sel" id="selectPalette" onchange="setPalette()"> Color palette
<option>Default</option> </p>
<option>Error!</option> <div class="il">
</select> <div id="selectPalette" class="list">
<div class="lstI" data-id="0">
<label class="check schkl">
&nbsp;
<input type="radio" value="${palettes[i].id}" name="palette" onChange="setPalette()">
<span class="checkmark schk"></span>
</label>
<div class="lstIcontent">
<span class="lstIname">
Default
</span>
</div>
</div>
<div class="lstI">
<div class="lstIcontent">
<span class="lstIname">
Loading...
</span>
</div>
</div>
</div>
</div> </div>
</div> </div>
@ -117,13 +138,9 @@
</div> </div>
</div> </div>
<p class="labels">Effect mode</p> <p class="labels">Effect mode</p>
<div class="staytop" id="staytop2"> <div id="fxlist" class="list">
<button class="btn" id="fxb0" onclick="setX(0);">Solid</button>
</div>
<div id="fxlist">
Loading... Loading...
</div> </div>
<br>
</div> </div>
<div id="Segments" class="tabcontent"> <div id="Segments" class="tabcontent">
@ -169,7 +186,7 @@
<div id="connind"></div> <div id="connind"></div>
<div id="toast"></div> <div id="toast"></div>
<div id="namelabel"></div> <div id="namelabel" onclick="toggleNodes()"></div>
<div id="info" class="modal"> <div id="info" class="modal">
<div id="imgw"> <div id="imgw">
<img alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAggAAACMCAYAAAAZQlGEAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAKLSURBVHhe7dgxjtwwEADBpf//5zUDwklnpzFAnKoSTigNFTT0AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGDcOieX+G5nvNLaznil6f1Nv+/tz3c7+3tmen/Tpu/jbe877c85AQD+EQgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAQiAAACEQAIAQCABACAQAINY5+aHvdsYRazvjK9jfM7fvz/0+Y3+/2+336w8CABACAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAADEOudrfLczXmltZ3yF6fuwv2em9+d+n5ne3zT3cZfp+/AHAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAYp3zNb7bGUes7Yz8wO334fmeuf35bmd/z9y+v9ufzx8EACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAQiAAACEQAIAQCABACAQAIAQCABACAQCIdc4x3+2MV1rbGfmFpr+/6e/l9ue73fT+pt1+H2/bn+/lGX8QAIAQCABACAQAIAQCABACAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgP/u8/kLYCqAxINTyZkAAAAASUVORK5CYII="> <img alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAggAAACMCAYAAAAZQlGEAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAKLSURBVHhe7dgxjtwwEADBpf//5zUDwklnpzFAnKoSTigNFTT0AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGDcOieX+G5nvNLaznil6f1Nv+/tz3c7+3tmen/Tpu/jbe877c85AQD+EQgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAQiAAACEQAIAQCABACAQAINY5+aHvdsYRazvjK9jfM7fvz/0+Y3+/2+336w8CABACAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAADEOudrfLczXmltZ3yF6fuwv2em9+d+n5ne3zT3cZfp+/AHAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAYp3zNb7bGUes7Yz8wO334fmeuf35bmd/z9y+v9ufzx8EACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAQiAAACEQAIAQCABACAQAIAQCABACAQCIdc4x3+2MV1rbGfmFpr+/6e/l9ue73fT+pt1+H2/bn+/lGX8QAIAQCABACAQAIAQCABACAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgP/u8/kLYCqAxINTyZkAAAAASUVORK5CYII=">
@ -177,11 +194,18 @@
<div id="kv">Loading...</div><br> <div id="kv">Loading...</div><br>
<button class="btn infobtn" onclick="requestJson(null)">Refresh</button> <button class="btn infobtn" onclick="requestJson(null)">Refresh</button>
<button class="btn infobtn" onclick="toggleInfo()">Close Info</button><br> <button class="btn infobtn" onclick="toggleInfo()">Close Info</button><br>
<button class="btn infobtn" onclick="openGH()">WLED Wiki</button> <button class="btn infobtn" onclick="toggleNodes()">Instance List</button>
<button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button><br> <button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button><br>
<span class="h">Made with <span id="heart">&#10084;&#xFE0E;</span> by Aircoookie and the WLED community</span> <span class="h">Made with <span id="heart">&#10084;&#xFE0E;</span> by Aircoookie and the WLED community</span>
</div> </div>
<div id="nodes" class="modal">
<div id="ndlt">WLED instances</div>
<div id="kn">Loading...</div><br>
<button class="btn infobtn" onclick="loadNodes()">Refresh</button>
<button class="btn infobtn" onclick="toggleNodes()">Close list</button><br>
</div>
<div id="rover" class="modal"> <div id="rover" class="modal">
<i class="icons huge">&#xe410;</i><br> <i class="icons huge">&#xe410;</i><br>
<div id="lv">?</div><br><br> <div id="lv">?</div><br><br>
@ -191,6 +215,7 @@
<button class="btn" onclick="setLor(2)">Override until reboot</button><br> <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> <span class="h">For best performance, it is recommended to turn off the streaming source when not in use.</span>
</div> </div>
<i id="roverstar" class="icons huge" onclick="setLor(0)">&#xe410;</i><br> <i id="roverstar" class="icons huge" onclick="setLor(0)">&#xe410;</i><br>
<script src="iro.js"></script> <script src="iro.js"></script>
<script src="rangetouch.js"></script> <script src="rangetouch.js"></script>

View File

@ -1,8 +1,9 @@
//page js //page js
var loc = false, locip; var loc = false, locip;
var noNewSegs = false; var noNewSegs = false;
var isOn = false, nlA = false, isLv = false, isInfo = false, syncSend = false, syncTglRecv = true, isRgbw = false; var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, syncSend = false, syncTglRecv = true, isRgbw = false;
var whites = [0,0,0]; var whites = [0,0,0];
var selColors;
var expanded = [false]; var expanded = [false];
var powered = [true]; var powered = [true];
var nlDur = 60, nlTar = 0; var nlDur = 60, nlTar = 0;
@ -15,6 +16,7 @@ var segCount = 0, ledCount = 0, lowestUnused = 0, maxSeg = 0, lSeg = 0;
var pcMode = false, pcModeA = false, lastw = 0; var pcMode = false, pcModeA = false, lastw = 0;
var d = document; var d = document;
const ranges = RangeTouch.setup('input[type="range"]', {}); const ranges = RangeTouch.setup('input[type="range"]', {});
var palettesData;
var pJson = {}; var pJson = {};
var pN = "", pI = 0; var pN = "", pI = 0;
var pmt = 1, pmtLS = 0, pmtLast = 0; var pmt = 1, pmtLS = 0, pmtLast = 0;
@ -51,7 +53,7 @@ var cpick = new iro.ColorPicker("#picker", {
}); });
function handleVisibilityChange() { function handleVisibilityChange() {
if (!document.hidden && new Date () - lastUpdate > 3000) { if (!d.hidden && new Date () - lastUpdate > 3000) {
requestJson(null); requestJson(null);
} }
} }
@ -148,8 +150,8 @@ function cTheme(light) {
} }
function loadBg(iUrl) { function loadBg(iUrl) {
let bg = document.getElementById('bg'); let bg = d.getElementById('bg');
let img = document.createElement("img"); let img = d.createElement("img");
img.src = iUrl; img.src = iUrl;
if (iUrl == "") { if (iUrl == "") {
var today = new Date(); var today = new Date();
@ -157,7 +159,6 @@ function loadBg(iUrl) {
} }
img.addEventListener('load', (event) => { img.addEventListener('load', (event) => {
var a = parseFloat(cfg.theme.alpha.bg); var a = parseFloat(cfg.theme.alpha.bg);
d.getElementById('staytop2').style.background = "transparent";
if (isNaN(a)) a = 0.6; if (isNaN(a)) a = 0.6;
bg.style.opacity = a; bg.style.opacity = a;
bg.style.backgroundImage = `url(${img.src})`; bg.style.backgroundImage = `url(${img.src})`;
@ -305,12 +306,11 @@ function qlName(i) {
} }
function cpBck() { function cpBck() {
var copyText = document.getElementById("bck"); var copyText = d.getElementById("bck");
copyText.select(); copyText.select();
copyText.setSelectionRange(0, 999999); copyText.setSelectionRange(0, 999999);
d.execCommand("copy");
document.execCommand("copy");
showToast("Copied to clipboard!"); showToast("Copied to clipboard!");
} }
@ -463,8 +463,9 @@ function populateInfo(i)
} }
} }
} }
var vcn = "Kuuhaku"; var vcn = "Kuuhaku";
if (i.ver.startsWith("0.11.")) vcn = "Mirai"; if (i.ver.startsWith("0.12.")) vcn = "Hikari";
if (i.cn) vcn = i.cn; if (i.cn) vcn = i.cn;
cn += `v${i.ver} "${vcn}"<br><br><table class="infot"> cn += `v${i.ver} "${vcn}"<br><br><table class="infot">
@ -474,6 +475,7 @@ function populateInfo(i)
${inforow("Uptime",getRuntimeStr(i.uptime))} ${inforow("Uptime",getRuntimeStr(i.uptime))}
${inforow("Free heap",heap," kB")} ${inforow("Free heap",heap," kB")}
${inforow("Estimated current",pwru)} ${inforow("Estimated current",pwru)}
${inforow("Frames / second",i.leds.fps)}
${inforow("MAC address",i.mac)} ${inforow("MAC address",i.mac)}
${inforow("Filesystem",i.fs.u + "/" + i.fs.t + " kB (" +Math.round(i.fs.u*100/i.fs.t) + "%)")} ${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 + ")")} ${inforow("Environment",i.arch + " " + i.core + " (" + i.lwip + ")")}
@ -565,6 +567,214 @@ function populateSegments(s)
d.getElementById('rsbtn').style.display = (segCount > 1) ? "inline":"none"; d.getElementById('rsbtn').style.display = (segCount > 1) ? "inline":"none";
} }
function populateEffects(effects)
{
var html = `<div class="searchbar"><input type="text" class="search" placeholder="Search" oninput="search(this)" />
<i class="icons search-cancel-icon" onclick="cancelSearch(this)">&#xe38f;</i></div>`;
effects.shift(); //remove solid
for (let i = 0; i < effects.length; i++) {
effects[i] = {id: parseInt(i)+1, name:effects[i]};
}
effects.sort(compare);
effects.unshift({
"id": 0,
"name": "Solid",
"class": "sticky"
});
for (let i = 0; i < effects.length; i++) {
html += generateListItemHtml(
'fx',
effects[i].id,
effects[i].name,
'setX',
'',
effects[i].class,
);
}
d.getElementById('fxlist').innerHTML=html;
}
function populatePalettes(palettes)
{
palettes.shift(); //remove default
for (let i = 0; i < palettes.length; i++) {
palettes[i] = {
"id": parseInt(i)+1,
"name": palettes[i]
};
}
palettes.sort(compare);
palettes.unshift({
"id": 0,
"name": "Default",
"class": "sticky"
});
var html = `<div class="searchbar"><input type="text" class="search" placeholder="Search" oninput="search(this)" />
<i class="icons search-cancel-icon" onclick="cancelSearch(this)">&#xe38f;</i></div>`;
for (let i = 0; i < palettes.length; i++) {
let previewCss = genPalPrevCss(palettes[i].id);
html += generateListItemHtml(
'palette',
palettes[i].id,
palettes[i].name,
'setPalette',
`<div class="lstIprev" style="${previewCss}"></div>`,
palettes[i].class,
);
}
d.getElementById('selectPalette').innerHTML=html;
}
function redrawPalPrev()
{
let palettes = d.querySelectorAll('#selectPalette .lstI');
for (let i = 0; i < palettes.length; i++) {
let id = palettes[i].dataset.id;
let lstPrev = palettes[i].querySelector('.lstIprev');
if (lstPrev) {
lstPrev.style = genPalPrevCss(id);
}
}
}
function genPalPrevCss(id)
{
if (!palettesData) {
return;
}
var paletteData = palettesData[id];
var previewCss = "";
if (!paletteData) {
return 'display: none';
}
// We need at least two colors for a gradient
if (paletteData.length == 1) {
paletteData[1] = paletteData[0];
if (Array.isArray(paletteData[1])) {
paletteData[1][0] = 255;
}
}
var gradient = [];
for (let j = 0; j < paletteData.length; j++) {
const element = paletteData[j];
let r;
let g;
let b;
let index = false;
if (Array.isArray(element)) {
index = element[0]/255*100;
r = element[1];
g = element[2];
b = element[3];
} else if (element == 'r') {
r = Math.random() * 255;
g = Math.random() * 255;
b = Math.random() * 255;
} else {
if (selColors) {
let pos = element[1] - 1;
r = selColors[pos][0];
g = selColors[pos][1];
b = selColors[pos][2];
}
}
if (index === false) {
index = j / paletteData.length * 100;
}
gradient.push(`rgb(${r},${g},${b}) ${index}%`);
}
return `background: linear-gradient(to right,${gradient.join()});`;
}
function generateListItemHtml(listName, id, name, clickAction, extraHtml = '', extraClass = '')
{
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>
</label>
<span class="lstIname">
${name}
</span>
${extraHtml}
</div>`;
}
function btype(b){
switch (b) {
case 32: return "ESP32";
case 82: return "ESP8266";
}
return "?";
}
function bname(o){
if (o.name=="WLED") return o.ip;
return o.name;
}
function populateNodes(i,n)
{
var cn="";
var urows="";
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>`;
urows += inforow(url,`${btype(o.type)}<br><i>${o.vid==0?"N/A":o.vid}</i>`);
nnodes++;
}
}
}
if (i.ndc < 0) cn += `Instance List is disabled.`;
else if (nnodes == 0) cn += `No other instances found.`;
cn += `<table class="infot">
${urows}
${inforow("Current instance:",i.name)}
</table>`;
d.getElementById('kn').innerHTML = cn;
}
function loadNodes()
{
var url = '/json/nodes';
if (loc) {
url = `http://${locip}/json/nodes`;
}
fetch
(url, {
method: 'get'
})
.then(res => {
if (!res.ok) {
showToast('Could not load Node list!', true);
}
return res.json();
})
.then(json => {
populateNodes(lastinfo, json);
})
.catch(function (error) {
showToast(error, true);
console.log(error);
});
}
function updateTrail(e, slidercol) function updateTrail(e, slidercol)
{ {
if (e==null) return; if (e==null) return;
@ -646,15 +856,12 @@ function updateUI()
d.getElementById('buttonNl').className = (nlA) ? "active":""; d.getElementById('buttonNl').className = (nlA) ? "active":"";
d.getElementById('buttonSync').className = (syncSend) ? "active":""; d.getElementById('buttonSync').className = (syncSend) ? "active":"";
d.getElementById('fxb' + selectedFx).style.backgroundColor = "var(--c-6)";
updateTrail(d.getElementById('sliderBri')); updateTrail(d.getElementById('sliderBri'));
updateTrail(d.getElementById('sliderSpeed')); updateTrail(d.getElementById('sliderSpeed'));
updateTrail(d.getElementById('sliderIntensity')); updateTrail(d.getElementById('sliderIntensity'));
updateTrail(d.getElementById('sliderW')); updateTrail(d.getElementById('sliderW'));
if (isRgbw) d.getElementById('wwrap').style.display = "block"; if (isRgbw) d.getElementById('wwrap').style.display = "block";
var spal = d.getElementById("selectPalette");
spal.style.backgroundColor = (spal.selectedIndex > 0) ? "var(--c-6)":"var(--c-3)";
updatePA(); updatePA();
updateHex(); updateHex();
updateRgb(); updateRgb();
@ -718,53 +925,63 @@ function requestJson(command, rinfo = true, verbose = true) {
jsonTimeout = null; jsonTimeout = null;
clearErrorToast(); clearErrorToast();
d.getElementById('connind').style.backgroundColor = "#070"; d.getElementById('connind').style.backgroundColor = "#070";
if (!json) showToast('Empty response', true); if (!json) {
if (json.success) return; showToast('Empty response', true);
}
if (json.success) {
return;
}
var s = json; var s = json;
if (!command || rinfo) { if (!command || rinfo) {
if (!rinfo) { if (!rinfo) {
pmt = json.info.fs.pmt; pmt = json.info.fs.pmt;
if (pmt != pmtLS || pmt == 0) { if (pmt != pmtLS || pmt == 0) {
setTimeout(loadPresets,99); setTimeout(loadPresets,99);
} }
else populatePresets(true); else {
populatePresets(true);
}
pmtLast = pmt; pmtLast = pmt;
var x='',y='<option value="0">Default</option>';
json.effects.shift(); //remove solid
for (let i = 0; i < json.effects.length; i++) json.effects[i] = {id: parseInt(i)+1, name:json.effects[i]};
json.effects.sort(compare);
for (let i = 0; i < json.effects.length; i++) {
x += `<button class="btn${(i==0)?" first":""}" id="fxb${json.effects[i].id}" onclick="setX(${json.effects[i].id});">${json.effects[i].name}</button><br>`;
}
json.palettes.shift(); //remove default populateEffects(json.effects);
for (let i = 0; i < json.palettes.length; i++) json.palettes[i] = {"id": parseInt(i)+1, "name":json.palettes[i]}; populatePalettes(json.palettes);
json.palettes.sort(compare);
for (let i = 0; i < json.palettes.length; i++) {
y += `<option value="${json.palettes[i].id}">${json.palettes[i].name}</option>`;
}
e1.innerHTML=x; e2.innerHTML=y;
} }
var info = json.info; var info = json.info;
var name = info.name; var name = info.name;
d.getElementById('namelabel').innerHTML = name; d.getElementById('namelabel').innerHTML = name;
if (name === "Dinnerbone") d.documentElement.style.transform = "rotate(180deg)"; if (name === "Dinnerbone") {
if (info.live) name = "(Live) " + name; d.documentElement.style.transform = "rotate(180deg)";
if (loc) name = "(L) " + name; }
if (info.live) {
name = "(Live) " + name;
}
if (loc) {
name = "(L) " + name;
}
d.title = name; d.title = name;
isRgbw = info.leds.wv; isRgbw = info.leds.wv;
ledCount = info.leds.count; ledCount = info.leds.count;
syncTglRecv = info.str; syncTglRecv = info.str;
maxSeg = info.leds.maxseg; maxSeg = info.leds.maxseg;
pmt = info.fs.pmt; pmt = info.fs.pmt;
if (!command && pmt != pmtLast) setTimeout(loadPresets,99);
if (!command && pmt != pmtLast) {
setTimeout(loadPresets,99);
}
pmtLast = pmt; pmtLast = pmt;
d.getElementById('buttonNodes').style.display = (info.ndc > 0 && window.innerWidth > 770) ? "block":"none";
lastinfo = info; lastinfo = info;
if (isInfo) populateInfo(info); if (isInfo) {
populateInfo(info);
}
s = json.state; s = json.state;
displayRover(info, s); displayRover(info, s);
if (!rinfo) loadPalettesData();
} }
isOn = s.on; isOn = s.on;
d.getElementById('sliderBri').value= s.bri; d.getElementById('sliderBri').value= s.bri;
nlA = s.nl.on; nlA = s.nl.on;
@ -773,7 +990,7 @@ function requestJson(command, rinfo = true, verbose = true) {
nlFade = s.nl.fade; nlFade = s.nl.fade;
syncSend = s.udpn.send; syncSend = s.udpn.send;
currentPreset = s.ps; currentPreset = s.ps;
d.getElementById('cyToggle').checked = (s.pl < 0) ? false : true; d.getElementById('cyToggle').checked = (s.pl >= 0);
d.getElementById('cycs').value = s.ccnf.min; d.getElementById('cycs').value = s.ccnf.min;
d.getElementById('cyce').value = s.ccnf.max; d.getElementById('cyce').value = s.ccnf.max;
d.getElementById('cyct').value = s.ccnf.time /10; d.getElementById('cyct').value = s.ccnf.time /10;
@ -791,6 +1008,8 @@ function requestJson(command, rinfo = true, verbose = true) {
updateUI(); updateUI();
return; return;
} }
selColors = i.col;
var cd = d.getElementById('csl').children; var cd = d.getElementById('csl').children;
for (let e = 2; e >= 0; e--) for (let e = 2; e >= 0; e--)
{ {
@ -803,18 +1022,46 @@ function requestJson(command, rinfo = true, verbose = true) {
d.getElementById('sliderSpeed').value = i.sx; d.getElementById('sliderSpeed').value = i.sx;
d.getElementById('sliderIntensity').value = i.ix; d.getElementById('sliderIntensity').value = i.ix;
d.getElementById('fxb' + selectedFx).style.backgroundColor = "var(--c-3)"; // Effects
e1.querySelector(`input[name="fx"][value="${i.fx}"]`).checked = true;
var selElement = e1.querySelector('.selected');
if (selElement) {
selElement.classList.remove('selected')
}
var selectedEffect = e1.querySelector(`.lstI[data-id="${i.fx}"]`);
selectedEffect.classList.add('selected');
selectedFx = i.fx; selectedFx = i.fx;
e2.value = i.pal;
if (!command) d.getElementById('Effects').scrollTop = d.getElementById('fxb' + selectedFx).offsetTop - d.getElementById('Effects').clientHeight/1.8; // Palettes
e2.querySelector(`input[name="palette"][value="${i.pal}"]`).checked = true;
selElement = e2.querySelector('.selected');
if (selElement) {
selElement.classList.remove('selected')
}
e2.querySelector(`.lstI[data-id="${i.pal}"]`).classList.add('selected');
if (!command) {
selectedEffect.scrollIntoView({
behavior: 'smooth',
block: 'nearest',
});
}
if (s.error && s.error != 0) { if (s.error && s.error != 0) {
var errstr = ""; var errstr = "";
switch (s.error) { switch (s.error) {
case 10: errstr = "Could not mount filesystem!"; break; case 10:
case 11: errstr = "Not enough space to save preset!"; break; errstr = "Could not mount filesystem!";
case 12: errstr = "The requested preset does not exist."; break; break;
case 19: errstr = "A filesystem error has occured."; break; case 11:
errstr = "Not enough space to save preset!";
break;
case 12:
errstr = "The requested preset does not exist.";
break;
case 19:
errstr = "A filesystem error has occured.";
break;
} }
showToast('Error ' + s.error + ": " + errstr, true); showToast('Error ' + s.error + ": " + errstr, true);
} }
@ -868,12 +1115,21 @@ function toggleLiveview() {
} }
function toggleInfo() { function toggleInfo() {
if (isNodes) toggleNodes();
isInfo = !isInfo; isInfo = !isInfo;
if (isInfo) populateInfo(lastinfo); if (isInfo) populateInfo(lastinfo);
d.getElementById('info').style.transform = (isInfo) ? "translateY(0px)":"translateY(100%)"; d.getElementById('info').style.transform = (isInfo) ? "translateY(0px)":"translateY(100%)";
d.getElementById('buttonI').className = (isInfo) ? "active":""; d.getElementById('buttonI').className = (isInfo) ? "active":"";
} }
function toggleNodes() {
if (isInfo) toggleInfo();
isNodes = !isNodes;
d.getElementById('nodes').style.transform = (isNodes) ? "translateY(0px)":"translateY(100%)";
d.getElementById('buttonNodes').className = (isNodes) ? "active":"";
if (isNodes) loadNodes();
}
function makeSeg() { function makeSeg() {
var ns = 0; var ns = 0;
if (lowestUnused > 0) { if (lowestUnused > 0) {
@ -1029,14 +1285,35 @@ function setSegBri(s){
requestJson(obj); requestJson(obj);
} }
function setX(ind) { function setX(ind = null) {
if (ind === null) {
ind = parseInt(d.querySelector('#fxlist input[name="fx"]:checked').value);
} else {
d.querySelector(`#fxlist input[name="fx"][value="${ind}`).checked = true;
}
var selElement = d.querySelector('#fxlist .selected');
if (selElement) {
selElement.classList.remove('selected')
}
d.querySelector(`#fxlist .lstI[data-id="${ind}"]`).classList.add('selected');
var obj = {"seg": {"fx": parseInt(ind)}}; var obj = {"seg": {"fx": parseInt(ind)}};
requestJson(obj); requestJson(obj);
} }
function setPalette() function setPalette(paletteId = null)
{ {
var obj = {"seg": {"pal": parseInt(d.getElementById('selectPalette').value)}}; if (paletteId === null) {
paletteId = parseInt(d.querySelector('#selectPalette input[name="palette"]:checked').value);
} else {
d.querySelector(`#selectPalette input[name="palette"][value="${paletteId}`).checked = true;
}
var selElement = d.querySelector('#selectPalette .selected');
if (selElement) {
selElement.classList.remove('selected')
}
d.querySelector(`#selectPalette .lstI[data-id="${paletteId}"]`).classList.add('selected');
var obj = {"seg": {"pal": paletteId}};
requestJson(obj); requestJson(obj);
} }
@ -1152,6 +1429,7 @@ function selectSlot(b) {
updateTrail(d.getElementById('sliderW')); updateTrail(d.getElementById('sliderW'));
updateHex(); updateHex();
updateRgb(); updateRgb();
redrawPalPrev();
} }
var lasth = 0; var lasth = 0;
@ -1278,6 +1556,88 @@ function rSegs()
requestJson(obj); requestJson(obj);
} }
function loadPalettesData()
{
if (palettesData) return;
const lsKey = "wledPalx";
var palettesDataJson = localStorage.getItem(lsKey);
if (palettesDataJson) {
try {
palettesDataJson = JSON.parse(palettesDataJson);
var d = new Date();
if (palettesDataJson && palettesDataJson.vid == lastinfo.vid) {
palettesData = palettesDataJson.p;
return;
}
} catch (e) {}
}
palettesData = {};
getPalettesData(0, function() {
localStorage.setItem(lsKey, JSON.stringify({
p: palettesData,
vid: lastinfo.vid
}));
redrawPalPrev();
});
}
function getPalettesData(page, callback)
{
var url = `/json/palx?page=${page}`;
if (loc) {
url = `http://${locip}${url}`;
}
fetch(url, {
method: 'get',
headers: {
"Content-type": "application/json; charset=UTF-8"
}
})
.then(res => {
if (!res.ok) {
showErrorToast();
}
return res.json();
})
.then(json => {
palettesData = Object.assign({}, palettesData, json.p);
if (page < json.m) {
getPalettesData(page + 1, callback);
} else {
callback();
}
})
.catch(function (error) {
showToast(error, true);
console.log(error);
presetError(false);
});
}
function search(searchField) {
var searchText = searchField.value.toUpperCase();
searchField.parentElement.getElementsByClassName('search-cancel-icon')[0].style.display = (searchText.length < 1)?"none":"inline";
var elements = searchField.parentElement.parentElement.querySelectorAll('.lstI');
for (i = 0; i < elements.length; i++) {
var item = elements[i];
var itemText = item.querySelector('.lstIname').innerText.toUpperCase();
if (itemText.indexOf(searchText) > -1) {
item.style.display = "";
} else {
item.style.display = "none";
}
}
}
function cancelSearch(ic) {
var searchField = ic.parentElement.getElementsByClassName('search')[0];
searchField.value = "";
search(searchField);
searchField.focus();
}
function expand(i,a) function expand(i,a)
{ {
if (!a) expanded[i] = !expanded[i]; if (!a) expanded[i] = !expanded[i];
@ -1303,7 +1663,7 @@ function unfocusSliders() {
} }
//sliding UI //sliding UI
const _C = document.querySelector('.container'), N = 4; const _C = d.querySelector('.container'), N = 4;
let iSlide = 0, x0 = null, scrollS = 0, locked = false, w; let iSlide = 0, x0 = null, scrollS = 0, locked = false, w;
@ -1354,6 +1714,7 @@ function move(e) {
function size() { function size() {
w = window.innerWidth; w = window.innerWidth;
d.getElementById('buttonNodes').style.display = (lastinfo.ndc > 0 && w > 770) ? "block":"none";
var h = d.getElementById('top').clientHeight; var h = d.getElementById('top').clientHeight;
sCol('--th', h + "px"); sCol('--th', h + "px");
sCol('--bh', d.getElementById('bot').clientHeight + "px"); sCol('--bh', d.getElementById('bot').clientHeight + "px");

View File

@ -0,0 +1,62 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
<meta charset="utf-8">
<meta name="theme-color" content="#222222">
<title>WLED Live Preview</title>
<style>
body {
margin: 0;
}
#canv {
background: black;
filter: brightness(175%);
width: 100%;
height: 100%;
position: absolute;
}
</style>
</head>
<body>
<div id="canv" />
<script>
console.info("Live-Preview websocket opening");
var socket = new WebSocket("ws://"+document.location.host+"/ws");
socket.onopen = function () {
console.info("Live-Preview websocket is opened");
socket.send("{'lv':true}");
}
socket.onclose = function () { console.info("Live-Preview websocket is closing"); }
socket.onerror = function (event) { console.error("Live-Preview websocket error:", event); }
function updatePreview(leds) {
var str = "linear-gradient(90deg,";
var len = leds.length;
for (i = 0; i < len; i++) {
var leddata = leds[i];
if (leddata.length > 6) leddata = leddata.substring(2);
str += "#" + leddata;
if (i < len -1) str += ","
}
str += ")";
document.getElementById("canv").style.background = str;
}
socket.onmessage = function (event) {
try {
var json = JSON.parse(event.data);
if (json && json.leds) {
requestAnimationFrame(function () {updatePreview(json.leds);});
}
}
catch (err) {
console.error("Live-Preview websocket error:",err);
}
}
</script>
</body>
</html>

View File

@ -5,7 +5,7 @@
<meta name="viewport" content="width=500"> <meta name="viewport" content="width=500">
<title>LED Settings</title> <title>LED Settings</title>
<script> <script>
var d=document,laprev=55; var d=document,laprev=55,maxB=1,maxM=5000,maxPB=4096,bquot=0; //maximum bytes for LED allocation: 5kB for 8266, 32kB for 32
function H() function H()
{ {
window.open("https://github.com/Aircoookie/WLED/wiki/Settings#led-settings"); window.open("https://github.com/Aircoookie/WLED/wiki/Settings#led-settings");
@ -13,6 +13,30 @@
function B() function B()
{ {
window.open("/settings","_self"); window.open("/settings","_self");
}
function bLimits(b,p,m) {
maxB = b; maxM = m; maxPB = p;
}
function trySubmit() {
var LCs = d.getElementsByTagName("input");
for (i=0; i<LCs.length; i++) {
var nm = LCs[i].name.substring(0,2);
//check for pin conflicts
if (nm=="L0" || nm=="L1" || nm=="RL" || nm=="BT" || nm=="IR" || nm=="AX")
if (LCs[i].value!="" && LCs[i].value!="-1") {
if (LCs[i].value > 5 && LCs[i].value < 12) {alert("Sorry, pins 6-11 can not be used.");LCs[i].focus();return;}
if (d.um_p && d.um_p.some((e)=>e==parseInt(LCs[i].value,10))) {alert("Usermod pin conflict!");LCs[i].focus();return;}
for (j=i+1; j<LCs.length; j++)
{
var n2 = LCs[j].name.substring(0,2);
if (n2=="L0" || n2=="L1" || n2=="RL" || n2=="BT" || n2=="IR" || n2=="AX")
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {alert("Pin conflict!");LCs[i].focus();return;}
}
}
}
if (bquot > 100) {var msg = "Too many LEDs for me to handle!"; if (maxM < 10000) msg += " Consider using an ESP32."; alert(msg); return;}
if (d.Sf.reportValidity()) d.Sf.submit();
} }
function S(){GetV();setABL();} function S(){GetV();setABL();}
function enABL() function enABL()
@ -42,23 +66,97 @@
case 255: d.Sf.LAsel.value = 255; break; case 255: d.Sf.LAsel.value = 255; break;
default: d.getElementById('LAdis').style.display = 'inline'; default: d.getElementById('LAdis').style.display = 'inline';
} }
d.getElementById('m1').innerHTML = maxM;
UI(); UI();
}
//returns mem usage
function getMem(type, len, p0) {
//len = parseInt(len);
if (type < 32) {
if (maxM < 10000 && p0 ==3) { //8266 DMA uses 5x the mem
if (type > 29) return len*20; //RGBW
return len*15;
} else if (maxM >= 10000) //ESP32 RMT uses double buffer?
{
if (type > 29) return len*8; //RGBW
return len*6;
}
if (type > 29) return len*4; //RGBW
return len*3;
}
if (type > 31 && type < 48) return 5;
if (type == 44 || type == 45) return len*4; //RGBW
return len*3;
} }
function UI() function UI()
{ {
var myC = d.querySelectorAll('.wc'), var isRGBW = false, memu = 0;
l = myC.length;
for (i = 0; i < l; i++) {
myC[i].style.display = (d.getElementById('rgbw').checked) ? 'inline':'none';
}
d.getElementById('ledwarning').style.display = (d.Sf.LC.value > 1000) ? 'inline':'none';
d.getElementById('ampwarning').style.display = (d.Sf.MA.value > 7200) ? 'inline':'none'; d.getElementById('ampwarning').style.display = (d.Sf.MA.value > 7200) ? 'inline':'none';
if (d.Sf.LA.value == 255) laprev = 12; if (d.Sf.LA.value == 255) laprev = 12;
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value; else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
var val = Math.ceil((100 + d.Sf.LC.value * laprev)/500)/2; var s = d.getElementsByTagName("select");
for (i=0; i<s.length; i++) {
if (s[i].name.substring(0,2)=="LT") {
n=s[i].name.substring(2);
var type = s[i].value;
d.getElementById("p0d"+n).innerHTML = (type > 49) ? "Data pin:" : (type >41) ? "Pins:" : "Pin:";
d.getElementById("p1d"+n).innerHTML = (type > 49) ? "Clk:" : "";
var LK = d.getElementsByName("L1"+n)[0];
memu += getMem(type, d.getElementsByName("LC"+n)[0].value, d.getElementsByName("L0"+n)[0].value);
for (p=1; p<5; p++) {
var LK = d.getElementsByName("L"+p+n)[0];
if (!LK) continue;
if ((type>49 && p==1) || (type>41 && type < 50 && (p+40 < type))) // TYPE_xxxx values from const.h
{
LK.style.display = "inline";
LK.required = true;
} else {
LK.style.display = "none";
LK.required = false;
LK.value="";
}
}
if (type == 30 || type == 31 || (type > 40 && type < 46 && type != 43)) isRGBW = true;
d.getElementById("dig"+n).style.display = (type > 31 && type < 48) ? "none":"inline";
d.getElementById("psd"+n).innerHTML = (type > 31 && type < 48) ? "Index:":"Start:";
}
}
var myC = d.querySelectorAll('.wc'),
l = myC.length;
for (i = 0; i < l; i++) {
myC[i].style.display = (isRGBW) ? 'inline':'none';
}
if (d.activeElement == d.getElementsByName("LC")[0]) {
var o = d.getElementsByClassName("iST");
var i = o.length;
if (i == 1) d.getElementsByName("LC0")[0].value = d.getElementsByName("LC")[0].value;
}
var LCs = d.getElementsByTagName("input");
var sLC = 0, maxLC = 0;
for (i=0; i<LCs.length; i++) {
var nm = LCs[i].name.substring(0,2);
if (nm=="LC" && LCs[i].name != "LC") {var c = parseInt(LCs[i].value,10); if (c) {sLC+=c; if (c>maxLC) maxLC = c;} continue;}
}
d.getElementById('m0').innerHTML = memu;
bquot = memu / maxM * 100;
d.getElementById('dbar').style.background = `linear-gradient(90deg, ${bquot > 60 ? bquot > 90 ? "red":"orange":"#ccc"} 0 ${bquot}%%, #444 ${bquot}%% 100%%)`;
d.getElementById('ledwarning').style.display = (maxLC > 800 || bquot > 80) ? 'inline':'none';
//TODO add warning "Recommended pins on ESP8266 are 1 and 2 (3 only with low LED count)"
//TODO add overmemory warning
//TODO block disallowed pins 6-11
d.getElementById('wreason').innerHTML = (bquot > 80) ? "than 60%% of max. LED memory" : "800 LEDs per pin";
//var val = Math.ceil((100 + d.Sf.LC.value * laprev)/500)/2;
var val = Math.ceil((100 + sLC * laprev)/500)/2;
val = (val > 5) ? Math.ceil(val) : val; val = (val > 5) ? Math.ceil(val) : val;
var s = ""; var s = "";
var is12V = (d.Sf.LAsel.value == 30); var is12V = (d.Sf.LAsel.value == 30);
@ -72,17 +170,84 @@
s += val; s += val;
s += "A supply connected to LEDs"; s += "A supply connected to LEDs";
} }
var val2 = Math.ceil((100 + d.Sf.LC.value * laprev)/1500)/2; var val2 = Math.ceil((100 + sLC * laprev)/1500)/2;
val2 = (val2 > 5) ? Math.ceil(val2) : val2; val2 = (val2 > 5) ? Math.ceil(val2) : val2;
var s2 = "(for most effects, ~"; var s2 = "(for most effects, ~";
s2 += val2; s2 += val2;
s2 += "A is enough)<br>"; s2 += "A is enough)<br>";
d.getElementById('psu').innerHTML = s; d.getElementById('psu').innerHTML = s;
d.getElementById('psu2').innerHTML = isWS2815 ? "" : s2; d.getElementById('psu2').innerHTML = isWS2815 ? "" : s2;
}
function lastEnd(i) {
if (i<1) return 0;
v = parseInt(d.getElementsByName("LS"+(i-1))[0].value) + parseInt(d.getElementsByName("LC"+(i-1))[0].value);
if (isNaN(v)) return 0;
return v;
}
function addLEDs(n)
{
if (n>1) {maxB=n; d.getElementById("+").style.display="inline"; return;}
var o = d.getElementsByClassName("iST");
var i = o.length;
if ((n==1 && i>=maxB) || (n==-1 && i==0)) return;
var f = d.getElementById("mLC");
if (n==1) {
var cn = `<div class="iST">
${i>0?'<hr style="width:260px">':''}
${i+1}:
<select name="LT${i}" onchange="UI()">
<option value="22">WS281x</option>
<option value="30">SK6812 RGBW</option>
<option value="31">TM1814</option>
<option value="24">400kHz</option>
<option value="50">WS2801</option>
<option value="51">APA102</option>
<option value="52">LPD8806</option>
<option value="53">P9813</option>
<option value="41">PWM White</option>
<option value="42">PWM WWCW</option>
<option value="43">PWM RGB</option>
<option value="44">PWM RGBW</option>
<option value="45">PWM RGBWC</option>
</select>&nbsp;
Color Order:
<select name="CO${i}">
<option value="0">GRB</option>
<option value="1">RGB</option>
<option value="2">BRG</option>
<option value="3">RBG</option>
<option value="4">BGR</option>
<option value="5">GBR</option>
</select><br>
<span id="p0d${i}">Pin:</span> <input type="number" name="L0${i}" min="0" max="40" required style="width:35px" oninput="UI()"/>
<span id="p1d${i}">Clock:</span> <input type="number" name="L1${i}" min="0" max="40" style="width:35px"/>
<span id="p2d${i}"></span><input type="number" name="L2${i}" min="0" max="40" style="width:35px"/>
<span id="p3d${i}"></span><input type="number" name="L3${i}" min="0" max="40" style="width:35px"/>
<span id="p4d${i}"></span><input type="number" name="L4${i}" min="0" max="40" style="width:35px"/>
<br>
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" min="0" max="8191" value="${lastEnd(i)}" required />&nbsp;
<div id="dig${i}" style="display:inline">
Count: <input type="number" name="LC${i}" min="0" max="${maxPB}" value="1" required oninput="UI()" /><br>
Reverse: <input type="checkbox" name="CV${i}"></div><br>
</div>`;
f.insertAdjacentHTML("beforeend", cn);
}
if (n==-1) {
o[--i].remove();--i;
}
d.getElementById("+").style.display = (i<maxB-1) ? "inline":"none";
d.getElementById("-").style.display = (i>0) ? "inline":"none";
UI();
} }
function GetV() function GetV()
{ {
//values injected by server while sending HTML //values injected by server while sending HTML
//d.um_p=[];addLEDs(3);d.Sf.LC.value=250;addLEDs(1);d.Sf.L00.value=2;d.Sf.L10.value=0;d.Sf.LC0.value=250;d.Sf.LT0.value=22;d.Sf.CO0.value=0;d.Sf.LS0.value=0;d.Sf.LS0.checked=0;d.Sf.MA.value=5400;d.Sf.LA.value=55;d.getElementsByClassName("pow")[0].innerHTML="350mA";d.Sf.CA.value=40;d.Sf.AW.value=3;d.Sf.BO.checked=0;d.Sf.BP.value=3;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=0;d.Sf.BF.value=64;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=1;d.Sf.PB.selectedIndex=0;d.Sf.RV.checked=0;d.Sf.SL.checked=0;d.Sf.RL.value=12;d.Sf.RM.checked=0;d.Sf.BT.value=-1;d.Sf.IR.value=-1;d.Sf.AX.value=-1;
} }
</script> </script>
<style> <style>
@ -92,13 +257,9 @@
<body onload="S()"> <body onload="S()">
<form id="form_s" name="Sf" method="post"> <form id="form_s" name="Sf" method="post">
<div class="helpB"><button type="button" onclick="H()">?</button></div> <div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr> <button type="button" onclick="B()">Back</button><button type="button" onclick="trySubmit()">Save</button><hr>
<h2>LED setup</h2> <h2>LED &amp; Hardware setup</h2>
LED count: <input name="LC" type="number" min="1" max="1500" oninput="UI()" required><br> Total LED count: <input name="LC" type="number" min="1" max="8192" oninput="UI()" required><br>
<div id="ledwarning" style="color: orange; display: none;">
&#9888; You might run into stability or lag issues.<br>
Use less than 1000 LEDs per ESP for the best experience!<br>
</div>
<i>Recommended power supply for brightest white:</i><br> <i>Recommended power supply for brightest white:</i><br>
<b><span id="psu">?</span></b><br> <b><span id="psu">?</span></b><br>
<span id="psu2"><br></span> <span id="psu2"><br></span>
@ -127,27 +288,20 @@
<span id="LAdis" style="display: none;">Custom max. current per LED: <input name="LA" type="number" min="0" max="255" id="la" oninput="UI()" required> mA<br></span> <span id="LAdis" style="display: none;">Custom max. current per LED: <input name="LA" type="number" min="0" max="255" id="la" oninput="UI()" required> mA<br></span>
<i>Keep at default if you are unsure about your type of LEDs.</i><br> <i>Keep at default if you are unsure about your type of LEDs.</i><br>
</div> </div>
<br> <h3>Hardware setup</h3>
LEDs are 4-channel type (RGBW): <input type="checkbox" name="EW" onchange=UI() id="rgbw"><br> <div id="mLC">LED outputs:</div>
<span class="wc"> <button type="button" id="+" onclick="addLEDs(1)" style="display:none;border-radius:20px;height:36px;">+</button>
Auto-calculate white channel from RGB:<br> <button type="button" id="-" onclick="addLEDs(-1)" style="display:none;border-radius:20px;width:36px;height:36px;">-</button><br>
<select name=AW> LED Memory Usage: <span id="m0">0</span> / <span id="m1">?</span> B<br>
<option value=0>None</option> <div id="dbar" style="display:inline-block; width: 100px; height: 10px; border-radius: 20px;"></div><br>
<option value=1>Brighter</option> <div id="ledwarning" style="color: orange; display: none;">
<option value=2>Accurate</option> &#9888; You might run into stability or lag issues.<br>
<option value=3>Dual</option> Use less than <span id="wreason">800 LEDs per pin</span> for the best experience!<br>
<option value=4>Legacy</option> </div><br>
</select> Relay pin: <input type="number" min="-1" max="40" name="RL" onchange="UI()"> Active high <input type="checkbox" name="RM"><br>
<br></span> Button pin: <input type="number" min="-1" max="40" name="BT" onchange="UI()"><br>
Color order: IR pin: <input type="number" min="-1" max="40" name="IR" onchange="UI()"><br>
<select name="CO"> AUX pin: <input type="number" min="-1" max="40" name="AX" onchange="UI()">
<option value=0>GRB</option>
<option value=1>RGB</option>
<option value=2>BRG</option>
<option value=3>RBG</option>
<option value=4>BGR</option>
<option value=5>GBR</option>
</select>
<h3>Defaults</h3> <h3>Defaults</h3>
Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br> Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br>
Default brightness: <input name="CA" type="number" min="0" max="255" required> (0-255)<br><br> Default brightness: <input name="CA" type="number" min="0" max="255" required> (0-255)<br><br>
@ -180,8 +334,18 @@
<option value="3">None (not recommended)</option> <option value="3">None (not recommended)</option>
</select><br> </select><br>
Reverse LED order (rotate 180): <input type="checkbox" name="RV"><br> Reverse LED order (rotate 180): <input type="checkbox" name="RV"><br>
Skip first LED: <input type="checkbox" name="SL"><hr> Skip first LED: <input type="checkbox" name="SL"><br>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button> <span class="wc">
Auto-calculate white channel from RGB:<br>
<select name="AW">
<option value=0>None</option>
<option value=1>Brighter</option>
<option value=2>Accurate</option>
<option value=3>Dual</option>
<option value=4>Legacy</option>
</select>
<br></span><hr>
<button type="button" onclick="B()">Back</button><button type="button" onclick="trySubmit()">Save</button>
</form> </form>
</body> </body>
</html> </html>

View File

@ -40,6 +40,9 @@ Send Philips Hue change notifications: <input type="checkbox" name="SH"><br>
Send Macro notifications: <input type="checkbox" name="SM"><br> Send Macro notifications: <input type="checkbox" name="SM"><br>
Send notifications twice: <input type="checkbox" name="S2"><br> Send notifications twice: <input type="checkbox" name="S2"><br>
<i>Reboot required to apply changes. </i> <i>Reboot required to apply changes. </i>
<h3>Instance List</h3>
Enable instance list: <input type="checkbox" name="NL"><br>
Make this instance discoverable: <input type="checkbox" name="NB"><br>
<h3>Realtime</h3> <h3>Realtime</h3>
Receive UDP realtime: <input type="checkbox" name="RD"><br><br> Receive UDP realtime: <input type="checkbox" name="RD"><br><br>
<i>Network DMX input</i><br> <i>Network DMX input</i><br>

View File

@ -68,9 +68,11 @@
<h3>Ethernet Type</h3> <h3>Ethernet Type</h3>
<select name="ETH"> <select name="ETH">
<option value="0">None</option> <option value="0">None</option>
<option value="1">WT32-ETH01</option>
<option value="2">ESP32-POE</option> <option value="2">ESP32-POE</option>
<option value="3">WESP32</option></select><br><br></div> <option value="4">QuinLED-ESP32</option>
<option value="3">WESP32</option>
<option value="1">WT32-ETH01</option>
</select><br><br></div>
<hr> <hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button> <button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button>
</form> </form>

View File

@ -62,10 +62,6 @@ void initDMX() {
dmx.init(512); // initialize with bus length dmx.init(512); // initialize with bus length
} }
#if (LEDPIN == 2)
#pragma message "Pin conflict compiling with DMX and LEDs on pin 2. Please set a different LEDPIN."
#endif
#else #else
void handleDMX() {} void handleDMX() {}
void initDMX() {} void initDMX() {}

View File

@ -35,7 +35,8 @@ void handleDDPPacket(e131_packet_t* p) {
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP); realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP);
for (uint16_t i = start; i < stop; i++) { for (uint16_t i = start; i < stop; i++) {
setRealtimePixel(i, data[c++], data[c++], data[c++], 0); setRealtimePixel(i, data[c], data[c+1], data[c+2], 0);
c+=3;
} }
bool push = p->flags & DDP_PUSH_FLAG; bool push = p->flags & DDP_PUSH_FLAG;
@ -187,11 +188,13 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
uint16_t ledsTotal = previousLeds + (dmxChannels - dmxOffset +1) / dmxChannelsPerLed; uint16_t ledsTotal = previousLeds + (dmxChannels - dmxOffset +1) / dmxChannelsPerLed;
if (!is4Chan) { if (!is4Chan) {
for (uint16_t i = previousLeds; i < ledsTotal; i++) { for (uint16_t i = previousLeds; i < ledsTotal; i++) {
setRealtimePixel(i, e131_data[dmxOffset++], e131_data[dmxOffset++], e131_data[dmxOffset++], 0); setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], 0);
dmxOffset+=3;
} }
} else { } else {
for (uint16_t i = previousLeds; i < ledsTotal; i++) { for (uint16_t i = previousLeds; i < ledsTotal; i++) {
setRealtimePixel(i, e131_data[dmxOffset++], e131_data[dmxOffset++], e131_data[dmxOffset++], e131_data[dmxOffset++]); setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], e131_data[dmxOffset+3]);
dmxOffset+=4;
} }
} }
break; break;

View File

@ -76,7 +76,6 @@ bool decodeIRCustom(uint32_t code);
void applyRepeatActions(); void applyRepeatActions();
void relativeChange(byte* property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF); void relativeChange(byte* property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF);
void changeEffectSpeed(int8_t amount); void changeEffectSpeed(int8_t amount);
void changeBrightness(int8_t amount);
void changeEffectIntensity(int8_t amount); void changeEffectIntensity(int8_t amount);
void decodeIR(uint32_t code); void decodeIR(uint32_t code);
void decodeIR24(uint32_t code); void decodeIR24(uint32_t code);
@ -149,23 +148,8 @@ void setCronixie();
void _overlayCronixie(); void _overlayCronixie();
void _drawOverlayCronixie(); void _drawOverlayCronixie();
//pin_manager.cpp
class PinManagerClass {
private:
#ifdef ESP8266
uint8_t pinAlloc[3] = {0x00, 0x00, 0x00}; //24bit, 1 bit per pin, we use first 17bits
#else
uint8_t pinAlloc[5] = {0x00, 0x00, 0x00, 0x00, 0x00}; //40bit, 1 bit per pin, we use all bits
#endif
public:
void deallocatePin(byte gpio);
bool allocatePin(byte gpio, bool output = true);
bool isPinAllocated(byte gpio);
bool isPinOk(byte gpio, bool output = true);
};
//playlist.cpp //playlist.cpp
void unloadPlaylist();
void loadPlaylist(JsonObject playlistObject); void loadPlaylist(JsonObject playlistObject);
void handlePlaylist(); void handlePlaylist();
@ -187,6 +171,8 @@ void notify(byte callMode, bool followUp=false);
void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC); void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
void handleNotifications(); void handleNotifications();
void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w); void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w);
void refreshNodeList();
void sendSysInfoUDP();
//um_manager.cpp //um_manager.cpp
class Usermod { class Usermod {

View File

@ -33,8 +33,10 @@ File f;
//wrapper to find out how long closing takes //wrapper to find out how long closing takes
void closeFile() { void closeFile() {
#ifdef WLED_DEBUG_FS
DEBUGFS_PRINT(F("Close -> ")); DEBUGFS_PRINT(F("Close -> "));
uint32_t s = millis(); uint32_t s = millis();
#endif
f.close(); f.close();
DEBUGFS_PRINTF("took %d ms\n", millis() - s); DEBUGFS_PRINTF("took %d ms\n", millis() - s);
doCloseFile = false; doCloseFile = false;
@ -53,7 +55,6 @@ bool bufferedFind(const char *target, bool fromStart = true) {
size_t targetLen = strlen(target); size_t targetLen = strlen(target);
size_t index = 0; size_t index = 0;
byte c;
uint16_t bufsize = 0, count = 0; uint16_t bufsize = 0, count = 0;
byte buf[FS_BUFSIZE]; byte buf[FS_BUFSIZE];
if (fromStart) f.seek(0); if (fromStart) f.seek(0);

View File

@ -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} .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" </style></head><body><h2>WLED Software Update</h2><form method="POST"
action="/update" id="uf" enctype="multipart/form-data" onsubmit="U()"> action="/update" id="uf" enctype="multipart/form-data" onsubmit="U()">
Installed version: 0.11.1<br>Download the latest binary: <a Installed version: 0.12.0-a0<br>Download the latest binary: <a
href="https://github.com/Aircoookie/WLED/releases" target="_blank"><img href="https://github.com/Aircoookie/WLED/releases" target="_blank"><img
src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"> src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square">
</a><br><input type="file" class="bt" name="update" accept=".bin" required><br> </a><br><input type="file" class="bt" name="update" accept=".bin" required><br>
@ -78,6 +78,17 @@ update();var tmout=null;function update(){if(document.hidden)return clearTimeout
</script></body></html>)====="; </script></body></html>)=====";
// Autogenerated from wled00/data/liveviewws.htm, do not edit!!
const char PAGE_liveviewws[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1"><meta
charset="utf-8"><meta name="theme-color" content="#222222"><title>
WLED Live Preview</title><style>
body{margin:0}#canv{background:#000;filter:brightness(175%);width:100%;height:100%;position:absolute}
</style></head><body><div id="canv"><script>
console.info("Live-Preview websocket opening");var socket=new WebSocket("ws://"+document.location.host+"/ws");function updatePreview(e){var o="linear-gradient(90deg,",n=e.length;for(i=0;i<n;i++){var t=e[i];t.length>6&&(t=t.substring(2)),o+="#"+t,i<n-1&&(o+=",")}o+=")",document.getElementById("canv").style.background=o}socket.onopen=function(){console.info("Live-Preview websocket is opened"),socket.send("{'lv':true}")},socket.onclose=function(){console.info("Live-Preview websocket is closing")},socket.onerror=function(e){console.error("Live-Preview websocket error:",e)},socket.onmessage=function(e){try{var o=JSON.parse(e.data);o&&o.leds&&requestAnimationFrame((function(){updatePreview(o.leds)}))}catch(e){console.error("Live-Preview websocket error:",e)}}
</script></body></html>)=====";
// Autogenerated from wled00/data/404.htm, do not edit!! // Autogenerated from wled00/data/404.htm, do not edit!!
const char PAGE_404[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta charset="utf-8"><meta const char PAGE_404[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta charset="utf-8"><meta
content="width=device-width" name="viewport"><meta name="theme-color" content="width=device-width" name="viewport"><meta name="theme-color"

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,54 @@ uint16_t irTimesRepeated = 0;
uint8_t lastIR6ColourIdx = 0; uint8_t lastIR6ColourIdx = 0;
// brightnessSteps: a static array of brightness levels following a geometric
// progression. Can be generated from the following Python, adjusting the
// arbitrary 4.5 value to taste:
//
// def values(level):
// while level >= 5:
// yield int(level)
// level -= level / 4.5
// result = [v for v in reversed(list(values(255)))]
// print("%d values: %s" % (len(result), result))
//
// It would be hard to maintain repeatable steps if calculating this on the fly.
const byte brightnessSteps[] = {
5, 7, 9, 12, 16, 20, 26, 34, 43, 56, 72, 93, 119, 154, 198, 255
};
const size_t numBrightnessSteps = sizeof(brightnessSteps) / sizeof(uint8_t);
// increment `bri` to the next `brightnessSteps` value
void incBrightness()
{
// dumb incremental search is efficient enough for so few items
for (int index = 0; index < numBrightnessSteps; ++index)
{
if (brightnessSteps[index] > bri)
{
bri = brightnessSteps[index];
lastRepeatableAction = ACTION_BRIGHT_UP;
break;
}
}
}
// decrement `bri` to the next `brightnessSteps` value
void decBrightness()
{
// dumb incremental search is efficient enough for so few items
for (int index = numBrightnessSteps - 1; index >= 0; --index)
{
if (brightnessSteps[index] < bri)
{
bri = brightnessSteps[index];
lastRepeatableAction = ACTION_BRIGHT_DOWN;
break;
}
}
}
//Add what your custom IR codes should trigger here. Guide: https://github.com/Aircoookie/WLED/wiki/Infrared-Control //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" //IR codes themselves can be defined directly after "case" or in "ir_codes.h"
bool decodeIRCustom(uint32_t code) bool decodeIRCustom(uint32_t code)
@ -47,16 +95,6 @@ void relativeChange(byte* property, int8_t amount, byte lowerBoundary, byte high
*property = (byte)constrain(new_val,0.1,255.1); *property = (byte)constrain(new_val,0.1,255.1);
} }
void changeBrightness(int8_t amount)
{
int16_t new_val = bri + amount;
if (new_val < 5) new_val = 5; //minimum brightness A=5
bri = (byte)constrain(new_val,0.1,255.1);
if(amount > 0) lastRepeatableAction = ACTION_BRIGHT_UP;
if(amount < 0) lastRepeatableAction = ACTION_BRIGHT_DOWN;
lastRepeatableValue = amount;
}
void changeEffectSpeed(int8_t amount) void changeEffectSpeed(int8_t amount)
{ {
if (effectCurrent != 0) { if (effectCurrent != 0) {
@ -142,11 +180,11 @@ void applyRepeatActions(){
if (lastRepeatableAction == ACTION_BRIGHT_UP) if (lastRepeatableAction == ACTION_BRIGHT_UP)
{ {
changeBrightness(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); incBrightness(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
} }
else if (lastRepeatableAction == ACTION_BRIGHT_DOWN ) else if (lastRepeatableAction == ACTION_BRIGHT_DOWN )
{ {
changeBrightness(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); decBrightness(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
} }
if (lastRepeatableAction == ACTION_SPEED_UP) if (lastRepeatableAction == ACTION_SPEED_UP)
@ -187,8 +225,8 @@ void applyRepeatActions(){
void decodeIR24(uint32_t code) void decodeIR24(uint32_t code)
{ {
switch (code) { switch (code) {
case IR24_BRIGHTER : changeBrightness(10); break; case IR24_BRIGHTER : incBrightness(); break;
case IR24_DARKER : changeBrightness(-10); break; case IR24_DARKER : decBrightness(); break;
case IR24_OFF : briLast = bri; bri = 0; break; case IR24_OFF : briLast = bri; bri = 0; break;
case IR24_ON : bri = briLast; break; case IR24_ON : bri = briLast; break;
case IR24_RED : colorFromUint32(COLOR_RED); break; case IR24_RED : colorFromUint32(COLOR_RED); break;
@ -219,8 +257,8 @@ void decodeIR24(uint32_t code)
void decodeIR24OLD(uint32_t code) void decodeIR24OLD(uint32_t code)
{ {
switch (code) { switch (code) {
case IR24_OLD_BRIGHTER : changeBrightness(10); break; case IR24_OLD_BRIGHTER : incBrightness(); break;
case IR24_OLD_DARKER : changeBrightness(-10); break; case IR24_OLD_DARKER : decBrightness(); break;
case IR24_OLD_OFF : briLast = bri; bri = 0; break; case IR24_OLD_OFF : briLast = bri; bri = 0; break;
case IR24_OLD_ON : bri = briLast; break; case IR24_OLD_ON : bri = briLast; break;
case IR24_OLD_RED : colorFromUint32(COLOR_RED); break; case IR24_OLD_RED : colorFromUint32(COLOR_RED); break;
@ -252,8 +290,8 @@ void decodeIR24OLD(uint32_t code)
void decodeIR24CT(uint32_t code) void decodeIR24CT(uint32_t code)
{ {
switch (code) { switch (code) {
case IR24_CT_BRIGHTER : changeBrightness(10); break; case IR24_CT_BRIGHTER : incBrightness(); break;
case IR24_CT_DARKER : changeBrightness(-10); break; case IR24_CT_DARKER : decBrightness(); break;
case IR24_CT_OFF : briLast = bri; bri = 0; break; case IR24_CT_OFF : briLast = bri; bri = 0; break;
case IR24_CT_ON : bri = briLast; break; case IR24_CT_ON : bri = briLast; break;
case IR24_CT_RED : colorFromUint32(COLOR_RED); break; case IR24_CT_RED : colorFromUint32(COLOR_RED); break;
@ -287,8 +325,8 @@ void decodeIR24CT(uint32_t code)
void decodeIR40(uint32_t code) void decodeIR40(uint32_t code)
{ {
switch (code) { switch (code) {
case IR40_BPLUS : changeBrightness(10); break; case IR40_BPLUS : incBrightness(); break;
case IR40_BMINUS : changeBrightness(-10); break; case IR40_BMINUS : decBrightness(); break;
case IR40_OFF : briLast = bri; bri = 0; break; case IR40_OFF : briLast = bri; bri = 0; break;
case IR40_ON : bri = briLast; break; case IR40_ON : bri = briLast; break;
case IR40_RED : colorFromUint24(COLOR_RED); break; case IR40_RED : colorFromUint24(COLOR_RED); break;
@ -344,8 +382,8 @@ void decodeIR40(uint32_t code)
void decodeIR44(uint32_t code) void decodeIR44(uint32_t code)
{ {
switch (code) { switch (code) {
case IR44_BPLUS : changeBrightness(10); break; case IR44_BPLUS : incBrightness(); break;
case IR44_BMINUS : changeBrightness(-10); break; case IR44_BMINUS : decBrightness(); break;
case IR44_OFF : briLast = bri; bri = 0; break; case IR44_OFF : briLast = bri; bri = 0; break;
case IR44_ON : bri = briLast; break; case IR44_ON : bri = briLast; break;
case IR44_RED : colorFromUint24(COLOR_RED); break; case IR44_RED : colorFromUint24(COLOR_RED); break;
@ -407,8 +445,8 @@ void decodeIR44(uint32_t code)
void decodeIR21(uint32_t code) void decodeIR21(uint32_t code)
{ {
switch (code) { switch (code) {
case IR21_BRIGHTER: changeBrightness(10); break; case IR21_BRIGHTER: incBrightness(); break;
case IR21_DARKER: changeBrightness(-10); break; case IR21_DARKER: decBrightness(); break;
case IR21_OFF: briLast = bri; bri = 0; break; case IR21_OFF: briLast = bri; bri = 0; break;
case IR21_ON: bri = briLast; break; case IR21_ON: bri = briLast; break;
case IR21_RED: colorFromUint32(COLOR_RED); break; case IR21_RED: colorFromUint32(COLOR_RED); break;
@ -437,8 +475,8 @@ void decodeIR6(uint32_t code)
{ {
switch (code) { switch (code) {
case IR6_POWER: toggleOnOff(); break; case IR6_POWER: toggleOnOff(); break;
case IR6_CHANNEL_UP: changeBrightness(10); break; case IR6_CHANNEL_UP: incBrightness(); break;
case IR6_CHANNEL_DOWN: changeBrightness(-10); break; case IR6_CHANNEL_DOWN: decBrightness(); break;
case IR6_VOLUME_UP: relativeChange(&effectCurrent, 1, 0, MODE_COUNT); break; // next effect case IR6_VOLUME_UP: relativeChange(&effectCurrent, 1, 0, MODE_COUNT); break; // next effect
case IR6_VOLUME_DOWN: // next palette case IR6_VOLUME_DOWN: // next palette
relativeChange(&effectPalette, 1, 0, strip.getPaletteCount() -1); relativeChange(&effectPalette, 1, 0, strip.getPaletteCount() -1);
@ -472,8 +510,8 @@ void decodeIR9(uint32_t code)
case IR9_A : if (!applyPreset(1)) effectCurrent = FX_MODE_COLORTWINKLE; break; case IR9_A : if (!applyPreset(1)) effectCurrent = FX_MODE_COLORTWINKLE; break;
case IR9_B : if (!applyPreset(2)) effectCurrent = FX_MODE_RAINBOW_CYCLE; break; case IR9_B : if (!applyPreset(2)) effectCurrent = FX_MODE_RAINBOW_CYCLE; break;
case IR9_C : if (!applyPreset(3)) effectCurrent = FX_MODE_BREATH; break; case IR9_C : if (!applyPreset(3)) effectCurrent = FX_MODE_BREATH; break;
case IR9_UP : changeBrightness(16); break; case IR9_UP : incBrightness(); break;
case IR9_DOWN : changeBrightness(-16); break; case IR9_DOWN : decBrightness(); break;
//case IR9_UP : changeEffectIntensity(16); break; //case IR9_UP : changeEffectIntensity(16); break;
//case IR9_DOWN : changeEffectIntensity(-16); break; //case IR9_DOWN : changeEffectIntensity(-16); break;
case IR9_LEFT : changeEffectSpeed(-16); break; case IR9_LEFT : changeEffectSpeed(-16); break;
@ -488,7 +526,7 @@ void initIR()
{ {
if (irEnabled > 0) if (irEnabled > 0)
{ {
irrecv = new IRrecv(IRPIN); irrecv = new IRrecv(irPin);
irrecv->enableIRIn(); irrecv->enableIRIn();
} }
} }

View File

@ -1,12 +1,14 @@
#include "wled.h" #include "wled.h"
#include "palettes.h"
/* /*
* JSON API (De)serialization * JSON API (De)serialization
*/ */
void deserializeSegment(JsonObject elem, byte it) void deserializeSegment(JsonObject elem, byte it)
{ {
byte id = elem[F("id")] | it; byte id = elem["id"] | it;
if (id < strip.getMaxSegments()) if (id < strip.getMaxSegments())
{ {
WS2812FX::Segment& seg = strip.getSegment(id); WS2812FX::Segment& seg = strip.getSegment(id);
@ -31,7 +33,7 @@ void deserializeSegment(JsonObject elem, byte it)
seg.setOption(SEG_OPTION_ON, elem["on"] | seg.getOption(SEG_OPTION_ON), id); seg.setOption(SEG_OPTION_ON, elem["on"] | seg.getOption(SEG_OPTION_ON), id);
JsonArray colarr = elem[F("col")]; JsonArray colarr = elem["col"];
if (!colarr.isNull()) if (!colarr.isNull())
{ {
for (uint8_t i = 0; i < 3; i++) for (uint8_t i = 0; i < 3; i++)
@ -57,7 +59,8 @@ void deserializeSegment(JsonObject elem, byte it)
if (sz == 0) continue; //do nothing on empty array if (sz == 0) continue; //do nothing on empty array
byte cp = copyArray(colX, rgbw, 4); byte cp = copyArray(colX, rgbw, 4);
if (cp == 1 && rgbw[0] == 0) seg.setColor(i, 0, id); if (cp == 1 && rgbw[0] == 0)
seg.setColor(i, 0, id);
colValid = true; colValid = true;
} }
@ -87,7 +90,7 @@ void deserializeSegment(JsonObject elem, byte it)
//if (pal != seg.palette && pal < strip.getPaletteCount()) strip.setPalette(pal); //if (pal != seg.palette && pal < strip.getPaletteCount()) strip.setPalette(pal);
seg.setOption(SEG_OPTION_SELECTED, elem[F("sel")] | seg.getOption(SEG_OPTION_SELECTED)); seg.setOption(SEG_OPTION_SELECTED, elem[F("sel")] | seg.getOption(SEG_OPTION_SELECTED));
seg.setOption(SEG_OPTION_REVERSED, elem[F("rev")] | seg.getOption(SEG_OPTION_REVERSED)); seg.setOption(SEG_OPTION_REVERSED, elem["rev"] | seg.getOption(SEG_OPTION_REVERSED));
seg.setOption(SEG_OPTION_MIRROR , elem[F("mi")] | seg.getOption(SEG_OPTION_MIRROR )); seg.setOption(SEG_OPTION_MIRROR , elem[F("mi")] | seg.getOption(SEG_OPTION_MIRROR ));
//temporary, strip object gets updated via colorUpdated() //temporary, strip object gets updated via colorUpdated()
@ -134,7 +137,7 @@ void deserializeSegment(JsonObject elem, byte it)
if (sz == 0 && sz > 4) break; if (sz == 0 && sz > 4) break;
int rgbw[] = {0,0,0,0}; int rgbw[] = {0,0,0,0};
byte cp = copyArray(icol, rgbw); copyArray(icol, rgbw);
if (set < 2) stop = start + 1; if (set < 2) stop = start + 1;
for (uint16_t i = start; i < stop; i++) { for (uint16_t i = start; i < stop; i++) {
@ -196,12 +199,12 @@ bool deserializeState(JsonObject root)
nightlightTargetBri = nl[F("tbri")] | nightlightTargetBri; nightlightTargetBri = nl[F("tbri")] | nightlightTargetBri;
JsonObject udpn = root["udpn"]; JsonObject udpn = root["udpn"];
notifyDirect = udpn[F("send")] | notifyDirect; notifyDirect = udpn["send"] | notifyDirect;
receiveNotifications = udpn[F("recv")] | receiveNotifications; receiveNotifications = udpn["recv"] | receiveNotifications;
bool noNotification = udpn[F("nn")]; //send no notification just for this request bool noNotification = udpn[F("nn")]; //send no notification just for this request
unsigned long timein = root[F("time")] | -1; unsigned long timein = root[F("time")] | UINT32_MAX;
if (timein != -1) { if (timein != UINT32_MAX) {
if (millis() - ntpLastSyncTime > 50000000L) setTime(timein); if (millis() - ntpLastSyncTime > 50000000L) setTime(timein);
if (presetsModifiedTime == 0) presetsModifiedTime = timein; if (presetsModifiedTime == 0) presetsModifiedTime = timein;
} }
@ -225,7 +228,7 @@ bool deserializeState(JsonObject root)
JsonVariant segVar = root["seg"]; JsonVariant segVar = root["seg"];
if (segVar.is<JsonObject>()) if (segVar.is<JsonObject>())
{ {
int id = segVar[F("id")] | -1; int id = segVar["id"] | -1;
if (id < 0) { //set all selected segments if (id < 0) { //set all selected segments
bool didSet = false; bool didSet = false;
@ -279,7 +282,8 @@ bool deserializeState(JsonObject root)
JsonObject playlist = root[F("playlist")]; JsonObject playlist = root[F("playlist")];
if (!playlist.isNull()) { if (!playlist.isNull()) {
loadPlaylist(playlist); return stateResponse; loadPlaylist(playlist);
noNotification = true; //do not notify both for this request and the first playlist entry
} }
colorUpdated(noNotification ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE); colorUpdated(noNotification ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE);
@ -289,7 +293,7 @@ bool deserializeState(JsonObject root)
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset, bool segmentBounds) void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset, bool segmentBounds)
{ {
root[F("id")] = id; root["id"] = id;
if (segmentBounds) { if (segmentBounds) {
root[F("start")] = seg.start; root[F("start")] = seg.start;
root["stop"] = seg.stop; root["stop"] = seg.stop;
@ -327,7 +331,7 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo
root[F("ix")] = seg.intensity; root[F("ix")] = seg.intensity;
root[F("pal")] = seg.palette; root[F("pal")] = seg.palette;
root[F("sel")] = seg.isSelected(); root[F("sel")] = seg.isSelected();
root[F("rev")] = seg.getOption(SEG_OPTION_REVERSED); root["rev"] = seg.getOption(SEG_OPTION_REVERSED);
root[F("mi")] = seg.getOption(SEG_OPTION_MIRROR); root[F("mi")] = seg.getOption(SEG_OPTION_MIRROR);
} }
@ -343,7 +347,6 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
if (errorFlag) root[F("error")] = errorFlag; if (errorFlag) root[F("error")] = errorFlag;
root[F("ps")] = currentPreset; root[F("ps")] = currentPreset;
root[F("pss")] = savedPresets;
root[F("pl")] = (presetCyclingEnabled) ? 0: -1; root[F("pl")] = (presetCyclingEnabled) ? 0: -1;
usermods.addToJsonState(root); usermods.addToJsonState(root);
@ -367,8 +370,8 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
} }
JsonObject udpn = root.createNestedObject("udpn"); JsonObject udpn = root.createNestedObject("udpn");
udpn[F("send")] = notifyDirect; udpn["send"] = notifyDirect;
udpn[F("recv")] = receiveNotifications; udpn["recv"] = receiveNotifications;
root[F("lor")] = realtimeOverride; root[F("lor")] = realtimeOverride;
} }
@ -424,6 +427,7 @@ void serializeInfo(JsonObject root)
leds_pin.add(LEDPIN); leds_pin.add(LEDPIN);
leds[F("pwr")] = strip.currentMilliamps; leds[F("pwr")] = strip.currentMilliamps;
leds[F("fps")] = strip.getFps();
leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0; leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0;
leds[F("maxseg")] = strip.getMaxSegments(); leds[F("maxseg")] = strip.getMaxSegments();
leds[F("seglock")] = false; //will be used in the future to prevent modifications to segment config leds[F("seglock")] = false; //will be used in the future to prevent modifications to segment config
@ -474,6 +478,8 @@ void serializeInfo(JsonObject root)
fs_info["t"] = fsBytesTotal / 1000; fs_info["t"] = fsBytesTotal / 1000;
fs_info[F("pmt")] = presetsModifiedTime; fs_info[F("pmt")] = presetsModifiedTime;
root[F("ndc")] = nodeListEnabled ? (int)Nodes.size() : -1;
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
wifi_info[F("txPower")] = (int) WiFi.getTxPower(); wifi_info[F("txPower")] = (int) WiFi.getTxPower();
@ -535,6 +541,171 @@ void serializeInfo(JsonObject root)
root["mac"] = escapedMac; root["mac"] = escapedMac;
} }
void setPaletteColors(JsonArray json, CRGBPalette16 palette)
{
for (int i = 0; i < 16; i++) {
JsonArray colors = json.createNestedArray();
CRGB color = palette[i];
colors.add((((float)i / (float)16) * 255));
colors.add(color.red);
colors.add(color.green);
colors.add(color.blue);
}
}
void setPaletteColors(JsonArray json, byte* tcp)
{
TRGBGradientPaletteEntryUnion* ent = (TRGBGradientPaletteEntryUnion*)(tcp);
TRGBGradientPaletteEntryUnion u;
// Count entries
uint16_t count = 0;
do {
u = *(ent + count);
count++;
} while ( u.index != 255);
u = *ent;
int indexstart = 0;
while( indexstart < 255) {
indexstart = u.index;
JsonArray colors = json.createNestedArray();
colors.add(u.index);
colors.add(u.r);
colors.add(u.g);
colors.add(u.b);
ent++;
u = *ent;
}
}
void serializePalettes(JsonObject root, AsyncWebServerRequest* request)
{
#ifdef ESP8266
int itemPerPage = 5;
#else
int itemPerPage = 8;
#endif
int page = 0;
if (request->hasParam("page")) {
page = request->getParam("page")->value().toInt();
}
int palettesCount = strip.getPaletteCount();
int maxPage = (palettesCount -1) / itemPerPage;
if (page > maxPage) page = maxPage;
int start = itemPerPage * page;
int end = start + itemPerPage;
if (end >= palettesCount) end = palettesCount;
root[F("m")] = maxPage;
JsonObject palettes = root.createNestedObject("p");
for (int i = start; i < end; i++) {
JsonArray curPalette = palettes.createNestedArray(String(i));
CRGB prim;
CRGB sec;
CRGB ter;
switch (i) {
case 0: //default palette
setPaletteColors(curPalette, PartyColors_p);
break;
case 1: //random
curPalette.add("r");
curPalette.add("r");
curPalette.add("r");
curPalette.add("r");
break;
case 2: //primary color only
curPalette.add(F("c1"));
break;
case 3: //primary + secondary
curPalette.add(F("c1"));
curPalette.add(F("c1"));
curPalette.add(F("c2"));
curPalette.add(F("c2"));
break;
case 4: //primary + secondary + tertiary
curPalette.add(F("c3"));
curPalette.add(F("c2"));
curPalette.add(F("c1"));
break;
case 5: {//primary + secondary (+tert if not off), more distinct
curPalette.add(F("c1"));
curPalette.add(F("c1"));
curPalette.add(F("c1"));
curPalette.add(F("c1"));
curPalette.add(F("c1"));
curPalette.add(F("c2"));
curPalette.add(F("c2"));
curPalette.add(F("c2"));
curPalette.add(F("c2"));
curPalette.add(F("c2"));
curPalette.add(F("c3"));
curPalette.add(F("c3"));
curPalette.add(F("c3"));
curPalette.add(F("c3"));
curPalette.add(F("c3"));
curPalette.add(F("c1"));
break;}
case 6: //Party colors
setPaletteColors(curPalette, PartyColors_p);
break;
case 7: //Cloud colors
setPaletteColors(curPalette, CloudColors_p);
break;
case 8: //Lava colors
setPaletteColors(curPalette, LavaColors_p);
break;
case 9: //Ocean colors
setPaletteColors(curPalette, OceanColors_p);
break;
case 10: //Forest colors
setPaletteColors(curPalette, ForestColors_p);
break;
case 11: //Rainbow colors
setPaletteColors(curPalette, RainbowColors_p);
break;
case 12: //Rainbow stripe colors
setPaletteColors(curPalette, RainbowStripeColors_p);
break;
default:
if (i < 13) {
break;
}
byte tcp[72];
memcpy_P(tcp, (byte*)pgm_read_dword(&(gGradientPalettes[i - 13])), 72);
setPaletteColors(curPalette, tcp);
break;
}
}
}
void serializeNodes(JsonObject root)
{
JsonArray nodes = root.createNestedArray("nodes");
for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end(); ++it)
{
if (it->second.ip[0] != 0)
{
JsonObject node = nodes.createNestedObject();
node[F("name")] = it->second.nodeName;
node["type"] = it->second.nodeType;
node["ip"] = it->second.ip.toString();
node[F("age")] = it->second.age;
node[F("vid")] = it->second.build;
}
}
}
void serveJson(AsyncWebServerRequest* request) void serveJson(AsyncWebServerRequest* request)
{ {
byte subJson = 0; byte subJson = 0;
@ -542,6 +713,8 @@ void serveJson(AsyncWebServerRequest* request)
if (url.indexOf("state") > 0) subJson = 1; if (url.indexOf("state") > 0) subJson = 1;
else if (url.indexOf("info") > 0) subJson = 2; else if (url.indexOf("info") > 0) subJson = 2;
else if (url.indexOf("si") > 0) subJson = 3; else if (url.indexOf("si") > 0) subJson = 3;
else if (url.indexOf("nodes") > 0) subJson = 4;
else if (url.indexOf("palx") > 0) subJson = 5;
else if (url.indexOf("live") > 0) { else if (url.indexOf("live") > 0) {
serveLiveLeds(request); serveLiveLeds(request);
return; return;
@ -568,6 +741,10 @@ void serveJson(AsyncWebServerRequest* request)
serializeState(doc); break; serializeState(doc); break;
case 2: //info case 2: //info
serializeInfo(doc); break; serializeInfo(doc); break;
case 4: //node list
serializeNodes(doc); break;
case 5: //palettes
serializePalettes(doc, request); break;
default: //all default: //all
JsonObject state = doc.createNestedObject("state"); JsonObject state = doc.createNestedObject("state");
serializeState(state); serializeState(state);
@ -588,7 +765,7 @@ void serveJson(AsyncWebServerRequest* request)
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient) bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
{ {
AsyncWebSocketClient * wsc; AsyncWebSocketClient * wsc = nullptr;
if (!request) { //not HTTP, use Websockets if (!request) { //not HTTP, use Websockets
#ifdef WLED_ENABLE_WEBSOCKETS #ifdef WLED_ENABLE_WEBSOCKETS
wsc = ws.client(wsClient); wsc = ws.client(wsClient);
@ -605,7 +782,7 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
for (uint16_t i= 0; i < used; i += n) for (uint16_t i= 0; i < used; i += n)
{ {
olen += sprintf(obuf + olen, "\"%06X\",", strip.getPixelColor(i)); olen += sprintf(obuf + olen, "\"%06X\",", strip.getPixelColor(i) & 0xFFFFFF);
} }
olen -= 1; olen -= 1;
oappend((const char*)F("],\"n\":")); oappend((const char*)F("],\"n\":"));

View File

@ -30,6 +30,7 @@ void toggleOnOff()
{ {
briLast = bri; briLast = bri;
bri = 0; bri = 0;
unloadPlaylist();
} }
} }

View File

@ -23,10 +23,9 @@ bool parseLx(int lxValue, byte rgbw[4])
ok = true; ok = true;
float tmpBri = floor((lxValue - 200000000) / 10000); ; float tmpBri = floor((lxValue - 200000000) / 10000); ;
uint16_t ct = (lxValue - 200000000) - (((uint8_t)tmpBri) * 10000); uint16_t ct = (lxValue - 200000000) - (((uint8_t)tmpBri) * 10000);
float temp = 0;
tmpBri *= 2.55; tmpBri *= 2.55;
constrain(tmpBri, 0, 255); tmpBri = constrain(tmpBri, 0, 255);
colorKtoRGB(ct, rgbw); colorKtoRGB(ct, rgbw);
lxRed = rgbw[0]; lxGreen = rgbw[1]; lxBlue = rgbw[2]; lxRed = rgbw[0]; lxGreen = rgbw[1]; lxBlue = rgbw[2];

View File

@ -110,7 +110,7 @@ void publishMqtt()
char s[10]; char s[10];
char subuf[38]; char subuf[38];
sprintf(s, "%ld", bri); sprintf(s, "%u", bri);
strcpy(subuf, mqttDeviceTopic); strcpy(subuf, mqttDeviceTopic);
strcat(subuf, "/g"); strcat(subuf, "/g");
mqtt->publish(subuf, 0, true, s); mqtt->publish(subuf, 0, true, s);

View File

@ -1,9 +1,6 @@
#include "pin_manager.h"
#include "wled.h" #include "wled.h"
/*
* Registers pins so there is no attempt for two interfaces to use the same pin
*/
void PinManagerClass::deallocatePin(byte gpio) void PinManagerClass::deallocatePin(byte gpio)
{ {
if (!isPinOk(gpio, false)) return; if (!isPinOk(gpio, false)) return;
@ -52,3 +49,43 @@ bool PinManagerClass::isPinOk(byte gpio, bool output)
return false; return false;
} }
#ifdef ARDUINO_ARCH_ESP32
byte PinManagerClass::allocateLedc(byte channels)
{
if (channels > 16 || channels == 0) return 255;
byte ca = 0;
for (byte i = 0; i < 16; i++) {
byte by = i >> 3;
byte bi = i - 8*by;
if (bitRead(ledcAlloc[by], bi)) { //found occupied pin
ca = 0;
} else {
ca++;
}
if (ca >= channels) { //enough free channels
byte in = (i + 1) - ca;
for (byte j = 0; j < ca; j++) {
byte b = in + j;
byte by = b >> 3;
byte bi = b - 8*by;
bitWrite(ledcAlloc[by], bi, true);
}
return in;
}
}
return 255; //not enough consecutive free LEDC channels
}
void PinManagerClass::deallocateLedc(byte pos, byte channels)
{
for (byte j = pos; j < pos + channels; j++) {
if (j > 16) return;
byte by = j >> 3;
byte bi = j - 8*by;
bitWrite(ledcAlloc[by], bi, false);
}
}
#endif
PinManagerClass pinManager = PinManagerClass();

29
wled00/pin_manager.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef WLED_PIN_MANAGER_H
#define WLED_PIN_MANAGER_H
/*
* Registers pins so there is no attempt for two interfaces to use the same pin
*/
#include <Arduino.h>
class PinManagerClass {
private:
#ifdef ESP8266
uint8_t pinAlloc[3] = {0x00, 0x00, 0x00}; //24bit, 1 bit per pin, we use first 17bits
#else
uint8_t pinAlloc[5] = {0x00, 0x00, 0x00, 0x00, 0x00}; //40bit, 1 bit per pin, we use all bits
uint8_t ledcAlloc[2] = {0x00, 0x00}; //16 LEDC channels
#endif
public:
void deallocatePin(byte gpio);
bool allocatePin(byte gpio, bool output = true);
bool isPinAllocated(byte gpio);
bool isPinOk(byte gpio, bool output = true);
#ifdef ARDUINO_ARCH_ESP32
byte allocateLedc(byte channels);
void deallocateLedc(byte pos, byte channels);
#endif
};
extern PinManagerClass pinManager;
#endif

View File

@ -10,19 +10,42 @@ typedef struct PlaylistEntry {
uint16_t tr; uint16_t tr;
} ple; } ple;
byte playlistRepeat = 1; int8_t playlistRepeat = 1;
byte playlistEndPreset = 0; byte playlistEndPreset = 0;
byte *playlistEntries = nullptr;
uint8_t* playlistEntries;
byte playlistLen; byte playlistLen;
int8_t playlistIndex = -1; int8_t playlistIndex = -1;
uint16_t playlistEntryDur = 0; uint16_t playlistEntryDur = 0;
void shufflePlaylist() {
int currentIndex = playlistLen, randomIndex;
PlaylistEntry temporaryValue, *entries = reinterpret_cast<PlaylistEntry*>(playlistEntries);
// While there remain elements to shuffle...
while (currentIndex--) {
// Pick a random element...
randomIndex = random(0, currentIndex);
// And swap it with the current element.
temporaryValue = entries[currentIndex];
entries[currentIndex] = entries[randomIndex];
entries[randomIndex] = temporaryValue;
}
}
void unloadPlaylist() {
if (playlistEntries != nullptr) {
delete[] playlistEntries;
playlistEntries = nullptr;
}
currentPlaylist = playlistIndex = -1;
playlistLen = playlistEntryDur = 0;
}
void loadPlaylist(JsonObject playlistObj) { void loadPlaylist(JsonObject playlistObj) {
delete playlistEntries; unloadPlaylist();
playlistIndex = -1; playlistEntryDur = 0;
JsonArray presets = playlistObj["ps"]; JsonArray presets = playlistObj["ps"];
playlistLen = presets.size(); playlistLen = presets.size();
if (playlistLen == 0) return; if (playlistLen == 0) return;
@ -72,26 +95,28 @@ void loadPlaylist(JsonObject playlistObj) {
currentPlaylist = 0; //TODO here we need the preset ID where the playlist is saved currentPlaylist = 0; //TODO here we need the preset ID where the playlist is saved
} }
void handlePlaylist()
{ void handlePlaylist() {
if (currentPlaylist < 0 || playlistEntries == nullptr || presetCyclingEnabled) return; if (currentPlaylist < 0 || playlistEntries == nullptr || presetCyclingEnabled) return;
if (millis() - presetCycledTime > (100*playlistEntryDur)) if (millis() - presetCycledTime > (100*playlistEntryDur)) {
{
presetCycledTime = millis(); presetCycledTime = millis();
if (bri == 0 || nightlightActive) return; if (bri == 0 || nightlightActive) return;
playlistIndex++; ++playlistIndex %= playlistLen; // -1 at 1st run (limit to playlistLen)
if (playlistIndex >= playlistLen) {
playlistIndex = 0; if (!playlistRepeat && !playlistIndex) { //stop if repeat == 0 and restart of playlist
if (playlistRepeat == 1) { //stop unloadPlaylist();
currentPlaylist = -1;
delete playlistEntries;
playlistEntries = nullptr;
if (playlistEndPreset) applyPreset(playlistEndPreset); if (playlistEndPreset) applyPreset(playlistEndPreset);
return; return;
} }
if (playlistRepeat > 1) playlistRepeat--; // playlist roll-over
if (!playlistIndex) {
if (playlistRepeat > 0) {// playlistRepeat < 0 => endless loop with shuffling presets
playlistRepeat--; // decrease repeat count on each index reset
} else {
shufflePlaylist(); // shuffle playlist and start over
}
} }
PlaylistEntry* entries = reinterpret_cast<PlaylistEntry*>(playlistEntries); PlaylistEntry* entries = reinterpret_cast<PlaylistEntry*>(playlistEntries);

View File

@ -75,18 +75,89 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
//LED SETTINGS //LED SETTINGS
if (subPage == 2) if (subPage == 2)
{ {
int t = request->arg(F("LC")).toInt(); int t = 0;
if (rlyPin>=0 && pinManager.isPinAllocated(rlyPin)) pinManager.deallocatePin(rlyPin);
#ifndef WLED_DISABLE_INFRARED
if (irPin>=0 && pinManager.isPinAllocated(irPin)) pinManager.deallocatePin(irPin);
#endif
if (btnPin>=0 && pinManager.isPinAllocated(btnPin)) pinManager.deallocatePin(btnPin);
//TODO remove all busses, but not in this system call
//busses->removeAll();
uint8_t colorOrder, type;
uint16_t length, start;
uint8_t pins[5] = {255, 255, 255, 255, 255};
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
char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length
char co[4] = "CO"; co[2] = 48+s; co[3] = 0; //strip color order
char lt[4] = "LT"; lt[2] = 48+s; lt[3] = 0; //strip type
char ls[4] = "LS"; ls[2] = 48+s; ls[3] = 0; //strip start LED
char cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse
if (!request->hasArg(lp)) {
DEBUG_PRINTLN("No data."); break;
}
for (uint8_t i = 0; i < 5; i++) {
lp[1] = 48+i;
if (!request->hasArg(lp)) break;
pins[i] = (request->arg(lp).length() > 0) ? request->arg(lp).toInt() : 255;
}
type = request->arg(lt).toInt();
if (request->hasArg(lc) && request->arg(lc).toInt() > 0) {
length = request->arg(lc).toInt();
} else {
break; // no parameter
}
colorOrder = request->arg(co).toInt();
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : 0;
if (busConfigs[s] != nullptr) delete busConfigs[s];
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder, request->hasArg(cv));
}
ledCount = request->arg(F("LC")).toInt();
if (t > 0 && t <= MAX_LEDS) ledCount = t; if (t > 0 && t <= MAX_LEDS) ledCount = t;
#ifdef ESP8266
#if LEDPIN == 3 // upate other pins
if (ledCount > MAX_LEDS_DMA) ledCount = MAX_LEDS_DMA; //DMA method uses too much ram #ifndef WLED_DISABLE_INFRARED
#endif int hw_ir_pin = request->arg(F("IR")).toInt();
if (pinManager.isPinOk(hw_ir_pin) && pinManager.allocatePin(hw_ir_pin,false)) {
irPin = hw_ir_pin;
} else {
irPin = -1;
}
#endif #endif
int hw_rly_pin = request->arg(F("RL")).toInt();
if (pinManager.allocatePin(hw_rly_pin,true)) {
rlyPin = hw_rly_pin;
} else {
rlyPin = -1;
}
rlyMde = (bool)request->hasArg(F("RM"));
int hw_btn_pin = request->arg(F("BT")).toInt();
if (pinManager.allocatePin(hw_btn_pin,false)) {
btnPin = hw_btn_pin;
pinMode(btnPin, INPUT_PULLUP);
} else {
btnPin = -1;
}
int hw_aux_pin = request->arg(F("AX")).toInt();
if (pinManager.allocatePin(hw_aux_pin,true)) {
auxPin = hw_aux_pin;
} else {
auxPin = -1;
}
strip.ablMilliampsMax = request->arg(F("MA")).toInt(); strip.ablMilliampsMax = request->arg(F("MA")).toInt();
strip.milliampsPerLed = request->arg(F("LA")).toInt(); strip.milliampsPerLed = request->arg(F("LA")).toInt();
useRGBW = request->hasArg(F("EW")); useRGBW = request->hasArg(F("EW"));
strip.setColorOrder(request->arg(F("CO")).toInt());
strip.rgbwMode = request->arg(F("AW")).toInt(); strip.rgbwMode = request->arg(F("AW")).toInt();
briS = request->arg(F("CA")).toInt(); briS = request->arg(F("CA")).toInt();
@ -146,6 +217,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
notifyMacro = request->hasArg(F("SM")); notifyMacro = request->hasArg(F("SM"));
notifyTwice = request->hasArg(F("S2")); notifyTwice = request->hasArg(F("S2"));
nodeListEnabled = request->hasArg(F("NL"));
if (!nodeListEnabled) Nodes.clear();
nodeBroadcastEnabled = request->hasArg(F("NB"));
receiveDirect = request->hasArg(F("RD")); receiveDirect = request->hasArg(F("RD"));
e131SkipOutOfSequence = request->hasArg(F("ES")); e131SkipOutOfSequence = request->hasArg(F("ES"));
e131Multicast = request->hasArg(F("EM")); e131Multicast = request->hasArg(F("EM"));
@ -328,12 +403,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
DMXFixtureMap[i] = t; DMXFixtureMap[i] = t;
} }
} }
#endif #endif
if (subPage != 6 || !doReboot) serializeConfig(); //do not save if factory reset
if (subPage == 2) { if (subPage != 2 && (subPage != 6 || !doReboot)) serializeConfig(); //do not save if factory reset or LED settings (which are saved after LED re-init)
strip.init(useRGBW,ledCount,skipFirstLed);
}
if (subPage == 4) alexaInit(); if (subPage == 4) alexaInit();
} }
@ -646,15 +718,15 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
} }
if (nightlightMode > NL_MODE_SUN) nightlightMode = NL_MODE_SUN; if (nightlightMode > NL_MODE_SUN) nightlightMode = NL_MODE_SUN;
#if AUXPIN >= 0
//toggle general purpose output //toggle general purpose output
if (auxPin>=0) {
pos = req.indexOf(F("AX=")); pos = req.indexOf(F("AX="));
if (pos > 0) { if (pos > 0) {
auxTime = getNumVal(&req, pos); auxTime = getNumVal(&req, pos);
auxActive = true; auxActive = true;
if (auxTime == 0) auxActive = false; if (auxTime == 0) auxActive = false;
} }
#endif }
pos = req.indexOf(F("TT=")); pos = req.indexOf(F("TT="));
if (pos > 0) transitionDelay = getNumVal(&req, pos); if (pos > 0) transitionDelay = getNumVal(&req, pos);

View File

@ -37,10 +37,10 @@ AsyncMqttClient::AsyncMqttClient()
_client.onPoll([](void* obj, AsyncClient* c) { (static_cast<AsyncMqttClient*>(obj))->_onPoll(c); }, this); _client.onPoll([](void* obj, AsyncClient* c) { (static_cast<AsyncMqttClient*>(obj))->_onPoll(c); }, this);
#ifdef ESP32 #ifdef ESP32
sprintf(_generatedClientId, "esp32%06x", ESP.getEfuseMac()); sprintf(_generatedClientId, "esp32%06x", (uint32_t)ESP.getEfuseMac());
_xSemaphore = xSemaphoreCreateMutex(); _xSemaphore = xSemaphoreCreateMutex();
#elif defined(ESP8266) #elif defined(ESP8266)
sprintf(_generatedClientId, "esp8266%06x", ESP.getChipId()); sprintf(_generatedClientId, "esp8266%06x", (uint32_t)ESP.getChipId());
#endif #endif
_clientId = _generatedClientId; _clientId = _generatedClientId;

View File

@ -93,7 +93,9 @@ struct BlynkHeader
} }
BLYNK_ATTR_PACKED; BLYNK_ATTR_PACKED;
#if !defined(htons) && (defined(ARDUINO) || defined(ESP8266) || defined(PARTICLE) || defined(__MBED__)) #if defined(ESP32)
#include <lwip/ip_addr.h>
#elif !defined(htons) && (defined(ARDUINO) || defined(ESP8266) || defined(PARTICLE) || defined(__MBED__))
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) ) #define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) )
#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ #define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \

View File

@ -45,8 +45,7 @@ public:
} }
BLYNK_LOG1(BLYNK_F("Connected to WiFi")); BLYNK_LOG1(BLYNK_F("Connected to WiFi"));
IPAddress myip = WiFi.localIP(); BLYNK_LOG_IP("IP: ", WiFi.localIP());
BLYNK_LOG_IP("IP: ", myip);
} }
void config(const char* auth, void config(const char* auth,

View File

@ -77,10 +77,9 @@ void DMXESPSerial::write(int Channel, uint8_t value) {
} }
void DMXESPSerial::end() { void DMXESPSerial::end() {
delete dmxData;
chanSize = 0; chanSize = 0;
Serial1.end(); Serial1.end();
dmxStarted == false; dmxStarted = false;
} }
void DMXESPSerial::update() { void DMXESPSerial::update() {

View File

@ -101,8 +101,8 @@ private:
case EspalexaDeviceType::whitespectrum: return PSTR("Color temperature light"); case EspalexaDeviceType::whitespectrum: return PSTR("Color temperature light");
case EspalexaDeviceType::color: return PSTR("Color light"); case EspalexaDeviceType::color: return PSTR("Color light");
case EspalexaDeviceType::extendedcolor: return PSTR("Extended color light"); case EspalexaDeviceType::extendedcolor: return PSTR("Extended color light");
default: return "";
} }
return "";
} }
const char* modelidString(EspalexaDeviceType t) const char* modelidString(EspalexaDeviceType t)
@ -113,8 +113,8 @@ private:
case EspalexaDeviceType::whitespectrum: return "LWT010"; case EspalexaDeviceType::whitespectrum: return "LWT010";
case EspalexaDeviceType::color: return "LST001"; case EspalexaDeviceType::color: return "LST001";
case EspalexaDeviceType::extendedcolor: return "LCT015"; case EspalexaDeviceType::extendedcolor: return "LCT015";
default: return "";
} }
return "";
} }
void encodeLightId(uint8_t idx, char* out) void encodeLightId(uint8_t idx, char* out)

View File

@ -112,7 +112,6 @@ uint32_t EspalexaDevice::getRGB()
{ {
if (_rgb != 0) return _rgb; //color has not changed if (_rgb != 0) return _rgb; //color has not changed
byte rgb[4]{0, 0, 0, 0}; byte rgb[4]{0, 0, 0, 0};
float r, g, b, w;
if (_mode == EspalexaColorMode::none) return 0; if (_mode == EspalexaColorMode::none) return 0;

View File

@ -144,7 +144,7 @@ public:
virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final { virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final {
if (_onRequest) { if (_onRequest) {
_contentLength = total; _contentLength = total;
if (total > 0 && request->_tempObject == NULL && total < _maxContentLength) { if (total > 0 && request->_tempObject == NULL && (int)total < _maxContentLength) {
request->_tempObject = malloc(total); request->_tempObject = malloc(total);
} }
if (request->_tempObject != NULL) { if (request->_tempObject != NULL) {

View File

@ -163,8 +163,40 @@ void handleNotifications()
if (!isSupp && notifierUdp.remoteIP() == Network.localIP()) return; //don't process broadcasts we send ourselves if (!isSupp && notifierUdp.remoteIP() == Network.localIP()) return; //don't process broadcasts we send ourselves
uint8_t udpIn[packetSize +1]; uint8_t udpIn[packetSize +1];
if (isSupp) notifier2Udp.read(udpIn, packetSize); uint16_t len;
else notifierUdp.read(udpIn, packetSize); if (isSupp) len = notifier2Udp.read(udpIn, packetSize);
else len = notifierUdp.read(udpIn, packetSize);
// WLED nodes info notifications
if (isSupp && udpIn[0] == 255 && udpIn[1] == 1 && len >= 40) {
if (!nodeListEnabled || notifier2Udp.remoteIP() == Network.localIP()) return;
uint8_t unit = udpIn[39];
NodesMap::iterator it = Nodes.find(unit);
if (it == Nodes.end() && Nodes.size() < WLED_MAX_NODES) { // Create a new element when not present
Nodes[unit].age = 0;
it = Nodes.find(unit);
}
if (it != Nodes.end()) {
for (byte x = 0; x < 4; x++) {
it->second.ip[x] = udpIn[x + 2];
}
it->second.age = 0; // reset 'age counter'
char tmpNodeName[33] = { 0 };
memcpy(&tmpNodeName[0], reinterpret_cast<byte *>(&udpIn[6]), 32);
tmpNodeName[32] = 0;
it->second.nodeName = tmpNodeName;
it->second.nodeName.trim();
it->second.nodeType = udpIn[38];
uint32_t build = 0;
if (len >= 44)
for (byte i=0; i<sizeof(uint32_t); i++)
build |= udpIn[40+i]<<(8*i);
it->second.build = build;
}
return;
}
//wled notifier, ignore if realtime packets active //wled notifier, ignore if realtime packets active
if (udpIn[0] == 0 && !realtimeMode && receiveNotifications) if (udpIn[0] == 0 && !realtimeMode && receiveNotifications)
@ -315,6 +347,15 @@ void handleNotifications()
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0); setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
id++; id++;
} }
} else if (udpIn[0] == 5) //dnrgbw
{
uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
for (uint16_t i = 4; i < packetSize -2; i += 4)
{
if (id >= ledCount) break;
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
id++;
}
} }
strip.show(); strip.show();
return; return;
@ -349,3 +390,72 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w)
} }
} }
} }
/*********************************************************************************************\
Refresh aging for remote units, drop if too old...
\*********************************************************************************************/
void refreshNodeList()
{
for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end();) {
bool mustRemove = true;
if (it->second.ip[0] != 0) {
if (it->second.age < 10) {
it->second.age++;
mustRemove = false;
++it;
}
}
if (mustRemove) {
it = Nodes.erase(it);
}
}
}
/*********************************************************************************************\
Broadcast system info to other nodes. (to update node lists)
\*********************************************************************************************/
void sendSysInfoUDP()
{
if (!udp2Connected) return;
IPAddress ip = Network.localIP();
// TODO: make a nice struct of it and clean up
// 0: 1 byte 'binary token 255'
// 1: 1 byte id '1'
// 2: 4 byte ip
// 6: 32 char name
// 38: 1 byte node type id
// 39: 1 byte node id
// 40: 4 byte version ID
// 44 bytes total
// send my info to the world...
uint8_t data[44] = {0};
data[0] = 255;
data[1] = 1;
for (byte x = 0; x < 4; x++) {
data[x + 2] = ip[x];
}
memcpy((byte *)data + 6, serverDescription, 32);
#ifdef ESP8266
data[38] = NODE_TYPE_ID_ESP8266;
#elif defined(ARDUINO_ARCH_ESP32)
data[38] = NODE_TYPE_ID_ESP32;
#else
data[38] = NODE_TYPE_ID_UNDEFINED;
#endif
data[39] = ip[3]; // unit ID == last IP number
uint32_t build = VERSION;
for (byte i=0; i<sizeof(uint32_t); i++)
data[40+i] = (build>>(8*i)) & 0xFF;
IPAddress broadcastIP(255, 255, 255, 255);
notifier2Udp.beginPacket(broadcastIP, udpPort2);
notifier2Udp.write(data, sizeof(data));
notifier2Udp.endPacket();
}

View File

@ -32,6 +32,7 @@ bool UsermodManager::add(Usermod* um)
if (numMods >= WLED_MAX_USERMODS || um == nullptr) return false; if (numMods >= WLED_MAX_USERMODS || um == nullptr) return false;
ums[numMods] = um; ums[numMods] = um;
numMods++; numMods++;
return true;
} }
byte UsermodManager::getModCount() {return numMods;} byte UsermodManager::getModCount() {return numMods;}

View File

@ -13,7 +13,9 @@
#ifdef USERMOD_DALLASTEMPERATURE #ifdef USERMOD_DALLASTEMPERATURE
#include "../usermods/Temperature/usermod_temperature.h" #include "../usermods/Temperature/usermod_temperature.h"
#endif #endif
//#include "usermod_v2_empty.h" //#include "usermod_v2_empty.h"
#ifdef USERMOD_BUZZER #ifdef USERMOD_BUZZER
#include "../usermods/buzzer/usermod_v2_buzzer.h" #include "../usermods/buzzer/usermod_v2_buzzer.h"
#endif #endif
@ -24,6 +26,11 @@
#ifdef USERMOD_MODE_SORT #ifdef USERMOD_MODE_SORT
#include "../usermods/usermod_v2_mode_sort/usermod_v2_mode_sort.h" #include "../usermods/usermod_v2_mode_sort/usermod_v2_mode_sort.h"
#endif #endif
// BME280 v2 usermod. Define "USERMOD_BME280" in my_config.h
#ifdef USERMOD_BME280
#include "../usermods/BME280_v2/usermod_bme280.h"
#endif
#ifdef USERMOD_FOUR_LINE_DISLAY #ifdef USERMOD_FOUR_LINE_DISLAY
#include "../usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h" #include "../usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h"
#endif #endif
@ -45,14 +52,21 @@ void registerUsermods()
* || || || * || || ||
* \/ \/ \/ * \/ \/ \/
*/ */
//usermods.add(new MyExampleUsermod()); //usermods.add(new MyExampleUsermod());
#ifdef USERMOD_DALLASTEMPERATURE
#ifdef USERMOD_DALLASTEMPERATURE
usermods.add(new UsermodTemperature()); usermods.add(new UsermodTemperature());
#endif #endif
//usermods.add(new UsermodRenameMe());
#ifdef USERMOD_BUZZER //usermods.add(new UsermodRenameMe());
#ifdef USERMOD_BUZZER
usermods.add(new BuzzerUsermod()); usermods.add(new BuzzerUsermod());
#endif #endif
#ifdef USERMOD_BME280
usermods.add(new UsermodBME280());
#endif
#ifdef USERMOD_SENSORSTOMQTT #ifdef USERMOD_SENSORSTOMQTT
usermods.add(new UserMod_SensorsToMQTT()); usermods.add(new UserMod_SensorsToMQTT());
#endif #endif

View File

@ -58,6 +58,16 @@ ethernet_settings ethernetBoards[] = {
17, // eth_mdio, 17, // eth_mdio,
ETH_PHY_LAN8720, // eth_type, ETH_PHY_LAN8720, // eth_type,
ETH_CLOCK_GPIO0_IN // eth_clk_mode ETH_CLOCK_GPIO0_IN // eth_clk_mode
},
// QuinLed-ESP32-Ethernet
{
0, // eth_address,
5, // eth_power,
23, // eth_mdc,
18, // eth_mdio,
ETH_PHY_LAN8720, // eth_type,
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
} }
}; };
@ -126,7 +136,9 @@ void prepareHostname(char* hostname)
//handle Ethernet connection event //handle Ethernet connection event
void WiFiEvent(WiFiEvent_t event) void WiFiEvent(WiFiEvent_t event)
{ {
#ifdef WLED_USE_ETHERNET
char hostname[25] = "wled-"; char hostname[25] = "wled-";
#endif
switch (event) { switch (event) {
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
@ -205,10 +217,20 @@ void WLED::loop()
handleHue(); handleHue();
handleBlynk(); handleBlynk();
/*if (presetToApply) { //LED settings have been saved, re-init busses
applyPreset(presetToApply); if (busConfigs[0] != nullptr) {
presetToApply = 0; busses.removeAll();
}*/ uint32_t mem = 0;
for (uint8_t i = 0; i < WLED_MAX_BUSSES; i++) {
if (busConfigs[i] == nullptr) break;
mem += busses.memUsage(*busConfigs[i]);
if (mem <= MAX_LED_MEMORY) busses.add(*busConfigs[i]);
delete busConfigs[i]; busConfigs[i] = nullptr;
}
strip.finalizeInit(useRGBW, ledCount, skipFirstLed);
yield();
serializeConfig();
}
yield(); yield();
@ -226,6 +248,8 @@ void WLED::loop()
if (millis() - lastMqttReconnectAttempt > 30000) { if (millis() - lastMqttReconnectAttempt > 30000) {
if (lastMqttReconnectAttempt > millis()) rolloverMillis++; //millis() rolls over every 50 days if (lastMqttReconnectAttempt > millis()) rolloverMillis++; //millis() rolls over every 50 days
initMqtt(); initMqtt();
refreshNodeList();
if (nodeBroadcastEnabled) sendSysInfoUDP();
} }
yield(); yield();
handleWs(); handleWs();
@ -272,17 +296,16 @@ void WLED::setup()
DEBUG_PRINT("esp8266 "); DEBUG_PRINT("esp8266 ");
DEBUG_PRINTLN(ESP.getCoreVersion()); DEBUG_PRINTLN(ESP.getCoreVersion());
#endif #endif
int heapPreAlloc = ESP.getFreeHeap();
DEBUG_PRINT("heap "); DEBUG_PRINT("heap ");
DEBUG_PRINTLN(ESP.getFreeHeap()); DEBUG_PRINTLN(ESP.getFreeHeap());
registerUsermods(); registerUsermods();
//strip.init(EEPROM.read(372), ledCount, EEPROM.read(2204)); // init LEDs quickly
//strip.setBrightness(0);
//DEBUG_PRINT(F("LEDs inited. heap usage ~")); //DEBUG_PRINT(F("LEDs inited. heap usage ~"));
//DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap()); //DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap());
#ifdef WLED_USE_DMX //reserve GPIO2 as hardcoded DMX pin
pinManager.allocatePin(2);
#endif
bool fsinit = false; bool fsinit = false;
DEBUGFS_PRINTLN(F("Mount FS")); DEBUGFS_PRINTLN(F("Mount FS"));
@ -298,7 +321,15 @@ void WLED::setup()
updateFSInfo(); updateFSInfo();
deserializeConfig(); deserializeConfig();
#if STATUSLED && STATUSLED != LEDPIN #if STATUSLED
bool lStatusLed = false;
for (uint8_t i=0; i<strip.numStrips; i++) {
if (strip.getStripPin(i)==STATUSLED) {
lStatusLed = true;
break;
}
}
if (!lStatusLed)
pinMode(STATUSLED, OUTPUT); pinMode(STATUSLED, OUTPUT);
#endif #endif
@ -310,7 +341,9 @@ void WLED::setup()
if (strcmp(clientSSID, DEFAULT_CLIENT_SSID) == 0) if (strcmp(clientSSID, DEFAULT_CLIENT_SSID) == 0)
showWelcomePage = true; showWelcomePage = true;
WiFi.persistent(false); WiFi.persistent(false);
#ifdef WLED_USE_ETHERNET
WiFi.onEvent(WiFiEvent); WiFi.onEvent(WiFiEvent);
#endif
Serial.println(F("Ada")); Serial.println(F("Ada"));
@ -356,25 +389,14 @@ void WLED::setup()
void WLED::beginStrip() void WLED::beginStrip()
{ {
// Initialize NeoPixel Strip and button // Initialize NeoPixel Strip and button
#ifdef ESP8266
#if LEDPIN == 3
if (ledCount > MAX_LEDS_DMA)
ledCount = MAX_LEDS_DMA; // DMA method uses too much ram
#endif
#endif
if (ledCount > MAX_LEDS || ledCount == 0) if (ledCount > MAX_LEDS || ledCount == 0)
ledCount = 30; ledCount = 30;
strip.init(useRGBW, ledCount, skipFirstLed); strip.finalizeInit(useRGBW, ledCount, skipFirstLed);
strip.setBrightness(0); strip.setBrightness(0);
strip.setShowCallback(handleOverlayDraw); strip.setShowCallback(handleOverlayDraw);
#if defined(BTNPIN) && BTNPIN > -1
pinManager.allocatePin(BTNPIN, false);
pinMode(BTNPIN, INPUT_PULLUP);
#endif
if (bootPreset > 0) applyPreset(bootPreset); if (bootPreset > 0) applyPreset(bootPreset);
if (turnOnAtBoot) { if (turnOnAtBoot) {
if (briS > 0) bri = briS; if (briS > 0) bri = briS;
@ -384,24 +406,13 @@ void WLED::beginStrip()
} }
colorUpdated(NOTIFIER_CALL_MODE_INIT); colorUpdated(NOTIFIER_CALL_MODE_INIT);
// init relay pin // init relay pin
#if RLYPIN >= 0 if (rlyPin>=0)
pinManager.allocatePin(RLYPIN); digitalWrite(rlyPin, (rlyMde ? bri : !bri));
pinMode(RLYPIN, OUTPUT);
#if RLYMDE
digitalWrite(RLYPIN, bri);
#else
digitalWrite(RLYPIN, !bri);
#endif
#endif
// disable button if it is "pressed" unintentionally // disable button if it is "pressed" unintentionally
#if (defined(BTNPIN) && BTNPIN > -1) || defined(TOUCHPIN) if (btnPin>=0 && isButtonPressed())
if (isButtonPressed())
buttonEnabled = false; buttonEnabled = false;
#else
buttonEnabled = false;
#endif
} }
void WLED::initAP(bool resetAP) void WLED::initAP(bool resetAP)
@ -447,7 +458,7 @@ void WLED::initConnection()
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
// Only initialize ethernet board if not NONE // Only initialize ethernet board if not NONE
if (ethernetType != WLED_ETH_NONE) { if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
ethernet_settings es = ethernetBoards[ethernetType]; ethernet_settings es = ethernetBoards[ethernetType];
ETH.begin( ETH.begin(
(uint8_t) es.eth_address, (uint8_t) es.eth_address,
@ -647,7 +658,13 @@ void WLED::handleConnection()
void WLED::handleStatusLED() void WLED::handleStatusLED()
{ {
#if STATUSLED && STATUSLED != LEDPIN #if STATUSLED
for (uint8_t s=0; s<strip.numStrips; s++) {
if (strip.getStripPin(s)==STATUSLED) {
return; // pin used for strip
}
}
ledStatusType = WLED_CONNECTED ? 0 : 2; ledStatusType = WLED_CONNECTED ? 0 : 2;
if (mqttEnabled && ledStatusType != 2) // Wi-Fi takes presendence over MQTT if (mqttEnabled && ledStatusType != 2) // Wi-Fi takes presendence over MQTT
ledStatusType = WLED_MQTT_CONNECTED ? 0 : 4; ledStatusType = WLED_MQTT_CONNECTED ? 0 : 4;

View File

@ -3,12 +3,12 @@
/* /*
Main sketch, global variable declarations Main sketch, global variable declarations
@title WLED project sketch @title WLED project sketch
@version 0.11.1 @version 0.12.0-a0
@author Christian Schwinne @author Christian Schwinne
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2101130 #define VERSION 2103130
//uncomment this if you have a "my_config.h" file you'd like to use //uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG //#define WLED_USE_MY_CONFIG
@ -65,7 +65,9 @@
#include <ESPmDNS.h> #include <ESPmDNS.h>
#include <AsyncTCP.h> #include <AsyncTCP.h>
//#include "SPIFFS.h" //#include "SPIFFS.h"
#ifndef CONFIG_LITTLEFS_FOR_IDF_3_2
#define CONFIG_LITTLEFS_FOR_IDF_3_2 #define CONFIG_LITTLEFS_FOR_IDF_3_2
#endif
#include <LITTLEFS.h> #include <LITTLEFS.h>
#endif #endif
@ -115,6 +117,9 @@
#include "FX.h" #include "FX.h"
#include "ir_codes.h" #include "ir_codes.h"
#include "const.h" #include "const.h"
#include "NodeStruct.h"
#include "pin_manager.h"
#include "bus_manager.h"
#ifndef CLIENT_SSID #ifndef CLIENT_SSID
#define CLIENT_SSID DEFAULT_CLIENT_SSID #define CLIENT_SSID DEFAULT_CLIENT_SSID
@ -130,7 +135,7 @@
Comment out this error message to build regardless. Comment out this error message to build regardless.
#endif #endif
#if IRPIN < 0 #if !defined(IRPIN) || IRPIN < 0
#ifndef WLED_DISABLE_INFRARED #ifndef WLED_DISABLE_INFRARED
#define WLED_DISABLE_INFRARED #define WLED_DISABLE_INFRARED
#endif #endif
@ -174,8 +179,8 @@
#endif #endif
// Global Variable definitions // Global Variable definitions
WLED_GLOBAL char versionString[] _INIT("0.11.1"); WLED_GLOBAL char versionString[] _INIT("0.12.0-a0");
#define WLED_CODENAME "Mirai" #define WLED_CODENAME "Hikari"
// AP and OTA default passwords (for maximum security change them!) // AP and OTA default passwords (for maximum security change them!)
WLED_GLOBAL char apPass[65] _INIT(DEFAULT_AP_PASS); WLED_GLOBAL char apPass[65] _INIT(DEFAULT_AP_PASS);
@ -183,13 +188,30 @@ WLED_GLOBAL char otaPass[33] _INIT(DEFAULT_OTA_PASS);
// Hardware CONFIG (only changeble HERE, not at runtime) // Hardware CONFIG (only changeble HERE, not at runtime)
// LED strip pin, button pin and IR pin changeable in NpbWrapper.h! // LED strip pin, button pin and IR pin changeable in NpbWrapper.h!
#ifndef BTNPIN
WLED_GLOBAL int8_t btnPin _INIT(-1);
#else
WLED_GLOBAL int8_t btnPin _INIT(BTNPIN);
#endif
#ifndef RLYPIN
WLED_GLOBAL int8_t rlyPin _INIT(-1);
#else
WLED_GLOBAL int8_t rlyPin _INIT(RLYPIN);
#endif
//Relay mode (1 = active high, 0 = active low, flipped in cfg.json)
#ifndef RLYMDE
WLED_GLOBAL bool rlyMde _INIT(true);
#else
WLED_GLOBAL bool rlyMde _INIT(RLYMDE);
#endif
#ifndef IRPIN
WLED_GLOBAL int8_t irPin _INIT(-1);
#else
WLED_GLOBAL int8_t irPin _INIT(IRPIN);
#endif
//WLED_GLOBAL byte presetToApply _INIT(0); //WLED_GLOBAL byte presetToApply _INIT(0);
#if AUXPIN >= 0
WLED_GLOBAL byte auxDefaultState _INIT(0); // 0: input 1: high 2: low
WLED_GLOBAL byte auxTriggeredState _INIT(0); // 0: input 1: high 2: low
#endif
WLED_GLOBAL char ntpServerName[33] _INIT("0.wled.pool.ntp.org"); // NTP server to use WLED_GLOBAL char ntpServerName[33] _INIT("0.wled.pool.ntp.org"); // NTP server to use
// WiFi CONFIG (all these can be changed via web UI, no need to set them here) // WiFi CONFIG (all these can be changed via web UI, no need to set them here)
@ -236,6 +258,10 @@ WLED_GLOBAL char serverDescription[33] _INIT("WLED"); // Name of module
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 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 // Sync CONFIG
WLED_GLOBAL NodesMap Nodes;
WLED_GLOBAL bool nodeListEnabled _INIT(true);
WLED_GLOBAL bool nodeBroadcastEnabled _INIT(true);
WLED_GLOBAL bool buttonEnabled _INIT(true); WLED_GLOBAL bool buttonEnabled _INIT(true);
WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver
@ -292,7 +318,7 @@ WLED_GLOBAL bool huePollingEnabled _INIT(false); // poll hue bridge fo
WLED_GLOBAL uint16_t huePollIntervalMs _INIT(2500); // low values (< 1sec) may cause lag but offer quicker response WLED_GLOBAL uint16_t huePollIntervalMs _INIT(2500); // low values (< 1sec) may cause lag but offer quicker response
WLED_GLOBAL char hueApiKey[47] _INIT("api"); // key token will be obtained from bridge WLED_GLOBAL char hueApiKey[47] _INIT("api"); // key token will be obtained from bridge
WLED_GLOBAL byte huePollLightId _INIT(1); // ID of hue lamp to sync to. Find the ID in the hue app ("about" section) WLED_GLOBAL byte huePollLightId _INIT(1); // ID of hue lamp to sync to. Find the ID in the hue app ("about" section)
WLED_GLOBAL IPAddress hueIP _INIT((0, 0, 0, 0)); // IP address of the bridge WLED_GLOBAL IPAddress hueIP _INIT_N(((0, 0, 0, 0))); // IP address of the bridge
WLED_GLOBAL bool hueApplyOnOff _INIT(true); WLED_GLOBAL bool hueApplyOnOff _INIT(true);
WLED_GLOBAL bool hueApplyBri _INIT(true); WLED_GLOBAL bool hueApplyBri _INIT(true);
WLED_GLOBAL bool hueApplyColor _INIT(true); WLED_GLOBAL bool hueApplyColor _INIT(true);
@ -455,23 +481,29 @@ WLED_GLOBAL int16_t currentPlaylist _INIT(0);
// realtime // realtime
WLED_GLOBAL byte realtimeMode _INIT(REALTIME_MODE_INACTIVE); WLED_GLOBAL byte realtimeMode _INIT(REALTIME_MODE_INACTIVE);
WLED_GLOBAL byte realtimeOverride _INIT(REALTIME_OVERRIDE_NONE); WLED_GLOBAL byte realtimeOverride _INIT(REALTIME_OVERRIDE_NONE);
WLED_GLOBAL IPAddress realtimeIP _INIT((0, 0, 0, 0)); WLED_GLOBAL IPAddress realtimeIP _INIT_N(((0, 0, 0, 0)));;
WLED_GLOBAL unsigned long realtimeTimeout _INIT(0); WLED_GLOBAL unsigned long realtimeTimeout _INIT(0);
WLED_GLOBAL uint8_t tpmPacketCount _INIT(0); WLED_GLOBAL uint8_t tpmPacketCount _INIT(0);
WLED_GLOBAL uint16_t tpmPayloadFrameSize _INIT(0); WLED_GLOBAL uint16_t tpmPayloadFrameSize _INIT(0);
// mqtt // mqtt
WLED_GLOBAL long lastMqttReconnectAttempt _INIT(0); WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0);
WLED_GLOBAL long lastInterfaceUpdate _INIT(0); WLED_GLOBAL unsigned long lastInterfaceUpdate _INIT(0);
WLED_GLOBAL byte interfaceUpdateCallMode _INIT(NOTIFIER_CALL_MODE_INIT); WLED_GLOBAL byte interfaceUpdateCallMode _INIT(NOTIFIER_CALL_MODE_INIT);
WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers
#if AUXPIN >= 0 // auxiliary debug pin
// auxiliary debug pin #ifndef AUXPIN
WLED_GLOBAL byte auxTime _INIT(0); WLED_GLOBAL int8_t auxPin _INIT(-1);
WLED_GLOBAL unsigned long auxStartTime _INIT(0); #else
WLED_GLOBAL bool auxActive _INIT(false, auxActiveBefore _INIT(false); WLED_GLOBAL int8_t auxPin _INIT(AUXPIN);
#endif #endif
WLED_GLOBAL byte auxTime _INIT(0);
WLED_GLOBAL unsigned long auxStartTime _INIT(0);
WLED_GLOBAL bool auxActive _INIT(false);
WLED_GLOBAL bool auxActiveBefore _INIT(false);
WLED_GLOBAL byte auxDefaultState _INIT(0); // 0: input 1: high 2: low
WLED_GLOBAL byte auxTriggeredState _INIT(0); // 0: input 1: high 2: low
// alexa udp // alexa udp
WLED_GLOBAL String escapedMac; WLED_GLOBAL String escapedMac;
@ -504,7 +536,6 @@ WLED_GLOBAL JsonDocument* fileDoc;
WLED_GLOBAL bool doCloseFile _INIT(false); WLED_GLOBAL bool doCloseFile _INIT(false);
// presets // presets
WLED_GLOBAL uint16_t savedPresets _INIT(0);
WLED_GLOBAL int16_t currentPreset _INIT(-1); WLED_GLOBAL int16_t currentPreset _INIT(-1);
WLED_GLOBAL bool isPreset _INIT(false); WLED_GLOBAL bool isPreset _INIT(false);
@ -531,15 +562,15 @@ WLED_GLOBAL ESPAsyncE131 e131 _INIT_N(((handleE131Packet)));
WLED_GLOBAL bool e131NewData _INIT(false); WLED_GLOBAL bool e131NewData _INIT(false);
// led fx library object // led fx library object
WLED_GLOBAL BusManager busses _INIT(BusManager());
WLED_GLOBAL WS2812FX strip _INIT(WS2812FX()); WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
WLED_GLOBAL BusConfig* busConfigs[WLED_MAX_BUSSES]; //temporary, to remember values from network callback until after
// Usermod manager // Usermod manager
WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager()); WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
WLED_GLOBAL PinManagerClass pinManager _INIT(PinManagerClass());
// Status LED // Status LED
#if STATUSLED && STATUSLED != LEDPIN #if STATUSLED
WLED_GLOBAL unsigned long ledStatusLastMillis _INIT(0); WLED_GLOBAL unsigned long ledStatusLastMillis _INIT(0);
WLED_GLOBAL unsigned short ledStatusType _INIT(0); // current status type - corresponds to number of blinks per second WLED_GLOBAL unsigned short ledStatusType _INIT(0); // current status type - corresponds to number of blinks per second
WLED_GLOBAL bool ledStatusState _INIT(0); // the current LED state WLED_GLOBAL bool ledStatusState _INIT(0); // the current LED state

View File

@ -39,9 +39,15 @@ void initServer()
DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Methods"), "*"); DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Methods"), "*");
DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Headers"), "*"); DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Headers"), "*");
#ifdef WLED_ENABLE_WEBSOCKETS
server.on("/liveview", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", PAGE_liveviewws);
});
#else
server.on("/liveview", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/liveview", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", PAGE_liveview); request->send_P(200, "text/html", PAGE_liveview);
}); });
#endif
//settings page //settings page
server.on("/settings", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/settings", HTTP_GET, [](AsyncWebServerRequest *request){
@ -239,7 +245,7 @@ bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest* request)
return false; return false;
} }
bool setStaticContentCacheHeaders(AsyncWebServerResponse *response) void setStaticContentCacheHeaders(AsyncWebServerResponse *response)
{ {
response->addHeader(F("Cache-Control"),"max-age=2592000"); response->addHeader(F("Cache-Control"),"max-age=2592000");
response->addHeader(F("ETag"), String(VERSION)); response->addHeader(F("ETag"), String(VERSION));

View File

@ -220,7 +220,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('c',SET_F("WS"),noWifiSleep); sappend('c',SET_F("WS"),noWifiSleep);
#ifdef WLED_USE_ETHERNET #ifdef WLED_USE_ETHERNET
sappend('i',SET_F("ETH"),ethernetType); sappend('v',SET_F("ETH"),ethernetType);
#else #else
//hide ethernet setting if not compiled in //hide ethernet setting if not compiled in
oappend(SET_F("document.getElementById('ethd').style.display='none';")); oappend(SET_F("document.getElementById('ethd').style.display='none';"));
@ -254,27 +254,72 @@ void getSettingsJS(byte subPage, char* dest)
} }
if (subPage == 2) { if (subPage == 2) {
#ifdef ESP8266 char nS[8];
#if LEDPIN == 3
oappend(SET_F("d.Sf.LC.max=500;")); // add usermod pins as d.um_p array (TODO: usermod config shouldn't use state. instead we should load "um" object from cfg.json)
#else /*DynamicJsonDocument doc(JSON_BUFFER_SIZE);
oappend(SET_F("d.Sf.LC.max=1500;")); JsonObject mods = doc.createNestedObject(F("mods"));
#endif usermods.addToJsonState(mods);
#endif if (!mods.isNull()) {
uint8_t i=0;
oappend(SET_F("d.um_p=["));
for (JsonPair kv : mods) {
if (strncmp_P(kv.key().c_str(),PSTR("pin_"),4) == 0) {
if (i++) oappend(SET_F(","));
oappend(itoa((int)kv.value(),nS,10));
}
}
oappend(SET_F("];"));
}*/
oappend(SET_F("bLimits("));
oappend(itoa(WLED_MAX_BUSSES,nS,10));
oappend(",");
oappend(itoa(MAX_LEDS_PER_BUS,nS,10));
oappend(",");
oappend(itoa(MAX_LED_MEMORY,nS,10));
oappend(SET_F(");"));
oappend(SET_F("d.Sf.LC.max=")); //TODO Formula for max LEDs on ESP8266 depending on types. 500 DMA or 1500 UART (about 4kB mem usage)
oappendi(MAX_LEDS);
oappend(";");
sappend('v',SET_F("LC"),ledCount); sappend('v',SET_F("LC"),ledCount);
for (uint8_t s=0; s < busses.getNumBusses(); s++){
Bus* bus = busses.getBus(s);
char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin
char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length
char co[4] = "CO"; co[2] = 48+s; co[3] = 0; //strip color order
char lt[4] = "LT"; lt[2] = 48+s; lt[3] = 0; //strip type
char ls[4] = "LS"; ls[2] = 48+s; ls[3] = 0; //strip start LED
char cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse
oappend(SET_F("addLEDs(1);"));
uint8_t pins[5];
uint8_t nPins = bus->getPins(pins);
for (uint8_t i = 0; i < nPins; i++) {
lp[1] = 48+i;
if (pinManager.isPinOk(pins[i])) sappend('v', lp, pins[i]);
}
sappend('v', lc, bus->getLength());
sappend('v',lt,bus->getType());
sappend('v',co,bus->getColorOrder());
sappend('v',ls,bus->getStart());
sappend('c',cv,bus->reversed);
}
sappend('v',SET_F("MA"),strip.ablMilliampsMax); sappend('v',SET_F("MA"),strip.ablMilliampsMax);
sappend('v',SET_F("LA"),strip.milliampsPerLed); sappend('v',SET_F("LA"),strip.milliampsPerLed);
if (strip.currentMilliamps) if (strip.currentMilliamps)
{ {
sappends('m',SET_F("(\"pow\")[0]"),""); sappends('m',SET_F("(\"pow\")[0]"),(char*)"");
olen -= 2; //delete "; olen -= 2; //delete ";
oappendi(strip.currentMilliamps); oappendi(strip.currentMilliamps);
oappend(SET_F("mA\";")); oappend(SET_F("mA\";"));
} }
sappend('v',SET_F("CA"),briS); sappend('v',SET_F("CA"),briS);
sappend('c',SET_F("EW"),useRGBW); //sappend('c',SET_F("EW"),useRGBW);
sappend('i',SET_F("CO"),strip.getColorOrder()); //sappend('i',SET_F("CO"),strip.getColorOrder());
sappend('v',SET_F("AW"),strip.rgbwMode); sappend('v',SET_F("AW"),strip.rgbwMode);
sappend('c',SET_F("BO"),turnOnAtBoot); sappend('c',SET_F("BO"),turnOnAtBoot);
@ -292,6 +337,11 @@ void getSettingsJS(byte subPage, char* dest)
sappend('i',SET_F("PB"),strip.paletteBlend); sappend('i',SET_F("PB"),strip.paletteBlend);
sappend('c',SET_F("RV"),strip.reverseMode); sappend('c',SET_F("RV"),strip.reverseMode);
sappend('c',SET_F("SL"),skipFirstLed); sappend('c',SET_F("SL"),skipFirstLed);
sappend('v',SET_F("RL"),rlyPin);
sappend('c',SET_F("RM"),rlyMde);
sappend('v',SET_F("BT"),btnPin);
sappend('v',SET_F("IR"),irPin);
sappend('v',SET_F("AX"),auxPin);
} }
if (subPage == 3) if (subPage == 3)
@ -314,6 +364,10 @@ void getSettingsJS(byte subPage, char* dest)
sappend('c',SET_F("SH"),notifyHue); sappend('c',SET_F("SH"),notifyHue);
sappend('c',SET_F("SM"),notifyMacro); sappend('c',SET_F("SM"),notifyMacro);
sappend('c',SET_F("S2"),notifyTwice); sappend('c',SET_F("S2"),notifyTwice);
sappend('c',SET_F("NL"),nodeListEnabled);
sappend('c',SET_F("NB"),nodeBroadcastEnabled);
sappend('c',SET_F("RD"),receiveDirect); sappend('c',SET_F("RD"),receiveDirect);
sappend('v',SET_F("EP"),e131Port); sappend('v',SET_F("EP"),e131Port);
sappend('c',SET_F("ES"),e131SkipOutOfSequence); sappend('c',SET_F("ES"),e131SkipOutOfSequence);