Merge branch 'dev' into autodiscovery
This commit is contained in:
commit
20bebe98b1
36
CHANGELOG.md
36
CHANGELOG.md
@ -2,6 +2,42 @@
|
||||
|
||||
### Development versions after 0.11.1 release
|
||||
|
||||
#### 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
|
||||
|
||||
- Added color transitions for all segments and slots and for segment brightness
|
||||
|
2887
package-lock.json
generated
2887
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.11.1",
|
||||
"version": "0.12.0-a0",
|
||||
"description": "Tools for WLED project",
|
||||
"main": "tools/cdata.js",
|
||||
"directories": {
|
||||
|
@ -12,7 +12,7 @@
|
||||
default_envs = travis_esp8266, travis_esp32
|
||||
|
||||
# Release binaries
|
||||
; default_envs = nodemcuv2, 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)
|
||||
; default_envs = nodemcuv2
|
||||
@ -30,7 +30,7 @@ default_envs = travis_esp8266, travis_esp32
|
||||
; default_envs = d1_mini_5CH_Shojo_PCB
|
||||
; default_envs = wemos_shield_esp32
|
||||
; default_envs = m5atom
|
||||
; default_envs = esp32_poe
|
||||
; default_envs = esp32_eth
|
||||
|
||||
src_dir = ./wled00
|
||||
data_dir = ./wled00/data
|
||||
@ -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).
|
||||
# ------------------------------------------------------------------------------
|
||||
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
|
||||
-DSECURE_CLIENT=SECURE_CLIENT_BEARSSL
|
||||
-DBEARSSL_SSL_BASIC
|
||||
@ -121,9 +111,6 @@ build_flags =
|
||||
; -D USERMOD_SENSORSTOMQTT
|
||||
|
||||
build_unflags =
|
||||
-Wall
|
||||
-Wreorder
|
||||
-Wdeprecated-declarations
|
||||
|
||||
# enables all features for travis CI
|
||||
build_flags_all_features =
|
||||
@ -159,15 +146,15 @@ build_flags =
|
||||
-DMIMETYPE_MINIMAL
|
||||
|
||||
[esp32]
|
||||
build_flags = -w -g
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
-DCONFIG_LITTLEFS_FOR_IDF_3_2
|
||||
|
||||
[scripts_defaults]
|
||||
extra_scripts = pio/name-firmware.py
|
||||
pio/gzip-firmware.py
|
||||
pio/strip-floats.py
|
||||
pio/user_config_copy.py
|
||||
extra_scripts = pio-scripts/name-firmware.py
|
||||
pio-scripts/gzip-firmware.py
|
||||
pio-scripts/strip-floats.py
|
||||
pio-scripts/user_config_copy.py
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# COMMON SETTINGS:
|
||||
@ -197,7 +184,7 @@ lib_deps =
|
||||
AsyncTCP @ 1.0.3
|
||||
IRremoteESP8266 @ 2.7.3
|
||||
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
|
||||
#TFT_eSPI
|
||||
#For use SSD1306 OLED display uncomment following
|
||||
@ -279,12 +266,12 @@ lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
||||
[env:esp32_poe]
|
||||
[env:esp32_eth]
|
||||
board = esp32-poe
|
||||
platform = espressif32@2.0
|
||||
upload_speed = 921600
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32} -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1
|
||||
build_flags = ${common.build_flags_esp32} -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
@ -11,7 +11,7 @@ default_envs = WLED_tasmota_1M
|
||||
board = esp01_1m
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_1m0m}
|
||||
board_build.ldscript = ${common.ldscript_1m128k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
; *********************************************************************
|
||||
|
@ -398,6 +398,14 @@ const char PAGE_dmxmap[] PROGMEM = R"=====()=====";
|
||||
method: "plaintext",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "liveviewws.htm",
|
||||
name: "PAGE_liveviewws",
|
||||
prepend: "=====(",
|
||||
append: ")=====",
|
||||
method: "plaintext",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "404.htm",
|
||||
name: "PAGE_404",
|
||||
|
427
usermods/Animated_Staircase/Animated_Staircase.h
Normal file
427
usermods/Animated_Staircase/Animated_Staircase.h
Normal 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
|
||||
}
|
||||
}
|
||||
};
|
21
usermods/Animated_Staircase/Animated_Staircase_config.h
Normal file
21
usermods/Animated_Staircase/Animated_Staircase_config.h
Normal 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
|
203
usermods/Animated_Staircase/README.md
Normal file
203
usermods/Animated_Staircase/README.md
Normal 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
|
40
usermods/BME280_v2/README.md
Normal file
40
usermods/BME280_v2/README.md
Normal 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`
|
212
usermods/BME280_v2/usermod_bme280.h
Normal file
212
usermods/BME280_v2/usermod_bme280.h
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
22
usermods/DHT/platformio_override.ini
Normal file
22
usermods/DHT/platformio_override.ini
Normal file
@ -0,0 +1,22 @@
|
||||
; Options
|
||||
; -------
|
||||
; USERMOD_DHT - define this to have this user mod included wled00\usermods_list.cpp
|
||||
; USERMOD_DHT_DHTTYPE - DHT model: 11, 21, 22 for DHT11, DHT21, or DHT22, defaults to 22/DHT22
|
||||
; USERMOD_DHT_PIN - pin to which DTH is connected, defaults to Q2 pin on QuinLed Dig-Uno's board
|
||||
; USERMOD_DHT_CELSIUS - define this to report temperatures in degrees celsious, otherwise fahrenheit will be reported
|
||||
; USERMOD_DHT_MEASUREMENT_INTERVAL - the number of milliseconds between measurements, defaults to 60 seconds
|
||||
; USERMOD_DHT_FIRST_MEASUREMENT_AT - the number of milliseconds after boot to take first measurement, defaults to 90 seconds
|
||||
; USERMOD_DHT_STATS - For debug, report delay stats
|
||||
|
||||
[env:d1_mini_usermod_dht_C]
|
||||
extends = env:d1_mini
|
||||
build_flags = ${env:d1_mini.build_flags} -D USERMOD_DHT -D USERMOD_DHT_CELSIUS
|
||||
lib_deps = ${env.lib_deps}
|
||||
https://github.com/alwynallan/DHT_nonblocking
|
||||
|
||||
[env:custom32_LEDPIN_16_usermod_dht_C]
|
||||
extends = env:custom32_LEDPIN_16
|
||||
build_flags = ${env:custom32_LEDPIN_16.build_flags} -D USERMOD_DHT -D USERMOD_DHT_CELSIUS -D USERMOD_DHT_STATS
|
||||
lib_deps = ${env.lib_deps}
|
||||
https://github.com/alwynallan/DHT_nonblocking
|
||||
|
41
usermods/DHT/readme.md
Normal file
41
usermods/DHT/readme.md
Normal file
@ -0,0 +1,41 @@
|
||||
# DHT Temperature/Humidity sensor usermod
|
||||
|
||||
This usermod will read from an attached DHT22 or DHT11 humidity and temperature sensor.
|
||||
The sensor readings are displayed in the Info section of the web UI.
|
||||
|
||||
If sensor is not detected after a while (10 update intervals), this usermod will be disabled.
|
||||
|
||||
## Installation
|
||||
|
||||
Copy the example `platformio_override.ini` to the root directory. This file should be placed in the same directory as `platformio.ini`.
|
||||
|
||||
### Define Your Options
|
||||
|
||||
* `USERMOD_DHT` - define this to have this user mod included wled00\usermods_list.cpp
|
||||
* `USERMOD_DHT_DHTTYPE` - DHT model: 11, 21, 22 for DHT11, DHT21, or DHT22, defaults to 22/DHT22
|
||||
* `USERMOD_DHT_PIN` - pin to which DTH is connected, defaults to Q2 pin on QuinLed Dig-Uno's board
|
||||
* `USERMOD_DHT_CELSIUS` - define this to report temperatures in degrees celsious, otherwise fahrenheit will be reported
|
||||
* `USERMOD_DHT_MEASUREMENT_INTERVAL` - the number of milliseconds between measurements, defaults to 60 seconds
|
||||
* `USERMOD_DHT_FIRST_MEASUREMENT_AT` - the number of milliseconds after boot to take first measurement, defaults to 90 seconds
|
||||
* `USERMOD_DHT_STATS` - For debug, report delay stats
|
||||
|
||||
## Project link
|
||||
|
||||
* [QuinLED-Dig-Uno](https://quinled.info/2018/09/15/quinled-dig-uno/) - Project link
|
||||
|
||||
### PlatformIO requirements
|
||||
|
||||
If you are using `platformio_override.ini`, you should be able to refresh the task list and see your custom task, for example `env:d1_mini_usermod_dht_C`. If not, you can add the libraries and dependencies into `platformio.ini` as you see fit.
|
||||
|
||||
|
||||
## Change Log
|
||||
|
||||
2020-02-04
|
||||
* Change default QuinLed pin to Q2
|
||||
* Instead of trying to keep updates at constant cadence, space readings out by measurement interval; hope this helps to avoid occasional bursts of readings with errors
|
||||
* Add some more (optional) stats
|
||||
2020-02-03
|
||||
* Due to poor readouts on ESP32 with previous DHT library, rewrote to use https://github.com/alwynallan/DHT_nonblocking
|
||||
* The new library serializes/delays up to 5ms for the sensor readout
|
||||
2020-02-02
|
||||
* Created
|
216
usermods/DHT/usermod_dht.h
Normal file
216
usermods/DHT/usermod_dht.h
Normal file
@ -0,0 +1,216 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
#include <dht_nonblocking.h>
|
||||
|
||||
// USERMOD_DHT_DHTTYPE:
|
||||
// 11 // DHT 11
|
||||
// 21 // DHT 21
|
||||
// 22 // DHT 22 (AM2302), AM2321 *** default
|
||||
#ifndef USERMOD_DHT_DHTTYPE
|
||||
#define USERMOD_DHT_DHTTYPE 22
|
||||
#endif
|
||||
|
||||
#if USERMOD_DHT_DHTTYPE == 11
|
||||
#define DHTTYPE DHT_TYPE_11
|
||||
#elif USERMOD_DHT_DHTTYPE == 21
|
||||
#define DHTTYPE DHT_TYPE_21
|
||||
#elif USERMOD_DHT_DHTTYPE == 22
|
||||
#define DHTTYPE DHT_TYPE_22
|
||||
#endif
|
||||
|
||||
// Connect pin 1 (on the left) of the sensor to +5V
|
||||
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
|
||||
// to 3.3V instead of 5V!
|
||||
// Connect pin 2 of the sensor to whatever your DHTPIN is
|
||||
// NOTE: Pin defaults below are for QuinLed Dig-Uno's Q2 on the board
|
||||
// Connect pin 4 (on the right) of the sensor to GROUND
|
||||
// NOTE: If using a bare sensor (AM*), Connect a 10K resistor from pin 2
|
||||
// (data) to pin 1 (power) of the sensor. DHT* boards have the pullup already
|
||||
|
||||
#ifdef USERMOD_DHT_PIN
|
||||
#define DHTPIN USERMOD_DHT_PIN
|
||||
#else
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#define DHTPIN 21
|
||||
#else //ESP8266 boards
|
||||
#define DHTPIN 4
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// the frequency to check sensor, 1 minute
|
||||
#ifndef USERMOD_DHT_MEASUREMENT_INTERVAL
|
||||
#define USERMOD_DHT_MEASUREMENT_INTERVAL 60000
|
||||
#endif
|
||||
|
||||
// how many seconds after boot to take first measurement, 90 seconds
|
||||
// 90 gives enough time to OTA update firmware if this crashses
|
||||
#ifndef USERMOD_DHT_FIRST_MEASUREMENT_AT
|
||||
#define USERMOD_DHT_FIRST_MEASUREMENT_AT 90000
|
||||
#endif
|
||||
|
||||
// from COOLDOWN_TIME in dht_nonblocking.cpp
|
||||
#define DHT_TIMEOUT_TIME 10000
|
||||
|
||||
DHT_nonblocking dht_sensor(DHTPIN, DHTTYPE);
|
||||
|
||||
class UsermodDHT : public Usermod {
|
||||
private:
|
||||
unsigned long nextReadTime = 0;
|
||||
unsigned long lastReadTime = 0;
|
||||
float humidity, temperature = 0;
|
||||
bool initializing = true;
|
||||
bool disabled = false;
|
||||
#ifdef USERMOD_DHT_STATS
|
||||
unsigned long nextResetStatsTime = 0;
|
||||
uint16_t updates = 0;
|
||||
uint16_t clean_updates = 0;
|
||||
uint16_t errors = 0;
|
||||
unsigned long maxDelay = 0;
|
||||
unsigned long currentIteration = 0;
|
||||
unsigned long maxIteration = 0;
|
||||
#endif
|
||||
|
||||
public:
|
||||
void setup() {
|
||||
nextReadTime = millis() + USERMOD_DHT_FIRST_MEASUREMENT_AT;
|
||||
lastReadTime = millis();
|
||||
#ifdef USERMOD_DHT_STATS
|
||||
nextResetStatsTime = millis() + 60*60*1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
if (millis() < nextReadTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USERMOD_DHT_STATS
|
||||
if (millis() >= nextResetStatsTime) {
|
||||
nextResetStatsTime += 60*60*1000;
|
||||
errors = 0;
|
||||
updates = 0;
|
||||
clean_updates = 0;
|
||||
}
|
||||
unsigned long dcalc = millis();
|
||||
if (currentIteration == 0) {
|
||||
currentIteration = millis();
|
||||
}
|
||||
#endif
|
||||
|
||||
float tempC;
|
||||
if (dht_sensor.measure(&tempC, &humidity)) {
|
||||
#ifdef USERMOD_DHT_CELSIUS
|
||||
temperature = tempC;
|
||||
#else
|
||||
temperature = tempC * 9 / 5 + 32;
|
||||
#endif
|
||||
|
||||
nextReadTime = millis() + USERMOD_DHT_MEASUREMENT_INTERVAL;
|
||||
lastReadTime = millis();
|
||||
initializing = false;
|
||||
|
||||
#ifdef USERMOD_DHT_STATS
|
||||
unsigned long icalc = millis() - currentIteration;
|
||||
if (icalc > maxIteration) {
|
||||
maxIteration = icalc;
|
||||
}
|
||||
if (icalc > DHT_TIMEOUT_TIME) {
|
||||
errors += icalc/DHT_TIMEOUT_TIME;
|
||||
} else {
|
||||
clean_updates += 1;
|
||||
}
|
||||
updates += 1;
|
||||
currentIteration = 0;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USERMOD_DHT_STATS
|
||||
dcalc = millis() - dcalc;
|
||||
if (dcalc > maxDelay) {
|
||||
maxDelay = dcalc;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (((millis() - lastReadTime) > 10*USERMOD_DHT_MEASUREMENT_INTERVAL)) {
|
||||
disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void addToJsonInfo(JsonObject& root) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
|
||||
JsonArray temp = user.createNestedArray("Temperature");
|
||||
JsonArray hum = user.createNestedArray("Humidity");
|
||||
|
||||
#ifdef USERMOD_DHT_STATS
|
||||
JsonArray next = user.createNestedArray("next");
|
||||
if (nextReadTime >= millis()) {
|
||||
next.add((nextReadTime - millis()) / 1000);
|
||||
next.add(" sec until read");
|
||||
} else {
|
||||
next.add((millis() - nextReadTime) / 1000);
|
||||
next.add(" sec active reading");
|
||||
}
|
||||
|
||||
JsonArray last = user.createNestedArray("last");
|
||||
last.add((millis() - lastReadTime) / 60000);
|
||||
last.add(" min since read");
|
||||
|
||||
JsonArray err = user.createNestedArray("errors");
|
||||
err.add(errors);
|
||||
err.add(" Errors");
|
||||
|
||||
JsonArray upd = user.createNestedArray("updates");
|
||||
upd.add(updates);
|
||||
upd.add(" Updates");
|
||||
|
||||
JsonArray cupd = user.createNestedArray("cleanUpdates");
|
||||
cupd.add(clean_updates);
|
||||
cupd.add(" Updates");
|
||||
|
||||
JsonArray iter = user.createNestedArray("maxIter");
|
||||
iter.add(maxIteration);
|
||||
iter.add(" ms");
|
||||
|
||||
JsonArray delay = user.createNestedArray("maxDelay");
|
||||
delay.add(maxDelay);
|
||||
delay.add(" ms");
|
||||
#endif
|
||||
|
||||
if (initializing) {
|
||||
// if we haven't read the sensor yet, let the user know
|
||||
// that we are still waiting for the first measurement
|
||||
temp.add((nextReadTime - millis()) / 1000);
|
||||
temp.add(" sec until read");
|
||||
hum.add((nextReadTime - millis()) / 1000);
|
||||
hum.add(" sec until read");
|
||||
return;
|
||||
}
|
||||
|
||||
hum.add(humidity);
|
||||
hum.add("%");
|
||||
|
||||
temp.add(temperature);
|
||||
#ifdef USERMOD_DHT_CELSIUS
|
||||
temp.add("°C");
|
||||
#else
|
||||
temp.add("°F");
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_DHT;
|
||||
}
|
||||
|
||||
};
|
@ -5,11 +5,13 @@
|
||||
#include <DallasTemperature.h> //DS18B20
|
||||
|
||||
//Pin defaults for QuinLed Dig-Uno
|
||||
#ifndef TEMPERATURE_PIN
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#define TEMPERATURE_PIN 18
|
||||
#else //ESP8266 boards
|
||||
#define TEMPERATURE_PIN 14
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// the frequency to check temperature, 1 minute
|
||||
#ifndef USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL
|
||||
@ -58,6 +60,7 @@ class UsermodTemperature : public Usermod {
|
||||
}
|
||||
|
||||
void getTemperature() {
|
||||
if (strip.isUpdating()) return;
|
||||
#ifdef USERMOD_DALLASTEMPERATURE_CELSIUS
|
||||
temperature = sensor.getTempC(sensorDeviceAddress);
|
||||
#else
|
||||
@ -80,30 +83,28 @@ class UsermodTemperature : public Usermod {
|
||||
disabled = !sensor.getAddress(sensorDeviceAddress, 0);
|
||||
|
||||
if (!disabled) {
|
||||
DEBUG_PRINTLN("Dallas Temperature found");
|
||||
DEBUG_PRINTLN(F("Dallas Temperature found"));
|
||||
// set the resolution for this specific device
|
||||
sensor.setResolution(sensorDeviceAddress, 9, true);
|
||||
// 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 {
|
||||
DEBUG_PRINTLN("Dallas Temperature not found");
|
||||
DEBUG_PRINTLN(F("Dallas Temperature not found"));
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
if (disabled || strip.isUpdating()) return;
|
||||
|
||||
unsigned long now = millis();
|
||||
|
||||
// check to see if we are due for taking a measurement
|
||||
// lastMeasurement will not be updated until the conversion
|
||||
// is complete the the reading is finished
|
||||
if (now - lastMeasurement < USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (now - lastMeasurement < USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL) return;
|
||||
|
||||
// we are due for a measurement, if we are not already waiting
|
||||
// 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
|
||||
// the DallasTemperature library returns -127C or -196.6F when problem
|
||||
// reading the sensor
|
||||
strcat(subuf, "/temperature");
|
||||
strcat_P(subuf, PSTR("/temperature"));
|
||||
mqtt->publish(subuf, 0, true, String(temperature).c_str());
|
||||
} else {
|
||||
// publish something else to indicate status?
|
||||
@ -136,34 +137,32 @@ class UsermodTemperature : public Usermod {
|
||||
|
||||
void addToJsonInfo(JsonObject& root) {
|
||||
// dont add temperature to info if we are disabled
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
if (disabled) return;
|
||||
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
JsonObject user = root[F("u")];
|
||||
if (user.isNull()) user = root.createNestedObject(F("u"));
|
||||
|
||||
JsonArray temp = user.createNestedArray("Temperature");
|
||||
JsonArray temp = user.createNestedArray(F("Temperature"));
|
||||
|
||||
if (!getTemperatureComplete) {
|
||||
// if we haven't read the sensor yet, let the user know
|
||||
// that we are still waiting for the first measurement
|
||||
temp.add((USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT - millis()) / 1000);
|
||||
temp.add(" sec until read");
|
||||
temp.add(F(" sec until read"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (temperature <= -100) {
|
||||
temp.add(0);
|
||||
temp.add(" Sensor Error!");
|
||||
temp.add(F(" Sensor Error!"));
|
||||
return;
|
||||
}
|
||||
|
||||
temp.add(temperature);
|
||||
#ifdef USERMOD_DALLASTEMPERATURE_CELSIUS
|
||||
temp.add("°C");
|
||||
temp.add(F("°C"));
|
||||
#else
|
||||
temp.add("°F");
|
||||
temp.add(F("°F"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
45
usermods/usermod_v2_auto_save/readme.md
Normal file
45
usermods/usermod_v2_auto_save/readme.md
Normal file
@ -0,0 +1,45 @@
|
||||
# Auto Save
|
||||
|
||||
v2 Usermod to automatically save settings
|
||||
to preset number AUTOSAVE_PRESET_NUM after a change to any of
|
||||
|
||||
* brightness
|
||||
* effect speed
|
||||
* effect intensity
|
||||
* mode (effect)
|
||||
* palette
|
||||
|
||||
but it will wait for AUTOSAVE_SETTLE_MS milliseconds, a "settle"
|
||||
period in case there are other changes (any change will
|
||||
extend the "settle" window).
|
||||
|
||||
It will additionally load preset AUTOSAVE_PRESET_NUM at startup.
|
||||
during the first `loop()`. Reasoning below.
|
||||
|
||||
AutoSaveUsermod is standalone, but if FourLineDisplayUsermod is installed, it will notify the user of the saved changes.
|
||||
|
||||
Note: I don't love that WLED doesn't respect the brightness of the preset being auto loaded, so the AutoSaveUsermod will set the AUTOSAVE_PRESET_NUM preset in the first loop, so brightness IS honored. This means WLED will effectively ignore Default brightness and Apply N preset at boot when the AutoSaveUsermod is installed.
|
||||
|
||||
## Installation
|
||||
|
||||
Copy and update the example `platformio_override.ini.sample`
|
||||
from the Rotary Encoder UI usermode folder to the root directory of your particular build.
|
||||
This file should be placed in the same directory as `platformio.ini`.
|
||||
|
||||
### Define Your Options
|
||||
|
||||
* `USERMOD_AUTO_SAVE` - define this to have this the Auto Save usermod included wled00\usermods_list.cpp
|
||||
* `USERMOD_FOUR_LINE_DISLAY` - define this to have this the Four Line Display mod included wled00\usermods_list.cpp - also tells this usermod that the display is available (see the Four Line Display usermod `readme.md` for more details)
|
||||
* `AUTOSAVE_SETTLE_MS` - Minimum time to wave before auto saving, defaults to 10000 (10s)
|
||||
* `AUTOSAVE_PRESET_NUM` - Preset number to auto-save to, auto-load at startup from, defaults to 99
|
||||
|
||||
### PlatformIO requirements
|
||||
|
||||
No special requirements.
|
||||
|
||||
Note: the Four Line Display usermod requires the libraries `U8g2` and `Wire`.
|
||||
|
||||
## Change Log
|
||||
|
||||
2021-02
|
||||
* First public release
|
192
usermods/usermod_v2_auto_save/usermod_v2_auto_save.h
Normal file
192
usermods/usermod_v2_auto_save/usermod_v2_auto_save.h
Normal file
@ -0,0 +1,192 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
//
|
||||
// v2 Usermod to automatically save settings
|
||||
// to preset number AUTOSAVE_PRESET_NUM after a change to any of
|
||||
//
|
||||
// * brightness
|
||||
// * effect speed
|
||||
// * effect intensity
|
||||
// * mode (effect)
|
||||
// * palette
|
||||
//
|
||||
// but it will wait for AUTOSAVE_SETTLE_MS milliseconds, a "settle"
|
||||
// period in case there are other changes (any change will
|
||||
// extend the "settle" window).
|
||||
//
|
||||
// It will additionally load preset AUTOSAVE_PRESET_NUM at startup.
|
||||
// during the first `loop()`. Reasoning below.
|
||||
//
|
||||
// AutoSaveUsermod is standalone, but if FourLineDisplayUsermod
|
||||
// is installed, it will notify the user of the saved changes.
|
||||
//
|
||||
// Note: I don't love that WLED doesn't respect the brightness
|
||||
// of the preset being auto loaded, so the AutoSaveUsermod
|
||||
// will set the AUTOSAVE_PRESET_NUM preset in the first loop,
|
||||
// so brightness IS honored. This means WLED will effectively
|
||||
// ignore Default brightness and Apply N preset at boot when
|
||||
// the AutoSaveUsermod is installed.
|
||||
|
||||
//How long to wait after settings change to auto-save
|
||||
#ifndef AUTOSAVE_SETTLE_MS
|
||||
#define AUTOSAVE_SETTLE_MS 10*1000
|
||||
#endif
|
||||
|
||||
//Preset number to save to
|
||||
#ifndef AUTOSAVE_PRESET_NUM
|
||||
#define AUTOSAVE_PRESET_NUM 99
|
||||
#endif
|
||||
|
||||
// "Auto save MM-DD HH:MM:SS"
|
||||
#define PRESET_NAME_BUFFER_SIZE 25
|
||||
|
||||
class AutoSaveUsermod : public Usermod {
|
||||
private:
|
||||
// If we've detected the need to auto save, this will
|
||||
// be non zero.
|
||||
unsigned long autoSaveAfter = 0;
|
||||
|
||||
char presetNameBuffer[PRESET_NAME_BUFFER_SIZE];
|
||||
|
||||
bool firstLoop = true;
|
||||
|
||||
uint8_t knownBrightness = 0;
|
||||
uint8_t knownEffectSpeed = 0;
|
||||
uint8_t knownEffectIntensity = 0;
|
||||
uint8_t knownMode = 0;
|
||||
uint8_t knownPalette = 0;
|
||||
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
FourLineDisplayUsermod* display;
|
||||
#endif
|
||||
|
||||
public:
|
||||
// gets called once at boot. Do all initialization that doesn't depend on
|
||||
// network here
|
||||
void setup() {
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
// This Usermod has enhanced funcionality if
|
||||
// FourLineDisplayUsermod is available.
|
||||
display = (FourLineDisplayUsermod*) usermods.lookup(USERMOD_ID_FOUR_LINE_DISP);
|
||||
#endif
|
||||
}
|
||||
|
||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||
// interfaces here
|
||||
void connected() {}
|
||||
|
||||
/**
|
||||
* Da loop.
|
||||
*/
|
||||
void loop() {
|
||||
unsigned long now = millis();
|
||||
uint8_t currentMode = strip.getMode();
|
||||
uint8_t currentPalette = strip.getSegment(0).palette;
|
||||
if (firstLoop) {
|
||||
firstLoop = false;
|
||||
applyPreset(AUTOSAVE_PRESET_NUM);
|
||||
knownBrightness = bri;
|
||||
knownEffectSpeed = effectSpeed;
|
||||
knownEffectIntensity = effectIntensity;
|
||||
knownMode = currentMode;
|
||||
knownPalette = currentPalette;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long wouldAutoSaveAfter = now + AUTOSAVE_SETTLE_MS;
|
||||
if (knownBrightness != bri) {
|
||||
knownBrightness = bri;
|
||||
autoSaveAfter = wouldAutoSaveAfter;
|
||||
} else if (knownEffectSpeed != effectSpeed) {
|
||||
knownEffectSpeed = effectSpeed;
|
||||
autoSaveAfter = wouldAutoSaveAfter;
|
||||
} else if (knownEffectIntensity != effectIntensity) {
|
||||
knownEffectIntensity = effectIntensity;
|
||||
autoSaveAfter = wouldAutoSaveAfter;
|
||||
} else if (knownMode != currentMode) {
|
||||
knownMode = currentMode;
|
||||
autoSaveAfter = wouldAutoSaveAfter;
|
||||
} else if (knownPalette != currentPalette) {
|
||||
knownPalette = currentPalette;
|
||||
autoSaveAfter = wouldAutoSaveAfter;
|
||||
}
|
||||
|
||||
if (autoSaveAfter && now > autoSaveAfter) {
|
||||
autoSaveAfter = 0;
|
||||
// Time to auto save. You may have some flickry?
|
||||
saveSettings();
|
||||
displayOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
void saveSettings() {
|
||||
updateLocalTime();
|
||||
sprintf(presetNameBuffer,
|
||||
"Auto save %02d-%02d %02d:%02d:%02d",
|
||||
month(localTime), day(localTime),
|
||||
hour(localTime), minute(localTime), second(localTime));
|
||||
savePreset(AUTOSAVE_PRESET_NUM, true, presetNameBuffer);
|
||||
}
|
||||
|
||||
void displayOverlay() {
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
if (display != nullptr) {
|
||||
display->wakeDisplay();
|
||||
display->overlay("Settings", "Auto Saved", 1500);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void addToJsonState(JsonObject& root) {
|
||||
}
|
||||
|
||||
/*
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void readFromJsonState(JsonObject& root) {
|
||||
}
|
||||
|
||||
/*
|
||||
* addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
|
||||
* It will be called by WLED when settings are actually saved (for example, LED settings are saved)
|
||||
* If you want to force saving the current state, use serializeConfig() in your loop().
|
||||
*
|
||||
* CAUTION: serializeConfig() will initiate a filesystem write operation.
|
||||
* It might cause the LEDs to stutter and will cause flash wear if called too often.
|
||||
* Use it sparingly and always in the loop, never in network callbacks!
|
||||
*
|
||||
* addToConfig() will also not yet add your setting to one of the settings pages automatically.
|
||||
* To make that work you still have to add the setting to the HTML, xml.cpp and set.cpp manually.
|
||||
*
|
||||
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
|
||||
*/
|
||||
void addToConfig(JsonObject& root) {
|
||||
}
|
||||
|
||||
/*
|
||||
* readFromConfig() can be used to read back the custom settings you added with addToConfig().
|
||||
* This is called by WLED when settings are loaded (currently this only happens once immediately after boot)
|
||||
*
|
||||
* readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes),
|
||||
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
|
||||
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
|
||||
*/
|
||||
void readFromConfig(JsonObject& root) {
|
||||
}
|
||||
|
||||
/*
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||
*/
|
||||
uint16_t getId() {
|
||||
return USERMOD_ID_AUTO_SAVE;
|
||||
}
|
||||
|
||||
};
|
39
usermods/usermod_v2_four_line_display/readme.md
Normal file
39
usermods/usermod_v2_four_line_display/readme.md
Normal file
@ -0,0 +1,39 @@
|
||||
# Rotary Encoder UI Usermod
|
||||
|
||||
First, thanks to the authors of the ssd11306_i2c_oled_u8g2 mod.
|
||||
|
||||
This usermod provides a four line display using either
|
||||
128x32 or 128x64 OLED displays.
|
||||
It's can operate independently, but starts to provide
|
||||
a relatively complete on-device UI when paired with the
|
||||
Rotary Encoder UI usermod. I strongly encourage you to use
|
||||
them together.
|
||||
|
||||
[See the pair of usermods in action](https://www.youtube.com/watch?v=tITQY80rIOA)
|
||||
|
||||
## Installation
|
||||
|
||||
Copy and update the example `platformio_override.ini.sample`
|
||||
from the Rotary Encoder UI usermode folder to the root directory of your particular build.
|
||||
This file should be placed in the same directory as `platformio.ini`.
|
||||
|
||||
### Define Your Options
|
||||
|
||||
* `USERMOD_FOUR_LINE_DISLAY` - define this to have this the Four Line Display mod included wled00\usermods_list.cpp - also tells Rotary Encoder usermod, if installed, that the display is available
|
||||
* `FLD_PIN_SCL` - The display SCL pin, defaults to 5
|
||||
* `FLD_PIN_SDA` - The display SDA pin, defaults to 4
|
||||
* `FLIP_MODE` - Set to 0 or 1
|
||||
* `LINE_HEIGHT` - Set to 1 or 2
|
||||
|
||||
There are other `#define` values in the Usermod that might be of interest.
|
||||
|
||||
### PlatformIO requirements
|
||||
|
||||
This usermod requires the `U8g2` and `Wire` libraries. See the
|
||||
`platformio_override.ini.sample` found in the Rotary Encoder
|
||||
UI usermod folder for how to include these using `platformio_override.ini`.
|
||||
|
||||
## Change Log
|
||||
|
||||
2021-02
|
||||
* First public release
|
@ -0,0 +1,526 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
||||
|
||||
//
|
||||
// Insired by the v1 usermod: ssd1306_i2c_oled_u8g2
|
||||
//
|
||||
// v2 usermod for using 128x32 or 128x64 i2c
|
||||
// OLED displays to provide a four line display
|
||||
// for WLED.
|
||||
//
|
||||
// Dependencies
|
||||
// * This usermod REQURES the ModeSortUsermod
|
||||
// * This Usermod works best, by far, when coupled
|
||||
// with RotaryEncoderUIUsermod.
|
||||
//
|
||||
// Make sure to enable NTP and set your time zone in WLED Config | Time.
|
||||
//
|
||||
// REQUIREMENT: You must add the following requirements to
|
||||
// REQUIREMENT: "lib_deps" within platformio.ini / platformio_override.ini
|
||||
// REQUIREMENT: * U8g2 (the version already in platformio.ini is fine)
|
||||
// REQUIREMENT: * Wire
|
||||
//
|
||||
|
||||
//The SCL and SDA pins are defined here.
|
||||
#ifndef FLD_PIN_SCL
|
||||
#define FLD_PIN_SCL 5
|
||||
#endif
|
||||
|
||||
#ifndef FLD_PIN_SDA
|
||||
#define FLD_PIN_SDA 4
|
||||
#endif
|
||||
|
||||
// U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(
|
||||
// U8X8_PIN_NONE, FLD_PIN_SCL, FLD_PIN_SDA);
|
||||
U8X8_SH1106_128X64_WINSTAR_HW_I2C u8x8(
|
||||
U8X8_PIN_NONE, FLD_PIN_SCL, FLD_PIN_SDA);
|
||||
|
||||
// Screen upside down? Change to 0 or 1
|
||||
#ifndef FLIP_MODE
|
||||
#define FLIP_MODE 0
|
||||
#endif
|
||||
|
||||
// LINE_HEIGHT 1 is single height, for 128x32 displays.
|
||||
// LINE_HEIGHT 2 makes the 128x64 screen display at double height.
|
||||
#ifndef LINE_HEIGHT
|
||||
#define LINE_HEIGHT 2
|
||||
#endif
|
||||
|
||||
// If you aren't also including RotaryEncoderUIUsermod
|
||||
// you probably want to set both
|
||||
// SLEEP_MODE_ENABLED false
|
||||
// CLOCK_MODE_ENABLED false
|
||||
// as you will never be able wake the display / disable the clock.
|
||||
#ifdef USERMOD_ROTARY_ENCODER_UI
|
||||
#ifndef SLEEP_MODE_ENABLED
|
||||
#define SLEEP_MODE_ENABLED true
|
||||
#endif
|
||||
#ifndef CLOCK_MODE_ENABLED
|
||||
#define CLOCK_MODE_ENABLED true
|
||||
#endif
|
||||
#else
|
||||
#define SLEEP_MODE_ENABLED false
|
||||
#define CLOCK_MODE_ENABLED false
|
||||
#endif
|
||||
|
||||
// When to time out to the clock or blank the screen
|
||||
// if SLEEP_MODE_ENABLED.
|
||||
#define SCREEN_TIMEOUT_MS 15*1000
|
||||
|
||||
#define TIME_INDENT 0
|
||||
#define DATE_INDENT 2
|
||||
|
||||
// Minimum time between redrawing screen in ms
|
||||
#define USER_LOOP_REFRESH_RATE_MS 1000
|
||||
|
||||
#if LINE_HEIGHT == 2
|
||||
#define DRAW_STRING draw1x2String
|
||||
#define DRAW_GLYPH draw1x2Glyph
|
||||
#define DRAW_BIG_STRING draw2x2String
|
||||
#else
|
||||
#define DRAW_STRING drawString
|
||||
#define DRAW_GLYPH drawGlyph
|
||||
#define DRAW_BIG_STRING draw2x2String
|
||||
#endif
|
||||
|
||||
// Extra char (+1) for null
|
||||
#define LINE_BUFFER_SIZE 16+1
|
||||
#define FLD_LINE_3_BRIGHTNESS 0
|
||||
#define FLD_LINE_3_EFFECT_SPEED 1
|
||||
#define FLD_LINE_3_EFFECT_INTENSITY 2
|
||||
#define FLD_LINE_3_PALETTE 3
|
||||
|
||||
#if LINE_HEIGHT == 2
|
||||
#define TIME_LINE 1
|
||||
#else
|
||||
#define TIME_LINE 0
|
||||
#endif
|
||||
|
||||
class FourLineDisplayUsermod : public Usermod {
|
||||
private:
|
||||
unsigned long lastTime = 0;
|
||||
|
||||
// needRedraw marks if redraw is required to prevent often redrawing.
|
||||
bool needRedraw = true;
|
||||
|
||||
// Next variables hold the previous known values to determine if redraw is
|
||||
// required.
|
||||
String knownSsid = "";
|
||||
IPAddress knownIp;
|
||||
uint8_t knownBrightness = 0;
|
||||
uint8_t knownEffectSpeed = 0;
|
||||
uint8_t knownEffectIntensity = 0;
|
||||
uint8_t knownMode = 0;
|
||||
uint8_t knownPalette = 0;
|
||||
uint8_t knownMinute = 99;
|
||||
uint8_t knownHour = 99;
|
||||
|
||||
bool displayTurnedOff = false;
|
||||
long lastUpdate = 0;
|
||||
long lastRedraw = 0;
|
||||
long overlayUntil = 0;
|
||||
byte lineThreeType = FLD_LINE_3_BRIGHTNESS;
|
||||
// Set to 2 or 3 to mark lines 2 or 3. Other values ignored.
|
||||
byte markLineNum = 0;
|
||||
|
||||
char lineBuffer[LINE_BUFFER_SIZE];
|
||||
|
||||
char **modes_qstrings = nullptr;
|
||||
char **palettes_qstrings = nullptr;
|
||||
|
||||
// If display does not work or looks corrupted check the
|
||||
// constructor reference:
|
||||
// https://github.com/olikraus/u8g2/wiki/u8x8setupcpp
|
||||
// or check the gallery:
|
||||
// https://github.com/olikraus/u8g2/wiki/gallery
|
||||
public:
|
||||
|
||||
// gets called once at boot. Do all initialization that doesn't depend on
|
||||
// network here
|
||||
void setup() {
|
||||
u8x8.begin();
|
||||
u8x8.setFlipMode(FLIP_MODE);
|
||||
u8x8.setPowerSave(0);
|
||||
u8x8.setContrast(10); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
u8x8.DRAW_STRING(0, 0*LINE_HEIGHT, "Loading...");
|
||||
|
||||
ModeSortUsermod *modeSortUsermod = (ModeSortUsermod*) usermods.lookup(USERMOD_ID_MODE_SORT);
|
||||
modes_qstrings = modeSortUsermod->getModesQStrings();
|
||||
palettes_qstrings = modeSortUsermod->getPalettesQStrings();
|
||||
}
|
||||
|
||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||
// interfaces here
|
||||
void connected() {}
|
||||
|
||||
/**
|
||||
* Da loop.
|
||||
*/
|
||||
void loop() {
|
||||
if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS) {
|
||||
return;
|
||||
}
|
||||
lastUpdate = millis();
|
||||
|
||||
redraw(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redraw the screen (but only if things have changed
|
||||
* or if forceRedraw).
|
||||
*/
|
||||
void redraw(bool forceRedraw) {
|
||||
if (overlayUntil > 0) {
|
||||
if (millis() >= overlayUntil) {
|
||||
// Time to display the overlay has elapsed.
|
||||
overlayUntil = 0;
|
||||
forceRedraw = true;
|
||||
}
|
||||
else {
|
||||
// We are still displaying the overlay
|
||||
// Don't redraw.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if values which are shown on display changed from the last time.
|
||||
if (forceRedraw) {
|
||||
needRedraw = true;
|
||||
} else if (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) {
|
||||
needRedraw = true;
|
||||
} else if (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP())) {
|
||||
needRedraw = true;
|
||||
} else if (knownBrightness != bri) {
|
||||
needRedraw = true;
|
||||
} else if (knownEffectSpeed != effectSpeed) {
|
||||
needRedraw = true;
|
||||
} else if (knownEffectIntensity != effectIntensity) {
|
||||
needRedraw = true;
|
||||
} else if (knownMode != strip.getMode()) {
|
||||
needRedraw = true;
|
||||
} else if (knownPalette != strip.getSegment(0).palette) {
|
||||
needRedraw = true;
|
||||
}
|
||||
|
||||
if (!needRedraw) {
|
||||
// Nothing to change.
|
||||
// Turn off display after 3 minutes with no change.
|
||||
if(SLEEP_MODE_ENABLED && !displayTurnedOff &&
|
||||
(millis() - lastRedraw > SCREEN_TIMEOUT_MS)) {
|
||||
// We will still check if there is a change in redraw()
|
||||
// and turn it back on if it changed.
|
||||
sleepOrClock(true);
|
||||
}
|
||||
else if (displayTurnedOff && CLOCK_MODE_ENABLED) {
|
||||
showTime();
|
||||
}
|
||||
return;
|
||||
}
|
||||
needRedraw = false;
|
||||
lastRedraw = millis();
|
||||
|
||||
if (displayTurnedOff)
|
||||
{
|
||||
// Turn the display back on
|
||||
sleepOrClock(false);
|
||||
}
|
||||
|
||||
// Update last known values.
|
||||
#if defined(ESP8266)
|
||||
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
|
||||
#else
|
||||
knownSsid = WiFi.SSID();
|
||||
#endif
|
||||
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
|
||||
knownBrightness = bri;
|
||||
knownMode = strip.getMode();
|
||||
knownPalette = strip.getSegment(0).palette;
|
||||
knownEffectSpeed = effectSpeed;
|
||||
knownEffectIntensity = effectIntensity;
|
||||
|
||||
// Do the actual drawing
|
||||
u8x8.clear();
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
|
||||
// First row with Wifi name
|
||||
String ssidString = knownSsid.substring(0, u8x8.getCols() > 1 ? u8x8.getCols() - 2 : 0);
|
||||
u8x8.DRAW_STRING(1, 0*LINE_HEIGHT, ssidString.c_str());
|
||||
// Print `~` char to indicate that SSID is longer, than owr dicplay
|
||||
if (knownSsid.length() > u8x8.getCols()) {
|
||||
u8x8.DRAW_STRING(u8x8.getCols() - 1, 0*LINE_HEIGHT, "~");
|
||||
}
|
||||
|
||||
// Second row with IP or Psssword
|
||||
// Print password in AP mode and if led is OFF.
|
||||
if (apActive && bri == 0) {
|
||||
u8x8.DRAW_STRING(1, 1*LINE_HEIGHT, apPass);
|
||||
}
|
||||
else {
|
||||
String ipString = knownIp.toString();
|
||||
u8x8.DRAW_STRING(1, 1*LINE_HEIGHT, ipString.c_str());
|
||||
}
|
||||
|
||||
// Third row with mode name
|
||||
showCurrentEffectOrPalette(modes_qstrings[knownMode], 2);
|
||||
|
||||
switch(lineThreeType) {
|
||||
case FLD_LINE_3_BRIGHTNESS:
|
||||
sprintf(lineBuffer, "Brightness %d", bri);
|
||||
u8x8.DRAW_STRING(1, 3*LINE_HEIGHT, lineBuffer);
|
||||
break;
|
||||
case FLD_LINE_3_EFFECT_SPEED:
|
||||
sprintf(lineBuffer, "FX Speed %d", effectSpeed);
|
||||
u8x8.DRAW_STRING(1, 3*LINE_HEIGHT, lineBuffer);
|
||||
break;
|
||||
case FLD_LINE_3_EFFECT_INTENSITY:
|
||||
sprintf(lineBuffer, "FX Intense %d", effectIntensity);
|
||||
u8x8.DRAW_STRING(1, 3*LINE_HEIGHT, lineBuffer);
|
||||
break;
|
||||
case FLD_LINE_3_PALETTE:
|
||||
showCurrentEffectOrPalette(palettes_qstrings[knownPalette], 3);
|
||||
break;
|
||||
}
|
||||
|
||||
u8x8.setFont(u8x8_font_open_iconic_arrow_1x1);
|
||||
u8x8.DRAW_GLYPH(0, markLineNum*LINE_HEIGHT, 66); // arrow icon
|
||||
|
||||
u8x8.setFont(u8x8_font_open_iconic_embedded_1x1);
|
||||
u8x8.DRAW_GLYPH(0, 0*LINE_HEIGHT, 80); // wifi icon
|
||||
u8x8.DRAW_GLYPH(0, 1*LINE_HEIGHT, 68); // home icon
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the current effect or palette (desiredEntry)
|
||||
* on the appropriate line (row).
|
||||
*
|
||||
* TODO: Should we cache the current effect and
|
||||
* TODO: palette name? This seems expensive.
|
||||
*/
|
||||
void showCurrentEffectOrPalette(char *qstring, uint8_t row) {
|
||||
uint8_t printedChars = 1;
|
||||
char singleJsonSymbol;
|
||||
int i = 0;
|
||||
while (true) {
|
||||
singleJsonSymbol = pgm_read_byte_near(qstring + i);
|
||||
if (singleJsonSymbol == '"' || singleJsonSymbol == '\0' ) {
|
||||
break;
|
||||
}
|
||||
u8x8.DRAW_GLYPH(printedChars, row * LINE_HEIGHT, singleJsonSymbol);
|
||||
printedChars++;
|
||||
if ( (printedChars > u8x8.getCols() - 2)) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If there screen is off or in clock is displayed,
|
||||
* this will return true. This allows us to throw away
|
||||
* the first input from the rotary encoder but
|
||||
* to wake up the screen.
|
||||
*/
|
||||
bool wakeDisplay() {
|
||||
if (displayTurnedOff) {
|
||||
// Turn the display back on
|
||||
sleepOrClock(false);
|
||||
redraw(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to show up to two lines as overlay for a
|
||||
* period of time.
|
||||
* Clears the screen and prints on the middle two lines.
|
||||
*/
|
||||
void overlay(const char* line1, const char *line2, long showHowLong) {
|
||||
if (displayTurnedOff) {
|
||||
// Turn the display back on
|
||||
sleepOrClock(false);
|
||||
}
|
||||
|
||||
// Print the overlay
|
||||
u8x8.clear();
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
if (line1) {
|
||||
u8x8.DRAW_STRING(0, 1*LINE_HEIGHT, line1);
|
||||
}
|
||||
if (line2) {
|
||||
u8x8.DRAW_STRING(0, 2*LINE_HEIGHT, line2);
|
||||
}
|
||||
overlayUntil = millis() + showHowLong;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify what data should be defined on line 3
|
||||
* (the last line).
|
||||
*/
|
||||
void setLineThreeType(byte newLineThreeType) {
|
||||
if (newLineThreeType == FLD_LINE_3_BRIGHTNESS ||
|
||||
newLineThreeType == FLD_LINE_3_EFFECT_SPEED ||
|
||||
newLineThreeType == FLD_LINE_3_EFFECT_INTENSITY ||
|
||||
newLineThreeType == FLD_LINE_3_PALETTE) {
|
||||
lineThreeType = newLineThreeType;
|
||||
}
|
||||
else {
|
||||
// Unknown value.
|
||||
lineThreeType = FLD_LINE_3_BRIGHTNESS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Line 2 or 3 (last two lines) can be marked with an
|
||||
* arrow in the first column. Pass 2 or 3 to this to
|
||||
* specify which line to mark with an arrow.
|
||||
* Any other values are ignored.
|
||||
*/
|
||||
void setMarkLine(byte newMarkLineNum) {
|
||||
if (newMarkLineNum == 2 || newMarkLineNum == 3) {
|
||||
markLineNum = newMarkLineNum;
|
||||
}
|
||||
else {
|
||||
markLineNum = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
|
||||
* Below it is shown how this could be used for e.g. a light sensor
|
||||
*/
|
||||
/*
|
||||
void addToJsonInfo(JsonObject& root)
|
||||
{
|
||||
int reading = 20;
|
||||
//this code adds "u":{"Light":[20," lux"]} to the info object
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
|
||||
JsonArray lightArr = user.createNestedArray("Light"); //name
|
||||
lightArr.add(reading); //value
|
||||
lightArr.add(" lux"); //unit
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Enable sleep (turn the display off) or clock mode.
|
||||
*/
|
||||
void sleepOrClock(bool enabled) {
|
||||
if (enabled) {
|
||||
if (CLOCK_MODE_ENABLED) {
|
||||
showTime();
|
||||
}
|
||||
else {
|
||||
u8x8.setPowerSave(1);
|
||||
}
|
||||
displayTurnedOff = true;
|
||||
}
|
||||
else {
|
||||
if (!CLOCK_MODE_ENABLED) {
|
||||
u8x8.setPowerSave(0);
|
||||
}
|
||||
displayTurnedOff = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the current date and time in large characters
|
||||
* on the middle rows. Based 24 or 12 hour depending on
|
||||
* the useAMPM configuration.
|
||||
*/
|
||||
void showTime() {
|
||||
updateLocalTime();
|
||||
byte minuteCurrent = minute(localTime);
|
||||
byte hourCurrent = hour(localTime);
|
||||
if (knownMinute == minuteCurrent && knownHour == hourCurrent) {
|
||||
// Time hasn't changed.
|
||||
return;
|
||||
}
|
||||
knownMinute = minuteCurrent;
|
||||
knownHour = hourCurrent;
|
||||
|
||||
u8x8.clear();
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
|
||||
int currentMonth = month(localTime);
|
||||
sprintf(lineBuffer, "%s %d", monthShortStr(currentMonth), day(localTime));
|
||||
u8x8.DRAW_BIG_STRING(DATE_INDENT, TIME_LINE*LINE_HEIGHT, lineBuffer);
|
||||
|
||||
byte showHour = hourCurrent;
|
||||
boolean isAM = false;
|
||||
if (useAMPM) {
|
||||
if (showHour == 0) {
|
||||
showHour = 12;
|
||||
isAM = true;
|
||||
}
|
||||
else if (showHour > 12) {
|
||||
showHour -= 12;
|
||||
isAM = false;
|
||||
}
|
||||
else {
|
||||
isAM = true;
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(lineBuffer, "%02d:%02d %s", showHour, minuteCurrent, useAMPM ? (isAM ? "AM" : "PM") : "");
|
||||
// For time, we always use LINE_HEIGHT of 2 since
|
||||
// we are printing it big.
|
||||
u8x8.DRAW_BIG_STRING(TIME_INDENT + (useAMPM ? 0 : 2), (TIME_LINE + 1) * 2, lineBuffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void addToJsonState(JsonObject& root) {
|
||||
}
|
||||
|
||||
/*
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void readFromJsonState(JsonObject& root) {
|
||||
}
|
||||
|
||||
/*
|
||||
* addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
|
||||
* It will be called by WLED when settings are actually saved (for example, LED settings are saved)
|
||||
* If you want to force saving the current state, use serializeConfig() in your loop().
|
||||
*
|
||||
* CAUTION: serializeConfig() will initiate a filesystem write operation.
|
||||
* It might cause the LEDs to stutter and will cause flash wear if called too often.
|
||||
* Use it sparingly and always in the loop, never in network callbacks!
|
||||
*
|
||||
* addToConfig() will also not yet add your setting to one of the settings pages automatically.
|
||||
* To make that work you still have to add the setting to the HTML, xml.cpp and set.cpp manually.
|
||||
*
|
||||
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
|
||||
*/
|
||||
void addToConfig(JsonObject& root) {
|
||||
}
|
||||
|
||||
/*
|
||||
* readFromConfig() can be used to read back the custom settings you added with addToConfig().
|
||||
* This is called by WLED when settings are loaded (currently this only happens once immediately after boot)
|
||||
*
|
||||
* readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes),
|
||||
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
|
||||
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
|
||||
*/
|
||||
void readFromConfig(JsonObject& root) {
|
||||
}
|
||||
|
||||
/*
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||
*/
|
||||
uint16_t getId() {
|
||||
return USERMOD_ID_FOUR_LINE_DISP;
|
||||
}
|
||||
|
||||
};
|
33
usermods/usermod_v2_mode_sort/readme.md
Normal file
33
usermods/usermod_v2_mode_sort/readme.md
Normal file
@ -0,0 +1,33 @@
|
||||
# Mode Sort
|
||||
|
||||
v2 usermod that provides data about modes and
|
||||
palettes to other usermods. Notably it provides:
|
||||
* A direct method for a mode or palette name
|
||||
* Ability to retrieve mode and palette names in
|
||||
alphabetical order
|
||||
|
||||
```char **getModesQStrings()```
|
||||
|
||||
Provides an array of char* (pointers) to the names of the
|
||||
palettes within JSON_mode_names, in the same order as
|
||||
JSON_mode_names. These strings end in double quote (")
|
||||
(or \0 if there is a problem).
|
||||
|
||||
```byte *getModesAlphaIndexes()```
|
||||
|
||||
An array of byte designating the indexes of names of the
|
||||
modes in alphabetical order. "Solid" will always remain
|
||||
at the front of the list.
|
||||
|
||||
```char **getPalettesQStrings()```
|
||||
|
||||
Provides an array of char* (pointers) to the names of the
|
||||
palettes within JSON_palette_names, in the same order as
|
||||
JSON_palette_names. These strings end in double quote (")
|
||||
(or \0 if there is a problem).
|
||||
|
||||
```byte *getPalettesAlphaIndexes()```
|
||||
|
||||
An array of byte designating the indexes of names of the
|
||||
palettes in alphabetical order. "Default" and those
|
||||
starting with "(" will always remain at the front of the list.
|
248
usermods/usermod_v2_mode_sort/usermod_v2_mode_sort.h
Normal file
248
usermods/usermod_v2_mode_sort/usermod_v2_mode_sort.h
Normal file
@ -0,0 +1,248 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
//
|
||||
// v2 usermod that provides data about modes and
|
||||
// palettes to other usermods. Notably it provides:
|
||||
// * A direct method for a mode or palette name
|
||||
// * Ability to retrieve mode and palette names in
|
||||
// alphabetical order
|
||||
//
|
||||
// char **getModesQStrings()
|
||||
// Provides an array of char* (pointers) to the names of the
|
||||
// palettes within JSON_mode_names, in the same order as
|
||||
// JSON_mode_names. These strings end in double quote (")
|
||||
// (or \0 if there is a problem).
|
||||
//
|
||||
// byte *getModesAlphaIndexes()
|
||||
// An array of byte designating the indexes of names of the
|
||||
// modes in alphabetical order. "Solid" will always remain
|
||||
// at the front of the list.
|
||||
//
|
||||
// char **getPalettesQStrings()
|
||||
// Provides an array of char* (pointers) to the names of the
|
||||
// palettes within JSON_palette_names, in the same order as
|
||||
// JSON_palette_names. These strings end in double quote (")
|
||||
// (or \0 if there is a problem).
|
||||
//
|
||||
// byte *getPalettesAlphaIndexes()
|
||||
// An array of byte designating the indexes of names of the
|
||||
// palettes in alphabetical order. "Default" and those
|
||||
// starting with "(" will always remain at the front of the list.
|
||||
//
|
||||
|
||||
// Number of modes at the start of the list to not sort
|
||||
#define MODE_SORT_SKIP_COUNT 1
|
||||
|
||||
// Which list is being sorted
|
||||
char **listBeingSorted = nullptr;
|
||||
|
||||
/**
|
||||
* Modes and palettes are stored as strings that
|
||||
* end in a quote character. Compare two of them.
|
||||
* We are comparing directly within either
|
||||
* JSON_mode_names or JSON_palette_names.
|
||||
*/
|
||||
int re_qstringCmp(const void *ap, const void *bp) {
|
||||
char *a = listBeingSorted[*((byte *)ap)];
|
||||
char *b = listBeingSorted[*((byte *)bp)];
|
||||
int i = 0;
|
||||
do {
|
||||
char aVal = pgm_read_byte_near(a + i);
|
||||
if (aVal >= 97 && aVal <= 122) {
|
||||
// Lowercase
|
||||
aVal -= 32;
|
||||
}
|
||||
char bVal = pgm_read_byte_near(b + i);
|
||||
if (bVal >= 97 && bVal <= 122) {
|
||||
// Lowercase
|
||||
bVal -= 32;
|
||||
}
|
||||
// Relly we shouldn't ever get to '\0'
|
||||
if (aVal == '"' || bVal == '"' || aVal == '\0' || bVal == '\0') {
|
||||
// We're done. one is a substring of the other
|
||||
// or something happenend and the quote didn't stop us.
|
||||
if (aVal == bVal) {
|
||||
// Same value, probably shouldn't happen
|
||||
// with this dataset
|
||||
return 0;
|
||||
}
|
||||
else if (aVal == '"' || aVal == '\0') {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (aVal == bVal) {
|
||||
// Same characters. Move to the next.
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
// We're done
|
||||
if (aVal < bVal) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
} while (true);
|
||||
// We shouldn't get here.
|
||||
return 0;
|
||||
}
|
||||
|
||||
class ModeSortUsermod : public Usermod {
|
||||
private:
|
||||
|
||||
// Pointers the start of the mode names within JSON_mode_names
|
||||
char **modes_qstrings = nullptr;
|
||||
|
||||
// Array of mode indexes in alphabetical order.
|
||||
byte *modes_alpha_indexes = nullptr;
|
||||
|
||||
// Pointers the start of the palette names within JSON_palette_names
|
||||
char **palettes_qstrings = nullptr;
|
||||
|
||||
// Array of palette indexes in alphabetical order.
|
||||
byte *palettes_alpha_indexes = nullptr;
|
||||
|
||||
public:
|
||||
/**
|
||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||
* You can use it to initialize variables, sensors or similar.
|
||||
*/
|
||||
void setup() {
|
||||
// Sort the modes and palettes on startup
|
||||
// as they are guarantted to change.
|
||||
sortModesAndPalettes();
|
||||
}
|
||||
|
||||
char **getModesQStrings() {
|
||||
return modes_qstrings;
|
||||
}
|
||||
|
||||
byte *getModesAlphaIndexes() {
|
||||
return modes_alpha_indexes;
|
||||
}
|
||||
|
||||
char **getPalettesQStrings() {
|
||||
return palettes_qstrings;
|
||||
}
|
||||
|
||||
byte *getPalettesAlphaIndexes() {
|
||||
return palettes_alpha_indexes;
|
||||
}
|
||||
|
||||
/**
|
||||
* This Usermod doesn't have anything for loop.
|
||||
*/
|
||||
void loop() {}
|
||||
|
||||
/**
|
||||
* Sort the modes and palettes to the index arrays
|
||||
* modes_alpha_indexes and palettes_alpha_indexes.
|
||||
*/
|
||||
void sortModesAndPalettes() {
|
||||
modes_qstrings = re_findModeStrings(JSON_mode_names, strip.getModeCount());
|
||||
modes_alpha_indexes = re_initIndexArray(strip.getModeCount());
|
||||
re_sortModes(modes_qstrings, modes_alpha_indexes, strip.getModeCount(), MODE_SORT_SKIP_COUNT);
|
||||
|
||||
palettes_qstrings = re_findModeStrings(JSON_palette_names, strip.getPaletteCount());
|
||||
palettes_alpha_indexes = re_initIndexArray(strip.getPaletteCount());
|
||||
|
||||
int skipPaletteCount = 1;
|
||||
while (true) {
|
||||
// How many palette names start with '*' and should not be sorted?
|
||||
// (Also skipping the first one, 'Default').
|
||||
if (pgm_read_byte_near(palettes_qstrings[skipPaletteCount]) == '*') {
|
||||
skipPaletteCount++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
re_sortModes(palettes_qstrings, palettes_alpha_indexes, strip.getPaletteCount(), skipPaletteCount);
|
||||
}
|
||||
|
||||
byte *re_initIndexArray(int numModes) {
|
||||
byte *indexes = (byte *)malloc(sizeof(byte) * numModes);
|
||||
for (byte i = 0; i < numModes; i++) {
|
||||
indexes[i] = i;
|
||||
}
|
||||
return indexes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of mode or palette names from the JSON string.
|
||||
* They don't end in '\0', they end in '"'.
|
||||
*/
|
||||
char **re_findModeStrings(const char json[], int numModes) {
|
||||
char **modeStrings = (char **)malloc(sizeof(char *) * numModes);
|
||||
uint8_t modeIndex = 0;
|
||||
bool insideQuotes = false;
|
||||
// advance past the mark for markLineNum that may exist.
|
||||
char singleJsonSymbol;
|
||||
|
||||
// Find the mode name in JSON
|
||||
bool complete = false;
|
||||
for (size_t i = 0; i < strlen_P(json); i++) {
|
||||
singleJsonSymbol = pgm_read_byte_near(json + i);
|
||||
switch (singleJsonSymbol) {
|
||||
case '"':
|
||||
insideQuotes = !insideQuotes;
|
||||
if (insideQuotes) {
|
||||
// We have a new mode or palette
|
||||
modeStrings[modeIndex] = (char *)(json + i + 1);
|
||||
}
|
||||
break;
|
||||
case '[':
|
||||
break;
|
||||
case ']':
|
||||
complete = true;
|
||||
break;
|
||||
case ',':
|
||||
modeIndex++;
|
||||
default:
|
||||
if (!insideQuotes) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (complete) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return modeStrings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort either the modes or the palettes using quicksort.
|
||||
*/
|
||||
void re_sortModes(char **modeNames, byte *indexes, int count, int numSkip) {
|
||||
listBeingSorted = modeNames;
|
||||
qsort(indexes + numSkip, count - numSkip, sizeof(byte), re_qstringCmp);
|
||||
listBeingSorted = nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void addToJsonState(JsonObject &root) {}
|
||||
|
||||
/*
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void readFromJsonState(JsonObject &root) {}
|
||||
|
||||
/*
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||
*/
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_MODE_SORT;
|
||||
}
|
||||
};
|
@ -0,0 +1,48 @@
|
||||
[platformio]
|
||||
default_envs = d1_mini
|
||||
; default_envs = esp32dev
|
||||
|
||||
[env:esp32dev]
|
||||
board = esp32dev
|
||||
platform = espressif32@2.0
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags =
|
||||
${common.build_flags_esp32}
|
||||
-D USERMOD_MODE_SORT
|
||||
-D USERMOD_FOUR_LINE_DISLAY -D FLD_PIN_SCL=22 -D FLD_PIN_SDA=21
|
||||
-D USERMOD_ROTARY_ENCODER_UI -D ENCODER_DT_PIN=18 -D ENCODER_CLK_PIN=5 -D ENCODER_SW_PIN=19
|
||||
-D USERMOD_AUTO_SAVE -D AUTOSAVE_PRESET_NUM=1
|
||||
-D LEDPIN=16 -D BTNPIN=13
|
||||
upload_speed = 460800
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
||||
[env:d1_mini]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
upload_speed = 460800
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags =
|
||||
${common.build_flags_esp8266}
|
||||
-D USERMOD_MODE_SORT
|
||||
-D USERMOD_FOUR_LINE_DISLAY -D FLD_PIN_SCL=5 -D FLD_PIN_SDA=4
|
||||
-D USERMOD_ROTARY_ENCODER_UI -D ENCODER_DT_PIN=12 -D ENCODER_CLK_PIN=14 -D ENCODER_SW_PIN=13
|
||||
-D USERMOD_AUTO_SAVE -D AUTOSAVE_PRESET_NUM=1
|
||||
-D LEDPIN=3 -D BTNPIN=0
|
||||
monitor_filters = esp8266_exception_decoder
|
||||
|
||||
[env]
|
||||
lib_deps =
|
||||
fastled/FastLED @ 3.3.2
|
||||
NeoPixelBus @ 2.6.0
|
||||
ESPAsyncTCP @ 1.2.0
|
||||
ESPAsyncUDP
|
||||
AsyncTCP @ 1.0.3
|
||||
IRremoteESP8266 @ 2.7.3
|
||||
https://github.com/lorol/LITTLEFS.git
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.0
|
||||
U8g2@~2.27.2
|
||||
Wire
|
33
usermods/usermod_v2_rotary_encoder_ui/readme.md
Normal file
33
usermods/usermod_v2_rotary_encoder_ui/readme.md
Normal file
@ -0,0 +1,33 @@
|
||||
# Rotary Encoder UI Usermod
|
||||
|
||||
First, thanks to the authors of other Rotary Encoder usermods.
|
||||
|
||||
This usermod starts to provide a relatively complete on-device
|
||||
UI when paired with the Four Line Display usermod. I strongly
|
||||
encourage you to try them together.
|
||||
|
||||
[See the pair of usermods in action](https://www.youtube.com/watch?v=tITQY80rIOA)
|
||||
|
||||
## Installation
|
||||
|
||||
Copy and update the example `platformio_override.ini.sample` to the root directory of your particular build.
|
||||
This file should be placed in the same directory as `platformio.ini`.
|
||||
|
||||
### Define Your Options
|
||||
|
||||
* `USERMOD_ROTARY_ENCODER_UI` - define this to have this user mod included wled00\usermods_list.cpp
|
||||
* `USERMOD_FOUR_LINE_DISLAY` - define this to have this the Four Line Display mod included wled00\usermods_list.cpp - also tells this usermod that the display is available (see the Four Line Display usermod `readme.md` for more details)
|
||||
* `ENCODER_DT_PIN` - The encoders DT pin, defaults to 12
|
||||
* `ENCODER_CLK_PIN` - The encoders CLK pin, defaults to 14
|
||||
* `ENCODER_SW_PIN` - The encoders SW pin, defaults to 13
|
||||
|
||||
### PlatformIO requirements
|
||||
|
||||
No special requirements.
|
||||
|
||||
Note: the Four Line Display usermod requires the libraries `U8g2` and `Wire`.
|
||||
|
||||
## Change Log
|
||||
|
||||
2021-02
|
||||
* First public release
|
@ -0,0 +1,401 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
//
|
||||
// Inspired by the v1 usermods
|
||||
// * rotary_encoder_change_brightness
|
||||
// * rotary_encoder_change_effect
|
||||
//
|
||||
// v2 usermod that provides a rotary encoder-based UI.
|
||||
//
|
||||
// This usermod allows you to control:
|
||||
//
|
||||
// * Brightness
|
||||
// * Selected Effect
|
||||
// * Effect Speed
|
||||
// * Effect Intensity
|
||||
// * Palette
|
||||
//
|
||||
// Change between modes by pressing a button.
|
||||
//
|
||||
// Dependencies
|
||||
// * This usermod REQURES the ModeSortUsermod
|
||||
// * This Usermod works best coupled with
|
||||
// FourLineDisplayUsermod.
|
||||
//
|
||||
|
||||
#ifndef ENCODER_DT_PIN
|
||||
#define ENCODER_DT_PIN 12
|
||||
#endif
|
||||
|
||||
#ifndef ENCODER_CLK_PIN
|
||||
#define ENCODER_CLK_PIN 14
|
||||
#endif
|
||||
|
||||
#ifndef ENCODER_SW_PIN
|
||||
#define ENCODER_SW_PIN 13
|
||||
#endif
|
||||
|
||||
#ifndef USERMOD_FOUR_LINE_DISLAY
|
||||
// These constants won't be defined if we aren't using FourLineDisplay.
|
||||
#define FLD_LINE_3_BRIGHTNESS 0
|
||||
#define FLD_LINE_3_EFFECT_SPEED 0
|
||||
#define FLD_LINE_3_EFFECT_INTENSITY 0
|
||||
#define FLD_LINE_3_PALETTE 0
|
||||
#endif
|
||||
|
||||
|
||||
// The last UI state
|
||||
#define LAST_UI_STATE 4
|
||||
|
||||
|
||||
class RotaryEncoderUIUsermod : public Usermod {
|
||||
private:
|
||||
int fadeAmount = 10; // Amount to change every step (brightness)
|
||||
unsigned long currentTime;
|
||||
unsigned long loopTime;
|
||||
const int pinA = ENCODER_DT_PIN; // DT from encoder
|
||||
const int pinB = ENCODER_CLK_PIN; // CLK from encoder
|
||||
const int pinC = ENCODER_SW_PIN; // SW from encoder
|
||||
unsigned char select_state = 0; // 0: brightness, 1: effect, 2: effect speed
|
||||
unsigned char button_state = HIGH;
|
||||
unsigned char prev_button_state = HIGH;
|
||||
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
FourLineDisplayUsermod *display;
|
||||
#else
|
||||
void* display = nullptr;
|
||||
#endif
|
||||
|
||||
byte *modes_alpha_indexes = nullptr;
|
||||
byte *palettes_alpha_indexes = nullptr;
|
||||
|
||||
unsigned char Enc_A;
|
||||
unsigned char Enc_B;
|
||||
unsigned char Enc_A_prev = 0;
|
||||
|
||||
bool currentEffectAndPaleeteInitialized = false;
|
||||
uint8_t effectCurrentIndex = 0;
|
||||
uint8_t effectPaletteIndex = 0;
|
||||
|
||||
public:
|
||||
/*
|
||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||
* You can use it to initialize variables, sensors or similar.
|
||||
*/
|
||||
void setup()
|
||||
{
|
||||
pinMode(pinA, INPUT_PULLUP);
|
||||
pinMode(pinB, INPUT_PULLUP);
|
||||
pinMode(pinC, INPUT_PULLUP);
|
||||
currentTime = millis();
|
||||
loopTime = currentTime;
|
||||
|
||||
ModeSortUsermod *modeSortUsermod = (ModeSortUsermod*) usermods.lookup(USERMOD_ID_MODE_SORT);
|
||||
modes_alpha_indexes = modeSortUsermod->getModesAlphaIndexes();
|
||||
palettes_alpha_indexes = modeSortUsermod->getPalettesAlphaIndexes();
|
||||
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
// This Usermod uses FourLineDisplayUsermod for the best experience.
|
||||
// But it's optional. But you want it.
|
||||
display = (FourLineDisplayUsermod*) usermods.lookup(USERMOD_ID_FOUR_LINE_DISP);
|
||||
if (display != nullptr) {
|
||||
display->setLineThreeType(FLD_LINE_3_BRIGHTNESS);
|
||||
display->setMarkLine(3);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* connected() is called every time the WiFi is (re)connected
|
||||
* Use it to initialize network interfaces
|
||||
*/
|
||||
void connected()
|
||||
{
|
||||
//Serial.println("Connected to WiFi!");
|
||||
}
|
||||
|
||||
/*
|
||||
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||
*
|
||||
* Tips:
|
||||
* 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection.
|
||||
* Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker.
|
||||
*
|
||||
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
|
||||
* Instead, use a timer check as shown here.
|
||||
*/
|
||||
void loop()
|
||||
{
|
||||
currentTime = millis(); // get the current elapsed time
|
||||
|
||||
// Initialize effectCurrentIndex and effectPaletteIndex to
|
||||
// current state. We do it here as (at least) effectCurrent
|
||||
// is not yet initialized when setup is called.
|
||||
if (!currentEffectAndPaleeteInitialized) {
|
||||
findCurrentEffectAndPalette();
|
||||
}
|
||||
|
||||
if (currentTime >= (loopTime + 2)) // 2ms since last check of encoder = 500Hz
|
||||
{
|
||||
button_state = digitalRead(pinC);
|
||||
if (prev_button_state != button_state)
|
||||
{
|
||||
if (button_state == LOW)
|
||||
{
|
||||
prev_button_state = button_state;
|
||||
|
||||
char newState = select_state + 1;
|
||||
if (newState > LAST_UI_STATE) newState = 0;
|
||||
|
||||
bool changedState = true;
|
||||
if (display != nullptr) {
|
||||
switch(newState) {
|
||||
case 0:
|
||||
changedState = changeState("Brightness", FLD_LINE_3_BRIGHTNESS, 3);
|
||||
break;
|
||||
case 1:
|
||||
changedState = changeState("Select FX", FLD_LINE_3_EFFECT_SPEED, 2);
|
||||
break;
|
||||
case 2:
|
||||
changedState = changeState("FX Speed", FLD_LINE_3_EFFECT_SPEED, 3);
|
||||
break;
|
||||
case 3:
|
||||
changedState = changeState("FX Intensity", FLD_LINE_3_EFFECT_INTENSITY, 3);
|
||||
break;
|
||||
case 4:
|
||||
changedState = changeState("Palette", FLD_LINE_3_PALETTE, 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (changedState) {
|
||||
select_state = newState;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_button_state = button_state;
|
||||
}
|
||||
}
|
||||
int Enc_A = digitalRead(pinA); // Read encoder pins
|
||||
int Enc_B = digitalRead(pinB);
|
||||
if ((!Enc_A) && (Enc_A_prev))
|
||||
{ // A has gone from high to low
|
||||
if (Enc_B == HIGH)
|
||||
{ // B is high so clockwise
|
||||
switch(select_state) {
|
||||
case 0:
|
||||
changeBrightness(true);
|
||||
break;
|
||||
case 1:
|
||||
changeEffect(true);
|
||||
break;
|
||||
case 2:
|
||||
changeEffectSpeed(true);
|
||||
break;
|
||||
case 3:
|
||||
changeEffectIntensity(true);
|
||||
break;
|
||||
case 4:
|
||||
changePalette(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (Enc_B == LOW)
|
||||
{ // B is low so counter-clockwise
|
||||
switch(select_state) {
|
||||
case 0:
|
||||
changeBrightness(false);
|
||||
break;
|
||||
case 1:
|
||||
changeEffect(false);
|
||||
break;
|
||||
case 2:
|
||||
changeEffectSpeed(false);
|
||||
break;
|
||||
case 3:
|
||||
changeEffectIntensity(false);
|
||||
break;
|
||||
case 4:
|
||||
changePalette(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Enc_A_prev = Enc_A; // Store value of A for next time
|
||||
loopTime = currentTime; // Updates loopTime
|
||||
}
|
||||
}
|
||||
|
||||
void findCurrentEffectAndPalette() {
|
||||
currentEffectAndPaleeteInitialized = true;
|
||||
for (uint8_t i = 0; i < strip.getModeCount(); i++) {
|
||||
byte value = modes_alpha_indexes[i];
|
||||
if (modes_alpha_indexes[i] == effectCurrent) {
|
||||
effectCurrentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < strip.getPaletteCount(); i++) {
|
||||
byte value = palettes_alpha_indexes[i];
|
||||
if (palettes_alpha_indexes[i] == strip.getSegment(0).palette) {
|
||||
effectPaletteIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean changeState(const char *stateName, byte lineThreeMode, byte markedLine) {
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
if (display != nullptr) {
|
||||
if (display->wakeDisplay()) {
|
||||
// Throw away wake up input
|
||||
return false;
|
||||
}
|
||||
display->overlay("Mode change", stateName, 1500);
|
||||
display->setLineThreeType(lineThreeMode);
|
||||
display->setMarkLine(markedLine);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void lampUdated() {
|
||||
bool fxChanged = strip.setEffectConfig(effectCurrent, effectSpeed, effectIntensity, effectPalette);
|
||||
|
||||
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
|
||||
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
|
||||
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||
updateInterfaces(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||
}
|
||||
|
||||
void changeBrightness(bool increase) {
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
if (display && display->wakeDisplay()) {
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (increase) {
|
||||
bri = (bri + fadeAmount <= 255) ? (bri + fadeAmount) : 255;
|
||||
}
|
||||
else {
|
||||
bri = (bri - fadeAmount >= 0) ? (bri - fadeAmount) : 0;
|
||||
}
|
||||
lampUdated();
|
||||
}
|
||||
|
||||
void changeEffect(bool increase) {
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
if (display && display->wakeDisplay()) {
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (increase) {
|
||||
effectCurrentIndex = (effectCurrentIndex + 1 >= strip.getModeCount()) ? 0 : (effectCurrentIndex + 1);
|
||||
}
|
||||
else {
|
||||
effectCurrentIndex = (effectCurrentIndex - 1 < 0) ? (strip.getModeCount() - 1) : (effectCurrentIndex - 1);
|
||||
}
|
||||
effectCurrent = modes_alpha_indexes[effectCurrentIndex];
|
||||
lampUdated();
|
||||
}
|
||||
|
||||
void changeEffectSpeed(bool increase) {
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
if (display && display->wakeDisplay()) {
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (increase) {
|
||||
effectSpeed = (effectSpeed + fadeAmount <= 255) ? (effectSpeed + fadeAmount) : 255;
|
||||
}
|
||||
else {
|
||||
effectSpeed = (effectSpeed - fadeAmount >= 0) ? (effectSpeed - fadeAmount) : 0;
|
||||
}
|
||||
lampUdated();
|
||||
}
|
||||
|
||||
void changeEffectIntensity(bool increase) {
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
if (display && display->wakeDisplay()) {
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (increase) {
|
||||
effectIntensity = (effectIntensity + fadeAmount <= 255) ? (effectIntensity + fadeAmount) : 255;
|
||||
}
|
||||
else {
|
||||
effectIntensity = (effectIntensity - fadeAmount >= 0) ? (effectIntensity - fadeAmount) : 0;
|
||||
}
|
||||
lampUdated();
|
||||
}
|
||||
|
||||
void changePalette(bool increase) {
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
if (display && display->wakeDisplay()) {
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (increase) {
|
||||
effectPaletteIndex = (effectPaletteIndex + 1 >= strip.getPaletteCount()) ? 0 : (effectPaletteIndex + 1);
|
||||
}
|
||||
else {
|
||||
effectPaletteIndex = (effectPaletteIndex - 1 < 0) ? (strip.getPaletteCount() - 1) : (effectPaletteIndex - 1);
|
||||
}
|
||||
effectPalette = palettes_alpha_indexes[effectPaletteIndex];
|
||||
lampUdated();
|
||||
}
|
||||
|
||||
/*
|
||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
|
||||
* Below it is shown how this could be used for e.g. a light sensor
|
||||
*/
|
||||
/*
|
||||
void addToJsonInfo(JsonObject& root)
|
||||
{
|
||||
int reading = 20;
|
||||
//this code adds "u":{"Light":[20," lux"]} to the info object
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
JsonArray lightArr = user.createNestedArray("Light"); //name
|
||||
lightArr.add(reading); //value
|
||||
lightArr.add(" lux"); //unit
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void addToJsonState(JsonObject &root)
|
||||
{
|
||||
//root["user0"] = userVar0;
|
||||
}
|
||||
|
||||
/*
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void readFromJsonState(JsonObject &root)
|
||||
{
|
||||
userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
|
||||
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
|
||||
}
|
||||
|
||||
/*
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||
*/
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_ROTARY_ENC_UI;
|
||||
}
|
||||
};
|
@ -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.call = 0;
|
||||
@ -1001,14 +1001,6 @@ uint16_t WS2812FX::mode_running_color(void) {
|
||||
return running(SEGCOLOR(0), SEGCOLOR(1));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Alternating red/green pixels running.
|
||||
*/
|
||||
uint16_t WS2812FX::mode_merry_christmas(void) {
|
||||
return running(RED, GREEN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Alternating red/white pixels running.
|
||||
*/
|
||||
@ -1042,7 +1034,7 @@ uint16_t WS2812FX::mode_running_random(void) {
|
||||
}
|
||||
|
||||
SEGENV.step++;
|
||||
if (SEGENV.step > ((255-SEGMENT.intensity) >> 4))
|
||||
if (SEGENV.step > (uint8_t)((255-SEGMENT.intensity) >> 4))
|
||||
{
|
||||
SEGENV.step = 0;
|
||||
}
|
||||
@ -1265,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);
|
||||
}
|
||||
} 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;
|
||||
for (uint8_t i=0; i <= size; i++) {
|
||||
setPixelColor(idexR+i, color1);
|
||||
@ -1576,9 +1568,9 @@ uint16_t WS2812FX::mode_oscillate(void)
|
||||
|
||||
if (SEGENV.call == 0)
|
||||
{
|
||||
oscillators[0] = {SEGLEN/4, SEGLEN/8, 1, 1};
|
||||
oscillators[1] = {SEGLEN/4*3, SEGLEN/8, 1, 2};
|
||||
oscillators[2] = {SEGLEN/4*2, SEGLEN/8, -1, 1};
|
||||
oscillators[0] = {(int16_t)(SEGLEN/4), (int8_t)(SEGLEN/8), 1, 1};
|
||||
oscillators[1] = {(int16_t)(SEGLEN/4*3), (int8_t)(SEGLEN/8), 1, 2};
|
||||
oscillators[2] = {(int16_t)(SEGLEN/4*2), (int8_t)(SEGLEN/8), -1, 1};
|
||||
}
|
||||
|
||||
uint32_t cycleTime = 20 + (2 * (uint32_t)(255 - SEGMENT.speed));
|
||||
@ -1927,7 +1919,6 @@ uint16_t WS2812FX::mode_noise16_2()
|
||||
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||
|
||||
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
|
||||
|
||||
@ -1991,7 +1982,7 @@ uint16_t WS2812FX::mode_colortwinkle()
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
|
||||
CRGB fastled_col, prev;
|
||||
fract8 fadeUpAmount = 8 + (SEGMENT.speed/4), fadeDownAmount = 5 + (SEGMENT.speed/7);
|
||||
fract8 fadeUpAmount = _brightness>28 ? 8 + (SEGMENT.speed>>2) : 68-_brightness, fadeDownAmount = _brightness>28 ? 8 + (SEGMENT.speed>>3) : 68-_brightness;
|
||||
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||
fastled_col = col_to_crgb(getPixelColor(i));
|
||||
prev = fastled_col;
|
||||
@ -3144,6 +3135,59 @@ uint16_t WS2812FX::mode_drip(void)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Tetris or Stacking (falling bricks) Effect
|
||||
* by Blaz Kristan (https://github.com/blazoncek, https://blaz.at/home)
|
||||
*/
|
||||
typedef struct Tetris {
|
||||
float pos;
|
||||
float speed;
|
||||
uint32_t col;
|
||||
} tetris;
|
||||
|
||||
uint16_t WS2812FX::mode_tetrix(void) {
|
||||
|
||||
uint16_t dataSize = sizeof(tetris);
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
Tetris* drop = reinterpret_cast<Tetris*>(SEGENV.data);
|
||||
|
||||
// initialize dropping on first call or segment full
|
||||
if (SEGENV.call == 0 || SEGENV.aux1 >= SEGLEN) {
|
||||
SEGENV.aux1 = 0; // reset brick stack size
|
||||
SEGENV.step = 0;
|
||||
fill(SEGCOLOR(1));
|
||||
return 250; // short wait
|
||||
}
|
||||
|
||||
if (SEGENV.step == 0) { //init
|
||||
drop->speed = 0.0238 * (SEGMENT.speed ? (SEGMENT.speed>>3)+1 : random8(6,40)); // set speed
|
||||
drop->pos = SEGLEN-1; // start at end of segment
|
||||
drop->col = color_from_palette(random8(0,15)<<4,false,false,0); // limit color choices so there is enough HUE gap
|
||||
SEGENV.step = 1; // drop state (0 init, 1 forming, 2 falling)
|
||||
SEGENV.aux0 = (SEGMENT.intensity ? (SEGMENT.intensity>>5)+1 : random8(1,5)) * (1+(SEGLEN>>6)); // size of brick
|
||||
}
|
||||
|
||||
if (SEGENV.step == 1) { // forming
|
||||
if (random8()>>6) { // random drop
|
||||
SEGENV.step = 2; // fall
|
||||
}
|
||||
}
|
||||
|
||||
if (SEGENV.step > 1) { // falling
|
||||
if (drop->pos > SEGENV.aux1) { // fall until top of stack
|
||||
drop->pos -= drop->speed; // may add gravity as: speed += gravity
|
||||
if (int(drop->pos) < SEGENV.aux1) drop->pos = SEGENV.aux1;
|
||||
for (uint16_t i=int(drop->pos); i<SEGLEN; i++) setPixelColor(i,i<int(drop->pos)+SEGENV.aux0 ? drop->col : SEGCOLOR(1));
|
||||
} else { // we hit bottom
|
||||
SEGENV.step = 0; // go back to init
|
||||
SEGENV.aux1 += SEGENV.aux0; // increase the stack size
|
||||
if (SEGENV.aux1 >= SEGLEN) return 1000; // wait for a second
|
||||
}
|
||||
}
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/ Plasma Effect
|
||||
/ adapted from https://github.com/atuline/FastLED-Demos/blob/master/plasma/plasma.ino
|
||||
@ -3153,8 +3197,8 @@ uint16_t WS2812FX::mode_plasma(void) {
|
||||
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:
|
||||
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.
|
||||
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.
|
||||
uint8_t thisBright = qsub8(colorIndex, beatsin8(6,0, (255 - SEGMENT.intensity)|0x01 ));
|
||||
CRGB color = ColorFromPalette(currentPalette, colorIndex, thisBright, LINEARBLEND);
|
||||
setPixelColor(i, color.red, color.green, color.blue);
|
||||
|
47
wled00/FX.h
47
wled00/FX.h
@ -24,15 +24,11 @@
|
||||
Modified for WLED
|
||||
*/
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
#ifndef WS2812FX_h
|
||||
#define WS2812FX_h
|
||||
|
||||
#ifdef ESP32_MULTISTRIP
|
||||
#include "../usermods/esp32_multistrip/NpbWrapper.h"
|
||||
#else
|
||||
#include "NpbWrapper.h"
|
||||
#endif
|
||||
|
||||
#include "const.h"
|
||||
|
||||
#define FASTLED_INTERNAL //remove annoying pragma messages
|
||||
@ -164,7 +160,7 @@
|
||||
#define FX_MODE_COMET 41
|
||||
#define FX_MODE_FIREWORKS 42
|
||||
#define FX_MODE_RAIN 43
|
||||
#define FX_MODE_MERRY_CHRISTMAS 44
|
||||
#define FX_MODE_TETRIX 44
|
||||
#define FX_MODE_FIRE_FLICKER 45
|
||||
#define FX_MODE_GRADIENT 46
|
||||
#define FX_MODE_LOADING 47
|
||||
@ -501,7 +497,7 @@ class WS2812FX {
|
||||
_mode[FX_MODE_COMET] = &WS2812FX::mode_comet;
|
||||
_mode[FX_MODE_FIREWORKS] = &WS2812FX::mode_fireworks;
|
||||
_mode[FX_MODE_RAIN] = &WS2812FX::mode_rain;
|
||||
_mode[FX_MODE_MERRY_CHRISTMAS] = &WS2812FX::mode_merry_christmas;
|
||||
_mode[FX_MODE_TETRIX] = &WS2812FX::mode_tetrix;
|
||||
_mode[FX_MODE_FIRE_FLICKER] = &WS2812FX::mode_fire_flicker;
|
||||
_mode[FX_MODE_GRADIENT] = &WS2812FX::mode_gradient;
|
||||
_mode[FX_MODE_LOADING] = &WS2812FX::mode_loading;
|
||||
@ -584,12 +580,11 @@ class WS2812FX {
|
||||
ablMilliampsMax = 850;
|
||||
currentMilliamps = 0;
|
||||
timebase = 0;
|
||||
bus = new NeoPixelWrapper();
|
||||
resetSegments();
|
||||
}
|
||||
|
||||
void
|
||||
init(bool supportWhite, uint16_t countPixels, bool skipFirst),
|
||||
finalizeInit(bool supportWhite, uint16_t countPixels, bool skipFirst),
|
||||
service(void),
|
||||
blur(uint8_t),
|
||||
fill(uint32_t),
|
||||
@ -629,6 +624,8 @@ class WS2812FX {
|
||||
paletteFade = 0,
|
||||
paletteBlend = 0,
|
||||
milliampsPerLed = 55,
|
||||
// getStripType(uint8_t strip=0),
|
||||
// setStripType(uint8_t type, uint8_t strip=0),
|
||||
getBrightness(void),
|
||||
getMode(void),
|
||||
getSpeed(void),
|
||||
@ -643,12 +640,19 @@ class WS2812FX {
|
||||
get_random_wheel_index(uint8_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);
|
||||
|
||||
uint16_t
|
||||
ablMilliampsMax,
|
||||
currentMilliamps,
|
||||
triwave16(uint16_t);
|
||||
// setStripLen(uint8_t strip, uint16_t len),
|
||||
// getStripLen(uint8_t strip=0),
|
||||
triwave16(uint16_t),
|
||||
getFps();
|
||||
|
||||
uint32_t
|
||||
now,
|
||||
@ -717,7 +721,7 @@ class WS2812FX {
|
||||
mode_comet(void),
|
||||
mode_fireworks(void),
|
||||
mode_rain(void),
|
||||
mode_merry_christmas(void),
|
||||
mode_tetrix(void),
|
||||
mode_halloween(void),
|
||||
mode_fire_flicker(void),
|
||||
mode_gradient(void),
|
||||
@ -794,8 +798,6 @@ class WS2812FX {
|
||||
mode_dynamic_smooth(void);
|
||||
|
||||
private:
|
||||
NeoPixelWrapper *bus;
|
||||
|
||||
uint32_t crgb_to_col(CRGB fastled);
|
||||
CRGB col_to_crgb(uint32_t);
|
||||
CRGBPalette16 currentPalette;
|
||||
@ -807,11 +809,12 @@ class WS2812FX {
|
||||
uint16_t _usedSegmentData = 0;
|
||||
uint16_t _transitionDur = 750;
|
||||
|
||||
uint16_t _cumulativeFps = 2;
|
||||
|
||||
void load_gradient_palette(uint8_t);
|
||||
void handle_palette(void);
|
||||
|
||||
bool
|
||||
shouldStartBus = false,
|
||||
_useRgbw = false,
|
||||
_skipFirstMode,
|
||||
_triggered;
|
||||
@ -847,7 +850,11 @@ class WS2812FX {
|
||||
|
||||
void
|
||||
blendPixelColor(uint16_t n, uint32_t color, uint8_t blend),
|
||||
startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot);
|
||||
startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot),
|
||||
deserializeMap(void);
|
||||
|
||||
uint16_t* customMappingTable = nullptr;
|
||||
uint16_t customMappingSize = 0;
|
||||
|
||||
uint32_t _lastPaletteChange = 0;
|
||||
uint32_t _lastShow = 0;
|
||||
@ -855,12 +862,6 @@ class WS2812FX {
|
||||
uint32_t _colors_t[3];
|
||||
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_palette_last = 99;
|
||||
segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 24 bytes per element
|
||||
@ -884,7 +885,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([
|
||||
"Scan","Scan Dual","Fade","Theater","Theater Rainbow","Running","Saw","Twinkle","Dissolve","Dissolve Rnd",
|
||||
"Sparkle","Sparkle Dark","Sparkle+","Strobe","Strobe Rainbow","Strobe Mega","Blink Rainbow","Android","Chase","Chase Random",
|
||||
"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Running 2","Aurora","Stream",
|
||||
"Scanner","Lighthouse","Fireworks","Rain","Merry Christmas","Fire Flicker","Gradient","Loading","Police","Police All",
|
||||
"Scanner","Lighthouse","Fireworks","Rain","Tetrix","Fire Flicker","Gradient","Loading","Police","Police All",
|
||||
"Two Dots","Two Areas","Circus","Halloween","Tri Chase","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet",
|
||||
"Scanner Dual","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","Bpm","Fill Noise",
|
||||
"Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Meteor Smooth","Railway","Ripple",
|
||||
|
@ -27,28 +27,28 @@
|
||||
#include "FX.h"
|
||||
#include "palettes.h"
|
||||
|
||||
//enable custom per-LED mapping. This can allow for better effects on matrices or special displays
|
||||
//#define WLED_CUSTOM_LED_MAPPING
|
||||
|
||||
#ifdef WLED_CUSTOM_LED_MAPPING
|
||||
//this is just an example (30 LEDs). It will first set all even, then all uneven LEDs.
|
||||
const uint16_t customMappingTable[] = {
|
||||
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28,
|
||||
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29};
|
||||
|
||||
//another example. Switches direction every 5 LEDs.
|
||||
/*const uint16_t customMappingTable[] = {
|
||||
0, 1, 2, 3, 4, 9, 8, 7, 6, 5, 10, 11, 12, 13, 14,
|
||||
19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25};*/
|
||||
|
||||
const uint16_t customMappingSize = sizeof(customMappingTable)/sizeof(uint16_t); //30 in example
|
||||
#endif
|
||||
|
||||
#ifndef PWM_INDEX
|
||||
#define PWM_INDEX 0
|
||||
#endif
|
||||
|
||||
void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst)
|
||||
/*
|
||||
Custom per-LED mapping has moved!
|
||||
|
||||
Create a file "ledmap.json" using the edit page.
|
||||
|
||||
this is just an example (30 LEDs). It will first set all even, then all uneven LEDs.
|
||||
{"map":[
|
||||
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28,
|
||||
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29]}
|
||||
|
||||
another example. Switches direction every 5 LEDs.
|
||||
{"map":[
|
||||
0, 1, 2, 3, 4, 9, 8, 7, 6, 5, 10, 11, 12, 13, 14,
|
||||
19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25]
|
||||
*/
|
||||
|
||||
//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;
|
||||
RESET_RUNTIME;
|
||||
@ -56,19 +56,36 @@ void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst)
|
||||
_length = countPixels;
|
||||
_skipFirstMode = skipFirst;
|
||||
|
||||
uint8_t ty = 1;
|
||||
if (supportWhite) ty = 2;
|
||||
_lengthRaw = _length;
|
||||
if (_skipFirstMode) {
|
||||
_lengthRaw += LED_SKIP_AMOUNT;
|
||||
}
|
||||
|
||||
bus->Begin((NeoPixelType)ty, _lengthRaw);
|
||||
//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();
|
||||
|
||||
//make segment 0 cover the entire strip
|
||||
_segments[0].start = 0;
|
||||
_segments[0].stop = _length;
|
||||
|
||||
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() {
|
||||
@ -167,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;
|
||||
if (SEGLEN) {//from segment
|
||||
|
||||
//color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments)
|
||||
if (_bri_t < 255) {
|
||||
col.R = scale8(col.R, _bri_t);
|
||||
col.G = scale8(col.G, _bri_t);
|
||||
col.B = scale8(col.B, _bri_t);
|
||||
col.W = scale8(col.W, _bri_t);
|
||||
r = scale8(r, _bri_t);
|
||||
g = scale8(g, _bri_t);
|
||||
b = scale8(b, _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 */
|
||||
bool reversed = reverseMode ^ IS_REVERSE;
|
||||
@ -189,30 +204,28 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
int16_t indexSet = realIndex + (reversed ? -j : j);
|
||||
int16_t indexSetRev = indexSet;
|
||||
if (reverseMode) indexSetRev = REV(indexSet);
|
||||
#ifdef WLED_CUSTOM_LED_MAPPING
|
||||
if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet];
|
||||
#endif
|
||||
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 (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 {
|
||||
bus->SetPixelColor(SEGMENT.stop - indexSet + skip + SEGMENT.start - 1, col);
|
||||
busses.setPixelColor(SEGMENT.stop - indexSet + skip + SEGMENT.start - 1, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { //live data, etc.
|
||||
if (reverseMode) i = REV(i);
|
||||
#ifdef WLED_CUSTOM_LED_MAPPING
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
#endif
|
||||
bus->SetPixelColor(i + skip, col);
|
||||
|
||||
uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b));
|
||||
busses.setPixelColor(i + skip, col);
|
||||
}
|
||||
if (skip && i == 0) {
|
||||
for (uint16_t j = 0; j < skip; j++) {
|
||||
bus->SetPixelColor(j, RgbwColor(0, 0, 0, 0));
|
||||
busses.setPixelColor(j, BLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -263,7 +276,7 @@ void WS2812FX::show(void) {
|
||||
|
||||
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)
|
||||
{
|
||||
@ -292,25 +305,30 @@ void WS2812FX::show(void) {
|
||||
uint16_t scaleI = scale * 255;
|
||||
uint8_t scaleB = (scaleI > 255) ? 255 : scaleI;
|
||||
uint8_t newBri = scale8(_brightness, scaleB);
|
||||
bus->SetBrightness(newBri);
|
||||
busses.setBrightness(newBri);
|
||||
currentMilliamps = (powerSum0 * newBri) / puPerMilliamp;
|
||||
} else
|
||||
{
|
||||
currentMilliamps = powerSum / puPerMilliamp;
|
||||
bus->SetBrightness(_brightness);
|
||||
busses.setBrightness(_brightness);
|
||||
}
|
||||
currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate
|
||||
currentMilliamps += _length; //add standby power back to estimate
|
||||
} else {
|
||||
currentMilliamps = 0;
|
||||
bus->SetBrightness(_brightness);
|
||||
busses.setBrightness(_brightness);
|
||||
}
|
||||
|
||||
// some buses send asynchronously and this method will return before
|
||||
// all of the data has been sent.
|
||||
// See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods
|
||||
bus->Show();
|
||||
_lastShow = millis();
|
||||
busses.show();
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -318,7 +336,16 @@ void WS2812FX::show(void) {
|
||||
* On some hardware (ESP32), strip updates are done asynchronously.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -354,7 +381,6 @@ uint8_t WS2812FX::getPaletteCount()
|
||||
|
||||
|
||||
bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t p) {
|
||||
uint8_t mainSeg = getMainSegmentId();
|
||||
Segment& seg = _segments[getMainSegmentId()];
|
||||
uint8_t modePrev = seg.mode, speedPrev = seg.speed, intensityPrev = seg.intensity, palettePrev = seg.palette;
|
||||
|
||||
@ -420,17 +446,6 @@ void WS2812FX::setBrightness(uint8_t b) {
|
||||
{
|
||||
_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
|
||||
}
|
||||
@ -482,15 +497,13 @@ uint32_t WS2812FX::getPixelColor(uint16_t i)
|
||||
{
|
||||
i = realPixelIndex(i);
|
||||
|
||||
#ifdef WLED_CUSTOM_LED_MAPPING
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
#endif
|
||||
|
||||
if (_skipFirstMode) i += LED_SKIP_AMOUNT;
|
||||
|
||||
if (i >= _lengthRaw) return 0;
|
||||
|
||||
return bus->GetPixelColorRgbw(i);
|
||||
return busses.getPixelColor(i);
|
||||
}
|
||||
|
||||
WS2812FX::Segment& WS2812FX::getSegment(uint8_t id) {
|
||||
@ -510,12 +523,13 @@ uint32_t WS2812FX::getLastShow(void) {
|
||||
return _lastShow;
|
||||
}
|
||||
|
||||
//TODO these need to be on a per-strip basis
|
||||
uint8_t WS2812FX::getColorOrder(void) {
|
||||
return bus->GetColorOrder();
|
||||
return COL_ORDER_GRB;
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -967,44 +981,31 @@ bool WS2812FX::segmentsAreIdentical(Segment* a, Segment* b)
|
||||
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;
|
||||
//load custom mapping table from JSON file
|
||||
void WS2812FX::deserializeMap(void) {
|
||||
if (!WLED_FS.exists("/ledmap.json")) return;
|
||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE); // full sized buffer for larger maps
|
||||
|
||||
RgbwColor c;
|
||||
uint32_t col = bus->GetPixelColorRgbw(PWM_INDEX);
|
||||
c.R = col >> 16; c.G = col >> 8; c.B = col; c.W = col >> 24;
|
||||
DEBUG_PRINTLN(F("Reading LED map from /ledmap.json..."));
|
||||
|
||||
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);
|
||||
if (!readObjectFromFile("/ledmap.json", nullptr, &doc)) return; //if file does not exist just exit
|
||||
|
||||
if (customMappingTable != nullptr) {
|
||||
delete[] customMappingTable;
|
||||
customMappingTable = nullptr;
|
||||
customMappingSize = 0;
|
||||
}
|
||||
|
||||
JsonArray map = doc[F("map")];
|
||||
if (!map.isNull() && map.size()) { // not an empty map
|
||||
customMappingSize = map.size();
|
||||
customMappingTable = new uint16_t[customMappingSize];
|
||||
for (uint16_t i=0; i<customMappingSize; i++) {
|
||||
customMappingTable[i] = (uint16_t) map[i];
|
||||
}
|
||||
#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
|
||||
|
||||
//gamma 2.8 lookup table used for color correction
|
||||
byte gammaT[] = {
|
||||
|
@ -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
404
wled00/bus_manager.h
Normal 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
882
wled00/bus_wrapper.h
Normal 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
|
@ -17,9 +17,7 @@ void shortPressAction()
|
||||
|
||||
bool isButtonPressed()
|
||||
{
|
||||
#if defined(BTNPIN) && BTNPIN > -1
|
||||
if (digitalRead(BTNPIN) == LOW) return true;
|
||||
#endif
|
||||
if (btnPin>=0 && digitalRead(btnPin) == LOW) return true;
|
||||
#ifdef TOUCHPIN
|
||||
if (touchRead(TOUCHPIN) <= TOUCH_THRESHOLD) return true;
|
||||
#endif
|
||||
@ -29,8 +27,7 @@ bool isButtonPressed()
|
||||
|
||||
void handleButton()
|
||||
{
|
||||
#if (defined(BTNPIN) && BTNPIN > -1) || defined(TOUCHPIN)
|
||||
if (!buttonEnabled) return;
|
||||
if (btnPin<0 || !buttonEnabled) return;
|
||||
|
||||
if (isButtonPressed()) //pressed
|
||||
{
|
||||
@ -75,7 +72,6 @@ void handleButton()
|
||||
buttonWaitTime = 0;
|
||||
shortPressAction();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void handleIO()
|
||||
@ -88,37 +84,39 @@ void handleIO()
|
||||
lastOnTime = millis();
|
||||
if (offMode)
|
||||
{
|
||||
#if RLYPIN >= 0
|
||||
digitalWrite(RLYPIN, RLYMDE);
|
||||
#endif
|
||||
if (rlyPin>=0) {
|
||||
pinMode(rlyPin, OUTPUT);
|
||||
digitalWrite(rlyPin, rlyMde);
|
||||
}
|
||||
offMode = false;
|
||||
}
|
||||
} else if (millis() - lastOnTime > 600)
|
||||
{
|
||||
if (!offMode) {
|
||||
#if LEDPIN == LED_BUILTIN
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
if (!offMode) {
|
||||
#ifdef ESP8266
|
||||
//turn off built-in LED if strip is turned off
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
#if RLYPIN >= 0
|
||||
digitalWrite(RLYPIN, !RLYMDE);
|
||||
#endif
|
||||
}
|
||||
if (rlyPin>=0) {
|
||||
pinMode(rlyPin, OUTPUT);
|
||||
digitalWrite(rlyPin, !rlyMde);
|
||||
}
|
||||
}
|
||||
offMode = true;
|
||||
}
|
||||
|
||||
#if AUXPIN >= 0
|
||||
//output
|
||||
if (auxActive || auxActiveBefore)
|
||||
if (auxPin>=1 && (auxActive || auxActiveBefore))
|
||||
{
|
||||
if (!auxActiveBefore)
|
||||
{
|
||||
auxActiveBefore = true;
|
||||
switch (auxTriggeredState)
|
||||
{
|
||||
case 0: pinMode(AUXPIN, INPUT); break;
|
||||
case 1: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, HIGH); break;
|
||||
case 2: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, LOW); break;
|
||||
case 0: pinMode(auxPin, INPUT); break;
|
||||
case 1: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, HIGH); break;
|
||||
case 2: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, LOW); break;
|
||||
}
|
||||
auxStartTime = millis();
|
||||
}
|
||||
@ -128,11 +126,10 @@ void handleIO()
|
||||
auxActiveBefore = false;
|
||||
switch (auxDefaultState)
|
||||
{
|
||||
case 0: pinMode(AUXPIN, INPUT); break;
|
||||
case 1: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, HIGH); break;
|
||||
case 2: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, LOW); break;
|
||||
case 0: pinMode(auxPin, INPUT); break;
|
||||
case 1: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, HIGH); break;
|
||||
case 2: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, LOW); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
174
wled00/cfg.cpp
174
wled00/cfg.cpp
@ -30,10 +30,8 @@ void deserializeConfig() {
|
||||
return;
|
||||
}
|
||||
|
||||
//deserializeJson(doc, json);
|
||||
|
||||
//int rev_major = doc[F("rev")][0]; // 1
|
||||
//int rev_minor = doc[F("rev")][1]; // 0
|
||||
//int rev_major = doc["rev"][0]; // 1
|
||||
//int rev_minor = doc["rev"][1]; // 0
|
||||
|
||||
//long vid = doc[F("vid")]; // 2010020
|
||||
|
||||
@ -89,31 +87,64 @@ void deserializeConfig() {
|
||||
|
||||
JsonObject hw = doc[F("hw")];
|
||||
|
||||
// initialize LED pins and lengths prior to other HW
|
||||
JsonObject hw_led = hw[F("led")];
|
||||
|
||||
CJSON(ledCount, hw_led[F("total")]);
|
||||
if (ledCount > MAX_LEDS) ledCount = MAX_LEDS;
|
||||
|
||||
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
|
||||
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]);
|
||||
CJSON(strip.reverseMode, hw_led[F("rev")]);
|
||||
CJSON(strip.reverseMode, hw_led["rev"]);
|
||||
CJSON(strip.rgbwMode, hw_led[F("rgbwm")]);
|
||||
|
||||
JsonObject hw_led_ins_0 = hw_led[F("ins")][0];
|
||||
//bool hw_led_ins_0_en = hw_led_ins_0[F("en")]; // true
|
||||
//int hw_led_ins_0_start = hw_led_ins_0[F("start")]; // 0
|
||||
//int hw_led_ins_0_len = hw_led_ins_0[F("len")]; // 1200
|
||||
JsonArray ins = hw_led["ins"];
|
||||
uint8_t s = 0; //bus iterator
|
||||
useRGBW = false;
|
||||
busses.removeAll();
|
||||
uint32_t mem = 0;
|
||||
for (JsonObject elm : ins) {
|
||||
if (s >= WLED_MAX_BUSSES) break;
|
||||
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
||||
JsonArray pinArr = elm[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
|
||||
|
||||
strip.setColorOrder(hw_led_ins_0[F("order")]);
|
||||
//bool hw_led_ins_0_rev = hw_led_ins_0[F("rev")]; // false
|
||||
skipFirstLed = hw_led_ins_0[F("skip")]; // 0
|
||||
useRGBW = (hw_led_ins_0[F("type")] == TYPE_SK6812_RGBW);
|
||||
uint16_t length = elm[F("len")];
|
||||
if (length==0) continue;
|
||||
uint8_t colorOrder = (int)elm[F("order")];
|
||||
//only use skip from the first strip (this shouldn't have been in ins obj. but remains here for compatibility)
|
||||
if (s==0) skipFirstLed = elm[F("skip")];
|
||||
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[F("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];
|
||||
buttonEnabled = hw_btn_ins_0[F("en")] | buttonEnabled;
|
||||
|
||||
//int hw_btn_ins_0_pin_0 = hw_btn_ins_0[F("pin")][0]; // 0
|
||||
CJSON(buttonEnabled, hw_btn_ins_0[F("type")]);
|
||||
int hw_btn_pin = hw_btn_ins_0[F("pin")][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")];
|
||||
CJSON(macroButton, hw_btn_ins_0_macros[0]);
|
||||
@ -122,11 +153,28 @@ void deserializeConfig() {
|
||||
|
||||
//int hw_btn_ins_0_type = hw_btn_ins_0[F("type")]; // 0
|
||||
|
||||
//int hw_ir_pin = hw[F("ir")][F("pin")]; // 4
|
||||
CJSON(irEnabled, hw[F("ir")][F("type")]); // 0
|
||||
#ifndef WLED_DISABLE_INFRARED
|
||||
int hw_ir_pin = hw[F("ir")][F("pin")]; // 4
|
||||
if (pinManager.allocatePin(hw_ir_pin,false)) {
|
||||
irPin = hw_ir_pin;
|
||||
} else {
|
||||
irPin = -1;
|
||||
}
|
||||
#endif
|
||||
CJSON(irEnabled, hw[F("ir")][F("type")]);
|
||||
|
||||
//int hw_relay_pin = hw[F("relay")][F("pin")]; // 12
|
||||
//bool hw_relay_rev = hw[F("relay")][F("rev")]; // false
|
||||
JsonObject relay = hw[F("relay")];
|
||||
|
||||
int hw_relay_pin = relay[F("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
|
||||
|
||||
@ -399,75 +447,61 @@ void serializeConfig() {
|
||||
hw_led[F("total")] = ledCount;
|
||||
hw_led[F("maxpwr")] = strip.ablMilliampsMax;
|
||||
hw_led[F("ledma")] = strip.milliampsPerLed;
|
||||
hw_led[F("rev")] = strip.reverseMode;
|
||||
hw_led["rev"] = strip.reverseMode;
|
||||
hw_led[F("rgbwm")] = strip.rgbwMode;
|
||||
|
||||
JsonArray hw_led_ins = hw_led.createNestedArray("ins");
|
||||
|
||||
JsonObject hw_led_ins_0 = hw_led_ins.createNestedObject();
|
||||
hw_led_ins_0[F("en")] = true;
|
||||
hw_led_ins_0[F("start")] = 0;
|
||||
hw_led_ins_0[F("len")] = ledCount;
|
||||
JsonArray hw_led_ins_0_pin = hw_led_ins_0.createNestedArray("pin");
|
||||
hw_led_ins_0_pin.add(LEDPIN);
|
||||
#ifdef DATAPIN
|
||||
hw_led_ins_0_pin.add(DATAPIN);
|
||||
#endif
|
||||
hw_led_ins_0[F("order")] = strip.getColorOrder();
|
||||
hw_led_ins_0[F("rev")] = false;
|
||||
hw_led_ins_0[F("skip")] = skipFirstLed ? 1 : 0;
|
||||
|
||||
//this is very crude and temporary
|
||||
byte ledType = TYPE_WS2812_RGB;
|
||||
if (useRGBW) ledType = TYPE_SK6812_RGBW;
|
||||
#ifdef USE_WS2801
|
||||
ledType = TYPE_WS2801;
|
||||
#endif
|
||||
#ifdef USE_APA102
|
||||
ledType = TYPE_APA102;
|
||||
#endif
|
||||
#ifdef USE_LPD8806
|
||||
ledType = TYPE_LPD8806;
|
||||
#endif
|
||||
#ifdef USE_P9813
|
||||
ledType = TYPE_P9813;
|
||||
#endif
|
||||
#ifdef USE_TM1814
|
||||
ledType = TYPE_TM1814;
|
||||
#endif
|
||||
|
||||
hw_led_ins_0[F("type")] = ledType;
|
||||
for (uint8_t s = 0; s < busses.getNumBusses(); s++) {
|
||||
Bus *bus = busses.getBus(s);
|
||||
if (!bus || bus->getLength()==0) break;
|
||||
JsonObject ins = hw_led_ins.createNestedObject();
|
||||
ins[F("en")] = true;
|
||||
ins[F("start")] = bus->getStart();
|
||||
ins[F("len")] = bus->getLength();
|
||||
JsonArray ins_pin = ins.createNestedArray("pin");
|
||||
uint8_t pins[5];
|
||||
uint8_t nPins = bus->getPins(pins);
|
||||
for (uint8_t i = 0; i < nPins; i++) ins_pin.add(pins[i]);
|
||||
ins[F("order")] = bus->getColorOrder();
|
||||
ins["rev"] = bus->reversed;
|
||||
ins[F("skip")] = (skipFirstLed && s == 0) ? 1 : 0;
|
||||
ins[F("type")] = bus->getType();
|
||||
}
|
||||
|
||||
JsonObject hw_btn = hw.createNestedObject("btn");
|
||||
|
||||
JsonArray hw_btn_ins = hw_btn.createNestedArray("ins");
|
||||
|
||||
#if defined(BTNPIN) && BTNPIN > -1
|
||||
// button BTNPIN
|
||||
JsonObject hw_btn_ins_0 = hw_btn_ins.createNestedObject();
|
||||
hw_btn_ins_0[F("type")] = (buttonEnabled) ? BTN_TYPE_PUSH : BTN_TYPE_NONE;
|
||||
|
||||
JsonArray hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin");
|
||||
hw_btn_ins_0_pin.add(BTNPIN);
|
||||
hw_btn_ins_0_pin.add(btnPin);
|
||||
|
||||
JsonArray hw_btn_ins_0_macros = hw_btn_ins_0.createNestedArray("macros");
|
||||
hw_btn_ins_0_macros.add(macroButton);
|
||||
hw_btn_ins_0_macros.add(macroLongPress);
|
||||
hw_btn_ins_0_macros.add(macroDoublePress);
|
||||
|
||||
#ifndef WLED_DISABLE_INFRARED
|
||||
if (irPin>=0) {
|
||||
JsonObject hw_ir = hw.createNestedObject("ir");
|
||||
hw_ir[F("pin")] = irPin;
|
||||
hw_ir[F("type")] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled )
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(IRPIN) && IRPIN > -1
|
||||
JsonObject hw_ir = hw.createNestedObject("ir");
|
||||
hw_ir[F("pin")] = IRPIN;
|
||||
hw_ir[F("type")] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled )
|
||||
#endif
|
||||
|
||||
#if defined(RLYPIN) && RLYPIN > -1
|
||||
JsonObject hw_relay = hw.createNestedObject("relay");
|
||||
hw_relay[F("pin")] = RLYPIN;
|
||||
hw_relay[F("rev")] = (RLYMDE) ? false : true;
|
||||
JsonObject hw_status = hw.createNestedObject("status");
|
||||
hw_status[F("pin")] = -1;
|
||||
#endif
|
||||
hw_relay[F("pin")] = rlyPin;
|
||||
hw_relay["rev"] = !rlyMde;
|
||||
|
||||
//JsonObject hw_status = hw.createNestedObject("status");
|
||||
//hw_status[F("pin")] = -1;
|
||||
|
||||
JsonObject hw_aux = hw.createNestedObject("aux");
|
||||
hw_aux[F("pin")] = auxPin;
|
||||
|
||||
JsonObject light = doc.createNestedObject("light");
|
||||
light[F("scale-bri")] = briMultiplier;
|
||||
|
@ -13,6 +13,12 @@
|
||||
//increase if you need more
|
||||
#define WLED_MAX_USERMODS 4
|
||||
|
||||
#ifdef ESP8266
|
||||
#define WLED_MAX_BUSSES 3
|
||||
#else
|
||||
#define WLED_MAX_BUSSES 10
|
||||
#endif
|
||||
|
||||
//Usermod IDs
|
||||
#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
|
||||
@ -21,6 +27,11 @@
|
||||
#define USERMOD_ID_FIXNETSERVICES 4 //Usermod "usermod_Fix_unreachable_netservices.h"
|
||||
#define USERMOD_ID_PIRSWITCH 5 //Usermod "usermod_PIR_sensor_switch.h"
|
||||
#define USERMOD_ID_IMU 6 //Usermod "usermod_mpu6050_imu.h"
|
||||
#define USERMOD_ID_FOUR_LINE_DISP 7 //Usermod "usermod_v2_four_line_display.h
|
||||
#define USERMOD_ID_ROTARY_ENC_UI 8 //Usermod "usermod_v2_rotary_encoder_ui.h"
|
||||
#define USERMOD_ID_AUTO_SAVE 9 //Usermod "usermod_v2_auto_save.h"
|
||||
#define USERMOD_ID_DHT 10 //Usermod "usermod_dht.h"
|
||||
#define USERMOD_ID_MODE_SORT 11 //Usermod "usermod_v2_mode_sort.h"
|
||||
|
||||
//Access point behavior
|
||||
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
||||
@ -90,6 +101,7 @@
|
||||
#define TYPE_GS8608 23 //same driver as WS2812, but will require signal 2x per second (else displays test pattern)
|
||||
#define TYPE_WS2811_400KHZ 24 //half-speed WS2812 protocol, used by very old WS2811 units
|
||||
#define TYPE_SK6812_RGBW 30
|
||||
#define TYPE_TM1814 31
|
||||
//"Analog" types (PWM) (32-47)
|
||||
#define TYPE_ONOFF 40 //binary output (relays etc.)
|
||||
#define TYPE_ANALOG_1CH 41 //single channel PWM. Uses value of brightest RGBW channel
|
||||
@ -102,8 +114,11 @@
|
||||
#define TYPE_APA102 51
|
||||
#define TYPE_LPD8806 52
|
||||
#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
|
||||
#define COL_ORDER_GRB 0 //GRB(w),defaut
|
||||
@ -123,9 +138,13 @@
|
||||
#define BTN_TYPE_SWITCH_ACT_HIGH 5 //not implemented
|
||||
|
||||
//Ethernet board types
|
||||
#define WLED_NUM_ETH_TYPES 5
|
||||
|
||||
#define WLED_ETH_NONE 0
|
||||
#define WLED_ETH_WT32_ETH01 1
|
||||
#define WLED_ETH_ESP32_POE 2
|
||||
#define WLED_ETH_WESP32 3
|
||||
#define WLED_ETH_QUINLED 4
|
||||
|
||||
//Hue error codes
|
||||
#define HUE_ERROR_INACTIVE 0
|
||||
@ -153,6 +172,9 @@
|
||||
#define ERR_FS_QUOTA 11 // The FS is full or the maximum file size is reached
|
||||
#define ERR_FS_PLOAD 12 // It was attempted to load a preset that does not exist
|
||||
#define ERR_FS_GENERAL 19 // A general unspecified filesystem error occured
|
||||
#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
|
||||
#define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness
|
||||
@ -165,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
|
||||
#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
|
||||
|
||||
#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)
|
||||
#define OMAX 2048
|
||||
|
||||
#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
|
||||
|
||||
@ -194,4 +238,9 @@
|
||||
#define WLED_MAX_NODES 150
|
||||
#endif
|
||||
|
||||
//this is merely a default now and can be changed at runtime
|
||||
#ifndef LEDPIN
|
||||
#define LEDPIN 2
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -465,7 +465,7 @@ function populateInfo(i)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
cn += `v${i.ver} "${vcn}"<br><br><table class="infot">
|
||||
@ -474,7 +474,8 @@ function populateInfo(i)
|
||||
${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")}
|
||||
${inforow("Uptime",getRuntimeStr(i.uptime))}
|
||||
${inforow("Free heap",heap," kB")}
|
||||
${inforow("Estimated current",pwru)}
|
||||
${inforow("Estimated current",pwru)}
|
||||
${inforow("Frames / second",i.leds.fps)}
|
||||
${inforow("MAC address",i.mac)}
|
||||
${inforow("Filesystem",i.fs.u + "/" + i.fs.t + " kB (" +Math.round(i.fs.u*100/i.fs.t) + "%)")}
|
||||
${inforow("Environment",i.arch + " " + i.core + " (" + i.lwip + ")")}
|
||||
|
62
wled00/data/liveviewws.htm
Normal file
62
wled00/data/liveviewws.htm
Normal 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>
|
@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=500">
|
||||
<title>LED Settings</title>
|
||||
<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()
|
||||
{
|
||||
window.open("https://github.com/Aircoookie/WLED/wiki/Settings#led-settings");
|
||||
@ -13,7 +13,31 @@
|
||||
function B()
|
||||
{
|
||||
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 enABL()
|
||||
{
|
||||
@ -42,23 +66,97 @@
|
||||
case 255: d.Sf.LAsel.value = 255; break;
|
||||
default: d.getElementById('LAdis').style.display = 'inline';
|
||||
}
|
||||
d.getElementById('m1').innerHTML = maxM;
|
||||
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()
|
||||
{
|
||||
var myC = d.querySelectorAll('.wc'),
|
||||
l = myC.length;
|
||||
for (i = 0; i < l; i++) {
|
||||
myC[i].style.display = (d.getElementById('rgbw').checked) ? 'inline':'none';
|
||||
}
|
||||
var isRGBW = false, memu = 0;
|
||||
|
||||
d.getElementById('ledwarning').style.display = (d.Sf.LC.value > 1000) ? 'inline':'none';
|
||||
d.getElementById('ampwarning').style.display = (d.Sf.MA.value > 7200) ? 'inline':'none';
|
||||
|
||||
if (d.Sf.LA.value == 255) laprev = 12;
|
||||
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
|
||||
|
||||
var val = Math.ceil((100 + d.Sf.LC.value * laprev)/500)/2;
|
||||
if (d.Sf.LA.value == 255) laprev = 12;
|
||||
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
|
||||
|
||||
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;
|
||||
var s = "";
|
||||
var is12V = (d.Sf.LAsel.value == 30);
|
||||
@ -72,18 +170,85 @@
|
||||
s += val;
|
||||
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;
|
||||
var s2 = "(for most effects, ~";
|
||||
s2 += val2;
|
||||
s2 += "A is enough)<br>";
|
||||
d.getElementById('psu').innerHTML = s;
|
||||
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>
|
||||
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 />
|
||||
<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()
|
||||
{
|
||||
//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>
|
||||
<style>
|
||||
@import url("style.css");
|
||||
@ -92,62 +257,51 @@
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
<h2>LED setup</h2>
|
||||
LED count: <input name="LC" type="number" min="1" max="1500" oninput="UI()" required><br>
|
||||
<div id="ledwarning" style="color: orange; display: none;">
|
||||
⚠ 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>
|
||||
<b><span id="psu">?</span></b><br>
|
||||
<span id="psu2"><br></span>
|
||||
<br>
|
||||
Enable automatic brightness limiter: <input type="checkbox" name="ABen" onchange="enABL()" id="able"><br>
|
||||
<div id="abl">
|
||||
Maximum Current: <input name="MA" type="number" min="250" max="65000" oninput="UI()" required> mA<br>
|
||||
<div id="ampwarning" style="color: orange; display: none;">
|
||||
⚠ Your power supply provides high current.<br>
|
||||
To improve the safety of your setup,<br>
|
||||
please use thick cables,<br>
|
||||
multiple power injection points and a fuse!<br>
|
||||
</div>
|
||||
<i>Automatically limits brightness to stay close to the limit.<br>
|
||||
Keep at <1A if powering LEDs directly from the ESP 5V pin!<br>
|
||||
If you are using an external power supply, enter its rating.<br>
|
||||
(Current estimated usage: <span class="pow">unknown</span>)</i><br><br>
|
||||
LED voltage (Max. current for a single LED):<br>
|
||||
<select name="LAsel" onchange="enLA()">
|
||||
<option value="55" selected>5V default (55mA)</option>
|
||||
<option value="35">5V efficient (35mA)</option>
|
||||
<option value="30">12V (30mA)</option>
|
||||
<option value="255">WS2815 (12mA)</option>
|
||||
<option value="50">Custom</option>
|
||||
</select><br>
|
||||
<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>
|
||||
<button type="button" onclick="B()">Back</button><button type="button" onclick="trySubmit()">Save</button><hr>
|
||||
<h2>LED & Hardware setup</h2>
|
||||
Total LED count: <input name="LC" type="number" min="1" max="8192" oninput="UI()" required><br>
|
||||
<i>Recommended power supply for brightest white:</i><br>
|
||||
<b><span id="psu">?</span></b><br>
|
||||
<span id="psu2"><br></span>
|
||||
<br>
|
||||
Enable automatic brightness limiter: <input type="checkbox" name="ABen" onchange="enABL()" id="able"><br>
|
||||
<div id="abl">
|
||||
Maximum Current: <input name="MA" type="number" min="250" max="65000" oninput="UI()" required> mA<br>
|
||||
<div id="ampwarning" style="color: orange; display: none;">
|
||||
⚠ Your power supply provides high current.<br>
|
||||
To improve the safety of your setup,<br>
|
||||
please use thick cables,<br>
|
||||
multiple power injection points and a fuse!<br>
|
||||
</div>
|
||||
<br>
|
||||
LEDs are 4-channel type (RGBW): <input type="checkbox" name="EW" onchange=UI() id="rgbw"><br>
|
||||
<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>
|
||||
Color order:
|
||||
<select name="CO">
|
||||
<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>
|
||||
<i>Automatically limits brightness to stay close to the limit.<br>
|
||||
Keep at <1A if powering LEDs directly from the ESP 5V pin!<br>
|
||||
If you are using an external power supply, enter its rating.<br>
|
||||
(Current estimated usage: <span class="pow">unknown</span>)</i><br><br>
|
||||
LED voltage (Max. current for a single LED):<br>
|
||||
<select name="LAsel" onchange="enLA()">
|
||||
<option value="55" selected>5V default (55mA)</option>
|
||||
<option value="35">5V efficient (35mA)</option>
|
||||
<option value="30">12V (30mA)</option>
|
||||
<option value="255">WS2815 (12mA)</option>
|
||||
<option value="50">Custom</option>
|
||||
</select><br>
|
||||
<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>
|
||||
</div>
|
||||
<h3>Hardware setup</h3>
|
||||
<div id="mLC">LED outputs:</div>
|
||||
<button type="button" id="+" onclick="addLEDs(1)" style="display:none;border-radius:20px;height:36px;">+</button>
|
||||
<button type="button" id="-" onclick="addLEDs(-1)" style="display:none;border-radius:20px;width:36px;height:36px;">-</button><br>
|
||||
LED Memory Usage: <span id="m0">0</span> / <span id="m1">?</span> B<br>
|
||||
<div id="dbar" style="display:inline-block; width: 100px; height: 10px; border-radius: 20px;"></div><br>
|
||||
<div id="ledwarning" style="color: orange; display: none;">
|
||||
⚠ You might run into stability or lag issues.<br>
|
||||
Use less than <span id="wreason">800 LEDs per pin</span> for the best experience!<br>
|
||||
</div><br>
|
||||
Relay pin: <input type="number" min="-1" max="40" name="RL" onchange="UI()"> Active high <input type="checkbox" name="RM"><br>
|
||||
Button pin: <input type="number" min="-1" max="40" name="BT" onchange="UI()"><br>
|
||||
IR pin: <input type="number" min="-1" max="40" name="IR" onchange="UI()"><br>
|
||||
AUX pin: <input type="number" min="-1" max="40" name="AX" onchange="UI()">
|
||||
<h3>Defaults</h3>
|
||||
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>
|
||||
@ -171,7 +325,7 @@
|
||||
<option value="2">Fade Color</option>
|
||||
<option value="3">Sunrise</option>
|
||||
</select>
|
||||
<h3>Advanced</h3>
|
||||
<h3>Advanced</h3>
|
||||
Palette blending:
|
||||
<select name="PB">
|
||||
<option value="0">Linear (wrap if moving)</option>
|
||||
@ -180,8 +334,18 @@
|
||||
<option value="3">None (not recommended)</option>
|
||||
</select><br>
|
||||
Reverse LED order (rotate 180): <input type="checkbox" name="RV"><br>
|
||||
Skip first LED: <input type="checkbox" name="SL"><hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||
Skip first LED: <input type="checkbox" name="SL"><br>
|
||||
<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>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -68,8 +68,11 @@
|
||||
<h3>Ethernet Type</h3>
|
||||
<select name="ETH">
|
||||
<option value="0">None</option>
|
||||
<option value="2">ESP32-POE</option>
|
||||
<option value="4">QuinLED-ESP32</option>
|
||||
<option value="3">WESP32</option>
|
||||
<option value="1">WT32-ETH01</option>
|
||||
<option value="2">ESP32-POE</option></select><br><br></div>
|
||||
</select><br><br></div>
|
||||
<hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button>
|
||||
</form>
|
||||
|
@ -35,7 +35,8 @@ void handleDDPPacket(e131_packet_t* p) {
|
||||
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP);
|
||||
|
||||
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;
|
||||
@ -187,11 +188,13 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
||||
uint16_t ledsTotal = previousLeds + (dmxChannels - dmxOffset +1) / dmxChannelsPerLed;
|
||||
if (!is4Chan) {
|
||||
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 {
|
||||
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;
|
||||
|
@ -76,7 +76,6 @@ bool decodeIRCustom(uint32_t code);
|
||||
void applyRepeatActions();
|
||||
void relativeChange(byte* property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF);
|
||||
void changeEffectSpeed(int8_t amount);
|
||||
void changeBrightness(int8_t amount);
|
||||
void changeEffectIntensity(int8_t amount);
|
||||
void decodeIR(uint32_t code);
|
||||
void decodeIR24(uint32_t code);
|
||||
@ -149,22 +148,6 @@ void setCronixie();
|
||||
void _overlayCronixie();
|
||||
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
|
||||
void loadPlaylist(JsonObject playlistObject);
|
||||
void handlePlaylist();
|
||||
@ -223,6 +206,7 @@ class UsermodManager {
|
||||
void readFromConfig(JsonObject& obj);
|
||||
|
||||
bool add(Usermod* um);
|
||||
Usermod* lookup(uint16_t mod_id);
|
||||
byte getModCount();
|
||||
};
|
||||
|
||||
|
@ -33,8 +33,10 @@ File f;
|
||||
|
||||
//wrapper to find out how long closing takes
|
||||
void closeFile() {
|
||||
DEBUGFS_PRINT(F("Close -> "));
|
||||
uint32_t s = millis();
|
||||
#ifdef WLED_DEBUG_FS
|
||||
DEBUGFS_PRINT(F("Close -> "));
|
||||
uint32_t s = millis();
|
||||
#endif
|
||||
f.close();
|
||||
DEBUGFS_PRINTF("took %d ms\n", millis() - s);
|
||||
doCloseFile = false;
|
||||
@ -53,7 +55,6 @@ bool bufferedFind(const char *target, bool fromStart = true) {
|
||||
size_t targetLen = strlen(target);
|
||||
|
||||
size_t index = 0;
|
||||
byte c;
|
||||
uint16_t bufsize = 0, count = 0;
|
||||
byte buf[FS_BUFSIZE];
|
||||
if (fromStart) f.seek(0);
|
||||
|
@ -42,7 +42,7 @@ function B(){window.history.back()}function U(){document.getElementById("uf").st
|
||||
.bt{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}input[type=file]{font-size:16px}body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%}#msg{display:none}
|
||||
</style></head><body><h2>WLED Software Update</h2><form method="POST"
|
||||
action="/update" id="uf" enctype="multipart/form-data" onsubmit="U()">
|
||||
Installed version: 0.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
|
||||
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>
|
||||
@ -78,6 +78,17 @@ update();var tmout=null;function update(){if(document.hidden)return clearTimeout
|
||||
</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!!
|
||||
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"
|
||||
|
File diff suppressed because one or more lines are too long
@ -21,6 +21,54 @@ uint16_t irTimesRepeated = 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
|
||||
//IR codes themselves can be defined directly after "case" or in "ir_codes.h"
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (effectCurrent != 0) {
|
||||
@ -142,11 +180,11 @@ void applyRepeatActions(){
|
||||
|
||||
if (lastRepeatableAction == ACTION_BRIGHT_UP)
|
||||
{
|
||||
changeBrightness(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
incBrightness(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
}
|
||||
else if (lastRepeatableAction == ACTION_BRIGHT_DOWN )
|
||||
{
|
||||
changeBrightness(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
decBrightness(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
}
|
||||
|
||||
if (lastRepeatableAction == ACTION_SPEED_UP)
|
||||
@ -187,8 +225,8 @@ void applyRepeatActions(){
|
||||
void decodeIR24(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR24_BRIGHTER : changeBrightness(10); break;
|
||||
case IR24_DARKER : changeBrightness(-10); break;
|
||||
case IR24_BRIGHTER : incBrightness(); break;
|
||||
case IR24_DARKER : decBrightness(); break;
|
||||
case IR24_OFF : briLast = bri; bri = 0; break;
|
||||
case IR24_ON : bri = briLast; break;
|
||||
case IR24_RED : colorFromUint32(COLOR_RED); break;
|
||||
@ -219,8 +257,8 @@ void decodeIR24(uint32_t code)
|
||||
void decodeIR24OLD(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR24_OLD_BRIGHTER : changeBrightness(10); break;
|
||||
case IR24_OLD_DARKER : changeBrightness(-10); break;
|
||||
case IR24_OLD_BRIGHTER : incBrightness(); break;
|
||||
case IR24_OLD_DARKER : decBrightness(); break;
|
||||
case IR24_OLD_OFF : briLast = bri; bri = 0; break;
|
||||
case IR24_OLD_ON : bri = briLast; break;
|
||||
case IR24_OLD_RED : colorFromUint32(COLOR_RED); break;
|
||||
@ -252,8 +290,8 @@ void decodeIR24OLD(uint32_t code)
|
||||
void decodeIR24CT(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR24_CT_BRIGHTER : changeBrightness(10); break;
|
||||
case IR24_CT_DARKER : changeBrightness(-10); break;
|
||||
case IR24_CT_BRIGHTER : incBrightness(); break;
|
||||
case IR24_CT_DARKER : decBrightness(); break;
|
||||
case IR24_CT_OFF : briLast = bri; bri = 0; break;
|
||||
case IR24_CT_ON : bri = briLast; break;
|
||||
case IR24_CT_RED : colorFromUint32(COLOR_RED); break;
|
||||
@ -287,8 +325,8 @@ void decodeIR24CT(uint32_t code)
|
||||
void decodeIR40(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR40_BPLUS : changeBrightness(10); break;
|
||||
case IR40_BMINUS : changeBrightness(-10); break;
|
||||
case IR40_BPLUS : incBrightness(); break;
|
||||
case IR40_BMINUS : decBrightness(); break;
|
||||
case IR40_OFF : briLast = bri; bri = 0; break;
|
||||
case IR40_ON : bri = briLast; break;
|
||||
case IR40_RED : colorFromUint24(COLOR_RED); break;
|
||||
@ -344,8 +382,8 @@ void decodeIR40(uint32_t code)
|
||||
void decodeIR44(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR44_BPLUS : changeBrightness(10); break;
|
||||
case IR44_BMINUS : changeBrightness(-10); break;
|
||||
case IR44_BPLUS : incBrightness(); break;
|
||||
case IR44_BMINUS : decBrightness(); break;
|
||||
case IR44_OFF : briLast = bri; bri = 0; break;
|
||||
case IR44_ON : bri = briLast; break;
|
||||
case IR44_RED : colorFromUint24(COLOR_RED); break;
|
||||
@ -407,8 +445,8 @@ void decodeIR44(uint32_t code)
|
||||
void decodeIR21(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR21_BRIGHTER: changeBrightness(10); break;
|
||||
case IR21_DARKER: changeBrightness(-10); break;
|
||||
case IR21_BRIGHTER: incBrightness(); break;
|
||||
case IR21_DARKER: decBrightness(); break;
|
||||
case IR21_OFF: briLast = bri; bri = 0; break;
|
||||
case IR21_ON: bri = briLast; break;
|
||||
case IR21_RED: colorFromUint32(COLOR_RED); break;
|
||||
@ -437,8 +475,8 @@ void decodeIR6(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR6_POWER: toggleOnOff(); break;
|
||||
case IR6_CHANNEL_UP: changeBrightness(10); break;
|
||||
case IR6_CHANNEL_DOWN: changeBrightness(-10); break;
|
||||
case IR6_CHANNEL_UP: incBrightness(); break;
|
||||
case IR6_CHANNEL_DOWN: decBrightness(); break;
|
||||
case IR6_VOLUME_UP: relativeChange(&effectCurrent, 1, 0, MODE_COUNT); break; // next effect
|
||||
case IR6_VOLUME_DOWN: // next palette
|
||||
relativeChange(&effectPalette, 1, 0, strip.getPaletteCount() -1);
|
||||
@ -472,8 +510,8 @@ void decodeIR9(uint32_t code)
|
||||
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_C : if (!applyPreset(3)) effectCurrent = FX_MODE_BREATH; break;
|
||||
case IR9_UP : changeBrightness(16); break;
|
||||
case IR9_DOWN : changeBrightness(-16); break;
|
||||
case IR9_UP : incBrightness(); break;
|
||||
case IR9_DOWN : decBrightness(); break;
|
||||
//case IR9_UP : changeEffectIntensity(16); break;
|
||||
//case IR9_DOWN : changeEffectIntensity(-16); break;
|
||||
case IR9_LEFT : changeEffectSpeed(-16); break;
|
||||
@ -488,7 +526,7 @@ void initIR()
|
||||
{
|
||||
if (irEnabled > 0)
|
||||
{
|
||||
irrecv = new IRrecv(IRPIN);
|
||||
irrecv = new IRrecv(irPin);
|
||||
irrecv->enableIRIn();
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ void deserializeSegment(JsonObject elem, byte it)
|
||||
|
||||
//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_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 ));
|
||||
|
||||
//temporary, strip object gets updated via colorUpdated()
|
||||
@ -134,7 +134,7 @@ void deserializeSegment(JsonObject elem, byte it)
|
||||
if (sz == 0 && sz > 4) break;
|
||||
|
||||
int rgbw[] = {0,0,0,0};
|
||||
byte cp = copyArray(icol, rgbw);
|
||||
copyArray(icol, rgbw);
|
||||
|
||||
if (set < 2) stop = start + 1;
|
||||
for (uint16_t i = start; i < stop; i++) {
|
||||
@ -200,8 +200,8 @@ bool deserializeState(JsonObject root)
|
||||
receiveNotifications = udpn[F("recv")] | receiveNotifications;
|
||||
bool noNotification = udpn[F("nn")]; //send no notification just for this request
|
||||
|
||||
unsigned long timein = root[F("time")] | -1;
|
||||
if (timein != -1) {
|
||||
unsigned long timein = root[F("time")] | UINT32_MAX;
|
||||
if (timein != UINT32_MAX) {
|
||||
if (millis() - ntpLastSyncTime > 50000000L) setTime(timein);
|
||||
if (presetsModifiedTime == 0) presetsModifiedTime = timein;
|
||||
}
|
||||
@ -327,7 +327,7 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo
|
||||
root[F("ix")] = seg.intensity;
|
||||
root[F("pal")] = seg.palette;
|
||||
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);
|
||||
}
|
||||
|
||||
@ -343,7 +343,6 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
||||
if (errorFlag) root[F("error")] = errorFlag;
|
||||
|
||||
root[F("ps")] = currentPreset;
|
||||
root[F("pss")] = savedPresets;
|
||||
root[F("pl")] = (presetCyclingEnabled) ? 0: -1;
|
||||
|
||||
usermods.addToJsonState(root);
|
||||
@ -424,6 +423,7 @@ void serializeInfo(JsonObject root)
|
||||
leds_pin.add(LEDPIN);
|
||||
|
||||
leds[F("pwr")] = strip.currentMilliamps;
|
||||
leds[F("fps")] = strip.getFps();
|
||||
leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0;
|
||||
leds[F("maxseg")] = strip.getMaxSegments();
|
||||
leds[F("seglock")] = false; //will be used in the future to prevent modifications to segment config
|
||||
@ -611,7 +611,7 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
|
||||
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||
{
|
||||
AsyncWebSocketClient * wsc;
|
||||
AsyncWebSocketClient * wsc = nullptr;
|
||||
if (!request) { //not HTTP, use Websockets
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
wsc = ws.client(wsClient);
|
||||
@ -628,7 +628,7 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||
|
||||
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;
|
||||
oappend((const char*)F("],\"n\":"));
|
||||
|
@ -23,10 +23,9 @@ bool parseLx(int lxValue, byte rgbw[4])
|
||||
ok = true;
|
||||
float tmpBri = floor((lxValue - 200000000) / 10000); ;
|
||||
uint16_t ct = (lxValue - 200000000) - (((uint8_t)tmpBri) * 10000);
|
||||
float temp = 0;
|
||||
|
||||
tmpBri *= 2.55;
|
||||
constrain(tmpBri, 0, 255);
|
||||
tmpBri = constrain(tmpBri, 0, 255);
|
||||
|
||||
colorKtoRGB(ct, rgbw);
|
||||
lxRed = rgbw[0]; lxGreen = rgbw[1]; lxBlue = rgbw[2];
|
||||
|
@ -110,7 +110,7 @@ void publishMqtt()
|
||||
char s[10];
|
||||
char subuf[38];
|
||||
|
||||
sprintf(s, "%ld", bri);
|
||||
sprintf(s, "%u", bri);
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat(subuf, "/g");
|
||||
mqtt->publish(subuf, 0, true, s);
|
||||
|
@ -1,9 +1,6 @@
|
||||
#include "pin_manager.h"
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Registers pins so there is no attempt for two interfaces to use the same pin
|
||||
*/
|
||||
|
||||
void PinManagerClass::deallocatePin(byte gpio)
|
||||
{
|
||||
if (!isPinOk(gpio, false)) return;
|
||||
@ -51,4 +48,44 @@ bool PinManagerClass::isPinOk(byte gpio, bool output)
|
||||
#endif
|
||||
|
||||
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
29
wled00/pin_manager.h
Normal 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
|
104
wled00/set.cpp
104
wled00/set.cpp
@ -75,18 +75,89 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
//LED SETTINGS
|
||||
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;
|
||||
#ifdef ESP8266
|
||||
#if LEDPIN == 3
|
||||
if (ledCount > MAX_LEDS_DMA) ledCount = MAX_LEDS_DMA; //DMA method uses too much ram
|
||||
#endif
|
||||
|
||||
// upate other pins
|
||||
#ifndef WLED_DISABLE_INFRARED
|
||||
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
|
||||
|
||||
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.milliampsPerLed = request->arg(F("LA")).toInt();
|
||||
|
||||
useRGBW = request->hasArg(F("EW"));
|
||||
strip.setColorOrder(request->arg(F("CO")).toInt());
|
||||
strip.rgbwMode = request->arg(F("AW")).toInt();
|
||||
|
||||
briS = request->arg(F("CA")).toInt();
|
||||
@ -328,12 +399,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
DMXFixtureMap[i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
if (subPage != 6 || !doReboot) serializeConfig(); //do not save if factory reset
|
||||
if (subPage == 2) {
|
||||
strip.init(useRGBW,ledCount,skipFirstLed);
|
||||
}
|
||||
|
||||
if (subPage != 2 && (subPage != 6 || !doReboot)) serializeConfig(); //do not save if factory reset or LED settings (which are saved after LED re-init)
|
||||
if (subPage == 4) alexaInit();
|
||||
}
|
||||
|
||||
@ -646,15 +714,15 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
}
|
||||
if (nightlightMode > NL_MODE_SUN) nightlightMode = NL_MODE_SUN;
|
||||
|
||||
#if AUXPIN >= 0
|
||||
//toggle general purpose output
|
||||
pos = req.indexOf(F("AX="));
|
||||
if (pos > 0) {
|
||||
auxTime = getNumVal(&req, pos);
|
||||
auxActive = true;
|
||||
if (auxTime == 0) auxActive = false;
|
||||
if (auxPin>=0) {
|
||||
pos = req.indexOf(F("AX="));
|
||||
if (pos > 0) {
|
||||
auxTime = getNumVal(&req, pos);
|
||||
auxActive = true;
|
||||
if (auxTime == 0) auxActive = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
pos = req.indexOf(F("TT="));
|
||||
if (pos > 0) transitionDelay = getNumVal(&req, pos);
|
||||
|
@ -37,10 +37,10 @@ AsyncMqttClient::AsyncMqttClient()
|
||||
_client.onPoll([](void* obj, AsyncClient* c) { (static_cast<AsyncMqttClient*>(obj))->_onPoll(c); }, this);
|
||||
|
||||
#ifdef ESP32
|
||||
sprintf(_generatedClientId, "esp32%06x", ESP.getEfuseMac());
|
||||
sprintf(_generatedClientId, "esp32%06x", (uint32_t)ESP.getEfuseMac());
|
||||
_xSemaphore = xSemaphoreCreateMutex();
|
||||
#elif defined(ESP8266)
|
||||
sprintf(_generatedClientId, "esp8266%06x", ESP.getChipId());
|
||||
sprintf(_generatedClientId, "esp8266%06x", (uint32_t)ESP.getChipId());
|
||||
#endif
|
||||
_clientId = _generatedClientId;
|
||||
|
||||
|
@ -93,7 +93,9 @@ struct BlynkHeader
|
||||
}
|
||||
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__
|
||||
#define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) )
|
||||
#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \
|
||||
|
@ -45,8 +45,7 @@ public:
|
||||
}
|
||||
BLYNK_LOG1(BLYNK_F("Connected to WiFi"));
|
||||
|
||||
IPAddress myip = WiFi.localIP();
|
||||
BLYNK_LOG_IP("IP: ", myip);
|
||||
BLYNK_LOG_IP("IP: ", WiFi.localIP());
|
||||
}
|
||||
|
||||
void config(const char* auth,
|
||||
|
@ -77,10 +77,9 @@ void DMXESPSerial::write(int Channel, uint8_t value) {
|
||||
}
|
||||
|
||||
void DMXESPSerial::end() {
|
||||
delete dmxData;
|
||||
chanSize = 0;
|
||||
Serial1.end();
|
||||
dmxStarted == false;
|
||||
dmxStarted = false;
|
||||
}
|
||||
|
||||
void DMXESPSerial::update() {
|
||||
|
@ -101,8 +101,8 @@ private:
|
||||
case EspalexaDeviceType::whitespectrum: return PSTR("Color temperature light");
|
||||
case EspalexaDeviceType::color: return PSTR("Color light");
|
||||
case EspalexaDeviceType::extendedcolor: return PSTR("Extended color light");
|
||||
default: return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
const char* modelidString(EspalexaDeviceType t)
|
||||
@ -113,8 +113,8 @@ private:
|
||||
case EspalexaDeviceType::whitespectrum: return "LWT010";
|
||||
case EspalexaDeviceType::color: return "LST001";
|
||||
case EspalexaDeviceType::extendedcolor: return "LCT015";
|
||||
default: return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void encodeLightId(uint8_t idx, char* out)
|
||||
|
@ -112,7 +112,6 @@ uint32_t EspalexaDevice::getRGB()
|
||||
{
|
||||
if (_rgb != 0) return _rgb; //color has not changed
|
||||
byte rgb[4]{0, 0, 0, 0};
|
||||
float r, g, b, w;
|
||||
|
||||
if (_mode == EspalexaColorMode::none) return 0;
|
||||
|
||||
|
@ -144,7 +144,7 @@ public:
|
||||
virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final {
|
||||
if (_onRequest) {
|
||||
_contentLength = total;
|
||||
if (total > 0 && request->_tempObject == NULL && total < _maxContentLength) {
|
||||
if (total > 0 && request->_tempObject == NULL && (int)total < _maxContentLength) {
|
||||
request->_tempObject = malloc(total);
|
||||
}
|
||||
if (request->_tempObject != NULL) {
|
||||
|
@ -347,6 +347,15 @@ void handleNotifications()
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
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();
|
||||
return;
|
||||
|
@ -15,11 +15,24 @@ void UsermodManager::readFromJsonState(JsonObject& obj) { for (byte i = 0; i < n
|
||||
void UsermodManager::addToConfig(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->addToConfig(obj); }
|
||||
void UsermodManager::readFromConfig(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->readFromConfig(obj); }
|
||||
|
||||
/*
|
||||
* Enables usermods to lookup another Usermod.
|
||||
*/
|
||||
Usermod* UsermodManager::lookup(uint16_t mod_id) {
|
||||
for (byte i = 0; i < numMods; i++) {
|
||||
if (ums[i]->getId() == mod_id) {
|
||||
return ums[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool UsermodManager::add(Usermod* um)
|
||||
{
|
||||
if (numMods >= WLED_MAX_USERMODS || um == nullptr) return false;
|
||||
ums[numMods] = um;
|
||||
numMods++;
|
||||
return true;
|
||||
}
|
||||
|
||||
byte UsermodManager::getModCount() {return numMods;}
|
@ -13,7 +13,9 @@
|
||||
#ifdef USERMOD_DALLASTEMPERATURE
|
||||
#include "../usermods/Temperature/usermod_temperature.h"
|
||||
#endif
|
||||
|
||||
//#include "usermod_v2_empty.h"
|
||||
|
||||
#ifdef USERMOD_BUZZER
|
||||
#include "../usermods/buzzer/usermod_v2_buzzer.h"
|
||||
#endif
|
||||
@ -21,6 +23,28 @@
|
||||
#include "usermod_v2_SensorsToMqtt.h"
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_MODE_SORT
|
||||
#include "../usermods/usermod_v2_mode_sort/usermod_v2_mode_sort.h"
|
||||
#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
|
||||
#include "../usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h"
|
||||
#endif
|
||||
#ifdef USERMOD_ROTARY_ENCODER_UI
|
||||
#include "../usermods/usermod_v2_rotary_encoder_ui/usermod_v2_rotary_encoder_ui.h"
|
||||
#endif
|
||||
#ifdef USERMOD_AUTO_SAVE
|
||||
#include "../usermods/usermod_v2_auto_save/usermod_v2_auto_save.h"
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_DHT
|
||||
#include "../usermods/DHT/usermod_dht.h"
|
||||
#endif
|
||||
|
||||
void registerUsermods()
|
||||
{
|
||||
/*
|
||||
@ -28,15 +52,39 @@ void registerUsermods()
|
||||
* || || ||
|
||||
* \/ \/ \/
|
||||
*/
|
||||
//usermods.add(new MyExampleUsermod());
|
||||
#ifdef USERMOD_DALLASTEMPERATURE
|
||||
//usermods.add(new MyExampleUsermod());
|
||||
|
||||
#ifdef USERMOD_DALLASTEMPERATURE
|
||||
usermods.add(new UsermodTemperature());
|
||||
#endif
|
||||
//usermods.add(new UsermodRenameMe());
|
||||
#ifdef USERMOD_BUZZER
|
||||
#endif
|
||||
|
||||
//usermods.add(new UsermodRenameMe());
|
||||
|
||||
#ifdef USERMOD_BUZZER
|
||||
usermods.add(new BuzzerUsermod());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_BME280
|
||||
usermods.add(new UsermodBME280());
|
||||
#endif
|
||||
#ifdef USERMOD_SENSORSTOMQTT
|
||||
usermods.add(new UserMod_SensorsToMQTT());
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_MODE_SORT
|
||||
usermods.add(new ModeSortUsermod());
|
||||
#endif
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
usermods.add(new FourLineDisplayUsermod());
|
||||
#endif
|
||||
#ifdef USERMOD_ROTARY_ENCODER_UI
|
||||
usermods.add(new RotaryEncoderUIUsermod());
|
||||
#endif
|
||||
#ifdef USERMOD_AUTO_SAVE
|
||||
usermods.add(new AutoSaveUsermod());
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_DHT
|
||||
usermods.add(new UsermodDHT());
|
||||
#endif
|
||||
}
|
108
wled00/wled.cpp
108
wled00/wled.cpp
@ -48,6 +48,26 @@ ethernet_settings ethernetBoards[] = {
|
||||
18, // eth_mdio,
|
||||
ETH_PHY_LAN8720, // eth_type,
|
||||
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
|
||||
},
|
||||
|
||||
// WESP32
|
||||
{
|
||||
0, // eth_address,
|
||||
-1, // eth_power,
|
||||
16, // eth_mdc,
|
||||
17, // eth_mdio,
|
||||
ETH_PHY_LAN8720, // eth_type,
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
@ -116,8 +136,10 @@ void prepareHostname(char* hostname)
|
||||
//handle Ethernet connection event
|
||||
void WiFiEvent(WiFiEvent_t event)
|
||||
{
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
char hostname[25] = "wled-";
|
||||
|
||||
#endif
|
||||
|
||||
switch (event) {
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
|
||||
case SYSTEM_EVENT_ETH_START:
|
||||
@ -195,10 +217,20 @@ void WLED::loop()
|
||||
handleHue();
|
||||
handleBlynk();
|
||||
|
||||
/*if (presetToApply) {
|
||||
applyPreset(presetToApply);
|
||||
presetToApply = 0;
|
||||
}*/
|
||||
//LED settings have been saved, re-init busses
|
||||
if (busConfigs[0] != nullptr) {
|
||||
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();
|
||||
|
||||
@ -264,18 +296,14 @@ void WLED::setup()
|
||||
DEBUG_PRINT("esp8266 ");
|
||||
DEBUG_PRINTLN(ESP.getCoreVersion());
|
||||
#endif
|
||||
int heapPreAlloc = ESP.getFreeHeap();
|
||||
DEBUG_PRINT("heap ");
|
||||
DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
registerUsermods();
|
||||
|
||||
//strip.init(EEPROM.read(372), ledCount, EEPROM.read(2204)); // init LEDs quickly
|
||||
//strip.setBrightness(0);
|
||||
|
||||
//DEBUG_PRINT(F("LEDs inited. heap usage ~"));
|
||||
//DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap());
|
||||
|
||||
|
||||
bool fsinit = false;
|
||||
DEBUGFS_PRINTLN(F("Mount FS"));
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
@ -290,8 +318,16 @@ void WLED::setup()
|
||||
updateFSInfo();
|
||||
deserializeConfig();
|
||||
|
||||
#if STATUSLED && STATUSLED != LEDPIN
|
||||
pinMode(STATUSLED, OUTPUT);
|
||||
#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);
|
||||
#endif
|
||||
|
||||
//DEBUG_PRINTLN(F("Load EEPROM"));
|
||||
@ -348,25 +384,14 @@ void WLED::setup()
|
||||
void WLED::beginStrip()
|
||||
{
|
||||
// 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)
|
||||
ledCount = 30;
|
||||
|
||||
strip.init(useRGBW, ledCount, skipFirstLed);
|
||||
strip.finalizeInit(useRGBW, ledCount, skipFirstLed);
|
||||
strip.setBrightness(0);
|
||||
strip.setShowCallback(handleOverlayDraw);
|
||||
|
||||
#if defined(BTNPIN) && BTNPIN > -1
|
||||
pinManager.allocatePin(BTNPIN, false);
|
||||
pinMode(BTNPIN, INPUT_PULLUP);
|
||||
#endif
|
||||
|
||||
if (bootPreset > 0) applyPreset(bootPreset);
|
||||
if (turnOnAtBoot) {
|
||||
if (briS > 0) bri = briS;
|
||||
@ -376,24 +401,13 @@ void WLED::beginStrip()
|
||||
}
|
||||
colorUpdated(NOTIFIER_CALL_MODE_INIT);
|
||||
|
||||
// init relay pin
|
||||
#if RLYPIN >= 0
|
||||
pinManager.allocatePin(RLYPIN);
|
||||
pinMode(RLYPIN, OUTPUT);
|
||||
#if RLYMDE
|
||||
digitalWrite(RLYPIN, bri);
|
||||
#else
|
||||
digitalWrite(RLYPIN, !bri);
|
||||
#endif
|
||||
#endif
|
||||
// init relay pin
|
||||
if (rlyPin>=0)
|
||||
digitalWrite(rlyPin, (rlyMde ? bri : !bri));
|
||||
|
||||
// disable button if it is "pressed" unintentionally
|
||||
#if (defined(BTNPIN) && BTNPIN > -1) || defined(TOUCHPIN)
|
||||
if (isButtonPressed())
|
||||
if (btnPin>=0 && isButtonPressed())
|
||||
buttonEnabled = false;
|
||||
#else
|
||||
buttonEnabled = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void WLED::initAP(bool resetAP)
|
||||
@ -424,7 +438,7 @@ void WLED::initAP(bool resetAP)
|
||||
udp2Connected = notifier2Udp.begin(udpPort2);
|
||||
}
|
||||
e131.begin(false, e131Port, e131Universe, E131_MAX_UNIVERSE_COUNT);
|
||||
|
||||
|
||||
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
|
||||
dnsServer.start(53, "*", WiFi.softAPIP());
|
||||
}
|
||||
@ -439,7 +453,7 @@ void WLED::initConnection()
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
|
||||
// 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];
|
||||
ETH.begin(
|
||||
(uint8_t) es.eth_address,
|
||||
@ -488,7 +502,7 @@ void WLED::initConnection()
|
||||
// convert the "serverDescription" into a valid DNS hostname (alphanumeric)
|
||||
char hostname[25] = "wled-";
|
||||
prepareHostname(hostname);
|
||||
|
||||
|
||||
#ifdef ESP8266
|
||||
WiFi.hostname(hostname);
|
||||
#endif
|
||||
@ -639,7 +653,13 @@ void WLED::handleConnection()
|
||||
|
||||
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;
|
||||
if (mqttEnabled && ledStatusType != 2) // Wi-Fi takes presendence over MQTT
|
||||
ledStatusType = WLED_MQTT_CONNECTED ? 0 : 4;
|
||||
@ -655,7 +675,7 @@ void WLED::handleStatusLED()
|
||||
#else
|
||||
digitalWrite(STATUSLED, LOW);
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,12 @@
|
||||
/*
|
||||
Main sketch, global variable declarations
|
||||
@title WLED project sketch
|
||||
@version 0.11.1
|
||||
@version 0.12.0-a0
|
||||
@author Christian Schwinne
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2101130
|
||||
#define VERSION 2103060
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
@ -65,7 +65,9 @@
|
||||
#include <ESPmDNS.h>
|
||||
#include <AsyncTCP.h>
|
||||
//#include "SPIFFS.h"
|
||||
#define CONFIG_LITTLEFS_FOR_IDF_3_2
|
||||
#ifndef CONFIG_LITTLEFS_FOR_IDF_3_2
|
||||
#define CONFIG_LITTLEFS_FOR_IDF_3_2
|
||||
#endif
|
||||
#include <LITTLEFS.h>
|
||||
#endif
|
||||
|
||||
@ -116,6 +118,8 @@
|
||||
#include "ir_codes.h"
|
||||
#include "const.h"
|
||||
#include "NodeStruct.h"
|
||||
#include "pin_manager.h"
|
||||
#include "bus_manager.h"
|
||||
|
||||
#ifndef CLIENT_SSID
|
||||
#define CLIENT_SSID DEFAULT_CLIENT_SSID
|
||||
@ -131,7 +135,7 @@
|
||||
Comment out this error message to build regardless.
|
||||
#endif
|
||||
|
||||
#if IRPIN < 0
|
||||
#if !defined(IRPIN) || IRPIN < 0
|
||||
#ifndef WLED_DISABLE_INFRARED
|
||||
#define WLED_DISABLE_INFRARED
|
||||
#endif
|
||||
@ -175,8 +179,8 @@
|
||||
#endif
|
||||
|
||||
// Global Variable definitions
|
||||
WLED_GLOBAL char versionString[] _INIT("0.11.1");
|
||||
#define WLED_CODENAME "Mirai"
|
||||
WLED_GLOBAL char versionString[] _INIT("0.12.0-a0");
|
||||
#define WLED_CODENAME "Hikari"
|
||||
|
||||
// AP and OTA default passwords (for maximum security change them!)
|
||||
WLED_GLOBAL char apPass[65] _INIT(DEFAULT_AP_PASS);
|
||||
@ -184,13 +188,30 @@ WLED_GLOBAL char otaPass[33] _INIT(DEFAULT_OTA_PASS);
|
||||
|
||||
// Hardware CONFIG (only changeble HERE, not at runtime)
|
||||
// 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);
|
||||
|
||||
#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
|
||||
|
||||
// WiFi CONFIG (all these can be changed via web UI, no need to set them here)
|
||||
@ -206,7 +227,11 @@ WLED_GLOBAL IPAddress staticGateway _INIT_N((( 0, 0, 0, 0))); // gateway (r
|
||||
WLED_GLOBAL IPAddress staticSubnet _INIT_N(((255, 255, 255, 0))); // most common subnet in home networks
|
||||
WLED_GLOBAL bool noWifiSleep _INIT(false); // disabling modem sleep modes will increase heat output and power usage, but may help with connection issues
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
WLED_GLOBAL int ethernetType _INIT(WLED_ETH_ESP32_POE); // ethernet board type
|
||||
#ifdef WLED_ETH_DEFAULT // default ethernet board type if specified
|
||||
WLED_GLOBAL int ethernetType _INIT(WLED_ETH_DEFAULT); // ethernet board type
|
||||
#else
|
||||
WLED_GLOBAL int ethernetType _INIT(WLED_ETH_NONE); // use none for ethernet board type if default not defined
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// LED CONFIG
|
||||
@ -291,7 +316,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 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 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 hueApplyBri _INIT(true);
|
||||
WLED_GLOBAL bool hueApplyColor _INIT(true);
|
||||
@ -454,23 +479,29 @@ WLED_GLOBAL int16_t currentPlaylist _INIT(0);
|
||||
// realtime
|
||||
WLED_GLOBAL byte realtimeMode _INIT(REALTIME_MODE_INACTIVE);
|
||||
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 uint8_t tpmPacketCount _INIT(0);
|
||||
WLED_GLOBAL uint16_t tpmPayloadFrameSize _INIT(0);
|
||||
|
||||
// mqtt
|
||||
WLED_GLOBAL long lastMqttReconnectAttempt _INIT(0);
|
||||
WLED_GLOBAL long lastInterfaceUpdate _INIT(0);
|
||||
WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0);
|
||||
WLED_GLOBAL unsigned long lastInterfaceUpdate _INIT(0);
|
||||
WLED_GLOBAL byte interfaceUpdateCallMode _INIT(NOTIFIER_CALL_MODE_INIT);
|
||||
WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers
|
||||
|
||||
#if AUXPIN >= 0
|
||||
// auxiliary debug pin
|
||||
WLED_GLOBAL byte auxTime _INIT(0);
|
||||
WLED_GLOBAL unsigned long auxStartTime _INIT(0);
|
||||
WLED_GLOBAL bool auxActive _INIT(false, auxActiveBefore _INIT(false);
|
||||
// auxiliary debug pin
|
||||
#ifndef AUXPIN
|
||||
WLED_GLOBAL int8_t auxPin _INIT(-1);
|
||||
#else
|
||||
WLED_GLOBAL int8_t auxPin _INIT(AUXPIN);
|
||||
#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
|
||||
WLED_GLOBAL String escapedMac;
|
||||
@ -503,7 +534,6 @@ WLED_GLOBAL JsonDocument* fileDoc;
|
||||
WLED_GLOBAL bool doCloseFile _INIT(false);
|
||||
|
||||
// presets
|
||||
WLED_GLOBAL uint16_t savedPresets _INIT(0);
|
||||
WLED_GLOBAL int16_t currentPreset _INIT(-1);
|
||||
WLED_GLOBAL bool isPreset _INIT(false);
|
||||
|
||||
@ -530,15 +560,15 @@ WLED_GLOBAL ESPAsyncE131 e131 _INIT_N(((handleE131Packet)));
|
||||
WLED_GLOBAL bool e131NewData _INIT(false);
|
||||
|
||||
// led fx library object
|
||||
WLED_GLOBAL BusManager busses _INIT(BusManager());
|
||||
WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
|
||||
WLED_GLOBAL BusConfig* busConfigs[WLED_MAX_BUSSES]; //temporary, to remember values from network callback until after
|
||||
|
||||
// Usermod manager
|
||||
WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
|
||||
|
||||
WLED_GLOBAL PinManagerClass pinManager _INIT(PinManagerClass());
|
||||
|
||||
// Status LED
|
||||
#if STATUSLED && STATUSLED != LEDPIN
|
||||
#if STATUSLED
|
||||
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 bool ledStatusState _INIT(0); // the current LED state
|
||||
|
@ -39,9 +39,15 @@ void initServer()
|
||||
DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Methods"), "*");
|
||||
DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Headers"), "*");
|
||||
|
||||
server.on("/liveview", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
request->send_P(200, "text/html", PAGE_liveview);
|
||||
});
|
||||
#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){
|
||||
request->send_P(200, "text/html", PAGE_liveview);
|
||||
});
|
||||
#endif
|
||||
|
||||
//settings page
|
||||
server.on("/settings", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
@ -229,14 +235,32 @@ void serveIndexOrWelcome(AsyncWebServerRequest *request)
|
||||
}
|
||||
}
|
||||
|
||||
bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest* request)
|
||||
{
|
||||
AsyncWebHeader* header = request->getHeader("If-None-Match");
|
||||
if (header && header->value() == String(VERSION)) {
|
||||
request->send(304);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void setStaticContentCacheHeaders(AsyncWebServerResponse *response)
|
||||
{
|
||||
response->addHeader(F("Cache-Control"),"max-age=2592000");
|
||||
response->addHeader(F("ETag"), String(VERSION));
|
||||
}
|
||||
|
||||
void serveIndex(AsyncWebServerRequest* request)
|
||||
{
|
||||
if (handleFileRead(request, "/index.htm")) return;
|
||||
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_index, PAGE_index_L);
|
||||
|
||||
response->addHeader(F("Content-Encoding"),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
|
||||
request->send(response);
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('c',SET_F("WS"),noWifiSleep);
|
||||
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
sappend('i',SET_F("ETH"),ethernetType);
|
||||
sappend('v',SET_F("ETH"),ethernetType);
|
||||
#else
|
||||
//hide ethernet setting if not compiled in
|
||||
oappend(SET_F("document.getElementById('ethd').style.display='none';"));
|
||||
@ -254,27 +254,72 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
}
|
||||
|
||||
if (subPage == 2) {
|
||||
#ifdef ESP8266
|
||||
#if LEDPIN == 3
|
||||
oappend(SET_F("d.Sf.LC.max=500;"));
|
||||
#else
|
||||
oappend(SET_F("d.Sf.LC.max=1500;"));
|
||||
#endif
|
||||
#endif
|
||||
char nS[8];
|
||||
|
||||
// add usermod pins as d.um_p array (TODO: usermod config shouldn't use state. instead we should load "um" object from cfg.json)
|
||||
/*DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||
JsonObject mods = doc.createNestedObject(F("mods"));
|
||||
usermods.addToJsonState(mods);
|
||||
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);
|
||||
|
||||
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("LA"),strip.milliampsPerLed);
|
||||
if (strip.currentMilliamps)
|
||||
{
|
||||
sappends('m',SET_F("(\"pow\")[0]"),"");
|
||||
sappends('m',SET_F("(\"pow\")[0]"),(char*)"");
|
||||
olen -= 2; //delete ";
|
||||
oappendi(strip.currentMilliamps);
|
||||
oappend(SET_F("mA\";"));
|
||||
}
|
||||
|
||||
sappend('v',SET_F("CA"),briS);
|
||||
sappend('c',SET_F("EW"),useRGBW);
|
||||
sappend('i',SET_F("CO"),strip.getColorOrder());
|
||||
//sappend('c',SET_F("EW"),useRGBW);
|
||||
//sappend('i',SET_F("CO"),strip.getColorOrder());
|
||||
sappend('v',SET_F("AW"),strip.rgbwMode);
|
||||
|
||||
sappend('c',SET_F("BO"),turnOnAtBoot);
|
||||
@ -292,6 +337,11 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('i',SET_F("PB"),strip.paletteBlend);
|
||||
sappend('c',SET_F("RV"),strip.reverseMode);
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user