Fix spelling error
This commit is contained in:
commit
ea69957ed1
1
.gitignore
vendored
1
.gitignore
vendored
@ -15,3 +15,4 @@
|
||||
node_modules
|
||||
.idea
|
||||
.direnv
|
||||
wled-update.sh
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.13.0-b2",
|
||||
"version": "0.13.0-bl2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.13.0-b2",
|
||||
"version": "0.13.0-bl3",
|
||||
"description": "Tools for WLED project",
|
||||
"main": "tools/cdata.js",
|
||||
"directories": {
|
||||
|
@ -166,7 +166,7 @@ lib_deps =
|
||||
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
|
||||
#TFT_eSPI
|
||||
#For use SSD1306 OLED display uncomment following
|
||||
#U8g2@~2.27.2
|
||||
U8g2@~2.28.8
|
||||
#For Dallas sensor uncomment following 2 lines
|
||||
#OneWire@~2.3.5
|
||||
#milesburton/DallasTemperature@^3.9.0
|
||||
|
6
tools/WLED_ESP32-wrover_4MB.csv
Normal file
6
tools/WLED_ESP32-wrover_4MB.csv
Normal file
@ -0,0 +1,6 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x180000,
|
||||
app1, app, ota_1, 0x190000,0x180000,
|
||||
spiffs, data, spiffs, 0x310000,0xF0000,
|
|
@ -65,7 +65,7 @@ function adoptVersionAndRepo(html) {
|
||||
return html;
|
||||
}
|
||||
|
||||
function writeHtmlGzipped(sourceFile, resultFile) {
|
||||
function writeHtmlGzipped(sourceFile, resultFile, page) {
|
||||
console.info("Reading " + sourceFile);
|
||||
new inliner(sourceFile, function (error, html) {
|
||||
console.info("Inlined " + html.length + " characters");
|
||||
@ -95,8 +95,8 @@ function writeHtmlGzipped(sourceFile, resultFile) {
|
||||
*/
|
||||
|
||||
// Autogenerated from ${sourceFile}, do not edit!!
|
||||
const uint16_t PAGE_index_L = ${result.length};
|
||||
const uint8_t PAGE_index[] PROGMEM = {
|
||||
const uint16_t PAGE_${page}_L = ${result.length};
|
||||
const uint8_t PAGE_${page}[] PROGMEM = {
|
||||
${array}
|
||||
};
|
||||
`;
|
||||
@ -194,7 +194,8 @@ function writeChunks(srcDir, specs, resultFile) {
|
||||
fs.writeFileSync(resultFile, src);
|
||||
}
|
||||
|
||||
writeHtmlGzipped("wled00/data/index.htm", "wled00/html_ui.h");
|
||||
writeHtmlGzipped("wled00/data/index.htm", "wled00/html_ui.h", 'index');
|
||||
writeHtmlGzipped("wled00/data/simple.htm", "wled00/html_simple.h", 'simple');
|
||||
|
||||
writeChunks(
|
||||
"wled00/data",
|
||||
|
@ -458,11 +458,15 @@ class Animated_Staircase : public Usermod {
|
||||
|
||||
useUSSensorTop = top[FPSTR(_useTopUltrasoundSensor)] | useUSSensorTop;
|
||||
topPIRorTriggerPin = top[FPSTR(_topPIRorTrigger_pin)] | topPIRorTriggerPin;
|
||||
// topPIRorTriggerPin = min(33,max(-1,(int)topPIRorTriggerPin)); // bounds check
|
||||
topEchoPin = top[FPSTR(_topEcho_pin)] | topEchoPin;
|
||||
// topEchoPin = min(39,max(-1,(int)topEchoPin)); // bounds check
|
||||
|
||||
useUSSensorBottom = top[FPSTR(_useBottomUltrasoundSensor)] | useUSSensorBottom;
|
||||
bottomPIRorTriggerPin = top[FPSTR(_bottomPIRorTrigger_pin)] | bottomPIRorTriggerPin;
|
||||
// bottomPIRorTriggerPin = min(33,max(-1,(int)bottomPIRorTriggerPin)); // bounds check
|
||||
bottomEchoPin = top[FPSTR(_bottomEcho_pin)] | bottomEchoPin;
|
||||
// bottomEchoPin = min(39,max(-1,(int)bottomEchoPin)); // bounds check
|
||||
|
||||
topMaxDist = top[FPSTR(_topEchoCm)] | topMaxDist;
|
||||
topMaxDist = min(150,max(30,(int)topMaxDist)); // max distnace ~1.5m (a lag of 9ms may be expected)
|
||||
|
@ -1,9 +0,0 @@
|
||||
# PIR sensor with MQTT
|
||||
|
||||
This simple usermod allows attaching a PIR sensor like the AM312 and publish the readings over MQTT. A message is sent when motion is detected as well as when motion has stopped.
|
||||
|
||||
This usermod has only been tested with the AM312 sensor though should work for any other PIR sensor. Note that this does not control the LED strip directly, it only publishes MQTT readings for use with other integrations like Home Assistant.
|
||||
|
||||
## Installation
|
||||
|
||||
Copy and replace the file `usermod.cpp` in wled00 directory.
|
@ -1,55 +0,0 @@
|
||||
#include "wled.h"
|
||||
/*
|
||||
* This v1 usermod file allows you to add own functionality to WLED more easily
|
||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
||||
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
|
||||
* If you just need 8 bytes, use 2551-2559 (you do not need to increase EEPSIZE)
|
||||
*
|
||||
* Consider the v2 usermod API if you need a more advanced feature set!
|
||||
*/
|
||||
|
||||
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
|
||||
|
||||
// PIR sensor pin
|
||||
const int MOTION_PIN = 16;
|
||||
// MQTT topic for sensor values
|
||||
const char MQTT_TOPIC[] = "/motion";
|
||||
|
||||
int prevState = LOW;
|
||||
|
||||
//gets called once at boot. Do all initialization that doesn't depend on network here
|
||||
void userSetup()
|
||||
{
|
||||
pinMode(MOTION_PIN, INPUT);
|
||||
}
|
||||
|
||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
||||
void userConnected()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void publishMqtt(String state)
|
||||
{
|
||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (mqtt != nullptr){
|
||||
char subuf[38];
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat(subuf, MQTT_TOPIC);
|
||||
mqtt->publish(subuf, 0, true, state.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
|
||||
void userLoop()
|
||||
{
|
||||
if (digitalRead(MOTION_PIN) == HIGH && prevState == LOW) { // Motion detected
|
||||
publishMqtt("ON");
|
||||
prevState = HIGH;
|
||||
}
|
||||
if (digitalRead(MOTION_PIN) == LOW && prevState == HIGH) { // Motion stopped
|
||||
publishMqtt("OFF");
|
||||
prevState = LOW;
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
# QuinLED Dig Uno board
|
||||
|
||||
These files allow WLED 0.9.1 to report the temp sensor on the Quinled board to MQTT. I use it to report the board temp to Home Assistant via MQTT, so it will send notifications if something happens and the board start to heat up.
|
||||
This code uses Aircookie's WLED software. It has a premade file for user modifications. I use it to publish the temperature from the dallas temperature sensor on the Quinled board. The entries for the top of the WLED00 file, initializes the required libraries, and variables for the sensor. The .ino file waits for 60 seconds, and checks to see if the MQTT server is connected (thanks Aircoookie). It then poles the sensor, and published it using the MQTT service already running, using the main topic programmed in the WLED UI.
|
||||
|
||||
Installation of file: Copy and replace file in wled00 directory
|
||||
|
||||
## Project link
|
||||
|
||||
* [QuinLED-Dig-Uno](https://quinled.info/2018/09/15/quinled-dig-uno/) - Project link
|
||||
|
||||
### Platformio requirements
|
||||
|
||||
Uncomment `DallasTemperature@~3.8.0`,`OneWire@~2.3.5 under` `[common]` section in `platformio.ini`:
|
||||
|
||||
```ini
|
||||
# platformio.ini
|
||||
...
|
||||
[platformio]
|
||||
...
|
||||
; default_envs = esp07
|
||||
default_envs = d1_mini
|
||||
...
|
||||
[common]
|
||||
...
|
||||
lib_deps_external =
|
||||
...
|
||||
#For use SSD1306 OLED display uncomment following
|
||||
U8g2@~2.27.3
|
||||
#For Dallas sensor uncomment following 2 lines
|
||||
DallasTemperature@~3.8.0
|
||||
OneWire@~2.3.5
|
||||
...
|
||||
```
|
@ -1,54 +0,0 @@
|
||||
#include <Arduino.h>
|
||||
#include "wled.h"
|
||||
//Intiating code for QuinLED Dig-Uno temp sensor
|
||||
//Uncomment Celsius if that is your prefered temperature scale
|
||||
#include <DallasTemperature.h> //Dallastemperature sensor
|
||||
#ifdef ARDUINO_ARCH_ESP32 //ESP32 boards
|
||||
OneWire oneWire(18);
|
||||
#else //ESP8266 boards
|
||||
OneWire oneWire(14);
|
||||
#endif
|
||||
DallasTemperature sensor(&oneWire);
|
||||
long temptimer = millis();
|
||||
long lastMeasure = 0;
|
||||
#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit
|
||||
void userSetup()
|
||||
{
|
||||
// Start the DS18B20 sensor
|
||||
sensor.begin();
|
||||
}
|
||||
|
||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
||||
void userConnected()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void userLoop()
|
||||
{
|
||||
temptimer = millis();
|
||||
|
||||
// Timer to publishe new temperature every 60 seconds
|
||||
if (temptimer - lastMeasure > 60000) {
|
||||
lastMeasure = temptimer;
|
||||
|
||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (mqtt != nullptr){
|
||||
sensor.requestTemperatures();
|
||||
|
||||
//Gets prefered temperature scale based on selection in definitions section
|
||||
#ifdef Celsius
|
||||
float board_temperature = sensor.getTempCByIndex(0);
|
||||
#else
|
||||
float board_temperature = sensors.getTempFByIndex(0);
|
||||
#endif
|
||||
|
||||
//Create character string populated with user defined device topic from the UI, and the read temperature. Then publish to MQTT server.
|
||||
char subuf[38];
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat(subuf, "/temperature");
|
||||
mqtt->publish(subuf, 0, true, String(board_temperature).c_str());
|
||||
return;}
|
||||
return;}
|
||||
return;
|
||||
}
|
@ -2,11 +2,14 @@
|
||||
|
||||
This usermod allow to use 240x240 display to display following:
|
||||
|
||||
* current date and time;
|
||||
* Network SSID;
|
||||
* IP address;
|
||||
* WiFi signal strength;
|
||||
* Brightness;
|
||||
* Chosen effect;
|
||||
* Chosen palette;
|
||||
* effect speed and intensity;
|
||||
* Estimated current in mA;
|
||||
|
||||
## Hardware
|
||||
@ -46,27 +49,29 @@ Add lines to section:
|
||||
default_envs = esp32dev
|
||||
build_flags = ${common.build_flags_esp32}
|
||||
-D USERMOD_ST7789_DISPLAY
|
||||
|
||||
-DUSER_SETUP_LOADED=1
|
||||
-DST7789_DRIVER=1
|
||||
-DTFT_WIDTH=240
|
||||
-DTFT_HEIGHT=240
|
||||
-DCGRAM_OFFSET=1
|
||||
-DTFT_MOSI=21
|
||||
-DTFT_SCLK=22
|
||||
-DTFT_DC=27
|
||||
-DTFT_RST=26
|
||||
-DTFT_BL=14
|
||||
-DLOAD_GLCD=1
|
||||
;optional for WROVER
|
||||
;-DCONFIG_SPIRAM_SUPPORT=1
|
||||
```
|
||||
|
||||
Save the `platformio.ini` file. Once this is saved, the required library files should be automatically downloaded for modifications in a later step.
|
||||
|
||||
### TFT_eSPI Library Adjustments
|
||||
|
||||
We need to modify a file in the `TFT_eSPI` library. If you followed the directions to modify and save the `platformio.ini` file above, the `User_Setup_Select.h` file can be found in the `/.pio/libdeps/esp32dev/TFT_eSPI` folder.
|
||||
If you are not using PlatformIO you need to modify a file in the `TFT_eSPI` library. If you followed the directions to modify and save the `platformio.ini` file above, the `Setup24_ST7789.h` file can be found in the `/.pio/libdeps/esp32dev/TFT_eSPI/User_Setups/` folder.
|
||||
|
||||
Modify the `User_Setup_Select.h` file as follows:
|
||||
Edit `Setup_ST7789.h` file and uncomment nad changep GPIO pin numbers in lines containing `TFT_MOSI`, `TFT_SCLK`, `TFT_RST`, `TFT_DC`.
|
||||
|
||||
* Comment out the following line (which is the 'default' setup file):
|
||||
Modify the `User_Setup_Select.h` by uncommentig the line containing `#include <User_Setups/Setup24_ST7789.h>` and commenting out line containing `#include <User_Setup.h>`.
|
||||
|
||||
```ini
|
||||
//#include <User_Setup.h> // Default setup is root library folder
|
||||
```
|
||||
|
||||
* Add following line:
|
||||
|
||||
```ini
|
||||
#include <User_Setups/Setup_ST7789_Display.h> // Setup file for ESP32 ST7789V SPI bus TFT
|
||||
```
|
||||
|
||||
* Copy file `"Setup_ST7789_Display.h"` from usermod folder to `/.pio/libdeps/esp32dev/TFT_eSPI/User_Setups`
|
||||
If your display includes backlight enable pin, #define TFT_BL with backlight enable GPIO number.
|
@ -7,27 +7,48 @@
|
||||
#include <TFT_eSPI.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#define USERMOD_ST7789_DISPLAY 97
|
||||
|
||||
#ifndef TFT_DISPOFF
|
||||
#define TFT_DISPOFF 0x28
|
||||
#ifndef USER_SETUP_LOADED
|
||||
#ifndef ST7789_DRIVER
|
||||
#error Please define ST7789_DRIVER
|
||||
#endif
|
||||
#ifndef TFT_WIDTH
|
||||
#error Please define TFT_WIDTH
|
||||
#endif
|
||||
#ifndef TFT_HEIGHT
|
||||
#error Please define TFT_HEIGHT
|
||||
#endif
|
||||
#ifndef TFT_MOSI
|
||||
#error Please define TFT_MOSI
|
||||
#endif
|
||||
#ifndef TFT_SCLK
|
||||
#error Please define TFT_SCLK
|
||||
#endif
|
||||
#ifndef TFT_DC
|
||||
#error Please define TFT_DC
|
||||
#endif
|
||||
#ifndef TFT_RST
|
||||
#error Please define TFT_RST
|
||||
#endif
|
||||
#ifndef LOAD_GLCD
|
||||
#error Please define LOAD_GLCD
|
||||
#endif
|
||||
#endif
|
||||
#ifndef TFT_BL
|
||||
#define TFT_BL -1
|
||||
#endif
|
||||
|
||||
#ifndef TFT_SLPIN
|
||||
#define TFT_SLPIN 0x10
|
||||
#endif
|
||||
#define USERMOD_ID_ST7789_DISPLAY 97
|
||||
|
||||
#define TFT_MOSI 21
|
||||
#define TFT_SCLK 22
|
||||
#define TFT_DC 18
|
||||
#define TFT_RST 5
|
||||
#define TFT_BL 26 // Display backlight control pin
|
||||
TFT_eSPI tft = TFT_eSPI(TFT_WIDTH, TFT_HEIGHT); // Invoke custom library
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI(240, 240); // Invoke custom library
|
||||
// Extra char (+1) for null
|
||||
#define LINE_BUFFER_SIZE 20
|
||||
|
||||
// How often we are redrawing screen
|
||||
#define USER_LOOP_REFRESH_RATE_MS 1000
|
||||
|
||||
extern int getSignalQuality(int rssi);
|
||||
|
||||
|
||||
//class name. Use something descriptive and leave the ": public Usermod" part :)
|
||||
class St7789DisplayUsermod : public Usermod {
|
||||
@ -45,9 +66,70 @@ class St7789DisplayUsermod : public Usermod {
|
||||
uint8_t knownBrightness = 0;
|
||||
uint8_t knownMode = 0;
|
||||
uint8_t knownPalette = 0;
|
||||
uint8_t tftcharwidth = 19; // Number of chars that fit on screen with text size set to 2
|
||||
uint8_t knownEffectSpeed = 0;
|
||||
uint8_t knownEffectIntensity = 0;
|
||||
uint8_t knownMinute = 99;
|
||||
uint8_t knownHour = 99;
|
||||
|
||||
const uint8_t tftcharwidth = 19; // Number of chars that fit on screen with text size set to 2
|
||||
long lastUpdate = 0;
|
||||
|
||||
void center(String &line, uint8_t width) {
|
||||
int len = line.length();
|
||||
if (len<width) for (byte i=(width-len)/2; i>0; i--) line = ' ' + line;
|
||||
for (byte i=line.length(); i<width; i++) line += ' ';
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
if (!ntpEnabled) return;
|
||||
char lineBuffer[LINE_BUFFER_SIZE];
|
||||
|
||||
updateLocalTime();
|
||||
byte minuteCurrent = minute(localTime);
|
||||
byte hourCurrent = hour(localTime);
|
||||
byte secondCurrent = second(localTime);
|
||||
knownMinute = minuteCurrent;
|
||||
knownHour = hourCurrent;
|
||||
|
||||
byte currentMonth = month(localTime);
|
||||
sprintf_P(lineBuffer, PSTR("%s %2d "), monthShortStr(currentMonth), day(localTime));
|
||||
tft.setTextColor(TFT_SILVER);
|
||||
tft.setCursor(84, 0);
|
||||
tft.setTextSize(2);
|
||||
tft.print(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_P(lineBuffer, PSTR("%2d:%02d"), (useAMPM ? showHour : hourCurrent), minuteCurrent);
|
||||
tft.setTextColor(TFT_WHITE);
|
||||
tft.setTextSize(4);
|
||||
tft.setCursor(60, 24);
|
||||
tft.print(lineBuffer);
|
||||
|
||||
tft.setTextSize(2);
|
||||
tft.setCursor(186, 24);
|
||||
//sprintf_P(lineBuffer, PSTR("%02d"), secondCurrent);
|
||||
if (useAMPM) tft.print(isAM ? "AM" : "PM");
|
||||
//else tft.print(lineBuffer);
|
||||
}
|
||||
|
||||
public:
|
||||
//Functions called by WLED
|
||||
|
||||
@ -57,6 +139,9 @@ class St7789DisplayUsermod : public Usermod {
|
||||
*/
|
||||
void setup()
|
||||
{
|
||||
PinManagerPinType pins[] = { { TFT_MOSI, true }, { TFT_MISO, false}, { TFT_SCLK, true }, { TFT_CS, true}, { TFT_DC, true}, { TFT_RST, true }, { TFT_BL, true } };
|
||||
if (!pinManager.allocateMultiplePins(pins, 5, PinOwner::UM_FourLineDisplay)) { return; }
|
||||
|
||||
tft.init();
|
||||
tft.setRotation(0); //Rotation here is set up for the text to be readable with the port on the left. Use 1 to flip.
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
@ -65,8 +150,8 @@ class St7789DisplayUsermod : public Usermod {
|
||||
tft.setTextDatum(MC_DATUM);
|
||||
tft.setTextSize(2);
|
||||
tft.print("Loading...");
|
||||
if (TFT_BL > 0)
|
||||
{ // TFT_BL has been set in the TFT_eSPI library
|
||||
if (TFT_BL >= 0)
|
||||
{
|
||||
pinMode(TFT_BL, OUTPUT); // Set backlight pin to output mode
|
||||
digitalWrite(TFT_BL, HIGH); // Turn backlight on.
|
||||
}
|
||||
@ -91,38 +176,30 @@ class St7789DisplayUsermod : public Usermod {
|
||||
* Instead, use a timer check as shown here.
|
||||
*/
|
||||
void loop() {
|
||||
// Check if we time interval for redrawing passes.
|
||||
char buff[LINE_BUFFER_SIZE];
|
||||
|
||||
// Check if we time interval for redrawing passes.
|
||||
if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
lastUpdate = millis();
|
||||
|
||||
// Turn off display after 5 minutes with no change.
|
||||
if(!displayTurnedOff && millis() - lastRedraw > 5*60*1000)
|
||||
// Turn off display after 5 minutes with no change.
|
||||
if (!displayTurnedOff && millis() - lastRedraw > 5*60*1000)
|
||||
{
|
||||
digitalWrite(TFT_BL, LOW); // Turn backlight off.
|
||||
if (TFT_BL >= 0) digitalWrite(TFT_BL, LOW); // Turn backlight off.
|
||||
displayTurnedOff = true;
|
||||
}
|
||||
|
||||
// Check if values which are shown on display changed from the last time.
|
||||
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 (knownMode != strip.getMode())
|
||||
{
|
||||
needRedraw = true;
|
||||
}
|
||||
else if (knownPalette != strip.getSegment(0).palette)
|
||||
// Check if values which are shown on display changed from the last time.
|
||||
if ((((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) ||
|
||||
(knownIp != (apActive ? IPAddress(4, 3, 2, 1) : Network.localIP())) ||
|
||||
(knownBrightness != bri) ||
|
||||
(knownEffectSpeed != effectSpeed) ||
|
||||
(knownEffectIntensity != effectIntensity) ||
|
||||
(knownMode != strip.getMode()) ||
|
||||
(knownPalette != strip.getSegment(0).palette))
|
||||
{
|
||||
needRedraw = true;
|
||||
}
|
||||
@ -135,12 +212,12 @@ class St7789DisplayUsermod : public Usermod {
|
||||
|
||||
if (displayTurnedOff)
|
||||
{
|
||||
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); // Turn backlight on.
|
||||
digitalWrite(TFT_BL, HIGH); // Turn backlight on.
|
||||
displayTurnedOff = false;
|
||||
}
|
||||
lastRedraw = millis();
|
||||
|
||||
// Update last known values.
|
||||
// Update last known values.
|
||||
#if defined(ESP8266)
|
||||
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
|
||||
#else
|
||||
@ -150,54 +227,69 @@ class St7789DisplayUsermod : public Usermod {
|
||||
knownBrightness = bri;
|
||||
knownMode = strip.getMode();
|
||||
knownPalette = strip.getSegment(0).palette;
|
||||
knownEffectSpeed = effectSpeed;
|
||||
knownEffectIntensity = effectIntensity;
|
||||
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
tft.setTextSize(2);
|
||||
// First row with Wifi name
|
||||
tft.setTextColor(TFT_SILVER);
|
||||
tft.setCursor(3, 40);
|
||||
tft.print(knownSsid.substring(0, tftcharwidth > 1 ? tftcharwidth - 1 : 0));
|
||||
// Print `~` char to indicate that SSID is longer, than our dicplay
|
||||
if (knownSsid.length() > tftcharwidth)
|
||||
tft.print("~");
|
||||
|
||||
// Second row with AP IP and Password or IP
|
||||
showTime();
|
||||
|
||||
tft.setTextSize(2);
|
||||
|
||||
// Wifi name
|
||||
tft.setTextColor(TFT_GREEN);
|
||||
tft.setTextSize(2);
|
||||
tft.setCursor(3, 64);
|
||||
// Print AP IP and password in AP mode or knownIP if AP not active.
|
||||
tft.setCursor(0, 60);
|
||||
String line = knownSsid.substring(0, tftcharwidth-1);
|
||||
// Print `~` char to indicate that SSID is longer, than our display
|
||||
if (knownSsid.length() > tftcharwidth) line = line.substring(0, tftcharwidth-1) + '~';
|
||||
center(line, tftcharwidth);
|
||||
tft.print(line.c_str());
|
||||
|
||||
// Print AP IP and password in AP mode or knownIP if AP not active.
|
||||
if (apActive)
|
||||
{
|
||||
tft.setTextColor(TFT_YELLOW);
|
||||
tft.setCursor(0, 84);
|
||||
tft.print("AP IP: ");
|
||||
tft.print(knownIp);
|
||||
tft.setCursor(3,86);
|
||||
tft.setTextColor(TFT_YELLOW);
|
||||
tft.setCursor(0,108);
|
||||
tft.print("AP Pass:");
|
||||
tft.print(apPass);
|
||||
}
|
||||
else
|
||||
{
|
||||
tft.setTextColor(TFT_GREEN);
|
||||
tft.print("IP: ");
|
||||
tft.print(knownIp);
|
||||
tft.setCursor(3,86);
|
||||
//tft.print("Signal Strength: ");
|
||||
//tft.print(i.wifi.signal);
|
||||
tft.setCursor(0, 84);
|
||||
line = knownIp.toString();
|
||||
center(line, tftcharwidth);
|
||||
tft.print(line.c_str());
|
||||
// percent brightness
|
||||
tft.setCursor(0, 120);
|
||||
tft.setTextColor(TFT_WHITE);
|
||||
tft.print("Bri: ");
|
||||
tft.print(((float(bri)/255)*100),0);
|
||||
tft.print((((int)bri*100)/255));
|
||||
tft.print("%");
|
||||
// signal quality
|
||||
tft.setCursor(124,120);
|
||||
tft.print("Sig: ");
|
||||
if (getSignalQuality(WiFi.RSSI()) < 10) {
|
||||
tft.setTextColor(TFT_RED);
|
||||
} else if (getSignalQuality(WiFi.RSSI()) < 25) {
|
||||
tft.setTextColor(TFT_ORANGE);
|
||||
} else {
|
||||
tft.setTextColor(TFT_GREEN);
|
||||
}
|
||||
tft.print(getSignalQuality(WiFi.RSSI()));
|
||||
tft.setTextColor(TFT_WHITE);
|
||||
tft.print("%");
|
||||
}
|
||||
|
||||
// Third row with mode name
|
||||
tft.setCursor(3, 108);
|
||||
// mode name
|
||||
tft.setTextColor(TFT_CYAN);
|
||||
tft.setCursor(0, 144);
|
||||
uint8_t qComma = 0;
|
||||
bool insideQuotes = false;
|
||||
uint8_t printedChars = 0;
|
||||
char singleJsonSymbol;
|
||||
// Find the mode name in JSON
|
||||
// Find the mode name in JSON
|
||||
for (size_t i = 0; i < strlen_P(JSON_mode_names); i++)
|
||||
{
|
||||
singleJsonSymbol = pgm_read_byte_near(JSON_mode_names + i);
|
||||
@ -214,20 +306,20 @@ class St7789DisplayUsermod : public Usermod {
|
||||
default:
|
||||
if (!insideQuotes || (qComma != knownMode))
|
||||
break;
|
||||
tft.setTextColor(TFT_MAGENTA);
|
||||
tft.print(singleJsonSymbol);
|
||||
printedChars++;
|
||||
}
|
||||
if ((qComma > knownMode) || (printedChars > tftcharwidth - 1))
|
||||
break;
|
||||
}
|
||||
// Fourth row with palette name
|
||||
|
||||
// palette name
|
||||
tft.setTextColor(TFT_YELLOW);
|
||||
tft.setCursor(3, 130);
|
||||
tft.setCursor(0, 168);
|
||||
qComma = 0;
|
||||
insideQuotes = false;
|
||||
printedChars = 0;
|
||||
// Looking for palette name in JSON.
|
||||
// Looking for palette name in JSON.
|
||||
for (size_t i = 0; i < strlen_P(JSON_palette_names); i++)
|
||||
{
|
||||
singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i);
|
||||
@ -247,18 +339,26 @@ class St7789DisplayUsermod : public Usermod {
|
||||
tft.print(singleJsonSymbol);
|
||||
printedChars++;
|
||||
}
|
||||
// The following is modified from the code from the u8g2/u8g8 based code (knownPalette was knownMode)
|
||||
// The following is modified from the code from the u8g2/u8g8 based code (knownPalette was knownMode)
|
||||
if ((qComma > knownPalette) || (printedChars > tftcharwidth - 1))
|
||||
break;
|
||||
}
|
||||
// Fifth row with estimated mA usage
|
||||
|
||||
tft.setCursor(0, 192);
|
||||
tft.setTextColor(TFT_SILVER);
|
||||
tft.setCursor(3, 152);
|
||||
// Print estimated milliamp usage (must specify the LED type in LED prefs for this to be a reasonable estimate).
|
||||
sprintf_P(buff, PSTR("FX Spd:%3d Int:%3d"), effectSpeed, effectIntensity);
|
||||
tft.print(buff);
|
||||
|
||||
// Fifth row with estimated mA usage
|
||||
tft.setTextColor(TFT_SILVER);
|
||||
tft.setCursor(0, 216);
|
||||
// Print estimated milliamp usage (must specify the LED type in LED prefs for this to be a reasonable estimate).
|
||||
tft.print("Current: ");
|
||||
tft.setTextColor(TFT_ORANGE);
|
||||
tft.print(strip.currentMilliamps);
|
||||
tft.print("mA");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
@ -295,7 +395,7 @@ class St7789DisplayUsermod : public Usermod {
|
||||
*/
|
||||
void readFromJsonState(JsonObject& root)
|
||||
{
|
||||
userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
|
||||
//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!"));
|
||||
}
|
||||
|
||||
@ -316,8 +416,8 @@ class St7789DisplayUsermod : public Usermod {
|
||||
*/
|
||||
void addToConfig(JsonObject& root)
|
||||
{
|
||||
JsonObject top = root.createNestedObject("exampleUsermod");
|
||||
top["great"] = userVar0; //save this var persistently whenever settings are saved
|
||||
//JsonObject top = root.createNestedObject("exampleUsermod");
|
||||
//top["great"] = userVar0; //save this var persistently whenever settings are saved
|
||||
}
|
||||
|
||||
|
||||
@ -329,10 +429,11 @@ class St7789DisplayUsermod : public Usermod {
|
||||
* 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)
|
||||
bool readFromConfig(JsonObject& root)
|
||||
{
|
||||
JsonObject top = root["top"];
|
||||
userVar0 = top["great"] | 42; //The value right of the pipe "|" is the default value in case your setting was not present in cfg.json (e.g. first boot)
|
||||
//JsonObject top = root["top"];
|
||||
//userVar0 = top["great"] | 42; //The value right of the pipe "|" is the default value in case your setting was not present in cfg.json (e.g. first boot)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -342,7 +443,7 @@ class St7789DisplayUsermod : public Usermod {
|
||||
*/
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ST7789_DISPLAY;
|
||||
return USERMOD_ID_ST7789_DISPLAY;
|
||||
}
|
||||
|
||||
//More methods can be added in the future, this example will then be extended.
|
||||
|
@ -1,39 +0,0 @@
|
||||
// Setup for the ESP32 board with 1.5" 240x240 display
|
||||
|
||||
// See SetupX_Template.h for all options available
|
||||
|
||||
#define ST7789_DRIVER
|
||||
#define TFT_SDA_READ // Display has a bidirectionsl SDA pin
|
||||
|
||||
#define TFT_WIDTH 240
|
||||
#define TFT_HEIGHT 240
|
||||
|
||||
#define CGRAM_OFFSET // Library will add offsets required
|
||||
|
||||
//#define TFT_MISO -1
|
||||
|
||||
#define TFT_MOSI 21
|
||||
#define TFT_SCLK 22
|
||||
//#define TFT_CS 5
|
||||
#define TFT_DC 18
|
||||
#define TFT_RST 5
|
||||
|
||||
#define TFT_BL 26 // Display backlight control pin
|
||||
|
||||
#define TFT_BACKLIGHT_ON HIGH // HIGH or LOW are options
|
||||
|
||||
#define LOAD_GLCD
|
||||
#define LOAD_FONT2
|
||||
#define LOAD_FONT4
|
||||
#define LOAD_FONT6
|
||||
#define LOAD_FONT7
|
||||
#define LOAD_FONT8
|
||||
#define LOAD_GFXFF
|
||||
|
||||
//#define SMOOTH_FONT
|
||||
|
||||
//#define SPI_FREQUENCY 27000000
|
||||
#define SPI_FREQUENCY 40000000 // Maximum for ILI9341
|
||||
|
||||
|
||||
#define SPI_READ_FREQUENCY 6000000 // 6 MHz is the maximum SPI read speed for the ST7789V
|
@ -81,7 +81,9 @@ class UsermodTemperature : public Usermod {
|
||||
temperature = readDallas();
|
||||
lastMeasurement = millis();
|
||||
waitingForConversion = false;
|
||||
DEBUG_PRINTF("Read temperature %2.1f.\n", temperature);
|
||||
//DEBUG_PRINTF("Read temperature %2.1f.\n", temperature); // does not work properly on 8266
|
||||
DEBUG_PRINT(F("Read temperature "));
|
||||
DEBUG_PRINTLN(temperature);
|
||||
}
|
||||
|
||||
bool findSensor() {
|
||||
|
@ -1,15 +0,0 @@
|
||||
WLED v2 UserMod for running macros at sunrise and sunset.
|
||||
|
||||
At the time of this text, this user mod requires code to be changed to set certain variables:
|
||||
1. To reflect the user's graphical location (latitude/longitude) used for calculating apparent sunrise/sunset
|
||||
2. To specify which macros will be run at sunrise and/or sunset. (defaults to 15 at sunrise and 16 at sunset)
|
||||
3. To optionally provide an offset from sunrise/sunset, in minutes (max of +/- 2 hours), when the macro will be run.
|
||||
|
||||
In addition, WLED must be configured to get time from NTP (and the time must be retrieved via NTP.)
|
||||
|
||||
Please open the UserMod_SunRiseAndSet.h file for instructions on what needs to be changed, where to copy files, etc.
|
||||
|
||||
If this usermod proves useful enough, the code might eventually be updated to allow prompting for the required information
|
||||
via the web interface and to store settings in EEPROM instead of hard-coding in the .h file.
|
||||
|
||||
This usermod has only been tested on the esp32dev platform, but there's no reason it wouldn't work on other platforms.
|
@ -1,166 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include <Dusk2Dawn.h>
|
||||
|
||||
/*
|
||||
*
|
||||
* REQUIREMENTS:
|
||||
* The Dusk2Dawn library must be installed. This can be found at https://github.com/dmkishi/Dusk2Dawn. The 1.0.1 version of this library found via
|
||||
* Arduino or platformio library managers is buggy and won't compile. The latest version from github should be used.
|
||||
*
|
||||
* NTP must be enabled and functional. It simply makes no sense to have events on sunrise/sunset when an accurate time isn't available.
|
||||
*
|
||||
* The user's geographical latitude and longitude must be configured (in decimal, not degrees/minutes/etc) using m_fLatitude and m_fLongitude
|
||||
*
|
||||
* if desired, an offset of up to +/- 2 hours can be specified for each of sunrise/sunset using m_sunriseOffset and m_sunsetOffset (defaults to 0)
|
||||
*
|
||||
* The specific macro to run at sunrise and/or sunset can be changed using m_sunriseMacro and m_sunsetMacro. (defaults to 15 and 16)
|
||||
*
|
||||
* From the Dusk2Dawn library:
|
||||
* HINT: An easy way to find the longitude and latitude for any location is
|
||||
* to find the spot in Google Maps, right click the place on the map, and
|
||||
* select "What's here?". At the bottom, you’ll see a card with the
|
||||
* coordinates.
|
||||
*
|
||||
* Once configured, copy UserMod_SunRiseAndSet.h to the sketch file (the same folder as wled00.ino exists),
|
||||
* and then edit "usermods_list.cpp":
|
||||
* Add '#include "UserMod_SunRiseAndSet.h"' in the 'includes' area
|
||||
* Add 'usermods.add(new UserMod_SunRiseAndSet());' in the registerUsermods() area
|
||||
*
|
||||
*/
|
||||
|
||||
class UserMod_SunRiseAndSet : public Usermod
|
||||
{
|
||||
private:
|
||||
|
||||
/**** USER SETTINGS ****/
|
||||
|
||||
float m_fLatitude = 40.6; // latitude where sunrise/set are calculated
|
||||
float m_fLongitude = -79.80; // longitude where sunrise/set are calculated
|
||||
int8_t m_sunriseOffset = 0; // offset from sunrise, in minutes, when macro should be run (negative for before sunrise, positive for after sunrise)
|
||||
int8_t m_sunsetOffset = 0; // offset from sunset, in minutes, when macro should be run (negative for before sunset, positive for after sunset)
|
||||
uint8_t m_sunriseMacro = 15; // macro number to run at sunrise
|
||||
uint8_t m_sunsetMacro = 16; // macro number to run at sunset
|
||||
|
||||
/**** END OF USER SETTINGS. DO NOT EDIT BELOW THIS LINE! ****/
|
||||
|
||||
|
||||
Dusk2Dawn *m_pD2D = NULL; // this must be dynamically allocated in order for parameters to be loaded from EEPROM
|
||||
|
||||
int m_nUserSunrise = -1; // time, in minutes from midnight, of sunrise
|
||||
int m_nUserSunset = -1; // time, in minutes from midnight, of sunset
|
||||
|
||||
byte m_nLastRunMinute = -1; // indicates what minute the userloop was last run - used so that the code only runs once per minute
|
||||
|
||||
public:
|
||||
|
||||
virtual void setup(void)
|
||||
{
|
||||
/* TODO: From EEPROM, load the following variables:
|
||||
*
|
||||
* int16_t latitude16 = 4060; // user provided latitude, multiplied by 100 and rounded
|
||||
* int16_t longitude16 = -7980; // user provided longitude, multiplied by 100 and rounded.
|
||||
* int8_t sunrise_offset = 0; // number of minutes to offset the sunrise macro trigger (positive for minutes after sunrise, negative for minutes before)
|
||||
* int8_t sunset_offset = 0; // number of minutes to offset the sunset macro trigger (positive for minutes after sunset, negative for minutes before)
|
||||
*
|
||||
* then:
|
||||
* m_fLatitude = (float)latitude / 100.0;
|
||||
* m_fLongitude = (float)longitude / 100.0;
|
||||
* m_sunriseOffset = sunrise_offset;
|
||||
* m_sunsetOffset = sunset_offset;
|
||||
*/
|
||||
|
||||
if ((0.0 != m_fLatitude) || (0.0 != m_fLongitude))
|
||||
{
|
||||
m_pD2D = new Dusk2Dawn (m_fLatitude, m_fLongitude, 0 /* UTC */);
|
||||
// can't really check for failures. if the alloc fails, the mod just doesn't work.
|
||||
}
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
// without NTP, or a configured lat/long, none of this stuff is going to work...
|
||||
// As an alternative, need to figure out how to determine if the user has manually set the clock or not.
|
||||
if (m_pD2D && (999000000L != ntpLastSyncTime))
|
||||
{
|
||||
// to prevent needing to import all the timezone stuff from other modules, work completely in UTC
|
||||
time_t timeUTC = toki.second();
|
||||
tmElements_t tmNow;
|
||||
breakTime(timeUTC, tmNow);
|
||||
int nCurMinute = tmNow.Minute;
|
||||
|
||||
if (m_nLastRunMinute != nCurMinute) //only check once a new minute begins
|
||||
{
|
||||
m_nLastRunMinute = nCurMinute;
|
||||
int numMinutes = (60 * tmNow.Hour) + m_nLastRunMinute; // how many minutes into the day are we?
|
||||
|
||||
// check to see if sunrise/sunset should be re-determined. Only do this if neither sunrise nor sunset
|
||||
// are set. That happens when the device has just stated, and after both sunrise/sunset have already run.
|
||||
if ((-1 == m_nUserSunrise) && (-1 == m_nUserSunset))
|
||||
{
|
||||
m_nUserSunrise = m_pD2D->sunrise(tmNow.Year + 1970, tmNow.Month, tmNow.Day, false) % 1440;
|
||||
m_nUserSunset = m_pD2D->sunset(tmNow.Year + 1970, tmNow.Month, tmNow.Day, false) % 1440;
|
||||
if (m_nUserSunrise > numMinutes) // has sunrise already passed? if so, recompute for tomorrow
|
||||
{
|
||||
breakTime(timeUTC + (60*60*24), tmNow);
|
||||
m_nUserSunrise = m_pD2D->sunrise(tmNow.Year + 1970, tmNow.Month, tmNow.Day, false) % 1440;
|
||||
if (m_nUserSunset > numMinutes) // if sunset has also passed, recompute that as well
|
||||
{
|
||||
m_nUserSunset = m_pD2D->sunset(tmNow.Year + 1970, tmNow.Month, tmNow.Day, false) % 1440;
|
||||
}
|
||||
}
|
||||
// offset by user provided values. becuase the offsets are signed bytes, the max offset is just over 2 hours.
|
||||
m_nUserSunrise += m_sunriseOffset;
|
||||
m_nUserSunset += m_sunsetOffset;
|
||||
}
|
||||
|
||||
if (numMinutes == m_nUserSunrise) // Good Morning!
|
||||
{
|
||||
if (m_sunriseMacro)
|
||||
applyMacro(m_sunriseMacro); // run macro 15
|
||||
m_nUserSunrise = -1;
|
||||
}
|
||||
else if (numMinutes == m_nUserSunset) // Good Night!
|
||||
{
|
||||
if (m_sunsetMacro)
|
||||
applyMacro(m_sunsetMacro); // run macro 16
|
||||
m_nUserSunset = -1;
|
||||
}
|
||||
} // if (m_nLastRunMinute != nCurMinute)
|
||||
} // if (m_pD2D && (999000000L != ntpLastSyncTime))
|
||||
}
|
||||
|
||||
void addToJsonState(JsonObject& root)
|
||||
{
|
||||
JsonObject user = root["SunRiseAndSet"];
|
||||
if (user.isNull()) user = root.createNestedObject("SunRiseAndSet");
|
||||
|
||||
char buf[10];
|
||||
if (-1 != m_nUserSunrise)
|
||||
{
|
||||
snprintf(buf, 10, "%02d:%02d UTC", m_nUserSunrise / 60, m_nUserSunrise % 60);
|
||||
user["rise"] = buf;
|
||||
}
|
||||
if (-1 != m_nUserSunset)
|
||||
{
|
||||
snprintf(buf, 10, "%02d:%02d UTC", m_nUserSunset / 60, m_nUserSunset % 60);
|
||||
user["set"] = buf;
|
||||
}
|
||||
JsonObject vars = user.createNestedObject("vars");
|
||||
vars["lat"] = m_fLatitude;
|
||||
vars["long"] = m_fLongitude;
|
||||
vars["rise_mac"] = m_sunriseMacro;
|
||||
vars["set_mac"] = m_sunsetMacro;
|
||||
vars["rise_off"] = m_sunriseOffset;
|
||||
vars["set_off"] = m_sunsetOffset;
|
||||
}
|
||||
|
||||
~UserMod_SunRiseAndSet(void)
|
||||
{
|
||||
if (m_pD2D) delete m_pD2D;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,515 +0,0 @@
|
||||
//this code is a modified version of https://github.com/Makuna/NeoPixelBus/issues/103
|
||||
#ifndef NpbWrapper_h
|
||||
#define NpbWrapper_h
|
||||
|
||||
// make sure we're using esp32 platform
|
||||
#ifndef ARDUINO_ARCH_ESP32
|
||||
#error This version of NbpWrapper.h only works with ESP32 hardware.
|
||||
#endif
|
||||
|
||||
#ifndef NUM_STRIPS
|
||||
#error Need to define number of LED strips using build flag -D NUM_STRIPS=4 for 4 LED strips
|
||||
#endif
|
||||
|
||||
#ifndef PIXEL_COUNTS
|
||||
#error Need to define pixel counts using build flag -D PIXEL_COUNTS="25, 25, 25, 25" for 4 LED strips with 25 LEDs each
|
||||
#endif
|
||||
|
||||
#ifndef DATA_PINS
|
||||
#error Need to define data pins using build flag -D DATA_PINS="1, 2, 3, 4" if LED strips are on data pins 1, 2, 3, and 4
|
||||
#endif
|
||||
|
||||
// //PIN CONFIGURATION
|
||||
#ifndef LEDPIN
|
||||
#define LEDPIN 1 // Legacy pin def required by some other portions of code. This pin is not used do drive LEDs.
|
||||
#endif
|
||||
|
||||
#ifndef IRPIN
|
||||
#define IRPIN -1 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0
|
||||
#endif
|
||||
|
||||
#ifndef RLYPIN
|
||||
#define RLYPIN -1 //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
|
||||
|
||||
#include <NeoPixelBrightnessBus.h>
|
||||
#include "const.h"
|
||||
|
||||
const uint8_t numStrips = NUM_STRIPS; // max 8 strips allowed on esp32
|
||||
const uint16_t pixelCounts[numStrips] = {PIXEL_COUNTS}; // number of pixels on each strip
|
||||
const uint8_t dataPins[numStrips] = {DATA_PINS}; // change these pins based on your board
|
||||
|
||||
#define PIXELFEATURE3 NeoGrbFeature
|
||||
#define PIXELFEATURE4 NeoGrbwFeature
|
||||
|
||||
// ESP32 has 8 RMT interfaces available, each of which can drive a strip of pixels
|
||||
// Convenience #defines for creating NeoPixelBrightnessBus on each RMT interface for both GRB and GRBW LED strips
|
||||
#define NeoPixelBrightnessBusGrbRmt0 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt0Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt1 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt1Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt2 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt2Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt3 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt3Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt4 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt4Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt5 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt5Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt6 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt6Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt7 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt7Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt0 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt0Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt1 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt1Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt2 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt2Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt3 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt3Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt4 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt4Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt5 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt5Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt6 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt6Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt7 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt7Ws2812xMethod>
|
||||
|
||||
enum NeoPixelType
|
||||
{
|
||||
NeoPixelType_None = 0,
|
||||
NeoPixelType_Grb = 1,
|
||||
NeoPixelType_Grbw = 2,
|
||||
NeoPixelType_End = 3
|
||||
};
|
||||
|
||||
class NeoPixelWrapper
|
||||
{
|
||||
public:
|
||||
NeoPixelWrapper() :
|
||||
_type(NeoPixelType_None)
|
||||
{
|
||||
// On initialization fill in the pixelStripStartIdx array with the beginning index of each strip
|
||||
// relative to th entire array.
|
||||
uint16_t totalPixels = 0;
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
pixelStripStartIdx[idx] = totalPixels;
|
||||
totalPixels += pixelCounts[idx];
|
||||
}
|
||||
}
|
||||
|
||||
~NeoPixelWrapper()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void Begin(NeoPixelType type, uint16_t pixelCount)
|
||||
{
|
||||
|
||||
cleanup();
|
||||
|
||||
_type = type;
|
||||
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrb0 = new NeoPixelBrightnessBusGrbRmt0(pixelCounts[idx], dataPins[idx]); pGrb0->Begin(); break;
|
||||
case 1: pGrb1 = new NeoPixelBrightnessBusGrbRmt1(pixelCounts[idx], dataPins[idx]); pGrb1->Begin(); break;
|
||||
case 2: pGrb2 = new NeoPixelBrightnessBusGrbRmt2(pixelCounts[idx], dataPins[idx]); pGrb2->Begin(); break;
|
||||
case 3: pGrb3 = new NeoPixelBrightnessBusGrbRmt3(pixelCounts[idx], dataPins[idx]); pGrb3->Begin(); break;
|
||||
case 4: pGrb4 = new NeoPixelBrightnessBusGrbRmt4(pixelCounts[idx], dataPins[idx]); pGrb4->Begin(); break;
|
||||
case 5: pGrb5 = new NeoPixelBrightnessBusGrbRmt5(pixelCounts[idx], dataPins[idx]); pGrb5->Begin(); break;
|
||||
case 6: pGrb6 = new NeoPixelBrightnessBusGrbRmt6(pixelCounts[idx], dataPins[idx]); pGrb6->Begin(); break;
|
||||
case 7: pGrb7 = new NeoPixelBrightnessBusGrbRmt7(pixelCounts[idx], dataPins[idx]); pGrb7->Begin(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrbw0 = new NeoPixelBrightnessBusGrbwRmt0(pixelCounts[idx], dataPins[idx]); pGrbw0->Begin(); break;
|
||||
case 1: pGrbw1 = new NeoPixelBrightnessBusGrbwRmt1(pixelCounts[idx], dataPins[idx]); pGrbw1->Begin(); break;
|
||||
case 2: pGrbw2 = new NeoPixelBrightnessBusGrbwRmt2(pixelCounts[idx], dataPins[idx]); pGrbw2->Begin(); break;
|
||||
case 3: pGrbw3 = new NeoPixelBrightnessBusGrbwRmt3(pixelCounts[idx], dataPins[idx]); pGrbw3->Begin(); break;
|
||||
case 4: pGrbw4 = new NeoPixelBrightnessBusGrbwRmt4(pixelCounts[idx], dataPins[idx]); pGrbw4->Begin(); break;
|
||||
case 5: pGrbw5 = new NeoPixelBrightnessBusGrbwRmt5(pixelCounts[idx], dataPins[idx]); pGrbw5->Begin(); break;
|
||||
case 6: pGrbw6 = new NeoPixelBrightnessBusGrbwRmt6(pixelCounts[idx], dataPins[idx]); pGrbw6->Begin(); break;
|
||||
case 7: pGrbw7 = new NeoPixelBrightnessBusGrbwRmt7(pixelCounts[idx], dataPins[idx]); pGrbw7->Begin(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Show()
|
||||
{
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrb0->Show(); break;
|
||||
case 1: pGrb1->Show(); break;
|
||||
case 2: pGrb2->Show(); break;
|
||||
case 3: pGrb3->Show(); break;
|
||||
case 4: pGrb4->Show(); break;
|
||||
case 5: pGrb5->Show(); break;
|
||||
case 6: pGrb6->Show(); break;
|
||||
case 7: pGrb7->Show(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrbw0->Show(); break;
|
||||
case 1: pGrbw1->Show(); break;
|
||||
case 2: pGrbw2->Show(); break;
|
||||
case 3: pGrbw3->Show(); break;
|
||||
case 4: pGrbw4->Show(); break;
|
||||
case 5: pGrbw5->Show(); break;
|
||||
case 6: pGrbw6->Show(); break;
|
||||
case 7: pGrbw7->Show(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CanShow()
|
||||
{
|
||||
bool canShow = true;
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: canShow &= pGrb0->CanShow(); break;
|
||||
case 1: canShow &= pGrb1->CanShow(); break;
|
||||
case 2: canShow &= pGrb2->CanShow(); break;
|
||||
case 3: canShow &= pGrb3->CanShow(); break;
|
||||
case 4: canShow &= pGrb4->CanShow(); break;
|
||||
case 5: canShow &= pGrb5->CanShow(); break;
|
||||
case 6: canShow &= pGrb6->CanShow(); break;
|
||||
case 7: canShow &= pGrb7->CanShow(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: canShow &= pGrbw0->CanShow(); break;
|
||||
case 1: canShow &= pGrbw1->CanShow(); break;
|
||||
case 2: canShow &= pGrbw2->CanShow(); break;
|
||||
case 3: canShow &= pGrbw3->CanShow(); break;
|
||||
case 4: canShow &= pGrbw4->CanShow(); break;
|
||||
case 5: canShow &= pGrbw5->CanShow(); break;
|
||||
case 6: canShow &= pGrbw6->CanShow(); break;
|
||||
case 7: canShow &= pGrbw7->CanShow(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return canShow;
|
||||
}
|
||||
|
||||
void SetPixelColorRaw(uint16_t indexPixel, RgbwColor c)
|
||||
{
|
||||
// figure out which strip this pixel index is on
|
||||
uint8_t stripIdx = 0;
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
if (indexPixel >= pixelStripStartIdx[idx])
|
||||
{
|
||||
stripIdx = idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// subtract strip start index so we're addressing just this strip instead of all pixels on all strips
|
||||
indexPixel -= pixelStripStartIdx[stripIdx];
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
RgbColor rgb = RgbColor(c.R, c.G, c.B);
|
||||
switch (stripIdx)
|
||||
{
|
||||
case 0: pGrb0->SetPixelColor(indexPixel, rgb); break;
|
||||
case 1: pGrb1->SetPixelColor(indexPixel, rgb); break;
|
||||
case 2: pGrb2->SetPixelColor(indexPixel, rgb); break;
|
||||
case 3: pGrb3->SetPixelColor(indexPixel, rgb); break;
|
||||
case 4: pGrb4->SetPixelColor(indexPixel, rgb); break;
|
||||
case 5: pGrb5->SetPixelColor(indexPixel, rgb); break;
|
||||
case 6: pGrb6->SetPixelColor(indexPixel, rgb); break;
|
||||
case 7: pGrb7->SetPixelColor(indexPixel, rgb); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
switch (stripIdx)
|
||||
{
|
||||
case 0: pGrbw0->SetPixelColor(indexPixel, c); break;
|
||||
case 1: pGrbw1->SetPixelColor(indexPixel, c); break;
|
||||
case 2: pGrbw2->SetPixelColor(indexPixel, c); break;
|
||||
case 3: pGrbw3->SetPixelColor(indexPixel, c); break;
|
||||
case 4: pGrbw4->SetPixelColor(indexPixel, c); break;
|
||||
case 5: pGrbw5->SetPixelColor(indexPixel, c); break;
|
||||
case 6: pGrbw6->SetPixelColor(indexPixel, c); break;
|
||||
case 7: pGrbw7->SetPixelColor(indexPixel, c); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetPixelColor(uint16_t indexPixel, RgbwColor c)
|
||||
{
|
||||
/*
|
||||
Set pixel color with necessary color order conversion.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
SetPixelColorRaw(indexPixel, col);
|
||||
}
|
||||
|
||||
void SetBrightness(byte b)
|
||||
{
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrb0->SetBrightness(b); break;
|
||||
case 1: pGrb1->SetBrightness(b); break;
|
||||
case 2: pGrb2->SetBrightness(b); break;
|
||||
case 3: pGrb3->SetBrightness(b); break;
|
||||
case 4: pGrb4->SetBrightness(b); break;
|
||||
case 5: pGrb5->SetBrightness(b); break;
|
||||
case 6: pGrb6->SetBrightness(b); break;
|
||||
case 7: pGrb7->SetBrightness(b); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrbw0->SetBrightness(b); break;
|
||||
case 1: pGrbw1->SetBrightness(b); break;
|
||||
case 2: pGrbw2->SetBrightness(b); break;
|
||||
case 3: pGrbw3->SetBrightness(b); break;
|
||||
case 4: pGrbw4->SetBrightness(b); break;
|
||||
case 5: pGrbw5->SetBrightness(b); break;
|
||||
case 6: pGrbw6->SetBrightness(b); break;
|
||||
case 7: pGrbw7->SetBrightness(b); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetColorOrder(byte colorOrder)
|
||||
{
|
||||
_colorOrder = colorOrder;
|
||||
}
|
||||
|
||||
uint8_t GetColorOrder()
|
||||
{
|
||||
return _colorOrder;
|
||||
}
|
||||
|
||||
RgbwColor GetPixelColorRaw(uint16_t indexPixel) const
|
||||
{
|
||||
// figure out which strip this pixel index is on
|
||||
uint8_t stripIdx = 0;
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
if (indexPixel >= pixelStripStartIdx[idx])
|
||||
{
|
||||
stripIdx = idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// subtract strip start index so we're addressing just this strip instead of all pixels on all strips
|
||||
indexPixel -= pixelStripStartIdx[stripIdx];
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
switch (stripIdx)
|
||||
{
|
||||
case 0: return pGrb0->GetPixelColor(indexPixel);
|
||||
case 1: return pGrb1->GetPixelColor(indexPixel);
|
||||
case 2: return pGrb2->GetPixelColor(indexPixel);
|
||||
case 3: return pGrb3->GetPixelColor(indexPixel);
|
||||
case 4: return pGrb4->GetPixelColor(indexPixel);
|
||||
case 5: return pGrb5->GetPixelColor(indexPixel);
|
||||
case 6: return pGrb6->GetPixelColor(indexPixel);
|
||||
case 7: return pGrb7->GetPixelColor(indexPixel);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
switch (stripIdx)
|
||||
{
|
||||
case 0: return pGrbw0->GetPixelColor(indexPixel);
|
||||
case 1: return pGrbw1->GetPixelColor(indexPixel);
|
||||
case 2: return pGrbw2->GetPixelColor(indexPixel);
|
||||
case 3: return pGrbw3->GetPixelColor(indexPixel);
|
||||
case 4: return pGrbw4->GetPixelColor(indexPixel);
|
||||
case 5: return pGrbw5->GetPixelColor(indexPixel);
|
||||
case 6: return pGrbw6->GetPixelColor(indexPixel);
|
||||
case 7: return pGrbw7->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 = GetPixelColorRaw(indexPixel);
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
NeoPixelType _type;
|
||||
byte _colorOrder = 0;
|
||||
|
||||
uint16_t pixelStripStartIdx[numStrips];
|
||||
|
||||
// pointers for every possible type for up to 8 strips
|
||||
NeoPixelBrightnessBusGrbRmt0 *pGrb0;
|
||||
NeoPixelBrightnessBusGrbRmt1 *pGrb1;
|
||||
NeoPixelBrightnessBusGrbRmt2 *pGrb2;
|
||||
NeoPixelBrightnessBusGrbRmt3 *pGrb3;
|
||||
NeoPixelBrightnessBusGrbRmt4 *pGrb4;
|
||||
NeoPixelBrightnessBusGrbRmt5 *pGrb5;
|
||||
NeoPixelBrightnessBusGrbRmt6 *pGrb6;
|
||||
NeoPixelBrightnessBusGrbRmt7 *pGrb7;
|
||||
NeoPixelBrightnessBusGrbwRmt0 *pGrbw0;
|
||||
NeoPixelBrightnessBusGrbwRmt1 *pGrbw1;
|
||||
NeoPixelBrightnessBusGrbwRmt2 *pGrbw2;
|
||||
NeoPixelBrightnessBusGrbwRmt3 *pGrbw3;
|
||||
NeoPixelBrightnessBusGrbwRmt4 *pGrbw4;
|
||||
NeoPixelBrightnessBusGrbwRmt5 *pGrbw5;
|
||||
NeoPixelBrightnessBusGrbwRmt6 *pGrbw6;
|
||||
NeoPixelBrightnessBusGrbwRmt7 *pGrbw7;
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: delete pGrb0; pGrb0 = NULL; break;
|
||||
case 1: delete pGrb1; pGrb1 = NULL; break;
|
||||
case 2: delete pGrb2; pGrb2 = NULL; break;
|
||||
case 3: delete pGrb3; pGrb3 = NULL; break;
|
||||
case 4: delete pGrb4; pGrb4 = NULL; break;
|
||||
case 5: delete pGrb5; pGrb5 = NULL; break;
|
||||
case 6: delete pGrb6; pGrb6 = NULL; break;
|
||||
case 7: delete pGrb7; pGrb7 = NULL; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: delete pGrbw0; pGrbw0 = NULL; break;
|
||||
case 1: delete pGrbw1; pGrbw1 = NULL; break;
|
||||
case 2: delete pGrbw2; pGrbw2 = NULL; break;
|
||||
case 3: delete pGrbw3; pGrbw3 = NULL; break;
|
||||
case 4: delete pGrbw4; pGrbw4 = NULL; break;
|
||||
case 5: delete pGrbw5; pGrbw5 = NULL; break;
|
||||
case 6: delete pGrbw6; pGrbw6 = NULL; break;
|
||||
case 7: delete pGrbw7; pGrbw7 = NULL; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
@ -1,22 +0,0 @@
|
||||
# esp32_multistrip
|
||||
|
||||
This usermod enables up to 8 data pins to be used from an esp32 module to drive separate LED strands. This only works with one-wire LEDs like the WS2812.
|
||||
|
||||
The esp32 RMT hardware is used for data output. See here for hardware driver implementation details: https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods
|
||||
|
||||
Pass the following variables to the compiler as build flags:
|
||||
|
||||
- `ESP32_MULTISTRIP`
|
||||
- Define this to use usermod NpbWrapper.h instead of default one in WLED.
|
||||
- `NUM_STRIPS`
|
||||
- Number of strips in use
|
||||
- `PIXEL_COUNTS`
|
||||
- List of pixel counts in each strip
|
||||
- `DATA_PINS`
|
||||
- List of data pins each strip is attached to. There may be board-specific restrictions on which pins can be used for RTM.
|
||||
|
||||
From the perspective of WLED software, the LEDs are addressed as one long strand. The modified NbpWrapper.h file addresses the appropriate strand from the overall LED index based on the number of LEDs defined in each strand.
|
||||
|
||||
See `platformio_override.ini` for example configuration.
|
||||
|
||||
Tested on low cost ESP-WROOM-32 dev boards from Amazon, such as those sold by KeeYees.
|
@ -1,16 +0,0 @@
|
||||
; Example platformio_override.ini that shows how to configure your environment to use the multistrip usermod.
|
||||
; Copy this file to the base wled directory that contains platformio.ini.
|
||||
; Multistrip requires ESP32 because it has many more pins that can be used as LED outputs.
|
||||
; Need to define NUM_STRIPS, PIXEL_COUNTS, and DATA_PINS as shown below.
|
||||
|
||||
[platformio]
|
||||
default_envs = esp32_multistrip
|
||||
|
||||
[env:esp32_multistrip]
|
||||
extends=env:esp32dev
|
||||
build_flags = ${env:esp32dev.build_flags}
|
||||
-D ESP32_MULTISTRIP ; define this variable to use ESP32_MULTISTRIP usermod
|
||||
-D NUM_STRIPS=4 ; number of pixel strips in use
|
||||
-D PIXEL_COUNTS="50, 50, 50, 50" ; number of pixels in each strip
|
||||
-D DATA_PINS="25, 26, 32, 33" ; esp32 pins used for each pixel strip. available pins depends on esp32 module.
|
||||
|
@ -317,15 +317,15 @@ class MultiRelay : public Usermod {
|
||||
* 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) {
|
||||
}
|
||||
//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) {
|
||||
}
|
||||
//void readFromJsonState(JsonObject &root) {
|
||||
//}
|
||||
|
||||
/**
|
||||
* provide the changeable values
|
||||
@ -335,11 +335,12 @@ class MultiRelay : public Usermod {
|
||||
|
||||
top[FPSTR(_enabled)] = enabled;
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
String parName = FPSTR(_relay_str); parName += "-"; parName += i; parName += "-";
|
||||
top[parName+"pin"] = _relay[i].pin;
|
||||
top[parName+FPSTR(_activeHigh)] = _relay[i].mode;
|
||||
top[parName+FPSTR(_delay_str)] = _relay[i].delay;
|
||||
top[parName+FPSTR(_external)] = _relay[i].external;
|
||||
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
||||
JsonObject relay = top.createNestedObject(parName);
|
||||
relay["pin"] = _relay[i].pin;
|
||||
relay[FPSTR(_activeHigh)] = _relay[i].mode;
|
||||
relay[FPSTR(_delay_str)] = _relay[i].delay;
|
||||
relay[FPSTR(_external)] = _relay[i].external;
|
||||
}
|
||||
DEBUG_PRINTLN(F("MultiRelay config saved."));
|
||||
}
|
||||
@ -363,12 +364,19 @@ class MultiRelay : public Usermod {
|
||||
enabled = top[FPSTR(_enabled)] | enabled;
|
||||
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
String parName = FPSTR(_relay_str); parName += "-"; parName += i; parName += "-";
|
||||
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
||||
oldPin[i] = _relay[i].pin;
|
||||
_relay[i].pin = top[parName]["pin"] | _relay[i].pin;
|
||||
_relay[i].mode = top[parName][FPSTR(_activeHigh)] | _relay[i].mode;
|
||||
_relay[i].external = top[parName][FPSTR(_external)] | _relay[i].external;
|
||||
_relay[i].delay = top[parName][FPSTR(_delay_str)] | _relay[i].delay;
|
||||
// begin backwards compatibility (beta) remove when 0.13 is released
|
||||
parName += '-';
|
||||
_relay[i].pin = top[parName+"pin"] | _relay[i].pin;
|
||||
_relay[i].mode = top[parName+FPSTR(_activeHigh)] | _relay[i].mode;
|
||||
_relay[i].external = top[parName+FPSTR(_external)] | _relay[i].external;
|
||||
_relay[i].delay = top[parName+FPSTR(_delay_str)] | _relay[i].delay;
|
||||
// end compatibility
|
||||
_relay[i].delay = min(600,max(0,abs((int)_relay[i].delay))); // bounds checking max 10min
|
||||
}
|
||||
|
||||
@ -396,7 +404,7 @@ class MultiRelay : public Usermod {
|
||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||
}
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
return true;
|
||||
return !top[F("relay-0")]["pin"].isNull();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,37 +0,0 @@
|
||||
# QuinLED-Dig-Quad Preassembled Unofficial Build
|
||||
|
||||
This usermod targets the [Preassembled QuinLED-Dig-Quad](https://quinled.info/pre-assembled-quinled-dig-quad/). Tested on board revision v1r6b,
|
||||
and includes the following features:
|
||||
|
||||
* **Multi-channel Support** - enabling use of LED1, LED2, LED3, LED4 pins to work using segments
|
||||
* **Temperature Sensor Support** - pulls readings from the built-in temperature sensor and adds the reading to the *Info* page in the UI
|
||||
|
||||
## Background
|
||||
|
||||
As a starting point, you should check out this awesome video from Quindor: [How to compile WLED yourself](https://quinled.info/2020/12/22/livestream-wled-compile/). The usermod you are reading now just provides some shortcuts for parts of what were covered in that video.
|
||||
|
||||
## Build Firmware with Multi-channel and Temp Support
|
||||
|
||||
1. Copy the `platformio_override.ini` file to the project's root directory
|
||||
1. If using VS Code with the PlatformIO plugin like in the video, you will now see this new project task listed in the PLATFORMIO panel at the bottom as `env:QL-DigQuad-Pre-v0.1` (you probably need to hit the refresh button)
|
||||
|
||||
<img src="images/pio-screenshot.png" width="400px"/>
|
||||
|
||||
1. Edit this file from the root directory as needed:
|
||||
|
||||
<img src="images/params.png" width="400px"/>
|
||||
|
||||
* `PIXEL_COUNTS` may need to be adjusted for your set-up. E.g. I have lots of LEDs in Channel 1, but that's probably unusual for most
|
||||
* `DATA_PINS` may need to be changed to "16,3,1,26" instead of "16,1,3,26" apparently depending on the board revision or some such
|
||||
|
||||
1. Build the mod (e.g. click `Build` from the project task circled above) and update your firmware using the `QL-DigQuad-Pre-v0.1` file, e.g. using _Manual OTA_ from the Config menu. Based on the video and my own experience, you might need to build twice 🤷♂️.
|
||||
|
||||
## Observing Temperature
|
||||
|
||||
Hopefully you can now see the Temperature listed in the Info page. If not, use Chrome Developer Tools to find the current temperature
|
||||
|
||||
1. Open the Developer Tools Console
|
||||
2. Enter `lastinfo.u.Temperature` to view the Temperature array
|
||||
|
||||
<img src="images/json-temp.png" width="300px"/>
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 296 KiB |
Binary file not shown.
Before Width: | Height: | Size: 69 KiB |
Binary file not shown.
Before Width: | Height: | Size: 321 KiB |
@ -1,16 +0,0 @@
|
||||
; QuinLED-Dig-Quad Preassembled Unofficial
|
||||
|
||||
[env:QL-DigQuad-Pre-v0.1]
|
||||
extends = env:esp32dev
|
||||
build_flags = ${common.build_flags_esp32}
|
||||
-D ESP32_MULTISTRIP
|
||||
-D NUM_STRIPS=4
|
||||
-D PIXEL_COUNTS="600, 300, 300, 300"
|
||||
-D DATA_PINS="16,1,3,26"
|
||||
-D RLYPIN=19
|
||||
-D BTNPIN=17
|
||||
-D USERMOD_DALLASTEMPERATURE
|
||||
-D USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL=10000
|
||||
lib_deps = ${env.lib_deps}
|
||||
milesburton/DallasTemperature@^3.9.0
|
||||
OneWire@~2.3.5
|
@ -1,35 +0,0 @@
|
||||
# SSD1306 128x32 OLED via I2C with u8g2
|
||||
This usermod allows to connect 128x32 Oled display to WLED controlled and show
|
||||
the next information:
|
||||
- Current SSID
|
||||
- IP address if obtained
|
||||
* in AP mode and turned off lightning AP password is shown
|
||||
- Current effect
|
||||
- Current palette
|
||||
- On/Off icon (sun/moon)
|
||||
|
||||
## Hardware
|
||||
![Hardware connection](assets/hw_connection.png)
|
||||
|
||||
## Requirements
|
||||
Functionality checked with:
|
||||
- commit 095429a7df4f9e2b34dd464f7bbfd068df6558eb
|
||||
- Wemos d1 mini
|
||||
- PlatformIO
|
||||
- Generic SSD1306 128x32 I2C OLED display from aliexpress
|
||||
|
||||
### Platformio
|
||||
Add `U8g2@~2.27.2` dependency to `lib_deps_external` under `[common]` section in `platformio.ini`:
|
||||
```ini
|
||||
# platformio.ini
|
||||
...
|
||||
[common]
|
||||
...
|
||||
lib_deps_external =
|
||||
...
|
||||
U8g2@~2.27.2
|
||||
...
|
||||
```
|
||||
|
||||
### Arduino IDE
|
||||
Install library `U8g2 by oliver` in `Tools | Include Library | Manage libraries` menu.
|
Binary file not shown.
Before Width: | Height: | Size: 34 KiB |
@ -1,175 +0,0 @@
|
||||
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
||||
|
||||
//The SCL and SDA pins are defined here.
|
||||
//Lolin32 boards use SCL=5 SDA=4
|
||||
#define U8X8_PIN_SCL 5
|
||||
#define U8X8_PIN_SDA 4
|
||||
|
||||
|
||||
// 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
|
||||
U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL,
|
||||
U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
|
||||
|
||||
// gets called once at boot. Do all initialization that doesn't depend on
|
||||
// network here
|
||||
void userSetup() {
|
||||
u8x8.begin();
|
||||
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.drawString(0, 0, "Loading...");
|
||||
}
|
||||
|
||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||
// interfaces here
|
||||
void userConnected() {}
|
||||
|
||||
// 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 knownMode = 0;
|
||||
uint8_t knownPalette = 0;
|
||||
|
||||
long lastUpdate = 0;
|
||||
long lastRedraw = 0;
|
||||
bool displayTurnedOff = false;
|
||||
// How often we are redrawing screen
|
||||
#define USER_LOOP_REFRESH_RATE_MS 5000
|
||||
|
||||
void userLoop() {
|
||||
|
||||
// Check if we time interval for redrawing passes.
|
||||
if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS) {
|
||||
return;
|
||||
}
|
||||
lastUpdate = millis();
|
||||
|
||||
// Turn off display after 3 minutes with no change.
|
||||
if(!displayTurnedOff && millis() - lastRedraw > 3*60*1000) {
|
||||
u8x8.setPowerSave(1);
|
||||
displayTurnedOff = true;
|
||||
}
|
||||
|
||||
// Check if values which are shown on display changed from the last time.
|
||||
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 (knownMode != strip.getMode()) {
|
||||
needRedraw = true;
|
||||
} else if (knownPalette != strip.getSegment(0).palette) {
|
||||
needRedraw = true;
|
||||
}
|
||||
|
||||
if (!needRedraw) {
|
||||
return;
|
||||
}
|
||||
needRedraw = false;
|
||||
|
||||
if (displayTurnedOff)
|
||||
{
|
||||
u8x8.setPowerSave(0);
|
||||
displayTurnedOff = false;
|
||||
}
|
||||
lastRedraw = millis();
|
||||
|
||||
// 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;
|
||||
|
||||
u8x8.clear();
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
|
||||
// First row with Wifi name
|
||||
u8x8.setCursor(1, 0);
|
||||
u8x8.print(knownSsid.substring(0, u8x8.getCols() > 1 ? u8x8.getCols() - 2 : 0));
|
||||
// Print `~` char to indicate that SSID is longer, than owr dicplay
|
||||
if (knownSsid.length() > u8x8.getCols())
|
||||
u8x8.print("~");
|
||||
|
||||
// Second row with IP or Psssword
|
||||
u8x8.setCursor(1, 1);
|
||||
// Print password in AP mode and if led is OFF.
|
||||
if (apActive && bri == 0)
|
||||
u8x8.print(apPass);
|
||||
else
|
||||
u8x8.print(knownIp);
|
||||
|
||||
// Third row with mode name
|
||||
u8x8.setCursor(2, 2);
|
||||
uint8_t qComma = 0;
|
||||
bool insideQuotes = false;
|
||||
uint8_t printedChars = 0;
|
||||
char singleJsonSymbol;
|
||||
// Find the mode name in JSON
|
||||
for (size_t i = 0; i < strlen_P(JSON_mode_names); i++) {
|
||||
singleJsonSymbol = pgm_read_byte_near(JSON_mode_names + i);
|
||||
switch (singleJsonSymbol) {
|
||||
case '"':
|
||||
insideQuotes = !insideQuotes;
|
||||
break;
|
||||
case '[':
|
||||
case ']':
|
||||
break;
|
||||
case ',':
|
||||
qComma++;
|
||||
default:
|
||||
if (!insideQuotes || (qComma != knownMode))
|
||||
break;
|
||||
u8x8.print(singleJsonSymbol);
|
||||
printedChars++;
|
||||
}
|
||||
if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
|
||||
break;
|
||||
}
|
||||
// Fourth row with palette name
|
||||
u8x8.setCursor(2, 3);
|
||||
qComma = 0;
|
||||
insideQuotes = false;
|
||||
printedChars = 0;
|
||||
// Looking for palette name in JSON.
|
||||
for (size_t i = 0; i < strlen_P(JSON_palette_names); i++) {
|
||||
singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i);
|
||||
switch (singleJsonSymbol) {
|
||||
case '"':
|
||||
insideQuotes = !insideQuotes;
|
||||
break;
|
||||
case '[':
|
||||
case ']':
|
||||
break;
|
||||
case ',':
|
||||
qComma++;
|
||||
default:
|
||||
if (!insideQuotes || (qComma != knownPalette))
|
||||
break;
|
||||
u8x8.print(singleJsonSymbol);
|
||||
printedChars++;
|
||||
}
|
||||
if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
|
||||
break;
|
||||
}
|
||||
|
||||
u8x8.setFont(u8x8_font_open_iconic_embedded_1x1);
|
||||
u8x8.drawGlyph(0, 0, 80); // wifi icon
|
||||
u8x8.drawGlyph(0, 1, 68); // home icon
|
||||
u8x8.setFont(u8x8_font_open_iconic_weather_2x2);
|
||||
u8x8.drawGlyph(0, 2, 66 + (bri > 0 ? 3 : 0)); // sun/moon icon
|
||||
}
|
@ -65,6 +65,7 @@ class AutoSaveUsermod : public Usermod {
|
||||
month(localTime), day(localTime),
|
||||
hour(localTime), minute(localTime), second(localTime));
|
||||
savePreset(autoSavePreset, true, presetNameBuffer);
|
||||
cacheInvalidate++; // force reload of presets
|
||||
}
|
||||
|
||||
void inline displayOverlay() {
|
||||
|
@ -114,6 +114,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
U8X8 *u8x8 = nullptr; // pointer to U8X8 display object
|
||||
#ifndef FLD_SPI_DEFAULT
|
||||
int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA
|
||||
uint32_t ioFrequency = 400000; // in Hz (minimum is 100000, baseline is 400000 and maximum should be 3400000)
|
||||
DisplayType type = SSD1306; // display type
|
||||
#else
|
||||
int8_t ioPin[5] = {FLD_PIN_CLOCKSPI, FLD_PIN_DATASPI, FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // SPI pins: CLK, MOSI, CS, DC, RST
|
||||
@ -155,6 +156,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
static const char _flip[];
|
||||
static const char _sleepMode[];
|
||||
static const char _clockMode[];
|
||||
static const char _busClkFrequency[];
|
||||
|
||||
// If display does not work or looks corrupted check the
|
||||
// constructor reference:
|
||||
@ -248,6 +250,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
|
||||
initDone = true;
|
||||
DEBUG_PRINTLN(F("Starting display."));
|
||||
if (!(type == SSD1306_SPI || type == SSD1306_SPI64)) u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
||||
u8x8->begin();
|
||||
setFlipMode(flip);
|
||||
setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
||||
@ -683,6 +686,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
top[FPSTR(_screenTimeOut)] = screenTimeout/1000;
|
||||
top[FPSTR(_sleepMode)] = (bool) sleepMode;
|
||||
top[FPSTR(_clockMode)] = (bool) clockMode;
|
||||
top[FPSTR(_busClkFrequency)] = ioFrequency/1000;
|
||||
DEBUG_PRINTLN(F("4 Line Display config saved."));
|
||||
}
|
||||
|
||||
@ -714,6 +718,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
screenTimeout = (top[FPSTR(_screenTimeOut)] | screenTimeout/1000) * 1000;
|
||||
sleepMode = top[FPSTR(_sleepMode)] | sleepMode;
|
||||
clockMode = top[FPSTR(_clockMode)] | clockMode;
|
||||
ioFrequency = min(3400, max(100, (int)(top[FPSTR(_busClkFrequency)] | ioFrequency/1000))) * 1000; // limit frequency
|
||||
|
||||
DEBUG_PRINT(FPSTR(_name));
|
||||
if (!initDone) {
|
||||
@ -739,12 +744,13 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
setup();
|
||||
needsRedraw |= true;
|
||||
}
|
||||
if (!(type == SSD1306_SPI || type == SSD1306_SPI64)) u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
||||
setContrast(contrast);
|
||||
setFlipMode(flip);
|
||||
if (needsRedraw && !wakeDisplay()) redraw(true);
|
||||
}
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
return !(top["pin"][2]).isNull();
|
||||
return !(top[_busClkFrequency]).isNull();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -764,3 +770,4 @@ const char FourLineDisplayUsermod::_screenTimeOut[] PROGMEM = "screenTimeOutSec"
|
||||
const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip";
|
||||
const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode";
|
||||
const char FourLineDisplayUsermod::_clockMode[] PROGMEM = "clockMode";
|
||||
const char FourLineDisplayUsermod::_busClkFrequency[] PROGMEM = "i2c-freq-kHz";
|
||||
|
256
wled00/FX.cpp
256
wled00/FX.cpp
@ -388,41 +388,12 @@ uint16_t WS2812FX::mode_rainbow_cycle(void) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* theater chase function
|
||||
*/
|
||||
uint16_t WS2812FX::theater_chase(uint32_t color1, uint32_t color2, bool do_palette) {
|
||||
byte gap = 2 + ((255 - SEGMENT.intensity) >> 5);
|
||||
uint32_t cycleTime = 50 + (255 - SEGMENT.speed)*2;
|
||||
uint32_t it = now / cycleTime;
|
||||
if (it != SEGENV.step) //new color
|
||||
{
|
||||
SEGENV.aux0 = (SEGENV.aux0 +1) % gap;
|
||||
SEGENV.step = it;
|
||||
}
|
||||
|
||||
for(uint16_t i = 0; i < SEGLEN; i++) {
|
||||
if((i % gap) == SEGENV.aux0) {
|
||||
if (do_palette)
|
||||
{
|
||||
setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
|
||||
} else {
|
||||
setPixelColor(i, color1);
|
||||
}
|
||||
} else {
|
||||
setPixelColor(i, color2);
|
||||
}
|
||||
}
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Theatre-style crawling lights.
|
||||
* Inspired by the Adafruit examples.
|
||||
*/
|
||||
uint16_t WS2812FX::mode_theater_chase(void) {
|
||||
return theater_chase(SEGCOLOR(0), SEGCOLOR(1), true);
|
||||
return running(SEGCOLOR(0), SEGCOLOR(1), true);
|
||||
}
|
||||
|
||||
|
||||
@ -431,7 +402,7 @@ uint16_t WS2812FX::mode_theater_chase(void) {
|
||||
* Inspired by the Adafruit examples.
|
||||
*/
|
||||
uint16_t WS2812FX::mode_theater_chase_rainbow(void) {
|
||||
return theater_chase(color_wheel(SEGENV.step), SEGCOLOR(1), false);
|
||||
return running(color_wheel(SEGENV.step), SEGCOLOR(1), true);
|
||||
}
|
||||
|
||||
|
||||
@ -976,29 +947,27 @@ uint16_t WS2812FX::mode_chase_flash_random(void) {
|
||||
/*
|
||||
* Alternating pixels running function.
|
||||
*/
|
||||
uint16_t WS2812FX::running(uint32_t color1, uint32_t color2) {
|
||||
uint8_t pxw = 1 + (SEGMENT.intensity >> 5);
|
||||
uint32_t cycleTime = 35 + (255 - SEGMENT.speed);
|
||||
uint16_t WS2812FX::running(uint32_t color1, uint32_t color2, bool theatre) {
|
||||
uint8_t width = (theatre ? 3 : 1) + (SEGMENT.intensity >> 4); // window
|
||||
uint32_t cycleTime = 50 + (255 - SEGMENT.speed);
|
||||
uint32_t it = now / cycleTime;
|
||||
if (SEGMENT.speed == 0) it = 0;
|
||||
bool usePalette = color1 == SEGCOLOR(0);
|
||||
|
||||
for(uint16_t i = 0; i < SEGLEN; i++) {
|
||||
if((i + SEGENV.aux0) % (pxw*2) < pxw) {
|
||||
if (color1 == SEGCOLOR(0))
|
||||
{
|
||||
setPixelColor(SEGLEN -i -1, color_from_palette(SEGLEN -i -1, true, PALETTE_SOLID_WRAP, 0));
|
||||
} else
|
||||
{
|
||||
setPixelColor(SEGLEN -i -1, color1);
|
||||
}
|
||||
uint32_t col = color2;
|
||||
if (usePalette) color1 = color_from_palette(i, true, PALETTE_SOLID_WRAP, 0);
|
||||
if (theatre) {
|
||||
if ((i % width) == SEGENV.aux0) col = color1;
|
||||
} else {
|
||||
setPixelColor(SEGLEN -i -1, color2);
|
||||
int8_t pos = (i % (width<<1));
|
||||
if ((pos < SEGENV.aux0-width) || ((pos >= SEGENV.aux0) && (pos < SEGENV.aux0+width))) col = color1;
|
||||
}
|
||||
setPixelColor(i,col);
|
||||
}
|
||||
|
||||
if (it != SEGENV.step )
|
||||
{
|
||||
SEGENV.aux0 = (SEGENV.aux0 +1) % (pxw*2);
|
||||
SEGENV.aux0 = (SEGENV.aux0 +1) % (theatre ? width : (width<<1));
|
||||
SEGENV.step = it;
|
||||
}
|
||||
return FRAMETIME;
|
||||
@ -1247,44 +1216,19 @@ uint16_t WS2812FX::mode_loading(void) {
|
||||
|
||||
|
||||
//American Police Light with all LEDs Red and Blue
|
||||
uint16_t WS2812FX::police_base(uint32_t color1, uint32_t color2, bool all)
|
||||
uint16_t WS2812FX::police_base(uint32_t color1, uint32_t color2, uint16_t width)
|
||||
{
|
||||
uint16_t counter = now * ((SEGMENT.speed >> 2) +1);
|
||||
uint16_t idexR = (counter * SEGLEN) >> 16;
|
||||
if (idexR >= SEGLEN) idexR = 0;
|
||||
uint16_t delay = 1 + (FRAMETIME<<3) / SEGLEN; // longer segments should change faster
|
||||
uint32_t it = now / map(SEGMENT.speed, 0, 255, delay<<4, delay);
|
||||
uint16_t offset = it % SEGLEN;
|
||||
|
||||
uint16_t topindex = SEGLEN >> 1;
|
||||
uint16_t idexB = (idexR > topindex) ? idexR - topindex : idexR + topindex;
|
||||
if (SEGENV.call == 0) SEGENV.aux0 = idexR;
|
||||
if (idexB >= SEGLEN) idexB = 0; //otherwise overflow on odd number of LEDs
|
||||
|
||||
if (all) { //different algo, ensuring immediate fill
|
||||
if (idexB > idexR) {
|
||||
fill(color2);
|
||||
for (uint16_t i = idexR; i < idexB; i++) setPixelColor(i, color1);
|
||||
} else {
|
||||
fill(color1);
|
||||
for (uint16_t i = idexB; i < idexR; i++) setPixelColor(i, color2);
|
||||
if (!width) width = 1;
|
||||
for (uint16_t i = 0; i < width; i++) {
|
||||
uint16_t indexR = (offset + i) % SEGLEN;
|
||||
uint16_t indexB = (offset + i + (SEGLEN>>1)) % SEGLEN;
|
||||
setPixelColor(indexR, color1);
|
||||
setPixelColor(indexB, color2);
|
||||
}
|
||||
} else { //regular dot-only mode
|
||||
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);
|
||||
setPixelColor(idexB+i, color2);
|
||||
}
|
||||
if (SEGENV.aux0 != idexR) {
|
||||
uint8_t gap = (SEGENV.aux0 < idexR)? idexR - SEGENV.aux0:SEGLEN - SEGENV.aux0 + idexR;
|
||||
for (uint8_t i = 0; i <= gap ; i++) {
|
||||
if ((idexR - i) < 0) idexR = SEGLEN-1 + i;
|
||||
if ((idexB - i) < 0) idexB = SEGLEN-1 + i;
|
||||
setPixelColor(idexR-i, color1);
|
||||
setPixelColor(idexB-i, color2);
|
||||
}
|
||||
SEGENV.aux0 = idexR;
|
||||
}
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
@ -1292,7 +1236,7 @@ uint16_t WS2812FX::police_base(uint32_t color1, uint32_t color2, bool all)
|
||||
//American Police Light with all LEDs Red and Blue
|
||||
uint16_t WS2812FX::mode_police_all()
|
||||
{
|
||||
return police_base(RED, BLUE, true);
|
||||
return police_base(RED, BLUE, (SEGLEN>>1));
|
||||
}
|
||||
|
||||
|
||||
@ -1300,15 +1244,15 @@ uint16_t WS2812FX::mode_police_all()
|
||||
uint16_t WS2812FX::mode_police()
|
||||
{
|
||||
fill(SEGCOLOR(1));
|
||||
|
||||
return police_base(RED, BLUE, false);
|
||||
return police_base(RED, BLUE, ((SEGLEN*(SEGMENT.intensity+1))>>9)); // max width is half the strip
|
||||
}
|
||||
|
||||
|
||||
//Police All with custom colors
|
||||
uint16_t WS2812FX::mode_two_areas()
|
||||
{
|
||||
return police_base(SEGCOLOR(0), SEGCOLOR(1), true);
|
||||
fill(SEGCOLOR(2));
|
||||
return police_base(SEGCOLOR(0), SEGCOLOR(1), ((SEGLEN*(SEGMENT.intensity+1))>>9)); // max width is half the strip
|
||||
}
|
||||
|
||||
|
||||
@ -1318,7 +1262,7 @@ uint16_t WS2812FX::mode_two_dots()
|
||||
fill(SEGCOLOR(2));
|
||||
uint32_t color2 = (SEGCOLOR(1) == SEGCOLOR(2)) ? SEGCOLOR(0) : SEGCOLOR(1);
|
||||
|
||||
return police_base(SEGCOLOR(0), color2, false);
|
||||
return police_base(SEGCOLOR(0), color2, ((SEGLEN*(SEGMENT.intensity+1))>>9)); // max width is half the strip
|
||||
}
|
||||
|
||||
|
||||
@ -1326,21 +1270,20 @@ uint16_t WS2812FX::mode_two_dots()
|
||||
* Tricolor chase function
|
||||
*/
|
||||
uint16_t WS2812FX::tricolor_chase(uint32_t color1, uint32_t color2) {
|
||||
uint32_t cycleTime = 50 + (255 - SEGMENT.speed)*2;
|
||||
uint32_t it = now / cycleTime;
|
||||
uint8_t width = (1 + SEGMENT.intensity/32) * 3; //value of 1-8 for each colour
|
||||
uint8_t index = it % width;
|
||||
uint32_t cycleTime = 50 + ((255 - SEGMENT.speed)<<1);
|
||||
uint32_t it = now / cycleTime; // iterator
|
||||
uint8_t width = (1 + (SEGMENT.intensity>>4)); // value of 1-16 for each colour
|
||||
uint8_t index = it % (width*3);
|
||||
|
||||
for(uint16_t i = 0; i < SEGLEN; i++, index++) {
|
||||
if(index > width-1) index = 0;
|
||||
for (uint16_t i = 0; i < SEGLEN; i++, index++) {
|
||||
if (index > (width*3)-1) index = 0;
|
||||
|
||||
uint32_t color = color1;
|
||||
if(index > width*2/3-1) color = color_from_palette(i, true, PALETTE_SOLID_WRAP, 1);
|
||||
else if(index > width/3-1) color = color2;
|
||||
if (index > (width<<1)-1) color = color_from_palette(i, true, PALETTE_SOLID_WRAP, 1);
|
||||
else if (index > width-1) color = color2;
|
||||
|
||||
setPixelColor(SEGLEN - i -1, color);
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
@ -1548,7 +1491,7 @@ uint16_t WS2812FX::mode_random_chase(void)
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
|
||||
//7 bytes
|
||||
typedef struct Oscillator {
|
||||
int16_t pos;
|
||||
int8_t size;
|
||||
@ -1780,7 +1723,7 @@ uint16_t WS2812FX::mode_fire_2012()
|
||||
// Step 1. Cool down every cell a little
|
||||
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||
uint8_t temp = qsub8(heat[i], random8(0, (((20 + SEGMENT.speed /3) * 10) / SEGLEN) + 2));
|
||||
heat[i] = (temp==0 && i<ignition) ? 2 : temp; // prevent ignition area from becoming black
|
||||
heat[i] = (temp==0 && i<ignition) ? 16 : temp; // prevent ignition area from becoming black
|
||||
}
|
||||
|
||||
// Step 2. Heat from each cell drifts 'up' and diffuses a little
|
||||
@ -1994,7 +1937,7 @@ uint16_t WS2812FX::mode_colortwinkle()
|
||||
|
||||
if (fadeUp) {
|
||||
CRGB incrementalColor = fastled_col;
|
||||
incrementalColor.nscale8_video( fadeUpAmount);
|
||||
incrementalColor.nscale8_video(fadeUpAmount);
|
||||
fastled_col += incrementalColor;
|
||||
|
||||
if (fastled_col.red == 255 || fastled_col.green == 255 || fastled_col.blue == 255) {
|
||||
@ -2002,24 +1945,21 @@ uint16_t WS2812FX::mode_colortwinkle()
|
||||
}
|
||||
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
||||
|
||||
if (col_to_crgb(getPixelColor(i)) == prev) //fix "stuck" pixels
|
||||
{
|
||||
if (col_to_crgb(getPixelColor(i)) == prev) { //fix "stuck" pixels
|
||||
fastled_col += fastled_col;
|
||||
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
||||
}
|
||||
} else {
|
||||
fastled_col.nscale8( 255 - fadeDownAmount);
|
||||
fastled_col.nscale8(255 - fadeDownAmount);
|
||||
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint16_t j = 0; j <= SEGLEN / 50; j++)
|
||||
{
|
||||
for (uint16_t j = 0; j <= SEGLEN / 50; j++) {
|
||||
if (random8() <= SEGMENT.intensity) {
|
||||
for (uint8_t times = 0; times < 5; times++) //attempt to spawn a new pixel 5 times
|
||||
{
|
||||
for (uint8_t times = 0; times < 5; times++) { //attempt to spawn a new pixel 5 times
|
||||
int i = random16(SEGLEN);
|
||||
if(getPixelColor(i) == 0) {
|
||||
if (getPixelColor(i) == 0) {
|
||||
fastled_col = ColorFromPalette(currentPalette, random8(), 64, NOBLEND);
|
||||
uint16_t index = i >> 3;
|
||||
uint8_t bitNum = i & 0x07;
|
||||
@ -2170,10 +2110,14 @@ typedef struct Ripple {
|
||||
uint16_t pos;
|
||||
} ripple;
|
||||
|
||||
#ifdef ESP8266
|
||||
#define MAX_RIPPLES 56
|
||||
#else
|
||||
#define MAX_RIPPLES 100
|
||||
#endif
|
||||
uint16_t WS2812FX::ripple_base(bool rainbow)
|
||||
{
|
||||
uint16_t maxRipples = 1 + (SEGLEN >> 2);
|
||||
if (maxRipples > 100) maxRipples = 100;
|
||||
uint16_t maxRipples = min(1 + (SEGLEN >> 2), MAX_RIPPLES); // 56 max for 16 segment ESP8266
|
||||
uint16_t dataSize = sizeof(ripple) * maxRipples;
|
||||
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
@ -2241,6 +2185,7 @@ uint16_t WS2812FX::ripple_base(bool rainbow)
|
||||
}
|
||||
return FRAMETIME;
|
||||
}
|
||||
#undef MAX_RIPPLES
|
||||
|
||||
uint16_t WS2812FX::mode_ripple(void) {
|
||||
return ripple_base(false);
|
||||
@ -2541,7 +2486,6 @@ uint16_t WS2812FX::mode_spots_fade()
|
||||
|
||||
|
||||
//each needs 12 bytes
|
||||
//Spark type is used for popcorn and 1D fireworks
|
||||
typedef struct Ball {
|
||||
unsigned long lastBounceTime;
|
||||
float impactVelocity;
|
||||
@ -2651,7 +2595,7 @@ uint16_t WS2812FX::mode_sinelon_dual(void) {
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::mode_sinelon_rainbow(void) {
|
||||
return sinelon_base(true, true);
|
||||
return sinelon_base(false, true);
|
||||
}
|
||||
|
||||
|
||||
@ -2670,7 +2614,7 @@ uint16_t WS2812FX::mode_glitter()
|
||||
|
||||
|
||||
|
||||
//each needs 12 bytes
|
||||
//each needs 11 bytes
|
||||
//Spark type is used for popcorn, 1D fireworks, and drip
|
||||
typedef struct Spark {
|
||||
float pos;
|
||||
@ -2685,7 +2629,7 @@ typedef struct Spark {
|
||||
*/
|
||||
uint16_t WS2812FX::mode_popcorn(void) {
|
||||
//allocate segment data
|
||||
uint16_t maxNumPopcorn = 24;
|
||||
uint16_t maxNumPopcorn = 22; // max 22 on 16 segment ESP8266
|
||||
uint16_t dataSize = sizeof(spark) * maxNumPopcorn;
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
|
||||
@ -2744,7 +2688,7 @@ uint16_t WS2812FX::candle(bool multi)
|
||||
if (multi)
|
||||
{
|
||||
//allocate segment data
|
||||
uint16_t dataSize = (SEGLEN -1) *3;
|
||||
uint16_t dataSize = (SEGLEN -1) *3; // max length of segment on 16 segment ESP8266 is 75 pixels
|
||||
if (!SEGENV.allocateData(dataSize)) return candle(false); //allocation failed
|
||||
}
|
||||
|
||||
@ -2831,9 +2775,14 @@ uint16_t WS2812FX::mode_candle_multi()
|
||||
/ based on the video: https://www.reddit.com/r/arduino/comments/c3sd46/i_made_this_fireworks_effect_for_my_led_strips/
|
||||
/ Speed sets frequency of new starbursts, intensity is the intensity of the burst
|
||||
*/
|
||||
#define STARBURST_MAX_FRAG 12
|
||||
|
||||
//each needs 64 byte
|
||||
#ifdef ESP8266
|
||||
#define STARBURST_MAX_FRAG 4
|
||||
#define STARBURST_MAX_STARS 6
|
||||
#else
|
||||
#define STARBURST_MAX_FRAG 10
|
||||
#define STARBURST_MAX_STARS 11
|
||||
#endif
|
||||
//each needs 18+STARBURST_MAX_FRAG*4 bytes
|
||||
typedef struct particle {
|
||||
CRGB color;
|
||||
uint32_t birth =0;
|
||||
@ -2844,8 +2793,7 @@ typedef struct particle {
|
||||
} star;
|
||||
|
||||
uint16_t WS2812FX::mode_starburst(void) {
|
||||
uint8_t numStars = 1 + (SEGLEN >> 3);
|
||||
if (numStars > 15) numStars = 15;
|
||||
uint8_t numStars = min(1 + (SEGLEN >> 3), STARBURST_MAX_STARS); // 11 * 58 * 32 = 19k (ESP32), 6 * 34 * 16 = 3.2k (ESP8266)
|
||||
uint16_t dataSize = sizeof(star) * numStars;
|
||||
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
@ -2946,18 +2894,22 @@ uint16_t WS2812FX::mode_starburst(void) {
|
||||
}
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
#undef STARBURST_MAX_FRAG
|
||||
#undef STARBURST_MAX_STARS
|
||||
|
||||
/*
|
||||
* Exploding fireworks effect
|
||||
* adapted from: http://www.anirama.com/1000leds/1d-fireworks/
|
||||
*/
|
||||
|
||||
#ifdef ESP8266
|
||||
#define MAX_SPARKS 20 // number of fragments (11 bytes per fragment)
|
||||
#else
|
||||
#define MAX_SPARKS 58 // number of fragments
|
||||
#endif
|
||||
uint16_t WS2812FX::mode_exploding_fireworks(void)
|
||||
{
|
||||
//allocate segment data
|
||||
uint16_t numSparks = 2 + (SEGLEN >> 1);
|
||||
if (numSparks > 80) numSparks = 80;
|
||||
uint16_t numSparks = min(2 + (SEGLEN >> 1), MAX_SPARKS); // max 58 for 32 segment ESP32, 20 for 16 segment ESP8266
|
||||
uint16_t dataSize = sizeof(spark) * numSparks;
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
|
||||
@ -3052,7 +3004,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void)
|
||||
SEGENV.aux0--;
|
||||
if (SEGENV.aux0 < 4) {
|
||||
SEGENV.aux0 = 0; //back to flare
|
||||
SEGENV.step = (SEGMENT.intensity > random8()); //decide firing side
|
||||
SEGENV.step = actuallyReverse ^ (SEGMENT.intensity > random8()); //decide firing side
|
||||
}
|
||||
}
|
||||
|
||||
@ -3060,6 +3012,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void)
|
||||
|
||||
return FRAMETIME;
|
||||
}
|
||||
#undef MAX_SPARKS
|
||||
|
||||
|
||||
/*
|
||||
@ -3069,7 +3022,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void)
|
||||
uint16_t WS2812FX::mode_drip(void)
|
||||
{
|
||||
//allocate segment data
|
||||
uint16_t numDrops = 4;
|
||||
uint8_t numDrops = 4;
|
||||
uint16_t dataSize = sizeof(spark) * numDrops;
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
|
||||
@ -3077,7 +3030,7 @@ uint16_t WS2812FX::mode_drip(void)
|
||||
|
||||
Spark* drops = reinterpret_cast<Spark*>(SEGENV.data);
|
||||
|
||||
numDrops = 1 + (SEGMENT.intensity >> 6);
|
||||
numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3
|
||||
|
||||
float gravity = -0.0005 - (SEGMENT.speed/50000.0);
|
||||
gravity *= SEGLEN;
|
||||
@ -3107,7 +3060,7 @@ uint16_t WS2812FX::mode_drip(void)
|
||||
if (drops[j].pos > 0) { // fall until end of segment
|
||||
drops[j].pos += drops[j].vel;
|
||||
if (drops[j].pos < 0) drops[j].pos = 0;
|
||||
drops[j].vel += gravity;
|
||||
drops[j].vel += gravity; // gravity is negative
|
||||
|
||||
for (uint16_t i=1;i<7-drops[j].colIndex;i++) { // some minor math so we don't expand bouncing droplets
|
||||
uint16_t pos = constrain(uint16_t(drops[j].pos) +i, 0, SEGLEN-1); //this is BAD, returns a pos >= SEGLEN occasionally
|
||||
@ -3142,6 +3095,7 @@ uint16_t WS2812FX::mode_drip(void)
|
||||
* Tetris or Stacking (falling bricks) Effect
|
||||
* by Blaz Kristan (https://github.com/blazoncek, https://blaz.at/home)
|
||||
*/
|
||||
//12 bytes
|
||||
typedef struct Tetris {
|
||||
float pos;
|
||||
float speed;
|
||||
@ -3163,8 +3117,8 @@ uint16_t WS2812FX::mode_tetrix(void) {
|
||||
}
|
||||
|
||||
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->speed = 0.0238 * (SEGMENT.speed ? (SEGMENT.speed>>2)+1 : random8(6,64)); // set speed
|
||||
drop->pos = SEGLEN; // start at end of segment (no need to subtract 1)
|
||||
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
|
||||
@ -3196,13 +3150,17 @@ uint16_t WS2812FX::mode_tetrix(void) {
|
||||
/ adapted from https://github.com/atuline/FastLED-Demos/blob/master/plasma/plasma.ino
|
||||
*/
|
||||
uint16_t WS2812FX::mode_plasma(void) {
|
||||
uint8_t thisPhase = beatsin8(6,-64,64); // Setting phase change for a couple of waves.
|
||||
uint8_t thatPhase = beatsin8(7,-64,64);
|
||||
// initialize phases on start
|
||||
if (SEGENV.call == 0) {
|
||||
SEGENV.aux0 = random8(0,2); // add a bit of randomness
|
||||
}
|
||||
uint8_t thisPhase = beatsin8(6+SEGENV.aux0,-64,64);
|
||||
uint8_t thatPhase = beatsin8(7+SEGENV.aux0,-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 thisBright = qsub8(colorIndex, beatsin8(6,0, (255 - SEGMENT.intensity)|0x01 ));
|
||||
uint8_t colorIndex = cubicwave8((i*(2+ 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(7,0, (128 - (SEGMENT.intensity>>1))));
|
||||
CRGB color = ColorFromPalette(currentPalette, colorIndex, thisBright, LINEARBLEND);
|
||||
setPixelColor(i, color.red, color.green, color.blue);
|
||||
}
|
||||
@ -3531,7 +3489,7 @@ uint16_t WS2812FX::mode_noisepal(void) { // S
|
||||
uint16_t scale = 15 + (SEGMENT.intensity >> 2); //default was 30
|
||||
//#define scale 30
|
||||
|
||||
uint16_t dataSize = sizeof(CRGBPalette16) * 2; //allocate space for 2 Palettes
|
||||
uint16_t dataSize = sizeof(CRGBPalette16) * 2; //allocate space for 2 Palettes (2 * 16 * 3 = 96 bytes)
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
|
||||
CRGBPalette16* palettes = reinterpret_cast<CRGBPalette16*>(SEGENV.data);
|
||||
@ -3644,7 +3602,7 @@ uint16_t WS2812FX::mode_chunchun(void)
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
|
||||
//13 bytes
|
||||
typedef struct Spotlight {
|
||||
float speed;
|
||||
uint8_t colorIdx;
|
||||
@ -3661,6 +3619,11 @@ typedef struct Spotlight {
|
||||
#define SPOT_TYPE_3X_DOT 4
|
||||
#define SPOT_TYPE_4X_DOT 5
|
||||
#define SPOT_TYPES_COUNT 6
|
||||
#ifdef ESP8266
|
||||
#define SPOT_MAX_COUNT 17 //Number of simultaneous waves
|
||||
#else
|
||||
#define SPOT_MAX_COUNT 49 //Number of simultaneous waves
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Spotlights moving back and forth that cast dancing shadows.
|
||||
@ -3671,7 +3634,7 @@ typedef struct Spotlight {
|
||||
*/
|
||||
uint16_t WS2812FX::mode_dancing_shadows(void)
|
||||
{
|
||||
uint8_t numSpotlights = map(SEGMENT.intensity, 0, 255, 2, 50);
|
||||
uint8_t numSpotlights = map(SEGMENT.intensity, 0, 255, 2, SPOT_MAX_COUNT); // 49 on 32 segment ESP32, 17 on 16 segment ESP8266
|
||||
bool initialize = SEGENV.aux0 != numSpotlights;
|
||||
SEGENV.aux0 = numSpotlights;
|
||||
|
||||
@ -3810,7 +3773,7 @@ uint16_t WS2812FX::mode_washing_machine(void) {
|
||||
Modified, originally by Mark Kriegsman https://gist.github.com/kriegsman/1f7ccbbfa492a73c015e
|
||||
*/
|
||||
uint16_t WS2812FX::mode_blends(void) {
|
||||
uint16_t dataSize = sizeof(uint32_t) * SEGLEN;
|
||||
uint16_t dataSize = sizeof(uint32_t) * SEGLEN; // max segment length of 56 pixels on 16 segment ESP8266
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data);
|
||||
uint8_t blendSpeed = map(SEGMENT.intensity, 0, UINT8_MAX, 10, 128);
|
||||
@ -3825,6 +3788,11 @@ uint16_t WS2812FX::mode_blends(void) {
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
/*
|
||||
TV Simulator
|
||||
Modified and adapted to WLED by Def3nder, based on "Fake TV Light for Engineers" by Phillip Burgess https://learn.adafruit.com/fake-tv-light-for-engineers/arduino-sketch
|
||||
*/
|
||||
//43 bytes
|
||||
typedef struct TvSim {
|
||||
uint32_t totalTime = 0;
|
||||
uint32_t fadeTime = 0;
|
||||
@ -3845,11 +3813,6 @@ typedef struct TvSim {
|
||||
uint16_t pb = 0;
|
||||
} tvSim;
|
||||
|
||||
|
||||
/*
|
||||
TV Simulator
|
||||
Modified and adapted to WLED by Def3nder, based on "Fake TV Light for Engineers" by Phillip Burgess https://learn.adafruit.com/fake-tv-light-for-engineers/arduino-sketch
|
||||
*/
|
||||
uint16_t WS2812FX::mode_tv_simulator(void) {
|
||||
uint16_t nr, ng, nb, r, g, b, i, hue;
|
||||
uint8_t sat, bri, j;
|
||||
@ -3957,10 +3920,15 @@ uint16_t WS2812FX::mode_tv_simulator(void) {
|
||||
*/
|
||||
|
||||
//CONFIG
|
||||
#define W_MAX_COUNT 20 //Number of simultaneous waves
|
||||
#ifdef ESP8266
|
||||
#define W_MAX_COUNT 9 //Number of simultaneous waves
|
||||
#else
|
||||
#define W_MAX_COUNT 20 //Number of simultaneous waves
|
||||
#endif
|
||||
#define W_MAX_SPEED 6 //Higher number, higher speed
|
||||
#define W_WIDTH_FACTOR 6 //Higher number, smaller waves
|
||||
|
||||
//24 bytes
|
||||
class AuroraWave {
|
||||
private:
|
||||
uint16_t ttl;
|
||||
@ -4055,10 +4023,10 @@ uint16_t WS2812FX::mode_aurora(void) {
|
||||
|
||||
if(SEGENV.aux0 != SEGMENT.intensity || SEGENV.call == 0) {
|
||||
//Intensity slider changed or first call
|
||||
SEGENV.aux1 = ((float)SEGMENT.intensity / 255) * W_MAX_COUNT;
|
||||
SEGENV.aux1 = map(SEGMENT.intensity, 0, 255, 2, W_MAX_COUNT);
|
||||
SEGENV.aux0 = SEGMENT.intensity;
|
||||
|
||||
if(!SEGENV.allocateData(sizeof(AuroraWave) * SEGENV.aux1)) {
|
||||
if(!SEGENV.allocateData(sizeof(AuroraWave) * SEGENV.aux1)) { // 26 on 32 segment ESP32, 9 on 16 segment ESP8266
|
||||
return mode_static(); //allocation failed
|
||||
}
|
||||
|
||||
|
71
wled00/FX.h
71
wled00/FX.h
@ -24,8 +24,6 @@
|
||||
Modified for WLED
|
||||
*/
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
#ifndef WS2812FX_h
|
||||
#define WS2812FX_h
|
||||
|
||||
@ -55,17 +53,17 @@
|
||||
/* each segment uses 52 bytes of SRAM memory, so if you're application fails because of
|
||||
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
|
||||
#ifdef ESP8266
|
||||
#define MAX_NUM_SEGMENTS 12
|
||||
#define MAX_NUM_SEGMENTS 16
|
||||
/* How many color transitions can run at once */
|
||||
#define MAX_NUM_TRANSITIONS 8
|
||||
/* How much data bytes all segments combined may allocate */
|
||||
#define MAX_SEGMENT_DATA 2048
|
||||
#define MAX_SEGMENT_DATA 3584
|
||||
#else
|
||||
#ifndef MAX_NUM_SEGMENTS
|
||||
#define MAX_NUM_SEGMENTS 16
|
||||
#endif
|
||||
#define MAX_NUM_TRANSITIONS 16
|
||||
#define MAX_SEGMENT_DATA 8192
|
||||
#ifndef MAX_NUM_SEGMENTS
|
||||
#define MAX_NUM_SEGMENTS 32
|
||||
#endif
|
||||
#define MAX_NUM_TRANSITIONS 24
|
||||
#define MAX_SEGMENT_DATA 20480
|
||||
#endif
|
||||
|
||||
#define LED_SKIP_AMOUNT 1
|
||||
@ -257,6 +255,7 @@ class WS2812FX {
|
||||
uint8_t grouping, spacing;
|
||||
uint8_t opacity;
|
||||
uint32_t colors[NUM_COLORS];
|
||||
char *name;
|
||||
bool setColor(uint8_t slot, uint32_t c, uint8_t segn) { //returns true if changed
|
||||
if (slot >= NUM_COLORS || segn >= MAX_NUM_SEGMENTS) return false;
|
||||
if (c == colors[slot]) return false;
|
||||
@ -296,19 +295,19 @@ class WS2812FX {
|
||||
{
|
||||
return ((options >> n) & 0x01);
|
||||
}
|
||||
bool isSelected()
|
||||
inline bool isSelected()
|
||||
{
|
||||
return getOption(0);
|
||||
}
|
||||
bool isActive()
|
||||
inline bool isActive()
|
||||
{
|
||||
return stop > start;
|
||||
}
|
||||
uint16_t length()
|
||||
inline uint16_t length()
|
||||
{
|
||||
return stop - start;
|
||||
}
|
||||
uint16_t groupLength()
|
||||
inline uint16_t groupLength()
|
||||
{
|
||||
return grouping + spacing;
|
||||
}
|
||||
@ -345,17 +344,23 @@ class WS2812FX {
|
||||
|
||||
// segment runtime parameters
|
||||
typedef struct Segment_runtime { // 28 bytes
|
||||
unsigned long next_time;
|
||||
uint32_t step;
|
||||
uint32_t call;
|
||||
uint16_t aux0;
|
||||
uint16_t aux1;
|
||||
unsigned long next_time; // millis() of next update
|
||||
uint32_t step; // custom "step" var
|
||||
uint32_t call; // call counter
|
||||
uint16_t aux0; // custom var
|
||||
uint16_t aux1; // custom var
|
||||
byte* data = nullptr;
|
||||
bool allocateData(uint16_t len){
|
||||
if (data && _dataLen == len) return true; //already allocated
|
||||
deallocateData();
|
||||
if (WS2812FX::instance->_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory
|
||||
data = new (std::nothrow) byte[len];
|
||||
// if possible use SPI RAM on ESP32
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||
if (psramFound())
|
||||
data = (byte*) ps_malloc(len);
|
||||
else
|
||||
#endif
|
||||
data = (byte*) malloc(len);
|
||||
if (!data) return false; //allocation failed
|
||||
WS2812FX::instance->_usedSegmentData += len;
|
||||
_dataLen = len;
|
||||
@ -363,7 +368,7 @@ class WS2812FX {
|
||||
return true;
|
||||
}
|
||||
void deallocateData(){
|
||||
delete[] data;
|
||||
free(data);
|
||||
data = nullptr;
|
||||
WS2812FX::instance->_usedSegmentData -= _dataLen;
|
||||
_dataLen = 0;
|
||||
@ -389,7 +394,7 @@ class WS2812FX {
|
||||
* the internal segment state should be reset.
|
||||
* Call resetIfRequired before calling the next effect function.
|
||||
*/
|
||||
void reset() { _requiresReset = true; }
|
||||
inline void reset() { _requiresReset = true; }
|
||||
private:
|
||||
uint16_t _dataLen = 0;
|
||||
bool _requiresReset = false;
|
||||
@ -605,7 +610,7 @@ class WS2812FX {
|
||||
}
|
||||
|
||||
void
|
||||
finalizeInit(uint16_t countPixels),
|
||||
finalizeInit(void),
|
||||
service(void),
|
||||
blur(uint8_t),
|
||||
fill(uint32_t),
|
||||
@ -622,11 +627,12 @@ class WS2812FX {
|
||||
trigger(void),
|
||||
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0),
|
||||
resetSegments(),
|
||||
populateDefaultSegments(),
|
||||
setPixelColor(uint16_t n, uint32_t c),
|
||||
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
|
||||
show(void),
|
||||
setColorOrder(uint8_t co),
|
||||
setPixelSegment(uint8_t n);
|
||||
setPixelSegment(uint8_t n),
|
||||
deserializeMap(uint8_t n=0);
|
||||
|
||||
bool
|
||||
isRgbw = false,
|
||||
@ -644,8 +650,6 @@ 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),
|
||||
@ -654,24 +658,17 @@ class WS2812FX {
|
||||
getMaxSegments(void),
|
||||
//getFirstSelectedSegment(void),
|
||||
getMainSegmentId(void),
|
||||
getColorOrder(void),
|
||||
gamma8(uint8_t),
|
||||
gamma8_cal(uint8_t, float),
|
||||
sin_gap(uint16_t),
|
||||
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,
|
||||
// setStripLen(uint8_t strip, uint16_t len),
|
||||
// getStripLen(uint8_t strip=0),
|
||||
triwave16(uint16_t),
|
||||
getFps();
|
||||
|
||||
@ -849,7 +846,6 @@ class WS2812FX {
|
||||
color_wipe(bool, bool),
|
||||
dynamic(bool),
|
||||
scan(bool),
|
||||
theater_chase(uint32_t, uint32_t, bool),
|
||||
running_base(bool,bool),
|
||||
larson_scanner(bool),
|
||||
sinelon_base(bool,bool),
|
||||
@ -857,8 +853,8 @@ class WS2812FX {
|
||||
chase(uint32_t, uint32_t, uint32_t, bool),
|
||||
gradient_base(bool),
|
||||
ripple_base(bool),
|
||||
police_base(uint32_t, uint32_t, bool),
|
||||
running(uint32_t, uint32_t),
|
||||
police_base(uint32_t, uint32_t, uint16_t),
|
||||
running(uint32_t, uint32_t, bool theatre=false),
|
||||
tricolor_chase(uint32_t, uint32_t),
|
||||
twinklefox_base(bool),
|
||||
spots_base(uint16_t),
|
||||
@ -869,8 +865,7 @@ 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),
|
||||
deserializeMap(void);
|
||||
startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot);
|
||||
|
||||
uint16_t* customMappingTable = nullptr;
|
||||
uint16_t customMappingSize = 0;
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
Modified heavily for WLED
|
||||
*/
|
||||
|
||||
#include "wled.h"
|
||||
#include "FX.h"
|
||||
#include "palettes.h"
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
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]
|
||||
19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25]}
|
||||
*/
|
||||
|
||||
//factory defaults LED setup
|
||||
@ -49,7 +49,7 @@
|
||||
//#define DEFAULT_LED_TYPE TYPE_WS2812_RGB
|
||||
|
||||
#ifndef PIXEL_COUNTS
|
||||
#define PIXEL_COUNTS DEFAULT_LED_COUNT
|
||||
#define PIXEL_COUNTS 30
|
||||
#endif
|
||||
|
||||
#ifndef DATA_PINS
|
||||
@ -65,25 +65,22 @@
|
||||
#endif
|
||||
|
||||
//do not call this method from system context (network callback)
|
||||
void WS2812FX::finalizeInit(uint16_t countPixels)
|
||||
void WS2812FX::finalizeInit(void)
|
||||
{
|
||||
RESET_RUNTIME;
|
||||
_length = countPixels;
|
||||
isRgbw = isOffRefreshRequred = false;
|
||||
|
||||
//if busses failed to load, add default (FS issue...)
|
||||
//if busses failed to load, add default (fresh install, FS issue, ...)
|
||||
if (busses.getNumBusses() == 0) {
|
||||
const uint8_t defDataPins[] = {DATA_PINS};
|
||||
const uint16_t defCounts[] = {PIXEL_COUNTS};
|
||||
const uint8_t defNumBusses = ((sizeof defDataPins) / (sizeof defDataPins[0]));
|
||||
const uint8_t defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0]));
|
||||
const uint8_t defNumBusses = ((sizeof defDataPins) / (sizeof defDataPins[0])); // min 1
|
||||
const uint8_t defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0])); // min 1
|
||||
uint16_t prevLen = 0;
|
||||
for (uint8_t i = 0; i < defNumBusses; i++) {
|
||||
for (uint8_t i = 0; i < defNumBusses && i < WLED_MAX_BUSSES; i++) {
|
||||
uint8_t defPin[] = {defDataPins[i]};
|
||||
uint16_t start = prevLen;
|
||||
uint16_t count = _length;
|
||||
if (defNumBusses > 1 && defNumCounts) {
|
||||
count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
|
||||
}
|
||||
uint16_t count = (i < defNumCounts) ? defCounts[i] : defCounts[i>0?i-1:0];
|
||||
prevLen += count;
|
||||
BusConfig defCfg = BusConfig(DEFAULT_LED_TYPE, defPin, start, count, COL_ORDER_GRB);
|
||||
busses.add(defCfg);
|
||||
@ -92,65 +89,33 @@ void WS2812FX::finalizeInit(uint16_t countPixels)
|
||||
|
||||
deserializeMap();
|
||||
|
||||
uint16_t segStarts[MAX_NUM_SEGMENTS] = {0};
|
||||
uint16_t segStops [MAX_NUM_SEGMENTS] = {0};
|
||||
_length = 0;
|
||||
for (uint8_t i=0; i<busses.getNumBusses(); i++) {
|
||||
Bus *bus = busses.getBus(i);
|
||||
if (bus == nullptr) continue;
|
||||
if (_length+bus->getLength() > MAX_LEDS) break;
|
||||
//RGBW mode is enabled if at least one of the strips is RGBW
|
||||
isRgbw |= bus->isRgbw();
|
||||
//refresh is required to remain off if at least one of the strips requires the refresh.
|
||||
isOffRefreshRequred |= BusManager::isOffRefreshRequred(bus->getType());
|
||||
_length += bus->getLength();
|
||||
}
|
||||
ledCount = _length;
|
||||
|
||||
// We will create default segments im populateDefaultSegments()
|
||||
|
||||
setBrightness(_brightness);
|
||||
|
||||
//TODO make sure segments are only refreshed when bus config actually changed (new settings page)
|
||||
uint8_t s = 0;
|
||||
#ifdef ESP8266
|
||||
for (uint8_t i = 0; i < busses.getNumBusses(); i++) {
|
||||
Bus* b = busses.getBus(i);
|
||||
|
||||
if (autoSegments) { //make one segment per bus
|
||||
segStarts[s] = b->getStart();
|
||||
segStops[s] = segStarts[s] + b->getLength();
|
||||
|
||||
//check for overlap with previous segments
|
||||
for (uint8_t j = 0; j < s; j++) {
|
||||
if (segStops[j] > segStarts[s] && segStarts[j] < segStops[s]) {
|
||||
//segments overlap, merge
|
||||
segStarts[j] = min(segStarts[s],segStarts[j]);
|
||||
segStops [j] = max(segStops [s],segStops [j]); segStops[s] = 0;
|
||||
s--;
|
||||
}
|
||||
}
|
||||
s++;
|
||||
}
|
||||
|
||||
#ifdef ESP8266
|
||||
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
|
||||
}
|
||||
|
||||
if (autoSegments) {
|
||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) {
|
||||
_segments[i].start = segStarts[i];
|
||||
_segments[i].stop = segStops [i];
|
||||
}
|
||||
} else {
|
||||
//expand the main seg to the entire length, but only if there are no other segments
|
||||
uint8_t mainSeg = getMainSegmentId();
|
||||
bool isMultipleSegs = false;
|
||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
|
||||
{
|
||||
if (i != mainSeg && _segments[i].isActive()) isMultipleSegs = true;
|
||||
}
|
||||
if (!isMultipleSegs) {
|
||||
_segments[mainSeg].start = 0; _segments[mainSeg].stop = _length;
|
||||
} else {
|
||||
//there are multiple segments, leave them, but prune length to total
|
||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
|
||||
{
|
||||
if (_segments[i].start > _length) _segments[i].stop = 0;
|
||||
if (_segments[i].stop > _length) _segments[i].stop = _length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812FX::service() {
|
||||
@ -218,14 +183,13 @@ uint16_t WS2812FX::realPixelIndex(uint16_t i) {
|
||||
int16_t realIndex = iGroup;
|
||||
if (IS_REVERSE) {
|
||||
if (IS_MIRROR) {
|
||||
realIndex = (SEGMENT.length() -1) / 2 - iGroup; //only need to index half the pixels
|
||||
realIndex = (SEGMENT.length() - 1) / 2 - iGroup; //only need to index half the pixels
|
||||
} else {
|
||||
realIndex = SEGMENT.length() - iGroup - 1;
|
||||
realIndex = (SEGMENT.length() - 1) - iGroup;
|
||||
}
|
||||
}
|
||||
|
||||
realIndex += SEGMENT.start;
|
||||
|
||||
return realIndex;
|
||||
}
|
||||
|
||||
@ -246,7 +210,6 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
}
|
||||
|
||||
if (SEGLEN) {//from segment
|
||||
|
||||
//color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments)
|
||||
if (_bri_t < 255) {
|
||||
r = scale8(r, _bri_t);
|
||||
@ -256,12 +219,12 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
}
|
||||
uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b));
|
||||
|
||||
bool reversed = IS_REVERSE;
|
||||
/* Set all the pixels in the group */
|
||||
uint16_t realIndex = realPixelIndex(i);
|
||||
uint16_t len = SEGMENT.length();
|
||||
|
||||
for (uint16_t j = 0; j < SEGMENT.grouping; j++) {
|
||||
int indexSet = realIndex + (reversed ? -j : j);
|
||||
uint16_t indexSet = realIndex + (IS_REVERSE ? -j : j);
|
||||
if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) {
|
||||
if (IS_MIRROR) { //set the corresponding mirrored pixel
|
||||
uint16_t indexMir = SEGMENT.stop - indexSet + SEGMENT.start - 1;
|
||||
@ -282,7 +245,6 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
}
|
||||
} else { //live data, etc.
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
|
||||
uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b));
|
||||
busses.setPixelColor(i, col);
|
||||
}
|
||||
@ -563,7 +525,9 @@ uint32_t WS2812FX::getPixelColor(uint16_t i)
|
||||
}
|
||||
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
if (i >= _length) return 0;
|
||||
|
||||
// TODO: may need to add IS_REVERSE and IS_MIRROR logic
|
||||
return busses.getPixelColor(i);
|
||||
}
|
||||
|
||||
@ -584,14 +548,14 @@ uint32_t WS2812FX::getLastShow(void) {
|
||||
return _lastShow;
|
||||
}
|
||||
|
||||
//TODO these need to be on a per-strip basis
|
||||
uint8_t WS2812FX::getColorOrder(void) {
|
||||
return COL_ORDER_GRB;
|
||||
}
|
||||
|
||||
void WS2812FX::setColorOrder(uint8_t co) {
|
||||
//bus->SetColorOrder(co);
|
||||
}
|
||||
// there is no longer any need for these two
|
||||
//uint8_t WS2812FX::getColorOrder(void) {
|
||||
// return COL_ORDER_GRB;
|
||||
//}
|
||||
//
|
||||
//void WS2812FX::setColorOrder(uint8_t co) {
|
||||
// //bus->SetColorOrder(co);
|
||||
//}
|
||||
|
||||
void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) {
|
||||
if (n >= MAX_NUM_SEGMENTS) return;
|
||||
@ -604,6 +568,10 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping,
|
||||
if (i2 <= i1) //disable segment
|
||||
{
|
||||
seg.stop = 0;
|
||||
if (seg.name) {
|
||||
delete[] seg.name;
|
||||
seg.name = nullptr;
|
||||
}
|
||||
if (n == mainSegment) //if main segment is deleted, set first active as main segment
|
||||
{
|
||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
|
||||
@ -628,6 +596,7 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping,
|
||||
}
|
||||
|
||||
void WS2812FX::resetSegments() {
|
||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) if (_segments[i].name) delete _segments[i].name;
|
||||
mainSegment = 0;
|
||||
memset(_segments, 0, sizeof(_segments));
|
||||
//memset(_segment_runtimes, 0, sizeof(_segment_runtimes));
|
||||
@ -656,6 +625,38 @@ void WS2812FX::resetSegments() {
|
||||
_segment_runtimes[0].reset();
|
||||
}
|
||||
|
||||
void WS2812FX::populateDefaultSegments() {
|
||||
uint16_t length = 0;
|
||||
if (autoSegments) {
|
||||
for (uint8_t i=0; i<busses.getNumBusses(); i++) {
|
||||
Bus *bus = busses.getBus(i);
|
||||
if (bus == nullptr) continue;
|
||||
_segments[i].start = bus->getStart();
|
||||
length += bus->getLength();
|
||||
_segments[i].stop = _segments[i].start + bus->getLength();
|
||||
_segments[i].mode = DEFAULT_MODE;
|
||||
_segments[i].colors[0] = DEFAULT_COLOR;
|
||||
_segments[i].speed = DEFAULT_SPEED;
|
||||
_segments[i].intensity = DEFAULT_INTENSITY;
|
||||
_segments[i].grouping = 1;
|
||||
_segments[i].setOption(SEG_OPTION_SELECTED, 1);
|
||||
_segments[i].setOption(SEG_OPTION_ON, 1);
|
||||
_segments[i].opacity = 255;
|
||||
}
|
||||
} else {
|
||||
_segments[0].start = 0;
|
||||
_segments[0].stop = _length;
|
||||
_segments[0].mode = DEFAULT_MODE;
|
||||
_segments[0].colors[0] = DEFAULT_COLOR;
|
||||
_segments[0].speed = DEFAULT_SPEED;
|
||||
_segments[0].intensity = DEFAULT_INTENSITY;
|
||||
_segments[0].grouping = 1;
|
||||
_segments[0].setOption(SEG_OPTION_SELECTED, 1);
|
||||
_segments[0].setOption(SEG_OPTION_ON, 1);
|
||||
_segments[0].opacity = 255;
|
||||
}
|
||||
}
|
||||
|
||||
//After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply)
|
||||
void WS2812FX::setPixelSegment(uint8_t n)
|
||||
{
|
||||
@ -1033,18 +1034,33 @@ uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8
|
||||
|
||||
|
||||
//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
|
||||
void WS2812FX::deserializeMap(uint8_t n) {
|
||||
String fileName = String(F("/ledmap"));
|
||||
if (n) fileName += String(n);
|
||||
fileName += String(F(".json"));
|
||||
bool isFile = WLED_FS.exists(fileName);
|
||||
|
||||
DEBUG_PRINTLN(F("Reading LED map from /ledmap.json..."));
|
||||
|
||||
if (!readObjectFromFile("/ledmap.json", nullptr, &doc)) return; //if file does not exist just exit
|
||||
|
||||
if (customMappingTable != nullptr) {
|
||||
if (!isFile) {
|
||||
// erase custom mapping if selecting nonexistent ledmap.json (n==0)
|
||||
if (!n && customMappingTable != nullptr) {
|
||||
customMappingSize = 0;
|
||||
delete[] customMappingTable;
|
||||
customMappingTable = nullptr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE); // full sized buffer for larger maps
|
||||
DEBUG_PRINT(F("Reading LED map from "));
|
||||
DEBUG_PRINTLN(fileName);
|
||||
|
||||
if (!readObjectFromFile(fileName.c_str(), nullptr, &doc)) return; //if file does not exist just exit
|
||||
|
||||
// erase old custom ledmap
|
||||
if (customMappingTable != nullptr) {
|
||||
customMappingSize = 0;
|
||||
delete[] customMappingTable;
|
||||
customMappingTable = nullptr;
|
||||
}
|
||||
|
||||
JsonArray map = doc[F("map")];
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "wled.h"
|
||||
#ifndef WLED_DISABLE_BLYNK
|
||||
#include "src/dependencies/blynk/Blynk/BlynkHandlers.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Remote light control with the free Blynk app
|
||||
|
@ -10,18 +10,24 @@
|
||||
#include "bus_wrapper.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
#define GET_BIT(var,bit) (((var)>>(bit))&0x01)
|
||||
#define SET_BIT(var,bit) ((var)|=(uint16_t)(0x0001<<(bit)))
|
||||
#define UNSET_BIT(var,bit) ((var)&=(~(uint16_t)(0x0001<<(bit))))
|
||||
|
||||
//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;
|
||||
uint16_t count;
|
||||
uint16_t start;
|
||||
uint8_t colorOrder;
|
||||
bool reversed;
|
||||
uint8_t skipAmount;
|
||||
bool rgbwOverride;
|
||||
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, uint8_t skip=0) {
|
||||
type = busType; count = len; start = pstart;
|
||||
colorOrder = pcolorOrder; reversed = rev; skipAmount = skip;
|
||||
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0) {
|
||||
rgbwOverride = (bool) GET_BIT(busType,7);
|
||||
type = busType & 0x7F; // bit 7 may be/is hacked to include RGBW info (1=RGBW, 0=RGB)
|
||||
count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev; skipAmount = skip;
|
||||
uint8_t nPins = 1;
|
||||
if (type > 47) nPins = 2;
|
||||
else if (type > 40 && type < 46) nPins = NUM_PWM_PINS(type);
|
||||
@ -74,7 +80,7 @@ class Bus {
|
||||
}
|
||||
|
||||
virtual uint16_t getLength() {
|
||||
return 1;
|
||||
return 1; // is this ok? shouldn't it be 0 in virtual function?
|
||||
}
|
||||
|
||||
virtual void setColorOrder() {}
|
||||
@ -130,12 +136,12 @@ class BusDigital : public Bus {
|
||||
reversed = bc.reversed;
|
||||
_skip = bc.skipAmount; //sacrificial pixels
|
||||
_len = bc.count + _skip;
|
||||
_iType = PolyBus::getI(bc.type, _pins, nr);
|
||||
_rgbw = bc.rgbwOverride || Bus::isRgbw(bc.type); // RGBW override in bit 7
|
||||
_iType = PolyBus::getI(bc.type, _pins, nr, _rgbw);
|
||||
if (_iType == I_NONE) return;
|
||||
_busPtr = PolyBus::create(_iType, _pins, _len, nr);
|
||||
_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);
|
||||
};
|
||||
|
||||
inline void show() {
|
||||
@ -189,7 +195,7 @@ class BusDigital : public Bus {
|
||||
}
|
||||
|
||||
inline bool isRgbw() {
|
||||
return (_type == TYPE_SK6812_RGBW || _type == TYPE_TM1814);
|
||||
return (_rgbw || _type == TYPE_SK6812_RGBW || _type == TYPE_TM1814);
|
||||
}
|
||||
|
||||
inline uint8_t skippedLeds() {
|
||||
@ -201,7 +207,6 @@ class BusDigital : public Bus {
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
//Serial.println("Digital Cleanup");
|
||||
PolyBus::cleanup(_busPtr, _iType);
|
||||
_iType = I_NONE;
|
||||
_valid = false;
|
||||
@ -220,6 +225,7 @@ class BusDigital : public Bus {
|
||||
uint8_t _iType = I_NONE;
|
||||
uint16_t _len = 0;
|
||||
uint8_t _skip = 0;
|
||||
bool _rgbw = false;
|
||||
void * _busPtr = nullptr;
|
||||
};
|
||||
|
||||
@ -227,6 +233,7 @@ class BusDigital : public Bus {
|
||||
class BusPwm : public Bus {
|
||||
public:
|
||||
BusPwm(BusConfig &bc) : Bus(bc.type, bc.start) {
|
||||
_valid = false;
|
||||
if (!IS_PWM(bc.type)) return;
|
||||
uint8_t numPins = NUM_PWM_PINS(bc.type);
|
||||
|
||||
@ -280,10 +287,12 @@ class BusPwm : public Bus {
|
||||
|
||||
//does no index check
|
||||
uint32_t getPixelColor(uint16_t pix) {
|
||||
if (!_valid) return 0;
|
||||
return ((_data[3] << 24) | (_data[0] << 16) | (_data[1] << 8) | (_data[2]));
|
||||
}
|
||||
|
||||
void show() {
|
||||
if (!_valid) return;
|
||||
uint8_t numPins = NUM_PWM_PINS(_type);
|
||||
for (uint8_t i = 0; i < numPins; i++) {
|
||||
uint8_t scaled = (_data[i] * _bri) / 255;
|
||||
@ -302,7 +311,9 @@ class BusPwm : public Bus {
|
||||
|
||||
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];
|
||||
for (uint8_t i = 0; i < numPins; i++) {
|
||||
pinArray[i] = _pins[i];
|
||||
}
|
||||
return numPins;
|
||||
}
|
||||
|
||||
@ -328,13 +339,13 @@ class BusPwm : public Bus {
|
||||
void deallocatePins() {
|
||||
uint8_t numPins = NUM_PWM_PINS(_type);
|
||||
for (uint8_t i = 0; i < numPins; i++) {
|
||||
pinManager.deallocatePin(_pins[i], PinOwner::BusPwm);
|
||||
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], PinOwner::BusPwm);
|
||||
}
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
pinManager.deallocateLedc(_ledcStart, numPins);
|
||||
@ -342,6 +353,86 @@ class BusPwm : public Bus {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class BusVirtual : public Bus {
|
||||
public:
|
||||
BusVirtual(BusConfig &bc) : Bus(bc.type, bc.start) {
|
||||
_valid = false;
|
||||
_data = (byte *)malloc(bc.count * (_rgbw ? 4 : 3));
|
||||
if (_data == nullptr) return;
|
||||
memset(_data, 0, bc.count * (_rgbw ? 4 : 3));
|
||||
_len = bc.count;
|
||||
//_rgbw = bc.rgbwOverride; // RGBW override in bit 7 or can have a special type
|
||||
_rgbw = _type == TYPE_VIRTUAL_RGBW;
|
||||
_colorOrder = bc.colorOrder;
|
||||
_client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]);
|
||||
_broadcastLock = false;
|
||||
_valid = true;
|
||||
};
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c) {
|
||||
if (!_valid || pix >= _len) return;
|
||||
_data[pix] = 0xFF & (c >> 16);
|
||||
_data[pix+1] = 0xFF & (c >> 8);
|
||||
_data[pix+2] = 0xFF & (c );
|
||||
if (_rgbw) _data[pix+3] = 0xFF & (c >> 24);
|
||||
}
|
||||
|
||||
uint32_t getPixelColor(uint16_t pix) {
|
||||
if (!_valid || pix >= _len) return 0;
|
||||
return ((_rgbw?(_data[pix+3] << 24):0) | (_data[pix] << 16) | (_data[pix+1] << 8) | (_data[pix+2]));
|
||||
}
|
||||
|
||||
void show() {
|
||||
if (!_valid || _broadcastLock) return;
|
||||
_broadcastLock = true;
|
||||
realtimeBoroadcast(_client, _len, _data, _rgbw);
|
||||
_broadcastLock = false;
|
||||
}
|
||||
|
||||
inline bool canShow() {
|
||||
return !_broadcastLock;
|
||||
}
|
||||
|
||||
inline void setBrightness(uint8_t b) {
|
||||
// not sure if this is correctly implemented
|
||||
for (uint16_t pix=0; pix<_len; pix++) {
|
||||
_data[pix ] = scale8(_data[pix ], b);
|
||||
_data[pix+1] = scale8(_data[pix+1], b);
|
||||
_data[pix+2] = scale8(_data[pix+2], b);
|
||||
if (_rgbw) _data[pix+3] = scale8(_data[pix+3], b);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool isRgbw() {
|
||||
return _rgbw;
|
||||
}
|
||||
|
||||
inline uint16_t getLength() {
|
||||
return _len;
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
_type = I_NONE;
|
||||
_valid = false;
|
||||
if (_data != nullptr) free(_data);
|
||||
_data = nullptr;
|
||||
}
|
||||
|
||||
~BusVirtual() {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
private:
|
||||
IPAddress _client;
|
||||
uint16_t _len = 0;
|
||||
uint8_t _colorOrder;
|
||||
bool _rgbw;
|
||||
bool _broadcastLock;
|
||||
byte* _data;
|
||||
};
|
||||
|
||||
|
||||
class BusManager {
|
||||
public:
|
||||
BusManager() {
|
||||
@ -352,7 +443,9 @@ class BusManager {
|
||||
static uint32_t memUsage(BusConfig &bc) {
|
||||
uint8_t type = bc.type;
|
||||
uint16_t len = bc.count;
|
||||
if (type < 32) {
|
||||
if (type < 4) {
|
||||
return len * (type+1);
|
||||
} else if (type < 32) {
|
||||
#ifdef ESP8266
|
||||
if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem
|
||||
if (type > 29) return len*20; //RGBW
|
||||
@ -373,7 +466,9 @@ class BusManager {
|
||||
|
||||
int add(BusConfig &bc) {
|
||||
if (numBusses >= WLED_MAX_BUSSES) return -1;
|
||||
if (IS_DIGITAL(bc.type)) {
|
||||
if (bc.type>1 && bc.type<4) {
|
||||
busses[numBusses] = new BusVirtual(bc);
|
||||
} else if (IS_DIGITAL(bc.type)) {
|
||||
busses[numBusses] = new BusDigital(bc, numBusses);
|
||||
} else {
|
||||
busses[numBusses] = new BusPwm(bc);
|
||||
@ -444,6 +539,7 @@ class BusManager {
|
||||
return len;
|
||||
}
|
||||
|
||||
// a workaround
|
||||
static inline bool isRgbw(uint8_t type) {
|
||||
return Bus::isRgbw(type);
|
||||
}
|
||||
|
@ -383,11 +383,6 @@ class PolyBus {
|
||||
uint8_t w = c >> 24;
|
||||
RgbwColor col;
|
||||
|
||||
//TODO make color order override possible on a per-strip basis
|
||||
#ifdef COLOR_ORDER_OVERRIDE
|
||||
if (pix >= COO_MIN && pix < COO_MAX) co = COO_ORDER;
|
||||
#endif
|
||||
|
||||
//reorder channels to selected order
|
||||
switch (co)
|
||||
{
|
||||
@ -559,10 +554,6 @@ class PolyBus {
|
||||
case I_SS_P98_3: col = (static_cast<B_SS_P98_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
}
|
||||
|
||||
#ifdef COLOR_ORDER_OVERRIDE
|
||||
if (pix >= COO_MIN && pix < COO_MAX) co = COO_ORDER;
|
||||
#endif
|
||||
|
||||
switch (co)
|
||||
{
|
||||
// W G R B
|
||||
@ -632,14 +623,17 @@ class PolyBus {
|
||||
}
|
||||
|
||||
//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) {
|
||||
static uint8_t getI(uint8_t busType, uint8_t* pins, uint8_t num = 0, bool isRGBW = false) {
|
||||
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
|
||||
// temporary hack to limit use of hardware SPI to a single SPI peripheral: only allow ESP32 hardware serial on segment 0
|
||||
if (!num) isHSPI = true;
|
||||
//if (num==0 && pins[0] == P_32_VS_MOSI && pins[1] == P_32_VS_CLK) isHSPI = true; // no nultiplexing, up to 80MHz clock
|
||||
//if (num==1 && pins[0] == P_32_HS_MOSI && pins[1] == P_32_HS_CLK) isHSPI = true;
|
||||
#endif
|
||||
uint8_t t = I_NONE;
|
||||
switch (busType) {
|
||||
@ -658,9 +652,8 @@ class PolyBus {
|
||||
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;
|
||||
return (isRGBW ? I_8266_U0_NEO_4 : I_8266_U0_NEO_3) + offset;
|
||||
case TYPE_WS2811_400KHZ:
|
||||
return I_8266_U0_400_3 + offset;
|
||||
case TYPE_TM1814:
|
||||
@ -678,9 +671,10 @@ class PolyBus {
|
||||
switch (busType) {
|
||||
case TYPE_WS2812_RGB:
|
||||
case TYPE_WS2812_WWA:
|
||||
return I_32_RN_NEO_3 + offset;
|
||||
// return I_32_RN_NEO_3 + offset;
|
||||
case TYPE_SK6812_RGBW:
|
||||
return I_32_RN_NEO_4 + offset;
|
||||
// return I_32_RN_NEO_4 + offset;
|
||||
return (isRGBW ? I_32_RN_NEO_4 : I_32_RN_NEO_3) + offset;
|
||||
case TYPE_WS2811_400KHZ:
|
||||
return I_32_RN_400_3 + offset;
|
||||
case TYPE_TM1814:
|
||||
|
@ -10,10 +10,11 @@ static const char _mqtt_topic_button[] PROGMEM = "%s/button/%d"; // optimize fl
|
||||
|
||||
void shortPressAction(uint8_t b)
|
||||
{
|
||||
if (!macroButton[b])
|
||||
{
|
||||
toggleOnOff();
|
||||
colorUpdated(CALL_MODE_BUTTON);
|
||||
if (!macroButton[b]) {
|
||||
switch (b) {
|
||||
case 0: toggleOnOff(); colorUpdated(CALL_MODE_BUTTON); break;
|
||||
default: ++effectCurrent %= strip.getModeCount(); colorUpdated(CALL_MODE_BUTTON); break;
|
||||
}
|
||||
} else {
|
||||
applyPreset(macroButton[b], CALL_MODE_BUTTON);
|
||||
}
|
||||
@ -26,6 +27,44 @@ void shortPressAction(uint8_t b)
|
||||
}
|
||||
}
|
||||
|
||||
void longPressAction(uint8_t b)
|
||||
{
|
||||
if (!macroLongPress[b]) {
|
||||
switch (b) {
|
||||
case 0: _setRandomColor(false,true); break;
|
||||
default: bri += 8; colorUpdated(CALL_MODE_BUTTON); buttonPressedTime[b] = millis(); break; // repeatable action
|
||||
}
|
||||
} else {
|
||||
applyPreset(macroLongPress[b], CALL_MODE_BUTTON);
|
||||
}
|
||||
|
||||
// publish MQTT message
|
||||
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
||||
char subuf[64];
|
||||
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
||||
mqtt->publish(subuf, 0, false, "long");
|
||||
}
|
||||
}
|
||||
|
||||
void doublePressAction(uint8_t b)
|
||||
{
|
||||
if (!macroDoublePress[b]) {
|
||||
switch (b) {
|
||||
case 0: toggleOnOff(); colorUpdated(CALL_MODE_BUTTON); break;
|
||||
default: ++effectPalette %= strip.getPaletteCount(); colorUpdated(CALL_MODE_BUTTON); break;
|
||||
}
|
||||
} else {
|
||||
applyPreset(macroDoublePress[b], CALL_MODE_BUTTON);
|
||||
}
|
||||
|
||||
// publish MQTT message
|
||||
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
||||
char subuf[64];
|
||||
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
||||
mqtt->publish(subuf, 0, false, "double");
|
||||
}
|
||||
}
|
||||
|
||||
bool isButtonPressed(uint8_t i)
|
||||
{
|
||||
if (btnPin[i]<0) return false;
|
||||
@ -186,61 +225,43 @@ void handleButton()
|
||||
}
|
||||
|
||||
//momentary button logic
|
||||
if (isButtonPressed(b)) //pressed
|
||||
{
|
||||
if (isButtonPressed(b)) { //pressed
|
||||
|
||||
if (!buttonPressedBefore[b]) buttonPressedTime[b] = millis();
|
||||
buttonPressedBefore[b] = true;
|
||||
|
||||
if (millis() - buttonPressedTime[b] > 600) //long press
|
||||
{
|
||||
if (!buttonLongPressed[b])
|
||||
{
|
||||
if (macroLongPress[b]) {applyPreset(macroLongPress[b], CALL_MODE_BUTTON);}
|
||||
else _setRandomColor(false,true);
|
||||
|
||||
// publish MQTT message
|
||||
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
||||
char subuf[64];
|
||||
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
||||
mqtt->publish(subuf, 0, false, "long");
|
||||
if (millis() - buttonPressedTime[b] > 600) { //long press
|
||||
if (!buttonLongPressed[b]) longPressAction(b);
|
||||
else if (b) { // repeatable action (~3 times per s) on button > 0
|
||||
longPressAction(b);
|
||||
buttonPressedTime[b] = millis() - 300; // 300ms
|
||||
}
|
||||
|
||||
buttonLongPressed[b] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!isButtonPressed(b) && buttonPressedBefore[b]) //released
|
||||
{
|
||||
|
||||
} else if (!isButtonPressed(b) && buttonPressedBefore[b]) { //released
|
||||
|
||||
long dur = millis() - buttonPressedTime[b];
|
||||
if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore[b] = false; continue;} //too short "press", debounce
|
||||
bool doublePress = buttonWaitTime[b];
|
||||
bool doublePress = buttonWaitTime[b]; //did we have short press before?
|
||||
buttonWaitTime[b] = 0;
|
||||
|
||||
if (dur > 6000 && b==0) //long press on button 0
|
||||
{
|
||||
if (b == 0 && dur > 6000) { //long press on button 0 (when released)
|
||||
WLED::instance().initAP(true);
|
||||
}
|
||||
else if (!buttonLongPressed[b]) { //short press
|
||||
if (macroDoublePress[b])
|
||||
{
|
||||
} else if (!buttonLongPressed[b]) { //short press
|
||||
// if this is second release within 350ms it is a double press (buttonWaitTime!=0)
|
||||
if (doublePress) {
|
||||
applyPreset(macroDoublePress[b], CALL_MODE_BUTTON);
|
||||
|
||||
// publish MQTT message
|
||||
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
||||
char subuf[64];
|
||||
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
||||
mqtt->publish(subuf, 0, false, "double");
|
||||
doublePressAction(b);
|
||||
} else {
|
||||
buttonWaitTime[b] = millis();
|
||||
}
|
||||
} else buttonWaitTime[b] = millis();
|
||||
} else shortPressAction(b);
|
||||
}
|
||||
buttonPressedBefore[b] = false;
|
||||
buttonLongPressed[b] = false;
|
||||
}
|
||||
|
||||
if (buttonWaitTime[b] && millis() - buttonWaitTime[b] > 450 && !buttonPressedBefore[b])
|
||||
{
|
||||
// if 450ms elapsed since last press/release it is a short press
|
||||
if (buttonWaitTime[b] && millis() - buttonWaitTime[b] > 350 && !buttonPressedBefore[b]) {
|
||||
buttonWaitTime[b] = 0;
|
||||
shortPressAction(b);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "wled.h"
|
||||
#include "wled_ethernet.h"
|
||||
|
||||
/*
|
||||
* Serializes and parses the cfg.json and wsec.json settings files, stored in internal FS.
|
||||
@ -29,6 +30,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
getStringFromJson(cmDNS, id[F("mdns")], 33);
|
||||
getStringFromJson(serverDescription, id[F("name")], 33);
|
||||
getStringFromJson(alexaInvocationName, id[F("inv")], 33);
|
||||
#ifndef WLED_DISABLE_SIMPLE_UI
|
||||
CJSON(simplifiedUI, id[F("sui")]);
|
||||
#endif
|
||||
|
||||
JsonObject nw_ins_0 = doc["nw"]["ins"][0];
|
||||
getStringFromJson(clientSSID, nw_ins_0[F("ssid")], 33);
|
||||
@ -60,7 +64,6 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
|
||||
CJSON(apBehavior, ap[F("behav")]);
|
||||
|
||||
|
||||
/*
|
||||
JsonArray ap_ip = ap["ip"];
|
||||
for (byte i = 0; i < 4; i++) {
|
||||
@ -79,16 +82,16 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
|
||||
CJSON(ledCount, hw_led[F("total")]);
|
||||
if (ledCount > MAX_LEDS) ledCount = MAX_LEDS;
|
||||
uint16_t lC = 0;
|
||||
|
||||
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
|
||||
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]);
|
||||
CJSON(strip.rgbwMode, hw_led[F("rgbwm")]);
|
||||
|
||||
JsonArray ins = hw_led["ins"];
|
||||
|
||||
if (fromFS || !ins.isNull()) {
|
||||
uint8_t s = 0; //bus iterator
|
||||
strip.isRgbw = false;
|
||||
strip.isOffRefreshRequred = false;
|
||||
uint8_t s = 0; // bus iterator
|
||||
busses.removeAll();
|
||||
uint32_t mem = 0;
|
||||
for (JsonObject elm : ins) {
|
||||
@ -104,12 +107,20 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
}
|
||||
|
||||
uint16_t length = elm[F("len")] | 1;
|
||||
if (length==0 || length+lC > MAX_LEDS) continue; // zero length or we reached max. number of LEDs, just stop
|
||||
uint8_t colorOrder = (int)elm[F("order")];
|
||||
uint8_t skipFirst = elm[F("skip")];
|
||||
uint16_t start = elm[F("start")] | 0;
|
||||
if (start > lC+length) continue; // something is very wrong :)
|
||||
uint8_t ledType = elm["type"] | TYPE_WS2812_RGB;
|
||||
bool reversed = elm["rev"];
|
||||
|
||||
//if ((bool)elm[F("rgbw")]) SET_BIT(ledType,7); else UNSET_BIT(ledType,7); // hack bit 7 to indicate RGBW (as an override if necessary)
|
||||
s++;
|
||||
lC += length;
|
||||
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst);
|
||||
mem += BusManager::memUsage(bc);
|
||||
if (mem <= MAX_LED_MEMORY && busses.getNumBusses() <= WLED_MAX_BUSSES) busses.add(bc); // finalization will be done in WLED::beginStrip()
|
||||
/*
|
||||
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst);
|
||||
if (bc.adjustBounds(ledCount)) {
|
||||
//RGBW mode is enabled if at least one of the strips is RGBW
|
||||
@ -120,9 +131,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
mem += busses.memUsage(bc);
|
||||
if (mem <= MAX_LED_MEMORY) busses.add(bc);
|
||||
}
|
||||
*/
|
||||
}
|
||||
strip.finalizeInit(ledCount);
|
||||
// finalization done in beginStrip()
|
||||
}
|
||||
if (lC > ledCount) ledCount = lC; // fix incorrect total length (honour analog setup)
|
||||
if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus
|
||||
|
||||
// read multiple button configuration
|
||||
@ -461,6 +474,7 @@ void serializeConfig() {
|
||||
id[F("mdns")] = cmDNS;
|
||||
id[F("name")] = serverDescription;
|
||||
id[F("inv")] = alexaInvocationName;
|
||||
id[F("sui")] = simplifiedUI;
|
||||
|
||||
JsonObject nw = doc.createNestedObject("nw");
|
||||
|
||||
@ -500,6 +514,25 @@ void serializeConfig() {
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
JsonObject ethernet = doc.createNestedObject("eth");
|
||||
ethernet["type"] = ethernetType;
|
||||
if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
|
||||
JsonArray pins = ethernet.createNestedArray("pin");
|
||||
for (uint8_t p=0; p<WLED_ETH_RSVD_PINS_COUNT; p++) pins.add(esp32_nonconfigurable_ethernet_pins[p].pin);
|
||||
if (ethernetBoards[ethernetType].eth_power>=0) pins.add(ethernetBoards[ethernetType].eth_power);
|
||||
if (ethernetBoards[ethernetType].eth_mdc>=0) pins.add(ethernetBoards[ethernetType].eth_mdc);
|
||||
if (ethernetBoards[ethernetType].eth_mdio>=0) pins.add(ethernetBoards[ethernetType].eth_mdio);
|
||||
switch (ethernetBoards[ethernetType].eth_clk_mode) {
|
||||
case ETH_CLOCK_GPIO0_IN:
|
||||
case ETH_CLOCK_GPIO0_OUT:
|
||||
pins.add(0);
|
||||
break;
|
||||
case ETH_CLOCK_GPIO16_OUT:
|
||||
pins.add(16);
|
||||
break;
|
||||
case ETH_CLOCK_GPIO17_OUT:
|
||||
pins.add(17);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
JsonObject hw = doc.createNestedObject("hw");
|
||||
@ -526,6 +559,7 @@ void serializeConfig() {
|
||||
ins["rev"] = bus->reversed;
|
||||
ins[F("skip")] = bus->skippedLeds();
|
||||
ins["type"] = bus->getType();
|
||||
ins[F("rgbw")] = bus->isRgbw();
|
||||
}
|
||||
|
||||
// button(s)
|
||||
@ -550,7 +584,7 @@ void serializeConfig() {
|
||||
|
||||
JsonObject hw_ir = hw.createNestedObject("ir");
|
||||
hw_ir["pin"] = irPin;
|
||||
hw_ir[F("type")] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled )
|
||||
hw_ir["type"] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled )
|
||||
|
||||
JsonObject hw_relay = hw.createNestedObject(F("relay"));
|
||||
hw_relay["pin"] = rlyPin;
|
||||
|
@ -122,6 +122,8 @@
|
||||
|
||||
#define TYPE_NONE 0 //light is not configured
|
||||
#define TYPE_RESERVED 1 //unused. Might indicate a "virtual" light
|
||||
#define TYPE_VIRTUAL_RGB 2 //virtual RGB bus (master broadcast bus)
|
||||
#define TYPE_VIRTUAL_RGBW 3 //virtual RGBW bus (master broadcast bus)
|
||||
//Digital types (data pin only) (16-31)
|
||||
#define TYPE_WS2812_1CH 20 //white-only chips
|
||||
#define TYPE_WS2812_WWA 21 //amber + warm + cold white
|
||||
@ -233,7 +235,7 @@
|
||||
// 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
|
||||
#ifdef ESP8266
|
||||
#define MAX_LEDS 1664 // can't rely on memory limit to limit this to 1600 LEDs
|
||||
#define MAX_LEDS 1200 // can't rely on memory limit to limit this to 1200 LEDs
|
||||
#else
|
||||
#define MAX_LEDS 8192
|
||||
#endif
|
||||
@ -241,14 +243,14 @@
|
||||
|
||||
#ifndef MAX_LED_MEMORY
|
||||
#ifdef ESP8266
|
||||
#define MAX_LED_MEMORY 5000
|
||||
#define MAX_LED_MEMORY 4000
|
||||
#else
|
||||
#define MAX_LED_MEMORY 64000
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MAX_LEDS_PER_BUS
|
||||
#define MAX_LEDS_PER_BUS 4096
|
||||
#define MAX_LEDS_PER_BUS 2048 // may not be enough for fast LEDs (i.e. APA102)
|
||||
#endif
|
||||
|
||||
// string temp buffer (now stored in stack locally)
|
||||
@ -282,7 +284,7 @@
|
||||
|
||||
// Maximum size of node map (list of other WLED instances)
|
||||
#ifdef ESP8266
|
||||
#define WLED_MAX_NODES 15
|
||||
#define WLED_MAX_NODES 24
|
||||
#else
|
||||
#define WLED_MAX_NODES 150
|
||||
#endif
|
||||
@ -304,8 +306,4 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_LED_COUNT
|
||||
#define DEFAULT_LED_COUNT 30
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because one or more lines are too long
@ -24,8 +24,8 @@
|
||||
<button id="buttonSync" onclick="toggleSync()"><i class="icons"></i><p class="tab-label">Sync</p></button>
|
||||
<button id="buttonSr" onclick="toggleLiveview()"><i class="icons"></i><p class="tab-label">Peek</p></button>
|
||||
<button id="buttonI" onclick="toggleInfo()"><i class="icons"></i><p class="tab-label">Info</p></button>
|
||||
<button id="buttonNodes" onclick="toggleNodes()"><i class="icons"></i><p class="tab-label">Nodes</p></button></div>
|
||||
<button onclick="window.location.href = '/settings';"><i class="icons"></i><p class="tab-label">Config</p></button>
|
||||
<button id="buttonNodes" onclick="toggleNodes()"><i class="icons"></i><p class="tab-label">Nodes</p></button>
|
||||
<button onclick="window.location.href='/settings';"><i class="icons"></i><p class="tab-label">Config</p></button>
|
||||
<button id="buttonPcm" onclick="togglePcMode(true)"><i class="icons"></i><p class="tab-label">PC Mode</p></button>
|
||||
</div>
|
||||
<div id="briwrap">
|
||||
@ -36,6 +36,7 @@
|
||||
<input id="sliderBri" onchange="setBri()" oninput="updateTrail(this)" max="255" min="1" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div>
|
||||
</div>
|
||||
<iframe id="liveview" src="about:blank"></iframe>
|
||||
@ -46,17 +47,26 @@
|
||||
<div id="Colors" class="tabcontent">
|
||||
<div id="picker" class="noslide"></div>
|
||||
<div id="rgbwrap">
|
||||
<div id="rwrap" class="il">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderR" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,1)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div><br>
|
||||
<div id="gwrap" class="il">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderG" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,2)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div><br>
|
||||
<div id="bwrap" class="il">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderB" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,3)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div><br>
|
||||
</div>
|
||||
<div id="wwrap">
|
||||
@ -64,6 +74,7 @@
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderW" class="noslide" onchange="setColor(0)" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div>
|
||||
</div>
|
||||
<div id="qcs-w">
|
||||
@ -77,28 +88,30 @@
|
||||
<div class="qcs" onclick="pC('#0000ff');" title="Blue" style="background-color:#0000ff;"></div>
|
||||
<div class="qcs" onclick="pC('#00ffc8');" title="Cyan" style="background-color:#00ffc8;"></div>
|
||||
<div class="qcs" onclick="pC('#08ff00');" title="Green" style="background-color:#08ff00;"></div>
|
||||
<div class="qcs" onclick="pC('rnd');" title="Random" style="background-color:var(--c-3); padding: 4px 8px; transform: translateY(-10px);">R</div>
|
||||
<div class="qcs" onclick="pC('rnd');" title="Random" style="background:linear-gradient(to right, red, orange, yellow, green, blue, purple);transform: translateY(-11px);">R</div>
|
||||
</div>
|
||||
<div id="csl">
|
||||
<button class="xxs cl btn" onclick="selectSlot(0);">1</button>
|
||||
<button class="xxs cl btn" onclick="selectSlot(1);">2</button>
|
||||
<button class="xxs cl btn" onclick="selectSlot(2);">3</button>
|
||||
<button class="btn xxs" onclick="selectSlot(0);">1</button>
|
||||
<button class="btn xxs" onclick="selectSlot(1);">2</button>
|
||||
<button class="btn xxs" onclick="selectSlot(2);">3</button>
|
||||
</div>
|
||||
<div id="hexw">
|
||||
<input id="hexc" type="text" class="noslide" onkeydown="hexEnter(this)" autocomplete="off" maxlength="8" />
|
||||
<button id="hexcnf" class="xxs btn" onclick="fromHex();"><i class="icons btna-icon"></i></button>
|
||||
<button id="hexcnf" class="btn btn-xs" onclick="fromHex();"><i class="icons btn-icon"></i></button>
|
||||
</div>
|
||||
<p class="labels">
|
||||
<i class="icons sel-icon" onclick="tglHex()"></i>
|
||||
Color palette
|
||||
</p>
|
||||
<p class="labels"><i class="icons sel-icon" onclick="tglHex()"></i> Color palette</p>
|
||||
<div class="il">
|
||||
<div class="staytop fnd">
|
||||
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'pallist')" onfocus="search(this,'pallist')" />
|
||||
<i class="icons clear-icon" onclick="clean(this)"></i>
|
||||
<i class="icons search-icon"></i>
|
||||
</div>
|
||||
<div id="pallist" class="list">
|
||||
<div class="lstI" data-id="0">
|
||||
<label class="check schkl">
|
||||
<label class="radio schkl">
|
||||
|
||||
<input type="radio" value="${palettes[i].id}" name="palette" onChange="setPalette()">
|
||||
<span class="checkmark schk"></span>
|
||||
<span class="radiomark schk"></span>
|
||||
</label>
|
||||
<div class="lstIcontent">
|
||||
<span class="lstIname">
|
||||
@ -120,48 +133,52 @@
|
||||
|
||||
<div id="Effects" class="tabcontent">
|
||||
<p class="labels">Effect speed</p>
|
||||
<div class="staytop">
|
||||
<div class="staytop" id="staytop">
|
||||
<i class="icons slider-icon"></i>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderSpeed" class="noslide" onchange="setSpeed()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||
<output class="sliderbubble hidden"></output>
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div>
|
||||
<p class="labels">Effect intensity</p>
|
||||
<div class="staytop" id="staytop1">
|
||||
<i class="icons slider-icon" onclick="tglLabels()"></i>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderIntensity" class="noslide" onchange="setIntensity()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||
<output class="sliderbubble hidden"></output>
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div>
|
||||
<div class="il">
|
||||
<p class="labels">Effect mode</p>
|
||||
<div class="staytop fnd" id="staytop2">
|
||||
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'fxlist')" onfocus="search(this,'fxlist')" />
|
||||
<i class="icons clear-icon" onclick="clean(this);"></i>
|
||||
<i class="icons search-icon"></i>
|
||||
</div>
|
||||
<div id="fxlist" class="list">
|
||||
Loading...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="Segments" class="tabcontent">
|
||||
<div id="segcont">
|
||||
Loading...
|
||||
</div>
|
||||
<div id="segutil">
|
||||
|
||||
<div id="segutil" class="staybot">
|
||||
</div>
|
||||
<div id="segutil2">
|
||||
<button class="btn btn-s" id="rsbtn" onclick="rSegs()">Reset segments</button>
|
||||
</div>
|
||||
<p>Transition: <input id="tt" class="noslide" type="number" min="0" max="65.5" step="0.1" value="0.7">s</p>
|
||||
<!--p>Transition: <input id="tt" class="noslide" type="number" min="0" max="65.5" step="0.1" value="0.7">s</p-->
|
||||
</div>
|
||||
|
||||
<div id="Presets" class="tabcontent">
|
||||
<div id="putil">
|
||||
|
||||
<div id="putil" class="staytop">
|
||||
</div>
|
||||
<div id="pql">
|
||||
|
||||
</div>
|
||||
<div id="pcont">
|
||||
Loading...
|
||||
@ -183,12 +200,12 @@
|
||||
<div id="imgw">
|
||||
<img class="wi" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB0AAAAFCAYAAAC5Fuf5AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABbSURBVChTlY9bDoAwDMNW7n9nwCipytQN4Z8tbrTHmDmF4oPzyldwRqp1SSdnV/NuZuzqerAByxXznBw3igkeFEfXyUuhK/yFM0CxJfyqXZEOc6/Sr9/bf7uIC5Nwd7orMvAPAAAAAElFTkSuQmCC" />
|
||||
</div><br>
|
||||
<div id="kv">Loading...</div><br>
|
||||
<button class="btn infobtn" onclick="requestJson(null)">Refresh</button>
|
||||
<button class="btn infobtn" onclick="toggleInfo()">Close Info</button><br>
|
||||
<button class="btn infobtn" onclick="toggleNodes()">Instance List</button>
|
||||
<button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button><br>
|
||||
<span class="h">Made with <span id="heart">❤︎</span> by Aircoookie and the WLED community</span>
|
||||
<div id="kv">Loading...</div><br>
|
||||
<button class="btn infobtn" onclick="loadInfo()">Refresh</button>
|
||||
<button class="btn infobtn" onclick="toggleInfo()">Close Info</button><br>
|
||||
<button class="btn infobtn" onclick="toggleNodes()">Instance List</button>
|
||||
<button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button><br>
|
||||
<span class="h">Made with <span id="heart">❤︎</span> by Aircoookie and the WLED community</span>
|
||||
</div>
|
||||
|
||||
<div id="nodes" class="modal">
|
||||
|
1579
wled00/data/index.js
1579
wled00/data/index.js
File diff suppressed because it is too large
Load Diff
@ -16,6 +16,7 @@
|
||||
background: #333;
|
||||
color: #fff;
|
||||
font-family: Verdana, Helvetica, sans-serif;
|
||||
display: inline-block;
|
||||
border: 1px solid #333;
|
||||
font-size: 6vmin;
|
||||
height: var(--h);
|
||||
|
@ -31,14 +31,14 @@ function mMap(){
|
||||
function S(){GCH(15);GetV();mMap();}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");}function B(){window.history.back();}
|
||||
function GetV(){}
|
||||
</script>
|
||||
<style>
|
||||
@import url("style.css");
|
||||
</style>
|
||||
<style>@import url("/style.css");</style>
|
||||
</head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
</div>
|
||||
<h2>Imma firin ma lazer (if it has DMX support)</h2><!-- TODO: Change to something less-meme-related //-->
|
||||
|
||||
Proxy Universe <input name=PU type=number min=0 max=63999 required> from E1.31 to DMX (0=disabled)<br>
|
||||
|
@ -40,17 +40,19 @@
|
||||
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
||||
if (d.um_p && d.um_p.some((e)=>e==parseInt(LCs[i].value,10))) {alert(`Sorry, pins ${JSON.stringify(d.um_p)} can't be used.`);LCs[i].value="";LCs[i].focus();return false;}
|
||||
else if (LCs[i].value > 5 && LCs[i].value < 12) {alert("Sorry, pins 6-11 can not be used.");LCs[i].value="";LCs[i].focus();return false;}
|
||||
else if (!(nm == "IR" || nm=="BT") && LCs[i].value > 33) {alert("Sorry, pins >33 are input only.");LCs[i].value="";LCs[i].focus();return false;}
|
||||
for (j=i+1; j<LCs.length; j++)
|
||||
{
|
||||
var n2 = LCs[j].name.substring(0,2);
|
||||
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4" || n2=="RL" || n2=="BT" || n2=="IR")
|
||||
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {alert(`Pin conflict between ${nm}/${n2}!`);LCs[j].value="";LCs[j].focus();return false;}
|
||||
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {alert(`Pin conflict between ${LCs[i].name}/${LCs[j].name}!`);LCs[j].value="";LCs[j].focus();return false;}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function trySubmit(e) {
|
||||
d.Sf.data.value = '';
|
||||
e.preventDefault();
|
||||
if (!pinsOK()) {e.stopPropagation();return false;} // Prevent form submission and contact with server
|
||||
if (bquot > 100) {var msg = "Too many LEDs for me to handle!"; if (maxM < 10000) msg += "\n\rConsider using an ESP32."; alert(msg);}
|
||||
@ -115,84 +117,119 @@
|
||||
if (d.Sf.LA.value == 255) laprev = 12;
|
||||
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
|
||||
|
||||
// enable/disable LED fields
|
||||
var s = d.getElementsByTagName("select");
|
||||
for (i=0; i<s.length; i++) {
|
||||
// is the field a LED type?
|
||||
if (s[i].name.substring(0,2)=="LT") {
|
||||
n=s[i].name.substring(2);
|
||||
var type = parseInt(s[i].value,10);
|
||||
gId("p0d"+n).innerHTML = (type > 49) ? "Data:" : (type >41) ? "Pins:" : "Pin:";
|
||||
gId("p1d"+n).innerHTML = (type > 49) ? "Clk:" : "";
|
||||
var LK = d.getElementsByName("L1"+n)[0];
|
||||
gId("p0d"+n).innerHTML = (type == 2 || type == 3) ? "IP address:" : (type > 49) ? "Data GPIO:" : (type >41) ? "GPIOs:" : "GPIO:";
|
||||
gId("p1d"+n).innerHTML = (type > 49) ? "Clk GPIO:" : "";
|
||||
var LK = d.getElementsByName("L1"+n)[0]; // clock pin
|
||||
|
||||
memu += getMem(type, d.getElementsByName("LC"+n)[0].value, d.getElementsByName("L0"+n)[0].value);
|
||||
memu += getMem(type, d.getElementsByName("LC"+n)[0].value, d.getElementsByName("L0"+n)[0].value); // calc memory
|
||||
|
||||
// enumerate pins
|
||||
for (p=1; p<5; p++) {
|
||||
var LK = d.getElementsByName("L"+p+n)[0];
|
||||
var LK = d.getElementsByName("L"+p+n)[0]; // secondary pins
|
||||
if (!LK) continue;
|
||||
if ((type>49 && p==1) || (type>41 && type < 50 && (p+40 < type))) // TYPE_xxxx values from const.h
|
||||
if (((type == 2 || type == 3) && p<4) || (type>49 && p==1) || (type>41 && type < 50 && (p+40 < type))) // TYPE_xxxx values from const.h
|
||||
{
|
||||
// display pin field
|
||||
LK.style.display = "inline";
|
||||
LK.required = true;
|
||||
} else {
|
||||
// hide pin field
|
||||
LK.style.display = "none";
|
||||
LK.required = false;
|
||||
LK.value="";
|
||||
}
|
||||
}
|
||||
if (type == 30 || type == 31 || (type > 40 && type < 46 && type != 43)) isRGBW = true;
|
||||
gId("dig"+n).style.display = (type > 31 && type < 48) ? "none":"inline";
|
||||
gId("psd"+n).innerHTML = (type > 31 && type < 48) ? "Index:":"Start:";
|
||||
if (change) {
|
||||
// // blazoncek experimental extension
|
||||
// gId("ew"+n).checked = (type == 30 || type == 31 || type == 44 || type == 45); // RGBW checkbox, TYPE_xxxx values from const.h
|
||||
gId("ls"+n).value = n+1; // set LED start
|
||||
if (type > 31 && type < 48) d.getElementsByName("LC"+n)[0].value = 1; // for sanity change analog count just to 1 LED
|
||||
}
|
||||
// // blazoncek experimental extension
|
||||
// gId("ew"+n).onclick = (type > 31 && type < 48) ? (function(){return false}) : (function(){}); // prevent change for analog
|
||||
// isRGBW |= gId("ew"+n).checked;
|
||||
isRGBW |= (type == 30 || type == 31 || (type > 40 && type < 46 && type != 43)); // RGBW checkbox, TYPE_xxxx values from const.h
|
||||
gId("co"+n).style.display = (type == 2 || type == 3 || type == 41 || type == 42) ? "none":"inline"; // hide color order for PWM W & WW/CW
|
||||
gId("dig"+n+"c").style.display = (type > 40 && type < 48) ? "none":"inline"; // hide count for analog
|
||||
gId("dig"+n+"r").style.display = (type == 2 || type == 3) ? "none":"inline"; // hide reversed for virtual
|
||||
gId("dig"+n+"s").style.display = (type == 2 || type == 3 || (type > 40 && type < 48)) ? "none":"inline"; // hide skip 1st for virtual & analog
|
||||
gId("rev"+n).innerHTML = (type > 40 && type < 48) ? "Inverted":"Reverse (rotated 180°)"; // change reverse text for analog
|
||||
gId("psd"+n).innerHTML = (type > 40 && type < 48) ? "Index:":"Start:"; // change analog start description
|
||||
}
|
||||
}
|
||||
|
||||
// display white channel calculation method
|
||||
var myC = d.querySelectorAll('.wc'),
|
||||
l = myC.length;
|
||||
for (i = 0; i < l; i++) {
|
||||
myC[i].style.display = (isRGBW) ? 'inline':'none';
|
||||
}
|
||||
|
||||
// check for pin conflicts
|
||||
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); // field name
|
||||
var n = LCs[i].name.substring(2); // bus number
|
||||
// do we have a led count field but not total led count
|
||||
if (nm=="LC" && LCs[i].name !== "LC") {
|
||||
var c=parseInt(LCs[i].value,10);
|
||||
/*if(gId("ls"+n).readOnly)*/ gId("ls"+n).value=sLC; // update led start field
|
||||
if(c){sLC+=c;if(c>maxLC)maxLC=c;} // increase led count
|
||||
continue;
|
||||
}
|
||||
// do we have led pins for digital leds
|
||||
if (nm=="L0" || nm=="L1") {
|
||||
var lc=d.getElementsByName("LC"+n)[0];
|
||||
lc.max=maxPB; // update max led count value
|
||||
}
|
||||
// ignore IP address
|
||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3") {
|
||||
var type = parseInt(d.getElementsByName("LT"+n)[0].value, 10); // LED type SELECT
|
||||
if (type==2 || type==3) continue;
|
||||
}
|
||||
// check for pin conflicts
|
||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4" || nm=="RL" || nm=="BT" || nm=="IR")
|
||||
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
||||
var p = []; // used pin array
|
||||
if (d.um_p && Array.isArray(d.um_p)) for (k=0;k<d.um_p.length;k++) p.push(d.um_p[k]); // fill with reservations
|
||||
for (j=0; j<LCs.length; j++) {
|
||||
if (i==j) continue;
|
||||
var n2 = LCs[j].name.substring(0,2);
|
||||
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4" || n2=="RL" || n2=="BT" || n2=="IR") {
|
||||
if (n2.substring(0,1)==="L") {
|
||||
var m = LCs[j].name.substring(2);
|
||||
var t2 = parseInt(d.getElementsByName("LT"+m)[0].value, 10);
|
||||
if (t2==2 || t2==3) continue;
|
||||
}
|
||||
if (LCs[j].value!="" && LCs[j].value!="-1") p.push(parseInt(LCs[j].value,10)); // add current pin
|
||||
}
|
||||
}
|
||||
// now check for conflicts
|
||||
if (p.some((e)=>e==parseInt(LCs[i].value,10))) LCs[i].style.color="red"; else LCs[i].style.color=parseInt(LCs[i].value,10)>33?"orange":"#fff";
|
||||
}
|
||||
}
|
||||
// update total led count
|
||||
if (gId("LC").readOnly) d.getElementsByName("LC")[0].value = sLC;
|
||||
// if we are changing total led count update led count for 1st strip
|
||||
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 n=LCs[i].name.substring(2);
|
||||
var c=parseInt(LCs[i].value,10);
|
||||
if(gId("ls"+n).readOnly) gId("ls"+n).value=sLC;
|
||||
if(c){sLC+=c;if(c>maxLC)maxLC=c;}
|
||||
continue;
|
||||
}
|
||||
if (nm=="L0" || nm=="L1") {
|
||||
var lc=d.getElementsByName("LC"+LCs[i].name.substring(2))[0];
|
||||
lc.max=maxPB;
|
||||
}
|
||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4" || nm=="RL" || nm=="BT" || nm=="IR")
|
||||
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
||||
var p = [];
|
||||
if (d.um_p && Array.isArray(d.um_p)) for (k=0;k<d.um_p.length;k++) p.push(d.um_p[k]);
|
||||
for (j=0; j<LCs.length; j++) {
|
||||
if (i==j) continue;
|
||||
var n2 = LCs[j].name.substring(0,2);
|
||||
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4" || n2=="RL" || n2=="BT" || n2=="IR")
|
||||
if (LCs[j].value!="" && LCs[j].value!="-1") p.push(parseInt(LCs[j].value,10));
|
||||
}
|
||||
if (p.some((e)=>e==parseInt(LCs[i].value,10))) LCs[i].style.color="red"; else LCs[i].style.color="#fff";
|
||||
}
|
||||
}
|
||||
|
||||
// memory usage and warnings
|
||||
gId('m0').innerHTML = memu;
|
||||
bquot = memu / maxM * 100;
|
||||
gId('dbar').style.background = `linear-gradient(90deg, ${bquot > 60 ? (bquot > 90 ? "red":"orange"):"#ccc"} 0 ${bquot}%%, #444 ${bquot}%% 100%%)`;
|
||||
gId('ledwarning').style.display = (sLC > maxPB || maxLC > 800 || bquot > 80) ? 'inline':'none';
|
||||
gId('ledwarning').style.color = (sLC > maxPB || maxLC > maxPB || bquot > 100) ? 'red':'orange';
|
||||
gId('wreason').innerHTML = (bquot > 80) ? "80% of max. LED memory" +(bquot>100 ? ` (<b>WARNING: Using over ${maxM}B!</b>)` : "") : "800 LEDs per pin";
|
||||
|
||||
gId('wreason').innerHTML = (bquot > 80) ? "80% of max. LED memory" +(bquot>100 ? ` (<b>WARNING: Using over ${maxM}B!</b>)` : "") : "800 LEDs per GPIO";
|
||||
// calculate power
|
||||
var val = Math.ceil((100 + sLC * laprev)/500)/2;
|
||||
val = (val > 5) ? Math.ceil(val) : val;
|
||||
var s = "";
|
||||
@ -237,10 +274,10 @@
|
||||
if (n==1) {
|
||||
// npm run build has trouble minimizing spaces inside string
|
||||
var cn = `<div class="iST">
|
||||
${i>0?'<hr style="width:260px">':''}
|
||||
<hr style="width:260px">
|
||||
${i+1}:
|
||||
<select name="LT${i}" onchange="UI()">
|
||||
<option value="22">WS281x</option>
|
||||
<select name="LT${i}" onchange="UI(true)">
|
||||
<option value="22" selected>WS281x</option>
|
||||
<option value="30">SK6812 RGBW</option>
|
||||
<option value="31">TM1814</option>
|
||||
<option value="24">400kHz</option>
|
||||
@ -253,8 +290,10 @@ ${i+1}:
|
||||
<option value="43">PWM RGB</option>
|
||||
<option value="44">PWM RGBW</option>
|
||||
<option value="45">PWM RGBWC</option>
|
||||
<option value="2">Virtual RGB</option>
|
||||
<option value="3">Virtual RGBW</option>
|
||||
</select>
|
||||
Color Order:
|
||||
<div id="co${i}" style="display:inline">Color Order:
|
||||
<select name="CO${i}">
|
||||
<option value="0">GRB</option>
|
||||
<option value="1">RGB</option>
|
||||
@ -262,19 +301,20 @@ Color Order:
|
||||
<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" class="xs" name="L0${i}" min="0" max="33" required onchange="UI()"/>
|
||||
<span id="p1d${i}">Clock:</span> <input type="number" class="xs" name="L1${i}" min="0" max="33" onchange="UI()"/>
|
||||
<span id="p2d${i}"></span><input type="number" class="xs" name="L2${i}" min="0" max="33" onchange="UI()"/>
|
||||
<span id="p3d${i}"></span><input type="number" class="xs" name="L3${i}" min="0" max="33" onchange="UI()"/>
|
||||
<span id="p4d${i}"></span><input type="number" class="xs" name="L4${i}" min="0" max="33" onchange="UI()"/>
|
||||
</select></div>
|
||||
<br>
|
||||
<span id="p0d${i}">GPIO:</span><input type="number" name="L0${i}" min="0" max="33" required class="s" onchange="UI()"/>
|
||||
<span id="p1d${i}"></span><input type="number" name="L1${i}" min="0" max="33" class="s" onchange="UI()"/>
|
||||
<span id="p2d${i}"></span><input type="number" name="L2${i}" min="0" max="33" class="s" onchange="UI()"/>
|
||||
<span id="p3d${i}"></span><input type="number" name="L3${i}" min="0" max="33" class="s" onchange="UI()"/>
|
||||
<span id="p4d${i}"></span><input type="number" name="L4${i}" min="0" max="33" class="s" onchange="UI()"/>
|
||||
<br>
|
||||
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" id="ls${i}" class="l" min="0" max="8191" value="${lastEnd(i)}" disabled readonly required />
|
||||
<div id="dig${i}c" style="display:inline">Count: <input type="number" name="LC${i}" class="l" min="0" max="${maxPB}" value="1" required oninput="UI()" /></div>
|
||||
<br>
|
||||
<div id="dig${i}r" style="display:inline"><span id="rev${i}">Reversed</span>: <input type="checkbox" name="CV${i}"></div>
|
||||
<div id="dig${i}s" style="display:inline">Skip 1<sup>st</sup> LED: <input id="sl${i}" type="checkbox" name="SL${i}"></div>
|
||||
<br>
|
||||
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" id="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 (rotated 180°): <input type="checkbox" name="CV${i}">
|
||||
Skip 1<sup>st</sup> LED: <input id="sl${i}" type="checkbox" name="SL${i}"><br>
|
||||
</div>
|
||||
</div>`;
|
||||
f.insertAdjacentHTML("beforeend", cn);
|
||||
}
|
||||
@ -291,7 +331,7 @@ Reverse (rotated 180°): <input type="checkbox" name="CV${i}">
|
||||
var c = gId("btns").innerHTML;
|
||||
var bt = "BT" + i;
|
||||
var be = "BE" + i;
|
||||
c += `Button ${i} pin: <input type="number" class="xs" min="-1" max="40" name="${bt}" onchange="UI()" value="${p}"> `;
|
||||
c += `Button ${i} GPIO: <input type="number" min="-1" max="40" name="${bt}" onchange="UI()" class="s" value="${p}">`;
|
||||
c += `<select name="${be}">`
|
||||
c += `<option value="0" ${t==0?"selected":""}>Disabled</option>`;
|
||||
c += `<option value="2" ${t==2?"selected":""}>Pushbutton</option>`;
|
||||
@ -319,19 +359,19 @@ Reverse (rotated 180°): <input type="checkbox" name="CV${i}">
|
||||
function GetV()
|
||||
{
|
||||
//values injected by server while sending HTML
|
||||
//maxM=5000;maxPB=1536;d.um_p=[1,6,7,8,9,10,11];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.RL.value=12;d.Sf.RM.checked=0;addBtn(0,0,2);addBtn(1,3,4);addBtn(2,-1,0);d.Sf.IR.value=-1;
|
||||
//maxM=5000;maxPB=1536;d.um_p=[1,6,7,8,9,10,11];addLEDs(5);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.RL.value=12;d.Sf.RM.checked=0;addBtn(0,0,2);addBtn(1,3,4);addBtn(2,-1,0);d.Sf.IR.value=-1;
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
@import url("style.css");
|
||||
</style>
|
||||
<style>@import url("style.css");</style>
|
||||
</head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
</div>
|
||||
<h2>LED & Hardware setup</h2>
|
||||
Total LED count: <input name="LC" id="LC" type="number" min="1" max="8192" oninput="UI()" required><br>
|
||||
Total LED count: <input name="LC" id="LC" type="number" min="1" max="8192" oninput="UI()" disabled required readonly><br>
|
||||
<i>Recommended power supply for brightest white:</i><br>
|
||||
<b><span id="psu">?</span></b><br>
|
||||
<span id="psu2"><br></span>
|
||||
@ -362,19 +402,21 @@ Reverse (rotated 180°): <input type="checkbox" name="CV${i}">
|
||||
</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>
|
||||
<hr style="width:260px">
|
||||
<button type="button" id="+" onclick="addLEDs(1)">+</button>
|
||||
<button type="button" id="-" onclick="addLEDs(-1)">-</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>
|
||||
Make a segment for each output: <input type="checkbox" name="MS"> <br>
|
||||
<hr style="width:260px">
|
||||
Create a segment for each output: <input type="checkbox" name="MS"> <br>
|
||||
<hr style="width:260px">
|
||||
<div id="btns"></div>
|
||||
Touch threshold: <input type="number" class="s" min="0" max="100" name="TT" required><br>
|
||||
IR pin: <input type="number" class="xs" min="-1" max="40" name="IR" onchange="UI()"> <select name="IT" onchange="UI()">
|
||||
Touch threshold: <input type="number" min="0" max="100" name="TT" required><br>
|
||||
IR GPIO: <input type="number" min="-1" max="40" name="IR" onchange="UI()" class="s"><select name="IT" onchange="UI()">
|
||||
<option value=0>Remote disabled</option>
|
||||
<option value=1>24-key RGB</option>
|
||||
<option value=2>24-key with CT</option>
|
||||
@ -388,23 +430,23 @@ Reverse (rotated 180°): <input type="checkbox" name="CV${i}">
|
||||
<div id="json" style="display:none;">JSON file: <input type="file" name="data" accept=".json"> <input type="button" value="Upload" onclick="uploadFile('/ir.json');"><br></div>
|
||||
<div id="toast"></div>
|
||||
<a href="https://github.com/Aircoookie/WLED/wiki/Infrared-Control" target="_blank">IR info</a><br>
|
||||
Relay pin: <input type="number" class="xs" min="-1" max="33" name="RL" onchange="UI()"> Invert <input type="checkbox" name="RM"><span style="cursor: pointer;" onclick="off('RL')"> ×</span><br>
|
||||
Relay GPIO: <input type="number" min="-1" max="33" name="RL" onchange="UI()" class="s"> invert <input type="checkbox" name="RM"><span style="cursor: pointer;" onclick="off('RL')"> ×</span><br>
|
||||
<hr style="width:260px">
|
||||
<h3>Defaults</h3>
|
||||
Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br>
|
||||
Default brightness: <input name="CA" type="number" class="s" min="0" max="255" required> (0-255)<br><br>
|
||||
Apply preset <input name="BP" type="number" class="s" min="0" max="250" required> at boot (0 uses defaults)
|
||||
Default brightness: <input name="CA" type="number" class="m" min="0" max="255" required> (0-255)<br><br>
|
||||
Apply preset <input name="BP" type="number" class="m" min="0" max="250" required> at boot (0 uses defaults)
|
||||
<br><br>
|
||||
Use Gamma correction for color: <input type="checkbox" name="GC"> (strongly recommended)<br>
|
||||
Use Gamma correction for brightness: <input type="checkbox" name="GB"> (not recommended)<br><br>
|
||||
Brightness factor: <input name="BF" type="number" class="s" min="1" max="255" required> %
|
||||
Brightness factor: <input name="BF" type="number" class="m" min="1" max="255" required> %
|
||||
<h3>Transitions</h3>
|
||||
Crossfade: <input type="checkbox" name="TF"><br>
|
||||
Transition Time: <input name="TD" type="number" class="l" min="0" max="65500"> ms<br>
|
||||
Transition Time: <input name="TD" type="number" class="xl" min="0" max="65500"> ms<br>
|
||||
Enable Palette transitions: <input type="checkbox" name="PF">
|
||||
<h3>Timed light</h3>
|
||||
Default Duration: <input name="TL" type="number" class="s" min="1" max="255" required> min<br>
|
||||
Default Target brightness: <input name="TB" type="number" class="s" min="0" max="255" required><br>
|
||||
Default Duration: <input name="TL" type="number" class="m" min="1" max="255" required> min<br>
|
||||
Default Target brightness: <input name="TB" type="number" class="m" min="0" max="255" required><br>
|
||||
Mode:
|
||||
<select name="TW">
|
||||
<option value="0">Wait and set</option>
|
||||
|
@ -57,8 +57,10 @@
|
||||
</head>
|
||||
<body onload="GetV()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button><hr>
|
||||
</div>
|
||||
<h2>Security & Update setup</h2>
|
||||
Lock wireless (OTA) software update: <input type="checkbox" name="NO"><br>
|
||||
Passphrase: <input type="password" name="OP" maxlength="32"><br>
|
||||
@ -70,6 +72,7 @@
|
||||
Factory reset: <input type="checkbox" name="RS"><br>
|
||||
All settings and presets will be erased.<br><br>
|
||||
HTTP traffic is unencrypted. An attacker in the same network can intercept form data!
|
||||
<hr>
|
||||
<h3>Software Update</h3>
|
||||
<button type="button" onclick="U()">Manual OTA Update</button><br>
|
||||
Enable ArduinoOTA: <input type="checkbox" name="AO"><br>
|
||||
|
@ -35,11 +35,14 @@ function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 556
|
||||
function S(){GetV();SetVal();}
|
||||
function GetV(){var d=document;}
|
||||
</script>
|
||||
<style>@import url("style.css");</style></head>
|
||||
<style>@import url("/style.css");</style>
|
||||
</head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post" onsubmit="GC()">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
</div>
|
||||
<h2>Sync setup</h2>
|
||||
<h3>WLED Broadcast</h3>
|
||||
UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required><br>
|
||||
|
@ -46,13 +46,15 @@
|
||||
var ih="<tr><th>Active</th><th>Hour</th><th>Minute</th><th>Preset</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>";
|
||||
for (i=0;i<8;i++)
|
||||
{
|
||||
ih+="<tr><td><input name=\"W"+i+"\" id=\"W"+i+"\" type=\"number\" style=\"display:none\"><input id=\"W"+i+"0\" type=\"checkbox\"></td><td><input name=\"H"+i+"\" type=\"number\" min=\"0\" max=\"24\"></td><td><input name=\"N"+i+"\" type=\"number\" min=\"0\" max=\"59\"></td><td><input name=\"T"+i+"\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
||||
ih+="<tr><td><input name=\"W"+i+"\" id=\"W"+i+"\" type=\"number\" style=\"display:none\"><input id=\"W"+i+"0\" type=\"checkbox\"></td><td><input name=\"H"+i+"\" class=\"sml\" type=\"number\" min=\"0\" max=\"24\"></td><td><input name=\"N"+i+"\" class=\"sml\" type=\"number\" min=\"0\" max=\"59\"></td><td><input name=\"T"+i+"\" class=\"med\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
||||
for (j=1;j<8;j++) ih+="<td><input id=\"W"+i+j+"\" type=\"checkbox\"></td>";
|
||||
ih+="</tr>";
|
||||
}
|
||||
ih+="<tr><td><input name=\"W8\" id=\"W8\" type=\"number\" style=\"display:none\"><input id=\"W80\" type=\"checkbox\"></td><td>Sunrise<input name=\"H8\" value=\"255\" type=\"hidden\"></td><td><input name=\"N8\" type=\"number\" min=\"-59\" max=\"59\"></td><td><input name=\"T8\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
||||
ih+="<tr><td><input name=\"W8\" id=\"W8\" type=\"number\" style=\"display:none\"><input id=\"W80\" type=\"checkbox\"></td><td>Sunrise<input name=\"H8\" class=\"sml\" value=\"255\" type=\"hidden\"></td><td><input name=\"N8\" class=\"sml\" type=\"number\" min=\"-59\" max=\"59\"></td><td><input name=\"T8\" class=\"med\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
||||
for (j=1;j<8;j++) ih+="<td><input id=\"W8"+j+"\" type=\"checkbox\"></td>";
|
||||
ih+="<tr><td><input name=\"W9\" id=\"W9\" type=\"number\" style=\"display:none\"><input id=\"W90\" type=\"checkbox\"></td><td>Sunset<input name=\"H9\" value=\"255\" type=\"hidden\"></td><td><input name=\"N9\" type=\"number\" min=\"-59\" max=\"59\"><td><input name=\"T9\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
||||
ih+="</tr><tr><td><input name=\"W9\" id=\"W9\" type=\"number\" style=\"display:none\"><input id=\"W90\" type=\"checkbox\"></td><td>Sunset<input name=\"H9\" class=\"sml\" value=\"255\" type=\"hidden\"></td><td><input name=\"N9\" class=\"sml\" type=\"number\" min=\"-59\" max=\"59\"></td><td><input name=\"T9\" class=\"med\" type=\"number\" min=\"0\" max=\"250\"></td>";
|
||||
for (j=1;j<8;j++) ih+="<td><input id=\"W9"+j+"\" type=\"checkbox\"></td>";
|
||||
ih+="</tr>";
|
||||
gId("TMT").innerHTML=ih;
|
||||
}
|
||||
function FC()
|
||||
@ -84,25 +86,25 @@
|
||||
td = tr.insertCell(0);
|
||||
td.innerHTML = `Button ${i}:`;
|
||||
td = tr.insertCell(1);
|
||||
td.innerHTML = `<input name="MP${i}" type="number" min="0" max="250" value="${p}" required>`;
|
||||
td.innerHTML = `<input name="MP${i}" type="number" class="m" min="0" max="250" value="${p}" required>`;
|
||||
td = tr.insertCell(2);
|
||||
td.innerHTML = `<input name="ML${i}" type="number" min="0" max="250" value="${l}" required>`;
|
||||
td.innerHTML = `<input name="ML${i}" type="number" class="m" min="0" max="250" value="${l}" required>`;
|
||||
td = tr.insertCell(3);
|
||||
td.innerHTML = `<input name="MD${i}" type="number" min="0" max="250" value="${d}" required>`;
|
||||
td.innerHTML = `<input name="MD${i}" type="number" class="m" min="0" max="250" value="${d}" required>`;
|
||||
}
|
||||
function GetV()
|
||||
{
|
||||
//values injected by server while sending HTML
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
@import url("style.css");
|
||||
</style>
|
||||
<style>@import url("/style.css");</style>
|
||||
</head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post" onsubmit="Wd()">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
</div>
|
||||
<h2>Time setup</h2>
|
||||
Get time from NTP server: <input type="checkbox" name="NT"><br>
|
||||
<input name="NS" maxlength="32"><br>
|
||||
@ -131,8 +133,8 @@
|
||||
</select><br>
|
||||
UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<br>
|
||||
Current local time is <span class="times">unknown</span>.<br>
|
||||
Latitude (N): <input name="LT" type="number" min="-66.6" max="66.6" step="0.01">
|
||||
Longitude (E): <input name="LN" type="number" min="-180" max="180" step="0.01">
|
||||
Latitude (N): <input name="LT" type="number" class="xl" min="-66.6" max="66.6" step="0.01">
|
||||
Longitude (E): <input name="LN" type="number" class="xl" min="-180" max="180" step="0.01">
|
||||
<div id="sun" class="times"></div>
|
||||
<h3>Clock</h3>
|
||||
Clock Overlay:
|
||||
@ -155,8 +157,8 @@
|
||||
</div>
|
||||
Countdown Mode: <input type="checkbox" name="CE"><br>
|
||||
Countdown Goal:<br>
|
||||
Year: 20 <input name="CY" type="number" min="0" max="99" required> Month: <input name="CI" type="number" min="1" max="12" required> Day: <input name="CD" type="number" min="1" max="31" required><br>
|
||||
Hour: <input name="CH" type="number" min="0" max="23" required> Minute: <input name="CM" type="number" min="0" max="59" required> Second: <input name="CS" type="number" min="0" max="59" required><br>
|
||||
Year: 20 <input name="CY" class="small" type="number" min="0" max="99" required> Month: <input name="CI" class="small" type="number" min="1" max="12" required> Day: <input name="CD" class="small" type="number" min="1" max="31" required><br>
|
||||
Hour: <input name="CH" class="small" type="number" min="0" max="23" required> Minute: <input name="CM" class="small" type="number" min="0" max="59" required> Second: <input name="CS" class="small" type="number" min="0" max="59" required><br>
|
||||
<h3>Macro presets</h3>
|
||||
<b>Macros have moved!</b><br>
|
||||
<i>Presets now also can be used as macros to save both JSON and HTTP API commands.<br>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<title>UI Settings</title>
|
||||
<script>
|
||||
var d = document;
|
||||
var initial_ds, initial_st;
|
||||
var initial_ds, initial_st, initial_su;
|
||||
var sett = null;
|
||||
var l = {
|
||||
"comp":{
|
||||
@ -148,9 +148,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
function cLS()
|
||||
{
|
||||
localStorage.removeItem('wledP');
|
||||
localStorage.removeItem('wledPmt');
|
||||
localStorage.removeItem('wledPalx');
|
||||
showToast("Cleared.");
|
||||
}
|
||||
|
||||
function Save() {
|
||||
SetLS();
|
||||
if (d.Sf.DS.value != initial_ds || d.Sf.ST.checked != initial_st) d.Sf.submit();
|
||||
if (d.Sf.DS.value != initial_ds || d.Sf.ST.checked != initial_st || d.Sf.SU.checked != initial_su) d.Sf.submit();
|
||||
}
|
||||
|
||||
function S()
|
||||
@ -158,6 +166,7 @@
|
||||
GetV();
|
||||
initial_ds = d.Sf.DS.value;
|
||||
initial_st = d.Sf.ST.checked;
|
||||
initial_su = d.Sf.SU.checked;
|
||||
GetLS();
|
||||
}
|
||||
function H()
|
||||
@ -208,7 +217,7 @@
|
||||
</head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div style="position:sticky;top:0;background-color:#222;">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="button" onclick="Save()">Save</button><br>
|
||||
<span id="lssuc" style="color:green; display:none">✔ Local UI settings saved!</span>
|
||||
@ -217,6 +226,7 @@
|
||||
<h2>Web Setup</h2>
|
||||
Server description: <input name="DS" maxlength="32"><br>
|
||||
Sync button toggles both send and receive: <input type="checkbox" name="ST"><br>
|
||||
Enable simplified UI: <input type="checkbox" name="SU"><br>
|
||||
<i>The following UI customization settings are unique both to the WLED device and this browser.<br>
|
||||
You will need to set them again if using a different browser, device or WLED IP address.<br>
|
||||
Refresh the main UI to apply changes.</i><br>
|
||||
@ -241,6 +251,7 @@
|
||||
<span class="l"></span>: <input type="checkbox" id="comp_hdays" class="agi cb"><br>
|
||||
<div id="holidays">Holidays: <input type="file" name="data2" accept=".json"> <input type="button" value="Upload" onclick="uploadFile(d.Sf.data2,'/holidays.json');"><br></div>
|
||||
<div id="toast"></div>
|
||||
<hr><button type="button" onclick="cLS()">Clear local storage</button>
|
||||
<hr><button type="button" onclick="B()">Back</button><button type="button" onclick="Save()">Save</button>
|
||||
</form>
|
||||
</body>
|
||||
|
@ -81,10 +81,10 @@
|
||||
case "number":
|
||||
c = `value="${o}"`;
|
||||
if (f.substr(-3)==="pin") {
|
||||
c += ' max="39" min="-1" style="width:40px;"';
|
||||
c += ' max="39" min="-1" class="s"';
|
||||
t = "int";
|
||||
} else {
|
||||
c += ' step="any" style="width:100px;"';
|
||||
c += ' step="any" class="xxl"';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -133,9 +133,7 @@
|
||||
}
|
||||
function GetV() {}
|
||||
</script>
|
||||
<style>
|
||||
@import url("style.css");
|
||||
</style>
|
||||
<style>@import url("/style.css");</style>
|
||||
</head>
|
||||
|
||||
<body onload="S()">
|
||||
|
@ -18,14 +18,14 @@
|
||||
//values injected by server while sending HTML
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
@import url("style.css");
|
||||
</style>
|
||||
<style>@import url("/style.css");</style>
|
||||
</head>
|
||||
<body onload="GetV()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button><hr>
|
||||
</div>
|
||||
<h2>WiFi setup</h2>
|
||||
<h3>Connect to existing network</h3>
|
||||
Network name (SSID, empty to not connect): <br><input name="CS" maxlength="32"><br>
|
||||
@ -74,7 +74,8 @@
|
||||
<option value="5">TwilightLord-ESP32</option>
|
||||
<option value="3">WESP32</option>
|
||||
<option value="1">WT32-ETH01</option>
|
||||
</select><br><br></div>
|
||||
</select><br><br>
|
||||
</div>
|
||||
<hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button>
|
||||
</form>
|
||||
|
858
wled00/data/simple.css
Normal file
858
wled00/data/simple.css
Normal file
File diff suppressed because one or more lines are too long
172
wled00/data/simple.htm
Normal file
172
wled00/data/simple.htm
Normal file
@ -0,0 +1,172 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<meta name="theme-color" content="#222222">
|
||||
<meta content="yes" name="apple-mobile-web-app-capable">
|
||||
<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAGACGAAAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAAQAAAAEAgGAAAAH/P/YQAAAE1JREFUOI1j/P//PwOxgNGeAUMxE9G6cQCKDWAhpADZ2f8PMjBS3QW08QK20KaZC2gfC9hCnqouoNgARgY7zMxAyNlUdQHlXiAlO2MDAD63EVqNHAe0AAAAAElFTkSuQmCC"/>
|
||||
<title>WLED</title>
|
||||
<script>function feedback(){}</script>
|
||||
<link rel="stylesheet" href="simple.css">
|
||||
</head>
|
||||
<body onload="onLoad()">
|
||||
|
||||
<div id="cv" class="overlay">Loading WLED UI...</div>
|
||||
<noscript><div class="overlay" style="opacity:1;">Sorry, WLED UI needs JavaScript!</div></noscript>
|
||||
<div id="bg"></div>
|
||||
|
||||
<div class="wrapper" id="top">
|
||||
<div class="tab top">
|
||||
<div class="btnwrap">
|
||||
<button id="buttonPower" onclick="togglePower()"><i class="icons"></i><p class="tab-label">Power</p></button>
|
||||
<button id="buttonI" onclick="toggleInfo()"><i class="icons"></i><p class="tab-label">Info</p></button>
|
||||
<button id="buttonNodes" onclick="toggleNodes()"><i class="icons"></i><p class="tab-label">Nodes</p></button></div>
|
||||
<button onclick="window.location.href='/settings';"><i class="icons"></i><p class="tab-label">Config</p></button>
|
||||
<button id="buttonCP" onclick="tglCP()"><i class="icons"></i><p class="tab-label">Expand</p></button>
|
||||
<button id="buttonBri" onclick="tglBri()"><i class="icons"></i><p class="tab-label">Brightness</p></button>
|
||||
</div>
|
||||
<div id="briwrap">
|
||||
<p class="label hd">Global brightness</p>
|
||||
<div class="il">
|
||||
<i class="icons slider-icon" onclick="tglTheme()"></i>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderBri" onchange="setBri()" oninput="updateTrail(this)" max="255" min="1" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class ="container">
|
||||
<div class="tabcontent">
|
||||
<div id="picker" class="center"></div>
|
||||
|
||||
<div id="qcs-w" class="center">
|
||||
<div class="qcs" onclick="pC('#ff0000');" title="Red" style="background-color:#ff0000;"></div>
|
||||
<div class="qcs" onclick="pC('#ffa000');" title="Orange" style="background-color:#ffa000;"></div>
|
||||
<div class="qcs" onclick="pC('#ffc800');" title="Yellow" style="background-color:#ffc800;"></div>
|
||||
<div class="qcs" onclick="pC('#ffe0a0');" title="Warm White" style="background-color:#ffe0a0;"></div>
|
||||
<div class="qcs" onclick="pC('#ffffff');" title="White" style="background-color:#ffffff;"></div>
|
||||
<div class="qcs qcsb" onclick="pC('#000000');" title="Black" style="background-color:#000000;"></div><br>
|
||||
<div class="qcs" onclick="pC('#ff00ff');" title="Pink" style="background-color:#ff00ff;"></div>
|
||||
<div class="qcs" onclick="pC('#0000ff');" title="Blue" style="background-color:#0000ff;"></div>
|
||||
<div class="qcs" onclick="pC('#00ffc8');" title="Cyan" style="background-color:#00ffc8;"></div>
|
||||
<div class="qcs" onclick="pC('#08ff00');" title="Green" style="background-color:#08ff00;"></div>
|
||||
<div class="qcs" onclick="pC('rnd');" title="Random" style="background:linear-gradient(to right, red, orange, yellow, green, blue, purple);transform: translateY(-11px);">R</div>
|
||||
</div>
|
||||
<div id="csl" class="center" style="display: none;">
|
||||
<button class="xxs btn" onclick="selectSlot(0);">1</button>
|
||||
<button class="xxs btn" onclick="selectSlot(1);">2</button>
|
||||
<button class="xxs btn" onclick="selectSlot(2);">3</button>
|
||||
</div>
|
||||
|
||||
<div id="wwrap" class="center">
|
||||
<p class="label h">White channel</p>
|
||||
<i class="icons slider-icon" id="wht" title="White channel"></i>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderW" onchange="setColor(0)" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div>
|
||||
|
||||
<div id="Segments" class="center">
|
||||
<div id="segcont"></div>
|
||||
</div>
|
||||
|
||||
<div id="QuickLoad" class="center">
|
||||
<p class="label h">Quick Load</p>
|
||||
<div id="pql"></div>
|
||||
</div>
|
||||
|
||||
<div id="Presets" class="center" style="display:none;">
|
||||
<p class="label h">Presets</p>
|
||||
<div class="fnd">
|
||||
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'pcont')" onfocus="search(this)" />
|
||||
<span onclick="clean(this)" class="icons"></span>
|
||||
<div class="icons"><svg xmlns='http://www.w3.org/2000/svg' class='fndIcn'><circle cx='8' cy='8' r='6' /><line x1='12' y1='12' x2='24' y2='12' transform='rotate(45,12,12)' /></svg></div>
|
||||
</div>
|
||||
<div id="pcont" class="list"></div>
|
||||
</div>
|
||||
|
||||
<div id="Effects" class="center">
|
||||
<p class="label h">Effect</p>
|
||||
<!--p class="label h">Effect speed</p-->
|
||||
<div title="Effect speed">
|
||||
<i class="icons slider-icon"></i>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderSpeed" onchange="setSpeed()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div>
|
||||
<!--p class="label h">Effect intensity</p-->
|
||||
<div title="Effect intensity">
|
||||
<i class="icons slider-icon" onclick="tglLabels()"></i>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderIntensity" onchange="setIntensity()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div>
|
||||
<div style="padding-bottom:20px;">
|
||||
<div onclick="tglFxDropdown()" class="c btn" id="fxBtn"><i class="icons"></i> Solid</div>
|
||||
<div onclick="tglPalDropdown()" class="c btn" id="palBtn"><i class="icons"></i>Default</div>
|
||||
<div id="fxDropdown" class="dd-content">
|
||||
<div class="fnd">
|
||||
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'fxlist')" onfocus="search(this)" />
|
||||
<span onclick="clean(this)" class="icons"></span>
|
||||
<div class="icons"><svg xmlns='http://www.w3.org/2000/svg' class='fndIcn'><circle cx='8' cy='8' r='6' /><line x1='12' y1='12' x2='24' y2='12' transform='rotate(45,12,12)' /></svg></div>
|
||||
</div>
|
||||
<div id="fxlist" class="list">
|
||||
<div class="lstI" data-id="0" onClick="setX(0)"><a href="#0" onClick="setX(0)">Solid</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="palDropdown" class="dd-content">
|
||||
<div class="fnd">
|
||||
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'pallist')" onfocus="search(this)" />
|
||||
<span onclick="clean(this)" class="icons"></span>
|
||||
<div class="icons"><svg xmlns='http://www.w3.org/2000/svg' class='fndIcn'><circle cx='8' cy='8' r='6' /><line x1='12' y1='12' x2='24' y2='12' transform='rotate(45,12,12)' /></svg></div>
|
||||
</div>
|
||||
<div id="pallist" class="list">
|
||||
<div class="lstI" data-id="0" onClick="setPalette(0)"><a href="#0" onClick="setPalette(0)">Default</a><div class="lstIprev"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="connind"></div>
|
||||
<div id="toast"></div>
|
||||
<div id="namelabel" onclick="toggleNodes()"></div>
|
||||
|
||||
<div id="info" class="modal">
|
||||
<div id="imgw">
|
||||
<img class="wi" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB0AAAAFCAYAAAC5Fuf5AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABbSURBVChTlY9bDoAwDMNW7n9nwCipytQN4Z8tbrTHmDmF4oPzyldwRqp1SSdnV/NuZuzqerAByxXznBw3igkeFEfXyUuhK/yFM0CxJfyqXZEOc6/Sr9/bf7uIC5Nwd7orMvAPAAAAAElFTkSuQmCC" />
|
||||
</div><br>
|
||||
<div id="kv">Loading...</div><br>
|
||||
<button class="btn infobtn" onclick="loadInfo()">Refresh</button>
|
||||
<button class="btn infobtn" onclick="toggleInfo()">Close Info</button><br>
|
||||
<button class="btn infobtn" onclick="toggleNodes()">Instance List</button>
|
||||
<button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button><br>
|
||||
<span class="h">Made with <span id="heart">❤︎</span> by Aircoookie and the WLED community</span>
|
||||
</div>
|
||||
|
||||
<div id="nodes" class="modal">
|
||||
<div id="ndlt">WLED instances</div>
|
||||
<div id="kn">Loading...</div><br>
|
||||
<button class="btn infobtn" onclick="loadNodes()">Refresh</button>
|
||||
<button class="btn infobtn" onclick="toggleNodes()">Close list</button><br>
|
||||
</div>
|
||||
|
||||
<i id="roverstar" class="icons huge" onclick="setLor(0)"></i><br>
|
||||
<script src="iro.js"></script>
|
||||
<script src="rangetouch.js"></script>
|
||||
<script src="simple.js"></script>
|
||||
</body>
|
||||
</html>
|
1398
wled00/data/simple.js
Normal file
1398
wled00/data/simple.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -14,13 +14,21 @@ button, .btn {
|
||||
color: #fff;
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.3ch solid #333;
|
||||
border-radius: 24px;
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
margin: 12px 8px 8px;
|
||||
padding: 1px 6px;
|
||||
padding: 8px 12px;
|
||||
min-width: 48px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.toprow {
|
||||
top: 0;
|
||||
position: sticky;
|
||||
background-color:#222;
|
||||
z-index:1;
|
||||
}
|
||||
.lnk {
|
||||
border: 0;
|
||||
}
|
||||
@ -35,8 +43,12 @@ input {
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.5ch solid #333;
|
||||
}
|
||||
input[type="text"] {
|
||||
font-size: medium;
|
||||
}
|
||||
input[type="number"] {
|
||||
width: 4em;
|
||||
font-size: medium;
|
||||
margin: 2px;
|
||||
}
|
||||
input[type="number"].xxl {
|
||||
@ -57,8 +69,12 @@ input[type="number"].s {
|
||||
input[type="number"].xs {
|
||||
width: 42px;
|
||||
}
|
||||
select {
|
||||
margin: 2px;
|
||||
font-size: medium;
|
||||
}
|
||||
input[type="checkbox"] {
|
||||
transform: scale(1.5);
|
||||
transform: scale(2);
|
||||
margin-right: 10px;
|
||||
}
|
||||
select {
|
||||
|
@ -15,9 +15,11 @@ void handleAlexa();
|
||||
void onAlexaChange(EspalexaDevice* dev);
|
||||
|
||||
//blynk.cpp
|
||||
#ifndef WLED_DISABLE_BLYNK
|
||||
void initBlynk(const char* auth, const char* host, uint16_t port);
|
||||
void handleBlynk();
|
||||
void updateBlynk();
|
||||
#endif
|
||||
|
||||
//button.cpp
|
||||
void shortPressAction(uint8_t b=0);
|
||||
@ -94,7 +96,7 @@ void sendHuePoll();
|
||||
void onHueData(void* arg, AsyncClient* client, void *data, size_t len);
|
||||
|
||||
//ir.cpp
|
||||
bool decodeIRCustom(uint32_t code);
|
||||
//bool decodeIRCustom(uint32_t code);
|
||||
void applyRepeatActions();
|
||||
void relativeChange(byte* property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF);
|
||||
void changeEffectSpeed(int8_t amount);
|
||||
@ -195,6 +197,7 @@ bool updateVal(const String* req, const char* key, byte* val, byte minv=0, byte
|
||||
|
||||
//udp.cpp
|
||||
void notify(byte callMode, bool followUp=false);
|
||||
void realtimeBoroadcast(IPAddress client, uint16_t length, byte *buffer, bool isRGBW);
|
||||
void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
|
||||
void handleNotifications();
|
||||
void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w);
|
||||
@ -224,14 +227,11 @@ class UsermodManager {
|
||||
|
||||
public:
|
||||
void loop();
|
||||
|
||||
void setup();
|
||||
void connected();
|
||||
|
||||
void addToJsonState(JsonObject& obj);
|
||||
void addToJsonInfo(JsonObject& obj);
|
||||
void readFromJsonState(JsonObject& obj);
|
||||
|
||||
void addToConfig(JsonObject& obj);
|
||||
bool readFromConfig(JsonObject& obj);
|
||||
void onMqttConnect(bool sessionPresent);
|
||||
|
@ -380,10 +380,10 @@ String getContentType(AsyncWebServerRequest* request, String filename){
|
||||
else if(filename.endsWith(".htm")) return "text/html";
|
||||
else if(filename.endsWith(".html")) return "text/html";
|
||||
else if(filename.endsWith(".css")) return "text/css";
|
||||
// else if(filename.endsWith(".js")) return "application/javascript";
|
||||
else if(filename.endsWith(".js")) return "application/javascript";
|
||||
else if(filename.endsWith(".json")) return "application/json";
|
||||
else if(filename.endsWith(".png")) return "image/png";
|
||||
// else if(filename.endsWith(".gif")) return "image/gif";
|
||||
else if(filename.endsWith(".gif")) return "image/gif";
|
||||
else if(filename.endsWith(".jpg")) return "image/jpeg";
|
||||
else if(filename.endsWith(".ico")) return "image/x-icon";
|
||||
// else if(filename.endsWith(".xml")) return "text/xml";
|
||||
|
@ -42,7 +42,7 @@ function B(){window.history.back()}function U(){document.getElementById("uf").st
|
||||
.bt{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}input[type=file]{font-size:16px}body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%}#msg{display:none}
|
||||
</style></head><body><h2>WLED Software Update</h2><form method="POST"
|
||||
action="/update" id="uf" enctype="multipart/form-data" onsubmit="U()">
|
||||
Installed version: 0.13.0-b2<br>Download the latest binary: <a
|
||||
Installed version: 0.13.0-bl3<br>Download the latest binary: <a
|
||||
href="https://github.com/Aircoookie/WLED/releases" target="_blank"><img
|
||||
src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square">
|
||||
</a><br><input type="file" class="bt" name="update" required><br><input
|
||||
|
File diff suppressed because one or more lines are too long
1819
wled00/html_simple.h
Normal file
1819
wled00/html_simple.h
Normal file
File diff suppressed because it is too large
Load Diff
4371
wled00/html_ui.h
4371
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -101,7 +101,7 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
|
||||
hueError = HUE_ERROR_JSON_PARSING; return;
|
||||
}
|
||||
|
||||
int hueErrorCode = root[0][F("error")][F("type")];
|
||||
int hueErrorCode = root[0][F("error")]["type"];
|
||||
if (hueErrorCode)//hue bridge returned error
|
||||
{
|
||||
hueError = hueErrorCode;
|
||||
|
@ -79,6 +79,9 @@ void presetFallback(uint8_t presetID, uint8_t effectID, uint8_t paletteID)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is no longer needed due to JSON IR mod
|
||||
*
|
||||
//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)
|
||||
@ -94,6 +97,7 @@ bool decodeIRCustom(uint32_t code)
|
||||
if (code != IRCUSTOM_MACRO1) colorUpdated(CALL_MODE_BUTTON); //don't update color again if we apply macro, it already does it
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
void relativeChange(byte* property, int8_t amount, byte lowerBoundary, byte higherBoundary)
|
||||
{
|
||||
@ -162,9 +166,10 @@ void decodeIR(uint32_t code)
|
||||
return;
|
||||
}
|
||||
lastValidCode = 0; irTimesRepeated = 0;
|
||||
if (decodeIRCustom(code)) return;
|
||||
//if (decodeIRCustom(code)) return;
|
||||
if (irEnabled == 8) { // any remote configurable with ir.json file
|
||||
decodeIRJson(code);
|
||||
colorUpdated(CALL_MODE_BUTTON);
|
||||
return;
|
||||
}
|
||||
if (code > 0xFFFFFF) return; //invalid code
|
||||
@ -566,14 +571,17 @@ Sample:
|
||||
void decodeIRJson(uint32_t code)
|
||||
{
|
||||
char objKey[10];
|
||||
const char* cmd;
|
||||
String cmdStr;
|
||||
DynamicJsonDocument irDoc(JSON_BUFFER_SIZE);
|
||||
JsonObject fdo;
|
||||
JsonObject jsonCmdObj;
|
||||
|
||||
sprintf(objKey, "\"0x%X\":", code);
|
||||
sprintf_P(objKey, PSTR("\"0x%lX\":"), (unsigned long)code);
|
||||
|
||||
// attempt to read command from ir.json
|
||||
// this may fail for two reasons: ir.json does not exist or IR code not found
|
||||
// if the IR code is not found readObjectFromFile() will clean() irDoc JSON document
|
||||
// so we can differentiate between the two
|
||||
readObjectFromFile("/ir.json", objKey, &irDoc);
|
||||
fdo = irDoc.as<JsonObject>();
|
||||
lastValidCode = 0;
|
||||
@ -583,8 +591,7 @@ void decodeIRJson(uint32_t code)
|
||||
return;
|
||||
}
|
||||
|
||||
cmd = fdo["cmd"]; //string
|
||||
cmdStr = String(cmd);
|
||||
cmdStr = fdo["cmd"].as<String>();;
|
||||
jsonCmdObj = fdo["cmd"]; //object
|
||||
|
||||
if (!cmdStr.isEmpty())
|
||||
@ -653,9 +660,7 @@ void handleIR()
|
||||
{
|
||||
if (results.value != 0) // only print results if anything is received ( != 0 )
|
||||
{
|
||||
Serial.print("IR recv\r\n0x");
|
||||
Serial.println((uint32_t)results.value, HEX);
|
||||
Serial.println();
|
||||
DEBUG_PRINTF("IR recv: 0x%lX\n", (unsigned long)results.value);
|
||||
}
|
||||
decodeIR(results.value);
|
||||
irrecv->resume();
|
||||
|
156
wled00/json.cpp
156
wled00/json.cpp
@ -17,11 +17,36 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
|
||||
uint16_t start = elem[F("start")] | seg.start;
|
||||
int stop = elem["stop"] | -1;
|
||||
|
||||
if (stop < 0) {
|
||||
uint16_t len = elem[F("len")];
|
||||
stop = (len > 0) ? start + len : seg.stop;
|
||||
}
|
||||
|
||||
if (elem["n"]) {
|
||||
// name field exists
|
||||
if (seg.name) { //clear old name
|
||||
delete[] seg.name;
|
||||
seg.name = nullptr;
|
||||
}
|
||||
|
||||
const char * name = elem["n"].as<const char*>();
|
||||
size_t len = 0;
|
||||
if (name != nullptr) len = strlen(name);
|
||||
if (len > 0 && len < 33) {
|
||||
seg.name = new char[len+1];
|
||||
if (seg.name) strlcpy(seg.name, name, 33);
|
||||
} else {
|
||||
// but is empty (already deleted above)
|
||||
elem.remove("n");
|
||||
}
|
||||
} else if (start != seg.start || stop != seg.stop) {
|
||||
// clearing or setting segment without name field
|
||||
if (seg.name) {
|
||||
delete[] seg.name;
|
||||
seg.name = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t grp = elem["grp"] | seg.grouping;
|
||||
uint16_t spc = elem[F("spc")] | seg.spacing;
|
||||
strip.setSegment(id, start, stop, grp, spc);
|
||||
@ -54,6 +79,15 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
{
|
||||
int rgbw[] = {0,0,0,0};
|
||||
bool colValid = false;
|
||||
if (colarr[i].is<unsigned long>()) {
|
||||
// unsigned long RGBW (@blazoncek v2 experimental API implementation)
|
||||
uint32_t colX = colarr[i];
|
||||
rgbw[0] = (colX >> 16) & 0xFF;
|
||||
rgbw[1] = (colX >> 8) & 0xFF;
|
||||
rgbw[2] = (colX ) & 0xFF;
|
||||
rgbw[3] = (colX >> 24) & 0xFF;
|
||||
colValid = true;
|
||||
} else {
|
||||
JsonArray colX = colarr[i];
|
||||
if (colX.isNull()) {
|
||||
byte brgbw[] = {0,0,0,0};
|
||||
@ -89,6 +123,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// lx parser
|
||||
#ifdef WLED_ENABLE_LOXONE
|
||||
@ -136,16 +171,16 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
strip.fill(0);
|
||||
}
|
||||
|
||||
uint16_t start = 0, stop = 0;
|
||||
//uint16_t start = 0, stop = 0;
|
||||
byte set = 0; //0 nothing set, 1 start set, 2 range set
|
||||
|
||||
for (uint16_t i = 0; i < iarr.size(); i++) {
|
||||
if(iarr[i].is<JsonInteger>()) {
|
||||
if (!set) {
|
||||
start = iarr[i];
|
||||
//start = iarr[i];
|
||||
set = 1;
|
||||
} else {
|
||||
stop = iarr[i];
|
||||
//stop = iarr[i];
|
||||
set = 2;
|
||||
}
|
||||
} else { //color
|
||||
@ -161,13 +196,6 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
for (uint8_t c = 0; c < 4; c++) rgbw[c] = brgbw[c];
|
||||
}
|
||||
}
|
||||
|
||||
if (set < 2) stop = start + 1;
|
||||
for (uint16_t i = start; i < stop; i++) {
|
||||
strip.setPixelColor(i, rgbw[0], rgbw[1], rgbw[2], rgbw[3]);
|
||||
}
|
||||
if (!set) start++;
|
||||
set = 0;
|
||||
}
|
||||
}
|
||||
strip.setPixelSegment(255);
|
||||
@ -180,6 +208,8 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
|
||||
bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
{
|
||||
DEBUG_PRINTLN(F("Deserializing state"));
|
||||
|
||||
strip.applyToAllSelected = false;
|
||||
bool stateResponse = root[F("v")] | false;
|
||||
|
||||
@ -200,14 +230,6 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
transitionDelayTemp = transitionDelay;
|
||||
}
|
||||
}
|
||||
|
||||
tr = root[F("tt")] | -1;
|
||||
if (tr >= 0)
|
||||
{
|
||||
transitionDelayTemp = tr;
|
||||
transitionDelayTemp *= 100;
|
||||
jsonTransitionOnce = true;
|
||||
}
|
||||
strip.setTransition(transitionDelayTemp);
|
||||
|
||||
tr = root[F("tb")] | -1;
|
||||
@ -287,16 +309,24 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
|
||||
usermods.readFromJsonState(root);
|
||||
|
||||
int8_t ledmap = root[F("ledmap")] | -1;
|
||||
if (ledmap >= 0) {
|
||||
strip.deserializeMap(ledmap);
|
||||
}
|
||||
|
||||
int ps = root[F("psave")] | -1;
|
||||
if (ps > 0) {
|
||||
DEBUG_PRINTLN(F("Saving preset"));
|
||||
savePreset(ps, true, nullptr, root);
|
||||
} else {
|
||||
ps = root[F("pdel")] | -1; //deletion
|
||||
if (ps > 0) {
|
||||
DEBUG_PRINTLN(F("Deleting preset"));
|
||||
deletePreset(ps);
|
||||
}
|
||||
ps = root["ps"] | -1; //load preset (clears state request!)
|
||||
if (ps >= 0) {
|
||||
DEBUG_PRINTLN(F("Applying preset"));
|
||||
if (!presetId) unloadPlaylist(); //stop playlist if preset changed manually
|
||||
applyPreset(ps, callMode);
|
||||
return stateResponse;
|
||||
@ -339,12 +369,15 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo
|
||||
byte segbri = seg.opacity;
|
||||
root["bri"] = (segbri) ? segbri : 255;
|
||||
|
||||
char colstr[70]; colstr[0] = '['; colstr[1] = '\0'; //max len 68 (5 chan, all 255)
|
||||
if (segmentBounds && seg.name != nullptr) root["n"] = reinterpret_cast<const char *>(seg.name);
|
||||
|
||||
// to conserve RAM we will serialize the col array manually
|
||||
// this will reduce RAM footprint from ~300 bytes to 84 bytes per segment
|
||||
char colstr[70]; colstr[0] = '['; colstr[1] = '\0'; //max len 68 (5 chan, all 255)
|
||||
const char *format = strip.isRgbw ? PSTR("[%u,%u,%u,%u]") : PSTR("[%u,%u,%u]");
|
||||
for (uint8_t i = 0; i < 3; i++)
|
||||
{
|
||||
byte segcol[4]; byte* c = segcol;
|
||||
|
||||
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
||||
{
|
||||
c = (i == 0)? col:colSec;
|
||||
@ -352,14 +385,11 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo
|
||||
segcol[0] = (byte)(seg.colors[i] >> 16); segcol[1] = (byte)(seg.colors[i] >> 8);
|
||||
segcol[2] = (byte)(seg.colors[i]); segcol[3] = (byte)(seg.colors[i] >> 24);
|
||||
}
|
||||
|
||||
char tmpcol[22];
|
||||
if (strip.isRgbw) sprintf_P(tmpcol, PSTR("[%u,%u,%u,%u]"), c[0], c[1], c[2], c[3]);
|
||||
else sprintf_P(tmpcol, PSTR("[%u,%u,%u]"), c[0], c[1], c[2]);
|
||||
|
||||
strcat(colstr, i<2 ? strcat(tmpcol,",") : tmpcol);
|
||||
sprintf_P(tmpcol, format, (unsigned)c[0], (unsigned)c[1], (unsigned)c[2], (unsigned)c[3]);
|
||||
strcat(colstr, i<2 ? strcat_P(tmpcol, PSTR(",")) : tmpcol);
|
||||
}
|
||||
strcat(colstr,"]");
|
||||
strcat_P(colstr, PSTR("]"));
|
||||
root["col"] = serialized(colstr);
|
||||
|
||||
root["fx"] = seg.mode;
|
||||
@ -377,10 +407,11 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
||||
root["on"] = (bri > 0);
|
||||
root["bri"] = briLast;
|
||||
root[F("transition")] = transitionDelay/100; //in 100ms
|
||||
root[F("tdd")] = transitionDelayDefault/100; //in 100ms
|
||||
}
|
||||
|
||||
if (!forPreset) {
|
||||
if (errorFlag) root[F("error")] = errorFlag;
|
||||
if (errorFlag) {root[F("error")] = errorFlag; errorFlag = ERR_NONE;}
|
||||
|
||||
root[F("ps")] = currentPreset;
|
||||
root[F("pl")] = currentPlaylist;
|
||||
@ -411,6 +442,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++)
|
||||
{
|
||||
WS2812FX::Segment sg = strip.getSegment(s);
|
||||
// TODO: add logic to stop at 16 segments if using versionAPI==1 on ESP8266
|
||||
if (sg.isActive())
|
||||
{
|
||||
JsonObject seg0 = seg.createNestedObject();
|
||||
@ -452,6 +484,15 @@ void serializeInfo(JsonObject root)
|
||||
leds[F("count")] = ledCount;
|
||||
leds[F("rgbw")] = strip.isRgbw;
|
||||
leds[F("wv")] = strip.isRgbw && (strip.rgbwMode == RGBW_MODE_MANUAL_ONLY || strip.rgbwMode == RGBW_MODE_DUAL); //should a white channel slider be displayed?
|
||||
|
||||
JsonArray leds_pin = leds.createNestedArray("pin");
|
||||
for (uint8_t s=0; s<busses.getNumBusses(); s++) {
|
||||
Bus *bus = busses.getBus(s);
|
||||
uint8_t pins[5];
|
||||
bus->getPins(pins);
|
||||
leds_pin.add(pins[0]); // need to elaborate this for multipin strips
|
||||
}
|
||||
|
||||
leds[F("pwr")] = strip.currentMilliamps;
|
||||
leds[F("fps")] = strip.getFps();
|
||||
leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0;
|
||||
@ -530,9 +571,11 @@ void serializeInfo(JsonObject root)
|
||||
#endif
|
||||
|
||||
root[F("freeheap")] = ESP.getFreeHeap();
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||
if (psramFound()) root[F("psram")] = ESP.getFreePsram();
|
||||
#endif
|
||||
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
||||
|
||||
|
||||
usermods.addToJsonInfo(root);
|
||||
|
||||
byte os = 0;
|
||||
@ -655,37 +698,37 @@ void serializePalettes(JsonObject root, AsyncWebServerRequest* request)
|
||||
curPalette.add("r");
|
||||
break;
|
||||
case 2: //primary color only
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add("c1");
|
||||
break;
|
||||
case 3: //primary + secondary
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add(F("c2"));
|
||||
curPalette.add(F("c2"));
|
||||
curPalette.add("c1");
|
||||
curPalette.add("c1");
|
||||
curPalette.add("c2");
|
||||
curPalette.add("c2");
|
||||
break;
|
||||
case 4: //primary + secondary + tertiary
|
||||
curPalette.add(F("c3"));
|
||||
curPalette.add(F("c2"));
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add("c3");
|
||||
curPalette.add("c2");
|
||||
curPalette.add("c1");
|
||||
break;
|
||||
case 5: {//primary + secondary (+tert if not off), more distinct
|
||||
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add(F("c2"));
|
||||
curPalette.add(F("c2"));
|
||||
curPalette.add(F("c2"));
|
||||
curPalette.add(F("c2"));
|
||||
curPalette.add(F("c2"));
|
||||
curPalette.add(F("c3"));
|
||||
curPalette.add(F("c3"));
|
||||
curPalette.add(F("c3"));
|
||||
curPalette.add(F("c3"));
|
||||
curPalette.add(F("c3"));
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add("c1");
|
||||
curPalette.add("c1");
|
||||
curPalette.add("c1");
|
||||
curPalette.add("c1");
|
||||
curPalette.add("c1");
|
||||
curPalette.add("c2");
|
||||
curPalette.add("c2");
|
||||
curPalette.add("c2");
|
||||
curPalette.add("c2");
|
||||
curPalette.add("c2");
|
||||
curPalette.add("c3");
|
||||
curPalette.add("c3");
|
||||
curPalette.add("c3");
|
||||
curPalette.add("c3");
|
||||
curPalette.add("c3");
|
||||
curPalette.add("c1");
|
||||
break;}
|
||||
case 6: //Party colors
|
||||
setPaletteColors(curPalette, PartyColors_p);
|
||||
@ -793,8 +836,7 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_PRINT("JSON buffer size: ");
|
||||
DEBUG_PRINTLN(doc.memoryUsage());
|
||||
DEBUG_PRINTF("JSON buffer size: %u for request: %d\n", doc.memoryUsage(), subJson);
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
@ -804,13 +846,13 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
|
||||
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||
{
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
AsyncWebSocketClient * wsc = nullptr;
|
||||
if (!request) { //not HTTP, use Websockets
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
wsc = ws.client(wsClient);
|
||||
if (!wsc || wsc->queueLength() > 0) return false; //only send if queue free
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t used = ledCount;
|
||||
uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS
|
||||
|
@ -190,8 +190,10 @@ void updateInterfaces(uint8_t callMode)
|
||||
espalexaDevice->setColor(col[0], col[1], col[2]);
|
||||
}
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_BLYNK
|
||||
if (callMode != CALL_MODE_BLYNK &&
|
||||
callMode != CALL_MODE_NO_NOTIFY) updateBlynk();
|
||||
#endif
|
||||
doPublishMqtt = true;
|
||||
lastInterfaceUpdate = millis();
|
||||
}
|
||||
@ -285,7 +287,9 @@ void handleNightlight()
|
||||
setLedsStandard();
|
||||
}
|
||||
}
|
||||
#ifndef WLED_DISABLE_BLYNK
|
||||
updateBlynk();
|
||||
#endif
|
||||
if (macroNl > 0)
|
||||
applyPreset(macroNl);
|
||||
nightlightActiveOld = false;
|
||||
|
@ -124,22 +124,22 @@ void publishMqtt()
|
||||
sprintf_P(s, PSTR("%u"), bri);
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
strcat_P(subuf, PSTR("/g"));
|
||||
mqtt->publish(subuf, 0, true, s);
|
||||
mqtt->publish(subuf, 0, true, s); // retain message
|
||||
|
||||
sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2]));
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
strcat_P(subuf, PSTR("/c"));
|
||||
mqtt->publish(subuf, 0, true, s);
|
||||
mqtt->publish(subuf, 0, true, s); // retain message
|
||||
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
strcat_P(subuf, PSTR("/status"));
|
||||
mqtt->publish(subuf, 0, true, "online");
|
||||
mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT
|
||||
|
||||
char apires[1024];
|
||||
char apires[1024]; // allocating 1024 bytes from stack can be risky
|
||||
XML_response(nullptr, apires);
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
strcat_P(subuf, PSTR("/v"));
|
||||
mqtt->publish(subuf, 0, false, apires);
|
||||
mqtt->publish(subuf, 0, false, apires); // do not retain message
|
||||
}
|
||||
|
||||
|
||||
@ -169,7 +169,7 @@ bool initMqtt()
|
||||
|
||||
strlcpy(mqttStatusTopic, mqttDeviceTopic, 33);
|
||||
strcat_P(mqttStatusTopic, PSTR("/status"));
|
||||
mqtt->setWill(mqttStatusTopic, 0, true, "offline");
|
||||
mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message
|
||||
mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME);
|
||||
mqtt->connect();
|
||||
return true;
|
||||
|
@ -1,6 +1,17 @@
|
||||
#include "src/dependencies/timezone/Timezone.h"
|
||||
#include "wled.h"
|
||||
#include "wled_math.h"
|
||||
#ifndef WLED_USE_REAL_MATH
|
||||
#include "wled_math.h"
|
||||
#else
|
||||
#define sin_t sin
|
||||
#define cos_t cos
|
||||
#define tan_t tan
|
||||
#define asin_t asin
|
||||
#define acos_t acos
|
||||
#define atan_t atan
|
||||
#define fmod_t fmod
|
||||
#define floor_t floor
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Acquires time from NTP server
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "pin_manager.h"
|
||||
#include "wled.h"
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
static void DebugPrintOwnerTag(PinOwner tag)
|
||||
{
|
||||
uint32_t q = static_cast<uint8_t>(tag);
|
||||
@ -10,6 +11,7 @@ static void DebugPrintOwnerTag(PinOwner tag)
|
||||
DEBUG_PRINT(F("(no owner)"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Actual allocation/deallocation routines
|
||||
bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag)
|
||||
@ -19,12 +21,14 @@ bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag)
|
||||
|
||||
// if a non-zero ownerTag, only allow de-allocation if the owner's tag is provided
|
||||
if ((ownerTag[gpio] != PinOwner::None) && (ownerTag[gpio] != tag)) {
|
||||
#ifdef WLED_DEBUG
|
||||
DEBUG_PRINT(F("PIN DEALLOC: IO "));
|
||||
DEBUG_PRINT(gpio);
|
||||
DEBUG_PRINT(F(" allocated by "));
|
||||
DebugPrintOwnerTag(ownerTag[gpio]);
|
||||
DEBUG_PRINT(F(", but attempted de-allocation by "));
|
||||
DebugPrintOwnerTag(tag);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -34,6 +38,7 @@ bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag)
|
||||
ownerTag[gpio] = PinOwner::None;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag)
|
||||
{
|
||||
bool shouldFail = false;
|
||||
@ -46,17 +51,21 @@ bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, by
|
||||
continue;
|
||||
}
|
||||
if (!isPinOk(gpio, mptArray[i].isOutput)) {
|
||||
#ifdef WLED_DEBUG
|
||||
DEBUG_PRINT(F("PIN ALLOC: Invalid pin attempted to be allocated: "));
|
||||
DEBUG_PRINT(gpio);
|
||||
DEBUG_PRINTLN(F(""));
|
||||
#endif
|
||||
shouldFail = true;
|
||||
}
|
||||
if (isPinAllocated(gpio)) {
|
||||
#ifdef WLED_DEBUG
|
||||
DEBUG_PRINT(F("PIN ALLOC: FAIL: IO "));
|
||||
DEBUG_PRINT(gpio);
|
||||
DEBUG_PRINT(F(" already allocated by "));
|
||||
DebugPrintOwnerTag(ownerTag[gpio]);
|
||||
DEBUG_PRINTLN(F(""));
|
||||
#endif
|
||||
shouldFail = true;
|
||||
}
|
||||
}
|
||||
@ -79,15 +88,18 @@ bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, by
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PinManagerClass::allocatePin(byte gpio, bool output, PinOwner tag)
|
||||
{
|
||||
if (!isPinOk(gpio, output)) return false;
|
||||
if (isPinAllocated(gpio)) {
|
||||
#ifdef WLED_DEBUG
|
||||
DEBUG_PRINT(F("PIN ALLOC: Pin "));
|
||||
DEBUG_PRINT(gpio);
|
||||
DEBUG_PRINT(F(" already allocated by "));
|
||||
DebugPrintOwnerTag(ownerTag[gpio]);
|
||||
DEBUG_PRINTLN(F(""));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -106,7 +118,7 @@ bool PinManagerClass::isPinAllocated(byte gpio, PinOwner tag)
|
||||
if (!isPinOk(gpio, false)) return true;
|
||||
if ((tag != PinOwner::None) && (ownerTag[gpio] != tag)) return false;
|
||||
byte by = gpio >> 3;
|
||||
byte bi = gpio - 8*by;
|
||||
byte bi = gpio - (by<<3);
|
||||
return bitRead(pinAlloc[by], bi);
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
typedef struct PinManagerPinType {
|
||||
int8_t pin;
|
||||
uint8_t isOutput;
|
||||
bool isOutput;
|
||||
} managed_pin_type;
|
||||
|
||||
/*
|
||||
@ -23,7 +23,6 @@ typedef struct PinManagerPinType {
|
||||
enum struct PinOwner : uint8_t {
|
||||
None = 0, // default == legacy == unspecified owner
|
||||
// High bit is set for all built-in pin owners
|
||||
// StatusLED -- THIS SHOULD NEVER BE ALLOCATED -- see handleStatusLED()
|
||||
Ethernet = 0x81,
|
||||
BusDigital = 0x82,
|
||||
BusDigital2 = 0x83,
|
||||
@ -88,7 +87,9 @@ class PinManagerClass {
|
||||
#endif
|
||||
inline void deallocatePin(byte gpio) { deallocatePin(gpio, PinOwner::None); }
|
||||
|
||||
// will return true for reserved pins
|
||||
bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None);
|
||||
// will return false for reserved pins
|
||||
bool isPinOk(byte gpio, bool output = true);
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
|
@ -90,7 +90,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
}
|
||||
|
||||
strip.isRgbw = false;
|
||||
uint8_t colorOrder, type, skip;
|
||||
uint16_t length, start;
|
||||
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
||||
@ -105,6 +104,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
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
|
||||
char sl[4] = "SL"; sl[2] = 48+s; sl[3] = 0; //skip 1st LED
|
||||
//char ew[4] = "EW"; ew[2] = 48+s; ew[3] = 0; //strip RGBW override
|
||||
if (!request->hasArg(lp)) {
|
||||
DEBUG_PRINTLN(F("No data.")); break;
|
||||
}
|
||||
@ -114,25 +114,24 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
pins[i] = (request->arg(lp).length() > 0) ? request->arg(lp).toInt() : 255;
|
||||
}
|
||||
type = request->arg(lt).toInt();
|
||||
strip.isRgbw = strip.isRgbw || BusManager::isRgbw(type);
|
||||
//if (request->hasArg(ew)) SET_BIT(type,7); else UNSET_BIT(type,7); // hack bit 7 to indicate RGBW (as a LED type override if necessary)
|
||||
skip = request->hasArg(sl) ? LED_SKIP_AMOUNT : 0;
|
||||
|
||||
colorOrder = request->arg(co).toInt();
|
||||
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : t;
|
||||
if (request->hasArg(lc) && request->arg(lc).toInt() > 0) {
|
||||
length = request->arg(lc).toInt();
|
||||
t += length = request->arg(lc).toInt();
|
||||
} else {
|
||||
break; // no parameter
|
||||
}
|
||||
|
||||
colorOrder = request->arg(co).toInt();
|
||||
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : 0;
|
||||
|
||||
// actual finalization is done in WLED::loop() (removing old busses and adding new)
|
||||
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
||||
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder, request->hasArg(cv), skip);
|
||||
doInitBusses = true;
|
||||
}
|
||||
|
||||
t = request->arg(F("LC")).toInt();
|
||||
if (t > 0 && t <= MAX_LEDS) ledCount = t;
|
||||
ledCount = request->arg(F("LC")).toInt();
|
||||
|
||||
// upate other pins
|
||||
int hw_ir_pin = request->arg(F("IR")).toInt();
|
||||
@ -181,7 +180,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
|
||||
fadeTransition = request->hasArg(F("TF"));
|
||||
t = request->arg(F("TD")).toInt();
|
||||
if (t > 0) transitionDelay = t;
|
||||
if (t >= 0) transitionDelay = t;
|
||||
transitionDelayDefault = t;
|
||||
strip.paletteFade = request->hasArg(F("PF"));
|
||||
|
||||
@ -202,6 +201,13 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
{
|
||||
strlcpy(serverDescription, request->arg(F("DS")).c_str(), 33);
|
||||
syncToggleReceive = request->hasArg(F("ST"));
|
||||
#ifndef WLED_DISABLE_SIMPLE_UI
|
||||
if (simplifiedUI ^ request->hasArg(F("SU"))) {
|
||||
// UI selection changed, invalidate browser cache
|
||||
cacheInvalidate++;
|
||||
}
|
||||
simplifiedUI = request->hasArg(F("SU"));
|
||||
#endif
|
||||
}
|
||||
|
||||
//SYNC
|
||||
@ -617,6 +623,30 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
}
|
||||
strip.setSegment(selectedSeg, startI, stopI, grpI, spcI);
|
||||
|
||||
pos = req.indexOf(F("RV=")); //Segment reverse
|
||||
if (pos > 0) mainseg.setOption(SEG_OPTION_REVERSED, req.charAt(pos+3) != '0');
|
||||
|
||||
pos = req.indexOf(F("MI=")); //Segment mirror
|
||||
if (pos > 0) mainseg.setOption(SEG_OPTION_MIRROR, req.charAt(pos+3) != '0');
|
||||
|
||||
pos = req.indexOf(F("SB=")); //Segment brightness/opacity
|
||||
if (pos > 0) {
|
||||
byte segbri = getNumVal(&req, pos);
|
||||
mainseg.setOption(SEG_OPTION_ON, segbri, selectedSeg);
|
||||
if (segbri) {
|
||||
mainseg.setOpacity(segbri, selectedSeg);
|
||||
}
|
||||
}
|
||||
|
||||
pos = req.indexOf(F("SW=")); //segment power
|
||||
if (pos > 0) {
|
||||
switch (getNumVal(&req, pos)) {
|
||||
case 0: mainseg.setOption(SEG_OPTION_ON, false); break;
|
||||
case 1: mainseg.setOption(SEG_OPTION_ON, true); break;
|
||||
default: mainseg.setOption(SEG_OPTION_ON, !mainseg.getOption(SEG_OPTION_ON)); break;
|
||||
}
|
||||
}
|
||||
|
||||
pos = req.indexOf(F("PS=")); //saves current in preset
|
||||
if (pos > 0) savePreset(getNumVal(&req, pos));
|
||||
|
||||
@ -707,7 +737,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
strip.applyToAllSelected = true;
|
||||
strip.setColor(2, t[0], t[1], t[2], t[3]);
|
||||
} else {
|
||||
strip.getSegment(selectedSeg).setColor(2,((t[0] << 16) + (t[1] << 8) + t[2] + (t[3] << 24)), selectedSeg);
|
||||
mainseg.setColor(2,((t[0] << 16) + (t[1] << 8) + t[2] + (t[3] << 24)), selectedSeg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -811,24 +841,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
pos = req.indexOf(F("TT="));
|
||||
if (pos > 0) transitionDelay = getNumVal(&req, pos);
|
||||
|
||||
//Segment reverse
|
||||
pos = req.indexOf(F("RV="));
|
||||
if (pos > 0) strip.getSegment(selectedSeg).setOption(SEG_OPTION_REVERSED, req.charAt(pos+3) != '0');
|
||||
|
||||
//Segment reverse
|
||||
pos = req.indexOf(F("MI="));
|
||||
if (pos > 0) strip.getSegment(selectedSeg).setOption(SEG_OPTION_MIRROR, req.charAt(pos+3) != '0');
|
||||
|
||||
//Segment brightness/opacity
|
||||
pos = req.indexOf(F("SB="));
|
||||
if (pos > 0) {
|
||||
byte segbri = getNumVal(&req, pos);
|
||||
strip.getSegment(selectedSeg).setOption(SEG_OPTION_ON, segbri, selectedSeg);
|
||||
if (segbri) {
|
||||
strip.getSegment(selectedSeg).setOpacity(segbri, selectedSeg);
|
||||
}
|
||||
}
|
||||
|
||||
//set time (unix timestamp)
|
||||
pos = req.indexOf(F("ST="));
|
||||
if (pos > 0) {
|
||||
|
@ -91,6 +91,12 @@ void notify(byte callMode, bool followUp)
|
||||
}
|
||||
|
||||
|
||||
void realtimeBoroadcast(IPAddress client, uint16_t length, byte *buffer, bool isRGBW)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void realtimeLock(uint32_t timeoutMs, byte md)
|
||||
{
|
||||
if (!realtimeMode && !realtimeOverride){
|
||||
@ -102,6 +108,10 @@ void realtimeLock(uint32_t timeoutMs, byte md)
|
||||
|
||||
realtimeTimeout = millis() + timeoutMs;
|
||||
if (timeoutMs == 255001 || timeoutMs == 65000) realtimeTimeout = UINT32_MAX;
|
||||
// if strip is off (bri==0) and not already in RTM
|
||||
if (bri == 0 && !realtimeMode) {
|
||||
strip.setBrightness(scaledBri(briLast));
|
||||
}
|
||||
realtimeMode = md;
|
||||
|
||||
if (arlsForceMaxBri && !realtimeOverride) strip.setBrightness(scaledBri(255));
|
||||
@ -567,7 +577,7 @@ uint8_t* copyRgbwToRgb(uint8_t *destination, uint8_t *source, uint16_t length) {
|
||||
// buffer - a buffer of at least length*4 bytes long
|
||||
// isRGBW - true if the buffer contains 4 components per pixel
|
||||
//
|
||||
void realtimeBoroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW) {
|
||||
void realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW) {
|
||||
|
||||
WiFiUDP ddpUdp;
|
||||
|
||||
|
@ -29,7 +29,7 @@ void sendSysInfoUDP();
|
||||
// buffer - a buffer of at least length*3 or length*4 bytes long
|
||||
// length - the number of pixels
|
||||
// isRGBW - true if the buffer contains 4 components per pixel
|
||||
void realtimeBoroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW);
|
||||
void realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW);
|
||||
|
||||
#define DDP_PORT 4048
|
||||
|
||||
|
@ -86,6 +86,10 @@
|
||||
#include "../usermods/rgb-rotary-encoder/rgb-rotary-encoder.h"
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_ST7789_DISPLAY
|
||||
#include "../usermods/ST7789_display/ST7789_Display.h"
|
||||
#endif
|
||||
|
||||
void registerUsermods()
|
||||
{
|
||||
/*
|
||||
@ -167,4 +171,8 @@ void registerUsermods()
|
||||
#ifdef RGB_ROTARY_ENCODER
|
||||
usermods.add(new RgbRotaryEncoderUsermod());
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_ST7789_DISPLAY
|
||||
usermods.add(new St7789DisplayUsermod());
|
||||
#endif
|
||||
}
|
||||
|
177
wled00/wled.cpp
177
wled00/wled.cpp
@ -8,6 +8,90 @@
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#endif
|
||||
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
// The following six pins are neither configurable nor
|
||||
// can they be re-assigned through IOMUX / GPIO matrix.
|
||||
// See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-ethernet-kit-v1.1.html#ip101gri-phy-interface
|
||||
const managed_pin_type esp32_nonconfigurable_ethernet_pins[WLED_ETH_RSVD_PINS_COUNT] = {
|
||||
{ 21, true }, // RMII EMAC TX EN == When high, clocks the data on TXD0 and TXD1 to transmitter
|
||||
{ 19, true }, // RMII EMAC TXD0 == First bit of transmitted data
|
||||
{ 22, true }, // RMII EMAC TXD1 == Second bit of transmitted data
|
||||
{ 25, false }, // RMII EMAC RXD0 == First bit of received data
|
||||
{ 26, false }, // RMII EMAC RXD1 == Second bit of received data
|
||||
{ 27, true }, // RMII EMAC CRS_DV == Carrier Sense and RX Data Valid
|
||||
};
|
||||
|
||||
const ethernet_settings ethernetBoards[] = {
|
||||
// None
|
||||
{
|
||||
},
|
||||
|
||||
// WT32-EHT01
|
||||
// Please note, from my testing only these pins work for LED outputs:
|
||||
// IO2, IO4, IO12, IO14, IO15
|
||||
// These pins do not appear to work from my testing:
|
||||
// IO35, IO36, IO39
|
||||
{
|
||||
1, // eth_address,
|
||||
16, // eth_power,
|
||||
23, // eth_mdc,
|
||||
18, // eth_mdio,
|
||||
ETH_PHY_LAN8720, // eth_type,
|
||||
ETH_CLOCK_GPIO0_IN // eth_clk_mode
|
||||
},
|
||||
|
||||
// ESP32-POE
|
||||
{
|
||||
0, // eth_address,
|
||||
12, // eth_power,
|
||||
23, // eth_mdc,
|
||||
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
|
||||
},
|
||||
|
||||
// TwilightLord-ESP32 Ethernet Shield
|
||||
{
|
||||
0, // eth_address,
|
||||
5, // eth_power,
|
||||
23, // eth_mdc,
|
||||
18, // eth_mdio,
|
||||
ETH_PHY_LAN8720, // eth_type,
|
||||
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
|
||||
},
|
||||
|
||||
// ESP3DEUXQuattro
|
||||
{
|
||||
1, // eth_address,
|
||||
-1, // eth_power,
|
||||
23, // eth_mdc,
|
||||
18, // eth_mdio,
|
||||
ETH_PHY_LAN8720, // eth_type,
|
||||
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Main WLED class implementation. Mostly initialization and connection logic
|
||||
*/
|
||||
@ -120,6 +204,10 @@ void WiFiEvent(WiFiEvent_t event)
|
||||
|
||||
void WLED::loop()
|
||||
{
|
||||
#ifdef WLED_DEBUG
|
||||
static unsigned long maxUsermodMillis = 0;
|
||||
#endif
|
||||
|
||||
handleTime();
|
||||
handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too
|
||||
handleConnection();
|
||||
@ -130,7 +218,15 @@ void WLED::loop()
|
||||
handleDMX();
|
||||
#endif
|
||||
userLoop();
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
unsigned long usermodMillis = millis();
|
||||
#endif
|
||||
usermods.loop();
|
||||
#ifdef WLED_DEBUG
|
||||
usermodMillis = millis() - usermodMillis;
|
||||
if (usermodMillis > maxUsermodMillis) maxUsermodMillis = usermodMillis;
|
||||
#endif
|
||||
|
||||
yield();
|
||||
handleIO();
|
||||
@ -159,7 +255,9 @@ void WLED::loop()
|
||||
yield();
|
||||
|
||||
handleHue();
|
||||
#ifndef WLED_DISABLE_BLYNK
|
||||
handleBlynk();
|
||||
#endif
|
||||
|
||||
yield();
|
||||
|
||||
@ -197,10 +295,12 @@ void WLED::loop()
|
||||
DEBUG_PRINTLN(F("Re-init busses."));
|
||||
busses.removeAll();
|
||||
uint32_t mem = 0;
|
||||
strip.isRgbw = false;
|
||||
for (uint8_t i = 0; i < WLED_MAX_BUSSES; i++) {
|
||||
if (busConfigs[i] == nullptr) break;
|
||||
|
||||
mem += BusManager::memUsage(*busConfigs[i]);
|
||||
if (mem <= MAX_LED_MEMORY) busses.add(*busConfigs[i]);
|
||||
/*
|
||||
// this is done in strip.finalizeInit()
|
||||
if (busConfigs[i]->adjustBounds(ledCount)) {
|
||||
mem += busses.memUsage(*busConfigs[i]);
|
||||
if (mem <= MAX_LED_MEMORY) {
|
||||
@ -211,20 +311,20 @@ void WLED::loop()
|
||||
strip.isOffRefreshRequred |= BusManager::isOffRefreshRequred(busConfigs[i]->type);
|
||||
}
|
||||
}
|
||||
*/
|
||||
delete busConfigs[i]; busConfigs[i] = nullptr;
|
||||
}
|
||||
strip.finalizeInit(ledCount);
|
||||
strip.finalizeInit();
|
||||
yield();
|
||||
serializeConfig();
|
||||
}
|
||||
|
||||
yield();
|
||||
handleWs();
|
||||
handleStatusLED();
|
||||
|
||||
// DEBUG serial logging
|
||||
#ifdef WLED_DEBUG
|
||||
if (millis() - debugTime > 9999) {
|
||||
if (millis() - debugTime > 29999) {
|
||||
DEBUG_PRINTLN(F("---DEBUG INFO---"));
|
||||
DEBUG_PRINT(F("Runtime: ")); DEBUG_PRINTLN(millis());
|
||||
DEBUG_PRINT(F("Unix time: ")); toki.printTime(toki.getTime());
|
||||
@ -245,8 +345,10 @@ void WLED::loop()
|
||||
DEBUG_PRINT(F("State time: ")); DEBUG_PRINTLN(wifiStateChangedTime);
|
||||
DEBUG_PRINT(F("NTP last sync: ")); DEBUG_PRINTLN(ntpLastSyncTime);
|
||||
DEBUG_PRINT(F("Client IP: ")); DEBUG_PRINTLN(Network.localIP());
|
||||
DEBUG_PRINT(F("Loops/sec: ")); DEBUG_PRINTLN(loops / 10);
|
||||
DEBUG_PRINT(F("Loops/sec: ")); DEBUG_PRINTLN(loops / 60);
|
||||
DEBUG_PRINT(F("Max UM time[ms]: ")); DEBUG_PRINTLN(maxUsermodMillis);
|
||||
loops = 0;
|
||||
maxUsermodMillis = 0;
|
||||
debugTime = millis();
|
||||
}
|
||||
loops++;
|
||||
@ -315,14 +417,6 @@ void WLED::setup()
|
||||
DEBUG_PRINTLN(F("Reading config"));
|
||||
deserializeConfigFromFS();
|
||||
|
||||
#if STATUSLED
|
||||
if (!pinManager.isPinAllocated(STATUSLED)) {
|
||||
// NOTE: Special case: The status LED should *NOT* be allocated.
|
||||
// See comments in handleStatusLed().
|
||||
pinMode(STATUSLED, OUTPUT);
|
||||
}
|
||||
#endif
|
||||
|
||||
DEBUG_PRINTLN(F("Initializing strip"));
|
||||
beginStrip();
|
||||
|
||||
@ -336,9 +430,12 @@ void WLED::setup()
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
#endif
|
||||
|
||||
#ifdef WLED_ENABLE_ADALIGHT
|
||||
#ifdef WLED_ENABLE_ADALIGHT // reserve GPIO3 (RX) pin for ADALight
|
||||
if (!pinManager.isPinAllocated(3)) {
|
||||
Serial.println(F("Ada"));
|
||||
pinManager.allocatePin(3,false);
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("ADALight disabled due to GPIO3 being used."));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -388,22 +485,20 @@ void WLED::setup()
|
||||
void WLED::beginStrip()
|
||||
{
|
||||
// Initialize NeoPixel Strip and button
|
||||
|
||||
if (ledCount > MAX_LEDS || ledCount == 0)
|
||||
ledCount = 30;
|
||||
|
||||
strip.finalizeInit(ledCount);
|
||||
strip.finalizeInit(); // busses created during deserializeConfig()
|
||||
strip.populateDefaultSegments();
|
||||
strip.setBrightness(0);
|
||||
strip.setShowCallback(handleOverlayDraw);
|
||||
|
||||
if (bootPreset > 0) {
|
||||
applyPreset(bootPreset, CALL_MODE_INIT);
|
||||
} else if (turnOnAtBoot) {
|
||||
if (turnOnAtBoot) {
|
||||
if (briS > 0) bri = briS;
|
||||
else if (bri == 0) bri = 128;
|
||||
} else {
|
||||
briLast = briS; bri = 0;
|
||||
}
|
||||
if (bootPreset > 0) {
|
||||
applyPreset(bootPreset, CALL_MODE_INIT);
|
||||
}
|
||||
colorUpdated(CALL_MODE_INIT);
|
||||
|
||||
// init relay pin
|
||||
@ -726,39 +821,3 @@ void WLED::handleConnection()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If status LED pin is allocated for other uses, does nothing
|
||||
// else blink at 1Hz when WLED_CONNECTED is false (no WiFi, ?? no Ethernet ??)
|
||||
// else blink at 2Hz when MQTT is enabled but not connected
|
||||
// else turn the status LED off
|
||||
void WLED::handleStatusLED()
|
||||
{
|
||||
#if STATUSLED
|
||||
static unsigned long ledStatusLastMillis = 0;
|
||||
static unsigned short ledStatusType = 0; // current status type - corresponds to number of blinks per second
|
||||
static bool ledStatusState = 0; // the current LED state
|
||||
|
||||
if (pinManager.isPinAllocated(STATUSLED)) {
|
||||
return; //lower priority if something else uses the same pin
|
||||
}
|
||||
|
||||
ledStatusType = WLED_CONNECTED ? 0 : 2;
|
||||
if (mqttEnabled && ledStatusType != 2) { // Wi-Fi takes precendence over MQTT
|
||||
ledStatusType = WLED_MQTT_CONNECTED ? 0 : 4;
|
||||
}
|
||||
if (ledStatusType) {
|
||||
if (millis() - ledStatusLastMillis >= (1000/ledStatusType)) {
|
||||
ledStatusLastMillis = millis();
|
||||
ledStatusState = ledStatusState ? 0 : 1;
|
||||
digitalWrite(STATUSLED, ledStatusState);
|
||||
}
|
||||
} else {
|
||||
#ifdef STATUSLEDINVERTED
|
||||
digitalWrite(STATUSLED, HIGH);
|
||||
#else
|
||||
digitalWrite(STATUSLED, LOW);
|
||||
#endif
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -3,12 +3,12 @@
|
||||
/*
|
||||
Main sketch, global variable declarations
|
||||
@title WLED project sketch
|
||||
@version 0.13.0-b2
|
||||
@version 0.13.0-bl2
|
||||
@author Christian Schwinne
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2109100
|
||||
#define VERSION 2109191
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
@ -31,9 +31,11 @@
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
#define WLED_ENABLE_MQTT // saves 12kb
|
||||
#endif
|
||||
#define WLED_ENABLE_ADALIGHT // saves 500b only
|
||||
//#define WLED_ENABLE_ADALIGHT // saves 500b only (uses GPIO3 (RX) for serial)
|
||||
//#define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2)
|
||||
#define WLED_ENABLE_LOXONE // uses 1.2kb
|
||||
#ifndef WLED_DISABLE_LOXONE
|
||||
#define WLED_ENABLE_LOXONE // uses 1.2kb
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_WEBSOCKETS
|
||||
#define WLED_ENABLE_WEBSOCKETS
|
||||
#endif
|
||||
@ -136,6 +138,9 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
|
||||
|
||||
#include "fcn_declare.h"
|
||||
#include "html_ui.h"
|
||||
#ifndef WLED_DISABLE_SIMPLE_UI
|
||||
#include "html_simple.h"
|
||||
#endif
|
||||
#include "html_settings.h"
|
||||
#include "html_other.h"
|
||||
#include "FX.h"
|
||||
@ -225,11 +230,7 @@ WLED_GLOBAL bool rlyMde _INIT(true);
|
||||
WLED_GLOBAL bool rlyMde _INIT(RLYMDE);
|
||||
#endif
|
||||
#ifndef IRPIN
|
||||
#ifdef WLED_DISABLE_INFRARED
|
||||
WLED_GLOBAL int8_t irPin _INIT(-1);
|
||||
#else
|
||||
WLED_GLOBAL int8_t irPin _INIT(4);
|
||||
#endif
|
||||
WLED_GLOBAL int8_t irPin _INIT(-1);
|
||||
#else
|
||||
WLED_GLOBAL int8_t irPin _INIT(IRPIN);
|
||||
#endif
|
||||
@ -264,7 +265,7 @@ WLED_GLOBAL bool noWifiSleep _INIT(false);
|
||||
#endif
|
||||
|
||||
// LED CONFIG
|
||||
WLED_GLOBAL uint16_t ledCount _INIT(DEFAULT_LED_COUNT); // overcurrent prevented by ABL
|
||||
WLED_GLOBAL uint16_t ledCount _INIT(0); // overcurrent prevented by ABL (filled in cfg.cpp, set.cpp or FX_fcn.cpp)
|
||||
WLED_GLOBAL bool turnOnAtBoot _INIT(true); // turn on LEDs at power-up
|
||||
WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load after power-up
|
||||
|
||||
@ -288,6 +289,8 @@ WLED_GLOBAL byte briMultiplier _INIT(100); // % of brightness to set (t
|
||||
// User Interface CONFIG
|
||||
WLED_GLOBAL char serverDescription[33] _INIT("WLED"); // Name of module
|
||||
WLED_GLOBAL bool syncToggleReceive _INIT(false); // UIs which only have a single button for sync should toggle send+receive if this is true, only send otherwise
|
||||
WLED_GLOBAL bool simplifiedUI _INIT(false); // enable simplified UI
|
||||
WLED_GLOBAL byte cacheInvalidate _INIT(0); // used to invalidate browser cache when switching from regular to simplified UI
|
||||
|
||||
// Sync CONFIG
|
||||
WLED_GLOBAL NodesMap Nodes;
|
||||
@ -566,7 +569,7 @@ WLED_GLOBAL JsonDocument* fileDoc;
|
||||
WLED_GLOBAL bool doCloseFile _INIT(false);
|
||||
|
||||
// presets
|
||||
WLED_GLOBAL int16_t currentPreset _INIT(-1);
|
||||
WLED_GLOBAL int8_t currentPreset _INIT(-1);
|
||||
|
||||
WLED_GLOBAL byte errorFlag _INIT(0);
|
||||
|
||||
@ -599,7 +602,6 @@ WLED_GLOBAL bool doInitBusses _INIT(false);
|
||||
// Usermod manager
|
||||
WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
|
||||
|
||||
|
||||
// enable additional debug output
|
||||
#ifdef WLED_DEBUG
|
||||
#ifndef ESP8266
|
||||
@ -629,7 +631,7 @@ WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
|
||||
WLED_GLOBAL unsigned long debugTime _INIT(0);
|
||||
WLED_GLOBAL int lastWifiState _INIT(3);
|
||||
WLED_GLOBAL unsigned long wifiStateChangedTime _INIT(0);
|
||||
WLED_GLOBAL int loops _INIT(0);
|
||||
WLED_GLOBAL unsigned long loops _INIT(0);
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
@ -666,6 +668,5 @@ public:
|
||||
void initAP(bool resetAP = false);
|
||||
void initConnection();
|
||||
void initInterfaces();
|
||||
void handleStatusLED();
|
||||
};
|
||||
#endif // WLED_H
|
||||
|
@ -1,20 +1,9 @@
|
||||
#ifndef WLED_ETHERNET_H
|
||||
#define WLED_ETHERNET_H
|
||||
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
#include "pin_manager.h"
|
||||
|
||||
// The following six pins are neither configurable nor
|
||||
// can they be re-assigned through IOMUX / GPIO matrix.
|
||||
// See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-ethernet-kit-v1.1.html#ip101gri-phy-interface
|
||||
const managed_pin_type esp32_nonconfigurable_ethernet_pins[6] = {
|
||||
{ 21, true }, // RMII EMAC TX EN == When high, clocks the data on TXD0 and TXD1 to transmitter
|
||||
{ 19, true }, // RMII EMAC TXD0 == First bit of transmitted data
|
||||
{ 22, true }, // RMII EMAC TXD1 == Second bit of transmitted data
|
||||
{ 25, false }, // RMII EMAC RXD0 == First bit of received data
|
||||
{ 26, false }, // RMII EMAC RXD1 == Second bit of received data
|
||||
{ 27, true }, // RMII EMAC CRS_DV == Carrier Sense and RX Data Valid
|
||||
};
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
|
||||
// For ESP32, the remaining five pins are at least somewhat configurable.
|
||||
// eth_address is in range [0..31], indicates which PHY (MAC?) address should be allocated to the interface
|
||||
@ -37,74 +26,10 @@ typedef struct EthernetSettings {
|
||||
eth_clock_mode_t eth_clk_mode;
|
||||
} ethernet_settings;
|
||||
|
||||
ethernet_settings ethernetBoards[] = {
|
||||
// None
|
||||
{
|
||||
},
|
||||
extern const ethernet_settings ethernetBoards[];
|
||||
|
||||
// WT32-EHT01
|
||||
// (*) NOTE: silkscreen on board revision v1.2 may be wrong:
|
||||
// silkscreen on v1.2 says IO35, but appears to be IO5
|
||||
// silkscreen on v1.2 says RXD, and appears to be IO35
|
||||
{
|
||||
1, // eth_address,
|
||||
16, // eth_power,
|
||||
23, // eth_mdc,
|
||||
18, // eth_mdio,
|
||||
ETH_PHY_LAN8720, // eth_type,
|
||||
ETH_CLOCK_GPIO0_IN // eth_clk_mode
|
||||
},
|
||||
|
||||
// ESP32-POE
|
||||
{
|
||||
0, // eth_address,
|
||||
12, // eth_power,
|
||||
23, // eth_mdc,
|
||||
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
|
||||
},
|
||||
|
||||
// TwilightLord-ESP32 Ethernet Shield
|
||||
{
|
||||
0, // eth_address,
|
||||
5, // eth_power,
|
||||
23, // eth_mdc,
|
||||
18, // eth_mdio,
|
||||
ETH_PHY_LAN8720, // eth_type,
|
||||
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
|
||||
},
|
||||
|
||||
// ESP3DEUXQuattro
|
||||
{
|
||||
1, // eth_address,
|
||||
-1, // eth_power,
|
||||
23, // eth_mdc,
|
||||
18, // eth_mdio,
|
||||
ETH_PHY_LAN8720, // eth_type,
|
||||
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
|
||||
}
|
||||
};
|
||||
#define WLED_ETH_RSVD_PINS_COUNT 6
|
||||
extern const managed_pin_type esp32_nonconfigurable_ethernet_pins[WLED_ETH_RSVD_PINS_COUNT];
|
||||
#endif
|
||||
|
||||
#endif
|
@ -80,6 +80,43 @@ float asin_t(float x) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
//https://stackoverflow.com/a/42542593
|
||||
#define A 0.0776509570923569
|
||||
#define B -0.287434475393028
|
||||
#define C ((HALF_PI/2) - A - B)
|
||||
|
||||
//polynominal factors for approximation between 1 and 5
|
||||
#define C0 0.089494f
|
||||
#define C1 0.974207f
|
||||
#define C2 -0.326175f
|
||||
#define C3 0.05375f
|
||||
#define C4 -0.003445f
|
||||
|
||||
float atan_t(float x) {
|
||||
bool neg = (x < 0);
|
||||
#ifdef WLED_DEBUG_MATH
|
||||
float xinput = x;
|
||||
#endif
|
||||
x = std::abs(x);
|
||||
float res;
|
||||
if (x > 5.0f) { //atan(x) converges to pi/2 - (1/x) for large values
|
||||
res = HALF_PI - (1.0f/x);
|
||||
}
|
||||
else if (x > 1.0f) { //1 < x < 5
|
||||
float xx = x * x;
|
||||
res = (C4*xx*xx)+(C3*xx*x)+(C2*xx)+(C1*x)+C0;
|
||||
} else { //this approximation is only for x <= 1
|
||||
float xx = x * x;
|
||||
res = ((A*xx + B)*xx + C)*x;
|
||||
}
|
||||
if (neg) res = -res;
|
||||
#ifdef WLED_DEBUG_MATH
|
||||
Serial.printf("atan,%f,%f,%f\n",xinput,res,atan(xinput));
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
//https://stackoverflow.com/a/42542593
|
||||
#define A 0.0776509570923569
|
||||
#define B -0.287434475393028
|
||||
|
@ -114,7 +114,7 @@ void handleSerial()
|
||||
if (!realtimeOverride) setRealtimePixel(pixel++, red, green, blue, 0);
|
||||
if (--count > 0) state = AdaState::Data_Red;
|
||||
else {
|
||||
if (!realtimeMode && bri == 0) strip.setBrightness(briLast);
|
||||
// if (!realtimeMode && bri == 0) strip.setBrightness(briLast); //realtimeLock() handles turning strip on/off
|
||||
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_ADALIGHT);
|
||||
|
||||
if (!realtimeOverride) strip.show();
|
||||
|
@ -4,6 +4,9 @@
|
||||
* Integrated HTTP web server page declarations
|
||||
*/
|
||||
|
||||
bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest* request);
|
||||
void setStaticContentCacheHeaders(AsyncWebServerResponse *response);
|
||||
|
||||
//Is this an IP?
|
||||
bool isIp(String str) {
|
||||
for (size_t i = 0; i < str.length(); i++) {
|
||||
@ -16,7 +19,7 @@ bool isIp(String str) {
|
||||
}
|
||||
|
||||
void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final){
|
||||
if(!index){
|
||||
if (!index) {
|
||||
request->_tempFile = WLED_FS.open(filename, "w");
|
||||
DEBUG_PRINT("Uploading ");
|
||||
DEBUG_PRINTLN(filename);
|
||||
@ -25,9 +28,10 @@ void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t
|
||||
if (len) {
|
||||
request->_tempFile.write(data,len);
|
||||
}
|
||||
if(final){
|
||||
if (final) {
|
||||
request->_tempFile.close();
|
||||
request->send(200, "text/plain", F("File Uploaded!"));
|
||||
cacheInvalidate++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,6 +167,15 @@ void initServer()
|
||||
size_t len, bool final) {handleUpload(request, filename, index, data, len, final);}
|
||||
);
|
||||
|
||||
server.on("/simple.htm", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (handleFileRead(request, "/simple.htm")) return;
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_simple, PAGE_simple_L);
|
||||
response->addHeader(F("Content-Encoding"),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
});
|
||||
|
||||
//if OTA is allowed
|
||||
if (!otaLock){
|
||||
#ifdef WLED_ENABLE_FS_EDITOR
|
||||
@ -287,6 +300,8 @@ bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest* request)
|
||||
|
||||
void setStaticContentCacheHeaders(AsyncWebServerResponse *response)
|
||||
{
|
||||
char tmp[12];
|
||||
// https://medium.com/@codebyamir/a-web-developers-guide-to-browser-caching-cc41f3b73e7c
|
||||
#ifndef WLED_DEBUG
|
||||
//this header name is misleading, "no-cache" will not disable cache,
|
||||
//it just revalidates on every load using the "If-None-Match" header with the last ETag value
|
||||
@ -294,7 +309,8 @@ void setStaticContentCacheHeaders(AsyncWebServerResponse *response)
|
||||
#else
|
||||
response->addHeader(F("Cache-Control"),"no-store,max-age=0"); // prevent caching if debug build
|
||||
#endif
|
||||
response->addHeader(F("ETag"), String(VERSION));
|
||||
sprintf_P(tmp, PSTR("%8d-%02x"), VERSION, cacheInvalidate);
|
||||
response->addHeader(F("ETag"), tmp);
|
||||
}
|
||||
|
||||
void serveIndex(AsyncWebServerRequest* request)
|
||||
@ -303,7 +319,13 @@ void serveIndex(AsyncWebServerRequest* request)
|
||||
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_index, PAGE_index_L);
|
||||
AsyncWebServerResponse *response;
|
||||
#ifndef WLED_DISABLE_SIMPLE_UI
|
||||
if (simplifiedUI)
|
||||
response = request->beginResponse_P(200, "text/html", PAGE_simple, PAGE_simple_L);
|
||||
else
|
||||
#endif
|
||||
response = request->beginResponse_P(200, "text/html", PAGE_index, PAGE_index_L);
|
||||
|
||||
response->addHeader(F("Content-Encoding"),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
|
@ -16,9 +16,11 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
if(type == WS_EVT_CONNECT){
|
||||
//client connected
|
||||
sendDataWs(client);
|
||||
DEBUG_PRINTLN(F("WS client connected."));
|
||||
} else if(type == WS_EVT_DISCONNECT){
|
||||
//client disconnected
|
||||
if (client->id() == wsLiveClientId) wsLiveClientId = 0;
|
||||
DEBUG_PRINTLN(F("WS client disconnected."));
|
||||
} else if(type == WS_EVT_DATA){
|
||||
//data packet
|
||||
AwsFrameInfo * info = (AwsFrameInfo*)arg;
|
||||
@ -39,6 +41,11 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
JsonObject root = jsonBuffer.as<JsonObject>();
|
||||
if (error || root.isNull()) return;
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
DEBUG_PRINT(F("Incoming WS: "));
|
||||
serializeJson(root,Serial);
|
||||
DEBUG_PRINTLN();
|
||||
#endif
|
||||
if (root["v"] && root.size() == 1) {
|
||||
//if the received value is just "{"v":true}", send only to this client
|
||||
verboseResponse = true;
|
||||
@ -76,12 +83,15 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG_PRINTLN(F("WS multipart message."));
|
||||
}
|
||||
} else if(type == WS_EVT_ERROR){
|
||||
//error was received from the other end
|
||||
DEBUG_PRINTLN(F("WS error."));
|
||||
|
||||
} else if(type == WS_EVT_PONG){
|
||||
//pong message was received (in response to a ping request maybe)
|
||||
DEBUG_PRINTLN(F("WS pong."));
|
||||
|
||||
}
|
||||
}
|
||||
@ -100,13 +110,22 @@ void sendDataWs(AsyncWebSocketClient * client)
|
||||
size_t len = measureJson(doc);
|
||||
buffer = ws.makeBuffer(len);
|
||||
if (!buffer) return; //out of memory
|
||||
|
||||
/*
|
||||
#ifdef WLED_DEBUG
|
||||
DEBUG_PRINT(F("Outgoing WS: "));
|
||||
serializeJson(doc,Serial);
|
||||
DEBUG_PRINTLN();
|
||||
#endif
|
||||
*/
|
||||
serializeJson(doc, (char *)buffer->get(), len +1);
|
||||
}
|
||||
DEBUG_PRINT(F("Sending WS data "));
|
||||
if (client) {
|
||||
client->text(buffer);
|
||||
DEBUG_PRINTLN(F("to a single client."));
|
||||
} else {
|
||||
ws.textAll(buffer);
|
||||
DEBUG_PRINTLN(F("to multiple clients."));
|
||||
}
|
||||
}
|
||||
|
||||
|
157
wled00/xml.cpp
157
wled00/xml.cpp
@ -1,4 +1,5 @@
|
||||
#include "wled.h"
|
||||
#include "wled_ethernet.h"
|
||||
|
||||
/*
|
||||
* Sending XML status files to client
|
||||
@ -158,24 +159,16 @@ void sappends(char stype, const char* key, char* val)
|
||||
{
|
||||
switch(stype)
|
||||
{
|
||||
case 's': { //string (we can interpret val as char*)
|
||||
case 's': {//string (we can interpret val as char*)
|
||||
String buf = val;
|
||||
//convert "%" to "%%" to make EspAsyncWebServer happy
|
||||
buf.replace("%","%%");
|
||||
oappend("d.Sf.");
|
||||
oappend(key);
|
||||
oappend(".value=\"");
|
||||
//convert "%" to "%%" to make EspAsyncWebServer happy
|
||||
char buf[130];
|
||||
uint8_t len = strlen(val) +1;
|
||||
uint8_t s = 0;
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
buf[i+s] = val[i];
|
||||
if (val[i] == '%') {
|
||||
s++; buf[i+s] = '%';
|
||||
}
|
||||
}
|
||||
|
||||
oappend(buf);
|
||||
oappend(buf.c_str());
|
||||
oappend("\";");
|
||||
break; }
|
||||
break;}
|
||||
case 'm': //message
|
||||
oappend(SET_F("d.getElementsByClassName"));
|
||||
oappend(key);
|
||||
@ -186,6 +179,52 @@ void sappends(char stype, const char* key, char* val)
|
||||
}
|
||||
}
|
||||
|
||||
void extractPin(JsonObject &obj, const char *key) {
|
||||
if (obj[key].is<JsonArray>()) {
|
||||
JsonArray pins = obj[key].as<JsonArray>();
|
||||
for (JsonVariant pv : pins) {
|
||||
if (pv.as<int>() > -1) { oappend(","); oappendi(pv.as<int>()); }
|
||||
}
|
||||
} else {
|
||||
if (obj[key].as<int>() > -1) { oappend(","); oappendi(obj[key].as<int>()); }
|
||||
}
|
||||
}
|
||||
|
||||
// oappens used pins by recursively scanning JsonObject
|
||||
void fillUMPins(JsonObject &mods)
|
||||
{
|
||||
for (JsonPair kv : mods) {
|
||||
// kv.key() is usermod name or subobject key
|
||||
// kv.value() is object itself
|
||||
JsonObject obj = kv.value();
|
||||
if (!obj.isNull()) {
|
||||
// element is an JsonObject
|
||||
if (!obj["pin"].isNull()) {
|
||||
extractPin(obj, "pin");
|
||||
} else {
|
||||
// scan keys (just one level deep as is possible with usermods)
|
||||
for (JsonPair so : obj) {
|
||||
const char *key = so.key().c_str();
|
||||
if (strstr(key, "pin")) {
|
||||
// we found a key containing "pin" substring
|
||||
if (strlen(strstr(key, "pin")) == 3) {
|
||||
// and it is at the end, we found another pin
|
||||
extractPin(obj, key);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!obj[so.key()].is<JsonObject>()) continue;
|
||||
JsonObject subObj = obj[so.key()];
|
||||
if (!subObj["pin"].isNull()) {
|
||||
// get pins from subobject
|
||||
extractPin(subObj, "pin");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//get values for settings form in javascript
|
||||
void getSettingsJS(byte subPage, char* dest)
|
||||
@ -198,7 +237,8 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
|
||||
if (subPage <1 || subPage >8) return;
|
||||
|
||||
if (subPage == 1) {
|
||||
if (subPage == 1)
|
||||
{
|
||||
sappends('s',SET_F("CS"),clientSSID);
|
||||
|
||||
byte l = strlen(clientPass);
|
||||
@ -264,50 +304,72 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
}
|
||||
}
|
||||
|
||||
if (subPage == 2) {
|
||||
if (subPage == 2)
|
||||
{
|
||||
char nS[8];
|
||||
|
||||
// add reserved and usermod pins as d.um_p array
|
||||
oappend(SET_F("d.um_p=[6,7,8,9,10,11"));
|
||||
|
||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE/2);
|
||||
JsonObject mods = doc.createNestedObject(F("um"));
|
||||
usermods.addToConfig(mods);
|
||||
oappend(SET_F("d.um_p=["));
|
||||
if (!mods.isNull()) {
|
||||
uint8_t i=0;
|
||||
for (JsonPair kv : mods) {
|
||||
if (!kv.value().isNull()) {
|
||||
// element is an JsonObject
|
||||
JsonObject obj = kv.value();
|
||||
if (obj["pin"] != nullptr) {
|
||||
if (obj["pin"].is<JsonArray>()) {
|
||||
JsonArray pins = obj["pin"].as<JsonArray>();
|
||||
for (JsonVariant pv : pins) {
|
||||
if (i++) oappend(SET_F(","));
|
||||
oappendi(pv.as<int>());
|
||||
}
|
||||
} else {
|
||||
if (i++) oappend(SET_F(","));
|
||||
oappendi(obj["pin"].as<int>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i) oappend(SET_F(","));
|
||||
oappend(SET_F("6,7,8,9,10,11")); // flash memory pins
|
||||
if (!mods.isNull()) fillUMPins(mods);
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
oappend(SET_F(",2")); // DMX hardcoded pin
|
||||
#endif
|
||||
//Adalight / Serial in requires pin 3 to be unused. However, Serial input can not be prevented by WLED
|
||||
|
||||
#ifdef WLED_ENABLE_ADALIGHT
|
||||
// inform settings page that pin 3 is used by ADALights if not aleready used by strip (previous setup)
|
||||
// NOTE: this will prohibit pin 3 use on new installs
|
||||
{
|
||||
bool pin3used = false;
|
||||
for (uint8_t s=0; s < busses.getNumBusses(); s++) {
|
||||
Bus* bus = busses.getBus(s);
|
||||
uint8_t pins[5];
|
||||
uint8_t nPins = bus->getPins(pins);
|
||||
for (uint8_t i = 0; i < nPins; i++) {
|
||||
if (pins[i] == 3) {
|
||||
pin3used = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pin3used) break;
|
||||
}
|
||||
if (!pin3used && pinManager.isPinAllocated(3)) oappend(SET_F(",3")); // ADALight (RX) pin
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
oappend(SET_F(",1")); // debug output (TX) pin
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||
if (psramFound()) oappend(SET_F(",16,17")); // GPIO16 & GPIO17 reserved for SPI RAM
|
||||
#endif
|
||||
//TODO: add reservations for Ethernet shield pins
|
||||
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
#endif
|
||||
if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
|
||||
for (uint8_t p=0; p<WLED_ETH_RSVD_PINS_COUNT; p++) { oappend(","); oappend(itoa(esp32_nonconfigurable_ethernet_pins[p].pin,nS,10)); }
|
||||
if (ethernetBoards[ethernetType].eth_power>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_power,nS,10)); }
|
||||
if (ethernetBoards[ethernetType].eth_mdc>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_mdc,nS,10)); }
|
||||
if (ethernetBoards[ethernetType].eth_mdio>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_mdio,nS,10)); }
|
||||
switch (ethernetBoards[ethernetType].eth_clk_mode) {
|
||||
case ETH_CLOCK_GPIO0_IN:
|
||||
case ETH_CLOCK_GPIO0_OUT:
|
||||
oappend(SET_F(",0"));
|
||||
break;
|
||||
case ETH_CLOCK_GPIO16_OUT:
|
||||
oappend(SET_F(",16"));
|
||||
break;
|
||||
case ETH_CLOCK_GPIO17_OUT:
|
||||
oappend(SET_F(",17"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
oappend(SET_F("];"));
|
||||
|
||||
// set limits
|
||||
@ -317,10 +379,6 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
oappend(itoa(MAX_LED_MEMORY,nS,10));
|
||||
oappend(SET_F(");"));
|
||||
|
||||
oappend(SET_F("d.Sf.LC.max=")); //TODO Formula for max LEDs on ESP8266 depending on types. 500 DMA or 1500 UART (about 4kB mem usage)
|
||||
oappendi(MAX_LEDS);
|
||||
oappend(";");
|
||||
|
||||
sappend('v',SET_F("LC"),ledCount);
|
||||
sappend('c',SET_F("MS"),autoSegments);
|
||||
|
||||
@ -333,19 +391,21 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
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
|
||||
char sl[4] = "SL"; sl[2] = 48+s; sl[3] = 0; //skip 1st LED
|
||||
// char ew[4] = "EW"; ew[2] = 48+s; ew[3] = 0; //strip RGBW override
|
||||
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]);
|
||||
if (pinManager.isPinOk(pins[i])) sappend('v',lp,pins[i]);
|
||||
}
|
||||
sappend('v', lc, bus->getLength());
|
||||
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('c',sl,bus->skippedLeds());
|
||||
// sappend('c',ew,bus->isRgbw());
|
||||
}
|
||||
sappend('v',SET_F("MA"),strip.ablMilliampsMax);
|
||||
sappend('v',SET_F("LA"),strip.milliampsPerLed);
|
||||
@ -391,6 +451,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
{
|
||||
sappends('s',SET_F("DS"),serverDescription);
|
||||
sappend('c',SET_F("ST"),syncToggleReceive);
|
||||
sappend('c',SET_F("SU"),simplifiedUI);
|
||||
}
|
||||
|
||||
if (subPage == 4)
|
||||
|
Loading…
Reference in New Issue
Block a user