Merge pull request #3529 from Aircoookie/0_14_1

0.14.1-beta
This commit is contained in:
Blaž Kristan 2023-12-18 21:20:12 +01:00 committed by GitHub
commit 7642c5a50d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
107 changed files with 4957 additions and 4734 deletions

View File

@ -1,5 +1,15 @@
## WLED changelog
#### Build 2311160
- Version bump: 0.14.1-b1
- Bugfixes (#3526, #3502, #3496, #3484, #3487, #3445, #3466, #3296, #3382, #3312)
- New feature: Sort presets by ID
- New usermod: LDR sensor (#3490 by @JeffWDH)
- Effect: Twinklefox & Tinklecat metadata fix
- Effect: separate #HH and #MM for Scrolling Text (#3480)
- SSDR usermod enhancements (#3368)
- PWM fan usermod enhancements (#3414)
#### Build 2310010, build 2310130
- Release of WLED version 0.14.0 "Hoshi"
- Bugfixes for #3400, #3403, #3405
@ -422,7 +432,7 @@
- Added application level pong websockets reply (#2139)
- Use AsyncTCP 1.0.3 as it mitigates the flickering issue from 0.13.0-b2
- Fixed transition manually updated in preset overriden by field value
- Fixed transition manually updated in preset overridden by field value
#### Build 2108050
@ -951,7 +961,7 @@
#### Build 2011040
- Inversed Rain direction (fixes #1147)
- Inverted Rain direction (fixes #1147)
#### Build 2011010
@ -1162,7 +1172,7 @@
- Added module info page to web UI
- Added realtime override functionality to web UI
- Added individial segment power and brightness to web UI
- Added individual segment power and brightness to web UI
- Added feature to one-click select single segment only by tapping segment name
- Removed palette jumping to default if color is changed

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "wled",
"version": "0.14.0",
"version": "0.14.1-b1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

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

View File

@ -217,7 +217,7 @@ build_flags =
; restrict to minimal mime-types
-DMIMETYPE_MINIMAL
; other special-purpose framework flags (see https://docs.platformio.org/en/latest/platforms/espressif8266.html)
; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 ;; in case of linker errors like "section `.text1' will not fit in region `iram1_0_seg'"
-D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 ;; in case of linker errors like "section `.text1' will not fit in region `iram1_0_seg'"
; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED ;; (experimental) adds some extra heap, but may cause slowdown
lib_deps =
@ -654,7 +654,7 @@ build_flags = ${common.build_flags_esp32}
-D RLYPIN=19
-D BTNPIN=17
-D IRPIN=18
-D UWLED_USE_MY_CONFIG
-U WLED_USE_MY_CONFIG
-D USERMOD_DALLASTEMPERATURE
-D USERMOD_FOUR_LINE_DISPLAY
-D TEMPERATURE_PIN=23

View File

@ -26,7 +26,7 @@ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control
- Up to 250 user presets to save and load colors/effects easily, supports cycling through them.
- Presets can be used to automatically execute API calls
- Nightlight function (gradually dims down)
- Full OTA software updatability (HTTP + ArduinoOTA), password protectable
- Full OTA software updateability (HTTP + ArduinoOTA), password protectable
- Configurable analog clock (Cronixie, 7-segment and EleksTube IPS clock support via usermods)
- Configurable Auto Brightness limit for safe operation
- Filesystem-based config for easier backup of presets and settings

View File

@ -133,7 +133,7 @@ class Animated_Staircase : public Usermod {
* received within this time, an object is detected
* and the function will return true.
*
* The speed of sound is 343 meters per second at 20 degress Celcius.
* The speed of sound is 343 meters per second at 20 degrees Celsius.
* Since the sound has to travel back and forth, the detection
* distance for the sensor in cm is (0.0343 * maxTimeUs) / 2.
*
@ -259,7 +259,7 @@ class Animated_Staircase : public Usermod {
}
}
// send sesnor values to JSON API
// send sensor values to JSON API
void writeSensorsToJson(JsonObject& staircase) {
staircase[F("top-sensor")] = topSensorRead;
staircase[F("bottom-sensor")] = bottomSensorRead;
@ -297,8 +297,8 @@ class Animated_Staircase : public Usermod {
offIndex = maxSegmentId = strip.getLastActiveSegmentId() + 1;
// shorten the strip transition time to be equal or shorter than segment delay
transitionDelayTemp = transitionDelay = segment_delay_ms;
strip.setTransition(segment_delay_ms/100);
transitionDelay = segment_delay_ms;
strip.setTransition(segment_delay_ms);
strip.trigger();
} else {
if (togglePower && !on && offMode) toggleOnOff(); // toggle power on if off
@ -309,7 +309,7 @@ class Animated_Staircase : public Usermod {
seg.setOption(SEG_OPTION_ON, true);
}
strip.trigger(); // force strip update
stateChanged = true; // inform external dvices/UI of change
stateChanged = true; // inform external devices/UI of change
colorUpdated(CALL_MODE_DIRECT_CHANGE);
DEBUG_PRINTLN(F("Animated Staircase disabled."));
}
@ -492,7 +492,7 @@ class Animated_Staircase : public Usermod {
bottomEchoPin = top[FPSTR(_bottomEcho_pin)] | bottomEchoPin;
topMaxDist = top[FPSTR(_topEchoCm)] | topMaxDist;
topMaxDist = min(150,max(30,(int)topMaxDist)); // max distnace ~1.5m (a lag of 9ms may be expected)
topMaxDist = min(150,max(30,(int)topMaxDist)); // max distance ~1.5m (a lag of 9ms may be expected)
bottomMaxDist = top[FPSTR(_bottomEchoCm)] | bottomMaxDist;
bottomMaxDist = min(150,max(30,(int)bottomMaxDist)); // max distance ~1.5m (a lag of 9ms may be expected)

View File

@ -38,7 +38,7 @@ Maximum distance for ultrasonic sensor can be configured as the time needed for
You _may_ need to use 10k pull-down resistors on the selected PIR pins, depending on the sensor.
## WLED configuration
1. In the WLED UI, confgure a segment for each step. The lowest step of the stairs is the
1. In the WLED UI, configure a segment for each step. The lowest step of the stairs is the
lowest segment id.
2. Save your segments into a preset.
3. Ideally, add the preset in the config > LED setup menu to the "apply
@ -91,7 +91,7 @@ To enable the usermod again, use `"enabled":true`.
Alternatively you can use _Usermod_ Settings page where you can change other parameters as well.
### Changing animation parameters and detection range of the ultrasonic HC-SR04 sensor
Using _Usermod_ Settings page you can define different usermod parameters, includng sensor pins, delay between segment activation etc.
Using _Usermod_ Settings page you can define different usermod parameters, including sensor pins, delay between segment activation etc.
When an ultrasonic sensor is enabled you can enter maximum detection distance in centimeters separately for top and bottom sensors.

View File

@ -9,7 +9,7 @@ The luminance is displayed in both the Info section of the web UI, as well as pu
- This must be added under `lib_deps` in your `platformio.ini` (or `platformio_override.ini`).
- Data is published over MQTT - make sure you've enabled the MQTT sync interface.
## Compiliation
## Compilation
To enable, compile with `USERMOD_BH1750` defined (e.g. in `platformio_override.ini`)
```ini

View File

@ -25,7 +25,7 @@
#define USERMOD_BH1750_FIRST_MEASUREMENT_AT 10000
#endif
// only report if differance grater than offset value
// only report if difference grater than offset value
#ifndef USERMOD_BH1750_OFFSET_VALUE
#define USERMOD_BH1750_OFFSET_VALUE 1
#endif

View File

@ -31,7 +31,7 @@ private:
// set the default pins based on the architecture, these get overridden by Usermod menu settings
#ifdef ESP8266
//uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
//uint8_t RST_PIN = 16; // Un-comment for Heltec WiFi-Kit-8
#endif
bool initDone = false;
@ -78,7 +78,7 @@ private:
static const char _name[];
static const char _enabled[];
// Read the BME280/BMP280 Sensor (which one runs depends on whether Celsius or Farenheit being set in Usermod Menu)
// Read the BME280/BMP280 Sensor (which one runs depends on whether Celsius or Fahrenheit being set in Usermod Menu)
void UpdateBME280Data(int SensorType)
{
float _temperature, _humidity, _pressure;

View File

@ -19,7 +19,7 @@ If you have an ESP32 board, connect the positive side of the battery to ADC1 (GP
- 💯 Displays current battery voltage
- 🚥 Displays battery level
- 🚫 Auto-off with configurable Threshold
- 🚨 Low power indicator with many configuration posibilities
- 🚨 Low power indicator with many configuration possibilities
## 🎈 Installation
@ -41,7 +41,7 @@ define `USERMOD_BATTERY` in `wled00/my_config.h`
| `USERMOD_BATTERY_MEASUREMENT_INTERVAL` | ms | battery check interval. defaults to 30 seconds |
| `USERMOD_BATTERY_MIN_VOLTAGE` | v | minimum battery voltage. default is 2.6 (18650 battery standard) |
| `USERMOD_BATTERY_MAX_VOLTAGE` | v | maximum battery voltage. default is 4.2 (18650 battery standard) |
| `USERMOD_BATTERY_TOTAL_CAPACITY` | mAh | the capacity of all cells in parralel sumed up |
| `USERMOD_BATTERY_TOTAL_CAPACITY` | mAh | the capacity of all cells in parallel summed up |
| `USERMOD_BATTERY_CALIBRATION` | | offset / calibration number, fine tune the measured voltage by the microcontroller |
| Auto-Off | --- | --- |
| `USERMOD_BATTERY_AUTO_OFF_ENABLED` | true/false | enables auto-off |

View File

@ -49,7 +49,7 @@
#endif
// how many seconds after boot to take first measurement, 90 seconds
// 90 gives enough time to OTA update firmware if this crashses
// 90 gives enough time to OTA update firmware if this crashes
#ifndef USERMOD_DHT_FIRST_MEASUREMENT_AT
#define USERMOD_DHT_FIRST_MEASUREMENT_AT 90000
#endif

View File

@ -46,7 +46,7 @@ class MyExampleUsermod : public Usermod {
static const char _enabled[];
// any private methods should go here (non-inline methosd should be defined out of class)
// any private methods should go here (non-inline method should be defined out of class)
void publishMqtt(const char* state, bool retain = false); // example for publishing MQTT message

View File

@ -15,23 +15,23 @@ OneWire oneWire(13);
DallasTemperature sensor(&oneWire);
long temptimer = millis();
long lastMeasure = 0;
#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit
#define Celsius // Show temperature measurement in Celsius otherwise is in Fahrenheit
// 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
// --> First choise of cheap I2C OLED 128X32 0.91"
// --> First choice of cheap I2C OLED 128X32 0.91"
U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
// --> Second choise of cheap I2C OLED 128X64 0.96" or 1.3"
// --> Second choice of cheap I2C OLED 128X64 0.96" or 1.3"
//U8X8_SSD1306_128X64_NONAME_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() {
sensor.begin(); //Start Dallas temperature sensor
u8x8.begin();
//u8x8.setFlipMode(1); //Uncoment if using WLED Wemos shield
//u8x8.setFlipMode(1); //Un-comment if using WLED Wemos shield
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);
@ -71,7 +71,7 @@ void userLoop() {
if (mqtt != nullptr)
{
sensor.requestTemperatures();
//Gets prefered temperature scale based on selection in definitions section
//Gets preferred temperature scale based on selection in definitions section
#ifdef Celsius
float board_temperature = sensor.getTempCByIndex(0);
#else
@ -138,11 +138,11 @@ void userLoop() {
// 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
// Print `~` char to indicate that SSID is longer than our display
if (knownSsid.length() > u8x8.getCols())
u8x8.print("~");
// Second row with IP or Psssword
// Second row with IP or Password
u8x8.setCursor(1, 1);
// Print password in AP mode and if led is OFF.
if (apActive && bri == 0)

View File

@ -10,7 +10,7 @@
void UpdateBME280Data();
#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit
#define Celsius // Show temperature measurement in Celsius otherwise is in Fahrenheit
BME280I2C bme; // Default : forced mode, standby time = 1000 ms
// Oversampling = pressure ×1, temperature ×1, humidity ×1, filter off,
@ -20,14 +20,14 @@ uint8_t SDA_PIN = 21;
#else //ESP8266 boards
uint8_t SCL_PIN = 5;
uint8_t SDA_PIN = 4;
// uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
// uint8_t RST_PIN = 16; // Un-comment for Heltec WiFi-Kit-8
#endif
//The SCL and SDA pins are defined here.
//ESP8266 Wemos D1 mini board use SCL=5 SDA=4 while ESP32 Wemos32 mini board use SCL=22 SDA=21
#define U8X8_PIN_SCL SCL_PIN
#define U8X8_PIN_SDA SDA_PIN
//#define U8X8_PIN_RESET RST_PIN // Uncoment for Heltec WiFi-Kit-8
//#define U8X8_PIN_RESET RST_PIN // Un-comment for Heltec WiFi-Kit-8
// If display does not work or looks corrupted check the
// constructor reference:
@ -36,9 +36,9 @@ uint8_t SDA_PIN = 4;
// https://github.com/olikraus/u8g2/wiki/gallery
// --> First choise of cheap I2C OLED 128X32 0.91"
U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
// --> Second choise of cheap I2C OLED 128X64 0.96" or 1.3"
// --> Second choice of cheap I2C OLED 128X64 0.96" or 1.3"
//U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
// --> Third choise of Heltec WiFi-Kit-8 OLED 128X32 0.91"
// --> Third choice of Heltec WiFi-Kit-8 OLED 128X32 0.91"
//U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_RESET, U8X8_PIN_SCL, U8X8_PIN_SDA); // Constructor for Heltec WiFi-Kit-8
// gets called once at boot. Do all initialization that doesn't depend on network here
@ -181,11 +181,11 @@ void userLoop() {
// 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
// Print `~` char to indicate that SSID is longer than our display
if (knownSsid.length() > u8x8.getCols())
u8x8.print("~");
// Second row with IP or Psssword
// Second row with IP or Password
u8x8.setCursor(1, 1);
// Print password in AP mode and if led is OFF.
if (apActive && bri == 0)

View File

@ -2,7 +2,7 @@
**Attention: This usermod compiles only for ESP8266**
This usermod-v2 modification performs a ping request to a local IP address every 60 seconds. This ensures WLED net services remain accessible in some problematic WLAN environments.
This usermod-v2 modification performs a ping request to a local IP address every 60 seconds. This ensures WLED net services remain accessible in some problematic WiFi environments.
The modification works with static or DHCP IP address configuration.
@ -24,7 +24,7 @@ The usermod supports the following state changes:
| JSON key | Value range | Description |
|-------------|------------------|---------------------------------|
| PingDelayMs | 5000 to 18000000 | Deactivdate/activate the sensor |
| PingDelayMs | 5000 to 18000000 | Deactivate/activate the sensor |
Changes also persist after a reboot.

View File

@ -15,7 +15,7 @@ private:
static const char _enabled[];
static const char _loopInterval[];
// any private methods should go here (non-inline methosd should be defined out of class)
// any private methods should go here (non-inline method should be defined out of class)
void publishMqtt(const char *state, bool retain = false); // example for publishing MQTT message
public:

View File

@ -0,0 +1,26 @@
# LDR_Dusk_Dawn_v2
This usermod will obtain readings from a Light Dependent Resistor (LDR) and will turn on/off specific presets based on those readings. This is useful for exterior lighting situations where you want the lights to only be on when it is dark out.
# Installation
Add "-D USERMOD_LDR_DUSK_DAWN" to your platformio.ini [common] build_flags and build.
Example:
```
[common]
build_flags =
-D USERMOD_LDR_DUSK_DAWN # Enable LDR Dusk Dawn Usermod
```
# Usermod Settings
Setting | Description | Default
--- | --- | ---
Enabled | Enable/Disable the LDR functionality. | Disabled
LDR Pin | The analog capable pin your LDR is connected to. | 34
Threshold Minutes | The number of minutes of consistent readings above/below the on/off threshold before the LED state will change. | 5
Threshold | The analog read value threshold from the LDR. Readings lower than this number will count towards changing the LED state to off. You can see the current LDR reading by going into the info section when LDR functionality is enabled. | 1000
On Preset | The WLED preset to be used for the LED on state. | 1
Off Preset | The WLED preset to be used for the LED off state. | 2
## Author
[@jeffwdh](https://github.com/jeffwdh)
jeffwdh@tarball.ca

View File

@ -0,0 +1,153 @@
#pragma once
#include "wled.h"
#ifndef ARDUINO_ARCH_ESP32
// 8266 does not support analogRead on user selectable pins
#error only ESP32 is supported by usermod LDR_DUSK_DAWN
#endif
class LDR_Dusk_Dawn_v2 : public Usermod {
private:
// Defaults
bool ldrEnabled = false;
int ldrPin = 34; //A2 on Adafruit Huzzah32
int ldrThresholdMinutes = 5; // How many minutes of readings above/below threshold until it switches LED state
int ldrThreshold = 1000; // Readings higher than this number will turn off LED.
int ldrOnPreset = 1; // Default "On" Preset
int ldrOffPreset = 2; // Default "Off" Preset
// Variables
bool initDone = false;
bool ldrEnabledPreviously = false; // Was LDR enabled for the previous check? First check is always no.
int ldrOffCount; // Number of readings above the threshold
int ldrOnCount; // Number of readings below the threshold
int ldrReading = 0; // Last LDR reading
int ldrLEDState; // Current LED on/off state
unsigned long lastMillis = 0;
static const char _name[];
public:
void setup() {
// register ldrPin
if ((ldrPin >= 0) && (digitalPinToAnalogChannel(ldrPin) >= 0)) {
if(!pinManager.allocatePin(ldrPin, false, PinOwner::UM_LDR_DUSK_DAWN)) ldrEnabled = false; // pin already in use -> disable usermod
else pinMode(ldrPin, INPUT); // alloc success -> configure pin for input
} else ldrEnabled = false; // invalid pin -> disable usermod
initDone = true;
}
void loop() {
// Only update every 10 seconds
if (millis() - lastMillis > 10000) {
if ( (ldrEnabled == true)
&& (ldrPin >= 0) && (digitalPinToAnalogChannel(ldrPin) >= 0) ) { // make sure that pin is valid for analogread()
// Default state is off
if (ldrEnabledPreviously == false) {
applyPreset(ldrOffPreset);
ldrEnabledPreviously = true;
ldrLEDState = 0;
}
// Get LDR reading and increment counter by number of seconds since last read
ldrReading = analogRead(ldrPin);
if (ldrReading <= ldrThreshold) {
ldrOnCount = ldrOnCount + 10;
ldrOffCount = 0;
} else {
ldrOffCount = ldrOffCount + 10;
ldrOnCount = 0;
}
if (ldrOnCount >= (ldrThresholdMinutes * 60)) {
ldrOnCount = 0;
// If LEDs were previously off, turn on
if (ldrLEDState == 0) {
applyPreset(ldrOnPreset);
ldrLEDState = 1;
}
}
if (ldrOffCount >= (ldrThresholdMinutes * 60)) {
ldrOffCount = 0;
// If LEDs were previously on, turn off
if (ldrLEDState == 1) {
applyPreset(ldrOffPreset);
ldrLEDState = 0;
}
}
} else {
// LDR is disabled, reset variables to default
ldrReading = 0;
ldrOnCount = 0;
ldrOffCount = 0;
ldrLEDState = 0;
ldrEnabledPreviously = false;
}
lastMillis = millis();
}
}
void addToConfig(JsonObject& root) {
JsonObject top = root.createNestedObject(FPSTR(_name));
top["Enabled"] = ldrEnabled;
top["LDR Pin"] = ldrPin;
top["Threshold Minutes"] = ldrThresholdMinutes;
top["Threshold"] = ldrThreshold;
top["On Preset"] = ldrOnPreset;
top["Off Preset"] = ldrOffPreset;
}
bool readFromConfig(JsonObject& root) {
int8_t oldLdrPin = ldrPin;
JsonObject top = root[FPSTR(_name)];
bool configComplete = !top.isNull();
configComplete &= getJsonValue(top["Enabled"], ldrEnabled);
configComplete &= getJsonValue(top["LDR Pin"], ldrPin);
configComplete &= getJsonValue(top["Threshold Minutes"], ldrThresholdMinutes);
configComplete &= getJsonValue(top["Threshold"], ldrThreshold);
configComplete &= getJsonValue(top["On Preset"], ldrOnPreset);
configComplete &= getJsonValue(top["Off Preset"], ldrOffPreset);
if (initDone && (ldrPin != oldLdrPin)) {
// pin changed - un-register previous pin, register new pin
if (oldLdrPin >= 0) pinManager.deallocatePin(oldLdrPin, PinOwner::UM_LDR_DUSK_DAWN);
setup(); // setup new pin
}
return configComplete;
}
void addToJsonInfo(JsonObject& root) {
// If "u" object does not exist yet we need to create it
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray LDR_Enabled = user.createNestedArray("LDR dusk/dawn enabled");
LDR_Enabled.add(ldrEnabled);
if (!ldrEnabled) return; // do not add more if usermod is disabled
JsonArray LDR_Reading = user.createNestedArray("LDR reading");
LDR_Reading.add(ldrReading);
JsonArray LDR_State = user.createNestedArray("LDR turned LEDs on");
LDR_State.add(bool(ldrLEDState));
// Optional debug information:
//JsonArray LDR_On_Count = user.createNestedArray("LDR on count");
//LDR_On_Count.add(ldrOnCount);
//JsonArray LDR_Off_Count = user.createNestedArray("LDR off count");
//LDR_Off_Count.add(ldrOffCount);
//bool pinValid = ((ldrPin >= 0) && (digitalPinToAnalogChannel(ldrPin) >= 0));
//if (pinManager.getPinOwner(ldrPin) != PinOwner::UM_LDR_DUSK_DAWN) pinValid = false;
//JsonArray LDR_valid = user.createNestedArray(F("LDR pin"));
//LDR_valid.add(ldrPin);
//LDR_valid.add(pinValid ? F(" OK"): F(" invalid"));
}
uint16_t getId() {
return USERMOD_ID_LDR_DUSK_DAWN;
}
};
const char LDR_Dusk_Dawn_v2::_name[] PROGMEM = "LDR_Dusk_Dawn_v2";

View File

@ -23,7 +23,7 @@ You can also use usermod's off timer instead of sensor's. In such case rotate th
## Usermod installation
**NOTE:** Usermod has been included in master branch of WLED so it can be compiled in directly just by defining `-D USERMOD_PIRSWITCH` and optionaly `-D PIR_SENSOR_PIN=16` to override default pin. You can also change the default off time by adding `-D PIR_SENSOR_OFF_SEC=30`.
**NOTE:** Usermod has been included in master branch of WLED so it can be compiled in directly just by defining `-D USERMOD_PIRSWITCH` and optionally `-D PIR_SENSOR_PIN=16` to override default pin. You can also change the default off time by adding `-D PIR_SENSOR_OFF_SEC=30`.
## API to enable/disable the PIR sensor from outside. For example from another usermod:
@ -31,7 +31,7 @@ To query or change the PIR sensor state the methods `bool PIRsensorEnabled()` an
When the PIR sensor state changes an MQTT message is broadcasted with topic `wled/deviceMAC/motion` and message `on` or `off`.
Usermod can also be configured to send just the MQTT message but not change WLED state using settings page as well as responding to motion only at night
(assuming NTP and lattitude/longitude are set to determine sunrise/sunset times).
(assuming NTP and latitude/longitude are set to determine sunrise/sunset times).
### There are two options to get access to the usermod instance:
@ -85,7 +85,7 @@ Have fun - @gegu & @blazoncek
2021-11
* Added information about dynamic configuration options
* Added option to temporary enable/disble usermod from WLED UI (Info dialog)
* Added option to temporary enable/disable usermod from WLED UI (Info dialog)
2022-11
* Added compile time option for off timer.

View File

@ -101,7 +101,7 @@ private:
/**
* Read and update PIR sensor state.
* Initilize/reset switch off timer
* Initialize/reset switch off timer
*/
bool updatePIRsensorState();

View File

@ -5,7 +5,7 @@ v2 Usermod to to control PWM fan with RPM feedback and temperature control
This usermod requires the Dallas Temperature usermod to obtain temperature information. If it's not available, the fan will run at 100% speed.
If the fan does not have _tachometer_ (RPM) output you can set the _tachometer-pin_ to -1 to disable that feature.
You can also set the thershold temperature at which fan runs at lowest speed. If the measured temperature is 3°C greater than the threshold temperature, the fan will run at 100%.
You can also set the threshold temperature at which fan runs at lowest speed. If the measured temperature is 3°C greater than the threshold temperature, the fan will run at 100%.
If the _tachometer_ is supported, the current speed (in RPM) will be displayed on the WLED Info page.
@ -22,7 +22,7 @@ This includes:
* PWM output pin (can be configured at compile time `-D PWM_PIN=xx`)
* tachometer input pin (can be configured at compile time `-D TACHO_PIN=xx`)
* sampling frequency in seconds
* threshold temperature in degees C
* threshold temperature in degrees Celsius
_NOTE:_ You may also need to tweak Dallas Temperature usermod sampling frequency to match PWM fan sampling frequency.

View File

@ -52,9 +52,15 @@ class PWMFanUsermod : public Usermod {
uint8_t tachoUpdateSec = 30;
float targetTemperature = 35.0;
uint8_t minPWMValuePct = 0;
uint8_t maxPWMValuePct = 100;
uint8_t numberOfInterrupsInOneSingleRotation = 2; // Number of interrupts ESP32 sees on tacho signal on a single fan rotation. All the fans I've seen trigger two interrups.
uint8_t pwmValuePct = 0;
// constant values
static const uint8_t _pwmMaxValue = 255;
static const uint8_t _pwmMaxStepCount = 7;
float _pwmTempStepSize = 0.5f;
// strings to reduce flash memory usage (used more than twice)
static const char _name[];
static const char _enabled[];
@ -63,6 +69,7 @@ class PWMFanUsermod : public Usermod {
static const char _temperature[];
static const char _tachoUpdateSec[];
static const char _minPWMValuePct[];
static const char _maxPWMValuePct[];
static const char _IRQperRotation[];
static const char _speed[];
static const char _lock[];
@ -156,31 +163,25 @@ class PWMFanUsermod : public Usermod {
void setFanPWMbasedOnTemperature(void) {
float temp = getActualTemperature();
float difftemp = temp - targetTemperature;
// Default to run fan at full speed.
int newPWMvalue = 255;
int pwmStep = ((100 - minPWMValuePct) * newPWMvalue) / (7*100);
int pwmMinimumValue = (minPWMValuePct * newPWMvalue) / 100;
// dividing minPercent and maxPercent into equal pwmvalue sizes
int pwmStepSize = ((maxPWMValuePct - minPWMValuePct) * _pwmMaxValue) / (_pwmMaxStepCount*100);
int pwmStep = calculatePwmStep(temp - targetTemperature);
// minimum based on full speed - not entered MaxPercent
int pwmMinimumValue = (minPWMValuePct * _pwmMaxValue) / 100;
updateFanSpeed(pwmMinimumValue + pwmStep*pwmStepSize);
}
if ((temp == NAN) || (temp <= -100.0)) {
uint8_t calculatePwmStep(float diffTemp){
if ((diffTemp == NAN) || (diffTemp <= -100.0)) {
DEBUG_PRINTLN(F("WARNING: no temperature value available. Cannot do temperature control. Will set PWM fan to 255."));
} else if (difftemp <= 0.0) {
// Temperature is below target temperature. Run fan at minimum speed.
newPWMvalue = pwmMinimumValue;
} else if (difftemp <= 0.5) {
newPWMvalue = pwmMinimumValue + pwmStep;
} else if (difftemp <= 1.0) {
newPWMvalue = pwmMinimumValue + 2*pwmStep;
} else if (difftemp <= 1.5) {
newPWMvalue = pwmMinimumValue + 3*pwmStep;
} else if (difftemp <= 2.0) {
newPWMvalue = pwmMinimumValue + 4*pwmStep;
} else if (difftemp <= 2.5) {
newPWMvalue = pwmMinimumValue + 5*pwmStep;
} else if (difftemp <= 3.0) {
newPWMvalue = pwmMinimumValue + 6*pwmStep;
return _pwmMaxStepCount;
}
updateFanSpeed(newPWMvalue);
if(diffTemp <=0){
return 0;
}
int calculatedStep = (diffTemp / _pwmTempStepSize)+1;
// anything greater than max stepcount gets max
return (uint8_t)min((int)_pwmMaxStepCount,calculatedStep);
}
public:
@ -312,6 +313,7 @@ class PWMFanUsermod : public Usermod {
top[FPSTR(_tachoUpdateSec)] = tachoUpdateSec;
top[FPSTR(_temperature)] = targetTemperature;
top[FPSTR(_minPWMValuePct)] = minPWMValuePct;
top[FPSTR(_maxPWMValuePct)] = maxPWMValuePct;
top[FPSTR(_IRQperRotation)] = numberOfInterrupsInOneSingleRotation;
DEBUG_PRINTLN(F("Autosave config saved."));
}
@ -345,6 +347,8 @@ class PWMFanUsermod : public Usermod {
targetTemperature = top[FPSTR(_temperature)] | targetTemperature;
minPWMValuePct = top[FPSTR(_minPWMValuePct)] | minPWMValuePct;
minPWMValuePct = (uint8_t) min(100,max(0,(int)minPWMValuePct)); // bounds checking
maxPWMValuePct = top[FPSTR(_maxPWMValuePct)] | maxPWMValuePct;
maxPWMValuePct = (uint8_t) min(100,max((int)minPWMValuePct,(int)maxPWMValuePct)); // bounds checking
numberOfInterrupsInOneSingleRotation = top[FPSTR(_IRQperRotation)] | numberOfInterrupsInOneSingleRotation;
numberOfInterrupsInOneSingleRotation = (uint8_t) max(1,(int)numberOfInterrupsInOneSingleRotation); // bounds checking
@ -389,6 +393,7 @@ const char PWMFanUsermod::_pwmPin[] PROGMEM = "PWM-pin";
const char PWMFanUsermod::_temperature[] PROGMEM = "target-temp-C";
const char PWMFanUsermod::_tachoUpdateSec[] PROGMEM = "tacho-update-s";
const char PWMFanUsermod::_minPWMValuePct[] PROGMEM = "min-PWM-percent";
const char PWMFanUsermod::_maxPWMValuePct[] PROGMEM = "max-PWM-percent";
const char PWMFanUsermod::_IRQperRotation[] PROGMEM = "IRQs-per-rotation";
const char PWMFanUsermod::_speed[] PROGMEM = "speed";
const char PWMFanUsermod::_lock[] PROGMEM = "lock";

View File

@ -30,7 +30,7 @@
#define USERMOD_SN_PHOTORESISTOR_RESISTOR_VALUE 10000.0f
#endif
// only report if differance grater than offset value
// only report if difference grater than offset value
#ifndef USERMOD_SN_PHOTORESISTOR_OFFSET_VALUE
#define USERMOD_SN_PHOTORESISTOR_OFFSET_VALUE 5
#endif

View File

@ -3,7 +3,7 @@
* This 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)
* bytes 2400+ are currently ununsed, but might be used for future wled features
* bytes 2400+ are currently unused, but might be used for future wled features
*/
/*
@ -144,7 +144,7 @@ void userLoop() {
// First row with Wifi name
tft.setCursor(1, 1);
tft.print(knownSsid.substring(0, tftcharwidth > 1 ? tftcharwidth - 1 : 0));
// Print `~` char to indicate that SSID is longer, than our dicplay
// Print `~` char to indicate that SSID is longer than our display
if (knownSsid.length() > tftcharwidth)
tft.print("~");

View File

@ -18,7 +18,7 @@ Copy the example `platformio_override.ini` to the root directory. This file sho
* `USERMOD_DALLASTEMPERATURE` - enables this user mod wled00/usermods_list.cpp
* `USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL` - number of milliseconds between measurements, defaults to 60000 ms (60s)
All parameters can be configured at runtime via the Usermods settings page, including pin, temperature in degrees Celsius or Farenheit and measurement interval.
All parameters can be configured at runtime via the Usermods settings page, including pin, temperature in degrees Celsius or Fahrenheit and measurement interval.
## Project link

View File

@ -34,30 +34,30 @@ uint8_t DALLAS_PIN =23;
uint8_t SCL_PIN = 5;
uint8_t SDA_PIN = 4;
uint8_t DALLAS_PIN =13;
// uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
// uint8_t RST_PIN = 16; // Un-comment for Heltec WiFi-Kit-8
#endif
//The SCL and SDA pins are defined here.
//ESP8266 Wemos D1 mini board use SCL=5 SDA=4 while ESP32 Wemos32 mini board use SCL=22 SDA=21
#define U8X8_PIN_SCL SCL_PIN
#define U8X8_PIN_SDA SDA_PIN
//#define U8X8_PIN_RESET RST_PIN // Uncoment for Heltec WiFi-Kit-8
//#define U8X8_PIN_RESET RST_PIN // Un-comment for Heltec WiFi-Kit-8
// Dallas sensor reading timer
long temptimer = millis();
long lastMeasure = 0;
#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit
#define Celsius // Show temperature measurement in Celsius otherwise is in Fahrenheit
// 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
// --> First choise of cheap I2C OLED 128X32 0.91"
// --> First choice of cheap I2C OLED 128X32 0.91"
U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
// --> Second choise of cheap I2C OLED 128X64 0.96" or 1.3"
// --> Second choice of cheap I2C OLED 128X64 0.96" or 1.3"
//U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
// --> Third choise of Heltec WiFi-Kit-8 OLED 128X32 0.91"
// --> Third choice of Heltec WiFi-Kit-8 OLED 128X32 0.91"
//U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_RESET, U8X8_PIN_SCL, U8X8_PIN_SDA); // Constructor for Heltec WiFi-Kit-8
// gets called once at boot. Do all initialization that doesn't depend on network here
void userSetup() {
@ -97,7 +97,7 @@ void userLoop() {
//----> Dallas temperature sensor MQTT publishing
temptimer = millis();
// Timer to publishe new temperature every 60 seconds
// Timer to publish new temperature every 60 seconds
if (temptimer - lastMeasure > 60000)
{
lastMeasure = temptimer;
@ -106,7 +106,7 @@ void userLoop() {
if (mqtt != nullptr)
{
// Serial.println(Dallas(DALLAS_PIN,0));
//Gets prefered temperature scale based on selection in definitions section
//Gets preferred temperature scale based on selection in definitions section
#ifdef Celsius
int16_t board_temperature = Dallas(DALLAS_PIN,0);
#else
@ -173,11 +173,11 @@ void userLoop() {
// 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
// Print `~` char to indicate that SSID is longer than our display
if (knownSsid.length() > u8x8.getCols())
u8x8.print("~");
// Second row with IP or Psssword
// Second row with IP or Password
u8x8.setCursor(1, 1);
// Print password in AP mode and if led is OFF.
if (apActive && bri == 0)

View File

@ -6,7 +6,7 @@
void UpdateBME280Data();
#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit
#define Celsius // Show temperature measurement in Celsius otherwise is in Fahrenheit
BME280I2C bme; // Default : forced mode, standby time = 1000 ms
// Oversampling = pressure ×1, temperature ×1, humidity ×1, filter off,
@ -16,25 +16,25 @@ uint8_t SDA_PIN = 21;
#else //ESP8266 boards
uint8_t SCL_PIN = 5;
uint8_t SDA_PIN = 4;
// uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
// uint8_t RST_PIN = 16; // Un-comment for Heltec WiFi-Kit-8
#endif
//The SCL and SDA pins are defined here.
//ESP8266 Wemos D1 mini board use SCL=5 SDA=4 while ESP32 Wemos32 mini board use SCL=22 SDA=21
#define U8X8_PIN_SCL SCL_PIN
#define U8X8_PIN_SDA SDA_PIN
//#define U8X8_PIN_RESET RST_PIN // Uncoment for Heltec WiFi-Kit-8
//#define U8X8_PIN_RESET RST_PIN // Un-comment for Heltec WiFi-Kit-8
// 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
// --> First choise of cheap I2C OLED 128X32 0.91"
// --> First choice of cheap I2C OLED 128X32 0.91"
U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
// --> Second choise of cheap I2C OLED 128X64 0.96" or 1.3"
// --> Second choice of cheap I2C OLED 128X64 0.96" or 1.3"
//U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
// --> Third choise of Heltec WiFi-Kit-8 OLED 128X32 0.91"
// --> Third choice of Heltec WiFi-Kit-8 OLED 128X32 0.91"
//U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_RESET, U8X8_PIN_SCL, U8X8_PIN_SDA); // Constructor for Heltec WiFi-Kit-8
// gets called once at boot. Do all initialization that doesn't depend on network here
@ -179,11 +179,11 @@ void userLoop() {
// 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
// Print `~` char to indicate that SSID is longer, than our display
if (knownSsid.length() > u8x8.getCols())
u8x8.print("~");
// Second row with IP or Psssword
// Second row with IP or Password
u8x8.setCursor(1, 1);
// Print password in AP mode and if led is OFF.
if (apActive && bri == 0)

View File

@ -77,7 +77,7 @@ static bool limiterOn = true; // bool: enable / disable dynamics
static uint16_t attackTime = 80; // int: attack time in milliseconds. Default 0.08sec
static uint16_t decayTime = 1400; // int: decay time in milliseconds. Default 1.40sec
// user settable options for FFTResult scaling
static uint8_t FFTScalingMode = 3; // 0 none; 1 optimized logarithmic; 2 optimized linear; 3 optimized sqare root
static uint8_t FFTScalingMode = 3; // 0 none; 1 optimized logarithmic; 2 optimized linear; 3 optimized square root
//
// AGC presets
@ -112,9 +112,9 @@ static float sampleAgc = 0.0f; // Smoothed AGC sample
static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay()
static uint8_t maxVol = 31; // Reasonable value for constant volume for 'peak detector', as it won't always trigger (deprecated)
static uint8_t binNum = 8; // Used to select the bin for FFT based beat detection (deprecated)
static bool udpSamplePeak = false; // Boolean flag for peak. Set at the same tiem as samplePeak, but reset by transmitAudioData
static bool udpSamplePeak = false; // Boolean flag for peak. Set at the same time as samplePeak, but reset by transmitAudioData
static unsigned long timeOfPeak = 0; // time of last sample peak detection.
static void detectSamplePeak(void); // peak detection function (needs scaled FFT reasults in vReal[])
static void detectSamplePeak(void); // peak detection function (needs scaled FFT results in vReal[])
static void autoResetPeak(void); // peak auto-reset function
@ -206,7 +206,7 @@ static float mapf(float x, float in_min, float in_max, float out_min, float out_
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
// compute average of several FFT resut bins
// compute average of several FFT result bins
static float fftAddAvg(int from, int to) {
float result = 0.0f;
for (int i = from; i <= to; i++) {
@ -324,7 +324,7 @@ void FFTcode(void * parameter)
*
* Andrew's updated mapping of 256 bins down to the 16 result bins with Sample Freq = 10240, samplesFFT = 512 and some overlap.
* Based on testing, the lowest/Start frequency is 60 Hz (with bin 3) and a highest/End frequency of 5120 Hz in bin 255.
* Now, Take the 60Hz and multiply by 1.320367784 to get the next frequency and so on until the end. Then detetermine the bins.
* Now, Take the 60Hz and multiply by 1.320367784 to get the next frequency and so on until the end. Then determine the bins.
* End frequency = Start frequency * multiplier ^ 16
* Multiplier = (End frequency/ Start frequency) ^ 1/16
* Multiplier = 1.320367784
@ -383,7 +383,7 @@ void FFTcode(void * parameter)
}
}
// post-processing of frequency channels (pink noise adjustment, AGC, smooting, scaling)
// post-processing of frequency channels (pink noise adjustment, AGC, smoothing, scaling)
postProcessFFTResults((fabsf(sampleAvg) > 0.25f)? true : false , NUM_GEQ_CHANNELS);
#if defined(WLED_DEBUG) || defined(SR_DEBUG)
@ -430,7 +430,7 @@ static void runMicFilter(uint16_t numSamples, float *sampleBuffer) // p
// FIR lowpass, to remove high frequency noise
float highFilteredSample;
if (i < (numSamples-1)) highFilteredSample = beta1*sampleBuffer[i] + beta2*last_vals[0] + beta2*sampleBuffer[i+1]; // smooth out spikes
else highFilteredSample = beta1*sampleBuffer[i] + beta2*last_vals[0] + beta2*last_vals[1]; // spcial handling for last sample in array
else highFilteredSample = beta1*sampleBuffer[i] + beta2*last_vals[0] + beta2*last_vals[1]; // special handling for last sample in array
last_vals[1] = last_vals[0];
last_vals[0] = sampleBuffer[i];
sampleBuffer[i] = highFilteredSample;
@ -627,7 +627,7 @@ class AudioReactive : public Usermod {
// variables used by getSample() and agcAvg()
int16_t micIn = 0; // Current sample starts with negative values and large values, which is why it's 16 bit signed
double sampleMax = 0.0; // Max sample over a few seconds. Needed for AGC controler.
double sampleMax = 0.0; // Max sample over a few seconds. Needed for AGC controller.
double micLev = 0.0; // Used to convert returned value to have '0' as minimum. A leveller
float expAdjF = 0.0f; // Used for exponential filter.
float sampleReal = 0.0f; // "sampleRaw" as float, to provide bits that are lost otherwise (before amplification by sampleGain or inputLevel). Needed for AGC.
@ -745,13 +745,13 @@ class AudioReactive : public Usermod {
* 2. we use two setpoints, one at ~60%, and one at ~80% of the maximum signal
* 3. the amplification depends on signal level:
* a) normal zone - very slow adjustment
* b) emergency zome (<10% or >90%) - very fast adjustment
* b) emergency zone (<10% or >90%) - very fast adjustment
*/
void agcAvg(unsigned long the_time)
{
const int AGC_preset = (soundAgc > 0)? (soundAgc-1): 0; // make sure the _compiler_ knows this value will not change while we are inside the function
float lastMultAgc = multAgc; // last muliplier used
float lastMultAgc = multAgc; // last multiplier used
float multAgcTemp = multAgc; // new multiplier
float tmpAgc = sampleReal * multAgc; // what-if amplified signal
@ -791,13 +791,13 @@ class AudioReactive : public Usermod {
if (((multAgcTemp > 0.085f) && (multAgcTemp < 6.5f)) //integrator anti-windup by clamping
&& (multAgc*sampleMax < agcZoneStop[AGC_preset])) //integrator ceiling (>140% of max)
control_integrated += control_error * 0.002 * 0.25; // 2ms = intgration time; 0.25 for damping
control_integrated += control_error * 0.002 * 0.25; // 2ms = integration time; 0.25 for damping
else
control_integrated *= 0.9; // spin down that beasty integrator
// apply PI Control
tmpAgc = sampleReal * lastMultAgc; // check "zone" of the signal using previous gain
if ((tmpAgc > agcZoneHigh[AGC_preset]) || (tmpAgc < soundSquelch + agcZoneLow[AGC_preset])) { // upper/lower emergy zone
if ((tmpAgc > agcZoneHigh[AGC_preset]) || (tmpAgc < soundSquelch + agcZoneLow[AGC_preset])) { // upper/lower energy zone
multAgcTemp = lastMultAgc + agcFollowFast[AGC_preset] * agcControlKp[AGC_preset] * control_error;
multAgcTemp += agcFollowFast[AGC_preset] * agcControlKi[AGC_preset] * control_integrated;
} else { // "normal zone"
@ -805,7 +805,7 @@ class AudioReactive : public Usermod {
multAgcTemp += agcFollowSlow[AGC_preset] * agcControlKi[AGC_preset] * control_integrated;
}
// limit amplification again - PI controler sometimes "overshoots"
// limit amplification again - PI controller sometimes "overshoots"
//multAgcTemp = constrain(multAgcTemp, 0.015625f, 32.0f); // 1/64 < multAgcTemp < 32
if (multAgcTemp > 32.0f) multAgcTemp = 32.0f;
if (multAgcTemp < 1.0f/64.0f) multAgcTemp = 1.0f/64.0f;
@ -835,7 +835,7 @@ class AudioReactive : public Usermod {
void getSample()
{
float sampleAdj; // Gain adjusted sample value
float tmpSample; // An interim sample variable used for calculatioins.
float tmpSample; // An interim sample variable used for calculations.
const float weighting = 0.2f; // Exponential filter weighting. Will be adjustable in a future release.
const int AGC_preset = (soundAgc > 0)? (soundAgc-1): 0; // make sure the _compiler_ knows this value will not change while we are inside the function
@ -1289,7 +1289,7 @@ class AudioReactive : public Usermod {
// complain when audio userloop has been delayed for long time. Currently we need userloop running between 500 and 1500 times per second.
// softhack007 disabled temporarily - avoid serial console spam with MANY leds and low FPS
//if ((userloopDelay > 65) && !disableSoundProcessing && (audioSyncEnabled == 0)) {
//DEBUG_PRINTF("[AR userLoop] hickup detected -> was inactive for last %d millis!\n", userloopDelay);
//DEBUG_PRINTF("[AR userLoop] hiccup detected -> was inactive for last %d millis!\n", userloopDelay);
//}
#endif
@ -1505,7 +1505,7 @@ class AudioReactive : public Usermod {
} else {
// Analog or I2S digital input
if (audioSource && (audioSource->isInitialized())) {
// audio source sucessfully configured
// audio source successfully configured
if (audioSource->getType() == AudioSource::Type_I2SAdc) {
infoArr.add(F("ADC analog"));
} else {

View File

@ -44,7 +44,7 @@
// benefit: analog mic inputs will be sampled contiously -> better response times and less "glitches"
// WARNING: this option WILL lock-up your device in case that any other analogRead() operation is performed;
// for example if you want to read "analog buttons"
//#define I2S_GRAB_ADC1_COMPLETELY // (experimental) continously sample analog ADC microphone. WARNING will cause analogRead() lock-up
//#define I2S_GRAB_ADC1_COMPLETELY // (experimental) continuously sample analog ADC microphone. WARNING will cause analogRead() lock-up
// data type requested from the I2S driver - currently we always use 32bit
//#define I2S_USE_16BIT_SAMPLES // (experimental) define this to request 16bit - more efficient but possibly less compatible
@ -378,7 +378,7 @@ class I2SSource : public AudioSource {
};
/* ES7243 Microphone
This is an I2S microphone that requires ininitialization over
This is an I2S microphone that requires initialization over
I2C before I2S data can be received
*/
class ES7243 : public I2SSource {
@ -429,8 +429,8 @@ public:
}
};
/* ES8388 Sound Modude
This is an I2S sound processing unit that requires ininitialization over
/* ES8388 Sound Module
This is an I2S sound processing unit that requires initialization over
I2C before I2S data can be received.
*/
class ES8388Source : public I2SSource {
@ -475,7 +475,7 @@ class ES8388Source : public I2SSource {
// The mics *and* line-in are BOTH connected to LIN2/RIN2 on the AudioKit
// so there's no way to completely eliminate the mics. It's also hella noisy.
// Line-in works OK on the AudioKit, generally speaking, as the mics really need
// amplification to be noticable in a quiet room. If you're in a very loud room,
// amplification to be noticeable in a quiet room. If you're in a very loud room,
// the mics on the AudioKit WILL pick up sound even in line-in mode.
// TL;DR: Don't use the AudioKit for anything, use the LyraT.
//

View File

@ -1,6 +1,6 @@
# Audioreactive usermod
Enabless controlling LEDs via audio input. Audio source can be a microphone or analog-in (AUX) using an appropriate adapter.
Enables controlling LEDs via audio input. Audio source can be a microphone or analog-in (AUX) using an appropriate adapter.
Supported microphones range from analog (MAX4466, MAX9814, ...) to digital (INMP441, ICS-43434, ...).
Does audio processing and provides data structure that specially written effects can use.
@ -19,7 +19,7 @@ This usermod is an evolution of [SR-WLED](https://github.com/atuline/WLED), and
## Supported MCUs
This audioreactive usermod works best on "classic ESP32" (dual core), and on ESP32-S3 which also has dual core and hardware floating point support.
It will compile succesfully for ESP32-S2 and ESP32-C3, however might not work well, as other WLED functions will become slow. Audio processing requires a lot of computing power, which can be problematic on smaller MCUs like -S2 and -C3.
It will compile successfully for ESP32-S2 and ESP32-C3, however might not work well, as other WLED functions will become slow. Audio processing requires a lot of computing power, which can be problematic on smaller MCUs like -S2 and -C3.
Analog audio is only possible on "classic" ESP32, but not on other MCUs like ESP32-S3.
@ -35,7 +35,7 @@ Customised _arduinoFFT_ library for use with this usermod can be found at https:
### using latest (develop) _arduinoFFT_ library
Alternatively, you can use the latest arduinoFFT development version.
ArduinoFFT `develop` library is slightly more accurate, and slighly faster than our customised library, however also needs additional 2kB RAM.
ArduinoFFT `develop` library is slightly more accurate, and slightly faster than our customised library, however also needs additional 2kB RAM.
* `build_flags` = `-D USERMOD_AUDIOREACTIVE` `-D UM_AUDIOREACTIVE_USE_NEW_FFT`
* `lib_deps`= `https://github.com/kosme/arduinoFFT#develop @ 1.9.2`
@ -63,7 +63,7 @@ You can use the following additional flags in your `build_flags`
* `-D SR_GAIN=x` : Default "gain" setting (60)
* `-D I2S_USE_RIGHT_CHANNEL`: Use RIGHT instead of LEFT channel (not recommended unless you strictly need this).
* `-D I2S_USE_16BIT_SAMPLES`: Use 16bit instead of 32bit for internal sample buffers. Reduces sampling quality, but frees some RAM ressources (not recommended unless you absolutely need this).
* `-D I2S_GRAB_ADC1_COMPLETELY`: Experimental: continously sample analog ADC microphone. Only effective on ESP32. WARNING this _will_ cause conflicts(lock-up) with any analogRead() call.
* `-D I2S_GRAB_ADC1_COMPLETELY`: Experimental: continuously sample analog ADC microphone. Only effective on ESP32. WARNING this _will_ cause conflicts(lock-up) with any analogRead() call.
* `-D MIC_LOGGER` : (debugging) Logs samples from the microphone to serial USB. Use with serial plotter (Arduino IDE)
* `-D SR_DEBUG` : (debugging) Additional error diagnostics and debug info on serial USB.

View File

@ -50,5 +50,5 @@ This usermod listens on `[mqttDeviceTopic]/switch/0/set` (where 0 is replaced wi
Feedback about the current state is provided at `[mqttDeviceTopic]/switch/0/state`.
### Home Assistant auto-discovery
Auto-discovery information is automatically published and you shoudn't have to do anything to register the switches in Home Assistant.
Auto-discovery information is automatically published and you shouldn't have to do anything to register the switches in Home Assistant.

View File

@ -2,7 +2,7 @@
This usermod-v2 modification allows the connection of multiple relays, each with individual delay and on/off mode.
Usermod supports PCF8574 I2C port expander to reduce GPIO use.
PCF8574 supports 8 outputs and each output corresponds to a relay in WLED (relay 0 = port 0, etc). I you are using more than 8 relays with multiple PCF8574 make sure their addresses are set conscutively (e.g. 0x20 and 0x21). You can set address of first expander in settings.
PCF8574 supports 8 outputs and each output corresponds to a relay in WLED (relay 0 = port 0, etc). I you are using more than 8 relays with multiple PCF8574 make sure their addresses are set in sequence (e.g. 0x20 and 0x21). You can set address of first expander in settings.
(**NOTE:** Will require Wire library and global I2C pins defined.)
## HTTP API

View File

@ -202,7 +202,7 @@ class MultiRelay : public Usermod {
};
// class implementetion
// class implementation
void MultiRelay::publishMqtt(int relay) {
#ifndef WLED_DISABLE_MQTT
@ -366,7 +366,7 @@ void MultiRelay::switchRelay(uint8_t relay, bool mode) {
if (relay>=MULTI_RELAY_MAX_RELAYS || _relay[relay].pin<0) return;
_relay[relay].state = mode;
if (usePcf8574 && _relay[relay].pin >= 100) {
// we need to send all ouputs at the same time
// we need to send all outputs at the same time
uint8_t state = 0;
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
if (_relay[i].pin < 100) continue;
@ -512,10 +512,10 @@ void MultiRelay::setup() {
* loop() is called continuously. Here you can check for events, read sensors, etc.
*/
void MultiRelay::loop() {
yield();
if (!enabled || strip.isUpdating()) return;
static unsigned long lastUpdate = 0;
yield();
if (!enabled || (strip.isUpdating() && millis() - lastUpdate < 100)) return;
if (millis() - lastUpdate < 100) return; // update only 10 times/s
lastUpdate = millis();

View File

@ -20,7 +20,7 @@
| `pinSourceSelect` | GPIO that is connected to SD's `SS`(source select) / `CS`(chip select) | 16 |
| `pinSourceClock` | GPIO that is connected to SD's `SCLK` (source clock) / `CLK`(clock) | 14 |
| `pinPoci` | GPIO that is connected to SD's `POCI`<sup></sup> (Peripheral-Out-Ctrl-In) / `MISO` (deprecated) | 36 |
| `pinPico` | GPIO that is connected to SD's `PICO`<sup></sup> (Peripheral-In-Ctrl-Out) / `MOSI` (deprecated) | 14 |
| `pinPico` | GPIO that is connected to SD's `PICO`<sup></sup> (Peripheral-In-Ctrl-Out) / `MOSI` (deprecated) | 15 |
| `sdEnable` | Enable to read data from the SD-card | true |
<sup></sup><sub>Following new naming convention of [OSHWA](https://www.oshwa.org/a-resolution-to-redefine-spi-signal-names/)</sub>
@ -31,4 +31,4 @@
- checks if the specified file is available on the SD card
```cpp
bool file_onSD(const char *filepath) {...}
```
```

View File

@ -17,7 +17,7 @@ The number of individual LEDs per segment. 7 segments per digit.
#### perPeriod -- ssLEDPerPeriod
The number of individual LEDs per period. A ':' (colon) has two periods.
#### startIdx -- ssStartLED
Index of the LED the display starts at. Enabless a seven segment display to be in the middle of a string.
Index of the LED the display starts at. Enables a seven segment display to be in the middle of a string.
#### timeEnable -- ssTimeEnabled
When true, when displayMask is configured for a time output and no message is set, the time will be displayed.
#### scrollSpd -- ssScrollSpeed

View File

@ -409,7 +409,7 @@ public:
if (mqttGroupTopic[0] != 0)
{
//subcribe for sevenseg messages on the group topic
//subscribe for sevenseg messages on the group topic
sprintf_P(subBuffer, PSTR("%s/%S/+/set"), mqttGroupTopic, _str_sevenSeg);
mqtt->subscribe(subBuffer, 2);
}
@ -417,7 +417,7 @@ public:
bool onMqttMessage(char *topic, char *payload)
{
//If topic beings iwth sevenSeg cut it off, otherwise not our message.
//If topic beings with sevenSeg cut it off, otherwise not our message.
size_t topicPrefixLen = strlen_P(PSTR("/sevenSeg/"));
if (strncmp_P(topic, PSTR("/sevenSeg/"), topicPrefixLen) == 0)
topic += topicPrefixLen;

View File

@ -24,6 +24,9 @@ Enables the inverted mode in which the background should be enabled and the digi
### Colon-blinking
Enables the blinking colon(s) if they are defined
### Leading-Zero
Shows the leading zero of the hour if it exists (i.e. shows `07` instead of `7`)
### enable-auto-brightness
Enables the auto brightness feature. Can be used only when the usermod SN_Photoresistor is installed.

View File

@ -17,6 +17,7 @@ private:
bool umSSDRDisplayTime = false;
bool umSSDRInverted = false;
bool umSSDRColonblink = true;
bool umSSDRLeadingZero = false;
bool umSSDREnableLDR = false;
String umSSDRHours = "";
String umSSDRMinutes = "";
@ -79,6 +80,7 @@ private:
static const char _str_timeEnabled[];
static const char _str_inverted[];
static const char _str_colonblink[];
static const char _str_leadingZero[];
static const char _str_displayMask[];
static const char _str_hours[];
static const char _str_minutes[];
@ -105,15 +107,15 @@ private:
switch (umSSDRDisplayMask[index]) {
case 'h':
timeVar = hourFormat12(localTime);
_showElements(&umSSDRHours, timeVar, 0, 1);
_showElements(&umSSDRHours, timeVar, 0, !umSSDRLeadingZero);
break;
case 'H':
timeVar = hour(localTime);
_showElements(&umSSDRHours, timeVar, 0, 1);
_showElements(&umSSDRHours, timeVar, 0, !umSSDRLeadingZero);
break;
case 'k':
timeVar = hour(localTime) + 1;
_showElements(&umSSDRHours, timeVar, 0, 0);
_showElements(&umSSDRHours, timeVar, 0, !umSSDRLeadingZero);
break;
case 'm':
timeVar = minute(localTime);
@ -309,6 +311,9 @@ private:
if (_cmpIntSetting_P(topic, payload, _str_colonblink, &umSSDRColonblink)) {
return true;
}
if (_cmpIntSetting_P(topic, payload, _str_leadingZero, &umSSDRLeadingZero)) {
return true;
}
if (strcmp_P(topic, _str_displayMask) == 0) {
umSSDRDisplayMask = String(payload);
_publishMQTTstr_P(_str_displayMask, umSSDRDisplayMask);
@ -323,6 +328,7 @@ private:
_publishMQTTint_P(_str_ldrEnabled, umSSDREnableLDR);
_publishMQTTint_P(_str_inverted, umSSDRInverted);
_publishMQTTint_P(_str_colonblink, umSSDRColonblink);
_publishMQTTint_P(_str_leadingZero, umSSDRLeadingZero);
_publishMQTTstr_P(_str_hours, umSSDRHours);
_publishMQTTstr_P(_str_minutes, umSSDRMinutes);
@ -347,6 +353,7 @@ private:
ssdrObj[FPSTR(_str_ldrEnabled)] = umSSDREnableLDR;
ssdrObj[FPSTR(_str_inverted)] = umSSDRInverted;
ssdrObj[FPSTR(_str_colonblink)] = umSSDRColonblink;
ssdrObj[FPSTR(_str_leadingZero)] = umSSDRLeadingZero;
ssdrObj[FPSTR(_str_displayMask)] = umSSDRDisplayMask;
ssdrObj[FPSTR(_str_hours)] = umSSDRHours;
ssdrObj[FPSTR(_str_minutes)] = umSSDRMinutes;
@ -425,6 +432,8 @@ public:
invert.add(umSSDRInverted);
JsonArray blink = user.createNestedArray("Blinking colon");
blink.add(umSSDRColonblink);
JsonArray zero = user.createNestedArray("Show the hour leading zero");
zero.add(umSSDRLeadingZero);
JsonArray ldrEnable = user.createNestedArray("Auto Brightness enabled");
ldrEnable.add(umSSDREnableLDR);
@ -454,6 +463,7 @@ public:
umSSDREnableLDR = ssdrObj[FPSTR(_str_ldrEnabled)] | umSSDREnableLDR;
umSSDRInverted = ssdrObj[FPSTR(_str_inverted)] | umSSDRInverted;
umSSDRColonblink = ssdrObj[FPSTR(_str_colonblink)] | umSSDRColonblink;
umSSDRLeadingZero = ssdrObj[FPSTR(_str_leadingZero)] | umSSDRLeadingZero;
umSSDRDisplayMask = ssdrObj[FPSTR(_str_displayMask)] | umSSDRDisplayMask;
}
}
@ -470,14 +480,14 @@ public:
if (mqttGroupTopic[0] != 0)
{
//subcribe for sevenseg messages on the group topic
//subscribe for sevenseg messages on the group topic
sprintf_P(subBuffer, PSTR("%s/%S/+/set"), mqttGroupTopic, _str_name);
mqtt->subscribe(subBuffer, 2);
}
}
bool onMqttMessage(char *topic, char *payload) {
//If topic beings iwth sevenSeg cut it off, otherwise not our message.
//If topic begins with sevenSeg cut it off, otherwise not our message.
size_t topicPrefixLen = strlen_P(PSTR("/wledSS/"));
if (strncmp_P(topic, PSTR("/wledSS/"), topicPrefixLen) == 0) {
topic += topicPrefixLen;
@ -516,6 +526,7 @@ public:
umSSDREnableLDR = (top[FPSTR(_str_ldrEnabled)] | umSSDREnableLDR);
umSSDRInverted = (top[FPSTR(_str_inverted)] | umSSDRInverted);
umSSDRColonblink = (top[FPSTR(_str_colonblink)] | umSSDRColonblink);
umSSDRLeadingZero = (top[FPSTR(_str_leadingZero)] | umSSDRLeadingZero);
umSSDRDisplayMask = top[FPSTR(_str_displayMask)] | umSSDRDisplayMask;
umSSDRHours = top[FPSTR(_str_hours)] | umSSDRHours;
@ -546,6 +557,7 @@ const char UsermodSSDR::_str_name[] PROGMEM = "UsermodSSDR";
const char UsermodSSDR::_str_timeEnabled[] PROGMEM = "enabled";
const char UsermodSSDR::_str_inverted[] PROGMEM = "inverted";
const char UsermodSSDR::_str_colonblink[] PROGMEM = "Colon-blinking";
const char UsermodSSDR::_str_leadingZero[] PROGMEM = "Leading-Zero";
const char UsermodSSDR::_str_displayMask[] PROGMEM = "Display-Mask";
const char UsermodSSDR::_str_hours[] PROGMEM = "LED-Numbers-Hours";
const char UsermodSSDR::_str_minutes[] PROGMEM = "LED-Numbers-Minutes";

View File

@ -290,7 +290,7 @@ void ShtUsermod::loop()
/**
* Whenever MQTT is connected, publish HA autodiscovery topics.
*
* Is only donce once.
* Is only done once.
*
* @see Usermod::onMqttConnect()
* @see UsermodManager::onMqttConnect()

View File

@ -91,7 +91,8 @@ class StairwayWipeUsermod : public Usermod {
void startWipe()
{
bri = briLast; //turn on
transitionDelayTemp = 0; //no transition
jsonTransitionOnce = true;
strip.setTransition(0); //no transition
effectCurrent = FX_MODE_COLOR_WIPE;
resetTimebase(); //make sure wipe starts from beginning
@ -105,10 +106,11 @@ class StairwayWipeUsermod : public Usermod {
void turnOff()
{
jsonTransitionOnce = true;
#ifdef STAIRCASE_WIPE_OFF
transitionDelayTemp = 0; //turn off immediately after wipe completed
strip.setTransition(0); //turn off immediately after wipe completed
#else
transitionDelayTemp = 4000; //fade out slowly
strip.setTransition(4000); //fade out slowly
#endif
bri = 0;
stateUpdated(CALL_MODE_NOTIFICATION);

View File

@ -23,7 +23,7 @@ private:
unsigned char Enc_B;
unsigned char Enc_A_prev = 0;
// private class memebers configurable by Usermod Settings (defaults set inside readFromConfig())
// private class members configurable by Usermod Settings (defaults set inside readFromConfig())
int8_t pins[3]; // pins[0] = DT from encoder, pins[1] = CLK from encoder, pins[2] = CLK from encoder (optional)
int fadeAmount; // how many points to fade the Neopixel with each step
@ -162,7 +162,7 @@ public:
* - configComplete is used to return false if any value is missing, not just if the main object is missing
* - The defaults are loaded every time readFromConfig() is run, not just once after boot
*
* This ensures that missing values are added to the config, with their default values, in the rare but plauible cases of:
* This ensures that missing values are added to the config, with their default values, in the rare but plausible cases of:
* - a single value being missing at boot, e.g. if the Usermod was upgraded and a new setting was added
* - a single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed)
*

View File

@ -101,7 +101,7 @@ class AutoSaveUsermod : public Usermod {
// network here
void setup() {
#ifdef USERMOD_FOUR_LINE_DISPLAY
// This Usermod has enhanced funcionality if
// This Usermod has enhanced functionality if
// FourLineDisplayUsermod is available.
display = (FourLineDisplayUsermod*) usermods.lookup(USERMOD_ID_FOUR_LINE_DISP);
#endif
@ -148,7 +148,7 @@ class AutoSaveUsermod : public Usermod {
if (autoSaveAfter && now > autoSaveAfter) {
autoSaveAfter = 0;
// Time to auto save. You may have some flickry?
// Time to auto save. You may have some flickery?
saveSettings();
displayOverlay();
}

View File

@ -23,7 +23,7 @@ This file should be placed in the same directory as `platformio.ini`.
* `FLD_PIN_SCL` - The display SCL pin, defaults to 5
* `FLD_PIN_SDA` - The display SDA pin, defaults to 4
All of the parameters can be configured via the Usermods settings page, inluding GPIO pins.
All of the parameters can be configured via the Usermods settings page, including GPIO pins.
### PlatformIO requirements

View File

@ -11,7 +11,7 @@
// for WLED.
//
// Dependencies
// * This usermod REQURES the ModeSortUsermod
// * This usermod REQUIRES the ModeSortUsermod
// * This Usermod works best, by far, when coupled
// with RotaryEncoderUIUsermod.
//
@ -393,7 +393,7 @@ class FourLineDisplayUsermod : public Usermod {
drawString(getCols() - 1, 0, "~");
}
// Second row with IP or Psssword
// Second row with IP or Password
drawGlyph(0, lineHeight, 68, u8x8_font_open_iconic_embedded_1x1); // wifi icon
// Print password in AP mode and if led is OFF.
if (apActive && bri == 0) {

View File

@ -6,7 +6,7 @@
#include "4LD_wled_fonts.c"
#ifndef FLD_ESP32_NO_THREADS
#define FLD_ESP32_USE_THREADS // comment out to use 0.13.x behviour without parallel update task - slower, but more robust. May delay other tasks like LEDs or audioreactive!!
#define FLD_ESP32_USE_THREADS // comment out to use 0.13.x behaviour without parallel update task - slower, but more robust. May delay other tasks like LEDs or audioreactive!!
#endif
//
@ -243,7 +243,7 @@ class FourLineDisplayUsermod : public Usermod {
*/
void setMarkLine(byte newMarkLineNum, byte newMarkColNum);
//Draw the arrow for the current setting beiong changed
//Draw the arrow for the current setting being changed
void drawArrow();
//Display the current effect or palette (desiredEntry)
@ -793,7 +793,7 @@ void FourLineDisplayUsermod::setMarkLine(byte newMarkLineNum, byte newMarkColNum
markColNum = newMarkColNum;
}
//Draw the arrow for the current setting beiong changed
//Draw the arrow for the current setting being changed
void FourLineDisplayUsermod::drawArrow() {
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
unsigned long now = millis();
@ -1066,7 +1066,7 @@ void FourLineDisplayUsermod::networkOverlay(const char* line1, long showHowLong)
bool FourLineDisplayUsermod::handleButton(uint8_t b) {
yield();
if (!enabled
|| b // butto 0 only
|| b // button 0 only
|| buttonType[b] == BTN_TYPE_SWITCH
|| buttonType[b] == BTN_TYPE_NONE
|| buttonType[b] == BTN_TYPE_RESERVED

View File

@ -10,7 +10,7 @@ curl --location --request GET 'http://[]/printer/objects/query?virtual_sdcard=pr
## Usage
Compile the source with the buildflag `-D USERMOD_KLIPPER_PERCENTAGE` added.
You can also use the WLBD bot in the Discord by simply extending an exsisting build enviroment:
You can also use the WLBD bot in the Discord by simply extending an existing build environment:
```
[env:esp32klipper]
extends = env:esp32dev
@ -23,7 +23,7 @@ build_flags = ${common.build_flags_esp32} -D USERMOD_KLIPPER_PERCENTAGE
Checkbox to enable or disable the overlay
### Klipper IP:
IP adress of your Klipper instance you want to poll. ESP has to be restarted after change
IP address of your Klipper instance you want to poll. ESP has to be restarted after change
### Direction :
0 = normal

View File

@ -79,7 +79,7 @@ public:
httpGet(wifiClient, errorMessage);
if (strcmp(errorMessage, "") == 0)
{
PSRAMDynamicJsonDocument klipperDoc(4096); // in practive about 2673
PSRAMDynamicJsonDocument klipperDoc(4096); // in practice about 2673
DeserializationError error = deserializeJson(klipperDoc, wifiClient);
if (error)
{

View File

@ -7,4 +7,4 @@ Contains a modification to use WLED in combination with the Ping Pong Ball LED C
To install this Usermod, you instruct PlatformIO to compile the Project with the USERMOD_PING_PONG_CLOCK flag.
WLED then automatically provides you with various settings on the Usermod Page.
Note: Depending on the size of your clock, you may have to update the led indices for the indivdual numbers and the base indices.
Note: Depending on the size of your clock, you may have to update the led indices for the individual numbers and the base indices.

View File

@ -18,15 +18,15 @@ private:
// ---- Variables for correct LED numbering below, edit only if your clock is built different ----
int baseH = 43; // Adress for the one place of the hours
int baseHH = 7; // Adress for the tens place of the hours
int baseM = 133; // Adress for the one place of the minutes
int baseMM = 97; // Adress for the tens place of the minutes
int colon1 = 79; // Adress for the first colon led
int colon2 = 80; // Adress for the second colon led
int baseH = 43; // Address for the one place of the hours
int baseHH = 7; // Address for the tens place of the hours
int baseM = 133; // Address for the one place of the minutes
int baseMM = 97; // Address for the tens place of the minutes
int colon1 = 79; // Address for the first colon led
int colon2 = 80; // Address for the second colon led
// Matrix for the illumination of the numbers
// Note: These only define the increments of the base adress. e.g. to define the second Minute you have to add the baseMM to every led position
// Note: These only define the increments of the base address. e.g. to define the second Minute you have to add the baseMM to every led position
const int numbers[10][10] =
{
{ 0, 1, 4, 6, 13, 15, 18, 19, -1, -1 }, // 0: null

View File

@ -20,7 +20,7 @@
// Change between modes by pressing a button.
//
// Dependencies
// * This usermod REQURES the ModeSortUsermod
// * This usermod REQUIRES the ModeSortUsermod
// * This Usermod works best coupled with
// FourLineDisplayUsermod.
//

View File

@ -4,7 +4,7 @@
//
// Inspired by the original v2 usermods
// * usermod_v2_rotaty_encoder_ui
// * usermod_v2_rotary_encoder_ui
//
// v2 usermod that provides a rotary encoder-based UI.
//
@ -99,7 +99,7 @@ static int re_qstringCmp(const void *ap, const void *bp) {
// Lowercase
bVal -= 32;
}
// Relly we shouldn't ever get to '\0'
// Really we shouldn't ever get to '\0'
if (aVal == '"' || bVal == '"' || aVal == '\0' || bVal == '\0') {
// We're done. one is a substring of the other
// or something happenend and the quote didn't stop us.
@ -596,7 +596,7 @@ void RotaryEncoderUIUsermod::loop()
bool changedState = false;
char lineBuffer[64];
do {
// finde new state
// find new state
switch (newState) {
case 0: strcpy_P(lineBuffer, PSTR("Brightness")); changedState = true; break;
case 1: if (!extractModeSlider(effectCurrent, 0, lineBuffer, 63)) newState++; else changedState = true; break; // speed

View File

@ -8,7 +8,7 @@ active: enable/disable usermod
diplayItIs: enable/disable display of "Es ist" on the clock
ledOffset: number of LEDs before the wordclock LEDs
### Update for alternatative wiring pattern
### Update for alternative wiring pattern
Based on this fantastic work I added an alternative wiring pattern.
The original used a long wire to connect DO to DI, from one line to the next line.

View File

@ -7,8 +7,8 @@
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
*
* This usermod can be used to drive a wordclock with a 11x10 pixel matrix with WLED. There are also 4 additional dots for the minutes.
* The visualisation is desribed in 4 mask with LED numbers (single dots for minutes, minutes, hours and "clock/Uhr").
* There are 2 parameters to chnage the behaviour:
* The visualisation is described in 4 mask with LED numbers (single dots for minutes, minutes, hours and "clock/Uhr").
* There are 2 parameters to change the behaviour:
*
* active: enable/disable usermod
* diplayItIs: enable/disable display of "Es ist" on the clock.

View File

@ -1,6 +1,6 @@
# Controlling Wiz lights
Enabless controlling [WiZ](https://www.wizconnected.com/en/consumer/) lights that are part of the same network as the WLED controller.
Enables controlling [WiZ](https://www.wizconnected.com/en/consumer/) lights that are part of the same network as the WLED controller.
The mod takes the colors from the first few pixels and sends them to the lights.
@ -8,7 +8,7 @@ The mod takes the colors from the first few pixels and sends them to the lights.
- Interval (ms)
- How frequently to update the WiZ lights, in milliseconds.
- Setting it too low may causse the ESP to become unresponsive.
- Setting it too low may cause the ESP to become unresponsive.
- Send Delay (ms)
- An optional millisecond delay after updating each WiZ light.
- Can help smooth out effects when using a large number of WiZ lights

View File

@ -51,7 +51,7 @@ uint16_t triwave16(uint16_t in) {
* Generates a tristate square wave w/ attac & decay
* @param x input value 0-255
* @param pulsewidth 0-127
* @param attdec attac & decay, max. pulsewidth / 2
* @param attdec attack & decay, max. pulsewidth / 2
* @returns signed waveform value
*/
int8_t tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec) {
@ -80,7 +80,7 @@ int8_t tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec) {
*/
uint16_t mode_static(void) {
SEGMENT.fill(SEGCOLOR(0));
return 350;
return strip.isOffRefreshRequired() ? FRAMETIME : 350;
}
static const char _data_FX_MODE_STATIC[] PROGMEM = "Solid";
@ -177,11 +177,11 @@ uint16_t color_wipe(bool rev, bool useRandomColors) {
SEGENV.step = 3;
}
if (SEGENV.step == 1) { //if flag set, change to new random color
SEGENV.aux1 = SEGMENT.get_random_wheel_index(SEGENV.aux0);
SEGENV.aux1 = get_random_wheel_index(SEGENV.aux0);
SEGENV.step = 2;
}
if (SEGENV.step == 3) {
SEGENV.aux0 = SEGMENT.get_random_wheel_index(SEGENV.aux1);
SEGENV.aux0 = get_random_wheel_index(SEGENV.aux1);
SEGENV.step = 0;
}
}
@ -271,7 +271,7 @@ uint16_t mode_random_color(void) {
if (it != SEGENV.step) //new color
{
SEGENV.aux1 = SEGENV.aux0;
SEGENV.aux0 = SEGMENT.get_random_wheel_index(SEGENV.aux0); //aux0 will store our random color wheel index
SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0); //aux0 will store our random color wheel index
SEGENV.step = it;
}
@ -604,22 +604,36 @@ static const char _data_FX_MODE_TWINKLE[] PROGMEM = "Twinkle@!,!;!,!;!;;m12=0";
* Dissolve function
*/
uint16_t dissolve(uint32_t color) {
uint16_t dataSize = (SEGLEN+7) >> 3; //1 bit per LED
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
if (SEGENV.call == 0) {
memset(SEGMENT.data, 0xFF, dataSize); // start by fading pixels up
SEGENV.aux0 = 1;
}
for (int j = 0; j <= SEGLEN / 15; j++) {
if (random8() <= SEGMENT.intensity) {
for (size_t times = 0; times < 10; times++) //attempt to spawn a new pixel 10 times
{
uint16_t i = random16(SEGLEN);
for (size_t times = 0; times < 10; times++) { //attempt to spawn a new pixel 10 times
unsigned i = random16(SEGLEN);
unsigned index = i >> 3;
unsigned bitNum = i & 0x07;
bool fadeUp = bitRead(SEGENV.data[index], bitNum);
if (SEGENV.aux0) { //dissolve to primary/palette
if (SEGMENT.getPixelColor(i) == SEGCOLOR(1) /*|| wa*/) {
if (fadeUp) {
if (color == SEGCOLOR(0)) {
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
} else {
SEGMENT.setPixelColor(i, color);
}
bitWrite(SEGENV.data[index], bitNum, false);
break; //only spawn 1 new pixel per frame per 50 LEDs
}
} else { //dissolve to secondary
if (SEGMENT.getPixelColor(i) != SEGCOLOR(1)) { SEGMENT.setPixelColor(i, SEGCOLOR(1)); break; }
if (!fadeUp) {
SEGMENT.setPixelColor(i, SEGCOLOR(1)); break;
bitWrite(SEGENV.data[index], bitNum, true);
}
}
}
}
@ -628,6 +642,7 @@ uint16_t dissolve(uint32_t color) {
if (SEGENV.step > (255 - SEGMENT.speed) + 15U) {
SEGENV.aux0 = !SEGENV.aux0;
SEGENV.step = 0;
memset(SEGMENT.data, (SEGENV.aux0 ? 0xFF : 0), dataSize); // switch fading
} else {
SEGENV.step++;
}
@ -816,7 +831,7 @@ uint16_t chase(uint32_t color1, uint32_t color2, uint32_t color3, bool do_palett
if (a < SEGENV.step) //we hit the start again, choose new color for Chase random
{
SEGENV.aux1 = SEGENV.aux0; //store previous random color
SEGENV.aux0 = SEGMENT.get_random_wheel_index(SEGENV.aux0);
SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0);
}
color1 = SEGMENT.color_wheel(SEGENV.aux0);
}
@ -1056,7 +1071,7 @@ uint16_t mode_chase_flash_random(void) {
SEGENV.aux1 = (SEGENV.aux1 + 1) % SEGLEN;
if (SEGENV.aux1 == 0) {
SEGENV.aux0 = SEGMENT.get_random_wheel_index(SEGENV.aux0);
SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0);
}
}
return delay;
@ -1224,7 +1239,7 @@ uint16_t mode_fireworks() {
if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, col);
else SEGMENT.setPixelColor(index, col);
SEGENV.aux1 = SEGENV.aux0; // old spark
SEGENV.aux0 = index; // remember where spark occured
SEGENV.aux0 = index; // remember where spark occurred
}
}
return FRAMETIME;
@ -1257,8 +1272,8 @@ uint16_t mode_rain() {
SEGENV.aux0++; // increase spark index
SEGENV.aux1++;
}
if (SEGENV.aux0 == 0) SEGENV.aux0 = UINT16_MAX; // reset previous spark positiom
if (SEGENV.aux1 == 0) SEGENV.aux0 = UINT16_MAX; // reset previous spark positiom
if (SEGENV.aux0 == 0) SEGENV.aux0 = UINT16_MAX; // reset previous spark position
if (SEGENV.aux1 == 0) SEGENV.aux0 = UINT16_MAX; // reset previous spark position
if (SEGENV.aux0 >= width*height) SEGENV.aux0 = 0; // ignore
if (SEGENV.aux1 >= width*height) SEGENV.aux1 = 0;
}
@ -2590,14 +2605,14 @@ uint16_t mode_twinklefox()
{
return twinklefox_base(false);
}
static const char _data_FX_MODE_TWINKLEFOX[] PROGMEM = "Twinklefox@!,Twinkle rate,,,,Cool;;!";
static const char _data_FX_MODE_TWINKLEFOX[] PROGMEM = "Twinklefox@!,Twinkle rate,,,,Cool;!,!;!";
uint16_t mode_twinklecat()
{
return twinklefox_base(true);
}
static const char _data_FX_MODE_TWINKLECAT[] PROGMEM = "Twinklecat@!,Twinkle rate,,,,Cool;;!";
static const char _data_FX_MODE_TWINKLECAT[] PROGMEM = "Twinklecat@!,Twinkle rate,,,,Cool;!,!;!";
//inspired by https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectBlinkingHalloweenEyes
@ -3586,7 +3601,7 @@ uint16_t mode_tetrix(void) {
}
if (drop->step == 0) { // init brick
// speed calcualtion: a single brick should reach bottom of strip in X seconds
// speed calculation: a single brick should reach bottom of strip in X seconds
// if the speed is set to 1 this should take 5s and at 255 it should take 0.25s
// as this is dependant on SEGLEN it should be taken into account and the fact that effect runs every FRAMETIME s
int speed = SEGMENT.speed ? SEGMENT.speed : random8(1,255);
@ -3669,7 +3684,7 @@ static const char _data_FX_MODE_PLASMA[] PROGMEM = "Plasma@Phase,!;!;!";
/*
* Percentage display
* Intesity values from 0-100 turn on the leds.
* Intensity values from 0-100 turn on the leds.
*/
uint16_t mode_percent(void) {
@ -3722,7 +3737,7 @@ static const char _data_FX_MODE_PERCENT[] PROGMEM = "Percent@,% of fill,,,,One c
/*
* Modulates the brightness similar to a heartbeat
* (unimplemented?) tries to draw an ECG aproximation on a 2D matrix
* (unimplemented?) tries to draw an ECG approximation on a 2D matrix
*/
uint16_t mode_heartbeat(void) {
uint8_t bpm = 40 + (SEGMENT.speed >> 3);
@ -4400,7 +4415,7 @@ uint16_t mode_tv_simulator(void) {
// how much time is elapsed ?
tvSimulator->elapsed = millis() - tvSimulator->startTime;
// fade from prev volor to next color
// fade from prev color to next color
if (tvSimulator->elapsed < tvSimulator->fadeTime) {
r = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pr, nr);
g = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pg, ng);
@ -5946,6 +5961,8 @@ uint16_t mode_2Dscrollingtext(void) {
else if (!strncmp_P(text,PSTR("#MMDD"),5)) sprintf_P(text, zero?PSTR("%02d/%02d") :PSTR("%d/%d"), month(localTime), day(localTime));
else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, zero?PSTR("%02d:%02d%s") :PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec);
else if (!strncmp_P(text,PSTR("#HHMM"),5)) sprintf_P(text, zero?PSTR("%02d:%02d") :PSTR("%d:%02d"), AmPmHour, minute(localTime));
else if (!strncmp_P(text,PSTR("#HH"),3)) sprintf_P(text, zero?PSTR("%02d") :PSTR("%d"), AmPmHour);
else if (!strncmp_P(text,PSTR("#MM"),3)) sprintf_P(text, zero?PSTR("%02d") :PSTR("%d"), minute(localTime));
}
const int numberOfLetters = strlen(text);
@ -6266,7 +6283,7 @@ uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline.
SEGMENT.fade_out(251); // 30%
float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f;
segmentSampleAvg *= 0.125; // divide by 8, to compensate for later "sensitivty" upscaling
segmentSampleAvg *= 0.125; // divide by 8, to compensate for later "sensitivity" upscaling
float mySampleAvg = mapf(segmentSampleAvg*2.0, 0, 32, 0, (float)SEGLEN/2.0f); // map to pixels available in current segment
uint16_t tempsamp = constrain(mySampleAvg, 0, SEGLEN/2); // Keep the sample from overflowing.
@ -6318,7 +6335,7 @@ uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew
SEGMENT.fade_out(253); // 50%
float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f;
segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivty" upscaling
segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivity" upscaling
float mySampleAvg = mapf(segmentSampleAvg*2.0, 0.0f, 32.0f, 0.0f, (float)SEGLEN/2.0f); // map to pixels availeable in current segment
int tempsamp = constrain(mySampleAvg, 0, SEGLEN/2); // Keep the sample from overflowing.
@ -6367,7 +6384,7 @@ uint16_t mode_gravimeter(void) { // Gravmeter. By Andrew Tuline.
SEGMENT.fade_out(249); // 25%
float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0;
segmentSampleAvg *= 0.25; // divide by 4, to compensate for later "sensitivty" upscaling
segmentSampleAvg *= 0.25; // divide by 4, to compensate for later "sensitivity" upscaling
float mySampleAvg = mapf(segmentSampleAvg*2.0, 0, 64, 0, (SEGLEN-1)); // map to pixels availeable in current segment
int tempsamp = constrain(mySampleAvg,0,SEGLEN-1); // Keep the sample from overflowing.
@ -6467,7 +6484,7 @@ uint16_t mode_midnoise(void) { // Midnoise. By Andrew Tuline.
SEGMENT.fade_out(SEGMENT.speed);
float tmpSound2 = volumeSmth * (float)SEGMENT.intensity / 256.0; // Too sensitive.
tmpSound2 *= (float)SEGMENT.intensity / 128.0; // Reduce sensitity/length.
tmpSound2 *= (float)SEGMENT.intensity / 128.0; // Reduce sensitivity/length.
int maxLen = mapf(tmpSound2, 0, 127, 0, SEGLEN/2);
if (maxLen >SEGLEN/2) maxLen = SEGLEN/2;
@ -6878,7 +6895,7 @@ uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Plesch
if (FFT_MajorPeak > MAX_FREQUENCY) FFT_MajorPeak = 1;
// MajorPeak holds the freq. value which is most abundant in the last sample.
// With our sampling rate of 10240Hz we have a usable freq range from roughtly 80Hz to 10240/2 Hz
// With our sampling rate of 10240Hz we have a usable freq range from roughly 80Hz to 10240/2 Hz
// we will treat everything with less than 65Hz as 0
if (FFT_MajorPeak < 80) {
@ -6899,7 +6916,7 @@ uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Plesch
return FRAMETIME;
} // mode_freqmatrix()
static const char _data_FX_MODE_FREQMATRIX[] PROGMEM = "Freqmatrix@Speed,Sound effect,Low bin,High bin,Sensivity;;;1f;m12=3,si=0"; // Corner, Beatsin
static const char _data_FX_MODE_FREQMATRIX[] PROGMEM = "Freqmatrix@Speed,Sound effect,Low bin,High bin,Sensitivity;;;1f;m12=3,si=0"; // Corner, Beatsin
//////////////////////
@ -6983,7 +7000,7 @@ uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschun
if (FFT_MajorPeak > MAX_FREQUENCY) FFT_MajorPeak = 1.0f;
// MajorPeak holds the freq. value which is most abundant in the last sample.
// With our sampling rate of 10240Hz we have a usable freq range from roughtly 80Hz to 10240/2 Hz
// With our sampling rate of 10240Hz we have a usable freq range from roughly 80Hz to 10240/2 Hz
// we will treat everything with less than 65Hz as 0
if (FFT_MajorPeak < 80) {
@ -7030,7 +7047,7 @@ uint16_t mode_gravfreq(void) { // Gravfreq. By Andrew Tuline.
SEGMENT.fade_out(250);
float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f;
segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivty" upscaling
segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivity" upscaling
float mySampleAvg = mapf(segmentSampleAvg*2.0f, 0,32, 0, (float)SEGLEN/2.0f); // map to pixels availeable in current segment
int tempsamp = constrain(mySampleAvg,0,SEGLEN/2); // Keep the sample from overflowing.
@ -7058,7 +7075,7 @@ uint16_t mode_gravfreq(void) { // Gravfreq. By Andrew Tuline.
return FRAMETIME;
} // mode_gravfreq()
static const char _data_FX_MODE_GRAVFREQ[] PROGMEM = "Gravfreq@Rate of fall,Sensivity;!,!;!;1f;ix=128,m12=0,si=0"; // Pixels, Beatsin
static const char _data_FX_MODE_GRAVFREQ[] PROGMEM = "Gravfreq@Rate of fall,Sensitivity;!,!;!;1f;ix=128,m12=0,si=0"; // Pixels, Beatsin
//////////////////////
@ -7650,7 +7667,7 @@ static const char _data_FX_MODE_2DWAVINGCELL[] PROGMEM = "Waving Cell@!,,Amplitu
static const char _data_RESERVED[] PROGMEM = "RSVD";
// add (or replace reserved) effect mode and data into vector
// use id==255 to find unallocatd gaps (with "Reserved" data string)
// use id==255 to find unallocated gaps (with "Reserved" data string)
// if vector size() is smaller than id (single) data is appended at the end (regardless of id)
void WS2812FX::addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name) {
if (id == 255) { // find empty slot

View File

@ -109,20 +109,15 @@
#define PINK (uint32_t)0xFF1493
#define ULTRAWHITE (uint32_t)0xFFFFFFFF
#define DARKSLATEGRAY (uint32_t)0x2F4F4F
#define DARKSLATEGREY (uint32_t)0x2F4F4F
#define DARKSLATEGREY DARKSLATEGRAY
// options
// bit 7: segment is in transition mode
// bits 4-6: TBD
// bit 3: mirror effect within segment
// bit 2: segment is on
// bit 1: reverse segment
// bit 0: segment is selected
// segment options
#define NO_OPTIONS (uint16_t)0x0000
#define TRANSPOSED (uint16_t)0x0400 // rotated 90deg & reversed
#define REVERSE_Y_2D (uint16_t)0x0200
#define MIRROR_Y_2D (uint16_t)0x0100
#define TRANSITIONAL (uint16_t)0x0080
#define TRANSPOSED (uint16_t)0x0100 // rotated 90deg & reversed
#define MIRROR_Y_2D (uint16_t)0x0080
#define REVERSE_Y_2D (uint16_t)0x0040
#define RESET_REQ (uint16_t)0x0020
#define FROZEN (uint16_t)0x0010
#define MIRROR (uint16_t)0x0008
#define SEGMENT_ON (uint16_t)0x0004
#define REVERSE (uint16_t)0x0002
@ -348,12 +343,11 @@ typedef struct Segment {
bool mirror : 1; // 3 : mirrored
bool freeze : 1; // 4 : paused/frozen
bool reset : 1; // 5 : indicates that Segment runtime requires reset
bool transitional: 1; // 6 : transitional (there is transition occuring)
bool reverse_y : 1; // 7 : reversed Y (2D)
bool mirror_y : 1; // 8 : mirrored Y (2D)
bool transpose : 1; // 9 : transposed (2D, swapped X & Y)
uint8_t map1D2D : 3; // 10-12 : mapping for 1D effect on 2D (0-use as strip, 1-expand vertically, 2-circular/arc, 3-rectangular/corner, ...)
uint8_t soundSim : 1; // 13 : 0-1 sound simulation types ("soft" & "hard" or "on"/"off")
bool reverse_y : 1; // 6 : reversed Y (2D)
bool mirror_y : 1; // 7 : mirrored Y (2D)
bool transpose : 1; // 8 : transposed (2D, swapped X & Y)
uint8_t map1D2D : 3; // 9-11 : mapping for 1D effect on 2D (0-use as strip, 1-expand vertically, 2-circular/arc, 3-rectangular/corner, ...)
uint8_t soundSim : 2; // 12-13 : 0-3 sound simulation types ("soft" & "hard" or "on"/"off")
uint8_t set : 2; // 14-15 : 0-3 UI segment sets/groups
};
};
@ -438,7 +432,7 @@ typedef struct Segment {
uint8_t _briT; // temporary brightness
uint8_t _cctT; // temporary CCT
CRGBPalette16 _palT; // temporary palette
uint8_t _prevPaletteBlends; // number of previous palette blends (there are max 255 belnds possible)
uint8_t _prevPaletteBlends; // number of previous palette blends (there are max 255 blends possible)
unsigned long _start; // must accommodate millis()
uint16_t _dur;
Transition(uint16_t dur=750)
@ -484,7 +478,6 @@ typedef struct Segment {
_dataLen(0),
_t(nullptr)
{
//refreshLightCapabilities();
#ifdef WLED_DEBUG
//Serial.printf("-- Creating segment: %p\n", this);
#endif
@ -519,6 +512,7 @@ typedef struct Segment {
inline bool getOption(uint8_t n) const { return ((options >> n) & 0x01); }
inline bool isSelected(void) const { return selected; }
inline bool isInTransition(void) const { return _t != nullptr; }
inline bool isActive(void) const { return stop > start; }
inline bool is2D(void) const { return (width()>1 && height()>1); }
inline bool hasRGB(void) const { return _isRGB; }
@ -569,15 +563,16 @@ typedef struct Segment {
void restoreSegenv(tmpsegd_t &tmpSegD);
#endif
uint16_t progress(void); //transition progression between 0-65535
uint8_t currentBri(uint8_t briNew, bool useCct = false);
uint8_t currentMode(uint8_t modeNew);
uint32_t currentColor(uint8_t slot, uint32_t colorNew);
uint8_t currentBri(bool useCct = false);
uint8_t currentMode(void);
uint32_t currentColor(uint8_t slot);
CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal);
CRGBPalette16 &currentPalette(CRGBPalette16 &tgt, uint8_t paletteID);
// 1D strip
uint16_t virtualLength(void) const;
void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color
void setPixelColor(unsigned n, uint32_t c) { setPixelColor(int(n), c); }
void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } // automatically inline
void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } // automatically inline
void setPixelColor(float i, uint32_t c, bool aa = true);
@ -595,7 +590,6 @@ typedef struct Segment {
void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(n, RGBW32(r,g,b,w), fast); } // automatically inline
void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); } // automatically inline
void fadePixelColor(uint16_t n, uint8_t fade);
uint8_t get_random_wheel_index(uint8_t pos);
uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255);
uint32_t color_wheel(uint8_t pos);
@ -606,6 +600,7 @@ typedef struct Segment {
#ifndef WLED_DISABLE_2D
uint16_t XY(uint16_t x, uint16_t y); // support function to get relative index within segment
void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color
void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); }
void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } // automatically inline
void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } // automatically inline
void setPixelColorXY(float x, float y, uint32_t c, bool aa = true);
@ -881,16 +876,14 @@ class WS2812FX { // 96 bytes
std::vector<Panel> panel;
#endif
void
setUpMatrix(),
setPixelColorXY(int x, int y, uint32_t c);
void setUpMatrix();
// outsmart the compiler :) by correctly overloading
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } // automatically inline
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(y * Segment::maxWidth + x, c); }
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); }
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
uint32_t
getPixelColorXY(uint16_t, uint16_t);
inline uint32_t getPixelColorXY(uint16_t x, uint16_t y) { return getPixelColor(isMatrix ? y * Segment::maxWidth + x : x);}
// end 2D support

View File

@ -134,7 +134,7 @@ void WS2812FX::setUpMatrix() {
#ifdef WLED_DEBUG
DEBUG_PRINT(F("Matrix ledmap:"));
for (uint16_t i=0; i<customMappingSize; i++) {
for (unsigned i=0; i<customMappingSize; i++) {
if (!(i%Segment::maxWidth)) DEBUG_PRINTLN();
DEBUG_PRINTF("%4d,", customMappingTable[i]);
}
@ -155,31 +155,6 @@ void WS2812FX::setUpMatrix() {
#endif
}
// absolute matrix version of setPixelColor()
void /*IRAM_ATTR*/ WS2812FX::setPixelColorXY(int x, int y, uint32_t col)
{
#ifndef WLED_DISABLE_2D
if (!isMatrix) return; // not a matrix set-up
uint16_t index = y * Segment::maxWidth + x;
#else
uint16_t index = x;
#endif
if (index < customMappingSize) index = customMappingTable[index];
if (index >= _length) return;
busses.setPixelColor(index, col);
}
// returns RGBW values of pixel
uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) {
#ifndef WLED_DISABLE_2D
uint16_t index = (y * Segment::maxWidth + x);
#else
uint16_t index = x;
#endif
if (index < customMappingSize) index = customMappingTable[index];
if (index >= _length) return 0;
return busses.getPixelColor(index);
}
///////////////////////////////////////////////////////////
// Segment:: routines
@ -188,18 +163,19 @@ uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) {
#ifndef WLED_DISABLE_2D
// XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element)
uint16_t /*IRAM_ATTR*/ Segment::XY(uint16_t x, uint16_t y) {
uint16_t IRAM_ATTR Segment::XY(uint16_t x, uint16_t y)
{
uint16_t width = virtualWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
uint16_t height = virtualHeight(); // segment height in logical pixels (is always >= 1)
return isActive() ? (x%width) + (y%height) * width : 0;
}
void /*IRAM_ATTR*/ Segment::setPixelColorXY(int x, int y, uint32_t col)
void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col)
{
if (!isActive()) return; // not active
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
uint8_t _bri_t = currentBri(on ? opacity : 0);
uint8_t _bri_t = currentBri();
if (_bri_t < 255) {
byte r = scale8(R(col), _bri_t);
byte g = scale8(G(col), _bri_t);
@ -310,32 +286,17 @@ void Segment::blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t
void Segment::addPixelColorXY(int x, int y, uint32_t color, bool fast) {
if (!isActive()) return; // not active
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
uint32_t col = getPixelColorXY(x,y);
uint8_t r = R(col);
uint8_t g = G(col);
uint8_t b = B(col);
uint8_t w = W(col);
if (fast) {
r = qadd8(r, R(color));
g = qadd8(g, G(color));
b = qadd8(b, B(color));
w = qadd8(w, W(color));
col = RGBW32(r,g,b,w);
} else {
col = color_add(col, color);
}
setPixelColorXY(x, y, col);
setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color, fast));
}
void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) {
if (!isActive()) return; // not active
CRGB pix = CRGB(getPixelColorXY(x,y)).nscale8_video(fade);
setPixelColorXY(x, y, pix);
setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true));
}
// blurRow: perform a blur on a row of a rectangular matrix
void Segment::blurRow(uint16_t row, fract8 blur_amount) {
if (!isActive()) return; // not active
if (!isActive() || blur_amount == 0) return; // not active
const uint_fast16_t cols = virtualWidth();
const uint_fast16_t rows = virtualHeight();
@ -344,7 +305,7 @@ void Segment::blurRow(uint16_t row, fract8 blur_amount) {
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
CRGB carryover = CRGB::Black;
for (uint_fast16_t x = 0; x < cols; x++) {
for (unsigned x = 0; x < cols; x++) {
CRGB cur = getPixelColorXY(x, row);
CRGB before = cur; // remember color before blur
CRGB part = cur;
@ -363,7 +324,7 @@ void Segment::blurRow(uint16_t row, fract8 blur_amount) {
// blurCol: perform a blur on a column of a rectangular matrix
void Segment::blurCol(uint16_t col, fract8 blur_amount) {
if (!isActive()) return; // not active
if (!isActive() || blur_amount == 0) return; // not active
const uint_fast16_t cols = virtualWidth();
const uint_fast16_t rows = virtualHeight();
@ -372,7 +333,7 @@ void Segment::blurCol(uint16_t col, fract8 blur_amount) {
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
CRGB carryover = CRGB::Black;
for (uint_fast16_t y = 0; y < rows; y++) {
for (unsigned y = 0; y < rows; y++) {
CRGB cur = getPixelColorXY(col, y);
CRGB part = cur;
CRGB before = cur; // remember color before blur
@ -391,7 +352,7 @@ void Segment::blurCol(uint16_t col, fract8 blur_amount) {
// 1D Box blur (with added weight - blur_amount: [0=no blur, 255=max blur])
void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
if (!isActive()) return; // not active
if (!isActive() || blur_amount == 0) return; // not active
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
const uint16_t dim1 = vertical ? rows : cols;
@ -401,7 +362,7 @@ void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
const float keep = 3.f - 2.f*seep;
// 1D box blur
CRGB tmp[dim1];
for (uint16_t j = 0; j < dim1; j++) {
for (int j = 0; j < dim1; j++) {
uint16_t x = vertical ? i : j;
uint16_t y = vertical ? j : i;
int16_t xp = vertical ? x : x-1; // "signed" to prevent underflow
@ -417,7 +378,7 @@ void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
b = (curr.b*keep + (prev.b + next.b)*seep) / 3;
tmp[j] = CRGB(r,g,b);
}
for (uint16_t j = 0; j < dim1; j++) {
for (int j = 0; j < dim1; j++) {
uint16_t x = vertical ? i : j;
uint16_t y = vertical ? j : i;
setPixelColorXY(x, y, tmp[j]);
@ -440,7 +401,7 @@ void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
void Segment::blur1d(fract8 blur_amount) {
const uint16_t rows = virtualHeight();
for (uint16_t y = 0; y < rows; y++) blurRow(y, blur_amount);
for (unsigned y = 0; y < rows; y++) blurRow(y, blur_amount);
}
void Segment::moveX(int8_t delta, bool wrap) {
@ -498,7 +459,7 @@ void Segment::move(uint8_t dir, uint8_t delta, bool wrap) {
}
void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
if (!isActive()) return; // not active
if (!isActive() || radius == 0) return; // not active
// Bresenhams Algorithm
int d = 3 - (2*radius);
int y = radius, x = 0;
@ -523,7 +484,7 @@ void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
// by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs
void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
if (!isActive()) return; // not active
if (!isActive() || radius == 0) return; // not active
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
for (int16_t y = -radius; y <= radius; y++) {
@ -540,7 +501,7 @@ void Segment::nscale8(uint8_t scale) {
if (!isActive()) return; // not active
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
for(uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
setPixelColorXY(x, y, CRGB(getPixelColorXY(x, y)).nscale8(scale));
}
}

View File

@ -89,25 +89,19 @@ bool Segment::_modeBlend = false;
Segment::Segment(const Segment &orig) {
//DEBUG_PRINTF("-- Copy segment constructor: %p -> %p\n", &orig, this);
memcpy((void*)this, (void*)&orig, sizeof(Segment));
transitional = false; // copied segment cannot be in transition
name = nullptr;
data = nullptr;
_dataLen = 0;
_t = nullptr;
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); }
if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); }
//if (orig._t) { _t = new Transition(orig._t->_dur); }
_t = nullptr; // copied segment cannot be in transition
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } else { name = nullptr; }
if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); } else { data = nullptr; _dataLen = 0; }
}
// move constructor
Segment::Segment(Segment &&orig) noexcept {
//DEBUG_PRINTF("-- Move segment constructor: %p -> %p\n", &orig, this);
memcpy((void*)this, (void*)&orig, sizeof(Segment));
orig.transitional = false; // old segment cannot be in transition any more
orig.name = nullptr;
orig.data = nullptr;
orig._dataLen = 0;
orig._t = nullptr;
orig._t = nullptr; // old segment cannot be in transition any more
}
// copy assignment
@ -115,27 +109,23 @@ Segment& Segment::operator= (const Segment &orig) {
//DEBUG_PRINTF("-- Copying segment: %p -> %p\n", &orig, this);
if (this != &orig) {
// clean destination
transitional = false; // copied segment cannot be in transition
if (name) delete[] name;
if (name) { delete[] name; name = nullptr; }
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); }
if (_t) {
#ifndef WLED_DISABLE_MODE_BLEND
if (_t->_segT._dataT) free(_t->_segT._dataT);
#endif
delete _t;
_t = nullptr; // copied segment cannot be in transition
}
deallocateData();
// copy source
memcpy((void*)this, (void*)&orig, sizeof(Segment));
transitional = false;
// erase pointers to allocated data
name = nullptr;
data = nullptr;
_dataLen = 0;
_t = nullptr;
// copy source data
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); }
if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); }
//if (orig._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); }
}
return *this;
}
@ -144,9 +134,7 @@ Segment& Segment::operator= (const Segment &orig) {
Segment& Segment::operator= (Segment &&orig) noexcept {
//DEBUG_PRINTF("-- Moving segment: %p -> %p\n", &orig, this);
if (this != &orig) {
transitional = false; // just temporary
if (name) { delete[] name; name = nullptr; } // free old name
deallocateData(); // free old runtime data
if (_t) {
#ifndef WLED_DISABLE_MODE_BLEND
if (_t->_segT._dataT) free(_t->_segT._dataT);
@ -154,12 +142,12 @@ Segment& Segment::operator= (Segment &&orig) noexcept {
delete _t;
_t = nullptr;
}
deallocateData(); // free old runtime data
memcpy((void*)this, (void*)&orig, sizeof(Segment));
orig.transitional = false; // old segment cannot be in transition
orig.name = nullptr;
orig.data = nullptr;
orig._dataLen = 0;
orig._t = nullptr;
orig._t = nullptr; // old segment cannot be in transition
}
return *this;
}
@ -237,7 +225,7 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
switch (pal) {
case 0: //default palette. Exceptions for specific effects above
targetPalette = PartyColors_p; break;
case 1: {//periodically replace palette with a random one. Transition palette change in 500ms
case 1: {//periodically replace palette with a random one
unsigned long timeSinceLastChange = millis() - _lastPaletteChange;
if (timeSinceLastChange > randomPaletteChangeTime * 1000U) {
_randomPalette = _newRandomPalette;
@ -263,7 +251,7 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
CRGB sec = gamma32(colors[1]);
CRGB ter = gamma32(colors[2]);
targetPalette = CRGBPalette16(ter,sec,prim); break;}
case 5: {//primary + secondary (+tert if not off), more distinct
case 5: {//primary + secondary (+tertiary if not off), more distinct
CRGB prim = gamma32(colors[0]);
CRGB sec = gamma32(colors[1]);
if (colors[2]) {
@ -301,47 +289,45 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
}
void Segment::startTransition(uint16_t dur) {
if (!dur) {
if (_t) _t->_dur = dur; // this will stop transition in next handleTransisiton()
else transitional = false;
if (dur == 0) {
if (isInTransition()) _t->_dur = dur; // this will stop transition in next handleTransition()
return;
}
if (transitional && _t) return; // already in transition no need to store anything
if (isInTransition()) return; // already in transition no need to store anything
// starting a transition has to occur before change so we get current values 1st
_t = new Transition(dur); // no previous transition running
if (!_t) return; // failed to allocate data
//DEBUG_PRINTF("-- Started transition: %p\n", this);
CRGBPalette16 _palT = CRGBPalette16(DEFAULT_COLOR); loadPalette(_palT, palette);
_t->_palT = _palT;
loadPalette(_t->_palT, palette);
_t->_briT = on ? opacity : 0;
_t->_cctT = cct;
#ifndef WLED_DISABLE_MODE_BLEND
swapSegenv(_t->_segT);
_t->_modeT = mode;
_t->_segT._optionsT |= 0b0000000001000000; // mark old segment transitional
_t->_segT._dataLenT = 0;
_t->_segT._dataT = nullptr;
if (_dataLen > 0 && data) {
_t->_segT._dataT = (byte *)malloc(_dataLen);
if (_t->_segT._dataT) {
//DEBUG_PRINTF("-- Allocated duplicate data (%d): %p\n", _dataLen, _t->_segT._dataT);
memcpy(_t->_segT._dataT, data, _dataLen);
_t->_segT._dataLenT = _dataLen;
if (modeBlending) {
swapSegenv(_t->_segT);
_t->_modeT = mode;
_t->_segT._dataLenT = 0;
_t->_segT._dataT = nullptr;
if (_dataLen > 0 && data) {
_t->_segT._dataT = (byte *)malloc(_dataLen);
if (_t->_segT._dataT) {
//DEBUG_PRINTF("-- Allocated duplicate data (%d): %p\n", _dataLen, _t->_segT._dataT);
memcpy(_t->_segT._dataT, data, _dataLen);
_t->_segT._dataLenT = _dataLen;
}
}
} else {
for (size_t i=0; i<NUM_COLORS; i++) _t->_segT._colorT[i] = colors[i];
}
#else
for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = colors[i];
#endif
transitional = true; // setOption(SEG_OPTION_TRANSITIONAL, true);
}
void Segment::stopTransition() {
if (!transitional) return;
transitional = false; // finish transitioning segment
//DEBUG_PRINTF("-- Stopping transition: %p\n", this);
if (_t) {
if (isInTransition()) {
#ifndef WLED_DISABLE_MODE_BLEND
if (_t->_segT._dataT && _t->_segT._dataLenT > 0) {
//DEBUG_PRINTF("-- Released duplicate data (%d): %p\n", _t->_segT._dataLenT, _t->_segT._dataT);
@ -356,14 +342,13 @@ void Segment::stopTransition() {
}
void Segment::handleTransition() {
if (!transitional) return;
uint16_t _progress = progress();
if (_progress == 0xFFFFU) stopTransition();
}
// transition progression between 0-65535
uint16_t Segment::progress() {
if (transitional && _t) {
if (isInTransition()) {
unsigned long timeNow = millis();
if (_t->_dur > 0 && timeNow - _t->_start < _t->_dur) return (timeNow - _t->_start) * 0xFFFFU / _t->_dur;
}
@ -420,8 +405,8 @@ void Segment::restoreSegenv(tmpsegd_t &tmpSeg) {
_t->_segT._stepT = step;
_t->_segT._callT = call;
//if (_t->_segT._dataT != data) DEBUG_PRINTF("--- data re-allocated: (%p) %p -> %p\n", this, _t->_segT._dataT, data);
_t->_segT._dataT = data; // sometimes memory gets re-allocated (!! INVESTIGATE WHY !!)
_t->_segT._dataLenT = _dataLen; // sometimes memory gets re-allocated (!! INVESTIGATE WHY !!)
_t->_segT._dataT = data;
_t->_segT._dataLenT = _dataLen;
}
options = tmpSeg._optionsT;
for (size_t i=0; i<NUM_COLORS; i++) colors[i] = tmpSeg._colorT[i];
@ -443,39 +428,40 @@ void Segment::restoreSegenv(tmpsegd_t &tmpSeg) {
}
#endif
uint8_t Segment::currentBri(uint8_t briNew, bool useCct) {
uint8_t Segment::currentBri(bool useCct) {
uint32_t prog = progress();
if (prog < 0xFFFFU) {
if (useCct) return ((briNew * prog) + _t->_cctT * (0xFFFFU - prog)) >> 16;
else return ((briNew * prog) + _t->_briT * (0xFFFFU - prog)) >> 16;
uint32_t curBri = (useCct ? cct : (on ? opacity : 0)) * prog;
curBri += (useCct ? _t->_cctT : (on ? _t->_briT : 0)) * (0xFFFFU - prog);
return curBri / 0xFFFFU;
}
return briNew;
return (useCct ? cct : (on ? opacity : 0));
}
uint8_t Segment::currentMode(uint8_t newMode) {
uint8_t Segment::currentMode() {
#ifndef WLED_DISABLE_MODE_BLEND
uint16_t prog = progress(); // implicit check for transitional & _t in progress()
if (prog < 0xFFFFU) return _t->_modeT;
uint16_t prog = progress();
if (modeBlending && prog < 0xFFFFU) return _t->_modeT;
#endif
return newMode;
return mode;
}
uint32_t Segment::currentColor(uint8_t slot, uint32_t colorNew) {
uint32_t Segment::currentColor(uint8_t slot) {
#ifndef WLED_DISABLE_MODE_BLEND
return transitional && _t ? color_blend(_t->_segT._colorT[slot], colorNew, progress(), true) : colorNew;
return isInTransition() ? color_blend(_t->_segT._colorT[slot], colors[slot], progress(), true) : colors[slot];
#else
return transitional && _t ? color_blend(_t->_colorT[slot], colorNew, progress(), true) : colorNew;
return isInTransition() ? color_blend(_t->_colorT[slot], colors[slot], progress(), true) : colors[slot];
#endif
}
CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
loadPalette(targetPalette, pal);
if (progress() < 0xFFFFU) {
uint16_t prog = progress();
if (strip.paletteFade && prog < 0xFFFFU) {
// blend palettes
// there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time)
// minimum blend time is 100ms maximum is 65535ms
unsigned long timeMS = millis() - _t->_start;
uint16_t noOfBlends = (255U * timeMS / _t->_dur) - _t->_prevPaletteBlends;
uint16_t noOfBlends = ((255U * prog) / 0xFFFFU) - _t->_prevPaletteBlends;
for (int i=0; i<noOfBlends; i++, _t->_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, targetPalette, 48);
targetPalette = _t->_palT; // copy transitioning/temporary palette
}
@ -500,6 +486,8 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
&& (!grp || (grouping == grp && spacing == spc))
&& (ofs == UINT16_MAX || ofs == offset)) return;
stateChanged = true; // send UDP/WS broadcast
if (stop) fill(BLACK); // turn old segment range off (clears pixels if changing spacing)
if (grp) { // prevent assignment of 0
grouping = grp;
@ -510,6 +498,10 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
}
if (ofs < UINT16_MAX) offset = ofs;
DEBUG_PRINT(F("setUp segment: ")); DEBUG_PRINT(i1);
DEBUG_PRINT(','); DEBUG_PRINT(i2);
DEBUG_PRINT(F(" -> ")); DEBUG_PRINT(i1Y);
DEBUG_PRINT(','); DEBUG_PRINTLN(i2Y);
markForReset();
if (boundsUnchanged) return;
@ -564,7 +556,6 @@ void Segment::setCCT(uint16_t k) {
void Segment::setOpacity(uint8_t o) {
if (opacity == o) return;
if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change
DEBUG_PRINT(F("-- Setting opacity: ")); DEBUG_PRINTLN(o);
opacity = o;
stateChanged = true; // send UDP/WS broadcast
}
@ -574,14 +565,16 @@ void Segment::setOption(uint8_t n, bool val) {
if (fadeTransition && n == SEG_OPTION_ON && val != prevOn) startTransition(strip.getTransition()); // start transition prior to change
if (val) options |= 0x01 << n;
else options &= ~(0x01 << n);
if (!(n == SEG_OPTION_SELECTED || n == SEG_OPTION_RESET || n == SEG_OPTION_TRANSITIONAL)) stateChanged = true; // send UDP/WS broadcast
if (!(n == SEG_OPTION_SELECTED || n == SEG_OPTION_RESET)) stateChanged = true; // send UDP/WS broadcast
}
void Segment::setMode(uint8_t fx, bool loadDefaults) {
// if we have a valid mode & is not reserved
if (fx < strip.getModeCount() && strncmp_P("RSVD", strip.getModeData(fx), 4)) {
if (fx != mode) {
if (fadeTransition) startTransition(strip.getTransition()); // set effect transitions
#ifndef WLED_DISABLE_MODE_BLEND
if (modeBlending) startTransition(strip.getTransition()); // set effect transitions
#endif
mode = fx;
// load default values from effect string
if (loadDefaults) {
@ -594,7 +587,7 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) {
sOpt = extractModeDefaults(fx, "o1"); check1 = (sOpt >= 0) ? (bool)sOpt : false;
sOpt = extractModeDefaults(fx, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false;
sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false;
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7);
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7); else map1D2D = M12_Pixels; // reset mapping if not defined (2D FX may not work)
sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 1);
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt;
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business
@ -743,7 +736,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
#endif
uint16_t len = length();
uint8_t _bri_t = currentBri(on ? opacity : 0);
uint8_t _bri_t = currentBri();
if (_bri_t < 255) {
byte r = scale8(R(col), _bri_t);
byte g = scale8(G(col), _bri_t);
@ -877,10 +870,11 @@ uint8_t Segment::differs(Segment& b) const {
if (startY != b.startY) d |= SEG_DIFFERS_BOUNDS;
if (stopY != b.stopY) d |= SEG_DIFFERS_BOUNDS;
//bit pattern: (msb first) set:2, sound:1, mapping:3, transposed, mirrorY, reverseY, [transitional, reset,] paused, mirrored, on, reverse, [selected]
if ((options & 0b1111111110011110U) != (b.options & 0b1111111110011110U)) d |= SEG_DIFFERS_OPT;
//bit pattern: (msb first)
// set:2, sound:2, mapping:3, transposed, mirrorY, reverseY, [reset,] paused, mirrored, on, reverse, [selected]
if ((options & 0b1111111111011110U) != (b.options & 0b1111111111011110U)) d |= SEG_DIFFERS_OPT;
if ((options & 0x0001U) != (b.options & 0x0001U)) d |= SEG_DIFFERS_SEL;
for (uint8_t i = 0; i < NUM_COLORS; i++) if (colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL;
for (unsigned i = 0; i < NUM_COLORS; i++) if (colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL;
return d;
}
@ -912,7 +906,7 @@ void Segment::refreshLightCapabilities() {
segStopIdx = stop;
}
for (uint8_t b = 0; b < busses.getNumBusses(); b++) {
for (unsigned b = 0; b < busses.getNumBusses(); b++) {
Bus *bus = busses.getBus(b);
if (bus == nullptr || bus->getLength()==0) break;
if (!bus->isOk()) continue;
@ -942,7 +936,7 @@ void Segment::fill(uint32_t c) {
if (!isActive()) return; // not active
const uint16_t cols = is2D() ? virtualWidth() : virtualLength();
const uint16_t rows = virtualHeight(); // will be 1 for 1D
for(uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
if (is2D()) setPixelColorXY(x, y, c);
else setPixelColor(x, c);
}
@ -956,27 +950,12 @@ void Segment::blendPixelColor(int n, uint32_t color, uint8_t blend) {
// Adds the specified color with the existing pixel color perserving color balance.
void Segment::addPixelColor(int n, uint32_t color, bool fast) {
if (!isActive()) return; // not active
uint32_t col = getPixelColor(n);
uint8_t r = R(col);
uint8_t g = G(col);
uint8_t b = B(col);
uint8_t w = W(col);
if (fast) {
r = qadd8(r, R(color));
g = qadd8(g, G(color));
b = qadd8(b, B(color));
w = qadd8(w, W(color));
col = RGBW32(r,g,b,w);
} else {
col = color_add(col, color);
}
setPixelColor(n, col);
setPixelColor(n, color_add(getPixelColor(n), color, fast));
}
void Segment::fadePixelColor(uint16_t n, uint8_t fade) {
if (!isActive()) return; // not active
CRGB pix = CRGB(getPixelColor(n)).nscale8_video(fade);
setPixelColor(n, pix);
setPixelColor(n, color_fade(getPixelColor(n), fade, true));
}
/*
@ -996,7 +975,7 @@ void Segment::fade_out(uint8_t rate) {
int g2 = G(color);
int b2 = B(color);
for (uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
color = is2D() ? getPixelColorXY(x, y) : getPixelColor(x);
int w1 = W(color);
int r1 = R(color);
@ -1025,9 +1004,9 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) {
const uint16_t cols = is2D() ? virtualWidth() : virtualLength();
const uint16_t rows = virtualHeight(); // will be 1 for 1D
for (uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) {
if (is2D()) setPixelColorXY(x, y, CRGB(getPixelColorXY(x,y)).nscale8(255-fadeBy));
else setPixelColor(x, CRGB(getPixelColor(x)).nscale8(255-fadeBy));
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
if (is2D()) setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), 255-fadeBy));
else setPixelColor(x, color_fade(getPixelColor(x), 255-fadeBy));
}
}
@ -1040,34 +1019,26 @@ void Segment::blur(uint8_t blur_amount)
#ifndef WLED_DISABLE_2D
if (is2D()) {
// compatibility with 2D
const uint_fast16_t cols = virtualWidth();
const uint_fast16_t rows = virtualHeight();
for (uint_fast16_t i = 0; i < rows; i++) blurRow(i, blur_amount); // blur all rows
for (uint_fast16_t k = 0; k < cols; k++) blurCol(k, blur_amount); // blur all columns
const unsigned cols = virtualWidth();
const unsigned rows = virtualHeight();
for (unsigned i = 0; i < rows; i++) blurRow(i, blur_amount); // blur all rows
for (unsigned k = 0; k < cols; k++) blurCol(k, blur_amount); // blur all columns
return;
}
#endif
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
CRGB carryover = CRGB::Black;
uint_fast16_t vlength = virtualLength();
for(uint_fast16_t i = 0; i < vlength; i++)
{
CRGB cur = CRGB(getPixelColor(i));
CRGB part = cur;
CRGB before = cur; // remember color before blur
part.nscale8(seep);
cur.nscale8(keep);
cur += carryover;
if(i > 0) {
uint32_t carryover = BLACK;
unsigned vlength = virtualLength();
for (unsigned i = 0; i < vlength; i++) {
uint32_t cur = getPixelColor(i);
uint32_t part = color_fade(cur, seep);
cur = color_add(color_fade(cur, keep), carryover, true);
if (i > 0) {
uint32_t c = getPixelColor(i-1);
uint8_t r = R(c);
uint8_t g = G(c);
uint8_t b = B(c);
setPixelColor((uint16_t)(i-1), qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue));
setPixelColor(i-1, color_add(c, part, true));
}
if (before != cur) // optimization: only set pixel if color has changed
setPixelColor((uint16_t)i,cur.red, cur.green, cur.blue);
setPixelColor(i, cur);
carryover = part;
}
}
@ -1080,7 +1051,7 @@ void Segment::blur(uint8_t blur_amount)
uint32_t Segment::color_wheel(uint8_t pos) {
if (palette) return color_from_palette(pos, false, true, 0);
pos = 255 - pos;
if(pos < 85) {
if (pos < 85) {
return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3);
} else if(pos < 170) {
pos -= 85;
@ -1091,21 +1062,6 @@ uint32_t Segment::color_wheel(uint8_t pos) {
}
}
/*
* Returns a new, random wheel index with a minimum distance of 42 from pos.
*/
uint8_t Segment::get_random_wheel_index(uint8_t pos) {
uint8_t r = 0, x = 0, y = 0, d = 0;
while(d < 42) {
r = random8();
x = abs(pos - r);
y = 255 - x;
d = MIN(x, y);
}
return r;
}
/*
* Gets a single color from the currently selected palette.
* @param i Palette Index (if mapping is true, the full palette will be _virtualSegmentLength long, if false, 255). Will wrap around automatically.
@ -1119,20 +1075,20 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_
{
// default palette or no RGB support on segment
if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) {
uint32_t color = currentColor(mcol, colors[mcol]);
uint32_t color = currentColor(mcol);
color = gamma32(color);
if (pbri == 255) return color;
return RGBW32(scale8_video(R(color),pbri), scale8_video(G(color),pbri), scale8_video(B(color),pbri), scale8_video(W(color),pbri));
return color_fade(color, pbri, true);
}
uint8_t paletteIndex = i;
if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1);
if (!wrap) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
CRGB fastled_col;
if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
CRGBPalette16 curPal;
if (transitional && _t) curPal = _t->_palT;
else loadPalette(curPal, palette);
fastled_col = ColorFromPalette(curPal, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global
curPal = currentPalette(curPal, palette);
//if (isInTransition()) curPal = _t->_palT;
//else loadPalette(curPal, palette);
CRGB fastled_col = ColorFromPalette(curPal, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global
return RGBW32(fastled_col.r, fastled_col.g, fastled_col.b, 0);
}
@ -1166,7 +1122,7 @@ void WS2812FX::finalizeInit(void)
const uint8_t defNumBusses = ((sizeof defDataPins) / (sizeof defDataPins[0]));
const uint8_t defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0]));
uint16_t prevLen = 0;
for (uint8_t i = 0; i < defNumBusses && i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
for (int i = 0; i < defNumBusses && i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
uint8_t defPin[] = {defDataPins[i]};
uint16_t start = prevLen;
uint16_t count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
@ -1177,7 +1133,7 @@ void WS2812FX::finalizeInit(void)
}
_length = 0;
for (uint8_t i=0; i<busses.getNumBusses(); i++) {
for (int i=0; i<busses.getNumBusses(); i++) {
Bus *bus = busses.getBus(i);
if (bus == nullptr) continue;
if (bus->getStart() + bus->getLength() > MAX_LEDS) break;
@ -1234,27 +1190,28 @@ void WS2812FX::service() {
if (!seg.freeze) { //only run effect function if not frozen
_virtualSegmentLength = seg.virtualLength();
_colors_t[0] = seg.currentColor(0, seg.colors[0]);
_colors_t[1] = seg.currentColor(1, seg.colors[1]);
_colors_t[2] = seg.currentColor(2, seg.colors[2]);
seg.currentPalette(_currentPalette, seg.palette);
_colors_t[0] = seg.currentColor(0);
_colors_t[1] = seg.currentColor(1);
_colors_t[2] = seg.currentColor(2);
seg.currentPalette(_currentPalette, seg.palette); // we need to pass reference
if (!cctFromRgb || correctWB) busses.setSegmentCCT(seg.currentBri(seg.cct, true), correctWB);
for (uint8_t c = 0; c < NUM_COLORS; c++) _colors_t[c] = gamma32(_colors_t[c]);
if (!cctFromRgb || correctWB) busses.setSegmentCCT(seg.currentBri(true), correctWB);
for (int c = 0; c < NUM_COLORS; c++) _colors_t[c] = gamma32(_colors_t[c]);
// Effect blending
// When two effects are being blended, each may have different segment data, this
// data needs to be saved first and then restored before running previous/transitional mode.
// data needs to be saved first and then restored before running previous mode.
// The blending will largely depend on the effect behaviour since actual output (LEDs) may be
// overwritten by later effect. To enable seamless blending for every effect, additional LED buffer
// would need to be allocated for each effect and then blended together for each pixel.
[[maybe_unused]] uint8_t tmpMode = seg.currentMode(seg.mode); // this will return old mode while in transition
[[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition
delay = (*_mode[seg.mode])(); // run new/current mode
#ifndef WLED_DISABLE_MODE_BLEND
if (seg.mode != tmpMode) {
if (modeBlending && seg.mode != tmpMode) {
Segment::tmpsegd_t _tmpSegData;
Segment::modeBlend(true); // set semaphore
seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state)
_virtualSegmentLength = seg.virtualLength(); // update SEGLEN (mapping may have changed)
uint16_t d2 = (*_mode[tmpMode])(); // run old mode
seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state)
delay = MIN(delay,d2); // use shortest delay
@ -1262,7 +1219,7 @@ void WS2812FX::service() {
}
#endif
if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++;
if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
if (seg.isInTransition() && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
}
seg.next_time = nowUp + delay;
@ -1382,7 +1339,7 @@ uint8_t WS2812FX::estimateCurrentAndLimitBri() {
}
void WS2812FX::show(void) {
// avoid race condition, caputre _callback value
// avoid race condition, capture _callback value
show_callback callback = _callback;
if (callback) callback();
@ -1399,12 +1356,12 @@ void WS2812FX::show(void) {
// or async show has a separate buffer (ESP32 RMT and I2S are ok)
if (newBri < _brightness) busses.setBrightness(_brightness);
unsigned long now = millis();
size_t diff = now - _lastShow;
unsigned long showNow = millis();
size_t diff = showNow - _lastShow;
size_t fpsCurr = 200;
if (diff > 0) fpsCurr = 1000 / diff;
_cumulativeFps = (3 * _cumulativeFps + fpsCurr +2) >> 2; // "+2" for proper rounding (2/4 = 0.5)
_lastShow = now;
_lastShow = showNow;
}
/**
@ -1417,7 +1374,7 @@ bool WS2812FX::isUpdating() {
/**
* Returns the refresh rate of the LED strip. Useful for finding out whether a given setup is fast enough.
* Only updates on show() or is set to 0 fps if last show is more than 2 secs ago, so accurary varies
* Only updates on show() or is set to 0 fps if last show is more than 2 secs ago, so accuracy varies
*/
uint16_t WS2812FX::getFps() {
if (millis() - _lastShow > 2000) return 0;
@ -1597,10 +1554,12 @@ void WS2812FX::setSegment(uint8_t segId, uint16_t i1, uint16_t i2, uint8_t group
_qStart = i1; _qStop = i2; _qStartY = startY; _qStopY = stopY;
_qGrouping = grouping; _qSpacing = spacing; _qOffset = offset;
_queuedChangesSegId = segId;
DEBUG_PRINT(F("Segment queued: ")); DEBUG_PRINTLN(segId);
return; // queued changes are applied immediately after effect function returns
}
_segments[segId].setUp(i1, i2, grouping, spacing, offset, startY, stopY);
if (segId > 0 && segId == getSegmentsNum()-1 && i2 <= i1) _segments.pop_back(); // if last segment was deleted remove it from vector
}
void WS2812FX::setUpSegmentFromQueuedChanges() {
@ -1729,7 +1688,7 @@ void WS2812FX::fixInvalidSegments() {
bool WS2812FX::checkSegmentAlignment() {
bool aligned = false;
for (segment &seg : _segments) {
for (uint8_t b = 0; b<busses.getNumBusses(); b++) {
for (unsigned b = 0; b<busses.getNumBusses(); b++) {
Bus *bus = busses.getBus(b);
if (seg.start == bus->getStart() && seg.stop == bus->getStart() + bus->getLength()) aligned = true;
}
@ -1752,13 +1711,8 @@ uint8_t WS2812FX::setPixelSegment(uint8_t n) {
}
void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col) {
if (i2 >= i)
{
for (uint16_t x = i; x <= i2; x++) setPixelColor(x, col);
} else
{
for (uint16_t x = i2; x <= i; x++) setPixelColor(x, col);
}
if (i2 < i) std::swap(i,i2);
for (unsigned x = i; x <= i2; x++) setPixelColor(x, col);
}
void WS2812FX::setTransitionMode(bool t) {
@ -1793,7 +1747,7 @@ void WS2812FX::loadCustomPalettes() {
if (readObjectFromFile(fileName, nullptr, &pDoc)) {
JsonArray pal = pDoc[F("palette")];
if (!pal.isNull() && pal.size()>4) { // not an empty palette (at least 2 entries)
if (!pal.isNull() && pal.size()>3) { // not an empty palette (at least 2 entries)
if (pal[0].is<int>() && pal[1].is<const char *>()) {
// we have an array of index & hex strings
size_t palSize = MIN(pal.size(), 36);
@ -1802,7 +1756,7 @@ void WS2812FX::loadCustomPalettes() {
uint8_t rgbw[] = {0,0,0,0};
tcp[ j ] = (uint8_t) pal[ i ].as<int>(); // index
colorFromHexString(rgbw, pal[i+1].as<const char *>()); // will catch non-string entires
for (size_t c=0; c<3; c++) tcp[j+1+c] = rgbw[c]; // only use RGB component
for (size_t c=0; c<3; c++) tcp[j+1+c] = gamma8(rgbw[c]); // only use RGB component
DEBUG_PRINTF("%d(%d) : %d %d %d\n", i, int(tcp[j]), int(tcp[j+1]), int(tcp[j+2]), int(tcp[j+3]));
}
} else {
@ -1810,13 +1764,15 @@ void WS2812FX::loadCustomPalettes() {
palSize -= palSize % 4; // make sure size is multiple of 4
for (size_t i=0; i<palSize && pal[i].as<int>()<256; i+=4) {
tcp[ i ] = (uint8_t) pal[ i ].as<int>(); // index
tcp[i+1] = (uint8_t) pal[i+1].as<int>(); // R
tcp[i+2] = (uint8_t) pal[i+2].as<int>(); // G
tcp[i+3] = (uint8_t) pal[i+3].as<int>(); // B
tcp[i+1] = gamma8((uint8_t) pal[i+1].as<int>()); // R
tcp[i+2] = gamma8((uint8_t) pal[i+2].as<int>()); // G
tcp[i+3] = gamma8((uint8_t) pal[i+3].as<int>()); // B
DEBUG_PRINTF("%d(%d) : %d %d %d\n", i, int(tcp[i]), int(tcp[i+1]), int(tcp[i+2]), int(tcp[i+3]));
}
}
customPalettes.push_back(targetPalette.loadDynamicGradientPalette(tcp));
} else {
DEBUG_PRINTLN(F("Wrong palette format."));
}
}
} else {
@ -1832,7 +1788,7 @@ bool WS2812FX::deserializeMap(uint8_t n) {
char fileName[32];
strcpy_P(fileName, PSTR("/ledmap"));
if (n) sprintf(fileName +7, "%d", n);
strcat(fileName, ".json");
strcat_P(fileName, PSTR(".json"));
bool isFile = WLED_FS.exists(fileName);
if (!isFile) {
@ -1866,7 +1822,7 @@ bool WS2812FX::deserializeMap(uint8_t n) {
if (!map.isNull() && map.size()) { // not an empty map
customMappingSize = map.size();
customMappingTable = new uint16_t[customMappingSize];
for (uint16_t i=0; i<customMappingSize; i++) {
for (unsigned i=0; i<customMappingSize; i++) {
customMappingTable[i] = (uint16_t) (map[i]<0 ? 0xFFFFU : map[i]);
}
}

View File

@ -64,7 +64,7 @@ void ColorOrderMap::add(uint16_t start, uint16_t len, uint8_t colorOrder) {
uint8_t IRAM_ATTR ColorOrderMap::getPixelColorOrder(uint16_t pix, uint8_t defaultColorOrder) const {
if (_count == 0) return defaultColorOrder;
// upper nibble containd W swap information
// upper nibble contains W swap information
uint8_t swapW = defaultColorOrder >> 4;
for (uint8_t i = 0; i < _count; i++) {
if (pix >= _mappings[i].start && pix < (_mappings[i].start + _mappings[i].len)) {
@ -77,7 +77,7 @@ uint8_t IRAM_ATTR ColorOrderMap::getPixelColorOrder(uint16_t pix, uint8_t defaul
uint32_t Bus::autoWhiteCalc(uint32_t c) {
uint8_t aWM = _autoWhiteMode;
if (_gAWM < 255) aWM = _gAWM;
if (_gAWM != AW_GLOBAL_DISABLED) aWM = _gAWM;
if (aWM == RGBW_MODE_MANUAL_ONLY) return c;
uint8_t w = W(c);
//ignore auto-white calculation if w>0 and mode DUAL (DUAL behaves as BRIGHTER if w==0)

View File

@ -114,7 +114,7 @@ class Bus {
, _needsRefresh(refresh)
, _data(nullptr) // keep data access consistent across all types of buses
{
_autoWhiteMode = Bus::hasWhite(_type) ? aw : RGBW_MODE_MANUAL_ONLY;
_autoWhiteMode = Bus::hasWhite(type) ? aw : RGBW_MODE_MANUAL_ONLY;
};
virtual ~Bus() {} //throw the bus under the bus
@ -148,7 +148,7 @@ class Bus {
}
virtual bool hasWhite(void) { return Bus::hasWhite(_type); }
static bool hasWhite(uint8_t type) {
if ((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_SK6812_RGBW || type == TYPE_TM1814) return true; // digital types with white channel
if ((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_SK6812_RGBW || type == TYPE_TM1814 || type == TYPE_UCS8904) return true; // digital types with white channel
if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true; // analog types with white channel
if (type == TYPE_NET_DDP_RGBW) return true; // network types with white channel
return false;
@ -229,7 +229,7 @@ class BusDigital : public Bus {
uint8_t* chan = (uint8_t*) &c;
for (uint_fast8_t i=0; i<4; i++) {
uint_fast16_t val = chan[i];
chan[i] = ((val << 8) + restoreBri) / (restoreBri + 1); //adding _bri slighly improves recovery / stops degradation on re-scale
chan[i] = ((val << 8) + restoreBri) / (restoreBri + 1); //adding _bri slightly improves recovery / stops degradation on re-scale
}
}
return c;

View File

@ -69,17 +69,17 @@
#define I_32_RN_NEO_3 21
#define I_32_I0_NEO_3 22
#define I_32_I1_NEO_3 23
#define I_32_BB_NEO_3 24 // bitbangging on ESP32 not recommended
#define I_32_BB_NEO_3 24 // bitbanging on ESP32 not recommended
//RGBW
#define I_32_RN_NEO_4 25
#define I_32_I0_NEO_4 26
#define I_32_I1_NEO_4 27
#define I_32_BB_NEO_4 28 // bitbangging on ESP32 not recommended
#define I_32_BB_NEO_4 28 // bitbanging on ESP32 not recommended
//400Kbps
#define I_32_RN_400_3 29
#define I_32_I0_400_3 30
#define I_32_I1_400_3 31
#define I_32_BB_400_3 32 // bitbangging on ESP32 not recommended
#define I_32_BB_400_3 32 // bitbanging on ESP32 not recommended
//TM1814 (RGBW)
#define I_32_RN_TM1_4 33
#define I_32_I0_TM1_4 34
@ -379,7 +379,7 @@ class PolyBus {
case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->Begin(); break;
#endif
// case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->Begin(); break;
// ESP32 can (and should, to avoid inadvertantly driving the chip select signal) specify the pins used for SPI, but only in begin()
// ESP32 can (and should, to avoid inadvertently driving the chip select signal) specify the pins used for SPI, but only in begin()
case I_HS_DOT_3: beginDotStar<B_HS_DOT_3*>(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break;
case I_HS_LPD_3: beginDotStar<B_HS_LPD_3*>(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break;
case I_HS_LPO_3: beginDotStar<B_HS_LPO_3*>(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break;

View File

@ -171,13 +171,12 @@ void handleAnalog(uint8_t b)
// remove noise & reduce frequency of UI updates
if (abs(int(aRead) - int(oldRead[b])) <= POT_SENSITIVITY) return; // no significant change in reading
// Unomment the next lines if you still see flickering related to potentiometer
// Un-comment the next lines if you still see flickering related to potentiometer
// This waits until strip finishes updating (why: strip was not updating at the start of handleButton() but may have started during analogRead()?)
//unsigned long wait_started = millis();
//while(strip.isUpdating() && (millis() - wait_started < STRIP_WAIT_TIME)) {
// delay(1);
//}
//if (strip.isUpdating()) return; // give up
oldRead[b] = aRead;
@ -375,7 +374,7 @@ void handleIO()
if (!offMode) {
#ifdef ESP8266
// turn off built-in LED if strip is turned off
// this will break digital bus so will need to be reinitialised on On
// this will break digital bus so will need to be re-initialised on On
PinOwner ledPinOwner = pinManager.getPinOwner(LED_BUILTIN);
if (!strip.isOffRefreshRequired() && (ledPinOwner == PinOwner::None || ledPinOwner == PinOwner::BusDigital)) {
pinMode(LED_BUILTIN, OUTPUT);
@ -392,4 +391,4 @@ void handleIO()
}
offMode = true;
}
}
}

View File

@ -81,10 +81,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
// initialize LED pins and lengths prior to other HW (except for ethernet)
JsonObject hw_led = hw["led"];
uint8_t autoWhiteMode = RGBW_MODE_MANUAL_ONLY;
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]);
Bus::setGlobalAWMode(hw_led[F("rgbwm")] | 255);
Bus::setGlobalAWMode(hw_led[F("rgbwm")] | AW_GLOBAL_DISABLED);
CJSON(correctWB, hw_led["cct"]);
CJSON(cctFromRgb, hw_led[F("cr")]);
CJSON(strip.cctBlending, hw_led[F("cb")]);
@ -150,7 +149,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
}
uint16_t length = elm["len"] | 1;
uint8_t colorOrder = (int)elm[F("order")];
uint8_t colorOrder = (int)elm[F("order")]; // contains white channel swap option in upper nibble
uint8_t skipFirst = elm[F("skip")];
uint16_t start = elm["start"] | 0;
if (length==0 || start + length > MAX_LEDS) continue; // zero length or we reached max. number of LEDs, just stop
@ -159,7 +158,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
bool refresh = elm["ref"] | false;
uint16_t freqkHz = elm[F("freq")] | 0; // will be in kHz for DotStar and Hz for PWM (not yet implemented fully)
ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh
uint8_t AWmode = elm[F("rgbwm")] | autoWhiteMode;
uint8_t AWmode = elm[F("rgbwm")] | RGBW_MODE_MANUAL_ONLY;
if (fromFS) {
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer);
mem += BusManager::memUsage(bc);
@ -216,7 +215,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
if (((buttonType[s] == BTN_TYPE_ANALOG) || (buttonType[s] == BTN_TYPE_ANALOG_INVERTED)) && (digitalPinToAnalogChannel(btnPin[s]) < 0))
{
// not an ADC analog pin
DEBUG_PRINTF("PIN ALLOC error: GPIO%d for analog button #%d is not an analog pin!\n", btnPin[s], s);
DEBUG_PRINT(F("PIN ALLOC error: GPIO")); DEBUG_PRINT(btnPin[s]);
DEBUG_PRINT(F("for analog button #")); DEBUG_PRINT(s);
DEBUG_PRINTLN(F(" is not an analog pin!"));
btnPin[s] = -1;
pinManager.deallocatePin(pin,PinOwner::Button);
}
@ -307,7 +308,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
PinManagerPinType i2c[2] = { { i2c_sda, true }, { i2c_scl, true } };
if (i2c_scl >= 0 && i2c_sda >= 0 && pinManager.allocateMultiplePins(i2c, 2, PinOwner::HW_I2C)) {
#ifdef ESP32
if (!Wire.setPins(i2c_sda, i2c_scl)) { i2c_scl = i2c_sda = -1; } // this will fail if Wire is initilised (Wire.begin() called prior)
if (!Wire.setPins(i2c_sda, i2c_scl)) { i2c_scl = i2c_sda = -1; } // this will fail if Wire is initialised (Wire.begin() called prior)
else Wire.begin();
#else
Wire.begin(i2c_sda, i2c_scl);
@ -357,8 +358,10 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
JsonObject light_tr = light["tr"];
CJSON(fadeTransition, light_tr["mode"]);
CJSON(modeBlending, light_tr["fx"]);
int tdd = light_tr["dur"] | -1;
if (tdd >= 0) transitionDelay = transitionDelayDefault = tdd * 100;
strip.setTransition(fadeTransition ? transitionDelayDefault : 0);
CJSON(strip.paletteFade, light_tr["pal"]);
CJSON(randomPaletteChangeTime, light_tr[F("rpc")]);
@ -827,6 +830,7 @@ void serializeConfig() {
JsonObject light_tr = light.createNestedObject("tr");
light_tr["mode"] = fadeTransition;
light_tr["fx"] = modeBlending;
light_tr["dur"] = transitionDelayDefault / 100;
light_tr["pal"] = strip.paletteFade;
light_tr[F("rpc")] = randomPaletteChangeTime;
@ -888,6 +892,7 @@ void serializeConfig() {
if_live[F("no-gc")] = arlsDisableGammaCorrection;
if_live[F("offset")] = arlsOffset;
#ifndef WLED_DISABLE_ALEXA
JsonObject if_va = interfaces.createNestedObject("va");
if_va[F("alexa")] = alexaEnabled;
@ -896,6 +901,7 @@ void serializeConfig() {
if_va_macros.add(macroAlexaOff);
if_va["p"] = alexaNumPresets;
#endif
#ifdef WLED_ENABLE_MQTT
JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
@ -1033,7 +1039,7 @@ bool deserializeConfigSec() {
JsonObject ap = doc["ap"];
getStringFromJson(apPass, ap["psk"] , 65);
JsonObject interfaces = doc["if"];
[[maybe_unused]] JsonObject interfaces = doc["if"];
#ifdef WLED_ENABLE_MQTT
JsonObject if_mqtt = interfaces["mqtt"];
@ -1072,7 +1078,7 @@ void serializeConfigSec() {
JsonObject ap = doc.createNestedObject("ap");
ap["psk"] = apPass;
JsonObject interfaces = doc.createNestedObject("if");
[[maybe_unused]] JsonObject interfaces = doc.createNestedObject("if");
#ifdef WLED_ENABLE_MQTT
JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
if_mqtt["psk"] = mqttPass;

View File

@ -35,23 +35,59 @@ uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16)
* color add function that preserves ratio
* idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule
*/
uint32_t color_add(uint32_t c1, uint32_t c2)
uint32_t color_add(uint32_t c1, uint32_t c2, bool fast)
{
uint32_t r = R(c1) + R(c2);
uint32_t g = G(c1) + G(c2);
uint32_t b = B(c1) + B(c2);
uint32_t w = W(c1) + W(c2);
uint16_t max = r;
if (g > max) max = g;
if (b > max) max = b;
if (w > max) max = w;
if (max < 256) return RGBW32(r, g, b, w);
else return RGBW32(r * 255 / max, g * 255 / max, b * 255 / max, w * 255 / max);
if (fast) {
uint8_t r = R(c1);
uint8_t g = G(c1);
uint8_t b = B(c1);
uint8_t w = W(c1);
r = qadd8(r, R(c2));
g = qadd8(g, G(c2));
b = qadd8(b, B(c2));
w = qadd8(w, W(c2));
return RGBW32(r,g,b,w);
} else {
uint32_t r = R(c1) + R(c2);
uint32_t g = G(c1) + G(c2);
uint32_t b = B(c1) + B(c2);
uint32_t w = W(c1) + W(c2);
uint16_t max = r;
if (g > max) max = g;
if (b > max) max = b;
if (w > max) max = w;
if (max < 256) return RGBW32(r, g, b, w);
else return RGBW32(r * 255 / max, g * 255 / max, b * 255 / max, w * 255 / max);
}
}
/*
* fades color toward black
* if using "video" method the resulting color will never become black unless it is already black
*/
uint32_t color_fade(uint32_t c1, uint8_t amount, bool video)
{
uint8_t r = R(c1);
uint8_t g = G(c1);
uint8_t b = B(c1);
uint8_t w = W(c1);
if (video) {
r = scale8_video(r, amount);
g = scale8_video(g, amount);
b = scale8_video(b, amount);
w = scale8_video(w, amount);
} else {
r = scale8(r, amount);
g = scale8(g, amount);
b = scale8(b, amount);
w = scale8(w, amount);
}
return RGBW32(r, g, b, w);
}
void setRandomColor(byte* rgb)
{
lastRandomIndex = strip.getMainSegment().get_random_wheel_index(lastRandomIndex);
lastRandomIndex = get_random_wheel_index(lastRandomIndex);
colorHStoRGB(lastRandomIndex*256,255,rgb);
}

View File

@ -150,6 +150,7 @@
#define USERMOD_ID_KLIPPER 40 //Usermod Klipper percentage
#define USERMOD_ID_WIREGUARD 41 //Usermod "wireguard.h"
#define USERMOD_ID_INTERNAL_TEMPERATURE 42 //Usermod "usermod_internal_temperature.h"
#define USERMOD_ID_LDR_DUSK_DAWN 43 //Usermod "usermod_LDR_Dusk_Dawn_v2.h"
//Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
@ -166,7 +167,7 @@
#define CALL_MODE_NO_NOTIFY 5
#define CALL_MODE_FX_CHANGED 6 //no longer used
#define CALL_MODE_HUE 7
#define CALL_MODE_PRESET_CYCLE 8
#define CALL_MODE_PRESET_CYCLE 8 //no longer used
#define CALL_MODE_BLYNK 9 //no longer used
#define CALL_MODE_ALEXA 10
#define CALL_MODE_WS_SEND 11 //special call mode, not for notifier, updates websocket only
@ -206,8 +207,8 @@
#define DMX_MODE_MULTIPLE_RGB 4 //every LED is addressed with its own RGB (ledCount * 3 channels)
#define DMX_MODE_MULTIPLE_DRGB 5 //every LED is addressed with its own RGB and share a master dimmer (ledCount * 3 + 1 channels)
#define DMX_MODE_MULTIPLE_RGBW 6 //every LED is addressed with its own RGBW (ledCount * 4 channels)
#define DMX_MODE_EFFECT_SEGMENT 8 //trigger standalone effects of WLED (15 channels per segement)
#define DMX_MODE_EFFECT_SEGMENT_W 9 //trigger standalone effects of WLED (18 channels per segement)
#define DMX_MODE_EFFECT_SEGMENT 8 //trigger standalone effects of WLED (15 channels per segment)
#define DMX_MODE_EFFECT_SEGMENT_W 9 //trigger standalone effects of WLED (18 channels per segment)
#define DMX_MODE_PRESET 10 //apply presets (1 channel)
//Light capability byte (unused) 0bRCCCTTTT
@ -313,17 +314,16 @@
#define SEG_OPTION_MIRROR 3 //Indicates that the effect will be mirrored within the segment
#define SEG_OPTION_FREEZE 4 //Segment contents will not be refreshed
#define SEG_OPTION_RESET 5 //Segment runtime requires reset
#define SEG_OPTION_TRANSITIONAL 6
#define SEG_OPTION_REVERSED_Y 7
#define SEG_OPTION_MIRROR_Y 8
#define SEG_OPTION_TRANSPOSED 9
#define SEG_OPTION_REVERSED_Y 6
#define SEG_OPTION_MIRROR_Y 7
#define SEG_OPTION_TRANSPOSED 8
//Segment differs return byte
#define SEG_DIFFERS_BRI 0x01 // opacity
#define SEG_DIFFERS_OPT 0x02 // all segment options except: selected, reset & transitional
#define SEG_DIFFERS_COL 0x04 // colors
#define SEG_DIFFERS_FX 0x08 // effect/mode parameters
#define SEG_DIFFERS_BOUNDS 0x10 // segment start/stop ounds
#define SEG_DIFFERS_BOUNDS 0x10 // segment start/stop bounds
#define SEG_DIFFERS_GSO 0x20 // grouping, spacing & offset
#define SEG_DIFFERS_SEL 0x80 // selected
@ -345,7 +345,8 @@
#define ERR_FS_QUOTA 11 // The FS is full or the maximum file size is reached
#define ERR_FS_PLOAD 12 // It was attempted to load a preset that does not exist
#define ERR_FS_IRLOAD 13 // It was attempted to load an IR JSON cmd, but the "ir.json" file does not exist
#define ERR_FS_GENERAL 19 // A general unspecified filesystem error occured
#define ERR_FS_RMLOAD 14 // It was attempted to load an remote JSON cmd, but the "remote.json" file does not exist
#define ERR_FS_GENERAL 19 // A general unspecified filesystem error occurred
#define ERR_OVERTEMP 30 // An attached temperature sensor has measured above threshold temperature (not implemented)
#define ERR_OVERCURRENT 31 // An attached current sensor has measured a current above the threshold (not implemented)
#define ERR_UNDERVOLT 32 // An attached voltmeter has measured a voltage below the threshold (not implemented)
@ -374,7 +375,8 @@
#define SUBPAGE_JS 254
#define SUBPAGE_WELCOME 255
#define NTP_PACKET_SIZE 48
#define NTP_PACKET_SIZE 48 // size of NTP receive buffer
#define NTP_MIN_PACKET_SIZE 48 // min expected size - NTP v4 allows for "extended information" appended to the standard fields
//maximum number of rendered LEDs - this does not have to match max. physical LEDs, e.g. if there are virtual busses
#ifndef MAX_LEDS
@ -458,8 +460,8 @@
//this is merely a default now and can be changed at runtime
#ifndef LEDPIN
#if defined(ESP8266) || (defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)) || defined(CONFIG_IDF_TARGET_ESP32C3)
#define LEDPIN 2 // GPIO2 (D4) on Wemod D1 mini compatible boards
#if defined(ESP8266) || (defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(ARDUINO_ESP32_PICO)
#define LEDPIN 2 // GPIO2 (D4) on Wemos D1 mini compatible boards, and on boards where GPIO16 is not available
#else
#define LEDPIN 16 // aligns with GPIO2 (D4) on Wemos D1 mini32 compatible boards
#endif
@ -483,7 +485,7 @@
#define PIN_TIMEOUT 900000 // time in ms after which the PIN will be required again, 15 minutes
// HW_PIN_SCL & HW_PIN_SDA are used for information in usermods settings page and usermods themselves
// which GPIO pins are actually used in a hardwarea layout (controller board)
// which GPIO pins are actually used in a hardware layout (controller board)
#if defined(I2CSCLPIN) && !defined(HW_PIN_SCL)
#define HW_PIN_SCL I2CSCLPIN
#endif
@ -506,7 +508,7 @@
#endif
// HW_PIN_SCLKSPI & HW_PIN_MOSISPI & HW_PIN_MISOSPI are used for information in usermods settings page and usermods themselves
// which GPIO pins are actually used in a hardwarea layout (controller board)
// which GPIO pins are actually used in a hardware layout (controller board)
#if defined(SPISCLKPIN) && !defined(HW_PIN_CLOCKSPI)
#define HW_PIN_CLOCKSPI SPISCLKPIN
#endif

View File

@ -485,7 +485,7 @@
console.log('Error: ', e); console.log(' Status: ', this.status);
//Show some error notification for some time
setTimeout(()=>{
//Remove it when time has pased
//Remove it when time has passed
}, 1000);
});
req.open("POST", "/upload");
@ -530,7 +530,7 @@
paletteArray.push({"palette":[0,70,70,70,255,70,70,70]});
}
//Get static palettes from localStorage and do some magic to reformat them into the same format as the pallete JSONs
//Get static palettes from localStorage and do some magic to reformat them into the same format as the palette JSONs
//This code excludes any objects with "non valid integer colors", i.e. r, c1, c2, c3 and such
//This code also fixes potentially broken palettes which doesn't end on 255
//The code finally also removes any representations of the custom palettes, since we read them from file

View File

@ -198,10 +198,11 @@
</label>
</div>
</div>
<div style="padding-bottom: 10px;">
<button class="btn btn-xs" type="button" onclick="window.location.href=getURL('/cpal.htm')"><i class="icons btn-icon">&#xe18a;</i></button>
<button class="btn btn-xs" type="button" onclick="palettesData=null;localStorage.removeItem('wledPalx');requestJson({rmcpal:true});setTimeout(loadPalettes,250,loadPalettesData);"><i class="icons btn-icon">&#xe037;</i></button>
</div>
</div>
<div style="padding-block: 10px;">
<button class="btn btn-xs" type="button" onclick="togglePixelMagicTool()"><i class="icons btn-icon">&#xe410;</i></button>
<button class="btn btn-xs" type="button" onclick="window.location.href=getURL('/cpal.htm')"><i class="icons btn-icon">&#xe18a;</i></button>
<button class="btn btn-xs" type="button" onclick="palettesData=null;localStorage.removeItem('wledPalx');requestJson({rmcpal:true});setTimeout(loadPalettes,250,loadPalettesData);"><i class="icons btn-icon">&#xe037;</i></button>
</div>
</div>
@ -392,6 +393,7 @@
<button class="btn" onclick="setLor(2)">Override until reboot</button><br>
<span class="h">For best performance, it is recommended to turn off the streaming source when not in use.</span>
</div>
<i id="roverstar" class="icons huge" onclick="setLor(0)">&#xe410;</i><br>
<script src="index.js"></script>
</body>

View File

@ -27,16 +27,15 @@ var cfg = {
theme:{base:"dark", bg:{url:""}, alpha:{bg:0.6,tab:0.8}, color:{bg:""}},
comp :{colors:{picker: true, rgb: false, quick: true, hex: false},
labels:true, pcmbot:false, pid:true, seglen:false, segpwr:false, segexp:false,
css:true, hdays:false, fxdef:true}
css:true, hdays:false, fxdef:true, idsort: false}
};
var hol = [
[0,11,24,4,"https://aircoookie.github.io/xmas.png"], // christmas
[0,2,17,1,"https://images.alphacoders.com/491/491123.jpg"], // st. Patrick's day
[2025,3,20,2,"https://aircoookie.github.io/easter.png"],
[2023,3,9,2,"https://aircoookie.github.io/easter.png"],
[2024,2,31,2,"https://aircoookie.github.io/easter.png"],
[0,6,4,1,"https://initiate.alphacoders.com/download/wallpaper/516792/images/jpg/510921363292536"], // 4th of July
[0,0,1,1,"https://initiate.alphacoders.com/download/wallpaper/1198800/images/jpg/2522807481585600"] // new year
[0,6,4,1,"https://images.alphacoders.com/516/516792.jpg"], // 4th of July
[0,0,1,1,"https://images.alphacoders.com/119/1198800.jpg"] // new year
];
function handleVisibilityChange() {if (!d.hidden && new Date () - lastUpdate > 3000) requestJson();}
@ -1209,7 +1208,7 @@ function updateUI()
if (hasRGB) {
updateTrail(gId('sliderR'));
updateTrail(gId('sliderG'));
updateTrail(gId('sliderB'));
updateTrail(gId('sliderB'));
}
if (hasWhite) updateTrail(gId('sliderW'));
@ -1302,7 +1301,7 @@ function displayRover(i,s)
function cmpP(a, b)
{
if (!a[1].n) return (a[0] > b[0]);
if (cfg.comp.idsort || !a[1].n) return (parseInt(a[0]) > parseInt(b[0]));
// sort playlists first, followed by presets with characters and last presets with special 1st character
const c = a[1].n.charCodeAt(0);
const d = b[1].n.charCodeAt(0);
@ -1461,9 +1460,9 @@ function readState(s,command=false)
// - For AC effects (id<128) 2 sliders and 3 colors and the palette will be shown
// - For SR effects (id>128) 5 sliders and 3 colors and the palette will be shown
// If effective (@)
// - a ; seperates slider controls (left) from color controls (middle) and palette control (right)
// - a ; separates slider controls (left) from color controls (middle) and palette control (right)
// - if left, middle or right is empty no controls are shown
// - a , seperates slider controls (max 5) or color controls (max 3). Palette has only one value
// - a , separates slider controls (max 5) or color controls (max 3). Palette has only one value
// - a ! means that the default is used.
// - For sliders: Effect speeds, Effect intensity, Custom 1, Custom 2, Custom 3
// - For colors: Fx color, Background color, Custom
@ -1514,12 +1513,15 @@ function setEffectParameters(idx)
}
// set the bottom position of selected effect (sticky) as the top of sliders div
setInterval(()=>{
function setSelectedEffectPosition() {
let top = parseInt(getComputedStyle(gId("sliders")).height);
top += 5;
let sel = d.querySelector('#fxlist .selected');
if (sel) sel.style.bottom = top + "px"; // we will need to remove this when unselected (in setFX())
},750);
}
setSelectedEffectPosition();
setInterval(setSelectedEffectPosition,750);
// set html color items on/off
var cslLabel = '';
var sep = '';
@ -1700,7 +1702,7 @@ function toggleLiveview()
let wsOn = ws && ws.readyState === WebSocket.OPEN;
var lvID = "liveview";
if (isM && wsOn) {
if (isM && wsOn) {
lvID += "2D";
if (isLv) gId('klv2D').innerHTML = `<iframe id="${lvID}" src="about:blank"></iframe>`;
gId('mlv2D').style.transform = (isLv) ? "translateY(0px)":"translateY(100%)";
@ -1796,6 +1798,7 @@ function makePlSel(el, incPl=false)
var arr = Object.entries(pJson);
for (var a of arr) {
var n = a[1].n ? a[1].n : "Preset " + a[0];
if (cfg.comp.idsort) n = a[0] + ' ' + n;
if (!incPl && a[1].playlist && a[1].playlist.ps) continue; // remove playlists, sub-playlists not yet supported
plSelContent += `<option value="${a[0]}" ${a[0]==el?"selected":""}>${n}</option>`
}
@ -1887,7 +1890,7 @@ function makeP(i,pl)
end: 0
};
var rep = plJson[i].repeat ? plJson[i].repeat : 0;
content =
content =
`<div id="ple${i}" style="margin-top:10px;"></div><label class="check revchkl">Shuffle
<input type="checkbox" id="pl${i}rtgl" onchange="plR(${i})" ${plJson[i].r||rep<0?"checked":""}>
<span class="checkmark"></span>

View File

@ -54,7 +54,7 @@
let mW = leds[2]; // matrix width
let mH = leds[3]; // matrix height
let pPL = Math.min(c.width / mW, c.height / mH); // pixels per LED (width of circle)
let lOf = Math.floor((c.width - pPL*mW)/2); //left offeset (to center matrix)
let lOf = Math.floor((c.width - pPL*mW)/2); //left offset (to center matrix)
var i = 4;
for (y=0.5;y<mH;y++) for (x=0.5; x<mW; x++) {
ctx.fillStyle = `rgb(${leds[i]},${leds[i+1]},${leds[i+2]})`;

View File

@ -69,7 +69,7 @@ function getPixelRGBValues(base64Image) {
let sizeY = szY.value;
if (color != accentColor || sizeX < 1 || sizeY < 1){
//image will not be rezised Set desitred size to original size
//image will not be resized Set desired size to original size
sizeX = image.width;
sizeY = image.height;
//failsafe for not generating huge images automatically
@ -153,7 +153,7 @@ function getPixelRGBValues(base64Image) {
let curentColorIndex = 0
let commandArray = [];
//For evry pixel in the LED array
//For every pixel in the LED array
for (let i = 0; i < maxi; i++) {
let pixel = ledRGBValues[i];
let r = pixel[0];

View File

@ -7,13 +7,10 @@
<title>Pixel Magic Tool</title>
<!-- <link
rel="shortcut icon"
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAK9JREFUeNqUUssNwyAMJZWVUw4dhRHakZA6RqWMFEbwKDnk1FNBekEWxOBYQggL/D68yXXq+M7PtHkcefn89vrOw/UrP96w/NUFGiDLRz71GyY0QJa1Yn+nFa0ShqUNYCAF0QvoceOB4naEZif6UTNRapYaTyauRi4DEspr4Hbs5YKsbmtMyeJ0LxeESV4gB+hlSy4oO2txWysyus0a0+lO6vBjxcTMlG4mt2H6F2AAhU5NWu4dorQAAAAASUVORK5CYII=
" /> -->
<style>
:root {
--s-thumb: #0006;
--s-background: #0003;
--overlay: rgba(0, 0, 0, 0.5);
--background: #111;
--text: #bbb;
@ -34,6 +31,24 @@
--warning-light: #f48c06;
}
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: var(--s-thumb);
opacity: 0.2;
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--s-background);
}
::selection {
background: var(--blue-light);
}
@ -65,7 +80,7 @@
display: block;
font-weight: 400;
margin: 2px 0 5px;
color: var(--text);
color: var(--gray-light);
font-size: 12px;
}
@ -83,10 +98,19 @@
font-weight: 600;
}
:is(a:hover, a:focus, a:active) {
a:is(:hover, :focus, :active) {
color: var(--blue-medium);
}
#wledEdit {
padding: 4px 8px;
background: var(--blue-light);
margin-left: 6px;
display: inline-block;
border-radius: 4px;
color: var(--gray-light);
}
.m-zero {
margin: 0 !important;
}
@ -108,8 +132,7 @@
}
.content {
width: calc(100% - 40px);
max-width: 768px;
width: min(768px, calc(100% - 40px));
margin: 20px;
}
@ -117,26 +140,43 @@
display: flex;
flex-wrap: nowrap;
justify-content: space-between;
margin: 20px 0 0;
margin-top: 20px;
}
.column {
flex-basis: calc(50% - 10px);
position: relative;
padding: 0 5px;
padding-inline: 5px;
}
.column-full {
flex-basis: 100%;
position: relative;
padding: 0 5px;
padding-inline: 5px;
}
.header {
display: flex;
flex-direction: column;
align-items: center;
padding-bottom: 20px;
}
.header .brand {
width: 100%;
max-width: 200px;
height: 100%;
display: block;
outline: none;
border: 0;
}
label {
display: block;
display: flex;
margin-bottom: 5px;
font-weight: bold;
color: var(--text);
align-items: center;
}
input[type="text"],
@ -157,7 +197,7 @@
width: 32px;
height: 32px;
cursor: pointer;
padding: 0px 1px;
padding-inline: 1px;
outline: none;
}
@ -172,18 +212,19 @@
}
.input-group .input-description {
width: 38px;
width: 100%;
max-width: 38px;
height: 38px;
padding: 10px 0;
display: flex;
justify-content: center;
align-items: center;
color: var(--gray-dark);
background: var(--gray-light);
border-radius: 0px 5px 5px 0;
border-radius: 0px 8px 8px 0;
border: 1px solid var(--gray-light);
border-left: 0;
text-align: center;
font-size: 14px;
line-height: 16px;
font-weight: 600;
}
.input-group .square {
@ -191,10 +232,19 @@
margin-left: 10px;
}
.input-group .square input {
text-align: center;
background: none;
padding: 0;
border: 0;
color: var(--gray-dark);
}
textarea {
resize: vertical;
resize: none;
min-height: 200px;
border-radius: 8px;
overflow-x: hidden;
}
.custom-select {
@ -231,7 +281,7 @@
text-align: center;
padding: 40px 10px;
border-radius: 8px;
margin: 20px 0 0;
margin-top: 20px;
transition: all 0.5s ease-in-out;
}
@ -253,14 +303,15 @@
width: 100%;
border-radius: 10px;
outline: none;
margin: 16px 0;
margin-block: 15px;
}
.range-slider::-webkit-slider-thumb {
.range-slider::-webkit-slider-thumb,
.range-slider::-moz-range-thumb {
appearance: none;
height: 16px;
width: 16px;
background-color: var(--gray-dark);
background-color: var(--blue-light);
border-radius: 50%;
cursor: pointer;
border: 0;
@ -326,7 +377,7 @@
align-items: center;
width: auto;
padding: 6px 12px;
margin: 10px 0 0;
margin-top: 10px;
border-radius: 8px;
transform: translateY(30px);
opacity: 0;
@ -334,7 +385,7 @@
}
.toast .toast-body {
padding: 8px 0;
padding-block: 8px;
font-weight: 600;
color: var(--text);
letter-spacing: 0.5px;
@ -360,7 +411,7 @@
height: 3px;
transform: scaleX(0);
transform-origin: left;
border-radius: inherit;
border-radius: 8px;
}
.toast.success .toast-progress {
@ -387,22 +438,6 @@
);
}
.header {
display: flex;
flex-direction: column;
align-items: center;
padding: 0 0 20px;
}
.header .brand {
width: 100%;
max-width: 200px;
height: 100%;
display: block;
outline: none;
border: 0;
}
.carousel {
display: flex;
height: 100%;
@ -410,18 +445,6 @@
cursor: pointer;
}
.carousel img {
display: block;
width: 100%;
height: 100%;
margin-right: 20px;
border: 0;
}
.carousel img:last-child {
margin-right: 0;
}
.button {
width: 100%;
border: 0;
@ -429,7 +452,7 @@
border-radius: 50px;
color: var(--text);
cursor: pointer;
margin: 0 0 10px;
margin-bottom: 10px;
background: var(--gray-medium);
border: 1px solid var(--gray-dark);
transition: all 0.5s ease-in-out;
@ -477,7 +500,7 @@
}
#recreatedImage {
margin: 20px 0;
margin-block: 20px;
}
.invalid {
@ -487,16 +510,12 @@
.error-message {
display: block;
color: var(--error-dark);
padding: 4px 0;
padding-block: 4px;
font-weight: 600;
font-size: 12px;
}
@media (max-width: 767px) {
.header {
padding-bottom: 0;
}
.row {
flex-wrap: wrap;
flex-direction: column;
@ -506,7 +525,7 @@
.column,
.column-full {
flex-basis: 100%;
margin: 20px 0 0;
margin-top: 20px;
padding: 0;
}
}
@ -542,68 +561,7 @@
<div class="content">
<form id="formGenerate" novalidate>
<div class="header">
<svg
class="brand"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px"
y="0px"
width="200px"
height="130px"
viewBox="0 0 200 130"
enable-background="new 0 0 200 130"
xml:space="preserve">
<image
width="200"
height="130"
x="0"
y="0"
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACCCAQAAACpkk8fAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElN
RQfnBg4TByTFKGw2AAAIWElEQVR42u2d+5GjOBCHf3t1AVBKYAiBDBZHMg7hHMEwETiEsyMxkwEh
cAl0OQPfH+IhgQQIBDRefVu1ZWMhHj20+iUBBN4LSulFL3pRuveZvAd/7X0CAZ0gEGb8WrIzvbpb
xKL+AuEJYcffWxyk/yRVnES+9w0AAMrwBfB4vpcJ5AQgwRUAcEGx98W8A4sEInKA6i8Fj7/2o+Ms
EEoQAXiKYlLr1+DPD0JXUVCKBwDgW2RrXnhzHGa4PyFXpABynKrvRfWp2PtS3oPFg7p4Ivd1MpQC
SKovH5QCKMRz+5uyJw52BaVIAXwiBlDiDiDXxw06y9/ErdmSAYC0YSpy/OA30nZDq7IMCm41O4xi
nAF84Gw6k0NAWRW1av9lnRYPetGLerq5u4/ek6XdJhGyJhLXOZP92MQPGUbe9GCjSTwJhM74RK3/
E3oAuLeKq8cNOYDPSl3IJ+oXdL/mhjv+QFPBQSAiQwbQQ1pZ4qT9GCujQoQUwM9ATyXK+snQtueK
X/Pfn/nMMFBZLlSjViluzWfJTZQj+4y244G7QArl/5YSOYDKaUQBYO6F136NeX9pr+W4oWu72Y83
tR0LnAUiLsatN9wadVZ01Jlb/x79miPCVGVVXgJwE2Xl/wzzSSkUhdQ1yDvtAAAiA0P8CuSOH8xX
Vipxo5xKpJrSaRC/lIjUuWkt+bL0e1Y+Z16v3RNeBTJg6AYmwkplKT5+NNhwwNOhaxMN83deigJd
+x6wEoh5rBCq/yPpezptzCtR2nW8pToz6IyqQFcm5NSZoTwh1kDeYAicIpuKsHvaVaAlrr5a2+ln
AUB/hr5o3t87UOA5tSk90CrQKz2BJUb9OKrKsmXQToO3LLHuZw9mx1r4vblAzW7qIP0fTxHZi0NY
RjlT/6NTn6CymLHPoF7O9sblfqnWVwkMqSDtqZLKaqC18Yi1WnZQdXPZRSAy0DJrzxPQucV3kTl0
4KKsmiM2atR5b3eCymIGLz9kFMOgLm2todz7t/K5nHXYsuqj2duSFfLAwQQyB5Et7qHcLu51GIFU
BXpuRJQCKH0GPChGjNozWaH/wwikKtCT5UdAp4DHgvSRvuf9fVvU0lkJvyzq38xxBCIpRXXxlE4Q
yAE5gEA0JWEjIcAW5PnoBYVG6iHXVktDHEAgmpJokZZPrbhk6dAJOS6IoIeBzr1n6TTimA6pJVnC
JIP8BS7wk5BrOIJAjEjLp6+4ZFU+OffncNwSoCcA4OnfUTyaQGLKoFUPvxtbCkTWIpZOrQvoSkKm
ivJe6EXO3yqa79IyevT6kxSAcf+2bXtEs1q6VAVP3tlSIG61iE1rTUnY6Mzfkt/I2N/4/uNqadp0
pTlMEci1uRlFXZWlZK6jtU7tz0RJIim1TL8tlVCNk6RluLUWbaZbZAg4ozwhIqs/UTahNM3MT9tL
YA4h/M6MIBBmBIEwg4VjqKWdZiV9ZpfAadSTPq1z2CdPQZ00C944Ez88IcwIAmFGEAgzgkCYsfGg
PmEhgEhpM5IW0mILO1Els7okE3ZVEmetsbC1lTVue6i1wmPZaptlZaowtBVJ5EMTuCdwnm3fqYmz
JoTFwuz1jqHC0Bp9YxbsCWMIM4JAmBEEwgy3MSTlsYTR/ijTU2O/PW89qJvjVCxXPxwktWzvrs2q
23YTqi03Fog5OLde0c7ss5y7tlx3bVbt25RqyzCGMCMIhBnmadEfs/szhgOY9HYIpkyLdsEYDmDS
m0refCr7P1rn3m+waO2UQb3Kk3WycvVWDytEKwvFesn8TTjicFbSNvd+rEjbDWPG8D1jWYnBbov2
PqlpvKdArnufwHyClcWMrRNU2UiD3RJNXNhaZfkdstuh+dPiA8vJBFwotTnzuanJoceQ1jexpoZX
mOO04HwnzHcPYwgzgkCYcWiVNYHIrMw4KTKdDQTix/tWUmMub6ey+dxsX93i/HYEj5gsoOTITp0P
9lRZBguIW6pqe8KgzowgEGa8u5VlQQnh5F4trvbtCzNXm+AmEPXtIS5LluXGrb+t1SFfo/tOPZ5e
bH1WWtzm3ABmAhFFG5+yVuOa9stNt3XB9O6x47Vn6TmlFsYQZgSBMCMIhBl7jiEJmcIahZiRwTAX
YExCeceC13fhmq/OQjsm7SmQaK0ht+FmtKC2Cc/MvDpmVpZf5LpXXXiHZ8IYwowgEGYcWmVxmBbt
m0MLZJuy022xCcQlKzeyn1ASW9YpcaOGqleT1COTrs7hOsIYwowgEGYEgTAjCIQZ6qA+WndqZEK9
quUYei997guXhfGDWhtTzLw6B5jaLtOYZ7PZ53wZ11xc4cVfQwSVxYwgEGYc21O3kQxGdJO9T2+I
9xTIavkO5a0QKvf5L5ihBFcuCarFeJlObQoSqZZjqf2SGNNOS6zBTiLr0AJZC/NMJ4vQc/zMm71u
LnMKAlmK5zUbg0Cm02boZVZe6v1ydn8XRH2PKAhkMnWGnjK5OM/SmmBRmPL77yKQfMM9V02LHTp0
sg91wKafalKNYj3gQmd8Nl8UI7nf17s8ITxIrLVYsfLLoJEcnhBnzE+IySiWLYzBzHpxq15fIZbF
jKCyfJE3n7qLwap+/6hBEFSWMxaVFSPGUxSaijrhKQq5YKCuonCRC8raDYTAZOgl/3W2ZvSS9e4U
UUr/Vq0eAKVta0rpH3X/fl9BZXmAYpzb2knxRN4u6FG7kdVv+VipdxCID+KBscHRjQxWFjOCQJgR
BOKDEt/IAaT06q0q+S3nq9dD/hhBIB4QpciagMgHpZS2A7nIcK8+RpRSOpbRD4O6b9Tl0U/a2+LU
tbsutqK7IJAVGciYFHzXtDsc9KKXeeFAelSOXu9XylpHcbivMIYEAkP8DyhqAZcAHYDzAAAAJXRF
WHRkYXRlOmNyZWF0ZQAyMDIzLTA2LTE0VDE5OjA3OjM2KzAwOjAw7raFWwAAACV0RVh0ZGF0ZTpt
b2RpZnkAMjAyMy0wNi0xNFQxOTowNzozNiswMDowMJ/rPecAAAAodEVYdGRhdGU6dGltZXN0YW1w
ADIwMjMtMDYtMTRUMTk6MDc6MzYrMDA6MDDI/hw4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFn
ZVJlYWR5ccllPAAAAABJRU5ErkJggg==" />
</svg>
<img src=" data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACCCAYAAAADm4eUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAACRBJREFUeNrsnYtx6joQhsWdWwBzGsAl0MGBSkILVABUQAtQCU4HLsG3gTN0kGvnyJmNIhnJT9n+vplMEr8f+q1dabVSCgCcrMa+gD9//uyKXw+xaP/r16+UVwMx8A+PAACBAEzLxCpMq49X2xSm1opXBNQgAJHy71xuxKdGMqAx4PvzOxe/TtTe8Qhkr39vi5+rWH4sfjJeDSxaINXXu/hymasyvuywGIEUAihriLX+91kU/qzDY3+02P1RibPOnLD001yK7c8TNqXM+4GRa5DSfNrpv1NhWn3VGMYyzCvAxBKm1lMLJ8YvbeUjSTZiXaavHxBIcOGqClEiViW6teSzNqnzNYrtDmLfvNj2ZtnsIv4+OQ5VnuO9+PktrsnLBHMsP+ifqqFhav5SLp7bRtwLDFiD7BwFNjGW1xWuN8M0u1lqn7MQlEsg7+V2Wpi7pb/w4lmUAjmLDxkCidnEisycUrSgQbQC0WbVm8X23xbrKpPn7jC3XnETNdab8eWU5tRKmE/VdVyN49xpUEAgbarxs6jGH9JUKtbta3ZNHGbQWix/b2Fa5GaNUbN9qrc1V/1HLYNAoJsa8Syd46rmM5Z/q+W0kNucp/XxYFiBZI6/beTCDPrWwSj2HfqFm/00Iec3GyRuluXK2KbJ/XV9PBhKIMUX7Biw7a0qRIZplr0wzfq8/ij7aQATK0aTKTGc+08Txuj3acOb8I9+mEc1ppTP8UwfESYukLtwyGMxExKL2ZQrd7+Pq1ZaicYC2YJ2eGEenQKv9+BYjkCmLpCGTbkAmFgDmVO2UJN1i0M26ssp9rmqn/FgkzE/Ech88fYpavp9THFVy119ObZRjlvH8Wr7lMwRgiOan5OGMekAoTWIT0+zQeOw7+Jc61AToklPthHGkphf4w6faeZRC51qgiv7oryuzkPzhdlomp/XYt1Tv6/9rASiwkectQn73jY4X5OEAomrwNpeYE1L0yvxHkXh+YjoXR97CpHZ1bzXyYOJBYCT/kmuhu8RTz2+tLlwZpuaqR8eZtWz53s0TeWsx3MikK6RYSwDnnPvUYjvPfZsH/uOPK7u0WKKHucQ9YyJBUANMg6eTrps0Wqa7fFSY74NacJe6s4dODYIgUBnZs45gmsoBXGe27NFIN3XGnIcS5+sRX9VHmtYhw5BSYQjP6nrRyDdIxPllS/9bqzvKtWO7D+6DPn1DjSVyns9xXT9CCQectP8IdUOJtYSzSqXGRFcK4gkESHhOxuP8KBWWSCnbiohkHFxmRHWWkW5MxvK9EJV+M5RFEifbI8u2maBbGoq3cR5Zeh+pu+teiYIBMIzG8ps+JYURFO531xfv6zBnlPoSEQg/SJzEeeMksTEioWyIN57qr7lsbMXZkQizJJUvQ51kbNrZQ4zSb0wt+T1ffNBPO6tbnavLkwlaS4+Ech49Jn98Mexa8yIUGpn15LrasytNvfuPH8XplKXkydNTSBXS8HIzJxYjvHVawUQKdaBR478S6Hza/zoQKoZr+08hrKM3yavE4xag9gK4Ejza7wjBhgTwt0BEAgAAgEYxgdZIjWDmwYb2DNCsjcn5tzxDeZX33fd1N7hHO/ec91TgwAgEAAEAoBAAHDSu3Xq2rJ2HKfV4KCaaIVFYQzEekVX6Uw3jpm30kUJRHXT4uHKHdx2HHVoa5VvpsLQpBFloXgf8R0d1PAtdwdlH4ezWppA5oRXpsIG8W6E8+CDACAQAAQCMCR9+iC7yCaQgZFxTIyaLFUgMRASQ/WgCPfOLnD7ujHyJXUtdp1ksJy1QEKC5aaYUmeEZ7ka+LTZi3eY1rzPXRcCwQcBQCAAHZpYjtCKzQjX5x0SwLXBkE56LA7rQXmGBHBtXtjEm3v6aKHz2bdKlh27QELZG0nNzsodX2Nuu4tBkOYIOo/7mKKj3WZkZOh89m2TZfeJ94hCYrGmw9azpY1EfBHWINA/Vx7B8NCKBbDUGsQxKCmE3xQRBDJnYnawbQ7zmwrr/ZVTD8B3cuWePz5FIJFj6y9pMET4Sb+L8/mWAmlrQeCDACAQAHyQRbIOMcswxxYqkJh6vB2DxC49JUYI7d1eUeQjEIguDOeI79u39acsgHTQIZDF8fRMoUMJwUkHAAQCgIkFL0xGm1+YRty69WZppStzIt8QSCS+irKHJYTmv/UlpKCGTstdcurgvF3fX6LcqX8OjmMgkBgovlRla9fe8iV+qB6mxNZfcq/COtK03G3vb++4j2hj5vBBABAIAAIBwAfpiK0jT6yNMjvHIGMuQpJddMipOO/J4i+sZvDuWvtISxXIemoOroWb8m99mlPIzKDvjlasiaIHBOWeNRMPDB8EAIEA4KQvAaaBRiBQz4lHMD+BXAaeMtjrfK4BWg2mgGvdlBpx82iUdPjuenkf+CAACAQAgQAgEIAYnPTWOU0DyHs836XBtfhwL37eKT6fuDLEZAO/u16gxWUkhmxhazKLl9n6U3OMtOXMVZhYAAgEYEE+CMTHtkVU7pbHh0DmzuTGcxSCvgaI8z5kOh9xjV9jZRgwFRERTTvtGz6UK3vLUv6i5tp5XsdYrYK1A7AQCPgKuhSCj5BChZ5qcaQD1hreaZsQCIzN+8ABsPggMDo3S40gx8XvPU20vjhq0+qBQGAscyw3TK6NWJ+OfH2Zvi5qkImRzvSckx0chkDi+vKmI4kkOlxNxHVhLcU+B/V3rnmTxk3ICARiJaSJuCJx7NO4CZlgRRiiNvgwaoFVzbZnH5NMHiMgGPNbwKfPdRGLBYCJBRPC5oOVLWCHmn1yZe/lPyEQmBu5FslTNMfuTIHoZdU2XzOBGSaUKZDPgM+QZmZMLIiNg/YnZHBmNdPXTSyT22z1/6YfUu4jRzteVeDAMWoQiMWRT7Q4flsc8s8awjKh549OSGO/tG3ibgQCsZA09Bl67YTExAJAIAAIBKZNrv421ab6/13ZkefIgi+5SOdd7/NAIDAryghgPS7EDAvZlM65dtA3lv3Kfe7G4rXYp9V4fJx0iJ2DsncSlk24T8c+VbOvSdnkmyEQWEKNkzbYLRt7LArAD7Rf8GHrx6jZ5yH289q39FeMfR5trwsfBAAAmvG/AAMAhiHUfzRdo4IAAAAASUVORK5CYII=" alt="Pixel Magic Tool" class="brand">
</div>
<div class="row">
<div class="column" validate>
@ -626,11 +584,11 @@
<label for="pattern">Pattern</label>
<select name="pattern" id="pattern" required>
<option value="">Select a choice</option>
<option value="1" title="['ffffff']" selected>
Individual
</option>
<option value="1" title="['ffffff']">Individual</option>
<option value="2" title="[0, 'ffffff']">Index</option>
<option value="3" title="[0, 5, 'ffffff']">Range</option>
<option value="3" title="[0, 5, 'ffffff']" selected>
Range
</option>
</select>
</div>
</div>
@ -686,11 +644,13 @@
max="255"
value="128"
class="range-slider" />
<input
type="text"
id="brightnessValue"
class="input-description square"
value="128" />
<div class="input-description square">
<input
type="text"
name="brightnessValue"
id="brightnessValue"
value="128" />
</div>
</div>
</div>
</div>
@ -698,7 +658,11 @@
<div class="column" validate>
<label for="animation">Animation</label>
<label class="switch">
<input type="checkbox" name="animation" id="animation" />
<input
type="checkbox"
name="animation"
id="animation"
data-parent="animation" />
<span class="switch-slider"></span>
</label>
</div>
@ -708,19 +672,25 @@
<input
type="checkbox"
name="transparentImage"
id="transparentImage" />
id="transparentImage"
data-parent="transparentImage" />
<span class="switch-slider"></span>
</label>
</div>
<div class="column" validate>
<label for="resizeImage">Resize Image</label>
<label class="switch">
<input type="checkbox" name="resizeImage" id="resizeImage" />
<input
type="checkbox"
name="resizeImage"
id="resizeImage"
data-parent="resizeImage"
checked />
<span class="switch-slider"></span>
</label>
</div>
</div>
<div class="row resizeImage" style="display: none">
<div class="row resizeImage">
<div class="column" validate>
<label for="width">Width</label>
<input type="number" name="width" id="width" value="16" />
@ -747,7 +717,9 @@
min="0"
step="0.1"
inputmode="numeric" />
<div class="input-description">sec</div>
<div class="input-description">
<span>sec</span>
</div>
</div>
</div>
<div class="column" validate>
@ -762,7 +734,9 @@
min="0"
step="0.1"
inputmode="numeric" />
<div class="input-description">sec</div>
<div class="input-description">
<span>sec</span>
</div>
</div>
</div>
</div>
@ -773,30 +747,27 @@
Color that will replace the
<strong>transparent pixels</strong> in the image
</small>
<input type="color" name="color" id="color" value="#eeeeee" />
<input type="color" name="color" id="color" value="#00BFFF" />
</div>
</div>
<div class="row">
<div class="column-full" validate>
<div class="custom-select">
<label for="images">Images</label>
<select name="images" id="images" required>
<option value="">Select a choice</option>
<option value="upload">Upload</option>
<label for="images">
<span>Images upload to WLED</span>
<a id="wledEdit" href="http://[wled-ip]/edit" target="_blank">
upload
</a>
</label>
<select name="images" id="images">
<option value="">Select image</option>
</select>
</div>
<small>
Images uploaded to
<a id="wledEdit" href="http://[wled-ip]/edit" target="_blank">
<strong>WLED</strong>
</a>
or upload image
</small>
</div>
</div>
<div id="dropzone" class="dropzone" validate style="display: none">
<div id="dropzone" class="dropzone" validate>
<p id="dropzoneLabel">
Drag and drop a file here or click to select a file
Drag and drop a file here or click to select a local file
</p>
<input
type="file"
@ -868,7 +839,7 @@
const hostname = element("hostname");
hostname.value = host;
hostname.addEventListener("change", async () => {
hostname.addEventListener("blur", async () => {
WLED_URL = `${protocol}//${hostname.value}`;
await segments();
@ -893,7 +864,7 @@
function hostnameLabel() {
const link = element("wledEdit");
link.href = link.href.replace("[wled-ip]", hostname.value);
link.href = WLED_URL + "/edit";
}
async function playlist() {
@ -999,6 +970,7 @@
if (success) {
toast(`Preset "${item.n}" save successfully`);
window.parent.postMessage("loadPresets", WLED_URL);
}
} catch (error) {
toast(`Error saving preset: ${error}`, "error");
@ -1047,12 +1019,9 @@
return mimeTypes.includes(mimetype);
});
const options = [
{ text: "Select a choice", value: "" },
{ text: "Upload", value: "upload" },
];
const options = [{ text: "Select image", value: "" }];
if (images) {
if (images.length > 0) {
options.push(
...images.map(({ name }) => ({
text: name,
@ -1064,6 +1033,11 @@
options.forEach(({ text, value }) => {
const option = new Option(text, value);
if (index === 0) {
option.selected = true;
}
select.appendChild(option);
});
}
@ -1076,7 +1050,6 @@
async function segments() {
const select = element("segments");
const pattern = element("pattern");
const width = element("width");
const height = element("height");
@ -1114,7 +1087,6 @@
option.selected = true;
width.value = w;
height.value = h;
pattern.value = w * h > 512 ? 3 : 1;
}
select.add(option);
@ -1278,12 +1250,12 @@
const dropzone = element("dropzone");
const { value } = e.target.selectedOptions[0];
if (value === "upload") {
if (!value) {
const dropzoneLabel = element("dropzoneLabel");
const source = element("source");
dropzoneLabel.textContent =
"Drag and drop a file here or click to select a file";
"Drag and drop a file here or click to select a local file";
source.value = "";
dropzone.style.display = "block";
@ -1293,62 +1265,51 @@
});
element("transparentImage").addEventListener("change", (e) => {
const transparentImage = d.getElementsByClassName("transparentImage");
const transparentImage = d.getElementsByClassName("transparentImage")[0];
const { checked } = e.target;
Array.from(transparentImage).forEach(function (element) {
if (checked) {
element.style.display = "flex";
} else {
element.style.display = "none";
}
});
if (checked) {
transparentImage.style.display = "flex";
} else {
transparentImage.style.display = "none";
}
});
element("resizeImage").addEventListener("change", (e) => {
const resizeImage = d.getElementsByClassName("resizeImage");
const resizeImage = d.getElementsByClassName("resizeImage")[0];
const pattern = element("pattern");
const { checked } = e.target;
Array.from(resizeImage).forEach(function (element) {
if (checked) {
pattern.value = 3;
element.style.display = "flex";
} else {
pattern.value = 1;
element.style.display = "none";
}
});
if (checked) {
resizeImage.style.display = "flex";
} else {
resizeImage.style.display = "none";
}
});
element("animation").addEventListener("change", (e) => {
const animation = d.getElementsByClassName("animation");
const animation = d.getElementsByClassName("animation")[0];
const pattern = element("pattern");
const source = element("source");
const { checked } = e.target;
Array.from(animation).forEach(function (element) {
if (checked) {
toast(
'If you want all frames in the image, set it to "0"',
"warning",
5000
);
if (checked) {
toast(
'If you want all frames in the image, set it to "0"',
"warning",
5000
);
source.setAttribute("accept", "image/gif");
element.style.display = "flex";
pattern.value = 3;
} else {
source.setAttribute(
"accept",
"image/jpg,image/jpeg,image/png,image/gif"
);
element.style.display = "none";
pattern.value = 1;
}
});
source.setAttribute("accept", "image/gif");
animation.style.display = "flex";
} else {
source.setAttribute(
"accept",
"image/jpg,image/jpeg,image/png,image/gif"
);
animation.style.display = "none";
}
});
element("btnGenerate").addEventListener("click", async (event) => {
@ -1402,8 +1363,7 @@
const response = element("response");
const recreatedImage = element("recreatedImage");
const urlImage =
images === "upload" ? URL.createObjectURL(file) : images;
const urlImage = !images ? URL.createObjectURL(file) : images;
const image = await loadImage(urlImage);
const { canvas, bri, id, i } = recreate(image);

View File

@ -80,7 +80,7 @@
<button type=submit id="b" onclick="window.location=getURL('/')">Back</button>
<button type="submit" onclick="window.location=getURL('/settings/wifi')">WiFi Setup</button>
<button type="submit" onclick="window.location=getURL('/settings/leds')">LED Preferences</button>
<button id="2dbtn" style="display:none;" type="submit" onclick="window.location=getURL('/settings/2D')">2D Configuration</button>
<button id="2dbtn" type="submit" onclick="window.location=getURL('/settings/2D')">2D Configuration</button>
<button type="submit" onclick="window.location=getURL('/settings/ui')">User Interface</button>
<button id="dmxbtn" style="display:none;" type="submit" onclick="window.location=getURL('/settings/dmx')">DMX Output</button>
<button type="submit" onclick="window.location=getURL('/settings/sync')">Sync Interfaces</button>

View File

@ -26,8 +26,8 @@
// success event
scE.addEventListener("load", () => {
GetV();
checkSi();
setABL();
checkSi();
d.Sf.addEventListener("submit", trySubmit);
if (d.um_p[0]==-1) d.um_p.shift();
pinDropdowns();
@ -773,6 +773,7 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
Brightness factor: <input name="BF" type="number" class="m" min="1" max="255" required> %
<h3>Transitions</h3>
Crossfade: <input type="checkbox" name="TF"><br>
Effect blending: <input type="checkbox" name="EB"><br>
Transition Time: <input name="TD" type="number" class="xl" min="0" max="65500"> ms<br>
Enable Palette transitions: <input type="checkbox" name="PF"><br>
<i>Random Cycle</i> Palette Time: <input name="TP" type="number" class="m" min="1" max="255"> s<br>

View File

@ -181,8 +181,8 @@
<option value="6">US-MST/MDT</option>
<option value="7">US-AZ</option>
<option value="8">US-PST/PDT</option>
<option value="9">CST(AWST)</option>
<option value="10">JST(KST)</option>
<option value="9">CST (AWST, PHST)</option>
<option value="10">JST (KST)</option>
<option value="11">AEST/AEDT</option>
<option value="12">NZST/NZDT</option>
<option value="13">North Korea</option>

View File

@ -26,7 +26,8 @@
"segexp" : "Always expand first segment",
"css": "Enable custom CSS",
"hdays": "Enable custom Holidays list",
"fxdef": "Use effect default parameters"
"fxdef": "Use effect default parameters",
"idsort": "Sort presets by ID"
},
"theme":{
"alpha": {
@ -277,6 +278,8 @@
<span class="l"></span>: <input type="checkbox" id="comp_seglen" class="agi cb"><br>
<span class="l"></span>: <input type="checkbox" id="comp_segpwr" class="agi cb"><br>
<span class="l"></span>: <input type="checkbox" id="comp_segexp" class="agi cb"><br>
<span class="l"></span>: <input type="checkbox" id="comp_fxdef" class="agi cb"><br>
<span class="l"></span>: <input type="checkbox" id="comp_idsort" class="agi cb"><br>
I hate dark mode: <input type="checkbox" id="dm" onchange="UI()"><br>
<span id="idonthateyou" style="display:none"><i>Why would you? </i>&#x1F97A;<br></span>
<span class="l"></span>: <input type="number" min=0.0 max=1.0 step=0.01 id="theme_alpha_tab" class="agi"><br>

View File

@ -32,7 +32,7 @@
).reduce(
// Filter out duplicate SSIDs. Since it is sorted by signal
// strength, the strongest signal will be kept in the
// order it orginally appeared in the array.
// order it as originally appeared in the array.
(unique, other) => {
if(!unique.some(obj => obj.ssid === other.ssid)) {
unique.push(other);

View File

@ -964,7 +964,7 @@ function readState(s,command=false)
errstr = "Missing IR.json.";
break;
case 19:
errstr = "A filesystem error has occured.";
errstr = "A filesystem error has occurred.";
break;
}
showToast('Error ' + s.error + ": " + errstr, true);

View File

@ -63,7 +63,8 @@ class NeoGammaWLEDMethod {
#define gamma32(c) NeoGammaWLEDMethod::Correct32(c)
#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c)
uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false);
uint32_t color_add(uint32_t,uint32_t);
uint32_t color_add(uint32_t,uint32_t, bool fast=false);
uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false);
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
void colorKtoRGB(uint16_t kelvin, byte* rgb);
@ -353,6 +354,7 @@ void checkSettingsPIN(const char *pin);
uint16_t crc16(const unsigned char* data_p, size_t length);
um_data_t* simulateSound(uint8_t simulationId);
void enumerateLedmaps();
uint8_t get_random_wheel_index(uint8_t pos);
#ifdef WLED_ADD_EEPROM_SUPPORT
//wled_eeprom.cpp

View File

@ -41,47 +41,47 @@ const char PAGE_dmxmap[] PROGMEM = R"=====()=====";
#endif
// Autogenerated from wled00/data/update.htm, do not edit!!
const uint16_t PAGE_update_length = 613;
const uint16_t PAGE_update_length = 616;
const uint8_t PAGE_update[] PROGMEM = {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a, 0x75, 0x53, 0x5d, 0x6f, 0xd4, 0x30,
0x10, 0x7c, 0xcf, 0xaf, 0x70, 0xfd, 0x74, 0x27, 0x51, 0xbb, 0x20, 0x5e, 0x28, 0x49, 0x0a, 0x47,
0x10, 0x7c, 0xcf, 0xaf, 0x70, 0xfd, 0x74, 0x27, 0x71, 0x36, 0x45, 0xbc, 0x50, 0x92, 0x14, 0x4a,
0x2b, 0x54, 0x09, 0xa9, 0x95, 0xda, 0x82, 0x78, 0x42, 0x8e, 0xbd, 0xb9, 0x98, 0x73, 0xec, 0xd4,
0xde, 0xdc, 0xe9, 0x84, 0xfa, 0xdf, 0xd9, 0x38, 0x77, 0x05, 0xf1, 0xf1, 0x12, 0xc5, 0xd9, 0xd9,
0xf1, 0xee, 0xcc, 0xa4, 0x3c, 0xb9, 0xbc, 0xf9, 0x70, 0xff, 0xf5, 0xf6, 0x8a, 0x75, 0xd8, 0xbb,
0xba, 0x3c, 0x3c, 0x41, 0x99, 0xba, 0xec, 0x01, 0x15, 0xd3, 0xc1, 0x23, 0x78, 0xac, 0xf8, 0xce,
0x1a, 0xec, 0x2a, 0x03, 0x5b, 0xab, 0xe1, 0x34, 0x1f, 0x38, 0xf3, 0xaa, 0x87, 0x8a, 0x6f, 0x2d,
0xec, 0x86, 0x10, 0x91, 0xd7, 0x45, 0x89, 0x16, 0x1d, 0xd4, 0x5f, 0x3e, 0x5d, 0x5d, 0xb2, 0x87,
0xc1, 0x28, 0x84, 0x52, 0xce, 0x9f, 0xca, 0xa4, 0xa3, 0x1d, 0xb0, 0x2e, 0xda, 0xd1, 0x6b, 0xb4,
0xc1, 0xb3, 0xd5, 0x62, 0xf9, 0x63, 0x67, 0xbd, 0x09, 0x3b, 0xd1, 0xd9, 0x84, 0x21, 0xee, 0x45,
0x1a, 0xec, 0x2a, 0x03, 0x5b, 0xab, 0x61, 0x95, 0x0f, 0x9c, 0x79, 0xd5, 0x43, 0xc5, 0xb7, 0x16,
0x76, 0x43, 0x88, 0xc8, 0xeb, 0xa2, 0x44, 0x8b, 0x0e, 0xea, 0x2f, 0x9f, 0xae, 0x2e, 0xd9, 0xc3,
0x60, 0x14, 0x42, 0x29, 0xe7, 0x4f, 0x65, 0xd2, 0xd1, 0x0e, 0x58, 0x17, 0xed, 0xe8, 0x35, 0xda,
0xe0, 0xd9, 0xc5, 0x62, 0xf9, 0x63, 0x67, 0xbd, 0x09, 0x3b, 0xd1, 0xd9, 0x84, 0x21, 0xee, 0x45,
0xa3, 0xf4, 0x66, 0xb1, 0x7c, 0x7a, 0x86, 0x3c, 0x10, 0xc4, 0x04, 0x3d, 0xf6, 0x34, 0x81, 0x58,
0x03, 0x5e, 0x39, 0x98, 0x5e, 0x57, 0xfb, 0x6b, 0xb3, 0xe0, 0x63, 0xcb, 0x97, 0x22, 0xe1, 0xde,
0x81, 0x30, 0x36, 0x0d, 0x4e, 0xed, 0x2b, 0xee, 0x83, 0x07, 0xfe, 0xe2, 0xbf, 0x2d, 0x7d, 0x5a,
0xff, 0xdd, 0xd3, 0xb8, 0xa0, 0x37, 0xfc, 0xa9, 0x28, 0xe5, 0x61, 0xc4, 0xc3, 0xa8, 0x2c, 0x45,
0x5d, 0x71, 0x99, 0x00, 0xd1, 0xfa, 0x75, 0x92, 0x49, 0x7c, 0x4f, 0x17, 0x43, 0xf5, 0x86, 0xd7,
0xbf, 0x21, 0x27, 0xaa, 0xba, 0x78, 0x67, 0xfb, 0x49, 0x00, 0x36, 0x46, 0xb7, 0xe0, 0x33, 0xbd,
0x4e, 0x89, 0x2f, 0xdf, 0x12, 0x32, 0x23, 0x4a, 0x39, 0x4b, 0xda, 0x04, 0xb3, 0x67, 0xc1, 0xbb,
0xa0, 0x4c, 0xc5, 0x3f, 0x02, 0x7e, 0x5e, 0x2c, 0x89, 0xae, 0x7b, 0x55, 0x17, 0x59, 0xb2, 0xbb,
0xd0, 0xe2, 0x4e, 0x45, 0x78, 0xd6, 0x8e, 0x2a, 0x65, 0x1b, 0x62, 0xcf, 0xc8, 0x8b, 0x2e, 0x50,
0xcf, 0xed, 0xcd, 0xdd, 0x3d, 0x67, 0x2a, 0xcb, 0x53, 0x71, 0x21, 0xc7, 0x0c, 0xe4, 0xcc, 0x52,
0x8d, 0x04, 0x61, 0x05, 0x90, 0x74, 0xfb, 0x81, 0x5c, 0xe9, 0x47, 0x87, 0x76, 0x50, 0x11, 0xe5,
0x44, 0x70, 0x4a, 0x30, 0xc5, 0xe9, 0xea, 0x34, 0x36, 0xbd, 0x25, 0x3b, 0x1f, 0xa6, 0x9b, 0xaf,
0x7d, 0x42, 0xe5, 0x1c, 0x18, 0xb6, 0x85, 0x98, 0x88, 0xf2, 0x9c, 0x95, 0x69, 0x50, 0x9e, 0x15,
0xda, 0xa9, 0x94, 0x2a, 0x9e, 0xec, 0xc0, 0xeb, 0x33, 0xf1, 0xf2, 0xb5, 0x38, 0xa3, 0x55, 0xa8,
0x42, 0x2b, 0xc4, 0xfa, 0x32, 0xec, 0xf2, 0x0a, 0x0c, 0x3b, 0x60, 0x8e, 0xee, 0x4f, 0xc8, 0x1a,
0xeb, 0x55, 0xdc, 0x53, 0xbf, 0x62, 0x45, 0x17, 0xa1, 0xad, 0x78, 0x87, 0x38, 0xa4, 0x73, 0x29,
0xd7, 0x16, 0xbb, 0xb1, 0x11, 0x3a, 0xf4, 0xf2, 0xbd, 0x8d, 0x3a, 0x84, 0xb0, 0xb1, 0x20, 0xa7,
0x7d, 0x65, 0x04, 0x07, 0x2a, 0x41, 0xe2, 0x0c, 0x55, 0x24, 0xb3, 0x2a, 0xfe, 0xad, 0x71, 0xca,
0x6f, 0x48, 0x13, 0xdb, 0xaf, 0x59, 0x91, 0x1d, 0x38, 0xf2, 0xd0, 0x17, 0x91, 0x3a, 0x0b, 0xce,
0x24, 0x61, 0xc3, 0x81, 0xf6, 0x48, 0xf1, 0x27, 0xb5, 0x48, 0xdb, 0xf5, 0x45, 0xd6, 0xbe, 0x6a,
0x69, 0xc2, 0xd3, 0xf4, 0x38, 0x92, 0xae, 0x53, 0x42, 0xa5, 0xca, 0x3b, 0x94, 0xd6, 0x0f, 0x23,
0xb2, 0x59, 0xab, 0xd6, 0x3a, 0x38, 0xa6, 0xf9, 0xa8, 0x68, 0x84, 0xc7, 0xd1, 0x46, 0x30, 0x33,
0xba, 0x19, 0x11, 0x29, 0x90, 0x33, 0x7c, 0xd6, 0x90, 0xc8, 0x66, 0x9b, 0x4e, 0x4a, 0x39, 0x97,
0xff, 0x01, 0x9d, 0x0f, 0x93, 0xf0, 0xda, 0x59, 0xbd, 0xa9, 0xf8, 0x6a, 0xd2, 0x7d, 0x45, 0x39,
0xff, 0xd5, 0x94, 0x0d, 0xaa, 0x4b, 0x63, 0xb7, 0x45, 0xf6, 0x71, 0x4a, 0x29, 0xd1, 0xd4, 0x99,
0x9d, 0xa2, 0x27, 0x84, 0x20, 0x70, 0x26, 0xbf, 0xcd, 0xcb, 0x32, 0x13, 0x98, 0x0f, 0xc8, 0xb4,
0x0b, 0x74, 0x08, 0x91, 0x66, 0x6d, 0x23, 0xa4, 0x2e, 0xfb, 0x31, 0xa8, 0x35, 0xb0, 0xf3, 0x65,
0x29, 0x89, 0x6f, 0x5a, 0x77, 0x8a, 0xdc, 0x94, 0xbf, 0xe9, 0xc7, 0xfe, 0x09, 0x45, 0xc9, 0x0d,
0xd4, 0xee, 0x03, 0x00, 0x00
0x03, 0x5e, 0x39, 0x98, 0x5e, 0x2f, 0xf6, 0xd7, 0x66, 0xc1, 0xc7, 0x96, 0x2f, 0x45, 0xc2, 0xbd,
0x03, 0x61, 0x6c, 0x1a, 0x9c, 0xda, 0x57, 0xdc, 0x07, 0x0f, 0xfc, 0xc5, 0x7f, 0x5b, 0xfa, 0xb4,
0xfe, 0xbb, 0xa7, 0x71, 0x41, 0x6f, 0xf8, 0x53, 0x51, 0xca, 0xc3, 0x88, 0x87, 0x51, 0x59, 0x8a,
0xba, 0xe2, 0x32, 0x01, 0xa2, 0xf5, 0xeb, 0x24, 0x93, 0xf8, 0x9e, 0xce, 0x87, 0xea, 0x0d, 0xaf,
0x7f, 0x43, 0x4e, 0x54, 0x75, 0xf1, 0xce, 0xf6, 0x93, 0x00, 0x6c, 0x8c, 0x6e, 0xc1, 0x67, 0x7a,
0x9d, 0x12, 0x5f, 0xbe, 0x25, 0x64, 0x46, 0x94, 0x72, 0x96, 0xb4, 0x09, 0x66, 0xcf, 0x82, 0x77,
0x41, 0x99, 0x8a, 0x7f, 0x04, 0xfc, 0xbc, 0x58, 0x12, 0x5d, 0xf7, 0xaa, 0x2e, 0xb2, 0x64, 0x77,
0xa1, 0xc5, 0x9d, 0x8a, 0xf0, 0xac, 0x1d, 0x55, 0xca, 0x36, 0xc4, 0x9e, 0x91, 0x17, 0x5d, 0xa0,
0x9e, 0xdb, 0x9b, 0xbb, 0x7b, 0xce, 0x54, 0x96, 0xa7, 0xe2, 0x42, 0x8e, 0x19, 0xc8, 0x99, 0xa5,
0x1a, 0x09, 0xc2, 0x0a, 0x20, 0xe9, 0xf6, 0x03, 0xb9, 0xd2, 0x8f, 0x0e, 0xed, 0xa0, 0x22, 0xca,
0x89, 0x60, 0x45, 0x30, 0xc5, 0xe9, 0xea, 0x34, 0x36, 0xbd, 0x25, 0x3b, 0x1f, 0xa6, 0x9b, 0xaf,
0x7d, 0x42, 0xe5, 0x1c, 0x18, 0xb6, 0x85, 0x98, 0x88, 0xf2, 0x8c, 0x95, 0x69, 0x50, 0x9e, 0x15,
0xda, 0xa9, 0x94, 0x2a, 0x9e, 0xec, 0xc0, 0xeb, 0x97, 0xe2, 0xf4, 0xb5, 0x38, 0x5d, 0x35, 0xa7,
0xb4, 0x0d, 0x15, 0x69, 0x8b, 0x58, 0x5f, 0x86, 0x5d, 0xde, 0x82, 0x61, 0x07, 0xcc, 0xd1, 0x08,
0x09, 0x59, 0x63, 0xbd, 0x8a, 0x7b, 0xa2, 0x50, 0xac, 0xe8, 0x22, 0xb4, 0x15, 0xef, 0x10, 0x87,
0x74, 0x26, 0xe5, 0xda, 0x62, 0x37, 0x36, 0x42, 0x87, 0x5e, 0xbe, 0xb7, 0x51, 0x87, 0x10, 0x36,
0x16, 0xe4, 0xb4, 0xb2, 0x8c, 0xe0, 0x40, 0x25, 0x48, 0x9c, 0xa1, 0x8a, 0xe4, 0x57, 0xc5, 0xbf,
0x35, 0x4e, 0xf9, 0x0d, 0xc9, 0x62, 0xfb, 0x35, 0x2b, 0xb2, 0x09, 0x47, 0x1e, 0xfa, 0x22, 0x52,
0x67, 0xc1, 0x99, 0x24, 0x6c, 0x38, 0xd0, 0x1e, 0x29, 0xfe, 0xa4, 0x16, 0x69, 0xbb, 0x3e, 0xcf,
0xf2, 0x57, 0x2d, 0x4d, 0xb8, 0x4a, 0x8f, 0x23, 0x49, 0x3b, 0x85, 0x54, 0xaa, 0xbc, 0x43, 0x69,
0xfd, 0x30, 0x22, 0x9b, 0xe5, 0x6a, 0xad, 0x83, 0x63, 0xa0, 0x8f, 0xa2, 0x46, 0x78, 0x1c, 0x6d,
0x04, 0x33, 0xa3, 0x9b, 0x11, 0x91, 0x32, 0x39, 0xc3, 0x67, 0x19, 0x89, 0x6c, 0x76, 0xea, 0xa4,
0x94, 0x73, 0xf9, 0x1f, 0xd0, 0xf9, 0x30, 0x69, 0xaf, 0x9d, 0xd5, 0x9b, 0x8a, 0x5f, 0x4c, 0xd2,
0x5f, 0x50, 0xd4, 0x7f, 0x35, 0x65, 0x8f, 0xea, 0xd2, 0xd8, 0x6d, 0x91, 0xad, 0x9c, 0x82, 0x4a,
0x34, 0x75, 0x66, 0xa7, 0xf4, 0x09, 0x21, 0x08, 0x9c, 0xc9, 0x6f, 0xf3, 0xb2, 0xcc, 0x04, 0xe6,
0x03, 0x32, 0xed, 0x02, 0x1d, 0x42, 0xa4, 0x59, 0xdb, 0x08, 0xa9, 0xcb, 0x7e, 0x0c, 0x6a, 0x0d,
0xec, 0x6c, 0x59, 0x4a, 0xe2, 0x9b, 0xd6, 0x9d, 0x52, 0x37, 0x45, 0x70, 0xfa, 0xb7, 0x7f, 0x02,
0x7b, 0x93, 0x33, 0x90, 0xf1, 0x03, 0x00, 0x00
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -986,157 +986,157 @@ const uint8_t PAGE_simple[] PROGMEM = {
0xd8, 0xeb, 0x27, 0xe8, 0x67, 0xa3, 0x30, 0x96, 0xd0, 0x91, 0x46, 0x24, 0xc1, 0x22, 0xf0, 0x62,
0x55, 0x72, 0xb5, 0xe0, 0xfa, 0x42, 0xda, 0x82, 0xe7, 0xba, 0x8d, 0x94, 0xc9, 0x63, 0x99, 0x33,
0xcd, 0x71, 0xf0, 0x23, 0x1b, 0x47, 0xd7, 0xd4, 0xd5, 0x19, 0x2b, 0x52, 0xc5, 0x22, 0xcd, 0x50,
0xcf, 0x12, 0x74, 0x18, 0x09, 0xb0, 0xa5, 0x12, 0xa6, 0x02, 0x0b, 0x0d, 0xbd, 0xc6, 0xf3, 0x10,
0xf5, 0x52, 0x5e, 0x41, 0xb7, 0x2a, 0x69, 0xc1, 0x14, 0x57, 0x83, 0x17, 0x95, 0xc6, 0x1c, 0x85,
0xef, 0xb2, 0x30, 0x40, 0x04, 0xe8, 0xe1, 0xab, 0x2e, 0x8c, 0x74, 0x77, 0x12, 0x0e, 0x3f, 0x42,
0xfc, 0x85, 0x38, 0x51, 0xb6, 0x1e, 0x62, 0x3b, 0x8b, 0x88, 0xff, 0x50, 0xa4, 0xe4, 0x9f, 0x33,
0xcf, 0x2f, 0xe4, 0xf7, 0xef, 0xa0, 0x09, 0x7e, 0x16, 0x92, 0x2f, 0xbf, 0x7f, 0x87, 0x45, 0x4f,
0x38, 0x1a, 0x3d, 0x1a, 0xcb, 0x25, 0xe4, 0x49, 0x9e, 0xf7, 0xbd, 0x69, 0x94, 0x11, 0x9b, 0x8d,
0x8f, 0x83, 0xcb, 0xd1, 0xcf, 0xb4, 0xc3, 0x59, 0x20, 0x40, 0x39, 0xe6, 0xa0, 0xc6, 0x23, 0xfa,
0x49, 0x8c, 0x5d, 0x46, 0x1e, 0x05, 0x6d, 0x83, 0xc1, 0xd5, 0x60, 0xce, 0x67, 0xdc, 0x49, 0x0f,
0x87, 0x58, 0xa3, 0x8c, 0x4b, 0x1b, 0xe6, 0x38, 0xc9, 0x63, 0x38, 0x06, 0x35, 0x06, 0x62, 0xd1,
0xb1, 0x28, 0x76, 0xbd, 0xd8, 0xab, 0x2c, 0x5e, 0xb6, 0x90, 0xc4, 0xbb, 0x48, 0x60, 0x21, 0x99,
0x3b, 0x3e, 0xb7, 0x87, 0xd1, 0x7d, 0x9b, 0x71, 0x23, 0x8e, 0x31, 0xfc, 0x6f, 0x7c, 0x0d, 0x83,
0x4c, 0xb1, 0xe5, 0x88, 0xd8, 0x08, 0x61, 0x59, 0xc8, 0xa1, 0x37, 0x64, 0x95, 0xbb, 0xdd, 0xd1,
0x42, 0xbe, 0x76, 0x47, 0xc0, 0x13, 0x7c, 0x04, 0x2f, 0xe3, 0xc0, 0xb0, 0x77, 0x34, 0xf7, 0xb7,
0x70, 0x9b, 0x02, 0x06, 0x89, 0xe7, 0x9f, 0x34, 0xa6, 0x38, 0xd0, 0x8a, 0x75, 0xbc, 0x9d, 0xd6,
0x46, 0xe6, 0x7c, 0x7b, 0xd3, 0xde, 0xaa, 0x70, 0x73, 0x01, 0xbf, 0x06, 0x53, 0x73, 0xff, 0x62,
0xec, 0x5c, 0xf2, 0x7f, 0x58, 0x69, 0xe8, 0xf1, 0x78, 0xab, 0xc2, 0x0e, 0x2a, 0xe7, 0x8a, 0x02,
0x0a, 0x0f, 0x9d, 0x42, 0x8d, 0x2a, 0x07, 0x0b, 0xe5, 0x81, 0xa5, 0x7c, 0xac, 0x41, 0xf8, 0x15,
0x78, 0x3e, 0xa4, 0x3d, 0x10, 0x4f, 0x7b, 0xf0, 0x7e, 0x6b, 0x24, 0x2a, 0xa6, 0xf9, 0x5a, 0x78,
0x05, 0xe2, 0x4d, 0x15, 0xb0, 0x4a, 0x1c, 0x0b, 0xac, 0x09, 0xc2, 0x4e, 0x19, 0xfc, 0xb5, 0x6d,
0x88, 0x65, 0x8b, 0xdf, 0xfb, 0x14, 0x4d, 0xe4, 0xd4, 0xcd, 0xcc, 0x34, 0x6a, 0xec, 0xf6, 0x1b,
0xfc, 0x1b, 0x8e, 0xa3, 0x0c, 0xdf, 0x15, 0x35, 0xf3, 0xae, 0xc3, 0x01, 0xfb, 0x34, 0x7c, 0x1b,
0x90, 0x90, 0xf4, 0x2f, 0xcc, 0x61, 0xbf, 0x7c, 0xec, 0x7a, 0x10, 0xef, 0xd8, 0x2d, 0x5e, 0x32,
0xe6, 0x4f, 0x43, 0x70, 0x3f, 0x7c, 0x83, 0x55, 0xd9, 0xe1, 0x42, 0xf7, 0xc4, 0xe3, 0x67, 0x96,
0x80, 0xe0, 0x42, 0x29, 0xf8, 0x4d, 0x33, 0xde, 0xb3, 0x35, 0xfc, 0xcf, 0xdd, 0x44, 0x0d, 0x5c,
0x06, 0x64, 0x61, 0xe2, 0xc6, 0x07, 0xe0, 0x6f, 0x38, 0xf9, 0xd3, 0x15, 0x1e, 0x16, 0xf6, 0xdf,
0xbb, 0xe6, 0xc7, 0x7b, 0xe0, 0xd9, 0x39, 0x2f, 0x7f, 0x7c, 0x2c, 0x3e, 0x8c, 0x6d, 0x4b, 0xad,
0x18, 0x00, 0x2d, 0xf6, 0xc7, 0x23, 0x38, 0xf7, 0xe0, 0x85, 0x47, 0xe1, 0x41, 0x5a, 0x39, 0x0c,
0xf6, 0xa1, 0x19, 0x3f, 0x46, 0xd3, 0x2b, 0x02, 0x7c, 0x29, 0x04, 0xb2, 0x75, 0x19, 0x86, 0x57,
0x5f, 0x9b, 0x83, 0xac, 0x0b, 0x57, 0x34, 0x83, 0xc1, 0x3a, 0xe5, 0x5d, 0xba, 0x1f, 0xb7, 0xe1,
0x48, 0xdc, 0x82, 0xa3, 0x85, 0x47, 0x2b, 0xed, 0xbd, 0xd5, 0x65, 0xfd, 0xdb, 0xdb, 0x3f, 0x2a,
0xed, 0xef, 0x67, 0xb0, 0x37, 0x7f, 0x60, 0xec, 0xe6, 0xe4, 0x58, 0xdd, 0xfa, 0xfa, 0xac, 0x46,
0xdc, 0xe4, 0x8c, 0x62, 0x30, 0x14, 0x29, 0xe3, 0x3b, 0x60, 0xc8, 0x5c, 0x71, 0x20, 0xeb, 0x17,
0x9f, 0xf6, 0xe2, 0x35, 0xea, 0x8b, 0x1c, 0x33, 0xfb, 0x6b, 0x05, 0xfc, 0x65, 0x03, 0xd8, 0x2b,
0x9d, 0xfb, 0xf5, 0xf9, 0xde, 0x78, 0x31, 0x23, 0x24, 0xb6, 0x0e, 0x41, 0xaf, 0xac, 0xd1, 0xfd,
0x23, 0x94, 0xab, 0xb5, 0xc5, 0xa6, 0x3f, 0x41, 0xc9, 0xbb, 0xe8, 0xe3, 0x7c, 0x1e, 0xbd, 0x93,
0x23, 0x72, 0x5f, 0x68, 0xf8, 0x08, 0x44, 0xf8, 0xde, 0x48, 0xaf, 0x73, 0xf5, 0x45, 0xf7, 0x16,
0xc8, 0x0e, 0xd2, 0x56, 0xce, 0x61, 0xe8, 0xc2, 0xd0, 0xf8, 0x08, 0x3d, 0x2c, 0xac, 0x80, 0xb4,
0xb9, 0xb9, 0xaa, 0x07, 0xf4, 0x4b, 0x75, 0xa0, 0x84, 0x99, 0x77, 0x1a, 0x19, 0x27, 0x67, 0x32,
0xe9, 0x4b, 0x23, 0xcd, 0xb4, 0x6b, 0x9c, 0x33, 0x30, 0x4d, 0x0c, 0x73, 0xa3, 0x80, 0x6a, 0xfe,
0x3d, 0xc2, 0xb1, 0x71, 0x86, 0xef, 0x5e, 0x0d, 0x0f, 0x73, 0xb9, 0x83, 0x7f, 0x61, 0x94, 0x2b,
0x70, 0xf5, 0xf9, 0x61, 0x46, 0x7b, 0xf0, 0x37, 0x46, 0xb9, 0x88, 0xc4, 0x59, 0x4f, 0x1b, 0xc0,
0xad, 0xbf, 0xf8, 0x01, 0x3e, 0xe4, 0xe7, 0x7c, 0xb9, 0x3a, 0xc6, 0xcf, 0xac, 0xaf, 0x0e, 0x56,
0x58, 0x2d, 0xd0, 0xd0, 0xc3, 0x34, 0x46, 0x03, 0x4b, 0x02, 0x4f, 0x71, 0x14, 0xaa, 0x77, 0x67,
0x29, 0x69, 0x88, 0xfc, 0x2c, 0x36, 0x13, 0xc2, 0x72, 0x3b, 0xdd, 0x49, 0x2d, 0x7c, 0x30, 0xad,
0x3b, 0x51, 0x49, 0x17, 0x5d, 0x1c, 0x31, 0xa0, 0xfe, 0x8d, 0x9a, 0xbe, 0x0e, 0x18, 0x27, 0xe5,
0x15, 0x90, 0x61, 0x96, 0x6a, 0x24, 0x0e, 0x87, 0x7e, 0x60, 0x2a, 0x3a, 0xdc, 0xa5, 0x41, 0x2e,
0xdb, 0xae, 0x7c, 0x1c, 0x71, 0xec, 0x32, 0xe8, 0x15, 0x68, 0x73, 0x26, 0x2b, 0x61, 0x45, 0x4c,
0x8d, 0x25, 0x8c, 0x85, 0xae, 0x42, 0x5e, 0x35, 0x13, 0xab, 0x41, 0x2e, 0xd9, 0x27, 0x4b, 0x60,
0xf1, 0x9a, 0xbc, 0xf8, 0xdc, 0xe2, 0xa5, 0x6a, 0x24, 0x8e, 0x5b, 0x16, 0xc9, 0x1d, 0x30, 0xbc,
0x19, 0xda, 0xce, 0xf3, 0x7a, 0xe4, 0x3c, 0x19, 0x6e, 0x32, 0x82, 0xc9, 0x4e, 0x35, 0xd5, 0x90,
0xfa, 0xe1, 0x7f, 0xb4, 0xcf, 0xf2, 0x0f, 0xb1, 0xf9, 0xa7, 0xdb, 0xbc, 0xb0, 0x45, 0x1a, 0xb1,
0x18, 0x99, 0x1b, 0x37, 0xd2, 0x76, 0x60, 0xef, 0x61, 0x24, 0x12, 0xde, 0x77, 0x47, 0xea, 0x0b,
0xa6, 0xbb, 0xde, 0xbe, 0x5d, 0xda, 0xce, 0xc4, 0x5d, 0xcc, 0x15, 0xce, 0x79, 0xfa, 0x11, 0x7a,
0x8e, 0xaf, 0xc7, 0xb2, 0xa9, 0xa3, 0xdc, 0xcb, 0x13, 0x10, 0x01, 0x54, 0xa4, 0x25, 0xdd, 0xb5,
0x26, 0x6d, 0xc4, 0x6c, 0x5c, 0x32, 0x43, 0xc9, 0xcf, 0x0f, 0x7d, 0x94, 0xd4, 0xc2, 0x41, 0x65,
0xaf, 0x0f, 0x7d, 0x5f, 0x04, 0x12, 0xb4, 0xbc, 0xdd, 0x2b, 0xfa, 0xb1, 0x9d, 0x06, 0x6e, 0x5f,
0x01, 0x81, 0xcf, 0xfa, 0x35, 0x51, 0x70, 0xe0, 0xdf, 0x08, 0x3f, 0xd1, 0x0a, 0xda, 0x5c, 0xe4,
0x58, 0x66, 0x10, 0x2a, 0xed, 0xed, 0x94, 0xa6, 0x8a, 0x22, 0x5f, 0x57, 0xcd, 0x19, 0x49, 0xf7,
0xc3, 0xc5, 0xf2, 0xa5, 0x58, 0x39, 0x7e, 0x0e, 0xbd, 0xd5, 0x49, 0x92, 0x26, 0x4a, 0x32, 0xc6,
0x49, 0xf7, 0xe9, 0x65, 0x6d, 0x7d, 0xdc, 0xdc, 0xe2, 0xeb, 0xac, 0x73, 0x90, 0x38, 0x5f, 0x20,
0x84, 0x50, 0xec, 0xf8, 0x5f, 0x80, 0x58, 0xda, 0x91, 0x09, 0x46, 0xe7, 0x31, 0x58, 0x76, 0x8e,
0x9c, 0x5d, 0x45, 0x06, 0xc2, 0xbc, 0x1e, 0xc2, 0xd9, 0x75, 0xc8, 0x0b, 0x64, 0x87, 0x91, 0x79,
0x10, 0xca, 0xe8, 0x45, 0x3c, 0x47, 0x61, 0xbf, 0x51, 0x3d, 0x0c, 0xba, 0x4f, 0x26, 0x1d, 0x6a,
0x01, 0x79, 0xee, 0x71, 0x78, 0xf2, 0xc3, 0xd3, 0xdd, 0x88, 0x67, 0xa0, 0xee, 0x62, 0x84, 0x39,
0x6e, 0x32, 0x75, 0xbc, 0x52, 0xa5, 0xc8, 0x09, 0x67, 0xff, 0x2b, 0x3e, 0x78, 0xc6, 0x99, 0x35,
0x15, 0x6e, 0x86, 0xa6, 0x78, 0xbe, 0x65, 0x98, 0x92, 0x48, 0x0f, 0x86, 0x20, 0x75, 0x23, 0x29,
0x8e, 0xe4, 0x0e, 0x6d, 0x6a, 0xf2, 0x78, 0xb3, 0x26, 0x18, 0x0d, 0xcd, 0x36, 0xd3, 0x2d, 0x56,
0xde, 0x19, 0xdd, 0x98, 0xf8, 0x2d, 0x11, 0x07, 0x37, 0xc0, 0x3d, 0xf7, 0x88, 0x91, 0x66, 0xae,
0x11, 0x23, 0xdd, 0xf3, 0x7e, 0x65, 0x5c, 0x2d, 0xd0, 0x17, 0x83, 0x4c, 0xfc, 0x1d, 0xb4, 0x8e,
0x26, 0xeb, 0x74, 0xa4, 0xab, 0xaf, 0x69, 0x59, 0xb3, 0x07, 0x89, 0x57, 0x34, 0x25, 0xc4, 0x7f,
0x0a, 0x74, 0x5b, 0x97, 0xff, 0x15, 0x46, 0xeb, 0x49, 0x80, 0xd6, 0x70, 0xf7, 0x5f, 0x88, 0x3e,
0xd2, 0x8c, 0x28, 0x53, 0xf0, 0x49, 0xc0, 0x63, 0x0a, 0x68, 0x3f, 0x05, 0x23, 0x42, 0x2f, 0x99,
0xcb, 0xe0, 0x6c, 0x8b, 0x3b, 0x11, 0x44, 0x10, 0x3c, 0xf8, 0x51, 0x8b, 0x25, 0xb5, 0xd8, 0xe7,
0x49, 0x92, 0x1c, 0x60, 0x02, 0xc6, 0x0a, 0xff, 0xc2, 0xe4, 0xe4, 0x7d, 0x2b, 0x69, 0xf6, 0x61,
0xa5, 0xa5, 0xab, 0xfe, 0x16, 0x53, 0xe8, 0xb3, 0xc0, 0x08, 0xd0, 0x93, 0x65, 0xa0, 0xc9, 0x19,
0x1b, 0x6b, 0x6d, 0x1d, 0xac, 0x00, 0x41, 0xf3, 0x18, 0x30, 0xfa, 0x2d, 0x98, 0xd9, 0x02, 0x33,
0x5e, 0xa4, 0xc0, 0x2a, 0x22, 0xc7, 0xb8, 0x81, 0x55, 0x34, 0x1e, 0x4b, 0xdf, 0x5d, 0x34, 0xf5,
0x6b, 0xcd, 0x4a, 0x0b, 0x12, 0x23, 0xda, 0x68, 0x9c, 0x31, 0x66, 0x81, 0x75, 0x6c, 0x6e, 0x46,
0xef, 0x78, 0x68, 0x34, 0x5c, 0xb6, 0x0a, 0x56, 0x73, 0xb4, 0xcd, 0xcd, 0x0f, 0xb1, 0x4d, 0xc3,
0x22, 0xde, 0x05, 0x12, 0x5f, 0xf1, 0x6c, 0x99, 0x09, 0xb9, 0x2f, 0xd8, 0x9d, 0x64, 0x78, 0x29,
0x36, 0x56, 0x49, 0xb0, 0x80, 0x91, 0x06, 0x31, 0x2b, 0x31, 0x78, 0x02, 0xac, 0x3c, 0x2a, 0x02,
0x21, 0xa5, 0xf6, 0xe3, 0x87, 0x09, 0xac, 0xc3, 0x04, 0x2e, 0x61, 0xa6, 0x65, 0x21, 0x0c, 0xfc,
0xa7, 0xf0, 0x03, 0xff, 0x0f, 0xea, 0x4d, 0x3d, 0x4b, 0x9b, 0x8e, 0x99, 0x06, 0xab, 0x2d, 0x16,
0xb0, 0xdb, 0xd1, 0x47, 0xd2, 0x4b, 0x77, 0x27, 0xa0, 0xa9, 0x08, 0x80, 0x43, 0x04, 0xb6, 0x13,
0x6d, 0x12, 0xe0, 0xbe, 0xd7, 0x2a, 0x34, 0x59, 0xcb, 0xb1, 0x8a, 0xf4, 0x96, 0xa5, 0x58, 0xd5,
0xf7, 0x6a, 0xa3, 0x32, 0x16, 0x11, 0x8c, 0x4e, 0x4c, 0x51, 0xf1, 0x3e, 0x46, 0xb3, 0x52, 0x39,
0x53, 0x14, 0x37, 0xac, 0x35, 0xcd, 0xbd, 0xf3, 0x7b, 0x7d, 0x25, 0x2c, 0x5d, 0xd0, 0xf3, 0x7f,
0x70, 0x88, 0x37, 0x20, 0xb0, 0xdd, 0x1c, 0x7c, 0x4f, 0x06, 0x77, 0xcf, 0x78, 0xb7, 0x7e, 0xe2,
0x0d, 0xa5, 0x8b, 0x4b, 0x8e, 0x33, 0x18, 0xae, 0x9b, 0x19, 0x6b, 0x2f, 0xa0, 0xf9, 0xcc, 0x3d,
0xc5, 0xc4, 0x86, 0x29, 0x62, 0xc7, 0x06, 0x7d, 0x93, 0x38, 0x99, 0xec, 0x2b, 0xa9, 0x46, 0xb6,
0xc2, 0x6f, 0xe7, 0xe9, 0xa9, 0x7a, 0x6c, 0x96, 0x17, 0xfa, 0xca, 0x76, 0xce, 0x7f, 0xcd, 0x8b,
0x25, 0xc0, 0x68, 0xa1, 0xd0, 0x68, 0xf4, 0x15, 0x9a, 0x92, 0x6a, 0xe4, 0x31, 0x45, 0xac, 0x84,
0x52, 0x00, 0x00, 0xe3, 0x4c, 0xec, 0x1a, 0x66, 0x7f, 0x7a, 0xe8, 0xec, 0x37, 0x7e, 0xf5, 0x1d,
0xbc, 0x81, 0xaa, 0xaf, 0xcc, 0xf1, 0x3a, 0x2f, 0xe4, 0x65, 0x45, 0xb0, 0x8b, 0x7f, 0xf1, 0x73,
0xa1, 0x9a, 0x15, 0x19, 0xb9, 0x28, 0x46, 0xd7, 0x8e, 0xf8, 0x0a, 0x17, 0x77, 0x43, 0xd3, 0xbd,
0x09, 0xcc, 0x8f, 0xe8, 0xfe, 0xc1, 0x75, 0xd2, 0xc1, 0xd9, 0x74, 0x12, 0x69, 0x93, 0xfb, 0x8a,
0x5f, 0xc7, 0x13, 0x48, 0x68, 0xbf, 0x96, 0xa3, 0x5f, 0x7a, 0xb5, 0x07, 0x09, 0x76, 0xd7, 0x34,
0x47, 0xbd, 0xf3, 0x49, 0xd6, 0x32, 0xac, 0xd3, 0x35, 0x1f, 0x97, 0xa5, 0x0d, 0x71, 0xab, 0x8f,
0x14, 0x47, 0x0e, 0x9a, 0xc6, 0x03, 0xc5, 0xbc, 0x3d, 0xbb, 0x8f, 0xee, 0x26, 0x02, 0x58, 0x13,
0xef, 0x6a, 0x22, 0xde, 0xb5, 0xa7, 0x08, 0x26, 0x19, 0xd9, 0x6b, 0x73, 0x59, 0x68, 0xc0, 0x08,
0xb7, 0xb3, 0x83, 0xdd, 0x22, 0x3c, 0x3a, 0xe4, 0x1f, 0x26, 0x0f, 0x35, 0xda, 0xc0, 0x13, 0xf8,
0x74, 0x58, 0xec, 0x58, 0x28, 0x3f, 0xf7, 0x2e, 0xfb, 0xe1, 0x67, 0xf3, 0x48, 0xb9, 0xd9, 0x1c,
0x8f, 0x06, 0x45, 0xc6, 0x21, 0x0a, 0xde, 0xa5, 0x2d, 0xeb, 0x2e, 0xa0, 0xa4, 0x3d, 0x8d, 0x9f,
0xe9, 0x9f, 0x59, 0xb5, 0xc8, 0x55, 0xcc, 0xd0, 0xb1, 0x5a, 0xb8, 0x97, 0x73, 0x0c, 0x6a, 0x5c,
0x75, 0x4a, 0x3b, 0x72, 0xc5, 0x45, 0x14, 0xa1, 0xb8, 0x09, 0xbb, 0xe6, 0x90, 0xf6, 0x64, 0xc7,
0x42, 0x61, 0x09, 0xda, 0x68, 0x2c, 0x54, 0xf8, 0x6f, 0xb8, 0x30, 0xff, 0x82, 0xef, 0xd2, 0x04,
0x44, 0x45, 0xf0, 0xb9, 0x7c, 0x75, 0x42, 0x18, 0x29, 0x66, 0xda, 0x02, 0x18, 0xdf, 0xcd, 0xf4,
0x60, 0x27, 0x7e, 0x3f, 0xca, 0xd2, 0xe0, 0x53, 0x59, 0xbc, 0x1f, 0x57, 0x00, 0x35, 0xae, 0xe6,
0x26, 0xa3, 0xd7, 0x35, 0x2d, 0x1d, 0x05, 0x0e, 0x33, 0x19, 0xfa, 0x59, 0x06, 0xdc, 0xce, 0x5b,
0xdc, 0x40, 0xb0, 0x5e, 0xf9, 0x08, 0x0c, 0x5c, 0x3c, 0x4b, 0xe3, 0x45, 0x09, 0xc5, 0x5d, 0x1c,
0x41, 0xe8, 0x3e, 0xae, 0x37, 0x97, 0x5f, 0xb9, 0xff, 0xbe, 0x88, 0xd7, 0xd4, 0x30, 0xb0, 0xe4,
0xbb, 0x7f, 0xab, 0x57, 0x5d, 0x5b, 0x1c, 0x19, 0x32, 0x7f, 0x68, 0x78, 0x65, 0x93, 0xb3, 0x32,
0x3a, 0x93, 0x86, 0x8f, 0x79, 0x41, 0x15, 0x37, 0xd0, 0x5b, 0xd0, 0xef, 0x6e, 0xf1, 0xd3, 0xdc,
0x2d, 0x09, 0xef, 0x6f, 0xa9, 0x3b, 0xb1, 0xfe, 0x1a, 0x41, 0x98, 0x86, 0xd7, 0xe9, 0x68, 0x79,
0x7e, 0x7b, 0x2b, 0x4b, 0x9d, 0x5c, 0x6c, 0x6f, 0x7f, 0x1e, 0xbd, 0xa3, 0xc5, 0x60, 0xf1, 0x4e,
0xab, 0x4c, 0xfc, 0xba, 0x1f, 0x69, 0x86, 0xd1, 0xa2, 0x9a, 0x39, 0x74, 0xa2, 0x58, 0xf3, 0xf5,
0x23, 0x7a, 0x24, 0x38, 0x4d, 0xbf, 0x84, 0x91, 0xc4, 0x2b, 0xf8, 0x10, 0x08, 0xce, 0x0e, 0xbd,
0xe2, 0x27, 0x89, 0x5a, 0x15, 0x7b, 0x62, 0x77, 0x2f, 0x71, 0xe1, 0x70, 0xf0, 0x21, 0xfb, 0x80,
0xc6, 0x42, 0xcd, 0x5e, 0x32, 0x4e, 0x65, 0x7d, 0x68, 0x27, 0x57, 0xee, 0x69, 0x2d, 0xe7, 0x84,
0xed, 0x45, 0x96, 0x3b, 0x67, 0x31, 0xa0, 0xff, 0xd5, 0x5a, 0x71, 0x13, 0xee, 0xe2, 0x2b, 0xc6,
0xbc, 0x70, 0xde, 0xc8, 0xd2, 0x30, 0x82, 0xb1, 0xa0, 0xd1, 0xbe, 0x34, 0x44, 0x61, 0x22, 0x32,
0x07, 0x3b, 0xf3, 0x5f, 0x74, 0xe8, 0x95, 0xe3, 0xe8, 0x6e, 0x8a, 0xf0, 0xe3, 0xa1, 0xc1, 0xf6,
0x28, 0x82, 0xe8, 0x88, 0x34, 0x3b, 0xbb, 0xa3, 0xde, 0xd0, 0xfb, 0x8c, 0x9c, 0x9d, 0x78, 0xc2,
0x0f, 0xf1, 0x67, 0x2d, 0x74, 0x30, 0xa4, 0x2f, 0x39, 0x47, 0xb6, 0x49, 0x23, 0xe2, 0xe8, 0xf9,
0xf6, 0x48, 0xac, 0x11, 0x59, 0xda, 0x8c, 0x65, 0x91, 0x1b, 0x8b, 0x43, 0x9b, 0x50, 0x17, 0xd0,
0xe9, 0xed, 0x4f, 0x8b, 0x73, 0x7f, 0xa3, 0x3a, 0xcc, 0x96, 0x95, 0x97, 0x64, 0x28, 0x64, 0xd0,
0x8b, 0x6a, 0x0b, 0xec, 0x44, 0x7a, 0x22, 0x36, 0x12, 0xea, 0xe6, 0xdf, 0x50, 0x1d, 0x14, 0x81,
0x59, 0xf6, 0x30, 0xe5, 0x24, 0x83, 0xaf, 0xca, 0xf1, 0xbf, 0x7f, 0x87, 0xbb, 0xee, 0xc6, 0xde,
0x4d, 0xbc, 0xc1, 0x0f, 0x10, 0xe8, 0xa3, 0x07, 0xa0, 0xa1, 0xf2, 0xfe, 0x10, 0x20, 0xd3, 0x0b,
0x49, 0x0b, 0x7d, 0x30, 0x9a, 0xff, 0xc1, 0x30, 0xff, 0xd3, 0x73, 0x18, 0xdd, 0x98, 0x96, 0xf0,
0x5f, 0xad, 0x55, 0x71, 0x74, 0x9e, 0xd7, 0xe8, 0x4b, 0xd2, 0x9f, 0x0f, 0x91, 0x0f, 0x93, 0x14,
0x35, 0x8b, 0x99, 0xcd, 0xc9, 0x0a, 0xf8, 0xa3, 0x5f, 0xea, 0x8c, 0xd9, 0x70, 0xb7, 0x26, 0xa2,
0x7f, 0x25, 0x10, 0x65, 0x51, 0x26, 0x5e, 0x01, 0x94, 0x4a, 0x3a, 0xff, 0x32, 0x33, 0xe3, 0xc5,
0xf1, 0xcc, 0x1c, 0x5f, 0x17, 0xbf, 0x34, 0xf0, 0xbe, 0x29, 0xd6, 0xc7, 0x6d, 0x11, 0x98, 0xe1,
0x77, 0x91, 0x0f, 0x12, 0xbe, 0x63, 0xc2, 0x36, 0x26, 0x18, 0xdb, 0xe9, 0x6c, 0x6e, 0x73, 0xf3,
0x53, 0xe3, 0x6b, 0x34, 0x3c, 0x74, 0x00, 0x1c, 0x18, 0xea, 0xf2, 0x9d, 0xe0, 0xdc, 0xd6, 0x96,
0xc6, 0x79, 0x14, 0xb9, 0xd5, 0x70, 0xb0, 0x6f, 0xd9, 0x2d, 0xc3, 0x0f, 0x74, 0x92, 0x70, 0x11,
0xbe, 0x38, 0x5e, 0x17, 0x40, 0xa0, 0xac, 0x83, 0xd1, 0xc5, 0x23, 0xa3, 0x9f, 0x45, 0x26, 0xee,
0xad, 0x79, 0xa4, 0x1f, 0x62, 0x14, 0xec, 0x02, 0xb1, 0xb0, 0xa6, 0xe1, 0x9a, 0x16, 0xe7, 0xa3,
0xf2, 0x90, 0x60, 0x3c, 0x70, 0x3d, 0xb8, 0xcd, 0x19, 0x0f, 0xe8, 0xa6, 0xb8, 0xe8, 0x0d, 0xcf,
0x16, 0xa4, 0x6d, 0x25, 0x63, 0x6a, 0xab, 0xff, 0x41, 0xf7, 0x98, 0xde, 0xba, 0x23, 0xd6, 0x62,
0xd9, 0xac, 0x1d, 0xc0, 0x19, 0x1f, 0x83, 0x4b, 0x6f, 0x3a, 0xc5, 0x2b, 0xa5, 0xc3, 0x14, 0x10,
0x5c, 0x62, 0x48, 0x84, 0x74, 0x3a, 0xed, 0x32, 0x5d, 0xc9, 0x77, 0xa6, 0xf8, 0x0a, 0x02, 0xa9,
0x33, 0xde, 0x40, 0x2f, 0x7f, 0xf4, 0x4e, 0x33, 0x40, 0x39, 0xff, 0x92, 0xf3, 0xcd, 0x4d, 0xf6,
0x64, 0xf2, 0x8b, 0xe3, 0xd8, 0x09, 0x3c, 0xf0, 0x93, 0x30, 0x79, 0x2f, 0x07, 0x56, 0x23, 0xbf,
0x43, 0x17, 0xe5, 0xef, 0xdf, 0x51, 0x49, 0x47, 0x84, 0x19, 0xa4, 0xd6, 0x66, 0xa8, 0x00, 0x87,
0x7a, 0x03, 0x69, 0x02, 0xad, 0xc5, 0xd7, 0x56, 0x96, 0xc7, 0xbc, 0x79, 0xa0, 0xb9, 0x2d, 0x0d,
0x63, 0xee, 0x5d, 0xe3, 0xe6, 0xa9, 0x64, 0xcb, 0x97, 0xa8, 0x81, 0x52, 0x06, 0x25, 0x38, 0x7a,
0xdd, 0x1b, 0xbd, 0xf7, 0x0d, 0xe6, 0x7c, 0xb9, 0xd4, 0xc0, 0xc4, 0x63, 0xa6, 0xe8, 0x9c, 0xa5,
0x1c, 0x6d, 0x7d, 0xc1, 0xf0, 0x0d, 0x6e, 0xef, 0x97, 0xa4, 0x20, 0x41, 0x78, 0x73, 0x02, 0xae,
0xbe, 0x0f, 0xca, 0x0d, 0xad, 0x8f, 0x8a, 0x2d, 0x2e, 0x83, 0xf3, 0xcb, 0x6d, 0x7c, 0xcf, 0x78,
0x9f, 0xbd, 0x48, 0x7c, 0xcf, 0xe0, 0xde, 0x2a, 0xfe, 0xf6, 0xdd, 0x81, 0xbe, 0x9d, 0xf8, 0xbf,
0xf6, 0x48, 0xd2, 0x45, 0x29, 0xc5, 0x00, 0x00
0xcf, 0x12, 0x74, 0x18, 0x09, 0xb0, 0xa5, 0x12, 0xa6, 0x42, 0x17, 0x1a, 0x40, 0x9d, 0x87, 0xc8,
0x97, 0x32, 0x0b, 0xba, 0x57, 0x49, 0x4b, 0xa6, 0xb8, 0x1a, 0xbc, 0xa8, 0x34, 0xe8, 0x28, 0x7c,
0x99, 0x85, 0x01, 0x32, 0x40, 0x0f, 0xdf, 0x75, 0x61, 0xa4, 0xbb, 0x93, 0x70, 0xfc, 0x11, 0x22,
0x30, 0xc4, 0x8a, 0xb2, 0xf5, 0x10, 0xdf, 0x59, 0x84, 0xfc, 0x87, 0x42, 0x25, 0xff, 0x9c, 0x7b,
0x7e, 0x21, 0xbf, 0x7f, 0x07, 0x4d, 0xf0, 0xb3, 0x90, 0x80, 0xf9, 0xfd, 0x3b, 0x2c, 0x7b, 0xc2,
0xe1, 0xe8, 0xd1, 0x60, 0x2e, 0x21, 0x4f, 0xf2, 0xbc, 0xef, 0x4e, 0xa3, 0x9c, 0xd8, 0x6c, 0x7c,
0x1c, 0x5d, 0x8e, 0x8e, 0xa6, 0x1d, 0xce, 0x02, 0x09, 0xca, 0x31, 0x0f, 0x35, 0x9e, 0xd1, 0x4f,
0x62, 0xf0, 0x32, 0x32, 0x29, 0x68, 0x1b, 0x2c, 0xae, 0x06, 0xf3, 0x3e, 0xe3, 0x56, 0x7a, 0x38,
0xc6, 0x1a, 0x85, 0x5c, 0xda, 0x30, 0xc7, 0x49, 0x1e, 0xe3, 0x31, 0xa8, 0x35, 0x10, 0x0b, 0x8f,
0x45, 0xb9, 0xeb, 0x05, 0x5f, 0x65, 0xf1, 0xb6, 0x85, 0x24, 0x5e, 0x46, 0x02, 0x2b, 0xc9, 0xdc,
0xf1, 0xd9, 0x3d, 0x8c, 0xee, 0xdb, 0x8c, 0x1b, 0x71, 0x8c, 0xe3, 0x7f, 0xe3, 0x6b, 0x18, 0x65,
0x8a, 0x2d, 0x47, 0xe4, 0x46, 0x08, 0xcb, 0x42, 0x0e, 0xdd, 0x21, 0xab, 0xfc, 0xed, 0x8e, 0x16,
0x72, 0xb6, 0x3b, 0x02, 0x1e, 0xe1, 0x23, 0x78, 0x1b, 0x07, 0xc6, 0xbd, 0xa3, 0xbd, 0xbf, 0x85,
0xfb, 0x14, 0x30, 0x48, 0x3c, 0x00, 0xa5, 0x31, 0xcd, 0x81, 0x56, 0xac, 0xe3, 0xf5, 0xb4, 0x36,
0x72, 0xe7, 0xdb, 0x9b, 0xf6, 0x56, 0x85, 0x9b, 0x0b, 0xf8, 0x39, 0x98, 0x9a, 0xfb, 0x17, 0x83,
0xe7, 0x92, 0xff, 0xc3, 0x5a, 0x43, 0x8f, 0xc7, 0x6b, 0x15, 0x76, 0x50, 0x3b, 0x57, 0x14, 0xd0,
0x78, 0xe8, 0x14, 0x6a, 0x54, 0x3b, 0x58, 0x68, 0x0f, 0x2c, 0xe5, 0x63, 0x15, 0xc2, 0xaf, 0xc0,
0xf3, 0x21, 0xf5, 0x81, 0x78, 0xea, 0x83, 0xf7, 0x5b, 0x23, 0x51, 0x39, 0xcd, 0xd7, 0xc2, 0x2b,
0x10, 0xaf, 0xaa, 0x80, 0x55, 0xe2, 0x58, 0x60, 0x4e, 0x10, 0x76, 0xcc, 0xe0, 0xaf, 0xed, 0x43,
0x2c, 0x9b, 0xfc, 0xde, 0xb7, 0x68, 0x22, 0xc7, 0x6e, 0x66, 0xa6, 0x51, 0x63, 0xd7, 0xdf, 0xe0,
0xdf, 0x70, 0x20, 0x65, 0xf8, 0xb2, 0xa8, 0x99, 0x77, 0x1f, 0x0e, 0x18, 0xa8, 0xe1, 0xeb, 0x80,
0x84, 0xa4, 0x7f, 0x63, 0x0e, 0xfb, 0xe5, 0x63, 0xf7, 0x83, 0x78, 0xe7, 0x6e, 0xf1, 0x96, 0x31,
0x7f, 0x1a, 0x82, 0x0b, 0xe2, 0x1b, 0xac, 0xca, 0x0e, 0x17, 0xba, 0x28, 0x1e, 0xbf, 0xb3, 0x04,
0x04, 0x17, 0x4a, 0xc1, 0x8f, 0x9a, 0xf1, 0x9e, 0xb1, 0xe1, 0x7f, 0xef, 0x26, 0x6a, 0xe1, 0x32,
0x20, 0x0b, 0x1b, 0x37, 0x3e, 0x00, 0x7f, 0xc7, 0xc9, 0x9f, 0xae, 0xf0, 0xb0, 0xb0, 0xff, 0xde,
0x3d, 0x3f, 0xde, 0x03, 0xcf, 0x0e, 0x7a, 0xf9, 0xe3, 0x63, 0x01, 0x62, 0x6c, 0x5f, 0x6a, 0xc5,
0x00, 0x68, 0xb1, 0x3f, 0x1e, 0xc1, 0xb9, 0x07, 0x2f, 0x3c, 0x0a, 0x0f, 0xd2, 0xca, 0x61, 0xb0,
0x2f, 0xcd, 0xf8, 0x41, 0x9a, 0x5e, 0x11, 0xe0, 0x4b, 0x21, 0x90, 0xad, 0xcb, 0x30, 0xbc, 0xfa,
0xda, 0x1c, 0x64, 0x5d, 0xb8, 0xa2, 0x19, 0x0c, 0xd6, 0x29, 0xef, 0xd6, 0xfd, 0xb8, 0x11, 0x47,
0xe2, 0x26, 0x1c, 0x2d, 0x3c, 0x5a, 0x69, 0xf0, 0xad, 0x2e, 0xeb, 0x5f, 0xdf, 0xfe, 0x51, 0x69,
0x7f, 0x43, 0x83, 0xbd, 0xf9, 0x03, 0x63, 0x57, 0x27, 0xc7, 0xea, 0xd6, 0xd7, 0x67, 0x35, 0xe2,
0x36, 0x67, 0x14, 0x83, 0xa1, 0x50, 0x19, 0xdf, 0x03, 0x43, 0xe6, 0x8a, 0x03, 0x59, 0xbf, 0xf8,
0xb4, 0x17, 0xb0, 0x51, 0x5f, 0xe4, 0x98, 0xd9, 0x5f, 0x2b, 0xe0, 0x2f, 0x5b, 0xc0, 0x5e, 0xe9,
0xdc, 0xaf, 0xcf, 0xf7, 0xc6, 0x0b, 0x1a, 0x21, 0xb1, 0x75, 0x08, 0x8a, 0x65, 0x8d, 0x6e, 0x20,
0xa1, 0x5c, 0xad, 0x2d, 0x76, 0xfd, 0x09, 0x4a, 0xde, 0x45, 0x1f, 0xe7, 0xf3, 0xe8, 0xa5, 0x1c,
0x91, 0x0b, 0x43, 0xc3, 0x67, 0x20, 0xc2, 0x17, 0x47, 0x7a, 0x9d, 0xab, 0x2f, 0xba, 0xb7, 0x40,
0x76, 0x90, 0xb6, 0x72, 0x0e, 0x43, 0x37, 0x86, 0xc6, 0x47, 0xe8, 0x61, 0x61, 0x05, 0xa4, 0xcd,
0xcd, 0x55, 0x3d, 0xa0, 0x9f, 0xaa, 0x03, 0x2d, 0xcc, 0xbc, 0xd3, 0xc8, 0x38, 0x39, 0x93, 0x49,
0x5f, 0x1a, 0x69, 0xa6, 0x5d, 0xe3, 0x9c, 0x81, 0x69, 0x62, 0x9c, 0x1b, 0x05, 0x54, 0xf3, 0x2f,
0x12, 0x8e, 0x8d, 0x33, 0x7c, 0xf9, 0x6a, 0x78, 0x98, 0xcb, 0x1d, 0xfc, 0x0b, 0xa3, 0x5c, 0x81,
0xab, 0xcf, 0x0f, 0x33, 0xda, 0x83, 0xbf, 0x31, 0xca, 0x45, 0x28, 0xce, 0x7a, 0xda, 0x00, 0x6e,
0xfd, 0xc5, 0x8f, 0xf0, 0x21, 0x3f, 0xe7, 0xcb, 0xd5, 0x31, 0x80, 0x66, 0x7d, 0x75, 0x30, 0xc3,
0x6a, 0x81, 0x8a, 0x1e, 0xa6, 0x31, 0x1a, 0x59, 0x12, 0xb8, 0x8a, 0xa3, 0x50, 0xbd, 0x4b, 0x4b,
0x49, 0x43, 0xe4, 0x67, 0xb1, 0x99, 0x10, 0x96, 0xdb, 0xe9, 0x4e, 0x6a, 0xe1, 0x93, 0x69, 0xdd,
0x89, 0x4a, 0xba, 0xe8, 0xe3, 0x88, 0x01, 0xf5, 0xaf, 0xd4, 0xf4, 0x75, 0xc0, 0x38, 0x29, 0xaf,
0x80, 0x0c, 0xb3, 0x54, 0x23, 0x71, 0x38, 0xf4, 0x0b, 0x53, 0xd1, 0xe1, 0x2e, 0x0d, 0x72, 0xd9,
0x78, 0xe5, 0xe3, 0x88, 0x63, 0xb7, 0x41, 0xaf, 0x40, 0x9b, 0x33, 0x59, 0x09, 0x2b, 0x62, 0x6b,
0x2c, 0x61, 0x2c, 0x74, 0x17, 0xf2, 0xaa, 0x99, 0x58, 0x0d, 0x72, 0xc9, 0x40, 0x59, 0x02, 0x8b,
0xf7, 0xe4, 0xc5, 0xe7, 0x16, 0x6f, 0x55, 0x23, 0x71, 0xdc, 0xb2, 0x50, 0xee, 0x80, 0xe1, 0xcd,
0xd0, 0x78, 0x9e, 0xd7, 0x23, 0x07, 0xca, 0x70, 0x97, 0x11, 0x6c, 0x76, 0xaa, 0xa9, 0x86, 0xd4,
0x0f, 0xff, 0xab, 0x7d, 0x96, 0x7f, 0x8a, 0xcd, 0x3f, 0xde, 0xe6, 0xc5, 0x2d, 0xd2, 0x90, 0xc5,
0xc8, 0xdc, 0xb8, 0x91, 0xb6, 0x03, 0x83, 0x0f, 0x43, 0x91, 0xf0, 0xc2, 0x3b, 0x52, 0x5f, 0x30,
0xdd, 0xf5, 0x06, 0xee, 0xd2, 0x7e, 0x26, 0x6e, 0x63, 0xae, 0xf0, 0xce, 0xd3, 0xaf, 0xd0, 0x73,
0x7c, 0x3d, 0x96, 0x4d, 0x3d, 0xe5, 0x5e, 0x9e, 0x80, 0x08, 0xa0, 0x22, 0x2d, 0xe9, 0xae, 0xb5,
0x69, 0x23, 0x76, 0xe3, 0x92, 0x1d, 0x4a, 0x7e, 0x7e, 0xe8, 0xa4, 0xa4, 0x16, 0x0e, 0x2a, 0x7b,
0x7d, 0xe8, 0xfb, 0x22, 0x92, 0xa0, 0xe5, 0x6d, 0x5f, 0xd1, 0xaf, 0xed, 0x34, 0x70, 0xff, 0x0a,
0x08, 0x7c, 0xd6, 0xaf, 0x89, 0x82, 0x03, 0xff, 0x46, 0xf8, 0x8d, 0x56, 0xd0, 0xe6, 0x22, 0xe7,
0x32, 0x83, 0x58, 0x69, 0x6f, 0xab, 0x34, 0x55, 0x14, 0xf9, 0xba, 0x6a, 0xce, 0x48, 0xba, 0x1f,
0x2e, 0x96, 0x2f, 0xc5, 0xca, 0xf1, 0x73, 0xe8, 0xad, 0x4e, 0x92, 0x34, 0x51, 0x92, 0x31, 0x50,
0xba, 0x4f, 0x6f, 0x6b, 0xeb, 0xe3, 0xee, 0x16, 0x5f, 0x67, 0x9d, 0x83, 0xc4, 0xf9, 0x02, 0x21,
0x84, 0x62, 0xc7, 0xff, 0x04, 0xc4, 0xd2, 0x96, 0x4c, 0x30, 0x3a, 0x8f, 0xc1, 0xb2, 0x83, 0xe4,
0xec, 0x2e, 0x32, 0x10, 0xe6, 0xf5, 0x10, 0xce, 0xae, 0x43, 0x6e, 0x20, 0x3b, 0x8c, 0xcc, 0x83,
0x50, 0x46, 0x2f, 0xe2, 0x3a, 0x0a, 0x3b, 0x8e, 0xea, 0x61, 0xd0, 0x7d, 0x32, 0xe9, 0x50, 0x0b,
0xc8, 0xf3, 0x8f, 0xc3, 0x93, 0x1f, 0x9f, 0xee, 0x46, 0x5c, 0x03, 0x75, 0x17, 0x43, 0xcc, 0x71,
0x97, 0xa9, 0xe3, 0x95, 0x2a, 0x45, 0x8e, 0x38, 0xfb, 0x9f, 0xf1, 0xc1, 0x43, 0xce, 0xac, 0xa9,
0x70, 0x33, 0x34, 0xc5, 0x73, 0x2e, 0xc3, 0x94, 0x44, 0x7a, 0x30, 0x04, 0xa9, 0x1b, 0x49, 0x71,
0x24, 0x77, 0x68, 0x53, 0x93, 0xc7, 0x9b, 0x35, 0xc1, 0x68, 0x68, 0xb6, 0x99, 0x6e, 0xb1, 0xf2,
0xce, 0xe8, 0xc6, 0xc4, 0x8f, 0x89, 0x38, 0xb8, 0x03, 0xee, 0xf9, 0x47, 0x8c, 0x34, 0xf3, 0x8d,
0x18, 0xe9, 0x9e, 0xf7, 0x2b, 0xe3, 0x6a, 0x81, 0xbe, 0x18, 0x64, 0xe2, 0x6f, 0xa1, 0x75, 0x34,
0x59, 0xa7, 0x23, 0x5d, 0x7d, 0x4f, 0xcb, 0x9a, 0x4d, 0x48, 0xbc, 0xa3, 0x29, 0x21, 0xfe, 0x53,
0xa0, 0xfb, 0xba, 0xfc, 0xaf, 0x30, 0x5a, 0x4f, 0x02, 0xb4, 0x86, 0xbb, 0xff, 0x42, 0xf4, 0x91,
0x66, 0x44, 0x99, 0x82, 0x4f, 0x02, 0x1e, 0x53, 0x40, 0xfb, 0x29, 0x18, 0x11, 0xba, 0xc9, 0x5c,
0x06, 0x67, 0x5b, 0xdc, 0x89, 0x20, 0x82, 0xe0, 0xc9, 0x8f, 0x5a, 0x2c, 0xa9, 0xc5, 0xbe, 0x4f,
0x92, 0xe4, 0x00, 0x13, 0x30, 0x56, 0xf8, 0x17, 0x26, 0x27, 0xef, 0x63, 0x49, 0xb3, 0x0f, 0x2b,
0x2d, 0xdd, 0xf5, 0xb7, 0x98, 0x42, 0x9f, 0x05, 0x46, 0x80, 0x9e, 0x2c, 0x03, 0x4d, 0xce, 0xd8,
0x58, 0x6b, 0xeb, 0x60, 0x05, 0x08, 0x9a, 0xc7, 0x80, 0xd1, 0x8f, 0xc1, 0xcc, 0x16, 0x98, 0xf1,
0x42, 0x05, 0x56, 0x11, 0x39, 0x06, 0x0e, 0xac, 0xa2, 0xf1, 0x58, 0xfa, 0xee, 0xa2, 0xa9, 0x5f,
0x6b, 0x56, 0x5a, 0x90, 0x18, 0xd1, 0x46, 0xe3, 0x8c, 0x31, 0x0b, 0xac, 0x63, 0x73, 0x33, 0x7a,
0xc9, 0x43, 0xa3, 0xe1, 0xb2, 0x55, 0xb0, 0x9a, 0xa3, 0x6d, 0x6e, 0x7e, 0x88, 0x6d, 0x1a, 0x17,
0xf1, 0x2e, 0x90, 0xf8, 0x8a, 0x67, 0xcb, 0x4c, 0xc8, 0x7d, 0xc1, 0xee, 0x24, 0xc3, 0x4b, 0xb1,
0xb1, 0x4a, 0x82, 0x05, 0x8c, 0x34, 0x08, 0x5a, 0x89, 0xc1, 0x13, 0x60, 0xe5, 0x51, 0x11, 0x08,
0x29, 0xb5, 0x1f, 0x3f, 0x4c, 0x60, 0x1d, 0x26, 0x70, 0x09, 0x33, 0x2d, 0x0b, 0x61, 0xe0, 0x3f,
0x85, 0x1f, 0xf8, 0x7f, 0x50, 0x6f, 0xea, 0x59, 0xda, 0x74, 0xcc, 0x34, 0x58, 0x6d, 0xb1, 0x80,
0xdd, 0x8e, 0x3e, 0x92, 0x5e, 0xba, 0x3b, 0x01, 0x4d, 0x45, 0x00, 0x1c, 0x22, 0xb0, 0x9d, 0x68,
0x93, 0x00, 0xf7, 0xbd, 0x56, 0xa1, 0xc9, 0x5a, 0x8e, 0x55, 0xa4, 0xd7, 0x2c, 0xc5, 0xaa, 0xbe,
0x57, 0x1b, 0x95, 0xb1, 0x88, 0x60, 0x74, 0x62, 0x8a, 0x8a, 0xf7, 0x35, 0x9a, 0x95, 0xca, 0x99,
0xa2, 0xb8, 0x61, 0xad, 0x69, 0xee, 0x1d, 0xe0, 0xeb, 0x2b, 0x61, 0xe9, 0x82, 0xae, 0xff, 0x83,
0x43, 0xbc, 0x02, 0x81, 0x6d, 0xe7, 0xe0, 0x7b, 0x32, 0xb8, 0x7c, 0xc6, 0xbb, 0xf6, 0x13, 0xaf,
0x28, 0x5d, 0xdc, 0x72, 0x9c, 0xc1, 0x78, 0xdd, 0xcc, 0x58, 0x7b, 0x01, 0xcd, 0x67, 0xee, 0x29,
0x26, 0x36, 0x4c, 0x11, 0x3b, 0x37, 0xe8, 0x9b, 0xc4, 0xc9, 0x64, 0x5f, 0x49, 0x35, 0xb2, 0x15,
0x7e, 0x3b, 0x4f, 0x8f, 0xd5, 0x63, 0xb3, 0xbc, 0xd0, 0x57, 0xb6, 0x73, 0xfe, 0x6b, 0x5e, 0x2c,
0x01, 0x46, 0x0b, 0x85, 0x46, 0xa3, 0xaf, 0xd0, 0x94, 0x54, 0x23, 0x8f, 0x29, 0x62, 0x25, 0x94,
0x02, 0x00, 0x18, 0x67, 0x62, 0xf7, 0x30, 0xfb, 0xd3, 0x43, 0x67, 0xbf, 0xf1, 0xab, 0xef, 0xe0,
0x15, 0x54, 0x7d, 0x65, 0x8e, 0xf7, 0x79, 0x21, 0x2f, 0x2b, 0x82, 0x5d, 0xfc, 0x8b, 0x9f, 0x0b,
0xd5, 0xac, 0xc8, 0xc8, 0x45, 0x31, 0xba, 0x76, 0xc4, 0x57, 0xb8, 0xb8, 0x1c, 0x9a, 0x6e, 0x4e,
0x60, 0x7e, 0x44, 0xf7, 0x0f, 0xee, 0x93, 0x0e, 0x0e, 0xa7, 0x93, 0x48, 0x9b, 0xdc, 0x57, 0xfc,
0x3c, 0x9e, 0x40, 0x42, 0x1b, 0xb6, 0x1c, 0xfd, 0xd4, 0xab, 0x3d, 0x48, 0xb0, 0xcb, 0xa6, 0x39,
0xea, 0x9e, 0x4f, 0xb2, 0x96, 0x61, 0x9d, 0xae, 0xf9, 0xba, 0x2c, 0x6d, 0x88, 0x5b, 0x7d, 0xa6,
0x38, 0x72, 0xd2, 0x34, 0x1e, 0x29, 0xe6, 0x6d, 0xda, 0x7d, 0x74, 0x39, 0x11, 0xc0, 0x9a, 0x78,
0x77, 0x13, 0xf1, 0xae, 0x3d, 0x45, 0x30, 0xc9, 0xc8, 0x66, 0x9b, 0xcb, 0x62, 0x03, 0x46, 0xb8,
0x9f, 0x1d, 0x6c, 0x17, 0xe1, 0xd9, 0x21, 0xff, 0x34, 0x79, 0xa8, 0xd1, 0x06, 0x1e, 0xc1, 0xa7,
0xc3, 0x62, 0xe7, 0x42, 0xf9, 0xb9, 0x77, 0xdb, 0x0f, 0x3f, 0x9b, 0x47, 0xca, 0xcd, 0xe6, 0x78,
0x36, 0x28, 0x32, 0x0e, 0x51, 0xf0, 0x6e, 0x6d, 0x59, 0x77, 0x03, 0x25, 0xed, 0x69, 0xfc, 0x50,
0xff, 0xcc, 0xaa, 0x45, 0xee, 0x62, 0x86, 0x8e, 0xd5, 0xc2, 0xbd, 0x9c, 0x63, 0x54, 0xe3, 0xaa,
0x63, 0xda, 0x91, 0x3b, 0x2e, 0xa2, 0x08, 0xc5, 0x5d, 0xd8, 0x35, 0xa7, 0xb4, 0x27, 0x3b, 0x16,
0x0a, 0x4b, 0xd0, 0x46, 0x63, 0xb1, 0xc2, 0x7f, 0xc3, 0x85, 0xf9, 0x17, 0x7c, 0x97, 0x26, 0x20,
0x2a, 0x82, 0xcf, 0xe5, 0xbb, 0x13, 0xc2, 0x48, 0x31, 0xd3, 0x16, 0xc0, 0xf8, 0x6e, 0xa6, 0x07,
0x3b, 0xf1, 0x0b, 0x52, 0x96, 0x06, 0x9f, 0xca, 0xe2, 0x05, 0xb9, 0x02, 0xa8, 0x71, 0x35, 0x37,
0x19, 0xbd, 0xaf, 0x69, 0xe9, 0x2c, 0x70, 0x98, 0xc9, 0xd0, 0xef, 0x32, 0xe0, 0x7e, 0xde, 0xe2,
0x0a, 0x82, 0xf5, 0xca, 0x47, 0x60, 0xe0, 0xe2, 0x61, 0x1a, 0x2f, 0x4c, 0x28, 0xee, 0xe2, 0x08,
0x62, 0xf7, 0x71, 0xbd, 0xb9, 0xfc, 0xca, 0x0d, 0xf8, 0x45, 0xc0, 0xa6, 0x86, 0x91, 0x25, 0xdf,
0xfd, 0x6b, 0xbd, 0xea, 0xda, 0xe2, 0xcc, 0x90, 0xf9, 0x43, 0xc3, 0x3b, 0x9b, 0x9c, 0x95, 0xe1,
0x99, 0x34, 0x7e, 0xcc, 0x8b, 0xaa, 0xb8, 0x81, 0xde, 0x82, 0x7e, 0x77, 0x8b, 0xdf, 0xe6, 0x6e,
0x49, 0x78, 0x81, 0x4b, 0xdd, 0x89, 0xf5, 0xd7, 0x08, 0xe2, 0x34, 0xbc, 0x4e, 0x47, 0xcb, 0xf3,
0xdb, 0x5b, 0x59, 0xea, 0xe4, 0x62, 0x9b, 0xfb, 0xf3, 0xe8, 0x25, 0x2d, 0x06, 0x0b, 0x78, 0x5a,
0x65, 0xe2, 0xd7, 0xfd, 0x50, 0x33, 0x0c, 0x17, 0xd5, 0xcc, 0xa1, 0x13, 0xc5, 0x9a, 0xaf, 0x1f,
0xd1, 0x33, 0xc1, 0x69, 0xfa, 0x29, 0x8c, 0x24, 0xde, 0xc1, 0x87, 0x40, 0x70, 0x76, 0xe8, 0x1d,
0x3f, 0x49, 0xd4, 0xaa, 0xd8, 0x13, 0xbb, 0x7c, 0x89, 0x0b, 0xc7, 0x83, 0x0f, 0xd9, 0x17, 0x34,
0x16, 0x6a, 0xf6, 0x92, 0x71, 0x2a, 0xeb, 0x43, 0x3b, 0xb9, 0x72, 0x53, 0x6b, 0x39, 0x27, 0x6c,
0x2f, 0xb2, 0xdc, 0x39, 0x0b, 0x02, 0xfd, 0xaf, 0xd6, 0x8a, 0xab, 0x70, 0x17, 0x9f, 0x31, 0xe6,
0x85, 0xf3, 0x46, 0x96, 0xc6, 0x11, 0x8c, 0x05, 0x8d, 0xf6, 0xa5, 0x21, 0x0a, 0x13, 0x91, 0x39,
0xd8, 0x99, 0xff, 0xa2, 0x43, 0xef, 0x1c, 0x47, 0x77, 0x53, 0x84, 0x1f, 0x0f, 0x0d, 0xb6, 0x47,
0x11, 0x84, 0x47, 0xa4, 0xd9, 0xe1, 0x1d, 0xf5, 0x86, 0x5e, 0x68, 0xe4, 0xec, 0xc4, 0x13, 0x7e,
0x88, 0x3f, 0x6b, 0xa1, 0x93, 0x21, 0x7d, 0xc9, 0x39, 0xb2, 0x4d, 0x1a, 0x12, 0x47, 0x0f, 0xb8,
0x47, 0x82, 0x8d, 0xc8, 0xd2, 0x6e, 0x2c, 0x0b, 0xdd, 0x58, 0x9c, 0xda, 0x84, 0xba, 0x80, 0x4e,
0x6f, 0x83, 0x5a, 0x9c, 0xfb, 0x3b, 0xd5, 0x61, 0xb6, 0xac, 0xbc, 0x24, 0x43, 0x31, 0x83, 0x5e,
0x58, 0x5b, 0x60, 0x27, 0xd2, 0x23, 0xb1, 0x91, 0x58, 0x37, 0xff, 0x8a, 0xea, 0xa0, 0x08, 0xcc,
0xb2, 0x87, 0x29, 0x27, 0x19, 0x7c, 0x56, 0x8e, 0xff, 0xfd, 0x3b, 0xdc, 0x75, 0x37, 0xf6, 0x6e,
0xe2, 0x15, 0x7e, 0x80, 0x40, 0x1f, 0x3d, 0x00, 0x0d, 0x95, 0xf7, 0x87, 0x00, 0x99, 0x5e, 0x4c,
0x5a, 0xe8, 0x8b, 0xd1, 0xfc, 0x0f, 0x86, 0xf9, 0x9f, 0x9e, 0xc3, 0xe8, 0xc6, 0xb4, 0x84, 0xff,
0x6a, 0xad, 0x0a, 0xa4, 0xf3, 0xbc, 0x46, 0x5f, 0x92, 0xfe, 0x7c, 0x88, 0x7c, 0x98, 0xa4, 0xa8,
0x59, 0xcc, 0x6c, 0x4e, 0x56, 0xc0, 0x1f, 0xfd, 0x52, 0x67, 0xcc, 0x86, 0xbb, 0x35, 0x11, 0xfd,
0x3b, 0x81, 0x28, 0x8b, 0x32, 0xf1, 0x0e, 0xa0, 0x54, 0xd2, 0xf9, 0x97, 0x99, 0x19, 0x2f, 0xce,
0x67, 0xe6, 0xf8, 0xba, 0xf8, 0xa5, 0x81, 0x17, 0x4e, 0xb1, 0x3e, 0x6e, 0x8b, 0xc0, 0x0c, 0xbf,
0x8b, 0x7c, 0x90, 0xf0, 0x1d, 0x13, 0xb6, 0x31, 0xc1, 0xd8, 0x4e, 0x67, 0x73, 0x9b, 0x9b, 0x9f,
0x1a, 0x5f, 0xa3, 0xe1, 0xa1, 0x03, 0xe0, 0xc0, 0x50, 0x97, 0x2f, 0x05, 0xe7, 0xb6, 0xb6, 0x34,
0xce, 0xa3, 0xc8, 0xad, 0x86, 0x83, 0x7d, 0xcb, 0x6e, 0x19, 0x7e, 0xa4, 0x93, 0x84, 0x8b, 0xf0,
0xc5, 0xf1, 0xba, 0x00, 0x02, 0x65, 0x1d, 0x8c, 0x2e, 0x9e, 0x19, 0xfd, 0x2c, 0x32, 0x71, 0x6f,
0xcd, 0x23, 0xfd, 0x10, 0xa3, 0x60, 0x37, 0x88, 0x85, 0x35, 0x0d, 0xd7, 0xb4, 0x38, 0x1f, 0x95,
0x87, 0x04, 0x03, 0x82, 0xeb, 0xc1, 0x75, 0xce, 0x78, 0x42, 0x37, 0xc5, 0x45, 0xaf, 0x78, 0xb6,
0x20, 0x6d, 0x2b, 0x19, 0x53, 0x5b, 0xfd, 0x2f, 0xba, 0xc7, 0xf4, 0xd6, 0x1d, 0xb1, 0x16, 0xcb,
0x66, 0xed, 0x00, 0xce, 0xf8, 0x18, 0x5c, 0x7a, 0xd5, 0x29, 0xde, 0x29, 0x1d, 0xa6, 0x80, 0xe0,
0x16, 0x43, 0x22, 0xa4, 0xd3, 0x69, 0x97, 0xe9, 0x4a, 0xbe, 0x33, 0xc5, 0x57, 0x10, 0x48, 0x9d,
0xf1, 0x06, 0x7a, 0xfb, 0xa3, 0x77, 0x9c, 0x01, 0xca, 0xf9, 0xb7, 0x9c, 0x6f, 0x6e, 0xb2, 0x27,
0x93, 0x5f, 0x9c, 0xc7, 0x4e, 0xe0, 0x89, 0x9f, 0x84, 0xc9, 0x7b, 0x39, 0xb0, 0x1a, 0xf9, 0x1d,
0xba, 0x28, 0x7f, 0xff, 0x8e, 0x4a, 0x3a, 0x22, 0xcc, 0x20, 0xb5, 0x36, 0x43, 0x05, 0x38, 0xd4,
0x1b, 0x48, 0x13, 0x68, 0x2d, 0xbe, 0xb6, 0xb2, 0x3c, 0xe6, 0xcd, 0x03, 0xcd, 0x6d, 0x69, 0x18,
0x73, 0xef, 0x1e, 0x37, 0x4f, 0x25, 0x5b, 0xbe, 0x45, 0x0d, 0x94, 0x32, 0x28, 0xc1, 0xd1, 0xfb,
0xde, 0xe8, 0xc5, 0x6f, 0x30, 0xe7, 0xcb, 0xa5, 0x06, 0x26, 0x9e, 0x33, 0x45, 0xe7, 0x2c, 0xe5,
0x68, 0xeb, 0x0b, 0x86, 0xaf, 0x70, 0x7b, 0xbf, 0x24, 0x05, 0x09, 0xc2, 0x9b, 0x13, 0x70, 0xf5,
0x7d, 0x50, 0x6e, 0x68, 0x7d, 0x54, 0x6c, 0x71, 0x1b, 0x9c, 0x5f, 0x6e, 0xe3, 0x7b, 0xc6, 0xfb,
0xee, 0x45, 0xe2, 0x7b, 0x06, 0xf7, 0x56, 0xf1, 0xb7, 0xef, 0x0e, 0xf4, 0xed, 0xc4, 0xff, 0x05,
0xd8, 0x57, 0xfa, 0x7c, 0x2a, 0xc5, 0x00, 0x00
};

File diff suppressed because it is too large Load Diff

View File

@ -210,7 +210,7 @@ void sendImprovInfoResponse() {
//Use serverDescription if it has been changed from the default "WLED", else mDNS name
bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0);
char vString[20];
sprintf_P(vString, PSTR("0.14.0/%i"), VERSION);
sprintf_P(vString, PSTR("0.14.1-b1/%i"), VERSION);
const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription};
sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str);

View File

@ -675,7 +675,7 @@ void decodeIRJson(uint32_t code)
} else {
// HTTP API command
String apireq = "win"; apireq += '&'; // reduce flash string usage
if (cmdStr.indexOf("~") || fdo["rpt"]) lastValidCode = code; // repeatable action
if (cmdStr.indexOf("~") > 0 || fdo["rpt"]) lastValidCode = code; // repeatable action
if (!cmdStr.startsWith(apireq)) cmdStr = apireq + cmdStr; // if no "win&" prefix
if (!irApplyToAllSelected && cmdStr.indexOf(F("SS="))<0) {
char tmp[10];

View File

@ -231,7 +231,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
getVal(elem["c1"], &seg.custom1);
getVal(elem["c2"], &seg.custom2);
uint8_t cust3 = seg.custom3;
getVal(elem["c3"], &cust3); // we can't pass reference to bifield
getVal(elem["c3"], &cust3); // we can't pass reference to bitfield
seg.custom3 = constrain(cust3, 0, 31);
seg.check1 = elem["o1"] | seg.check1;
@ -244,8 +244,9 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
seg.map1D2D = M12_Pixels; // no mapping
// set brightness immediately and disable transition
transitionDelayTemp = 0;
jsonTransitionOnce = true;
seg.stopTransition();
strip.setTransition(0);
strip.setBrightness(scaledBri(bri), true);
// freeze and init to black
@ -327,23 +328,18 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
int tr = -1;
if (!presetId || currentPlaylist < 0) { //do not apply transition time from preset if playlist active, as it would override playlist transition times
tr = root[F("transition")] | -1;
if (tr >= 0)
{
transitionDelay = tr;
transitionDelay *= 100;
transitionDelayTemp = transitionDelay;
if (tr >= 0) {
transitionDelay = tr * 100;
if (fadeTransition) strip.setTransition(transitionDelay);
}
}
// temporary transition (applies only once)
tr = root[F("tt")] | -1;
if (tr >= 0)
{
transitionDelayTemp = tr;
transitionDelayTemp *= 100;
if (tr >= 0) {
jsonTransitionOnce = true;
if (fadeTransition) strip.setTransition(tr * 100);
}
strip.setTransition(transitionDelayTemp); // required here for color transitions to have correct duration
tr = root[F("tb")] | -1;
if (tr >= 0) strip.timebase = ((uint32_t)tr) - millis();
@ -380,8 +376,8 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
if (root.containsKey("live")) {
if (root["live"].as<bool>()) {
transitionDelayTemp = 0;
jsonTransitionOnce = true;
strip.setTransition(0);
realtimeLock(65000);
} else {
exitRealtime();
@ -501,7 +497,8 @@ void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset, b
root["cct"] = seg.cct;
root[F("set")] = seg.set;
if (segmentBounds && seg.name != nullptr) root["n"] = reinterpret_cast<const char *>(seg.name); //not good practice, but decreases required JSON buffer
if (seg.name != nullptr) root["n"] = reinterpret_cast<const char *>(seg.name); //not good practice, but decreases required JSON buffer
else if (forPreset) root["n"] = "";
// to conserve RAM we will serialize the col array manually
// this will reduce RAM footprint from ~300 bytes to 84 bytes per segment
@ -885,7 +882,7 @@ void serializePalettes(JsonObject root, int page)
curPalette.add("c2");
curPalette.add("c1");
break;
case 5: //primary + secondary (+tert if not off), more distinct
case 5: //primary + secondary (+tertiary if not off), more distinct
curPalette.add("c1");
curPalette.add("c1");
curPalette.add("c1");

View File

@ -134,13 +134,9 @@ void stateUpdated(byte callMode) {
usermods.onStateChange(callMode);
if (fadeTransition) {
//set correct delay if not using notification delay
if (callMode != CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay; // load actual transition duration
jsonTransitionOnce = false;
strip.setTransition(transitionDelayTemp);
if (transitionDelayTemp == 0) {
applyFinalBri();
strip.trigger();
if (strip.getTransition() == 0) {
jsonTransitionOnce = false;
transitionActive = false;
return;
}
@ -152,7 +148,6 @@ void stateUpdated(byte callMode) {
transitionActive = true;
transitionStartTime = millis();
} else {
strip.setTransition(0);
applyFinalBri();
strip.trigger();
}
@ -165,6 +160,8 @@ void updateInterfaces(uint8_t callMode)
sendDataWs();
lastInterfaceUpdate = millis();
interfaceUpdateCallMode = 0; //disable
if (callMode == CALL_MODE_WS_SEND) return;
#ifndef WLED_DISABLE_ALEXA
@ -174,7 +171,6 @@ void updateInterfaces(uint8_t callMode)
}
#endif
doPublishMqtt = true;
interfaceUpdateCallMode = 0; //disable
}
@ -186,13 +182,14 @@ void handleTransitions()
if (doPublishMqtt) publishMqtt();
#endif
if (transitionActive && transitionDelayTemp > 0)
{
float tper = (millis() - transitionStartTime)/(float)transitionDelayTemp;
if (tper >= 1.0f)
{
strip.setTransitionMode(false);
if (transitionActive && strip.getTransition() > 0) {
float tper = (millis() - transitionStartTime)/(float)strip.getTransition();
if (tper >= 1.0f) {
strip.setTransitionMode(false); // stop all transitions
// restore (global) transition time if not called from UDP notifier or single/temporary transition from JSON (also playlist)
if (jsonTransitionOnce) strip.setTransition(transitionDelay);
transitionActive = false;
jsonTransitionOnce = false;
tperLast = 0;
applyFinalBri();
return;

View File

@ -199,6 +199,9 @@ void handleNetworkTime()
{
if (millis() - ntpPacketSentTime > 10000)
{
#ifdef ARDUINO_ARCH_ESP32 // I had problems using udp.flush() on 8266
while (ntpUdp.parsePacket() > 0) ntpUdp.flush(); // flush any existing packets
#endif
sendNTPPacket();
ntpPacketSentTime = millis();
}
@ -239,16 +242,38 @@ void sendNTPPacket()
ntpUdp.endPacket();
}
static bool isValidNtpResponse(byte * ntpPacket) {
// Perform a few validity checks on the packet
// based on https://github.com/taranais/NTPClient/blob/master/NTPClient.cpp
if((ntpPacket[0] & 0b11000000) == 0b11000000) return false; //reject LI=UNSYNC
// if((ntpPacket[0] & 0b00111000) >> 3 < 0b100) return false; //reject Version < 4
if((ntpPacket[0] & 0b00000111) != 0b100) return false; //reject Mode != Server
if((ntpPacket[1] < 1) || (ntpPacket[1] > 15)) return false; //reject invalid Stratum
if( ntpPacket[16] == 0 && ntpPacket[17] == 0 &&
ntpPacket[18] == 0 && ntpPacket[19] == 0 &&
ntpPacket[20] == 0 && ntpPacket[21] == 0 &&
ntpPacket[22] == 0 && ntpPacket[23] == 0) //reject ReferenceTimestamp == 0
return false;
return true;
}
bool checkNTPResponse()
{
int cb = ntpUdp.parsePacket();
if (!cb) return false;
if (cb < NTP_MIN_PACKET_SIZE) {
#ifdef ARDUINO_ARCH_ESP32 // I had problems using udp.flush() on 8266
if (cb > 0) ntpUdp.flush(); // this avoids memory leaks on esp32
#endif
return false;
}
uint32_t ntpPacketReceivedTime = millis();
DEBUG_PRINT(F("NTP recv, l="));
DEBUG_PRINTLN(cb);
byte pbuf[NTP_PACKET_SIZE];
ntpUdp.read(pbuf, NTP_PACKET_SIZE); // read the packet into the buffer
if (!isValidNtpResponse(pbuf)) return false; // verify we have a valid response to client
Toki::Time arrived = toki.fromNTP(pbuf + 32);
Toki::Time departed = toki.fromNTP(pbuf + 40);

View File

@ -60,7 +60,8 @@ enum struct PinOwner : uint8_t {
UM_BME280 = USERMOD_ID_BME280, // 0x1E // Usermod "usermod_bme280.h -- Uses "standard" HW_I2C pins
UM_Audioreactive = USERMOD_ID_AUDIOREACTIVE, // 0x20 // Usermod "audio_reactive.h"
UM_SdCard = USERMOD_ID_SD_CARD, // 0x25 // Usermod "usermod_sd_card.h"
UM_PWM_OUTPUTS = USERMOD_ID_PWM_OUTPUTS // 0x26 // Usermod "usermod_pwm_outputs.h"
UM_PWM_OUTPUTS = USERMOD_ID_PWM_OUTPUTS, // 0x26 // Usermod "usermod_pwm_outputs.h"
UM_LDR_DUSK_DAWN = USERMOD_ID_LDR_DUSK_DAWN // 0x2B // Usermod "usermod_LDR_Dusk_Dawn_v2.h"
};
static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected");

View File

@ -144,7 +144,7 @@ void handlePlaylist() {
}
jsonTransitionOnce = true;
transitionDelayTemp = playlistEntries[playlistIndex].tr * 100;
strip.setTransition(fadeTransition ? playlistEntries[playlistIndex].tr * 100 : 0);
playlistEntryDur = playlistEntries[playlistIndex].dur;
applyPreset(playlistEntries[playlistIndex].preset);
}

View File

@ -212,9 +212,9 @@ void savePreset(byte index, const char* pname, JsonObject sObj)
playlistSave = false;
if (sObj[F("ql")].is<const char*>()) strlcpy(quickLoad, sObj[F("ql")].as<const char*>(), 9); // client limits QL to 2 chars, buffer for 8 bytes to allow unicode
if (sObj["o"].isNull()) { // no "o" means not a playlist or custom API call, saving of state is async (not immediately)
includeBri = sObj["ib"].as<bool>() || index==255; // temporary preset needs brightness
segBounds = sObj["sb"].as<bool>() || index==255; // temporary preset needs bounds
if (sObj.size()==0 || sObj["o"].isNull()) { // no "o" means not a playlist or custom API call, saving of state is async (not immediately)
includeBri = sObj["ib"].as<bool>() || sObj.size()==0 || index==255; // temporary preset needs brightness
segBounds = sObj["sb"].as<bool>() || sObj.size()==0 || index==255; // temporary preset needs bounds
selectedOnly = sObj[F("sc")].as<bool>();
saveLedmap = sObj[F("ledmap")] | -1;
} else {

View File

@ -26,11 +26,11 @@ void handleRemote(){}
// since it's broadly commercially available and works out of the box as a drop-in
typedef struct message_structure {
uint8_t program; // 0x91 for ON button, 0x81 for all others
uint8_t seq[4]; // Incremetal sequence number 32 bit unsigned integer LSB first
uint8_t seq[4]; // Incremental sequence number 32 bit unsigned integer LSB first
uint8_t byte5 = 32; // Unknown
uint8_t button; // Identifies which button is being pressed
uint8_t byte8 = 1; // Unknown, but always 0x01
uint8_t byte9 = 100; // Unnkown, but always 0x64
uint8_t byte9 = 100; // Unknown, but always 0x64
uint8_t byte10; // Unknown, maybe checksum
uint8_t byte11; // Unknown, maybe checksum

View File

@ -117,7 +117,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
pins[i] = (request->arg(lp).length() > 0) ? request->arg(lp).toInt() : 255;
}
type = request->arg(lt).toInt();
type |= request->hasArg(rf) << 7; // off refresh override
skip = request->arg(sl).toInt();
colorOrder = request->arg(co).toInt();
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : t;
@ -149,7 +148,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
} else {
freqHz = 0;
}
channelSwap = (type == TYPE_SK6812_RGBW || type == TYPE_TM1814) ? request->arg(wo).toInt() : 0;
channelSwap = Bus::hasWhite(type) ? request->arg(wo).toInt() : 0;
type |= request->hasArg(rf) << 7; // off refresh override
// actual finalization is done in WLED::loop() (removing old busses and adding new)
// this may happen even before this loop is finished so we do "doInitBusses" after the loop
if (busConfigs[s] != nullptr) delete busConfigs[s];
@ -172,7 +172,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
}
busses.updateColorOrderMap(com);
// upate other pins
// update other pins
int hw_ir_pin = request->arg(F("IR")).toInt();
if (pinManager.allocatePin(hw_ir_pin,false, PinOwner::IR)) {
irPin = hw_ir_pin;
@ -247,6 +247,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
}
fadeTransition = request->hasArg(F("TF"));
modeBlending = request->hasArg(F("EB"));
t = request->arg(F("TD")).toInt();
if (t >= 0) transitionDelayDefault = t;
strip.paletteFade = request->hasArg(F("PF"));
@ -395,7 +396,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
//start ntp if not already connected
if (ntpEnabled && WLED_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort);
ntpLastSyncTime = 0; // force new NTP query
ntpLastSyncTime = NTP_NEVER; // force new NTP query
longitude = request->arg(F("LN")).toFloat();
latitude = request->arg(F("LT")).toFloat();
@ -651,10 +652,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
DEBUG_PRINTLN(value);
} else {
// we are using a hidden field with the same name as our parameter (!before the actual parameter!)
// to describe the type of parameter (text,float,int), for boolean patameters the first field contains "off"
// to describe the type of parameter (text,float,int), for boolean parameters the first field contains "off"
// so checkboxes have one or two fields (first is always "false", existence of second depends on checkmark and may be "true")
if (subObj[name].isNull()) {
// the first occurence of the field describes the parameter type (used in next loop)
// the first occurrence of the field describes the parameter type (used in next loop)
if (value == "false") subObj[name] = false; // checkboxes may have only one field
else subObj[name] = value;
} else {
@ -1062,6 +1063,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
pos = req.indexOf(F("TT="));
if (pos > 0) transitionDelay = getNumVal(&req, pos);
if (fadeTransition) strip.setTransition(transitionDelay);
//set time (unix timestamp)
pos = req.indexOf(F("ST="));

View File

@ -28,7 +28,7 @@
#define BREAKFORMAT SERIAL_8N1
bool dmxStarted = false;
int sendPin = 2; //dafault on ESP8266
int sendPin = 2; //default on ESP8266
//DMX value array and size. Entry 0 will hold startbyte
uint8_t dmxDataStore[dmxMaxChannel] = {};

View File

@ -34,7 +34,7 @@
#define DS1307_CTRL_ID 0x68
// PUBLIC FUNCTIONS
time_t DS1307RTC::get() // Aquire data from buffer and convert to time_t
time_t DS1307RTC::get() // Acquire data from buffer and convert to time_t
{
tmElements_t tm;
if (read(tm) == false) return 0;
@ -48,7 +48,7 @@ bool DS1307RTC::set(time_t t)
return write(tm);
}
// Aquire data from the RTC chip in BCD format
// Acquire data from the RTC chip in BCD format
bool DS1307RTC::read(tmElements_t &tm)
{
uint8_t sec;

View File

@ -101,9 +101,9 @@ int year(time_t t) { // the year for the given time
/*============================================================================*/
/* functions to convert to and from system time */
/* These are for interfacing with time serivces and are not normally needed in a sketch */
/* These are for interfacing with time services and are not normally needed in a sketch */
// leap year calulator expects year argument as years offset from 1970
// leap year calculator expects year argument as years offset from 1970
#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) )
static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0
@ -193,7 +193,7 @@ time_t makeTime(tmElements_t &tm){
}
time_t getUnixTime(int hr,int min,int sec,int dy, int mnth, int yr){
// year can be given as full four digit year or two digts (2010 or 10 for 2010);
// year can be given as full four digit year or two digits (2010 or 10 for 2010);
//it is converted to years since 1970
if( yr > 99)
yr = yr - 1970;

View File

@ -11,7 +11,7 @@
#include "Timezone.h"
//THIS LINE WAS ADDED FOR COMPATIBILY WITH THE WLED DEPENDENCY STRUCTURE. REMOVE IF YOU USE IT OUTSIDE OF WLED!
//THIS LINE WAS ADDED FOR COMPATIBILITY WITH THE WLED DEPENDENCY STRUCTURE. REMOVE IF YOU USE IT OUTSIDE OF WLED!
#include "../time/TimeLib.h"
#ifdef __AVR__

View File

@ -45,7 +45,7 @@ void notify(byte callMode, bool followUp)
//3: supports FX intensity, 24 byte packet 4: supports transitionDelay 5: sup palette
//6: supports timebase syncing, 29 byte packet 7: supports tertiary color 8: supports sys time sync, 36 byte packet
//9: supports sync groups, 37 byte packet 10: supports CCT, 39 byte packet 11: per segment options, variable packet length (40+MAX_NUM_SEGMENTS*3)
//12: enhanced effct sliders, 2D & mapping options
//12: enhanced effect sliders, 2D & mapping options
udpOut[11] = 12;
col = mainseg.colors[1];
udpOut[12] = R(col);
@ -323,9 +323,17 @@ void handleNotifications()
bool someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
// set transition time before making any segment changes
if (version > 3) {
if (fadeTransition) {
jsonTransitionOnce = true;
strip.setTransition(((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00));
}
}
//apply colors from notification to main segment, only if not syncing full segments
if ((receiveNotificationColor || !someSel) && (version < 11 || !receiveSegmentOptions)) {
// primary color, only apply white if intented (version > 0)
// primary color, only apply white if intended (version > 0)
strip.setColor(0, RGBW32(udpIn[3], udpIn[4], udpIn[5], (version > 0) ? udpIn[10] : 0));
if (version > 1) {
strip.setColor(1, RGBW32(udpIn[12], udpIn[13], udpIn[14], udpIn[15])); // secondary color
@ -382,8 +390,9 @@ void handleNotifications()
}
if (version > 11) {
// when applying synced options ignore selected as it may be used as indicator of which segments to sync
// freeze, reset & transitional should never be synced
selseg.options = (selseg.options & 0x0071U) | (udpIn[28+ofs]<<8) | (udpIn[9 +ofs] & 0x8E); // ignore selected, freeze, reset & transitional
// freeze, reset should never be synced
// LSB to MSB: select, reverse, on, mirror, freeze, reset, reverse_y, mirror_y, transpose, map1d2d (3), ssim (2), set (2)
selseg.options = (selseg.options & 0b0000000000110001U) | (udpIn[28+ofs]<<8) | (udpIn[9 +ofs] & 0b11001110U); // ignore selected, freeze, reset
if (applyEffects) {
selseg.custom1 = udpIn[29+ofs];
selseg.custom2 = udpIn[30+ofs];
@ -450,11 +459,6 @@ void handleNotifications()
}
}
if (version > 3)
{
transitionDelayTemp = ((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00);
}
nightlightActive = udpIn[6];
if (nightlightActive) nightlightDelayMins = udpIn[7];

View File

@ -19,7 +19,7 @@ bool UsermodManager::handleButton(uint8_t b) {
bool UsermodManager::getUMData(um_data_t **data, uint8_t mod_id) {
for (byte i = 0; i < numMods; i++) {
if (mod_id > 0 && ums[i]->getId() != mod_id) continue; // only get data form requested usermod if provided
if (ums[i]->getUMData(data)) return true; // if usermod does provide data return immediately (only one usermod can povide data at one time)
if (ums[i]->getUMData(data)) return true; // if usermod does provide data return immediately (only one usermod can provide data at one time)
}
return false;
}

Some files were not shown because too many files have changed in this diff Show More